Files
speckle-server/packages/frontend-2/components/workspace/moveProject/SelectProject.vue
T
andrewwallacespeckle 3fb4933d5b fix(fe): Move projects - Use different empty text when search is active
fix(fe): Move projects - Use different empty text when search is active
2025-04-22 11:44:16 +01:00

164 lines
4.9 KiB
Vue

<template>
<div>
<FormTextInput
v-bind="bind"
label="Move projects"
name="search"
color="foundation"
placeholder="Search projects..."
show-clear
full-width
class="mb-2"
v-on="on"
/>
<div v-if="showLoading" class="py-4 flex items-center justify-center w-full h-32">
<CommonLoadingIcon size="sm" />
</div>
<template v-else>
<div
v-if="hasMoveableProjects"
class="flex flex-col mt-2 border rounded-md border-outline-3"
>
<div
v-for="project in moveableProjects"
:key="project.id"
class="flex px-4 py-3 items-center space-x-2 justify-between border-b last:border-0 border-outline-3"
>
<div class="flex flex-col flex-1 truncate text-body-xs">
<span class="font-medium text-foreground truncate">
{{ project.name }}
</span>
<div class="flex items-center gap-x-1">
<span class="text-foreground-3 truncate">
{{ project.modelCount.totalCount }} model{{
project.modelCount.totalCount !== 1 ? 's' : ''
}}
</span>
</div>
</div>
<div
:key="`${project.id}-${project.permissions.canMoveToWorkspace.code}`"
v-tippy="getProjectTooltip(project)"
>
<FormButton
size="sm"
color="outline"
:disabled="isProjectDisabled(project)"
@click="handleProjectClick(project)"
>
Move...
</FormButton>
</div>
</div>
</div>
<p v-else-if="!search?.length" class="py-4 text-body-xs text-foreground-2">
You don't have any projects that can be moved into this workspace. Only projects
you own and that aren't in another workspace can be moved.
</p>
<p v-else class="py-4 text-body-xs text-foreground-2">
No projects match your search.
</p>
</template>
<InfiniteLoading
v-if="!search?.length"
:settings="{ identifier }"
@infinite="onInfiniteLoad"
/>
<WorkspacePlanProjectModelLimitReachedDialog
v-model:open="showLimitDialog"
:workspace-name="workspace?.name"
:plan="workspace?.plan?.name"
:workspace-role="workspace?.role"
:workspace-slug="workspace?.slug || ''"
location="move_project_dialog"
/>
</div>
</template>
<script setup lang="ts">
import {
CommonLoadingIcon,
FormTextInput,
useDebouncedTextInput
} from '@speckle/ui-components'
import type {
PermissionCheckResult,
WorkspaceMoveProjectManager_ProjectFragment,
WorkspaceMoveProjectManager_WorkspaceFragment
} from '~~/lib/common/generated/gql/graphql'
import { usePaginatedQuery } from '~/lib/common/composables/graphql'
import { workspaceMoveProjectManagerUserQuery } from '~/lib/workspaces/graphql/queries'
const search = defineModel<string>('search')
const { on, bind } = useDebouncedTextInput({ model: search })
const emit = defineEmits<{
(e: 'project-selected', project: WorkspaceMoveProjectManager_ProjectFragment): void
}>()
defineProps<{
workspace?: WorkspaceMoveProjectManager_WorkspaceFragment
projectPermissions?: PermissionCheckResult
}>()
const {
query: { result, loading },
identifier,
onInfiniteLoad
} = usePaginatedQuery({
query: workspaceMoveProjectManagerUserQuery,
baseVariables: computed(() => ({
cursor: null as string | null,
filter: {
search: search.value?.length ? search.value : null,
personalOnly: true
}
})),
resolveKey: (vars) => [vars.filter?.search || ''],
resolveCurrentResult: (res) => res?.activeUser?.projects,
resolveNextPageVariables: (baseVars, cursor) => ({
...baseVars,
cursor
}),
resolveCursorFromVariables: (vars) => vars.cursor
})
const showLimitDialog = ref(false)
const userProjects = computed(() => result.value?.activeUser?.projects.items || [])
const moveableProjects = computed(() => userProjects.value)
const hasMoveableProjects = computed(() => moveableProjects.value.length > 0)
const isProjectDisabled = computed(
() => (project: WorkspaceMoveProjectManager_ProjectFragment) => {
if (project.permissions.canMoveToWorkspace.authorized) {
return false
}
return true
}
)
const getProjectTooltip = computed(
() => (project: WorkspaceMoveProjectManager_ProjectFragment) => {
if (project.permissions.canMoveToWorkspace.authorized) {
return undefined
}
return project.permissions.canMoveToWorkspace.message
}
)
const handleProjectClick = (project: WorkspaceMoveProjectManager_ProjectFragment) => {
const permission = project.permissions?.canMoveToWorkspace
if (permission?.code === 'WorkspaceLimitsReached') {
showLimitDialog.value = true
return
}
if (permission?.authorized) {
emit('project-selected', project)
}
}
const showLoading = computed(() => loading.value && userProjects.value.length === 0)
</script>