refactor: switch workspace after creation (#4015)

Co-authored-by: amk-dev <akash.k.mohan98@gmail.com>
This commit is contained in:
Nivedin
2024-05-09 20:28:24 +05:30
committed by GitHub
parent 5c4b651aee
commit ef1117d8cc
11 changed files with 112 additions and 149 deletions

View File

@@ -32,7 +32,6 @@ import { useI18n } from "~/composables/i18n"
import { useToast } from "~/composables/toast"
import { appendRESTCollections, restCollections$ } from "~/newstore/collections"
import MyCollectionImport from "~/components/importExport/ImportExportSteps/MyCollectionImport.vue"
import { GetMyTeamsQuery } from "~/helpers/backend/graphql"
import IconFolderPlus from "~icons/lucide/folder-plus"
import IconOpenAPI from "~icons/lucide/file"
@@ -55,16 +54,15 @@ import { teamCollectionsExporter } from "~/helpers/import-export/export/teamColl
import { GistSource } from "~/helpers/import-export/import/import-sources/GistSource"
import { ImporterOrExporter } from "~/components/importExport/types"
import { TeamWorkspace } from "~/services/workspace.service"
const t = useI18n()
const toast = useToast()
type SelectedTeam = GetMyTeamsQuery["myTeams"][number] | undefined
type CollectionType =
| {
type: "team-collections"
selectedTeam: SelectedTeam
selectedTeam: TeamWorkspace
}
| { type: "my-collections" }
@@ -433,7 +431,7 @@ const HoppTeamCollectionsExporter: ImporterOrExporter = {
props.collectionsType.selectedTeam
) {
const res = await teamCollectionsExporter(
props.collectionsType.selectedTeam.id
props.collectionsType.selectedTeam.teamID
)
if (E.isRight(res)) {
@@ -569,8 +567,8 @@ const hasTeamWriteAccess = computed(() => {
}
return (
collectionsType.selectedTeam.myRole === "EDITOR" ||
collectionsType.selectedTeam.myRole === "OWNER"
collectionsType.selectedTeam.role === "EDITOR" ||
collectionsType.selectedTeam.role === "OWNER"
)
})
@@ -578,17 +576,17 @@ const selectedTeamID = computed(() => {
const { collectionsType } = props
return collectionsType.type === "team-collections"
? collectionsType.selectedTeam?.id
? collectionsType.selectedTeam?.teamID
: undefined
})
const getCollectionJSON = async () => {
if (
props.collectionsType.type === "team-collections" &&
props.collectionsType.selectedTeam?.id
props.collectionsType.selectedTeam?.teamID
) {
const res = await getTeamCollectionJSON(
props.collectionsType.selectedTeam?.id
props.collectionsType.selectedTeam?.teamID
)
return E.isRight(res)

View File

@@ -56,23 +56,25 @@
</template>
<script setup lang="ts">
import { computed, nextTick, reactive, ref, watch } from "vue"
import { cloneDeep } from "lodash-es"
import { useI18n } from "@composables/i18n"
import { useToast } from "@composables/toast"
import {
HoppGQLRequest,
HoppRESTRequest,
isHoppRESTRequest,
} from "@hoppscotch/data"
import { pipe } from "fp-ts/function"
import { computedWithControl } from "@vueuse/core"
import { useService } from "dioc/vue"
import * as TE from "fp-ts/TaskEither"
import { GetMyTeamsQuery } from "~/helpers/backend/graphql"
import { pipe } from "fp-ts/function"
import { cloneDeep } from "lodash-es"
import { computed, nextTick, reactive, ref, watch } from "vue"
import { GQLError } from "~/helpers/backend/GQLClient"
import {
createRequestInCollection,
updateTeamRequest,
} from "~/helpers/backend/mutations/TeamRequest"
import { Picked } from "~/helpers/types/HoppPicked"
import { useI18n } from "@composables/i18n"
import { useToast } from "@composables/toast"
import {
cascadeParentCollectionForHeaderAuth,
editGraphqlRequest,
@@ -80,12 +82,10 @@ import {
saveGraphqlRequestAs,
saveRESTRequestAs,
} from "~/newstore/collections"
import { GQLError } from "~/helpers/backend/GQLClient"
import { computedWithControl } from "@vueuse/core"
import { platform } from "~/platform"
import { useService } from "dioc/vue"
import { RESTTabService } from "~/services/tab/rest"
import { GQLTabService } from "~/services/tab/graphql"
import { RESTTabService } from "~/services/tab/rest"
import { TeamWorkspace } from "~/services/workspace.service"
const t = useI18n()
const toast = useToast()
@@ -93,12 +93,10 @@ const toast = useToast()
const RESTTabs = useService(RESTTabService)
const GQLTabs = useService(GQLTabService)
type SelectedTeam = GetMyTeamsQuery["myTeams"][number] | undefined
type CollectionType =
| {
type: "team-collections"
selectedTeam: SelectedTeam
selectedTeam: TeamWorkspace
}
| { type: "my-collections"; selectedTeam: undefined }
@@ -192,7 +190,7 @@ watch(
}
)
const updateTeam = (newTeam: SelectedTeam) => {
const updateTeam = (newTeam: TeamWorkspace) => {
collectionsType.value.selectedTeam = newTeam
}
@@ -493,7 +491,7 @@ const updateTeamCollectionOrFolder = (
const data = {
title: requestUpdated.name,
request: JSON.stringify(requestUpdated),
teamID: collectionsType.value.selectedTeam.id,
teamID: collectionsType.value.selectedTeam.teamID,
}
pipe(
createRequestInCollection(collectionID, data),

View File

@@ -387,7 +387,6 @@ import IconPlus from "~icons/lucide/plus"
import IconHelpCircle from "~icons/lucide/help-circle"
import IconImport from "~icons/lucide/folder-down"
import { computed, PropType, Ref, toRef } from "vue"
import { GetMyTeamsQuery } from "~/helpers/backend/graphql"
import { useI18n } from "@composables/i18n"
import { useColorMode } from "@composables/theming"
import { TeamCollection } from "~/helpers/teams/TeamCollection"
@@ -400,17 +399,16 @@ import * as O from "fp-ts/Option"
import { Picked } from "~/helpers/types/HoppPicked.js"
import { RESTTabService } from "~/services/tab/rest"
import { useService } from "dioc/vue"
import { TeamWorkspace } from "~/services/workspace.service"
const t = useI18n()
const colorMode = useColorMode()
const tabs = useService(RESTTabService)
type SelectedTeam = GetMyTeamsQuery["myTeams"][number] | undefined
type CollectionType =
| {
type: "team-collections"
selectedTeam: SelectedTeam
selectedTeam: TeamWorkspace
}
| { type: "my-collections"; selectedTeam: undefined }
@@ -614,7 +612,7 @@ const hasNoTeamAccess = computed(
() =>
props.collectionsType.type === "team-collections" &&
(props.collectionsType.selectedTeam === undefined ||
props.collectionsType.selectedTeam.myRole === "VIEWER")
props.collectionsType.selectedTeam.role === "VIEWER")
)
const isSelected = ({

View File

@@ -200,7 +200,7 @@ const toast = useToast()
defineProps<{
// Whether to activate the ability to pick items (activates 'select' events)
saveRequest: boolean
picked: Picked
picked: Picked | null
}>()
const collections = useReadonlyStream(graphqlCollections$, [], "deep")

View File

@@ -178,7 +178,6 @@ import { useI18n } from "@composables/i18n"
import { Picked } from "~/helpers/types/HoppPicked"
import { useReadonlyStream } from "~/composables/stream"
import { useLocalState } from "~/newstore/localstate"
import { GetMyTeamsQuery } from "~/helpers/backend/graphql"
import { pipe } from "fp-ts/function"
import * as TE from "fp-ts/TaskEither"
import {
@@ -245,7 +244,7 @@ import {
} from "~/helpers/collection/collection"
import { currentReorderingStatus$ } from "~/newstore/reordering"
import { defineActionHandler, invokeAction } from "~/helpers/actions"
import { WorkspaceService } from "~/services/workspace.service"
import { TeamWorkspace, WorkspaceService } from "~/services/workspace.service"
import { useService } from "dioc/vue"
import { RESTTabService } from "~/services/tab/rest"
import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties"
@@ -274,16 +273,14 @@ const props = defineProps({
const emit = defineEmits<{
(event: "select", payload: Picked | null): void
(event: "update-team", team: SelectedTeam): void
(event: "update-team", team: TeamWorkspace): void
(event: "update-collection-type", type: CollectionType["type"]): void
}>()
type SelectedTeam = GetMyTeamsQuery["myTeams"][number] | undefined
type CollectionType =
| {
type: "team-collections"
selectedTeam: SelectedTeam
selectedTeam: TeamWorkspace
}
| { type: "my-collections"; selectedTeam: undefined }
@@ -330,9 +327,7 @@ const requestMoveLoading = ref<string[]>([])
// TeamList-Adapter
const workspaceService = useService(WorkspaceService)
const teamListAdapter = workspaceService.acquireTeamListAdapter(null)
const myTeams = useReadonlyStream(teamListAdapter.teamList$, null)
const REMEMBERED_TEAM_ID = useLocalState("REMEMBERED_TEAM_ID")
const teamListFetched = ref(false)
// Team Collection Adapter
const teamCollectionAdapter = new TeamCollectionAdapter(null)
@@ -378,7 +373,7 @@ watch(
filterTexts,
(newFilterText) => {
if (collectionsType.value.type === "team-collections") {
const selectedTeamID = collectionsType.value.selectedTeam?.id
const selectedTeamID = collectionsType.value.selectedTeam?.teamID
selectedTeamID &&
debouncedSearch(newFilterText, selectedTeamID)?.catch(() => {})
@@ -435,28 +430,6 @@ onMounted(() => {
}
})
watch(
() => myTeams.value,
(newTeams) => {
if (newTeams && !teamListFetched.value) {
teamListFetched.value = true
if (REMEMBERED_TEAM_ID.value && currentUser.value) {
const team = newTeams.find((t) => t.id === REMEMBERED_TEAM_ID.value)
if (team) updateSelectedTeam(team)
}
}
}
)
watch(
() => collectionsType.value.selectedTeam,
(newTeam) => {
if (newTeam) {
teamCollectionAdapter.changeTeamID(newTeam.id)
}
}
)
const switchToMyCollections = () => {
collectionsType.value.type = "my-collections"
collectionsType.value.selectedTeam = undefined
@@ -488,11 +461,12 @@ const expandTeamCollection = (collectionID: string) => {
teamCollectionAdapter.expandCollection(collectionID)
}
const updateSelectedTeam = (team: SelectedTeam) => {
const updateSelectedTeam = (team: TeamWorkspace) => {
if (team) {
collectionsType.value.type = "team-collections"
teamCollectionAdapter.changeTeamID(team.teamID)
collectionsType.value.selectedTeam = team
REMEMBERED_TEAM_ID.value = team.id
REMEMBERED_TEAM_ID.value = team.teamID
emit("update-team", team)
emit("update-collection-type", "team-collections")
}
@@ -501,23 +475,14 @@ const updateSelectedTeam = (team: SelectedTeam) => {
const workspace = workspaceService.currentWorkspace
// Used to switch collection type and team when user switch workspace in the global workspace switcher
// Check if there is a teamID in the workspace, if yes, switch to team collections and select the team
// If there is no teamID, switch to my collections
watch(
() => {
const space = workspace.value
return space.type === "personal" ? undefined : space.teamID
},
(teamID) => {
if (teamID) {
const team = myTeams.value?.find((t) => t.id === teamID)
if (team) {
updateSelectedTeam(team)
}
return
workspace,
(newWorkspace) => {
if (newWorkspace.type === "personal") {
switchToMyCollections()
} else if (newWorkspace.type === "team") {
updateSelectedTeam(newWorkspace)
}
return switchToMyCollections()
},
{
immediate: true,
@@ -545,7 +510,7 @@ const hasTeamWriteAccess = computed(() => {
return false
}
const role = collectionsType.value.selectedTeam?.myRole
const role = collectionsType.value.selectedTeam?.role
return role === "OWNER" || role === "EDITOR"
})
@@ -760,7 +725,7 @@ const addNewRootCollection = (name: string) => {
})
pipe(
createNewRootCollection(name, collectionsType.value.selectedTeam.id),
createNewRootCollection(name, collectionsType.value.selectedTeam.teamID),
TE.match(
(err: GQLError<string>) => {
toast.error(`${getErrorMessage(err)}`)
@@ -831,7 +796,7 @@ const onAddRequest = (requestName: string) => {
const data = {
request: JSON.stringify(newRequest),
teamID: collectionsType.value.selectedTeam.id,
teamID: collectionsType.value.selectedTeam.teamID,
title: requestName,
}
@@ -1158,7 +1123,7 @@ const duplicateRequest = (payload: {
const data = {
request: JSON.stringify(newRequest),
teamID: collectionsType.value.selectedTeam.id,
teamID: collectionsType.value.selectedTeam.teamID,
title: `${request.name} - ${t("action.duplicate")}`,
}

View File

@@ -364,6 +364,7 @@ const switchToTeamWorkspace = (team: GetMyTeamsQuery["myTeams"][number]) => {
teamID: team.id,
teamName: team.name,
type: "team",
role: team.myRole,
})
}
watch(

View File

@@ -46,41 +46,38 @@
</template>
<script setup lang="ts">
import { computed, ref, watch } from "vue"
import { isEqual } from "lodash-es"
import { platform } from "~/platform"
import { GetMyTeamsQuery } from "~/helpers/backend/graphql"
import { useReadonlyStream, useStream } from "@composables/stream"
import { Environment } from "@hoppscotch/data"
import { useService } from "dioc/vue"
import * as TE from "fp-ts/TaskEither"
import { pipe } from "fp-ts/function"
import { isEqual } from "lodash-es"
import { computed, ref, watch } from "vue"
import { useI18n } from "~/composables/i18n"
import { useToast } from "~/composables/toast"
import { defineActionHandler } from "~/helpers/actions"
import { GQLError } from "~/helpers/backend/GQLClient"
import { deleteTeamEnvironment } from "~/helpers/backend/mutations/TeamEnvironment"
import TeamEnvironmentAdapter from "~/helpers/teams/TeamEnvironmentAdapter"
import {
deleteEnvironment,
getSelectedEnvironmentIndex,
globalEnv$,
selectedEnvironmentIndex$,
setSelectedEnvironmentIndex,
} from "~/newstore/environments"
import TeamEnvironmentAdapter from "~/helpers/teams/TeamEnvironmentAdapter"
import { defineActionHandler } from "~/helpers/actions"
import { useLocalState } from "~/newstore/localstate"
import { pipe } from "fp-ts/function"
import * as TE from "fp-ts/TaskEither"
import { GQLError } from "~/helpers/backend/GQLClient"
import { deleteEnvironment } from "~/newstore/environments"
import { deleteTeamEnvironment } from "~/helpers/backend/mutations/TeamEnvironment"
import { useToast } from "~/composables/toast"
import { WorkspaceService } from "~/services/workspace.service"
import { useService } from "dioc/vue"
import { Environment } from "@hoppscotch/data"
import { platform } from "~/platform"
import { TeamWorkspace, WorkspaceService } from "~/services/workspace.service"
const t = useI18n()
const toast = useToast()
type EnvironmentType = "my-environments" | "team-environments"
type SelectedTeam = GetMyTeamsQuery["myTeams"][number] | undefined
type EnvironmentsChooseType = {
type: EnvironmentType
selectedTeam: SelectedTeam
selectedTeam: TeamWorkspace | undefined
}
const environmentType = ref<EnvironmentsChooseType>({
@@ -102,11 +99,7 @@ const currentUser = useReadonlyStream(
platform.auth.getCurrentUser()
)
// TeamList-Adapter
const workspaceService = useService(WorkspaceService)
const teamListAdapter = workspaceService.acquireTeamListAdapter(null)
const myTeams = useReadonlyStream(teamListAdapter.teamList$, null)
const teamListFetched = ref(false)
const REMEMBERED_TEAM_ID = useLocalState("REMEMBERED_TEAM_ID")
const adapter = new TeamEnvironmentAdapter(undefined)
@@ -118,29 +111,17 @@ const loading = computed(
() => adapterLoading.value && teamEnvironmentList.value.length === 0
)
watch(
() => myTeams.value,
(newTeams) => {
if (newTeams && !teamListFetched.value) {
teamListFetched.value = true
if (REMEMBERED_TEAM_ID.value && currentUser.value) {
const team = newTeams.find((t) => t.id === REMEMBERED_TEAM_ID.value)
if (team) updateSelectedTeam(team)
}
}
}
)
const switchToMyEnvironments = () => {
environmentType.value.selectedTeam = undefined
updateEnvironmentType("my-environments")
adapter.changeTeamID(undefined)
}
const updateSelectedTeam = (newSelectedTeam: SelectedTeam | undefined) => {
const updateSelectedTeam = (newSelectedTeam: TeamWorkspace | undefined) => {
if (newSelectedTeam) {
adapter.changeTeamID(newSelectedTeam.teamID)
environmentType.value.selectedTeam = newSelectedTeam
REMEMBERED_TEAM_ID.value = newSelectedTeam.id
REMEMBERED_TEAM_ID.value = newSelectedTeam.teamID
updateEnvironmentType("team-environments")
}
}
@@ -148,15 +129,6 @@ const updateEnvironmentType = (newEnvironmentType: EnvironmentType) => {
environmentType.value.type = newEnvironmentType
}
watch(
() => environmentType.value.selectedTeam,
(newTeam) => {
if (newTeam) {
adapter.changeTeamID(newTeam.id)
}
}
)
const workspace = workspaceService.currentWorkspace
// Switch to my environments if workspace is personal and to team environments if workspace is team
@@ -170,8 +142,7 @@ watch(workspace, (newWorkspace) => {
})
}
} else if (newWorkspace.type === "team") {
const team = myTeams.value?.find((t) => t.id === newWorkspace.teamID)
updateSelectedTeam(team)
updateSelectedTeam(newWorkspace)
}
})

View File

@@ -4,7 +4,7 @@
class="sticky top-upperPrimaryStickyFold z-10 flex flex-1 flex-shrink-0 justify-between overflow-x-auto border-b border-dividerLight bg-primary"
>
<HoppButtonSecondary
v-if="team === undefined || team.myRole === 'VIEWER'"
v-if="team === undefined || team.role === 'VIEWER'"
v-tippy="{ theme: 'tooltip' }"
disabled
class="!rounded-none"
@@ -28,7 +28,7 @@
:icon="IconHelpCircle"
/>
<HoppButtonSecondary
v-if="team !== undefined && team.myRole === 'VIEWER'"
v-if="team !== undefined && team.role === 'VIEWER'"
v-tippy="{ theme: 'tooltip' }"
disabled
:icon="IconImport"
@@ -84,7 +84,7 @@
)"
:key="`environment-${index}`"
:environment="environment"
:is-viewer="team?.myRole === 'VIEWER'"
:is-viewer="team?.role === 'VIEWER'"
@edit-environment="editEnvironment(environment)"
/>
</div>
@@ -103,16 +103,16 @@
:show="showModalDetails"
:action="action"
:editing-environment="editingEnvironment"
:editing-team-id="team?.id"
:editing-team-id="team?.teamID"
:editing-variable-name="editingVariableName"
:is-secret-option-selected="secretOptionSelected"
:is-viewer="team?.myRole === 'VIEWER'"
:is-viewer="team?.role === 'VIEWER'"
@hide-modal="displayModalEdit(false)"
/>
<EnvironmentsImportExport
v-if="showModalImportExport"
:team-environments="teamEnvironments"
:team-id="team?.id"
:team-id="team?.teamID"
environment-type="TEAM_ENV"
@hide-modal="displayModalImportExport(false)"
/>
@@ -129,16 +129,14 @@ import IconPlus from "~icons/lucide/plus"
import IconHelpCircle from "~icons/lucide/help-circle"
import IconImport from "~icons/lucide/folder-down"
import { defineActionHandler } from "~/helpers/actions"
import { GetMyTeamsQuery } from "~/helpers/backend/graphql"
import { TeamWorkspace } from "~/services/workspace.service"
const t = useI18n()
const colorMode = useColorMode()
type SelectedTeam = GetMyTeamsQuery["myTeams"][number] | undefined
const props = defineProps<{
team: SelectedTeam
team: TeamWorkspace | undefined
teamEnvironments: TeamEnvironment[]
adapterError: GQLError<string> | null
loading: boolean
@@ -151,7 +149,7 @@ const editingEnvironment = ref<TeamEnvironment | null>(null)
const editingVariableName = ref("")
const secretOptionSelected = ref(false)
const isTeamViewer = computed(() => props.team?.myRole === "VIEWER")
const isTeamViewer = computed(() => props.team?.role === "VIEWER")
const displayModalAdd = (shouldDisplay: boolean) => {
action.value = "new"

View File

@@ -37,13 +37,17 @@ import { TeamNameCodec } from "~/helpers/backend/types/TeamName"
import { useI18n } from "@composables/i18n"
import { useToast } from "@composables/toast"
import { platform } from "~/platform"
import { useService } from "dioc/vue"
import { WorkspaceService } from "~/services/workspace.service"
import { useLocalState } from "~/newstore/localstate"
const t = useI18n()
const toast = useToast()
defineProps<{
const props = defineProps<{
show: boolean
switchWorkspaceAfterCreation?: boolean
}>()
const emit = defineEmits<{
@@ -52,8 +56,12 @@ const emit = defineEmits<{
const editingName = ref<string | null>(null)
const REMEMBERED_TEAM_ID = useLocalState("REMEMBERED_TEAM_ID")
const isLoading = ref(false)
const workspaceService = useService(WorkspaceService)
const addNewTeam = async () => {
isLoading.value = true
await pipe(
@@ -76,8 +84,19 @@ const addNewTeam = async () => {
// Handle GQL errors (use err obj)
}
},
() => {
(team) => {
toast.success(`${t("team.new_created")}`)
if (props.switchWorkspaceAfterCreation) {
REMEMBERED_TEAM_ID.value = team.id
workspaceService.changeWorkspace({
teamID: team.id,
teamName: team.name,
type: "team",
role: team.myRole,
})
}
hideModal()
}
)

View File

@@ -66,7 +66,11 @@
{{ t("error.something_went_wrong") }}
</div>
</div>
<TeamsAdd :show="showModalAdd" @hide-modal="displayModalAdd(false)" />
<TeamsAdd
:show="showModalAdd"
:switch-workspace-after-creation="true"
@hide-modal="displayModalAdd(false)"
/>
</div>
</template>
<script setup lang="ts">
@@ -153,6 +157,7 @@ const switchToTeamWorkspace = (team: GetMyTeamsQuery["myTeams"][number]) => {
workspaceService.changeWorkspace({
teamID: team.id,
teamName: team.name,
role: team.myRole,
type: "team",
})
}
@@ -175,7 +180,6 @@ watch(
const displayModalAdd = (shouldDisplay: boolean) => {
showModalAdd.value = shouldDisplay
teamListadapter.fetchList()
}
defineActionHandler("modals.team.new", () => {

View File

@@ -5,13 +5,24 @@ import { useStreamStatic } from "~/composables/stream"
import TeamListAdapter from "~/helpers/teams/TeamListAdapter"
import { platform } from "~/platform"
import { min } from "lodash-es"
import { TeamMemberRole } from "~/helpers/backend/graphql"
/**
* Defines a workspace and its information
*/
export type Workspace =
| { type: "personal" }
| { type: "team"; teamID: string; teamName: string }
export type PersonalWorkspace = {
type: "personal"
}
export type TeamWorkspace = {
type: "team"
teamID: string
teamName: string
role: TeamMemberRole | null | undefined
}
export type Workspace = PersonalWorkspace | TeamWorkspace
export type WorkspaceServiceEvent = {
type: "managed-team-list-adapter-polled"