From 8f5a5b28d3bcf6160da1a80514dd61a27b3a8fec Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 23 Sep 2025 17:43:25 +0200 Subject: [PATCH 1/2] Feat: Only show unlimited add-on for business plan (#5529) --- .../components/billing/UsageAlert.vue | 6 ++-- .../components/pricingTable/Addon.vue | 5 --- .../components/pricingTable/Plan.vue | 34 +++++-------------- .../workspaces/billing/addOns/AddOns.vue | 8 ++--- .../billing/upgradeDialog/UpgradeDialog.vue | 9 +++-- .../components/workspace/wizard/Wizard.vue | 5 --- .../lib/workspaces/composables/wizard.ts | 10 ++---- 7 files changed, 24 insertions(+), 53 deletions(-) diff --git a/packages/frontend-2/components/billing/UsageAlert.vue b/packages/frontend-2/components/billing/UsageAlert.vue index bd6ab5b6f..2a559b203 100644 --- a/packages/frontend-2/components/billing/UsageAlert.vue +++ b/packages/frontend-2/components/billing/UsageAlert.vue @@ -18,10 +18,10 @@ const description = computed(() => { if (!props.planName) return '' if (props.planName === WorkspacePlans.Team) - return 'Your workspace has reached a usage limit. To keep using Speckle, you can buy the Unlimited projects and models add-on to your current Starter plan, or upgrade to the Business plan.' + return 'Your workspace has reached a usage limit. Upgrade to the Business plan to keep using Speckle.' if (props.planName === WorkspacePlans.Pro) - return 'Your workspace has reached a usage limit. To keep using Speckle, you can buy the Unlimited projects and models add-on to your current Business plan.' + return 'Your workspace has reached a usage limit. Buy the Unlimited projects and models add-on to keep using Speckle.' - return 'Your workspace has reached a usage limit. To keep using Speckle, you should upgrade your workspace to the Starter or Business plan. Note that both plans can be extended with the Unlimited projects and models add-on.' + return 'Your workspace has reached a usage limit. To keep using Speckle, you should upgrade your workspace to the Starter or Business plan.' }) diff --git a/packages/frontend-2/components/pricingTable/Addon.vue b/packages/frontend-2/components/pricingTable/Addon.vue index 20b35c285..6dcc812c3 100644 --- a/packages/frontend-2/components/pricingTable/Addon.vue +++ b/packages/frontend-2/components/pricingTable/Addon.vue @@ -18,7 +18,6 @@ const props = defineProps<{ isYearlyIntervalSelected: boolean currency?: Currency tooltip?: string - fixedPrice?: string }>() const { addonPrices } = useWorkspaceAddonPrices() @@ -40,10 +39,6 @@ const addonPrice = computed(() => { }) const text = computed(() => { - if (props.fixedPrice) { - return props.fixedPrice - } - return addonPrice.value ? `${addonPrice.value} per editor seat / month` : 'Contact us for pricing' diff --git a/packages/frontend-2/components/pricingTable/Plan.vue b/packages/frontend-2/components/pricingTable/Plan.vue index 46a3f5667..68ba5d1a8 100644 --- a/packages/frontend-2/components/pricingTable/Plan.vue +++ b/packages/frontend-2/components/pricingTable/Plan.vue @@ -64,7 +64,7 @@ :description="featureMetadata.description" /> -
+
Available add-ons
@@ -145,16 +144,16 @@ const commonFeatures = shallowRef([ planLimits.value.projectCount === 1 ? '' : 's' }`, description: - props.plan === WorkspacePlans.Free - ? 'Your maximum number of projects' - : 'Your maximum number of projects. Can be extended with the Unlimited projects and models add-on.' + props.plan === WorkspacePlans.Pro + ? 'Your maximum number of projects. Can be extended with the Unlimited projects and models add-on.' + : 'Your maximum number of projects' }, { displayName: `${planLimits.value.modelCount} models per workspace`, description: - props.plan === WorkspacePlans.Free - ? 'Your maximum number of models' - : 'Your maximum number of models. Can be extended with the Unlimited projects and models add-on.' + props.plan === WorkspacePlans.Pro + ? 'Your maximum number of models. Can be extended with the Unlimited projects and models add-on.' + : 'Your maximum number of models' }, { displayName: planLimits.value.versionsHistory @@ -384,30 +383,13 @@ const badgeText = computed(() => ) const displayAddons = computed(() => { - if (props.plan === WorkspacePlans.Team) { + if (props.plan === WorkspacePlans.Pro) { return [ { title: 'Unlimited projects and models', tooltip: 'You can purchase this in the next step' } ] - } else if (props.plan === WorkspacePlans.Pro) { - return [ - { - title: 'Unlimited projects and models', - tooltip: 'You can purchase this in the next step' - }, - { - title: 'Extra data regions', - fixedPrice: '$500 per region / month', - tooltip: 'Available upon request' - }, - { - title: 'Priority support', - fixedPrice: 'Contact us for pricing', - tooltip: 'Available upon request' - } - ] } return [] }) diff --git a/packages/frontend-2/components/settings/workspaces/billing/addOns/AddOns.vue b/packages/frontend-2/components/settings/workspaces/billing/addOns/AddOns.vue index cae4c7fbb..2b9be3bbf 100644 --- a/packages/frontend-2/components/settings/workspaces/billing/addOns/AddOns.vue +++ b/packages/frontend-2/components/settings/workspaces/billing/addOns/AddOns.vue @@ -4,7 +4,7 @@ title="Unlimited projects and models" :subtitle="`${addonPrice} per editor/month`" info="Power through with unlimited projects and models in your workspace." - disclaimer="Only on Starter & Business plans" + disclaimer="Only on Business plan" :button="unlimitedAddOnButton" /> @@ -51,7 +51,7 @@ const props = defineProps<{ }>() const { - isPaidPlan, + isBusinessPlan, currency, plan, intervalIsYearly, @@ -78,14 +78,14 @@ const addOnButtonTooltip = computed(() => { return 'You must be a workspace admin in order to purchase the add-on' if (hasUnlimitedAddon.value) return 'The add-on is already included in your subscription' - if (!isPaidPlan.value) return 'Only available for Starter & Business plans' + if (!isBusinessPlan.value) return 'Only available for the Business plan' return undefined }) const unlimitedAddOnButton = computed(() => ({ text: 'Buy add-on', id: 'buy-add-on', - disabled: !isPaidPlan.value || hasUnlimitedAddon.value || !isAdmin.value, + disabled: !isBusinessPlan.value || hasUnlimitedAddon.value || !isAdmin.value, disabledMessage: addOnButtonTooltip.value, onClick: () => { isUpgradeDialogOpen.value = true diff --git a/packages/frontend-2/components/settings/workspaces/billing/upgradeDialog/UpgradeDialog.vue b/packages/frontend-2/components/settings/workspaces/billing/upgradeDialog/UpgradeDialog.vue index aab2ada6c..7a7886a55 100644 --- a/packages/frontend-2/components/settings/workspaces/billing/upgradeDialog/UpgradeDialog.vue +++ b/packages/frontend-2/components/settings/workspaces/billing/upgradeDialog/UpgradeDialog.vue @@ -62,7 +62,7 @@ const mixpanel = useMixpanel() const { projectCount, modelCount } = useWorkspaceUsage(props.slug) const featureFlags = useFeatureFlags() -const showAddonSelect = ref(true) +const showAddonSelect = ref(false) const isLoading = ref(false) const title = computed(() => { @@ -196,7 +196,12 @@ watch( () => isOpen.value, (newVal) => { if (newVal) { - showAddonSelect.value = props.isChangingPlan && !isSamePlanWithAddon.value + // Only show addon select for Business (Pro) plans + const isBusinessPlan = + props.plan === PaidWorkspacePlans.Pro || + props.plan === PaidWorkspacePlans.ProUnlimited + showAddonSelect.value = + props.isChangingPlan && !isSamePlanWithAddon.value && isBusinessPlan // If the add-on is required or already included, set it to yes if (usageExceedsNewPlanLimit.value && props.isChangingPlan) { includeUnlimitedAddon.value = 'yes' diff --git a/packages/frontend-2/components/workspace/wizard/Wizard.vue b/packages/frontend-2/components/workspace/wizard/Wizard.vue index 89f8d931b..8ad0a37d0 100644 --- a/packages/frontend-2/components/workspace/wizard/Wizard.vue +++ b/packages/frontend-2/components/workspace/wizard/Wizard.vue @@ -104,11 +104,6 @@ onResult((result) => { newState.plan === PaidWorkspacePlans.ProUnlimited ) { goToStep(WizardSteps.Region) - } else if ( - newState.plan === PaidWorkspacePlans.Team || - newState.plan === PaidWorkspacePlans.TeamUnlimited - ) { - goToStep(WizardSteps.AddOns) } else { goToStep(WizardSteps.Pricing) } diff --git a/packages/frontend-2/lib/workspaces/composables/wizard.ts b/packages/frontend-2/lib/workspaces/composables/wizard.ts index 172ebd69f..63bfd68d2 100644 --- a/packages/frontend-2/lib/workspaces/composables/wizard.ts +++ b/packages/frontend-2/lib/workspaces/composables/wizard.ts @@ -92,15 +92,9 @@ export const useWorkspacesWizard = () => { let shouldComplete = false if (wizardState.value.currentStep === WizardSteps.Pricing) { - if (state.value.plan === WorkspacePlans.Free) { - shouldComplete = true - } - } - - if (wizardState.value.currentStep === WizardSteps.AddOns) { if ( - state.value.plan === WorkspacePlans.Team || - state.value.plan === WorkspacePlans.TeamUnlimited + state.value.plan === WorkspacePlans.Free || + state.value.plan === WorkspacePlans.Team ) { shouldComplete = true } From af466ec5989bd5d88c0cb8a402df51a2d57275fb Mon Sep 17 00:00:00 2001 From: andrewwallacespeckle Date: Tue, 23 Sep 2025 18:21:14 +0200 Subject: [PATCH 2/2] fix(fe): checkbox alignment --- .../components/project/page/discussions/Header.vue | 1 + .../viewer/filters/filter/string/SelectAll.vue | 3 +-- .../viewer/filters/filter/string/ValueItem.vue | 7 +++---- .../ui-components/src/components/form/Checkbox.vue | 12 ++++++++---- packages/ui-components/src/composables/form/input.ts | 2 +- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/frontend-2/components/project/page/discussions/Header.vue b/packages/frontend-2/components/project/page/discussions/Header.vue index 01b9bff12..b1357a625 100644 --- a/packages/frontend-2/components/project/page/discussions/Header.vue +++ b/packages/frontend-2/components/project/page/discussions/Header.vue @@ -9,6 +9,7 @@ name="includeArchived" :value="true" label="Include resolved" + label-position="right" />
diff --git a/packages/frontend-2/components/viewer/filters/filter/string/SelectAll.vue b/packages/frontend-2/components/viewer/filters/filter/string/SelectAll.vue index 6761bf0ea..652d109a5 100644 --- a/packages/frontend-2/components/viewer/filters/filter/string/SelectAll.vue +++ b/packages/frontend-2/components/viewer/filters/filter/string/SelectAll.vue @@ -15,7 +15,7 @@ :name="`select-all-${selectedCount}-${totalCount}`" :model-value="areAllValuesSelected" :indeterminate="areSomeValuesSelected" - class="pointer-events-none -mt-1" + class="pointer-events-none" :class="selectAllCheckboxClasses" hide-label /> @@ -32,7 +32,6 @@