205 lines
6.2 KiB
Vue
205 lines
6.2 KiB
Vue
<template>
|
|
<LayoutDialog v-model:open="open" max-width="sm" :buttons="dialogButtons">
|
|
<template #header>Move project to workspace</template>
|
|
<div class="flex flex-col space-y-4">
|
|
<template v-if="!workspace">
|
|
<ProjectsWorkspaceSelect
|
|
v-if="hasWorkspaces"
|
|
v-model="selectedWorkspace"
|
|
:items="workspaces"
|
|
:disabled-roles="[Roles.Workspace.Member, Roles.Workspace.Guest]"
|
|
disabled-item-tooltip="Only workspace admins can move projects into a workspace."
|
|
label="Select a workspace"
|
|
help="Once a project is moved to a workspace, it cannot be moved out from it."
|
|
show-label
|
|
/>
|
|
<div v-else class="flex flex-col gap-y-2">
|
|
<p class="text-body-xs text-foreground font-medium">
|
|
You're not a member of any workspaces.
|
|
</p>
|
|
<FormButton :to="workspacesRoute">Learn about workspaces</FormButton>
|
|
</div>
|
|
</template>
|
|
|
|
<div v-if="project && (selectedWorkspace || workspace)" class="text-body-xs">
|
|
<div class="text-body-xs text-foreground flex flex-col gap-y-4">
|
|
<div class="rounded border bg-foundation-2 border-outline-3 py-2 px-4">
|
|
<p>
|
|
Move
|
|
<span class="font-medium">{{ project.name }}</span>
|
|
to
|
|
<span class="font-medium">
|
|
{{ selectedWorkspace?.name ?? workspace?.name }}
|
|
</span>
|
|
</p>
|
|
<p class="text-foreground-3">
|
|
{{ project.modelCount.totalCount }} {{ modelText }},
|
|
{{ project.versions.totalCount }} {{ versionsText }}
|
|
</p>
|
|
</div>
|
|
<p class="text-body-2xs text-foreground-2">
|
|
The project, including models and versions, will be moved to the workspace,
|
|
where all existing members and admins will have access.
|
|
<span class="pt-2 block">
|
|
The project's collaborators will become workspace members and keep their
|
|
project roles.
|
|
</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<WorkspaceRegionStaticDataDisclaimer
|
|
v-if="showRegionStaticDataDisclaimer"
|
|
v-model:open="showRegionStaticDataDisclaimer"
|
|
:variant="RegionStaticDataDisclaimerVariant.MoveProjectIntoWorkspace"
|
|
@confirm="onConfirmHandler"
|
|
/>
|
|
</LayoutDialog>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { graphql } from '~~/lib/common/generated/gql'
|
|
import type {
|
|
ProjectsMoveToWorkspaceDialog_WorkspaceFragment,
|
|
ProjectsMoveToWorkspaceDialog_ProjectFragment
|
|
} from '~~/lib/common/generated/gql/graphql'
|
|
import { useMutationLoading, useQuery } from '@vue/apollo-composable'
|
|
import { type LayoutDialogButton } from '@speckle/ui-components'
|
|
import { useMoveProjectToWorkspace } from '~/lib/projects/composables/projectManagement'
|
|
import { Roles } from '@speckle/shared'
|
|
import { workspacesRoute } from '~/lib/common/helpers/route'
|
|
import {
|
|
useWorkspaceCustomDataResidencyDisclaimer,
|
|
RegionStaticDataDisclaimerVariant
|
|
} from '~/lib/workspaces/composables/region'
|
|
|
|
graphql(`
|
|
fragment ProjectsMoveToWorkspaceDialog_Workspace on Workspace {
|
|
id
|
|
role
|
|
name
|
|
logo
|
|
...WorkspaceHasCustomDataResidency_Workspace
|
|
...ProjectsWorkspaceSelect_Workspace
|
|
}
|
|
`)
|
|
|
|
graphql(`
|
|
fragment ProjectsMoveToWorkspaceDialog_User on User {
|
|
workspaces {
|
|
items {
|
|
...ProjectsMoveToWorkspaceDialog_Workspace
|
|
}
|
|
}
|
|
}
|
|
`)
|
|
|
|
graphql(`
|
|
fragment ProjectsMoveToWorkspaceDialog_Project on Project {
|
|
id
|
|
name
|
|
modelCount: models(limit: 0) {
|
|
totalCount
|
|
}
|
|
versions(limit: 0) {
|
|
totalCount
|
|
}
|
|
}
|
|
`)
|
|
|
|
const query = graphql(`
|
|
query ProjectsMoveToWorkspaceDialog {
|
|
activeUser {
|
|
id
|
|
...ProjectsMoveToWorkspaceDialog_User
|
|
}
|
|
}
|
|
`)
|
|
|
|
const props = defineProps<{
|
|
project: ProjectsMoveToWorkspaceDialog_ProjectFragment
|
|
workspace?: ProjectsMoveToWorkspaceDialog_WorkspaceFragment
|
|
eventSource?: string // Used for mixpanel tracking
|
|
}>()
|
|
const open = defineModel<boolean>('open', { required: true })
|
|
|
|
const isWorkspacesEnabled = useIsWorkspacesEnabled()
|
|
const { result } = useQuery(query, null, () => ({
|
|
enabled: isWorkspacesEnabled.value
|
|
}))
|
|
const loading = useMutationLoading()
|
|
const moveProject = useMoveProjectToWorkspace()
|
|
|
|
const selectedWorkspace = ref<ProjectsMoveToWorkspaceDialog_WorkspaceFragment>()
|
|
|
|
const workspaces = computed(() => result.value?.activeUser?.workspaces.items ?? [])
|
|
const hasWorkspaces = computed(() => workspaces.value.length > 0)
|
|
const modelText = computed(() =>
|
|
props.project.modelCount.totalCount === 1 ? 'model' : 'models'
|
|
)
|
|
const versionsText = computed(() =>
|
|
props.project.versions.totalCount === 1 ? 'version' : 'versions'
|
|
)
|
|
const dialogButtons = computed<LayoutDialogButton[]>(() => {
|
|
return hasWorkspaces.value
|
|
? [
|
|
{
|
|
text: 'Cancel',
|
|
props: { color: 'outline' },
|
|
onClick: () => {
|
|
open.value = false
|
|
}
|
|
},
|
|
{
|
|
text: 'Move',
|
|
props: {
|
|
color: 'primary',
|
|
disabled: (!selectedWorkspace.value && !props.workspace) || loading.value
|
|
},
|
|
onClick: () => triggerAction()
|
|
}
|
|
]
|
|
: [
|
|
{
|
|
text: 'Close',
|
|
props: { color: 'outline' },
|
|
onClick: () => {
|
|
open.value = false
|
|
}
|
|
}
|
|
]
|
|
})
|
|
|
|
const onMoveProject = async () => {
|
|
const workspaceId = selectedWorkspace.value?.id ?? props.workspace?.id
|
|
const workspaceName = selectedWorkspace.value?.name ?? props.workspace?.name
|
|
if (!workspaceId || !workspaceName) return
|
|
|
|
const res = await moveProject({
|
|
projectId: props.project.id,
|
|
workspaceId,
|
|
workspaceName,
|
|
eventSource: props.eventSource
|
|
})
|
|
if (res?.id) {
|
|
open.value = false
|
|
}
|
|
}
|
|
|
|
const { showRegionStaticDataDisclaimer, triggerAction, onConfirmHandler } =
|
|
useWorkspaceCustomDataResidencyDisclaimer({
|
|
workspace: computed(() => selectedWorkspace.value ?? props.workspace),
|
|
onConfirmAction: onMoveProject
|
|
})
|
|
|
|
watch(
|
|
() => open.value,
|
|
(isOpen, oldIsOpen) => {
|
|
if (isOpen && isOpen !== oldIsOpen) {
|
|
selectedWorkspace.value = undefined
|
|
showRegionStaticDataDisclaimer.value = false
|
|
}
|
|
}
|
|
)
|
|
</script>
|