+
+
+
+
+
-
-
-
-
-
diff --git a/packages/frontend-2/components/project/page/settings/general/block/Discussions.vue b/packages/frontend-2/components/project/page/settings/general/block/Discussions.vue
index f800d95af..05f8ebb39 100644
--- a/packages/frontend-2/components/project/page/settings/general/block/Discussions.vue
+++ b/packages/frontend-2/components/project/page/settings/general/block/Discussions.vue
@@ -21,7 +21,7 @@
diff --git a/packages/frontend-2/components/projects/MoveToWorkspaceDialog.vue b/packages/frontend-2/components/projects/MoveToWorkspaceDialog.vue
index f0cd5ccb2..523b79a93 100644
--- a/packages/frontend-2/components/projects/MoveToWorkspaceDialog.vue
+++ b/packages/frontend-2/components/projects/MoveToWorkspaceDialog.vue
@@ -64,7 +64,7 @@ import type {
ProjectsMoveToWorkspaceDialog_ProjectFragment
} from '~~/lib/common/generated/gql/graphql'
import { useMutationLoading, useQuery } from '@vue/apollo-composable'
-import { type LayoutDialogButton } from '@speckle/ui-components'
+import type { LayoutDialogButton } from '@speckle/ui-components'
import { useMoveProjectToWorkspace } from '~/lib/projects/composables/projectManagement'
import { Roles } from '@speckle/shared'
import { workspacesRoute } from '~/lib/common/helpers/route'
diff --git a/packages/frontend-2/components/settings/Sidebar.vue b/packages/frontend-2/components/settings/Sidebar.vue
index 4852b0497..8ff37f1c3 100644
--- a/packages/frontend-2/components/settings/Sidebar.vue
+++ b/packages/frontend-2/components/settings/Sidebar.vue
@@ -19,10 +19,7 @@
-
+
@@ -68,62 +65,103 @@
/>
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
@@ -132,11 +170,10 @@
diff --git a/packages/frontend-2/components/settings/server/ActiveUsers.vue b/packages/frontend-2/components/settings/server/ActiveUsers.vue
index 98db1d5a6..a9a4a328f 100644
--- a/packages/frontend-2/components/settings/server/ActiveUsers.vue
+++ b/packages/frontend-2/components/settings/server/ActiveUsers.vue
@@ -139,7 +139,8 @@ const {
query: getUsersQuery,
baseVariables: computed(() => ({
query: search.value?.length ? search.value : null,
- limit: 50
+ limit: 50,
+ cursor: null as Nullable
})),
resolveKey: (vars) => [vars.query || ''],
resolveCurrentResult: (res) => res?.admin.userList,
diff --git a/packages/frontend-2/components/settings/server/PendingInvitations.vue b/packages/frontend-2/components/settings/server/PendingInvitations.vue
index 2c173083c..5697626f3 100644
--- a/packages/frontend-2/components/settings/server/PendingInvitations.vue
+++ b/packages/frontend-2/components/settings/server/PendingInvitations.vue
@@ -95,6 +95,7 @@ import { usePaginatedQuery } from '~/lib/common/composables/graphql'
import { getInvitesQuery } from '~~/lib/server-management/graphql/queries'
import { HorizontalDirection } from '~~/lib/common/composables/window'
import type { LayoutMenuItem } from '~~/lib/layout/helpers/components'
+import type { Nullable } from '@speckle/shared'
const { triggerNotification } = useGlobalToast()
const { mutate: resendInvitationMutation } = useMutation(adminResendInviteMutation)
@@ -114,7 +115,8 @@ const {
query: getInvitesQuery,
baseVariables: computed(() => ({
query: search.value?.length ? search.value : null,
- limit: 50
+ limit: 50,
+ cursor: null as Nullable
})),
resolveKey: (vars) => [vars.query || ''],
resolveCurrentResult: (res) => res?.admin.inviteList,
diff --git a/packages/frontend-2/components/settings/user/developer/AccessTokens/CreateDialog.vue b/packages/frontend-2/components/settings/user/developer/AccessTokens/CreateDialog.vue
index 5c01c3d1a..f94913bf5 100644
--- a/packages/frontend-2/components/settings/user/developer/AccessTokens/CreateDialog.vue
+++ b/packages/frontend-2/components/settings/user/developer/AccessTokens/CreateDialog.vue
@@ -96,8 +96,8 @@ const onSubmit = handleSubmit(async (tokenFormValues) => {
emit('token-created', result.data.apiTokenCreate)
triggerNotification({
type: ToastNotificationType.Success,
- title: 'Webhook created',
- description: 'The webhook has been successfully created'
+ title: 'Token created',
+ description: 'The token has been successfully created'
})
} else {
const errorMessage = getFirstErrorMessage(result?.errors)
diff --git a/packages/frontend-2/components/settings/user/email/DeleteDialog.vue b/packages/frontend-2/components/settings/user/email/DeleteDialog.vue
index 6e9f7ef44..28d903269 100644
--- a/packages/frontend-2/components/settings/user/email/DeleteDialog.vue
+++ b/packages/frontend-2/components/settings/user/email/DeleteDialog.vue
@@ -1,14 +1,14 @@
{{
- cancel
- ? `Are you sure you want to cancel adding ${email?.email} to your account?`
+ isAdding
+ ? `Do you want to stop adding ${email?.email}? Any progress will be discarded.`
: `Are you sure you want to delete ${email?.email} from your account?`
}}
@@ -22,7 +22,7 @@ import { useUserEmails } from '~/lib/user/composables/emails'
const props = defineProps<{
email?: UserEmail
- cancel?: boolean
+ isAdding?: boolean
}>()
const isOpen = defineModel('open', { required: true })
@@ -31,14 +31,14 @@ const { deleteUserEmail } = useUserEmails()
const dialogButtons = computed((): LayoutDialogButton[] => [
{
- text: 'Cancel',
+ text: props.isAdding ? 'No' : 'Cancel',
props: { color: 'outline' },
onClick: () => {
isOpen.value = false
}
},
{
- text: props.cancel ? 'Confirm' : 'Delete',
+ text: props.isAdding ? 'Yes' : 'Delete',
props: { color: 'primary' },
onClick: () => {
onDeleteEmail()
@@ -48,7 +48,10 @@ const dialogButtons = computed((): LayoutDialogButton[] => [
const onDeleteEmail = async () => {
if (!props.email) return
- const success = await deleteUserEmail(props.email)
+ const success = await deleteUserEmail({
+ email: props.email,
+ hideToast: props.isAdding
+ })
if (success) {
isOpen.value = false
}
diff --git a/packages/frontend-2/components/settings/user/email/ListItem.vue b/packages/frontend-2/components/settings/user/email/ListItem.vue
index ed865211e..c7592b7bf 100644
--- a/packages/frontend-2/components/settings/user/email/ListItem.vue
+++ b/packages/frontend-2/components/settings/user/email/ListItem.vue
@@ -62,11 +62,7 @@
:email="emailData.email"
/>
-
+
diff --git a/packages/frontend-2/components/settings/workspaces/billing/AddOns.vue b/packages/frontend-2/components/settings/workspaces/billing/AddOns.vue
new file mode 100644
index 000000000..d6be6ed73
--- /dev/null
+++ b/packages/frontend-2/components/settings/workspaces/billing/AddOns.vue
@@ -0,0 +1,23 @@
+
+
+
+
+
Unlimited projects and models
+
plus X per seat / month
+
+ Add more projects and models to your workspace.
+
+
Contact us
+
+
+
Extra data regions
+
Talk to us!
+
+ Add more available data regions. Learn more about Speckle Data Regions.
+
+
Contact us
+
+
+
diff --git a/packages/frontend-2/components/settings/workspaces/billing/Page.vue b/packages/frontend-2/components/settings/workspaces/billing/Page.vue
new file mode 100644
index 000000000..8643e9bbb
--- /dev/null
+++ b/packages/frontend-2/components/settings/workspaces/billing/Page.vue
@@ -0,0 +1,477 @@
+
+
+
+
+
+ 𝓒𝓱𝓪𝓷𝓰𝓮 𝓽𝓸 𝓷𝓮𝔀 𝓹𝓵𝓪𝓷 💸
+
+
+
+
+
+
+
+
+
+
+ {{ summaryPlanHeading }}
+
+
+
+ Workspace
+
+ {{ currentPlan?.name ?? WorkspacePlans.Starter }}
+
+
+
+ TRIAL
+
+
+
+
+
+ {{ formatPrice(seatPrice?.[Roles.Workspace.Member]) }} per
+ seat/month
+
+ Free
+
+
+ {{ formatPrice(seatPrice?.[Roles.Workspace.Member]) }} per
+ seat/month
+
+
+ {{ formatPrice(seatPrice?.[Roles.Workspace.Member]) }} per
+ seat/month, billed
+ {{
+ subscription?.billingInterval === BillingInterval.Yearly
+ ? 'annually'
+ : 'monthly'
+ }}
+
+
+
+
+
+
+ {{ summaryBillHeading }}
+
+
+ {{ summaryBillValue }} per
+ {{
+ subscription?.billingInterval === BillingInterval.Yearly
+ ? 'year'
+ : 'month'
+ }}
+
+
+ {{ summaryBillDescription }}
+
+
+
+
+ Expected bill
+
+ {{ isAcademiaPlan ? 'Free' : 'Not applicable' }}
+
+
+
+
+
+ {{ summaryDateHeading }}
+
+
+ {{ isPurchasablePlan ? nextPaymentDue : 'Never' }}
+
+
+ Subscribe before this date
+
+ {{
+ subscription?.billingInterval === BillingInterval.Yearly
+ ? 'Annual'
+ : 'Monthly'
+ }}
+ billing period
+
+
+
+
+
+
+
Billing portal
+
+ View invoices, edit payment details, and manage your subscription.
+
+
+
+
+ Open billing portal
+
+
+
+
+
+
+
+
+
+
+
+ Need help?
+
+ Contact us
+
+
+
+ Need help?
+
+ Read the docs
+
+ or
+
+ contact support
+
+
+
+
+
+
Coming soon
+
+
+
+
+
diff --git a/packages/frontend-2/components/settings/workspaces/billing/PageNew.vue b/packages/frontend-2/components/settings/workspaces/billing/PageNew.vue
new file mode 100644
index 000000000..52e9720e3
--- /dev/null
+++ b/packages/frontend-2/components/settings/workspaces/billing/PageNew.vue
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 𝕮𝖍𝖆𝖓𝖌𝖊 𝖙𝖔 𝖋𝖗𝖊𝖊 𝖕𝖑𝖆𝖓
+
+
+ 𝕮𝖍𝖆𝖓𝖌𝖊 𝖙𝖔 𝖙𝖊𝖆𝖒 𝖕𝖑𝖆𝖓
+
+
+ 𝕮𝖍𝖆𝖓𝖌𝖊 𝖙𝖔 𝖕𝖗𝖔 𝖕𝖑𝖆𝖓
+
+
+
+
+
+
+
+
diff --git a/packages/frontend-2/components/settings/workspaces/billing/PricingTable/Plan.vue b/packages/frontend-2/components/settings/workspaces/billing/PricingTable/Plan.vue
index 3e264fa6b..dd7c9f56f 100644
--- a/packages/frontend-2/components/settings/workspaces/billing/PricingTable/Plan.vue
+++ b/packages/frontend-2/components/settings/workspaces/billing/PricingTable/Plan.vue
@@ -5,7 +5,7 @@
Workspace
- {{ plan.name }}
+ {{ plan }}
{{ badgeText }}
@@ -13,10 +13,15 @@
- £{{
- yearlyIntervalSelected
- ? plan.cost.yearly[Roles.Workspace.Member]
- : plan.cost.monthly[Roles.Workspace.Member]
+ {{
+ formatPrice(
+ props.yearlyIntervalSelected && planPrice?.['workspace:member']
+ ? {
+ ...planPrice['workspace:member'],
+ amount: planPrice['workspace:member'].amount * 0.8
+ }
+ : planPrice?.['workspace:member']
+ )
}}
per seat/month
@@ -40,7 +45,7 @@
-
- {{ feature.name }}
+ {{ featureMetadata.displayName }}
@@ -89,7 +94,7 @@
diff --git a/packages/frontend-2/components/settings/workspaces/billing/UpgradeDialog.vue b/packages/frontend-2/components/settings/workspaces/billing/UpgradeDialog.vue
index 4d4539ca4..58647bf8c 100644
--- a/packages/frontend-2/components/settings/workspaces/billing/UpgradeDialog.vue
+++ b/packages/frontend-2/components/settings/workspaces/billing/UpgradeDialog.vue
@@ -10,7 +10,7 @@
Workspace {{ startCase(plan) }} plan
- £{{ seatPrice }}/seat/month, billed
+ {{ seatPrice }}/seat/month, billed
{{ billingInterval === BillingInterval.Yearly ? 'annually' : 'monthly' }}
@@ -22,33 +22,36 @@
diff --git a/packages/frontend-2/components/settings/workspaces/billing/usage/index.vue b/packages/frontend-2/components/settings/workspaces/billing/usage/index.vue
new file mode 100644
index 000000000..97556172d
--- /dev/null
+++ b/packages/frontend-2/components/settings/workspaces/billing/usage/index.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/frontend-2/components/settings/workspaces/members/GuestsTable.vue b/packages/frontend-2/components/settings/workspaces/members/GuestsTable.vue
index ae2b45a78..d42db5c23 100644
--- a/packages/frontend-2/components/settings/workspaces/members/GuestsTable.vue
+++ b/packages/frontend-2/components/settings/workspaces/members/GuestsTable.vue
@@ -11,9 +11,8 @@
:columns="[
{ id: 'name', header: 'Name', classes: 'col-span-3' },
{ id: 'company', header: 'Company', classes: 'col-span-3' },
- { id: 'verified', header: 'Status', classes: 'col-span-3' },
{ id: 'projects', header: 'Projects', classes: 'col-span-2' },
- { id: 'actions', header: '', classes: 'col-span-1 flex justify-end' }
+ { id: 'actions', header: '', classes: 'col-span-4 flex justify-end' }
]"
:items="guests"
:loading="searchResultLoading"
@@ -36,11 +35,6 @@
{{ item.user.company ? item.user.company : '-' }}
-
-
- {{ item.user.verified ? 'Verified' : 'Unverified' }}
-
-
@@ -121,7 +115,6 @@ graphql(`
avatar
name
company
- verified
}
projectRoles {
role
diff --git a/packages/frontend-2/components/settings/workspaces/members/InvitesTable.vue b/packages/frontend-2/components/settings/workspaces/members/InvitesTable.vue
index 93246a6f8..34a760779 100644
--- a/packages/frontend-2/components/settings/workspaces/members/InvitesTable.vue
+++ b/packages/frontend-2/components/settings/workspaces/members/InvitesTable.vue
@@ -108,7 +108,7 @@ graphql(`
fragment SettingsWorkspacesMembersInvitesTable_Workspace on Workspace {
id
...SettingsWorkspacesMembersTableHeader_Workspace
- invitedTeam(filter: $invitesFilter) {
+ invitedTeam {
...SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator
}
}
diff --git a/packages/frontend-2/components/settings/workspaces/members/JoinRequestsTable.vue b/packages/frontend-2/components/settings/workspaces/members/JoinRequestsTable.vue
index 1d470d64d..70360a0e2 100644
--- a/packages/frontend-2/components/settings/workspaces/members/JoinRequestsTable.vue
+++ b/packages/frontend-2/components/settings/workspaces/members/JoinRequestsTable.vue
@@ -5,10 +5,11 @@
:columns="[
{ id: 'name', header: 'Name', classes: 'col-span-3' },
{ id: 'createdAt', header: 'Requested at', classes: 'col-span-3' },
+ { id: 'status', header: 'Status', classes: 'col-span-3' },
{
id: 'actions',
header: '',
- classes: 'col-span-3 lg:col-span-6 flex items-center justify-end'
+ classes: 'col-span-3 flex items-center justify-end'
}
]"
:items="joinRequests"
@@ -27,13 +28,22 @@
{{ formattedFullDate(item.createdAt) }}
+
+
+ {{ item.status }}
+
+
-
+
Approve
Deny
+
@@ -45,10 +55,13 @@
diff --git a/packages/frontend-2/components/tutorials/Page.vue b/packages/frontend-2/components/tutorials/Page.vue
new file mode 100644
index 000000000..7dc90e9bd
--- /dev/null
+++ b/packages/frontend-2/components/tutorials/Page.vue
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
Tutorials
+
+
+ Get started with Speckle with step-by-step instructions for all skill
+ levels.
+
+
+
+
+
+
+
+
+
+ View all tutorials
+
+
+
+
+
+
+
+
diff --git a/packages/frontend-2/components/viewer/AnchoredPoints.vue b/packages/frontend-2/components/viewer/AnchoredPoints.vue
index 776a03caf..c1acb6348 100644
--- a/packages/frontend-2/components/viewer/AnchoredPoints.vue
+++ b/packages/frontend-2/components/viewer/AnchoredPoints.vue
@@ -20,6 +20,13 @@
:key="thread.id"
:model-value="thread"
:class="openThread?.id === thread.id ? 'z-[12]' : 'z-[11]'"
+ :has-previous="
+ allThreadsChronologicalOrder.findIndex((t) => t.id === thread.id) > 0
+ "
+ :has-next="
+ allThreadsChronologicalOrder.findIndex((t) => t.id === thread.id) <
+ allThreadsChronologicalOrder.length - 1
+ "
@update:model-value="onThreadUpdate"
@update:expanded="onThreadExpandedChange"
@next="(model) => openNextThread(model)"
diff --git a/packages/frontend-2/components/viewer/Base.vue b/packages/frontend-2/components/viewer/Base.vue
index ce73ce0dd..f9a2b7ccf 100644
--- a/packages/frontend-2/components/viewer/Base.vue
+++ b/packages/frontend-2/components/viewer/Base.vue
@@ -1,8 +1,13 @@
-
+
diff --git a/packages/frontend-2/components/viewer/Controls.vue b/packages/frontend-2/components/viewer/Controls.vue
index 289c86935..a173617c2 100644
--- a/packages/frontend-2/components/viewer/Controls.vue
+++ b/packages/frontend-2/components/viewer/Controls.vue
@@ -3,7 +3,7 @@