Merge branch 'main' into andrew/web-3131-move-projects-jumps-when-opening

This commit is contained in:
andrewwallacespeckle
2025-04-22 11:17:47 +01:00
6 changed files with 38 additions and 38 deletions
@@ -28,15 +28,15 @@
Add project
</FormButton>
</LayoutMenu>
<WorkspaceMoveProjectManager
v-model:open="showMoveProjectDialog"
:workspace-slug="workspaceSlug"
/>
<ProjectsAddDialog
v-model:open="showNewProjectDialog"
:workspace-id="workspace?.id"
/>
<ClientOnly>
<WorkspaceMoveProjectManager
v-model:open="showMoveProjectDialog"
:workspace-slug="workspaceSlug"
/>
<WorkspacePlanProjectModelLimitReachedDialog
v-model:open="showLimitDialog"
:workspace-name="workspace?.name"
@@ -60,9 +60,6 @@ graphql(`
...BillingAlert_Workspace
id
role
plan {
status
}
}
`)
@@ -24,10 +24,9 @@
</template>
<script setup lang="ts">
import { Roles } from '@speckle/shared'
import { Roles, WorkspacePlans } from '@speckle/shared'
import { LayoutSidebar } from '@speckle/ui-components'
import { graphql } from '~~/lib/common/generated/gql'
import { useWorkspacePlan } from '~/lib/workspaces/composables/plan'
import { useQuery } from '@vue/apollo-composable'
import { workspaceSidebarQuery } from '~/lib/workspaces/graphql/queries'
@@ -42,6 +41,9 @@ graphql(`
domains {
id
}
plan {
name
}
}
`)
@@ -54,9 +56,7 @@ const { result: workspaceResult } = useQuery(workspaceSidebarQuery, () => ({
}))
const workspace = computed(() => workspaceResult.value?.workspaceBySlug)
const { isFreePlan } = useWorkspacePlan(props.workspaceSlug)
const isFreePlan = computed(() => workspace.value?.plan?.name === WorkspacePlans.Free)
const isWorkspaceGuest = computed(() => workspace.value?.slug === Roles.Workspace.Guest)
const isWorkspaceAdmin = computed(() => workspace.value?.role === Roles.Workspace.Admin)
const hasDomains = computed(() => workspace.value?.domains?.length)
@@ -5,8 +5,8 @@
<PricingTablePlan
v-for="plan in plans"
:key="plan"
v-model:is-yearly-interval-selected="isYearlyIntervalSelected"
:plan="plan"
:yearly-interval-selected="isYearlySelected"
can-upgrade
@on-yearly-interval-selected="onYearlyIntervalSelected"
>
@@ -17,7 +17,7 @@
@click="onCtaClick(plan)"
>
{{
plan === WorkspacePlans.Free && !isYearlySelected
plan === WorkspacePlans.Free
? 'Get started for free'
: `Subscribe to ${formatName(plan)}`
}}
@@ -44,7 +44,9 @@ import { formatName } from '~/lib/billing/helpers/plan'
const { goToNextStep, goToPreviousStep, state } = useWorkspacesWizard()
const mixpanel = useMixpanel()
const isYearlySelected = ref(false)
const isYearlyIntervalSelected = defineModel<boolean>('isYearlyIntervalSelected', {
default: false
})
const plans = computed(() => [
WorkspacePlans.Free,
@@ -54,9 +56,10 @@ const plans = computed(() => [
const onCtaClick = (plan: WorkspacePlans) => {
state.value.plan = plan as unknown as PaidWorkspacePlans
state.value.billingInterval = isYearlySelected.value
? BillingInterval.Yearly
: BillingInterval.Monthly
state.value.billingInterval =
isYearlyIntervalSelected.value && plan !== WorkspacePlans.Free
? BillingInterval.Yearly
: BillingInterval.Monthly
mixpanel.track('Workspace Pricing Step Completed', {
plan: state.value.plan,
@@ -67,13 +70,13 @@ const onCtaClick = (plan: WorkspacePlans) => {
}
const onYearlyIntervalSelected = (newValue: boolean) => {
isYearlySelected.value = newValue
isYearlyIntervalSelected.value = newValue
}
watch(
() => state.value.billingInterval,
(newVal) => {
isYearlySelected.value = newVal === BillingInterval.Yearly
isYearlyIntervalSelected.value = newVal === BillingInterval.Yearly
},
{ immediate: true }
)
@@ -133,7 +133,7 @@ type Documents = {
"\n fragment ViewerModelVersionCardItem on Version {\n id\n message\n referencedObject\n sourceApplication\n createdAt\n previewUrl\n authorUser {\n ...LimitedUserAvatar\n }\n }\n": typeof types.ViewerModelVersionCardItemFragmentDoc,
"\n fragment WorkspaceAddProjectMenu_Workspace on Workspace {\n id\n name\n slug\n role\n plan {\n name\n }\n permissions {\n canCreateProject {\n ...FullPermissionCheckResult\n }\n canMoveProjectToWorkspace {\n ...FullPermissionCheckResult\n }\n }\n }\n": typeof types.WorkspaceAddProjectMenu_WorkspaceFragmentDoc,
"\n fragment WorkspaceDashboard_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceDashboardHeader_Workspace\n ...WorkspaceDashboardProjectList_Workspace\n id\n name\n role\n creationState {\n completed\n state\n }\n }\n": typeof types.WorkspaceDashboard_WorkspaceFragmentDoc,
"\n fragment WorkspaceDashboardHeader_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceAddProjectMenu_Workspace\n ...BillingAlert_Workspace\n id\n role\n plan {\n status\n }\n }\n": typeof types.WorkspaceDashboardHeader_WorkspaceFragmentDoc,
"\n fragment WorkspaceDashboardHeader_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceAddProjectMenu_Workspace\n ...BillingAlert_Workspace\n id\n role\n }\n": typeof types.WorkspaceDashboardHeader_WorkspaceFragmentDoc,
"\n fragment WorkspaceDashboardProjectList_ProjectCollection on ProjectCollection {\n totalCount\n items {\n ...ProjectDashboardItem\n }\n cursor\n }\n": typeof types.WorkspaceDashboardProjectList_ProjectCollectionFragmentDoc,
"\n fragment WorkspaceDashboardProjectList_Workspace on Workspace {\n ...WorkspaceAddProjectMenu_Workspace\n id\n }\n": typeof types.WorkspaceDashboardProjectList_WorkspaceFragmentDoc,
"\n fragment WorkspaceInviteBanner_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n invitedBy {\n id\n ...LimitedUserAvatar\n }\n workspaceId\n workspaceName\n token\n user {\n id\n }\n ...UseWorkspaceInviteManager_PendingWorkspaceCollaborator\n }\n": typeof types.WorkspaceInviteBanner_PendingWorkspaceCollaboratorFragmentDoc,
@@ -146,7 +146,7 @@ type Documents = {
"\n fragment WorkspaceSidebarAbout_Workspace on Workspace {\n id\n name\n description\n }\n": typeof types.WorkspaceSidebarAbout_WorkspaceFragmentDoc,
"\n fragment WorkspaceSidebarMembers_Workspace on Workspace {\n ...InviteDialogWorkspace_Workspace\n id\n slug\n team {\n totalCount\n items {\n id\n user {\n id\n name\n ...LimitedUserAvatar\n }\n }\n }\n invitedTeam(filter: $invitesFilter) {\n id\n role\n email\n }\n adminWorkspacesJoinRequests {\n totalCount\n items {\n status\n id\n }\n }\n }\n": typeof types.WorkspaceSidebarMembers_WorkspaceFragmentDoc,
"\n fragment WorkspaceSidebarSecurity_Workspace on Workspace {\n id\n slug\n domains {\n id\n domain\n }\n }\n": typeof types.WorkspaceSidebarSecurity_WorkspaceFragmentDoc,
"\n fragment WorkspaceSidebar_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceSidebarAbout_Workspace\n ...WorkspaceSidebarSecurity_Workspace\n id\n role\n slug\n domains {\n id\n }\n }\n": typeof types.WorkspaceSidebar_WorkspaceFragmentDoc,
"\n fragment WorkspaceSidebar_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceSidebarAbout_Workspace\n ...WorkspaceSidebarSecurity_Workspace\n id\n role\n slug\n domains {\n id\n }\n plan {\n name\n }\n }\n": typeof types.WorkspaceSidebar_WorkspaceFragmentDoc,
"\n fragment WorkspaceWizard_Workspace on Workspace {\n creationState {\n completed\n state\n }\n name\n slug\n }\n": typeof types.WorkspaceWizard_WorkspaceFragmentDoc,
"\n fragment WorkspaceWizardStepRegion_ServerInfo on ServerInfo {\n multiRegion {\n regions {\n id\n ...SettingsWorkspacesRegionsSelect_ServerRegionItem\n }\n }\n }\n": typeof types.WorkspaceWizardStepRegion_ServerInfoFragmentDoc,
"\n query ActiveUserMainMetadata {\n activeUser {\n id\n email\n emails {\n id\n email\n verified\n }\n company\n bio\n name\n role\n avatar\n isOnboardingFinished\n createdAt\n verified\n notificationPreferences\n versions(limit: 0) {\n totalCount\n }\n }\n }\n": typeof types.ActiveUserMainMetadataDocument,
@@ -549,7 +549,7 @@ const documents: Documents = {
"\n fragment ViewerModelVersionCardItem on Version {\n id\n message\n referencedObject\n sourceApplication\n createdAt\n previewUrl\n authorUser {\n ...LimitedUserAvatar\n }\n }\n": types.ViewerModelVersionCardItemFragmentDoc,
"\n fragment WorkspaceAddProjectMenu_Workspace on Workspace {\n id\n name\n slug\n role\n plan {\n name\n }\n permissions {\n canCreateProject {\n ...FullPermissionCheckResult\n }\n canMoveProjectToWorkspace {\n ...FullPermissionCheckResult\n }\n }\n }\n": types.WorkspaceAddProjectMenu_WorkspaceFragmentDoc,
"\n fragment WorkspaceDashboard_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceDashboardHeader_Workspace\n ...WorkspaceDashboardProjectList_Workspace\n id\n name\n role\n creationState {\n completed\n state\n }\n }\n": types.WorkspaceDashboard_WorkspaceFragmentDoc,
"\n fragment WorkspaceDashboardHeader_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceAddProjectMenu_Workspace\n ...BillingAlert_Workspace\n id\n role\n plan {\n status\n }\n }\n": types.WorkspaceDashboardHeader_WorkspaceFragmentDoc,
"\n fragment WorkspaceDashboardHeader_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceAddProjectMenu_Workspace\n ...BillingAlert_Workspace\n id\n role\n }\n": types.WorkspaceDashboardHeader_WorkspaceFragmentDoc,
"\n fragment WorkspaceDashboardProjectList_ProjectCollection on ProjectCollection {\n totalCount\n items {\n ...ProjectDashboardItem\n }\n cursor\n }\n": types.WorkspaceDashboardProjectList_ProjectCollectionFragmentDoc,
"\n fragment WorkspaceDashboardProjectList_Workspace on Workspace {\n ...WorkspaceAddProjectMenu_Workspace\n id\n }\n": types.WorkspaceDashboardProjectList_WorkspaceFragmentDoc,
"\n fragment WorkspaceInviteBanner_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n invitedBy {\n id\n ...LimitedUserAvatar\n }\n workspaceId\n workspaceName\n token\n user {\n id\n }\n ...UseWorkspaceInviteManager_PendingWorkspaceCollaborator\n }\n": types.WorkspaceInviteBanner_PendingWorkspaceCollaboratorFragmentDoc,
@@ -562,7 +562,7 @@ const documents: Documents = {
"\n fragment WorkspaceSidebarAbout_Workspace on Workspace {\n id\n name\n description\n }\n": types.WorkspaceSidebarAbout_WorkspaceFragmentDoc,
"\n fragment WorkspaceSidebarMembers_Workspace on Workspace {\n ...InviteDialogWorkspace_Workspace\n id\n slug\n team {\n totalCount\n items {\n id\n user {\n id\n name\n ...LimitedUserAvatar\n }\n }\n }\n invitedTeam(filter: $invitesFilter) {\n id\n role\n email\n }\n adminWorkspacesJoinRequests {\n totalCount\n items {\n status\n id\n }\n }\n }\n": types.WorkspaceSidebarMembers_WorkspaceFragmentDoc,
"\n fragment WorkspaceSidebarSecurity_Workspace on Workspace {\n id\n slug\n domains {\n id\n domain\n }\n }\n": types.WorkspaceSidebarSecurity_WorkspaceFragmentDoc,
"\n fragment WorkspaceSidebar_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceSidebarAbout_Workspace\n ...WorkspaceSidebarSecurity_Workspace\n id\n role\n slug\n domains {\n id\n }\n }\n": types.WorkspaceSidebar_WorkspaceFragmentDoc,
"\n fragment WorkspaceSidebar_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceSidebarAbout_Workspace\n ...WorkspaceSidebarSecurity_Workspace\n id\n role\n slug\n domains {\n id\n }\n plan {\n name\n }\n }\n": types.WorkspaceSidebar_WorkspaceFragmentDoc,
"\n fragment WorkspaceWizard_Workspace on Workspace {\n creationState {\n completed\n state\n }\n name\n slug\n }\n": types.WorkspaceWizard_WorkspaceFragmentDoc,
"\n fragment WorkspaceWizardStepRegion_ServerInfo on ServerInfo {\n multiRegion {\n regions {\n id\n ...SettingsWorkspacesRegionsSelect_ServerRegionItem\n }\n }\n }\n": types.WorkspaceWizardStepRegion_ServerInfoFragmentDoc,
"\n query ActiveUserMainMetadata {\n activeUser {\n id\n email\n emails {\n id\n email\n verified\n }\n company\n bio\n name\n role\n avatar\n isOnboardingFinished\n createdAt\n verified\n notificationPreferences\n versions(limit: 0) {\n totalCount\n }\n }\n }\n": types.ActiveUserMainMetadataDocument,
@@ -1339,7 +1339,7 @@ export function graphql(source: "\n fragment WorkspaceDashboard_Workspace on Wo
/**
* 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 WorkspaceDashboardHeader_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceAddProjectMenu_Workspace\n ...BillingAlert_Workspace\n id\n role\n plan {\n status\n }\n }\n"): (typeof documents)["\n fragment WorkspaceDashboardHeader_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceAddProjectMenu_Workspace\n ...BillingAlert_Workspace\n id\n role\n plan {\n status\n }\n }\n"];
export function graphql(source: "\n fragment WorkspaceDashboardHeader_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceAddProjectMenu_Workspace\n ...BillingAlert_Workspace\n id\n role\n }\n"): (typeof documents)["\n fragment WorkspaceDashboardHeader_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceAddProjectMenu_Workspace\n ...BillingAlert_Workspace\n id\n role\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
@@ -1391,7 +1391,7 @@ export function graphql(source: "\n fragment WorkspaceSidebarSecurity_Workspace
/**
* 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 WorkspaceSidebar_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceSidebarAbout_Workspace\n ...WorkspaceSidebarSecurity_Workspace\n id\n role\n slug\n domains {\n id\n }\n }\n"): (typeof documents)["\n fragment WorkspaceSidebar_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceSidebarAbout_Workspace\n ...WorkspaceSidebarSecurity_Workspace\n id\n role\n slug\n domains {\n id\n }\n }\n"];
export function graphql(source: "\n fragment WorkspaceSidebar_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceSidebarAbout_Workspace\n ...WorkspaceSidebarSecurity_Workspace\n id\n role\n slug\n domains {\n id\n }\n plan {\n name\n }\n }\n"): (typeof documents)["\n fragment WorkspaceSidebar_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceSidebarAbout_Workspace\n ...WorkspaceSidebarSecurity_Workspace\n id\n role\n slug\n domains {\n id\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.
*/
File diff suppressed because one or more lines are too long