diff --git a/packages/frontend-2/components/project/page/models/Tab.vue b/packages/frontend-2/components/project/page/models/Tab.vue index 216009160..6691296e0 100644 --- a/packages/frontend-2/components/project/page/models/Tab.vue +++ b/packages/frontend-2/components/project/page/models/Tab.vue @@ -10,16 +10,57 @@ :disabled="loading" class="z-[1] relative" /> - +
+ + +
+ Drop file to upload +
+
+ + +
+ +
+ + @@ -29,6 +70,11 @@ import type { SourceAppDefinition } from '@speckle/shared' import type { FormUsersSelectItemFragment } from '~~/lib/common/generated/gql/graphql' import { projectModelsPageQuery } from '~~/lib/projects/graphql/queries' import { useProjectPageItemViewType } from '~~/lib/projects/composables/projectPages' +import { + useFileImport, + useGlobalFileImportManager +} from '~~/lib/core/composables/fileImport' +import type { ProjectPageLatestItemsModelItemFragment } from '~/lib/common/generated/gql/graphql' const route = useRoute() const projectId = computed(() => route.params.id as string) @@ -45,9 +91,69 @@ const { result } = useQuery(projectModelsPageQuery, () => ({ const project = computed(() => result.value?.project) +// File upload logic +const { addFailedJob } = useGlobalFileImportManager() +const showNewModelDialog = ref(false) + +const { + maxSizeInBytes, + onFilesSelected, + accept, + upload: fileUpload, + isUploading, + uploadSelected, + resetSelected, + isUploadable: isFileUploadUploadable +} = useFileImport({ + project: computed(() => project.value || { id: '' }), + manuallyTriggerUpload: true, + fileSelectedCallback: () => { + if (!fileUpload.value?.error) { + // Only if upload is valid, trigger model creation dialog + showNewModelDialog.value = true + } + }, + errorCallback: ({ failedJob }) => { + // Register global file upload error and reset upload + addFailedJob(failedJob) + resetSelected() + } +}) + +const canCreateModel = computed( + () => project.value?.permissions?.canCreateModel?.authorized ?? false +) + +const hasModels = computed(() => (project.value?.models?.totalCount ?? 0) > 0) + +const onModelCreate = (params: { model: ProjectPageLatestItemsModelItemFragment }) => { + if (!isFileUploadUploadable.value) return + + uploadSelected({ + model: params.model + }) +} + const clearSearch = () => { search.value = '' selectedMembers.value = [] selectedApps.value = [] } + +// Watch for upload completion to reset state +watch(isUploading, (newVal, oldVal) => { + if (!newVal && oldVal) { + // Reset file upload state when upload finishes + resetSelected() + } +}) + +watch(showNewModelDialog, (newVal, oldVal) => { + if (oldVal && !newVal) { + // Unselect file if model was not created + if (!isUploading.value) { + resetSelected() + } + } +})