Move to composable
This commit is contained in:
@@ -54,6 +54,11 @@
|
||||
:variant="RegionStaticDataDisclaimerVariant.MoveProjectIntoWorkspace"
|
||||
@confirm="onConfirmHandler"
|
||||
/>
|
||||
<WorkspacePlanLimitReachedDialog
|
||||
v-model:open="showLimitReachedDialog"
|
||||
:limit="limit"
|
||||
:limit-type="limitType"
|
||||
/>
|
||||
</LayoutDialog>
|
||||
</template>
|
||||
|
||||
@@ -72,6 +77,7 @@ import {
|
||||
useWorkspaceCustomDataResidencyDisclaimer,
|
||||
RegionStaticDataDisclaimerVariant
|
||||
} from '~/lib/workspaces/composables/region'
|
||||
import { useWorkspacePlanLimits } from '~/lib/workspaces/composables/plan'
|
||||
|
||||
graphql(`
|
||||
fragment ProjectsMoveToWorkspaceDialog_Workspace on Workspace {
|
||||
@@ -129,8 +135,13 @@ const { result } = useQuery(query, null, () => ({
|
||||
}))
|
||||
const loading = useMutationLoading()
|
||||
const moveProject = useMoveProjectToWorkspace()
|
||||
const { getLimitType, getLimit } = useWorkspacePlanLimits(props.workspace?.slug || '')
|
||||
|
||||
const selectedWorkspace = ref<ProjectsMoveToWorkspaceDialog_WorkspaceFragment>()
|
||||
const showLimitReachedDialog = ref(false)
|
||||
|
||||
const limitType = computed(() => getLimitType(props.project))
|
||||
const limit = computed(() => getLimit(limitType.value))
|
||||
|
||||
const workspaces = computed(() => result.value?.activeUser?.workspaces.items ?? [])
|
||||
const hasWorkspaces = computed(() => workspaces.value.length > 0)
|
||||
@@ -156,7 +167,7 @@ const dialogButtons = computed<LayoutDialogButton[]>(() => {
|
||||
color: 'primary',
|
||||
disabled: (!selectedWorkspace.value && !props.workspace) || loading.value
|
||||
},
|
||||
onClick: () => triggerAction()
|
||||
onClick: () => onMoveClick()
|
||||
}
|
||||
]
|
||||
: [
|
||||
@@ -201,4 +212,12 @@ watch(
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const onMoveClick = () => {
|
||||
if (limitType.value) {
|
||||
showLimitReachedDialog.value = true
|
||||
} else {
|
||||
triggerAction()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -136,23 +136,6 @@ const open = defineModel<boolean>('open', { required: true })
|
||||
const search = defineModel<string>('search')
|
||||
const { on, bind } = useDebouncedTextInput({ model: search })
|
||||
|
||||
// TODO: Get these from the workspace plan composable
|
||||
const projectLimit = computed(() => {
|
||||
return 3
|
||||
})
|
||||
const modelLimit = computed(() => {
|
||||
return 8
|
||||
})
|
||||
const projectCount = computed(() => {
|
||||
return 1
|
||||
})
|
||||
const modelCount = computed(() => {
|
||||
return 2
|
||||
})
|
||||
|
||||
const remainingProjects = computed(() => projectLimit.value - projectCount.value)
|
||||
const remainingModels = computed(() => modelLimit.value - modelCount.value)
|
||||
|
||||
const {
|
||||
query: { result },
|
||||
identifier,
|
||||
@@ -180,6 +163,23 @@ const selectedProject = ref<ProjectsMoveToWorkspaceDialog_ProjectFragment | null
|
||||
const showMoveToWorkspaceDialog = ref(false)
|
||||
const showLimitReachedDialog = ref(false)
|
||||
|
||||
// TODO: Get these from the workspace plan composable
|
||||
const projectLimit = computed(() => {
|
||||
return 3
|
||||
})
|
||||
const modelLimit = computed(() => {
|
||||
return 8
|
||||
})
|
||||
const projectCount = computed(() => {
|
||||
return 1
|
||||
})
|
||||
const modelCount = computed(() => {
|
||||
return 2
|
||||
})
|
||||
|
||||
const remainingProjects = computed(() => projectLimit.value - projectCount.value)
|
||||
const remainingModels = computed(() => modelLimit.value - modelCount.value)
|
||||
|
||||
const workspaceProjects = computed(() =>
|
||||
props.workspace.projects.items.map((project) => project.id)
|
||||
)
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<LayoutDialog v-model:open="isOpen" is-transparent max-width="lg">
|
||||
<div class="flex items-stretch">
|
||||
<div class="w-1/2 bg-primary p-6">Left</div>
|
||||
<div class="w-1/2 bg-foundation p-6 flex flex-col gap-y-8">
|
||||
<div class="flex flex-col gap-y-2 mt-8 px-4">
|
||||
<div class="w-1/2 bg-foundation p-6 flex flex-col gap-y-10">
|
||||
<div class="flex flex-col gap-y-2 mt-6 px-4">
|
||||
<h4 class="text-heading-sm text-foreground">Upgrade your plan</h4>
|
||||
<p class="text-foreground">
|
||||
The {{ props.limit }} {{ props.limitType }} limit for this workspace has
|
||||
@@ -24,6 +24,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Nullable } from '@speckle/shared'
|
||||
import { LayoutDialog } from '@speckle/ui-components'
|
||||
import { settingsWorkspaceRoutes } from '~/lib/common/helpers/route'
|
||||
|
||||
@@ -31,6 +32,6 @@ const isOpen = defineModel<boolean>('open', { required: true })
|
||||
|
||||
const props = defineProps<{
|
||||
limit: number
|
||||
limitType: 'project' | 'model'
|
||||
limitType: Nullable<'project' | 'model'>
|
||||
}>()
|
||||
</script>
|
||||
|
||||
@@ -375,6 +375,7 @@ type Documents = {
|
||||
"\n fragment DiscoverableList_Requests on User {\n workspaceJoinRequests {\n items {\n id\n status\n workspace {\n id\n name\n logo\n slug\n team {\n totalCount\n items {\n avatar\n }\n }\n }\n }\n }\n }\n": typeof types.DiscoverableList_RequestsFragmentDoc,
|
||||
"\n fragment UseWorkspaceInviteManager_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n token\n workspaceId\n workspaceSlug\n user {\n id\n }\n }\n": typeof types.UseWorkspaceInviteManager_PendingWorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment WorkspacesPlan_Workspace on Workspace {\n id\n plan {\n status\n createdAt\n name\n paymentMethod\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n seats {\n totalCount\n assigned\n viewersCount\n }\n }\n }\n": typeof types.WorkspacesPlan_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspacePlanLimits_Workspace on Workspace {\n id\n projects {\n totalCount\n items {\n id\n models(limit: 0) {\n totalCount\n }\n }\n }\n plan {\n name\n }\n }\n": typeof types.WorkspacePlanLimits_WorkspaceFragmentDoc,
|
||||
"\n subscription OnWorkspaceProjectsUpdate($slug: String!) {\n workspaceProjectsUpdated(workspaceId: null, workspaceSlug: $slug) {\n projectId\n workspaceId\n type\n project {\n ...ProjectDashboardItem\n }\n }\n }\n ": typeof types.OnWorkspaceProjectsUpdateDocument,
|
||||
"\n fragment WorkspaceHasCustomDataResidency_Workspace on Workspace {\n id\n defaultRegion {\n id\n name\n }\n }\n": typeof types.WorkspaceHasCustomDataResidency_WorkspaceFragmentDoc,
|
||||
"\n query CheckProjectWorkspaceDataResidency($projectId: String!) {\n project(id: $projectId) {\n id\n workspace {\n ...WorkspaceHasCustomDataResidency_Workspace\n }\n }\n }\n": typeof types.CheckProjectWorkspaceDataResidencyDocument,
|
||||
@@ -413,6 +414,7 @@ type Documents = {
|
||||
"\n query DiscoverableWorkspacesRequests {\n activeUser {\n id\n ...DiscoverableList_Requests\n }\n }\n": typeof types.DiscoverableWorkspacesRequestsDocument,
|
||||
"\n query WorkspacePlan($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacesPlan_Workspace\n }\n }\n": typeof types.WorkspacePlanDocument,
|
||||
"\n query WorkspaceLastAdminCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspaceLastAdminCheck_Workspace\n }\n }\n": typeof types.WorkspaceLastAdminCheckDocument,
|
||||
"\n query WorkspacePlanLimits($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacePlanLimits_Workspace\n }\n }\n": typeof types.WorkspacePlanLimitsDocument,
|
||||
"\n subscription onWorkspaceUpdated(\n $workspaceId: String\n $workspaceSlug: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceUpdated(workspaceId: $workspaceId, workspaceSlug: $workspaceSlug) {\n id\n workspace {\n id\n ...WorkspaceProjectList_Workspace\n }\n }\n }\n": typeof types.OnWorkspaceUpdatedDocument,
|
||||
"\n query LegacyBranchRedirectMetadata($streamId: String!, $branchName: String!) {\n project(id: $streamId) {\n modelByName(name: $branchName) {\n id\n }\n }\n }\n": typeof types.LegacyBranchRedirectMetadataDocument,
|
||||
"\n query LegacyViewerCommitRedirectMetadata($streamId: String!, $commitId: String!) {\n project(id: $streamId) {\n version(id: $commitId) {\n id\n model {\n id\n }\n }\n }\n }\n": typeof types.LegacyViewerCommitRedirectMetadataDocument,
|
||||
@@ -797,6 +799,7 @@ const documents: Documents = {
|
||||
"\n fragment DiscoverableList_Requests on User {\n workspaceJoinRequests {\n items {\n id\n status\n workspace {\n id\n name\n logo\n slug\n team {\n totalCount\n items {\n avatar\n }\n }\n }\n }\n }\n }\n": types.DiscoverableList_RequestsFragmentDoc,
|
||||
"\n fragment UseWorkspaceInviteManager_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n token\n workspaceId\n workspaceSlug\n user {\n id\n }\n }\n": types.UseWorkspaceInviteManager_PendingWorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment WorkspacesPlan_Workspace on Workspace {\n id\n plan {\n status\n createdAt\n name\n paymentMethod\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n seats {\n totalCount\n assigned\n viewersCount\n }\n }\n }\n": types.WorkspacesPlan_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspacePlanLimits_Workspace on Workspace {\n id\n projects {\n totalCount\n items {\n id\n models(limit: 0) {\n totalCount\n }\n }\n }\n plan {\n name\n }\n }\n": types.WorkspacePlanLimits_WorkspaceFragmentDoc,
|
||||
"\n subscription OnWorkspaceProjectsUpdate($slug: String!) {\n workspaceProjectsUpdated(workspaceId: null, workspaceSlug: $slug) {\n projectId\n workspaceId\n type\n project {\n ...ProjectDashboardItem\n }\n }\n }\n ": types.OnWorkspaceProjectsUpdateDocument,
|
||||
"\n fragment WorkspaceHasCustomDataResidency_Workspace on Workspace {\n id\n defaultRegion {\n id\n name\n }\n }\n": types.WorkspaceHasCustomDataResidency_WorkspaceFragmentDoc,
|
||||
"\n query CheckProjectWorkspaceDataResidency($projectId: String!) {\n project(id: $projectId) {\n id\n workspace {\n ...WorkspaceHasCustomDataResidency_Workspace\n }\n }\n }\n": types.CheckProjectWorkspaceDataResidencyDocument,
|
||||
@@ -835,6 +838,7 @@ const documents: Documents = {
|
||||
"\n query DiscoverableWorkspacesRequests {\n activeUser {\n id\n ...DiscoverableList_Requests\n }\n }\n": types.DiscoverableWorkspacesRequestsDocument,
|
||||
"\n query WorkspacePlan($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacesPlan_Workspace\n }\n }\n": types.WorkspacePlanDocument,
|
||||
"\n query WorkspaceLastAdminCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspaceLastAdminCheck_Workspace\n }\n }\n": types.WorkspaceLastAdminCheckDocument,
|
||||
"\n query WorkspacePlanLimits($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacePlanLimits_Workspace\n }\n }\n": types.WorkspacePlanLimitsDocument,
|
||||
"\n subscription onWorkspaceUpdated(\n $workspaceId: String\n $workspaceSlug: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceUpdated(workspaceId: $workspaceId, workspaceSlug: $workspaceSlug) {\n id\n workspace {\n id\n ...WorkspaceProjectList_Workspace\n }\n }\n }\n": types.OnWorkspaceUpdatedDocument,
|
||||
"\n query LegacyBranchRedirectMetadata($streamId: String!, $branchName: String!) {\n project(id: $streamId) {\n modelByName(name: $branchName) {\n id\n }\n }\n }\n": types.LegacyBranchRedirectMetadataDocument,
|
||||
"\n query LegacyViewerCommitRedirectMetadata($streamId: String!, $commitId: String!) {\n project(id: $streamId) {\n version(id: $commitId) {\n id\n model {\n id\n }\n }\n }\n }\n": types.LegacyViewerCommitRedirectMetadataDocument,
|
||||
@@ -2316,6 +2320,10 @@ export function graphql(source: "\n fragment UseWorkspaceInviteManager_PendingW
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment WorkspacesPlan_Workspace on Workspace {\n id\n plan {\n status\n createdAt\n name\n paymentMethod\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n seats {\n totalCount\n assigned\n viewersCount\n }\n }\n }\n"): (typeof documents)["\n fragment WorkspacesPlan_Workspace on Workspace {\n id\n plan {\n status\n createdAt\n name\n paymentMethod\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n seats {\n totalCount\n assigned\n viewersCount\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment WorkspacePlanLimits_Workspace on Workspace {\n id\n projects {\n totalCount\n items {\n id\n models(limit: 0) {\n totalCount\n }\n }\n }\n plan {\n name\n }\n }\n"): (typeof documents)["\n fragment WorkspacePlanLimits_Workspace on Workspace {\n id\n projects {\n totalCount\n items {\n id\n models(limit: 0) {\n totalCount\n }\n }\n }\n plan {\n name\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -2468,6 +2476,10 @@ export function graphql(source: "\n query WorkspacePlan($slug: String!) {\n
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n query WorkspaceLastAdminCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspaceLastAdminCheck_Workspace\n }\n }\n"): (typeof documents)["\n query WorkspaceLastAdminCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspaceLastAdminCheck_Workspace\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n query WorkspacePlanLimits($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacePlanLimits_Workspace\n }\n }\n"): (typeof documents)["\n query WorkspacePlanLimits($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacePlanLimits_Workspace\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,8 @@
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import { workspacePlanQuery } from '~~/lib/workspaces/graphql/queries'
|
||||
import {
|
||||
workspacePlanLimitsQuery,
|
||||
workspacePlanQuery
|
||||
} from '~~/lib/workspaces/graphql/queries'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import {
|
||||
isNewWorkspacePlan,
|
||||
@@ -32,6 +35,24 @@ graphql(`
|
||||
}
|
||||
`)
|
||||
|
||||
graphql(`
|
||||
fragment WorkspacePlanLimits_Workspace on Workspace {
|
||||
id
|
||||
projects {
|
||||
totalCount
|
||||
items {
|
||||
id
|
||||
models(limit: 0) {
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
plan {
|
||||
name
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
export const useWorkspacePlan = (slug: string) => {
|
||||
const isBillingIntegrationEnabled = useIsBillingIntegrationEnabled()
|
||||
|
||||
@@ -137,3 +158,61 @@ export const useWorkspacePlan = (slug: string) => {
|
||||
editorSeats
|
||||
}
|
||||
}
|
||||
|
||||
export const useWorkspacePlanLimits = (slug: string) => {
|
||||
const isBillingIntegrationEnabled = useIsBillingIntegrationEnabled()
|
||||
|
||||
const { result } = useQuery(
|
||||
workspacePlanLimitsQuery,
|
||||
() => ({
|
||||
slug
|
||||
}),
|
||||
() => ({
|
||||
enabled: isBillingIntegrationEnabled
|
||||
})
|
||||
)
|
||||
|
||||
const projectLimit = computed(() => 3)
|
||||
const modelLimit = computed(() => 8)
|
||||
|
||||
const projectCount = computed(
|
||||
() => result.value?.workspaceBySlug?.projects.totalCount || 0
|
||||
)
|
||||
const modelCount = computed(
|
||||
() =>
|
||||
result.value?.workspaceBySlug?.projects.items.reduce(
|
||||
(total, project) => total + project.models.totalCount,
|
||||
0
|
||||
) ?? 0
|
||||
)
|
||||
|
||||
const remainingProjects = computed(() => projectLimit.value - projectCount.value)
|
||||
const remainingModels = computed(() => modelLimit.value - modelCount.value)
|
||||
|
||||
const canAddProject = computed(() => remainingProjects.value > 0)
|
||||
const canAddModels = (projectModelCount: number) =>
|
||||
remainingModels.value >= projectModelCount
|
||||
|
||||
const getLimitType = (project: { modelCount: { totalCount: number } }) => {
|
||||
if (!canAddProject.value) return 'project'
|
||||
if (!canAddModels(project.modelCount.totalCount)) return 'model'
|
||||
return null
|
||||
}
|
||||
|
||||
const getLimit = (limitType: 'project' | 'model' | null) => {
|
||||
return limitType === 'model' ? modelLimit.value : projectLimit.value
|
||||
}
|
||||
|
||||
return {
|
||||
projectLimit,
|
||||
modelLimit,
|
||||
projectCount,
|
||||
modelCount,
|
||||
remainingProjects,
|
||||
remainingModels,
|
||||
canAddProject,
|
||||
canAddModels,
|
||||
getLimitType,
|
||||
getLimit
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,3 +157,11 @@ export const workspaceLastAdminCheckQuery = graphql(`
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
export const workspacePlanLimitsQuery = graphql(`
|
||||
query WorkspacePlanLimits($slug: String!) {
|
||||
workspaceBySlug(slug: $slug) {
|
||||
...WorkspacePlanLimits_Workspace
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
Reference in New Issue
Block a user