feat: enable saved views for all workspace plans (#5343)
* feat: enable saved views for all workspace plans * more test fixes
This commit is contained in:
committed by
GitHub
parent
fdf3b93e95
commit
a074aedd65
Binary file not shown.
|
Before Width: | Height: | Size: 8.4 KiB |
@@ -97,7 +97,6 @@
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<ViewerSavedViewsPlanUpsell v-else />
|
||||
<ViewerSavedViewsPanelGroupsCreateDialog
|
||||
v-model:open="showCreateGroupDialog"
|
||||
@success="onAddGroup"
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-4 p-4">
|
||||
<img src="~/assets/images/viewer/saved-views/plan_upsell.webp" alt="Saved Views" />
|
||||
<div>
|
||||
<div class="text-foreground text-body font-semibold">Save custom views</div>
|
||||
<div class="text-body-2xs font-medium text-foreground-2">
|
||||
<p class="pb-3">Upgrade to a business plan to save, organise and present</p>
|
||||
<ul class="flex flex-col gap-2 list-disc list-inside">
|
||||
<li>It's cool</li>
|
||||
<li>It's nice</li>
|
||||
<li>It's got enough spice</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<FormButton size="sm">Upgrade</FormButton>
|
||||
<FormButton size="sm" color="outline">Learn more</FormButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -74,7 +74,7 @@ import { Roles, WorkspacePlans } from '@speckle/shared'
|
||||
import {
|
||||
ProjectNotEnoughPermissionsError,
|
||||
SavedViewNoAccessError,
|
||||
WorkspacePlanNoFeatureAccessError
|
||||
WorkspaceNoAccessError
|
||||
} from '@speckle/shared/authz'
|
||||
import * as ViewerRoute from '@speckle/shared/viewer/route'
|
||||
import { resourceBuilder } from '@speckle/shared/viewer/route'
|
||||
@@ -121,7 +121,6 @@ const fakeViewerState = (overrides?: PartialDeep<ViewerState.SerializedViewerSta
|
||||
let otherGuy: BasicTestUser
|
||||
let myProject: BasicTestStream
|
||||
let myProjectWorkspace: BasicTestWorkspace
|
||||
let myLackingProjectWorkspace: BasicTestWorkspace
|
||||
let myLackingProject: BasicTestStream
|
||||
let myModel1: BasicTestBranch
|
||||
let myModel2: BasicTestBranch
|
||||
@@ -269,13 +268,13 @@ const fakeViewerState = (overrides?: PartialDeep<ViewerState.SerializedViewerSta
|
||||
addPlan: WorkspacePlans.Pro
|
||||
})
|
||||
])
|
||||
myLackingProjectWorkspace = workspaceCreate[0]
|
||||
myProjectWorkspace = workspaceCreate[1]
|
||||
|
||||
const projectCreate = await Promise.all([
|
||||
createTestStream(
|
||||
buildBasicTestProject({
|
||||
workspaceId: myLackingProjectWorkspace.id
|
||||
// non-workspaced project
|
||||
workspaceId: undefined
|
||||
}),
|
||||
me
|
||||
),
|
||||
@@ -355,61 +354,6 @@ const fakeViewerState = (overrides?: PartialDeep<ViewerState.SerializedViewerSta
|
||||
expect(res.data?.projectMutations.savedViewMutations.createView).to.not.be.ok
|
||||
})
|
||||
|
||||
it('should fail with ForbiddenError if workspace plan does not include SavedViews', async () => {
|
||||
const res = await createSavedView(
|
||||
buildCreateInput({
|
||||
projectId: myLackingProject.id,
|
||||
resourceIdString: 'abc'
|
||||
})
|
||||
)
|
||||
expect(res).to.haveGraphQLErrors({ code: ForbiddenError.code })
|
||||
expect(res.data?.projectMutations.savedViewMutations.createView).to.not.be.ok
|
||||
})
|
||||
|
||||
it('should fail with ForbiddenError to create a saved view group if user lacks access (free plan)', async () => {
|
||||
const resourceIds = ViewerRoute.resourceBuilder().addModel(
|
||||
myLackingProject.id
|
||||
)
|
||||
const resourceIdString = resourceIds.toString()
|
||||
|
||||
const res = await createSavedViewGroup({
|
||||
input: {
|
||||
projectId: myLackingProject.id,
|
||||
resourceIdString,
|
||||
groupName: 'Should Not Work'
|
||||
}
|
||||
})
|
||||
|
||||
expect(res).to.haveGraphQLErrors({ code: ForbiddenError.code })
|
||||
expect(res.data?.projectMutations.savedViewMutations.createGroup).to.not.be.ok
|
||||
})
|
||||
|
||||
it('should fail with ForbiddenError to create a saved view if user lacks access (free plan)', async () => {
|
||||
const resourceIds = ViewerRoute.resourceBuilder().addModel(
|
||||
myLackingProject.id
|
||||
)
|
||||
const resourceIdString = resourceIds.toString()
|
||||
const viewerState = fakeViewerState({
|
||||
projectId: myLackingProject.id,
|
||||
resources: {
|
||||
request: {
|
||||
resourceIdString
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const res = await createSavedView(
|
||||
buildCreateInput({
|
||||
projectId: myLackingProject.id,
|
||||
resourceIdString,
|
||||
viewerState
|
||||
})
|
||||
)
|
||||
|
||||
expect(res).to.haveGraphQLErrors({ code: ForbiddenError.code })
|
||||
expect(res.data?.projectMutations.savedViewMutations.createView).to.not.be.ok
|
||||
})
|
||||
|
||||
it('should support dedicated auth policy check', async () => {
|
||||
const res = await canCreateSavedView({
|
||||
projectId: myLackingProject.id
|
||||
@@ -419,7 +363,7 @@ const fakeViewerState = (overrides?: PartialDeep<ViewerState.SerializedViewerSta
|
||||
|
||||
const data = res.data?.project.permissions.canCreateSavedView
|
||||
expect(data?.authorized).to.be.false
|
||||
expect(data?.code).to.equal(WorkspacePlanNoFeatureAccessError.code)
|
||||
expect(data?.code).to.equal(WorkspaceNoAccessError.code)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -977,7 +977,7 @@ describe('ensureCanUseProjectWorkspacePlanFeatureFragment', () => {
|
||||
|
||||
const result = await sut({
|
||||
projectId: 'project-id',
|
||||
feature: WorkspacePlanFeatures.SavedViews
|
||||
feature: WorkspacePlanFeatures.HideSpeckleBranding
|
||||
})
|
||||
|
||||
expect(result).toBeAuthOKResult()
|
||||
@@ -990,7 +990,7 @@ describe('ensureCanUseProjectWorkspacePlanFeatureFragment', () => {
|
||||
|
||||
const result = await sut({
|
||||
projectId: 'project-id',
|
||||
feature: WorkspacePlanFeatures.SavedViews
|
||||
feature: WorkspacePlanFeatures.HideSpeckleBranding
|
||||
})
|
||||
|
||||
expect(result).toBeAuthErrorResult({
|
||||
@@ -1008,7 +1008,7 @@ describe('ensureCanUseProjectWorkspacePlanFeatureFragment', () => {
|
||||
|
||||
const result = await sut({
|
||||
projectId: 'project-id',
|
||||
feature: WorkspacePlanFeatures.SavedViews
|
||||
feature: WorkspacePlanFeatures.HideSpeckleBranding
|
||||
})
|
||||
|
||||
expect(result).toBeAuthErrorResult({
|
||||
@@ -1026,7 +1026,7 @@ describe('ensureCanUseProjectWorkspacePlanFeatureFragment', () => {
|
||||
|
||||
const result = await sut({
|
||||
projectId: 'project-id',
|
||||
feature: WorkspacePlanFeatures.SavedViews,
|
||||
feature: WorkspacePlanFeatures.HideSpeckleBranding,
|
||||
allowUnworkspaced: true
|
||||
})
|
||||
|
||||
@@ -1044,7 +1044,7 @@ describe('ensureCanUseProjectWorkspacePlanFeatureFragment', () => {
|
||||
|
||||
const result = await sut({
|
||||
projectId: 'project-id',
|
||||
feature: WorkspacePlanFeatures.SavedViews
|
||||
feature: WorkspacePlanFeatures.HideSpeckleBranding
|
||||
})
|
||||
|
||||
expect(result).toBeAuthErrorResult({
|
||||
|
||||
@@ -20,8 +20,7 @@ import {
|
||||
SavedViewNoAccessError,
|
||||
SavedViewNotFoundError,
|
||||
UngroupedSavedViewGroupLockError,
|
||||
WorkspaceNoAccessError,
|
||||
WorkspacePlanNoFeatureAccessError
|
||||
WorkspaceNoAccessError
|
||||
} from '../domain/authErrors.js'
|
||||
import { nanoid } from 'nanoid'
|
||||
|
||||
@@ -191,11 +190,17 @@ describe('ensureCanAccessSavedViewFragment', () => {
|
||||
)
|
||||
|
||||
it.each(<const>['read', 'write'])(
|
||||
'fails when workspace plan is too cheap (%s)',
|
||||
'succeeds to %s even on free plan',
|
||||
async (access) => {
|
||||
const sut = buildWorkspaceSUT({
|
||||
getWorkspacePlan: getWorkspacePlanFake({
|
||||
name: 'team'
|
||||
name: 'free'
|
||||
}),
|
||||
getSavedView: getSavedViewFake({
|
||||
id: savedViewId,
|
||||
projectId,
|
||||
visibility: SavedViewVisibility.public,
|
||||
authorId: userId
|
||||
})
|
||||
})
|
||||
|
||||
@@ -205,9 +210,7 @@ describe('ensureCanAccessSavedViewFragment', () => {
|
||||
savedViewId,
|
||||
access
|
||||
})
|
||||
expect(result).toBeAuthErrorResult({
|
||||
code: WorkspacePlanNoFeatureAccessError.code
|
||||
})
|
||||
expect(result).toBeAuthOKResult()
|
||||
}
|
||||
)
|
||||
|
||||
@@ -413,27 +416,6 @@ describe('ensureCanAccessSavedViewGroupFragment', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it.each(<const>['read', 'write'])(
|
||||
'fails when workspace plan is too cheap (%s)',
|
||||
async (access) => {
|
||||
const sut = buildWorkspaceSUT({
|
||||
getWorkspacePlan: getWorkspacePlanFake({
|
||||
name: 'team'
|
||||
})
|
||||
})
|
||||
|
||||
const result = await sut({
|
||||
userId,
|
||||
projectId,
|
||||
savedViewGroupId,
|
||||
access
|
||||
})
|
||||
expect(result).toBeAuthErrorResult({
|
||||
code: WorkspacePlanNoFeatureAccessError.code
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it.each(<const>['read', 'write'])(
|
||||
'fails if view doesnt exist (%s)',
|
||||
async (access) => {
|
||||
|
||||
@@ -347,7 +347,7 @@ describe('ensureCanUseWorkspacePlanFeatureFragment', () => {
|
||||
|
||||
const result = await sut({
|
||||
workspaceId: cryptoRandomString({ length: 10 }),
|
||||
feature: WorkspacePlanFeatures.SavedViews
|
||||
feature: WorkspacePlanFeatures.HideSpeckleBranding
|
||||
})
|
||||
|
||||
expect(result).toBeOKResult()
|
||||
@@ -362,7 +362,7 @@ describe('ensureCanUseWorkspacePlanFeatureFragment', () => {
|
||||
|
||||
const result = await sut({
|
||||
workspaceId: cryptoRandomString({ length: 10 }),
|
||||
feature: WorkspacePlanFeatures.SavedViews
|
||||
feature: WorkspacePlanFeatures.HideSpeckleBranding
|
||||
})
|
||||
|
||||
expect(result).toBeAuthErrorResult({
|
||||
@@ -380,7 +380,7 @@ describe('ensureCanUseWorkspacePlanFeatureFragment', () => {
|
||||
|
||||
const result = await sut({
|
||||
workspaceId: cryptoRandomString({ length: 10 }),
|
||||
feature: WorkspacePlanFeatures.SavedViews
|
||||
feature: WorkspacePlanFeatures.HideSpeckleBranding
|
||||
})
|
||||
|
||||
expect(result).toBeAuthErrorResult({
|
||||
@@ -395,7 +395,7 @@ describe('ensureCanUseWorkspacePlanFeatureFragment', () => {
|
||||
|
||||
const result = await sut({
|
||||
workspaceId: cryptoRandomString({ length: 10 }),
|
||||
feature: WorkspacePlanFeatures.SavedViews
|
||||
feature: WorkspacePlanFeatures.HideSpeckleBranding
|
||||
})
|
||||
|
||||
expect(result).toBeAuthErrorResult({
|
||||
@@ -413,7 +413,7 @@ describe('ensureCanUseWorkspacePlanFeatureFragment', () => {
|
||||
|
||||
const result = await sut({
|
||||
workspaceId: cryptoRandomString({ length: 10 }),
|
||||
feature: WorkspacePlanFeatures.SavedViews
|
||||
feature: WorkspacePlanFeatures.HideSpeckleBranding
|
||||
})
|
||||
|
||||
expect(result).toBeAuthErrorResult({
|
||||
|
||||
@@ -14,10 +14,9 @@ import {
|
||||
ProjectNotEnoughPermissionsError,
|
||||
ServerNoAccessError,
|
||||
WorkspaceNoAccessError,
|
||||
WorkspacePlanNoFeatureAccessError,
|
||||
WorkspaceReadOnlyError
|
||||
} from '../../../domain/authErrors.js'
|
||||
import { PaidWorkspacePlans } from '../../../../workspaces/index.js'
|
||||
import { WorkspacePlans } from '../../../../workspaces/index.js'
|
||||
|
||||
const buildSUT = (overrides?: OverridesOf<typeof canCreateSavedViewPolicy>) =>
|
||||
canCreateSavedViewPolicy({
|
||||
@@ -71,7 +70,7 @@ describe('canCreateSavedViewPolicy', () => {
|
||||
id: 'workspace-id'
|
||||
}),
|
||||
getWorkspacePlan: getWorkspacePlanFake({
|
||||
name: PaidWorkspacePlans.Pro
|
||||
name: WorkspacePlans.Pro
|
||||
}),
|
||||
getWorkspaceSsoProvider: async () => ({
|
||||
providerId: 'provider-id'
|
||||
@@ -153,10 +152,10 @@ describe('canCreateSavedViewPolicy', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('fails if not on pro/business plan', async () => {
|
||||
it('succeeds even on free plan', async () => {
|
||||
const canCreate = buildWorkspaceSUT({
|
||||
getWorkspacePlan: getWorkspacePlanFake({
|
||||
name: PaidWorkspacePlans.Team
|
||||
name: WorkspacePlans.Free
|
||||
})
|
||||
})
|
||||
|
||||
@@ -164,15 +163,13 @@ describe('canCreateSavedViewPolicy', () => {
|
||||
userId: 'user-id',
|
||||
projectId: 'project-id'
|
||||
})
|
||||
expect(result).toBeAuthErrorResult({
|
||||
code: WorkspacePlanNoFeatureAccessError.code
|
||||
})
|
||||
expect(result).toBeAuthOKResult()
|
||||
})
|
||||
|
||||
it('fails if workspace readonly', async () => {
|
||||
const canCreate = buildWorkspaceSUT({
|
||||
getWorkspacePlan: getWorkspacePlanFake({
|
||||
name: PaidWorkspacePlans.Pro,
|
||||
name: WorkspacePlans.Pro,
|
||||
status: 'canceled'
|
||||
})
|
||||
})
|
||||
|
||||
@@ -134,135 +134,137 @@ export const WorkspacePaidPlanConfigs: (params: {
|
||||
featureFlags: Partial<FeatureFlags> | undefined
|
||||
}) => {
|
||||
[plan in PaidWorkspacePlans]: WorkspacePlanConfig<plan>
|
||||
} = (params) => ({
|
||||
[PaidWorkspacePlans.Team]: {
|
||||
plan: PaidWorkspacePlans.Team,
|
||||
features: [...baseFeatures],
|
||||
limits: {
|
||||
projectCount: 5,
|
||||
modelCount: 25,
|
||||
versionsHistory: { value: 30, unit: 'day' },
|
||||
commentHistory: { value: 30, unit: 'day' }
|
||||
}
|
||||
},
|
||||
[PaidWorkspacePlans.TeamUnlimited]: {
|
||||
plan: PaidWorkspacePlans.TeamUnlimited,
|
||||
features: [...baseFeatures],
|
||||
limits: {
|
||||
projectCount: null,
|
||||
modelCount: null,
|
||||
versionsHistory: { value: 30, unit: 'day' },
|
||||
commentHistory: { value: 30, unit: 'day' }
|
||||
}
|
||||
},
|
||||
[PaidWorkspacePlans.Pro]: {
|
||||
plan: PaidWorkspacePlans.Pro,
|
||||
features: [
|
||||
...baseFeatures,
|
||||
WorkspacePlanFeatures.DomainSecurity,
|
||||
WorkspacePlanFeatures.SSO,
|
||||
WorkspacePlanFeatures.CustomDataRegion,
|
||||
WorkspacePlanFeatures.HideSpeckleBranding,
|
||||
...(params.featureFlags?.FF_SAVED_VIEWS_ENABLED
|
||||
? [WorkspacePlanFeatures.SavedViews]
|
||||
: [])
|
||||
],
|
||||
limits: {
|
||||
projectCount: 10,
|
||||
modelCount: 50,
|
||||
versionsHistory: null,
|
||||
commentHistory: null
|
||||
}
|
||||
},
|
||||
[PaidWorkspacePlans.ProUnlimited]: {
|
||||
plan: PaidWorkspacePlans.ProUnlimited,
|
||||
features: [
|
||||
...baseFeatures,
|
||||
WorkspacePlanFeatures.DomainSecurity,
|
||||
WorkspacePlanFeatures.SSO,
|
||||
WorkspacePlanFeatures.CustomDataRegion,
|
||||
WorkspacePlanFeatures.HideSpeckleBranding,
|
||||
...(params.featureFlags?.FF_SAVED_VIEWS_ENABLED
|
||||
? [WorkspacePlanFeatures.SavedViews]
|
||||
: [])
|
||||
],
|
||||
limits: {
|
||||
projectCount: null,
|
||||
modelCount: null,
|
||||
versionsHistory: null,
|
||||
commentHistory: null
|
||||
} = (params) => {
|
||||
const finalBaseFeatures = [
|
||||
...baseFeatures,
|
||||
...(params.featureFlags?.FF_SAVED_VIEWS_ENABLED
|
||||
? [WorkspacePlanFeatures.SavedViews]
|
||||
: [])
|
||||
]
|
||||
|
||||
return {
|
||||
[PaidWorkspacePlans.Team]: {
|
||||
plan: PaidWorkspacePlans.Team,
|
||||
features: [...finalBaseFeatures],
|
||||
limits: {
|
||||
projectCount: 5,
|
||||
modelCount: 25,
|
||||
versionsHistory: { value: 30, unit: 'day' },
|
||||
commentHistory: { value: 30, unit: 'day' }
|
||||
}
|
||||
},
|
||||
[PaidWorkspacePlans.TeamUnlimited]: {
|
||||
plan: PaidWorkspacePlans.TeamUnlimited,
|
||||
features: [...finalBaseFeatures],
|
||||
limits: {
|
||||
projectCount: null,
|
||||
modelCount: null,
|
||||
versionsHistory: { value: 30, unit: 'day' },
|
||||
commentHistory: { value: 30, unit: 'day' }
|
||||
}
|
||||
},
|
||||
[PaidWorkspacePlans.Pro]: {
|
||||
plan: PaidWorkspacePlans.Pro,
|
||||
features: [
|
||||
...finalBaseFeatures,
|
||||
WorkspacePlanFeatures.DomainSecurity,
|
||||
WorkspacePlanFeatures.SSO,
|
||||
WorkspacePlanFeatures.CustomDataRegion,
|
||||
WorkspacePlanFeatures.HideSpeckleBranding
|
||||
],
|
||||
limits: {
|
||||
projectCount: 10,
|
||||
modelCount: 50,
|
||||
versionsHistory: null,
|
||||
commentHistory: null
|
||||
}
|
||||
},
|
||||
[PaidWorkspacePlans.ProUnlimited]: {
|
||||
plan: PaidWorkspacePlans.ProUnlimited,
|
||||
features: [
|
||||
...finalBaseFeatures,
|
||||
WorkspacePlanFeatures.DomainSecurity,
|
||||
WorkspacePlanFeatures.SSO,
|
||||
WorkspacePlanFeatures.CustomDataRegion,
|
||||
WorkspacePlanFeatures.HideSpeckleBranding
|
||||
],
|
||||
limits: {
|
||||
projectCount: null,
|
||||
modelCount: null,
|
||||
versionsHistory: null,
|
||||
commentHistory: null
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const WorkspaceUnpaidPlanConfigs: (params: {
|
||||
featureFlags: Partial<FeatureFlags> | undefined
|
||||
}) => {
|
||||
[plan in UnpaidWorkspacePlans]: WorkspacePlanConfig<plan>
|
||||
} = (params) => ({
|
||||
[UnpaidWorkspacePlans.Enterprise]: {
|
||||
plan: UnpaidWorkspacePlans.Enterprise,
|
||||
features: [
|
||||
...baseFeatures,
|
||||
WorkspacePlanFeatures.DomainSecurity,
|
||||
WorkspacePlanFeatures.SSO,
|
||||
WorkspacePlanFeatures.CustomDataRegion,
|
||||
WorkspacePlanFeatures.HideSpeckleBranding,
|
||||
WorkspacePlanFeatures.ExclusiveMembership,
|
||||
...(params.featureFlags?.FF_SAVED_VIEWS_ENABLED
|
||||
? [WorkspacePlanFeatures.SavedViews]
|
||||
: [])
|
||||
],
|
||||
limits: unlimited
|
||||
},
|
||||
[UnpaidWorkspacePlans.Unlimited]: {
|
||||
plan: UnpaidWorkspacePlans.Unlimited,
|
||||
features: [
|
||||
...baseFeatures,
|
||||
WorkspacePlanFeatures.DomainSecurity,
|
||||
WorkspacePlanFeatures.SSO,
|
||||
WorkspacePlanFeatures.CustomDataRegion,
|
||||
WorkspacePlanFeatures.HideSpeckleBranding,
|
||||
WorkspacePlanFeatures.ExclusiveMembership,
|
||||
...(params.featureFlags?.FF_SAVED_VIEWS_ENABLED
|
||||
? [WorkspacePlanFeatures.SavedViews]
|
||||
: [])
|
||||
],
|
||||
limits: unlimited
|
||||
},
|
||||
[UnpaidWorkspacePlans.Academia]: {
|
||||
plan: UnpaidWorkspacePlans.Academia,
|
||||
features: [
|
||||
...baseFeatures,
|
||||
WorkspacePlanFeatures.DomainSecurity,
|
||||
WorkspacePlanFeatures.SSO,
|
||||
WorkspacePlanFeatures.CustomDataRegion,
|
||||
WorkspacePlanFeatures.HideSpeckleBranding,
|
||||
...(params.featureFlags?.FF_SAVED_VIEWS_ENABLED
|
||||
? [WorkspacePlanFeatures.SavedViews]
|
||||
: [])
|
||||
],
|
||||
limits: unlimited
|
||||
},
|
||||
[UnpaidWorkspacePlans.TeamUnlimitedInvoiced]: {
|
||||
...WorkspacePaidPlanConfigs(params).teamUnlimited,
|
||||
plan: UnpaidWorkspacePlans.TeamUnlimitedInvoiced
|
||||
},
|
||||
[UnpaidWorkspacePlans.ProUnlimitedInvoiced]: {
|
||||
...WorkspacePaidPlanConfigs(params).proUnlimited,
|
||||
plan: UnpaidWorkspacePlans.ProUnlimitedInvoiced
|
||||
},
|
||||
[UnpaidWorkspacePlans.Free]: {
|
||||
plan: UnpaidWorkspacePlans.Free,
|
||||
features: baseFeatures,
|
||||
limits: {
|
||||
projectCount: 1,
|
||||
modelCount: 5,
|
||||
versionsHistory: { value: 7, unit: 'day' },
|
||||
commentHistory: { value: 7, unit: 'day' }
|
||||
} = (params) => {
|
||||
const finalBaseFeatures = [
|
||||
...baseFeatures,
|
||||
...(params.featureFlags?.FF_SAVED_VIEWS_ENABLED
|
||||
? [WorkspacePlanFeatures.SavedViews]
|
||||
: [])
|
||||
]
|
||||
return {
|
||||
[UnpaidWorkspacePlans.Enterprise]: {
|
||||
plan: UnpaidWorkspacePlans.Enterprise,
|
||||
features: [
|
||||
...finalBaseFeatures,
|
||||
WorkspacePlanFeatures.DomainSecurity,
|
||||
WorkspacePlanFeatures.SSO,
|
||||
WorkspacePlanFeatures.CustomDataRegion,
|
||||
WorkspacePlanFeatures.HideSpeckleBranding,
|
||||
WorkspacePlanFeatures.ExclusiveMembership
|
||||
],
|
||||
limits: unlimited
|
||||
},
|
||||
[UnpaidWorkspacePlans.Unlimited]: {
|
||||
plan: UnpaidWorkspacePlans.Unlimited,
|
||||
features: [
|
||||
...finalBaseFeatures,
|
||||
WorkspacePlanFeatures.DomainSecurity,
|
||||
WorkspacePlanFeatures.SSO,
|
||||
WorkspacePlanFeatures.CustomDataRegion,
|
||||
WorkspacePlanFeatures.HideSpeckleBranding,
|
||||
WorkspacePlanFeatures.ExclusiveMembership
|
||||
],
|
||||
limits: unlimited
|
||||
},
|
||||
[UnpaidWorkspacePlans.Academia]: {
|
||||
plan: UnpaidWorkspacePlans.Academia,
|
||||
features: [
|
||||
...finalBaseFeatures,
|
||||
WorkspacePlanFeatures.DomainSecurity,
|
||||
WorkspacePlanFeatures.SSO,
|
||||
WorkspacePlanFeatures.CustomDataRegion,
|
||||
WorkspacePlanFeatures.HideSpeckleBranding
|
||||
],
|
||||
limits: unlimited
|
||||
},
|
||||
[UnpaidWorkspacePlans.TeamUnlimitedInvoiced]: {
|
||||
...WorkspacePaidPlanConfigs(params).teamUnlimited,
|
||||
plan: UnpaidWorkspacePlans.TeamUnlimitedInvoiced
|
||||
},
|
||||
[UnpaidWorkspacePlans.ProUnlimitedInvoiced]: {
|
||||
...WorkspacePaidPlanConfigs(params).proUnlimited,
|
||||
plan: UnpaidWorkspacePlans.ProUnlimitedInvoiced
|
||||
},
|
||||
[UnpaidWorkspacePlans.Free]: {
|
||||
plan: UnpaidWorkspacePlans.Free,
|
||||
features: finalBaseFeatures,
|
||||
limits: {
|
||||
projectCount: 1,
|
||||
modelCount: 5,
|
||||
versionsHistory: { value: 7, unit: 'day' },
|
||||
commentHistory: { value: 7, unit: 'day' }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const WorkspacePlanConfigs = (params: {
|
||||
featureFlags: Partial<FeatureFlags> | undefined
|
||||
|
||||
+1
-21
@@ -1,23 +1,3 @@
|
||||
{
|
||||
/* load each package separately, rather than as one giant progream */
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "packages/fileimport-service" },
|
||||
{ "path": "packages/frontend-2" },
|
||||
{ "path": "packages/monitor-deployment" },
|
||||
{ "path": "packages/objectloader" },
|
||||
{ "path": "packages/objectloader2" },
|
||||
{ "path": "packages/objectsender" },
|
||||
{ "path": "packages/preview-frontend" },
|
||||
{ "path": "packages/preview-service" },
|
||||
{ "path": "packages/server" },
|
||||
{ "path": "packages/shared" },
|
||||
{ "path": "packages/tailwind-theme" },
|
||||
{ "path": "packages/ui-components" },
|
||||
{ "path": "packages/ui-components-nuxt" },
|
||||
{ "path": "packages/viewer" },
|
||||
{ "path": "packages/viewer-sandbox" },
|
||||
{ "path": "packages/webhook-service" }
|
||||
/* …add all other packages listed in workspace.code-workspace */
|
||||
]
|
||||
"files": []
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@
|
||||
"Prorotation"
|
||||
],
|
||||
"typescript.tsserver.maxTsServerMemory": 8192,
|
||||
"typescript.disableAutomaticTypeAcquisition": true,
|
||||
"tailwindCSS.experimental.configFile": {
|
||||
"packages/frontend-2/tailwind.config.cjs": "packages/frontend-2/**"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user