From 596312ab0e583de7088273bc5c48274b62fa4e41 Mon Sep 17 00:00:00 2001 From: Kristaps Fabians Geikins Date: Wed, 28 May 2025 12:12:18 +0300 Subject: [PATCH] feat(frontend): personal project limit disclaimers & prompts (#4822) * ProjectsAdd wrapper * WorkspaceMoveProject wrapper added * move wrapper finalized * passing through location * more cleanup * model add wrapper * permissions cleanup * add invite wrapper * vue-tippy bugfix * ViewerLimitsDialog prep * upgrade limit alert prep * limit alerts * movemanager fix * new add flow * slug update fix * add model flow * invites? * some extra fixes * move unmount fix? * more fixes * vue-tsc update * style: remove h-32 for smaller screens * vue-tsc parser fix * prep for new viewer limits dialog * updated viewer dialogs * comment variant cleanup * CR comments --------- Co-authored-by: michalspeckle --- package.json | 1 - .../global/illustration/ProjectShape.vue | 30 ++ .../components/project/InviteAdd.vue | 49 ++ .../project/model-page/Versions.vue | 7 +- .../project/model-page/versions/Card.vue | 24 +- .../components/project/models/Add.vue | 83 ++++ .../page/collaborators/Collaborators.vue | 24 +- .../page/latest-items/comments/Grid.vue | 7 +- .../page/latest-items/comments/GridItem.vue | 8 +- .../components/project/page/models/Header.vue | 65 +-- .../project/page/models/ListView.vue | 4 +- .../page/models/NewModelStructureItem.vue | 88 ---- .../project/page/models/StructureItem.vue | 15 +- .../frontend-2/components/projects/Add.vue | 101 ++++ .../components/projects/AddDialog.vue | 189 +++----- .../components/projects/Dashboard.vue | 49 +- .../projects/add-dialog/Metadata.vue | 123 +++++ .../projects/add-dialog/Workspace.vue | 28 ++ .../settings/shared/projects/index.vue | 61 ++- .../settings/workspaces/billing/Usage.vue | 2 +- .../components/viewer/PreSetupWrapper.vue | 36 +- .../viewer/anchored-point/thread/Comment.vue | 8 +- .../components/viewer/comments/ListItem.vue | 2 +- .../components/viewer/limits/Dialog.vue | 167 ++----- .../viewer/limits/WorkspaceDialog.vue | 123 +++++ .../viewer/resources/LimitAlert.vue | 50 ++ .../viewer/resources/PersonalLimitAlert.vue | 85 ++++ .../viewer/resources/UpgradeLimitAlert.vue | 57 ++- .../viewer/resources/VersionCard.vue | 40 +- .../components/workspace/AddProjectMenu.vue | 67 ++- .../workspace/moveProject/Confirm.vue | 4 +- .../workspace/moveProject/Intro.vue | 163 +++++++ .../workspace/moveProject/Manager.vue | 190 +++++--- .../workspace/moveProject/SelectProject.vue | 15 +- .../workspace/moveProject/SelectWorkspace.vue | 126 +++-- .../workspace/moveProject/index.vue | 116 +++++ .../lib/auth/composables/activeUser.ts | 1 + .../lib/common/composables/dialog.ts | 228 +++++++++ .../lib/common/composables/permissions.ts | 88 ++++ .../lib/common/generated/gql/gql.ts | 240 ++++++--- .../lib/common/generated/gql/graphql.ts | 194 +++++--- .../lib/common/helpers/permissions.ts | 2 + .../lib/projects/composables/permissions.ts | 147 ++++++ .../projects/composables/projectManagement.ts | 23 + .../lib/projects/graphql/fragments.ts | 1 + .../lib/projects/graphql/mutations.ts | 1 + .../lib/projects/graphql/queries.ts | 3 + .../frontend-2/lib/projects/helpers/limits.ts | 7 + .../lib/server-management/graphql/queries.ts | 3 - .../lib/user/composables/projectUpdates.ts | 18 +- .../lib/viewer/composables/resources.ts | 72 +++ .../frontend-2/lib/viewer/graphql/queries.ts | 1 + .../lib/workspaces/composables/limits.ts | 19 +- .../composables/projects/permissions.ts | 96 ++++ packages/frontend-2/package.json | 2 +- .../frontend-2/pages/projects/[id]/index.vue | 17 +- .../pages/settings/server/projects.vue | 16 +- .../settings/workspaces/[slug]/projects.vue | 33 +- packages/objectsender/package.json | 2 +- packages/ui-components/package.json | 2 +- .../src/components/layout/Dialog.vue | 8 +- yarn.lock | 459 ++++-------------- 62 files changed, 2686 insertions(+), 1204 deletions(-) create mode 100644 packages/frontend-2/components/global/illustration/ProjectShape.vue create mode 100644 packages/frontend-2/components/project/InviteAdd.vue create mode 100644 packages/frontend-2/components/project/models/Add.vue delete mode 100644 packages/frontend-2/components/project/page/models/NewModelStructureItem.vue create mode 100644 packages/frontend-2/components/projects/Add.vue create mode 100644 packages/frontend-2/components/projects/add-dialog/Metadata.vue create mode 100644 packages/frontend-2/components/projects/add-dialog/Workspace.vue create mode 100644 packages/frontend-2/components/viewer/limits/WorkspaceDialog.vue create mode 100644 packages/frontend-2/components/viewer/resources/LimitAlert.vue create mode 100644 packages/frontend-2/components/viewer/resources/PersonalLimitAlert.vue create mode 100644 packages/frontend-2/components/workspace/moveProject/Intro.vue create mode 100644 packages/frontend-2/components/workspace/moveProject/index.vue create mode 100644 packages/frontend-2/lib/common/composables/dialog.ts create mode 100644 packages/frontend-2/lib/common/composables/permissions.ts create mode 100644 packages/frontend-2/lib/common/helpers/permissions.ts create mode 100644 packages/frontend-2/lib/projects/composables/permissions.ts create mode 100644 packages/frontend-2/lib/projects/helpers/limits.ts create mode 100644 packages/frontend-2/lib/viewer/composables/resources.ts create mode 100644 packages/frontend-2/lib/workspaces/composables/projects/permissions.ts diff --git a/package.json b/package.json index 87fe21974..8b18a9e23 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,6 @@ "typescript": "^5.7.3", "typescript-eslint": "^8.20.0", "wait-on": ">=7.2.0", - "vue-tsc@npm:2.2.2/@vue/language-core": "2.2.0", "vitest": "^3.0.7" }, "config": { diff --git a/packages/frontend-2/components/global/illustration/ProjectShape.vue b/packages/frontend-2/components/global/illustration/ProjectShape.vue new file mode 100644 index 000000000..04aa70c1f --- /dev/null +++ b/packages/frontend-2/components/global/illustration/ProjectShape.vue @@ -0,0 +1,30 @@ + diff --git a/packages/frontend-2/components/project/InviteAdd.vue b/packages/frontend-2/components/project/InviteAdd.vue new file mode 100644 index 000000000..3199d9cd7 --- /dev/null +++ b/packages/frontend-2/components/project/InviteAdd.vue @@ -0,0 +1,49 @@ + + diff --git a/packages/frontend-2/components/project/model-page/Versions.vue b/packages/frontend-2/components/project/model-page/Versions.vue index 43c29eb54..eefe9a464 100644 --- a/packages/frontend-2/components/project/model-page/Versions.vue +++ b/packages/frontend-2/components/project/model-page/Versions.vue @@ -38,8 +38,7 @@ v-model:selected="itemsSelectedState[item.id]" :version="item" :model-id="project.model.id" - :project-id="project.id" - :workspace-slug="project.workspace?.slug" + :project="project" :style="`z-index: ${items.length - i};`" :selectable="!!selectedItems.length" :selection-disabled="disabledSelections[item.id]" @@ -51,8 +50,7 @@ v-else :version="item" :model-id="project.model.id" - :project-id="project.id" - :workspace-slug="project.workspace?.slug" + :project="project" :style="`z-index: ${items.length - i};`" /> @@ -130,6 +128,7 @@ graphql(` } ...ProjectsModelPageEmbed_Project ...ProjectCardImportFileArea_Project + ...ProjectModelPageVersionsCard_Project } `) diff --git a/packages/frontend-2/components/project/model-page/versions/Card.vue b/packages/frontend-2/components/project/model-page/versions/Card.vue index c95a2bd82..5591643ef 100644 --- a/packages/frontend-2/components/project/model-page/versions/Card.vue +++ b/packages/frontend-2/components/project/model-page/versions/Card.vue @@ -17,7 +17,7 @@ -
() const isAutomateModuleEnabled = useIsAutomateModuleEnabled() @@ -188,7 +200,7 @@ const viewerRoute = computed(() => { const resourceIdString = SpeckleViewer.ViewerRoute.resourceBuilder() .addModel(props.modelId, props.version.id) .toString() - return modelRoute(props.projectId, resourceIdString) + return modelRoute(props.project.id, resourceIdString) }) const sourceApp = computed(() => diff --git a/packages/frontend-2/components/project/models/Add.vue b/packages/frontend-2/components/project/models/Add.vue new file mode 100644 index 000000000..6d489dac0 --- /dev/null +++ b/packages/frontend-2/components/project/models/Add.vue @@ -0,0 +1,83 @@ + + diff --git a/packages/frontend-2/components/project/page/collaborators/Collaborators.vue b/packages/frontend-2/components/project/page/collaborators/Collaborators.vue index b4ad0c226..fa659ab33 100644 --- a/packages/frontend-2/components/project/page/collaborators/Collaborators.vue +++ b/packages/frontend-2/components/project/page/collaborators/Collaborators.vue @@ -3,7 +3,7 @@

Collaborators

-
+
Invite to project @@ -40,11 +40,7 @@
- +
@@ -65,6 +61,8 @@ import { useCancelProjectInvite, useUpdateUserRole } from '~~/lib/projects/composables/projectManagement' +import { useCanInviteToProject } from '~/lib/projects/composables/permissions' +import { PersonalProjectsLimitedError } from '@speckle/shared/authz' graphql(` fragment ProjectPageCollaborators_Project on Project { @@ -74,6 +72,7 @@ graphql(` ...FullPermissionCheckResult } } + ...ProjectInviteAdd_Project } `) @@ -111,19 +110,28 @@ const route = useRoute() const apollo = useApolloClient().client const mixpanel = useMixpanel() const cancelInvite = useCancelProjectInvite() + const { result: pageResult } = useQuery(projectPageCollaboratorsQuery, () => ({ projectId: projectId.value, filter: { roles: [Roles.Workspace.Admin] } })) +const canInviteToProject = useCanInviteToProject({ + project: computed(() => pageResult.value?.project) +}) const showInviteDialog = ref(false) const loading = ref(false) const canUpdate = computed(() => pageResult.value?.project?.permissions?.canUpdate) -const canInvite = computed(() => project.value?.permissions?.canInvite?.authorized) -const tooltipText = computed(() => +const canInvite = computed(() => { + return ( + canInviteToProject.canActuallyInvite.value || + canInviteToProject.cantClickInviteCode.value === PersonalProjectsLimitedError.code + ) +}) +const canInviteTooltip = computed(() => canInvite.value ? undefined : project.value?.permissions?.canInvite?.message ) const project = computed(() => pageResult.value?.project) diff --git a/packages/frontend-2/components/project/page/latest-items/comments/Grid.vue b/packages/frontend-2/components/project/page/latest-items/comments/Grid.vue index 81ad65ad3..b8e40c062 100644 --- a/packages/frontend-2/components/project/page/latest-items/comments/Grid.vue +++ b/packages/frontend-2/components/project/page/latest-items/comments/Grid.vue @@ -1,12 +1,13 @@ @@ -92,6 +92,9 @@ import { useDebouncedTextInput, type InfiniteLoaderState } from '@speckle/ui-com import { MagnifyingGlassIcon, Squares2X2Icon } from '@heroicons/vue/24/outline' import { useUserProjectsUpdatedTracking } from '~~/lib/user/composables/projectUpdates' import { useMixpanel } from '~/lib/core/composables/mp' +import { useCanCreatePersonalProject } from '~~/lib/projects/composables/permissions' +import type { ProjectsDashboardQueryQuery } from '~/lib/common/generated/gql/graphql' +import type { Get } from 'type-fest' graphql(` fragment ProjectsDashboard_UserProjectCollection on UserProjectCollection { @@ -101,6 +104,7 @@ graphql(` graphql(` fragment ProjectsDashboard_User on User { + ...ProjectsAdd_User permissions { canCreatePersonalProject { ...FullPermissionCheckResult @@ -115,12 +119,13 @@ const infiniteLoaderId = ref('') const cursor = ref(null as Nullable) const selectedRoles = ref(undefined as Optional) const filterProjectsToMove = ref(false) -const openNewProject = ref(false) const showLoadingBar = ref(false) const showMoveProjectDialog = ref(false) -const emittedProjectId = ref>(null) +const emittedProject = + ref>() const areQueriesLoading = useQueryLoading() const isWorkspacesEnabled = useIsWorkspacesEnabled() +const showCreateNewProjectDialog = ref(false) useUserProjectsUpdatedTracking() const { @@ -149,14 +154,15 @@ const { cursor: null as Nullable })) +const { canClickCreate } = useCanCreatePersonalProject({ + activeUser: computed(() => projectsPanelResult.value?.activeUser) +}) + onProjectsResult((res) => { cursor.value = res.data?.activeUser?.projects.cursor || null infiniteLoaderId.value = JSON.stringify(projectsVariables.value?.filter || {}) }) -const canCreatePersonalProject = computed( - () => projectsPanelResult.value?.activeUser?.permissions?.canCreatePersonalProject -) const projects = computed(() => projectsPanelResult.value?.activeUser?.projects) const showEmptyState = computed(() => { const isFiltering = @@ -196,13 +202,16 @@ const infiniteLoad = async (state: InfiniteLoaderState) => { const mixpanel = useMixpanel() -const onMoveProject = (projectId: string, location: string) => { - emittedProjectId.value = projectId +const onMoveProject = (projectId: string | undefined, location: string) => { + const project = projectId + ? projects.value?.items.find((p) => p.id === projectId) + : undefined + emittedProject.value = project || undefined + mixpanel.track('Move Project CTA Clicked', { location, // eslint-disable-next-line camelcase - workspace_id: - projects.value?.items.find((p) => p.id === projectId)?.workspace?.id || undefined + workspace_id: project?.workspace?.id || undefined }) showMoveProjectDialog.value = true } @@ -218,4 +227,8 @@ const clearSearch = () => { search.value = '' selectedRoles.value = [] } + +const onClickCreate = () => { + showCreateNewProjectDialog.value = true +} diff --git a/packages/frontend-2/components/projects/add-dialog/Metadata.vue b/packages/frontend-2/components/projects/add-dialog/Metadata.vue new file mode 100644 index 000000000..c5a22106a --- /dev/null +++ b/packages/frontend-2/components/projects/add-dialog/Metadata.vue @@ -0,0 +1,123 @@ + + diff --git a/packages/frontend-2/components/projects/add-dialog/Workspace.vue b/packages/frontend-2/components/projects/add-dialog/Workspace.vue new file mode 100644 index 000000000..9d42e2f72 --- /dev/null +++ b/packages/frontend-2/components/projects/add-dialog/Workspace.vue @@ -0,0 +1,28 @@ + + diff --git a/packages/frontend-2/components/settings/shared/projects/index.vue b/packages/frontend-2/components/settings/shared/projects/index.vue index 7eabd7164..daf80fab6 100644 --- a/packages/frontend-2/components/settings/shared/projects/index.vue +++ b/packages/frontend-2/components/settings/shared/projects/index.vue @@ -12,8 +12,8 @@ v-on="on" /> -
- +
+ Create
@@ -93,7 +93,7 @@ :project="projectToModify" /> - +
@@ -101,7 +101,8 @@ import { HorizontalDirection } from '~~/lib/common/composables/window' import type { SettingsSharedProjects_ProjectFragment, - ProjectsDeleteDialog_ProjectFragment + ProjectsDeleteDialog_ProjectFragment, + SettingsSharedProjects_WorkspaceFragment } from '~~/lib/common/generated/gql/graphql' import { MagnifyingGlassIcon, @@ -113,6 +114,9 @@ import { useDebouncedTextInput, type LayoutMenuItem } from '@speckle/ui-componen import { graphql } from '~/lib/common/generated/gql' import { useRouter } from 'vue-router' import { projectRoute } from '~/lib/common/helpers/route' +import { useCanCreatePersonalProject } from '~/lib/projects/composables/permissions' +import { useCanCreateWorkspaceProject } from '~/lib/workspaces/composables/projects/permissions' +import type { MaybeNullOrUndefined } from '@speckle/shared' graphql(` fragment SettingsSharedProjects_Project on Project { @@ -150,17 +154,42 @@ graphql(` } `) +graphql(` + fragment SettingsSharedProjects_Workspace on Workspace { + id + ...ProjectsAdd_Workspace + } +`) + const props = defineProps<{ - projects?: SettingsSharedProjects_ProjectFragment[] - workspaceId?: string - disableCreate?: boolean - disabledTooltip?: string - limitReached?: boolean + workspaceId: MaybeNullOrUndefined + projects: MaybeNullOrUndefined + workspace: MaybeNullOrUndefined }>() -const emit = defineEmits<{ - (e: 'project-limit-reached'): void -}>() +const { activeUser } = useActiveUser() +const canCreatePersonal = useCanCreatePersonalProject({ + activeUser: computed(() => activeUser.value) +}) + +const canCreateWorkspace = useCanCreateWorkspaceProject({ + workspace: computed(() => props.workspace) +}) + +const isCreateDisabled = computed(() => { + if (props.workspaceId) { + return !canCreateWorkspace.canClickCreate.value + } + + return !canCreatePersonal.canClickCreate.value +}) +const createDisabledTooltip = computed(() => { + if (props.workspaceId) { + return canCreateWorkspace.cantClickCreateReason.value + } + + return canCreatePersonal.cantClickCreateReason.value +}) const search = defineModel('search') const { on, bind } = useDebouncedTextInput({ model: search }) @@ -236,12 +265,4 @@ const onActionChosen = ( const toggleMenu = (itemId: string) => { showActionsMenu.value[itemId] = !showActionsMenu.value[itemId] } - -const handleCreateProject = () => { - if (props.limitReached) { - emit('project-limit-reached') - } else { - openNewProject.value = true - } -} diff --git a/packages/frontend-2/components/settings/workspaces/billing/Usage.vue b/packages/frontend-2/components/settings/workspaces/billing/Usage.vue index 33afe5b0d..e75a2eaab 100644 --- a/packages/frontend-2/components/settings/workspaces/billing/Usage.vue +++ b/packages/frontend-2/components/settings/workspaces/billing/Usage.vue @@ -94,7 +94,7 @@ const props = defineProps<{ }>() const { projectCount, modelCount } = useWorkspaceUsage(props.slug) -const { limits } = useWorkspaceLimits(props.slug) +const { limits } = useWorkspaceLimits({ slug: computed(() => props.slug) }) const { seats, statusIsCanceled, isSelfServePlan } = useWorkspacePlan(props.slug) const formatUsageText = (current: number, max: number, type: string) => { diff --git a/packages/frontend-2/components/viewer/PreSetupWrapper.vue b/packages/frontend-2/components/viewer/PreSetupWrapper.vue index 74217a9b6..cf1240b80 100644 --- a/packages/frontend-2/components/viewer/PreSetupWrapper.vue +++ b/packages/frontend-2/components/viewer/PreSetupWrapper.vue @@ -55,11 +55,9 @@ @@ -127,6 +125,7 @@ import { projectsRoute, workspaceRoute } from '~~/lib/common/helpers/route' import { useMixpanel } from '~/lib/core/composables/mp' import { writableAsyncComputed } from '~/lib/common/composables/async' import { parseUrlParameters, resourceBuilder } from '@speckle/shared/viewer/route' +import { ViewerLimitsDialogType } from '~/lib/projects/helpers/limits' graphql(` fragment ModelPageProject on Project { @@ -144,6 +143,7 @@ graphql(` hideSpeckleBranding } hasAccessToFeature(featureName: hideSpeckleBranding) + ...ViewerLimitsDialog_Project } `) @@ -188,13 +188,12 @@ emit('setup', state) const { resources: { - response: { project, resourceItems, modelsAndVersionIds } - }, - urlHashState: { focusedThreadId } + response: { project, modelsAndVersionIds } + } } = state const showLimitsDialog = ref(false) -const limitsDialogType = ref<'version' | 'comment' | 'federated'>('version') +const limitsDialogType = ref(ViewerLimitsDialogType.Version) // Check for missing referencedObject in url referenced versions (out of plan limits) const hasMissingReferencedObject = computed(() => { @@ -222,19 +221,6 @@ const hasMissingReferencedObject = computed(() => { return result }) -// Check for missing thread when a specific threadId is present in URL -const hasMissingThread = computed(() => { - const threadIdFromUrl = focusedThreadId.value - - if (!threadIdFromUrl) return false - - const thread = state.resources.response.commentThreads.value.find( - (thread) => thread.id === threadIdFromUrl - ) - - return !thread || !thread.rawText -}) - const isFederated = computed( () => state.resources.response.resourceItems.value.length > 1 ) @@ -294,8 +280,8 @@ onMounted(() => { // Watch for plan limit conditions and show dialog if needed watch( - [hasMissingReferencedObject, hasMissingThread, resourceItems, project], - ([missingObject, missingThread]) => { + [hasMissingReferencedObject], + ([missingObject]) => { if (missingObject) { if (isFederated.value) { limitsDialogType.value = 'federated' @@ -303,10 +289,6 @@ watch( limitsDialogType.value = 'version' } showLimitsDialog.value = true - return - } else if (missingThread && isFederated.value && hasMissingReferencedObject.value) { - limitsDialogType.value = 'comment' - showLimitsDialog.value = true } else { showLimitsDialog.value = false } diff --git a/packages/frontend-2/components/viewer/anchored-point/thread/Comment.vue b/packages/frontend-2/components/viewer/anchored-point/thread/Comment.vue index 2d76cb72e..08db1f9ec 100644 --- a/packages/frontend-2/components/viewer/anchored-point/thread/Comment.vue +++ b/packages/frontend-2/components/viewer/anchored-point/thread/Comment.vue @@ -22,7 +22,7 @@ :class="isEmbedEnabled ? 'mt-2' : 'mt-3'" > diff --git a/packages/frontend-2/components/viewer/resources/LimitAlert.vue b/packages/frontend-2/components/viewer/resources/LimitAlert.vue new file mode 100644 index 000000000..9b97a5b39 --- /dev/null +++ b/packages/frontend-2/components/viewer/resources/LimitAlert.vue @@ -0,0 +1,50 @@ + + diff --git a/packages/frontend-2/components/viewer/resources/PersonalLimitAlert.vue b/packages/frontend-2/components/viewer/resources/PersonalLimitAlert.vue new file mode 100644 index 000000000..6d9cc5bf2 --- /dev/null +++ b/packages/frontend-2/components/viewer/resources/PersonalLimitAlert.vue @@ -0,0 +1,85 @@ + + diff --git a/packages/frontend-2/components/viewer/resources/UpgradeLimitAlert.vue b/packages/frontend-2/components/viewer/resources/UpgradeLimitAlert.vue index 5b8b99d31..8f448c7b5 100644 --- a/packages/frontend-2/components/viewer/resources/UpgradeLimitAlert.vue +++ b/packages/frontend-2/components/viewer/resources/UpgradeLimitAlert.vue @@ -1,27 +1,60 @@ diff --git a/packages/frontend-2/components/viewer/resources/VersionCard.vue b/packages/frontend-2/components/viewer/resources/VersionCard.vue index f06c92969..7d3b07794 100644 --- a/packages/frontend-2/components/viewer/resources/VersionCard.vue +++ b/packages/frontend-2/components/viewer/resources/VersionCard.vue @@ -75,26 +75,18 @@
-
- Upgrade to view versions older than the {{ versionLimitFormatted }} limit. -
+ limit-type="version" + variant="inline" + :project="project" + />
{{ version.message || 'no message' }}
- - Upgrade -
{{ version.sourceApplication }} @@ -108,11 +100,9 @@ import { ChevronDownIcon, LockClosedIcon } from '@heroicons/vue/24/solid' import { keyboardClick } from '@speckle/ui-components' import dayjs from 'dayjs' import localizedFormat from 'dayjs/plugin/localizedFormat' +import { useInjectedViewerState } from '~/lib/viewer/composables/setup' import type { ViewerModelVersionCardItemFragment } from '~~/lib/common/generated/gql/graphql' import { useMixpanel } from '~~/lib/core/composables/mp' -import { settingsWorkspaceRoutes } from '~/lib/common/helpers/route' -import { useNavigation } from '~/lib/navigation/composables/navigation' -import { useWorkspaceLimits } from '~/lib/workspaces/composables/limits' dayjs.extend(localizedFormat) @@ -141,8 +131,11 @@ const emit = defineEmits<{ }>() const mp = useMixpanel() -const { activeWorkspaceSlug } = useNavigation() -const { versionLimitFormatted } = useWorkspaceLimits(activeWorkspaceSlug.value || '') +const { + resources: { + response: { project } + } +} = useInjectedViewerState() const isLoaded = computed(() => props.isLoadedVersion) const isLatest = computed(() => props.isLatestVersion) @@ -178,13 +171,4 @@ const handleViewChanges = () => { action: 'enable' }) } - -const handleUpgradeClick = () => { - mp.track('Hidden Version Upgrade Button Clicked', { - location: 'viewer', - // eslint-disable-next-line camelcase - workspace_id: activeWorkspaceSlug.value - }) - navigateTo(settingsWorkspaceRoutes.billing.route(activeWorkspaceSlug.value || '')) -} diff --git a/packages/frontend-2/components/workspace/AddProjectMenu.vue b/packages/frontend-2/components/workspace/AddProjectMenu.vue index 3e5dfd758..089c2a86f 100644 --- a/packages/frontend-2/components/workspace/AddProjectMenu.vue +++ b/packages/frontend-2/components/workspace/AddProjectMenu.vue @@ -28,36 +28,31 @@ Add project - + - - - -
+ diff --git a/packages/frontend-2/components/workspace/moveProject/Manager.vue b/packages/frontend-2/components/workspace/moveProject/Manager.vue index ef71649c3..483b0a9da 100644 --- a/packages/frontend-2/components/workspace/moveProject/Manager.vue +++ b/packages/frontend-2/components/workspace/moveProject/Manager.vue @@ -1,8 +1,27 @@