From e2edad3e4e006a09d775ce5abb985137e17080df Mon Sep 17 00:00:00 2001 From: andrewwallacespeckle Date: Tue, 23 Sep 2025 09:53:24 +0200 Subject: [PATCH 1/8] fix(fe): keep section box gizmo enabled after reset --- packages/frontend-2/lib/viewer/composables/ui.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/frontend-2/lib/viewer/composables/ui.ts b/packages/frontend-2/lib/viewer/composables/ui.ts index 959b140d1..6e30dec5f 100644 --- a/packages/frontend-2/lib/viewer/composables/ui.ts +++ b/packages/frontend-2/lib/viewer/composables/ui.ts @@ -85,6 +85,7 @@ export function useSectionBoxUtilities() { const resetSectionBoxCompletely = () => { sectionBox.value = null visible.value = false + toggleSectionBox() } return { From 3573b0a38812c8a026bf37e5d9e45af201d05095 Mon Sep 17 00:00:00 2001 From: andrewwallacespeckle Date: Tue, 23 Sep 2025 10:27:03 +0200 Subject: [PATCH 2/8] Revert "fix(fe): keep section box gizmo enabled after reset" This reverts commit e2edad3e4e006a09d775ce5abb985137e17080df. --- packages/frontend-2/lib/viewer/composables/ui.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/frontend-2/lib/viewer/composables/ui.ts b/packages/frontend-2/lib/viewer/composables/ui.ts index 6e30dec5f..959b140d1 100644 --- a/packages/frontend-2/lib/viewer/composables/ui.ts +++ b/packages/frontend-2/lib/viewer/composables/ui.ts @@ -85,7 +85,6 @@ export function useSectionBoxUtilities() { const resetSectionBoxCompletely = () => { sectionBox.value = null visible.value = false - toggleSectionBox() } return { From e1982bed126ab3ec74e00eacddaa675436ceb020 Mon Sep 17 00:00:00 2001 From: andrewwallacespeckle Date: Tue, 23 Sep 2025 10:36:31 +0200 Subject: [PATCH 3/8] fix(fe): close section box panel on reset --- packages/frontend-2/components/viewer/controls/Bottom.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/frontend-2/components/viewer/controls/Bottom.vue b/packages/frontend-2/components/viewer/controls/Bottom.vue index c5e48a953..32cead6fc 100644 --- a/packages/frontend-2/components/viewer/controls/Bottom.vue +++ b/packages/frontend-2/components/viewer/controls/Bottom.vue @@ -247,6 +247,7 @@ const onReset = () => { } if (activePanel.value === ActivePanel.sectionBox) { resetSectionBoxCompletely() + activePanel.value = ActivePanel.none } } From ef8c3a959663990629ea1f0472e2187a962d27a6 Mon Sep 17 00:00:00 2001 From: AlexandruPopovici Date: Tue, 23 Sep 2025 11:32:31 +0200 Subject: [PATCH 4/8] fix(viewer-lib): Fixed WEB-4323 --- packages/viewer-sandbox/src/Sandbox.ts | 2 -- packages/viewer-sandbox/src/main.ts | 3 +++ .../extensions/measurements/PerpendicularMeasurement.ts | 5 +++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/viewer-sandbox/src/Sandbox.ts b/packages/viewer-sandbox/src/Sandbox.ts index 530e366dc..bca71cd6e 100644 --- a/packages/viewer-sandbox/src/Sandbox.ts +++ b/packages/viewer-sandbox/src/Sandbox.ts @@ -434,8 +434,6 @@ export default class Sandbox { } this.viewer.getExtension(SectionTool).setBox(box) this.viewer.getExtension(SectionTool).toggle() - const sectionCaps = this.viewer.getExtension(SectionCaps) - if (sectionCaps) sectionCaps.enabled = !sectionCaps.enabled }) const toggleSectionBoxVisibility = this.tabs.pages[0].addButton({ diff --git a/packages/viewer-sandbox/src/main.ts b/packages/viewer-sandbox/src/main.ts index de0c5bb88..d76656d57 100644 --- a/packages/viewer-sandbox/src/main.ts +++ b/packages/viewer-sandbox/src/main.ts @@ -638,6 +638,9 @@ const getStream = () => { // Revit v3 instances // 'https://app.speckle.systems/projects/03074a2834/models/a013d06fe1@cc11e1ead1' + + // Gergo's new house + // 'https://app.speckle.systems/projects/4743372784/models/2aeaa357e6' ) } diff --git a/packages/viewer/src/modules/extensions/measurements/PerpendicularMeasurement.ts b/packages/viewer/src/modules/extensions/measurements/PerpendicularMeasurement.ts index b51f3ef6b..94514d27d 100644 --- a/packages/viewer/src/modules/extensions/measurements/PerpendicularMeasurement.ts +++ b/packages/viewer/src/modules/extensions/measurements/PerpendicularMeasurement.ts @@ -209,6 +209,11 @@ export class PerpendicularMeasurement extends Measurement { public toMeasurementData(): MeasurementData { const data = super.toMeasurementData() data.innerPoints = [[this.midPoint.x, this.midPoint.y, this.midPoint.z]] + if (this.flipStartNormal) { + vec3Buff0.copy(this.startNormal) + vec3Buff0.negate() + data.startNormal = [vec3Buff0.x, vec3Buff0.y, vec3Buff0.z] + } return data } From cb4ae3c1923ea588597f219156263d2d73d2445b Mon Sep 17 00:00:00 2001 From: AlexandruPopovici Date: Tue, 23 Sep 2025 11:37:41 +0200 Subject: [PATCH 5/8] chore(viewer-sandbox): Fixed error --- packages/viewer-sandbox/src/Sandbox.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/viewer-sandbox/src/Sandbox.ts b/packages/viewer-sandbox/src/Sandbox.ts index bca71cd6e..e38feee51 100644 --- a/packages/viewer-sandbox/src/Sandbox.ts +++ b/packages/viewer-sandbox/src/Sandbox.ts @@ -58,7 +58,6 @@ import { ObjectLoader2Flags, ObjectLoader2Factory } from '@speckle/objectloader2' -import { SectionCaps } from './Extensions/SectionCaps.ts/SectionCaps' import { MeasurementType } from '@speckle/shared/viewer/state' export default class Sandbox { From a7a20adb16e122653003134a548d87e224681cc7 Mon Sep 17 00:00:00 2001 From: andrewwallacespeckle Date: Tue, 23 Sep 2025 12:07:51 +0200 Subject: [PATCH 6/8] fix(viewer): raise MIN_CLICK_TIMING to improve single clicks --- packages/viewer/src/modules/input/Input.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/viewer/src/modules/input/Input.ts b/packages/viewer/src/modules/input/Input.ts index cbb3edb26..13232b119 100644 --- a/packages/viewer/src/modules/input/Input.ts +++ b/packages/viewer/src/modules/input/Input.ts @@ -26,7 +26,7 @@ export interface InputEventPayload { //TO DO: Define proper interface for InputEvent data export default class Input extends EventEmitter { private static readonly MAX_DOUBLE_CLICK_TIMING = 500 - private static readonly MIN_CLICK_TIMING = 150 + private static readonly MIN_CLICK_TIMING = 200 private tapTimeout: number = 0 private lastTap = 0 private lastClick = 0 From 8f5a5b28d3bcf6160da1a80514dd61a27b3a8fec Mon Sep 17 00:00:00 2001 From: Mike Date: Tue, 23 Sep 2025 17:43:25 +0200 Subject: [PATCH 7/8] 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 8/8] 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 @@