Merge branch 'main' into andrew/web-2920-fe

This commit is contained in:
andrewwallacespeckle
2025-04-05 17:00:32 +01:00
80 changed files with 1017 additions and 1475 deletions
+1 -1
View File
@@ -996,7 +996,7 @@ jobs:
- run: echo "export KUBECONFIG=$(pwd)/.kube/config" >> "${BASH_ENV}"
- run: echo "${KUBECONFIG}"
- run:
name: Template Helm Chart
name: Template Speckle Server Helm Chart
command: |
nix-shell \
--run "helm template speckle-server ./utils/helm/speckle-server" \
@@ -27,39 +27,8 @@
<h3 class="label mb-2">Access permissions</h3>
<ProjectVisibilitySelect v-model="visibility" mount-menu-on-body />
</div>
<template v-if="isWorkspacesEnabled && !workspaceId">
<div class="flex gap-y-2 flex-col">
<p class="text-body-xs text-foreground font-medium">Workspace</p>
<div class="flex gap-x-2 items-center">
<ProjectsWorkspaceSelect
v-model="selectedWorkspace"
:items="workspaces"
:disabled-roles="[Roles.Workspace.Guest]"
:disabled="!hasWorkspaces"
disabled-item-tooltip="You dont have rights to create projects in this workspace"
class="flex-1"
/>
<div v-tippy="'Create workspace'" class="flex">
<FormButton
:icon-left="PlusIcon"
hide-text
class="flex"
color="outline"
@click="navigateToWorkspaceExplainer"
/>
</div>
</div>
<p class="text-foreground-2 text-body-2xs">
Workspaces offer better project management and higher data security.
</p>
</div>
</template>
</div>
</form>
<CommonConfirmDialog
v-model:open="showConfirmDialog"
@confirm="handleConfirmAction"
/>
</LayoutDialog>
</template>
<script setup lang="ts">
@@ -69,31 +38,7 @@ import { SimpleProjectVisibility } from '~~/lib/common/generated/gql/graphql'
import { isRequired, isStringOfLength } from '~~/lib/common/helpers/validation'
import { useMixpanel } from '~~/lib/core/composables/mp'
import { useCreateProject } from '~~/lib/projects/composables/projectManagement'
import { useIsWorkspacesEnabled } from '~/composables/globals'
import { PlusIcon } from '@heroicons/vue/24/outline'
import type { ProjectsAddDialog_WorkspaceFragment } from '~/lib/common/generated/gql/graphql'
import { graphql } from '~~/lib/common/generated/gql'
import { projectWorkspaceSelectQuery } from '~/lib/projects/graphql/queries'
import { useQuery } from '@vue/apollo-composable'
import { Roles } from '@speckle/shared'
import { workspacesRoute } from '~/lib/common/helpers/route'
graphql(`
fragment ProjectsAddDialog_Workspace on Workspace {
id
...ProjectsWorkspaceSelect_Workspace
}
`)
graphql(`
fragment ProjectsAddDialog_User on User {
workspaces {
items {
...ProjectsAddDialog_Workspace
}
}
}
`)
type FormValues = {
name: string
@@ -108,37 +53,29 @@ const emit = defineEmits<{
(e: 'created'): void
}>()
const isWorkspacesEnabled = useIsWorkspacesEnabled()
const createProject = useCreateProject()
const router = useRouter()
const logger = useLogger()
const { handleSubmit, meta, isSubmitting } = useForm<FormValues>()
const { result: workspaceResult } = useQuery(projectWorkspaceSelectQuery, null, () => ({
enabled: isWorkspacesEnabled.value
}))
const { handleSubmit, isSubmitting } = useForm<FormValues>()
const visibility = ref(SimpleProjectVisibility.Unlisted)
const selectedWorkspace = ref<ProjectsAddDialog_WorkspaceFragment>()
const showConfirmDialog = ref(false)
const confirmActionType = ref<'navigate' | 'close' | null>(null)
const isClosing = ref(false)
const isLoading = ref(false)
const open = defineModel<boolean>('open', { required: true })
const mp = useMixpanel()
const onSubmit = handleSubmit(async (values) => {
if (isClosing.value) return // Prevent submission while closing
if (isLoading.value) return // Prevent submission while closing
try {
isClosing.value = true
const workspaceId = props.workspaceId || selectedWorkspace.value?.id
isLoading.value = true
await createProject({
name: values.name,
description: values.description,
visibility: visibility.value,
...(workspaceId ? { workspaceId } : {})
...(props.workspaceId ? { workspaceId: props.workspaceId } : {})
})
emit('created')
mp.track('Stream Action', {
@@ -149,18 +86,13 @@ const onSubmit = handleSubmit(async (values) => {
})
open.value = false
} catch (error) {
isClosing.value = false
isLoading.value = false
logger.error('Failed to create project:', error)
}
})
const workspaces = computed(
() => workspaceResult.value?.activeUser?.workspaces.items ?? []
)
const hasWorkspaces = computed(() => workspaces.value.length > 0)
const dialogButtons = computed((): LayoutDialogButton[] => {
const isDisabled = isSubmitting.value || isClosing.value
const isDisabled = isSubmitting.value || isLoading.value
return [
{
@@ -169,7 +101,7 @@ const dialogButtons = computed((): LayoutDialogButton[] => {
color: 'outline',
disabled: isDisabled
},
onClick: confirmCancel
onClick: () => (open.value = false)
},
{
text: 'Create',
@@ -183,41 +115,10 @@ const dialogButtons = computed((): LayoutDialogButton[] => {
]
})
const formIsDirty = computed(() => {
return meta.value.dirty
})
const navigateToWorkspaceExplainer = () => {
if (formIsDirty.value) {
confirmActionType.value = 'navigate'
showConfirmDialog.value = true
} else {
router.push(workspacesRoute)
}
}
const confirmCancel = () => {
if (formIsDirty.value) {
confirmActionType.value = 'close'
showConfirmDialog.value = true
} else {
open.value = false
}
}
const handleConfirmAction = () => {
if (confirmActionType.value === 'navigate') {
router.push(workspacesRoute)
} else if (confirmActionType.value === 'close') {
open.value = false
}
confirmActionType.value = null
}
watch(open, (newVal, oldVal) => {
if (newVal && !oldVal) {
selectedWorkspace.value = undefined
isClosing.value = false
isLoading.value = false
}
})
</script>
@@ -1,64 +1,68 @@
<template>
<LayoutDialog v-model:open="open" max-width="sm" :buttons="dialogButtons">
<template #header>Move project to workspace</template>
<div class="flex flex-col space-y-4">
<ProjectsWorkspaceSelect
v-if="hasWorkspaces"
v-model="selectedWorkspace"
:items="workspaces"
:disabled-roles="[Roles.Workspace.Member, Roles.Workspace.Guest]"
disabled-item-tooltip="Only workspace admins can move projects into a workspace."
label="Select a workspace"
help="Once a project is moved to a workspace, it cannot be moved out from it."
show-label
/>
<div v-else class="flex flex-col gap-y-2">
<p class="text-body-xs text-foreground font-medium">
You're not a member of any workspaces.
</p>
<FormButton :to="workspacesRoute">Learn about workspaces</FormButton>
</div>
<div>
<LayoutDialog v-model:open="open" max-width="sm" :buttons="dialogButtons">
<template #header>Move project to workspace</template>
<div class="flex flex-col space-y-4">
<template v-if="!workspace">
<ProjectsWorkspaceSelect
v-if="hasWorkspaces"
v-model="selectedWorkspace"
:items="workspaces"
:disabled-roles="[Roles.Workspace.Member, Roles.Workspace.Guest]"
disabled-item-tooltip="Only workspace admins can move projects into a workspace."
label="Select a workspace"
help="Once a project is moved to a workspace, it cannot be moved out from it."
show-label
/>
<div v-else class="flex flex-col gap-y-2">
<p class="text-body-xs text-foreground font-medium">
You're not a member of any workspaces.
</p>
<FormButton :to="workspaceCreateRoute">Learn about workspaces</FormButton>
</div>
</template>
<div v-if="project && selectedWorkspace" class="text-body-xs">
<div class="text-body-xs text-foreground flex flex-col gap-y-4">
<div class="rounded border bg-foundation-2 border-outline-3 py-2 px-4">
<p>
Move
<span class="font-medium">{{ project.name }}</span>
to
<span class="font-medium">
{{ selectedWorkspace?.name }}
<div v-if="project && (selectedWorkspace || workspace)" class="text-body-xs">
<div class="text-body-xs text-foreground flex flex-col gap-y-4">
<div class="rounded border bg-foundation-2 border-outline-3 py-2 px-4">
<p>
Move
<span class="font-medium">{{ project.name }}</span>
to
<span class="font-medium">
{{ selectedWorkspace?.name ?? workspace?.name }}
</span>
</p>
<p class="text-foreground-3">
{{ project.modelCount.totalCount }} {{ modelText }},
{{ project.versions.totalCount }} {{ versionsText }}
</p>
</div>
<p class="text-body-2xs text-foreground-2">
The project, including models and versions, will be moved to the
workspace, where all existing members and admins will have access.
<span class="pt-2 block">
The project's collaborators will become workspace members and keep their
project roles.
</span>
</p>
<p class="text-foreground-3">
{{ project.modelCount.totalCount }} {{ modelText }},
{{ project.versions.totalCount }} {{ versionsText }}
</p>
</div>
<p class="text-body-2xs text-foreground-2">
The project, including models and versions, will be moved to the workspace,
where all existing members and admins will have access.
<span class="pt-2 block">
The project's collaborators will become workspace members and keep their
project roles.
</span>
</p>
</div>
</div>
</div>
<WorkspaceRegionStaticDataDisclaimer
v-if="showRegionStaticDataDisclaimer"
v-model:open="showRegionStaticDataDisclaimer"
:variant="RegionStaticDataDisclaimerVariant.MoveProjectIntoWorkspace"
@confirm="onConfirmHandler"
/>
<WorkspaceRegionStaticDataDisclaimer
v-if="showRegionStaticDataDisclaimer"
v-model:open="showRegionStaticDataDisclaimer"
:variant="RegionStaticDataDisclaimerVariant.MoveProjectIntoWorkspace"
@confirm="onConfirmHandler"
/>
</LayoutDialog>
<WorkspacePlanLimitReachedDialog
v-if="activeLimit"
v-model:open="showLimitReachedDialog"
:limit="activeLimit"
:limit-type="limitType"
/>
</LayoutDialog>
</div>
</template>
<script setup lang="ts">
@@ -71,25 +75,19 @@ import { useMutationLoading, useQuery } from '@vue/apollo-composable'
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'
import { workspaceCreateRoute } from '~/lib/common/helpers/route'
import {
useWorkspaceCustomDataResidencyDisclaimer,
RegionStaticDataDisclaimerVariant
} from '~/lib/workspaces/composables/region'
import {
useWorkspaceModelLimits,
useWorkspaceProjectLimits
} from '~/lib/workspaces/composables/limits'
graphql(`
fragment ProjectsMoveToWorkspaceDialog_Workspace on Workspace {
id
role
projectCount: projects(limit: 0) {
totalCount
}
name
logo
slug
...WorkspaceHasCustomDataResidency_Workspace
...ProjectsWorkspaceSelect_Workspace
}
@@ -129,8 +127,10 @@ const query = graphql(`
const props = defineProps<{
project: ProjectsMoveToWorkspaceDialog_ProjectFragment
workspace?: ProjectsMoveToWorkspaceDialog_WorkspaceFragment
eventSource?: string // Used for mixpanel tracking
}>()
const open = defineModel<boolean>('open', { required: true })
const isWorkspacesEnabled = useIsWorkspacesEnabled()
@@ -141,6 +141,16 @@ const loading = useMutationLoading()
const moveProject = useMoveProjectToWorkspace()
const selectedWorkspace = ref<ProjectsMoveToWorkspaceDialog_WorkspaceFragment>()
const activeWorkspaceSlug = computed(
() => selectedWorkspace.value?.slug || props.workspace?.slug || ''
)
// Get workspace limits
const { canAddProject, canAddModels, limits } = useWorkspaceLimits(
activeWorkspaceSlug.value
)
const showLimitReachedDialog = ref(false)
const workspaces = computed(() => result.value?.activeUser?.workspaces.items ?? [])
@@ -152,35 +162,21 @@ const versionsText = computed(() =>
props.project.versions.totalCount === 1 ? 'version' : 'versions'
)
const modelCount = computed(() => {
return props.project.modelCount.totalCount
})
// Determine which limit type is hit
const limitType = computed((): 'project' | 'model' | null => {
if (!canAddProject.value) return 'project'
const projectCount = computed(() => {
return selectedWorkspace.value?.projectCount.totalCount ?? 0
})
const projectModelCount = props.project.modelCount.totalCount
if (!canAddModels(projectModelCount)) return 'model'
const { canAddProject, projectLimit } = useWorkspaceProjectLimits(projectCount)
const { canAddModel, modelLimit } = useWorkspaceModelLimits(modelCount)
const limitType = computed(() => {
if (!canAddProject.value) {
return 'project'
}
if (!canAddModel.value) {
return 'model'
}
return null
})
// Get the value of the limit that's hit
const activeLimit = computed(() => {
if (!canAddProject.value) {
return projectLimit.value
}
if (!canAddModel.value) {
return modelLimit.value
}
return null
if (limitType.value === 'project') return limits.value.projectCount ?? 0
if (limitType.value === 'model') return limits.value.modelCount ?? 0
return 0
})
const dialogButtons = computed<LayoutDialogButton[]>(() => {
@@ -197,7 +193,7 @@ const dialogButtons = computed<LayoutDialogButton[]>(() => {
text: 'Move',
props: {
color: 'primary',
disabled: !selectedWorkspace.value || loading.value
disabled: (!selectedWorkspace.value && !props.workspace) || loading.value
},
onClick: () => onMoveClick()
}
@@ -214,8 +210,8 @@ const dialogButtons = computed<LayoutDialogButton[]>(() => {
})
const onMoveProject = async () => {
const workspaceId = selectedWorkspace.value?.id
const workspaceName = selectedWorkspace.value?.name
const workspaceId = selectedWorkspace.value?.id ?? props.workspace?.id
const workspaceName = selectedWorkspace.value?.name ?? props.workspace?.name
if (!workspaceId || !workspaceName) return
const res = await moveProject({
@@ -231,7 +227,7 @@ const onMoveProject = async () => {
const { showRegionStaticDataDisclaimer, triggerAction, onConfirmHandler } =
useWorkspaceCustomDataResidencyDisclaimer({
workspace: computed(() => selectedWorkspace.value),
workspace: computed(() => selectedWorkspace.value ?? props.workspace),
onConfirmAction: onMoveProject
})
@@ -246,7 +242,11 @@ watch(
)
const onMoveClick = () => {
if (limitType.value) {
const projectModelCount = props.project.modelCount.totalCount
// Check if we can add this project to the workspace
if (!canAddProject.value || !canAddModels(projectModelCount)) {
open.value = false
showLimitReachedDialog.value = true
} else {
triggerAction()
@@ -1,107 +0,0 @@
<template>
<LayoutDialog v-model:open="open" max-width="sm" :buttons="dialogButtons">
<template #header>{{ title ? title : 'Remove user' }}</template>
<div class="flex flex-col gap-y-2 text-body-xs text-foreground">
<p class="py-2">
Are you sure you want to remove
<span class="font-medium">{{ name }}</span>
from the workspace?
</p>
<p v-if="showBillingInfo" class="text-foreground-2">
Your workspace is currently billed for {{ memberSeatText
}}{{ hasGuestSeats ? ` and ${guestSeatText}` : '' }}. Your bill will remain the
same until it is adjusted at the start of your next renewal:
{{ nextBillingCycleEnd }}
</p>
</div>
</LayoutDialog>
</template>
<script setup lang="ts">
import type { LayoutDialogButton } from '@speckle/ui-components'
import { graphql } from '~/lib/common/generated/gql'
import type { MaybeNullOrUndefined } from '@speckle/shared'
import {
type SettingsSharedDeleteUserDialog_WorkspaceFragment,
type WorkspacePlans,
WorkspacePlanStatuses
} from '~/lib/common/generated/gql/graphql'
import dayjs from 'dayjs'
import { isPaidPlan } from '~/lib/billing/helpers/types'
graphql(`
fragment SettingsSharedDeleteUserDialog_Workspace on Workspace {
id
plan {
status
name
}
subscription {
currentBillingCycleEnd
seats {
guest
plan
}
}
}
`)
const emit = defineEmits<{
(e: 'removeUser'): void
}>()
const props = defineProps<{
name: string
title?: string
workspace: MaybeNullOrUndefined<SettingsSharedDeleteUserDialog_WorkspaceFragment>
}>()
const open = defineModel<boolean>('open', { required: true })
const memberSeatText = computed(() => {
if (!props.workspace?.subscription) return ''
return `${props.workspace.subscription.seats.plan} member ${
props.workspace.subscription.seats.plan === 1 ? 'seat' : 'seats'
}`
})
const guestSeatText = computed(() => {
if (!props.workspace?.subscription) return ''
return `${props.workspace.subscription.seats.guest} guest ${
props.workspace.subscription.seats.guest === 1 ? 'seat' : 'seats'
}`
})
const hasGuestSeats = computed(() => {
return (
props.workspace?.subscription?.seats.guest &&
props.workspace.subscription.seats.guest > 0
)
})
const nextBillingCycleEnd = computed(() => {
if (!props.workspace?.subscription) return ''
return dayjs(props.workspace.subscription.currentBillingCycleEnd).format(
'MMMM D, YYYY'
)
})
const showBillingInfo = computed(() => {
if (!props.workspace?.plan) return false
return (
isPaidPlan(props.workspace.plan.name as unknown as WorkspacePlans) &&
props.workspace.plan.status === WorkspacePlanStatuses.Valid
)
})
const dialogButtons = computed((): LayoutDialogButton[] => [
{
text: 'Cancel',
props: { color: 'outline' },
onClick: () => (open.value = false)
},
{
text: 'Remove',
props: { color: 'primary' },
onClick: () => {
open.value = false
emit('removeUser')
}
}
])
</script>
@@ -1,181 +0,0 @@
<template>
<LayoutDialog v-model:open="open" max-width="sm" :buttons="dialogButtons">
<template #header>Change role</template>
<div class="flex flex-col gap-4 mb-4 -mt-1">
<FormSelectWorkspaceRoles
v-model="newRole"
label="New role"
fully-control-value
:disabled-items="disabledItems"
:current-role="currentRole"
show-label
show-description
/>
<div
v-if="
workspaceDomainPolicyCompliant === false && newRole !== Roles.Workspace.Guest
"
class="flex gap-x-2 items-center"
>
<ExclamationCircleIcon class="text-danger w-4 h-4" />
<p class="text-foreground">
This user can only have the guest role due to the workspace policy.
</p>
</div>
<CommonCard
v-if="newRole"
class="bg-foundation !py-4 text-body-2xs flex flex-row gap-y-2"
>
<p
v-for="(message, i) in getWorkspaceProjectRoleMessages(newRole)"
:key="`message-${i}`"
>
{{ message }}
</p>
</CommonCard>
<div v-if="showBillingInfo" class="text-body-2xs text-foreground-2 leading-5">
<p class="mb-2">
Your workspace is currently billed for {{ memberSeatText
}}{{ hasGuestSeats ? ` and ${guestSeatText}` : '' }}.
<br />
Changing a user's role may add a seat to your current billing cycle.
</p>
<p>
Unused seats will be adjusted at the start of your next billing cycle:
<br />
{{ nextBillingCycleEnd }}
</p>
</div>
</div>
</LayoutDialog>
</template>
<script setup lang="ts">
import type { LayoutDialogButton } from '@speckle/ui-components'
import { type MaybeNullOrUndefined, Roles, type WorkspaceRoles } from '@speckle/shared'
import { ExclamationCircleIcon } from '@heroicons/vue/24/outline'
import { graphql } from '~/lib/common/generated/gql'
import {
type SettingsWorkspacesMembersChangeRoleDialog_WorkspaceFragment,
type WorkspacePlans,
WorkspacePlanStatuses
} from '~/lib/common/generated/gql/graphql'
import dayjs from 'dayjs'
import { isPaidPlan } from '~/lib/billing/helpers/types'
graphql(`
fragment SettingsWorkspacesMembersChangeRoleDialog_Workspace on Workspace {
id
plan {
status
name
}
subscription {
currentBillingCycleEnd
seats {
guest
plan
}
}
}
`)
const emit = defineEmits<{
(e: 'updateRole', newRole: WorkspaceRoles): void
}>()
const props = defineProps<{
workspaceDomainPolicyCompliant?: boolean | null
currentRole?: WorkspaceRoles
workspace: MaybeNullOrUndefined<SettingsWorkspacesMembersChangeRoleDialog_WorkspaceFragment>
}>()
const open = defineModel<boolean>('open', { required: true })
const newRole = ref<WorkspaceRoles | undefined>()
const disabledItems = computed<WorkspaceRoles[]>(() =>
props.workspaceDomainPolicyCompliant === false
? [Roles.Workspace.Member, Roles.Workspace.Admin]
: []
)
const dialogButtons = computed((): LayoutDialogButton[] => [
{
text: 'Cancel',
props: { color: 'outline' },
onClick: () => (open.value = false)
},
{
text: 'Update',
props: { color: 'primary', disabled: !newRole.value },
onClick: () => {
open.value = false
if (newRole.value) {
emit('updateRole', newRole.value)
}
}
}
])
const memberSeatText = computed(() => {
if (!props.workspace?.subscription) return ''
return `${props.workspace.subscription.seats.plan} member ${
props.workspace.subscription.seats.plan === 1 ? 'seat' : 'seats'
}`
})
const guestSeatText = computed(() => {
if (!props.workspace?.subscription) return ''
return `${props.workspace.subscription.seats.guest} guest ${
props.workspace.subscription.seats.guest === 1 ? 'seat' : 'seats'
}`
})
const hasGuestSeats = computed(() => {
return (
props.workspace?.subscription?.seats.guest &&
props.workspace.subscription.seats.guest > 0
)
})
const nextBillingCycleEnd = computed(() => {
if (!props.workspace?.subscription) return ''
return dayjs(props.workspace.subscription.currentBillingCycleEnd).format(
'MMMM D, YYYY'
)
})
const showBillingInfo = computed(() => {
if (!props.workspace?.plan || !newRole.value) return false
return (
isPaidPlan(props.workspace.plan.name as unknown as WorkspacePlans) &&
props.workspace.plan.status === WorkspacePlanStatuses.Valid
)
})
const getWorkspaceProjectRoleMessages = (workspaceRole: WorkspaceRoles): string[] => {
switch (workspaceRole) {
case Roles.Workspace.Admin:
return [
'Becomes project owner for all existing and new workspace projects.',
'Cannot be removed or have role changed by project owners.'
]
case Roles.Workspace.Member:
return [
'Becomes project viewer for all existing and new workspace projects.',
'Project owners can change their role or remove them.'
]
case Roles.Workspace.Guest:
return [
'Loses access to all existing workspace projects.',
'Project owners can assign a role or remove them.'
]
}
}
watch(
() => open.value,
(newVal, oldVal) => {
if (newVal && !oldVal) {
newRole.value = undefined
}
}
)
</script>
@@ -116,7 +116,6 @@ graphql(`
slug
name
...SettingsWorkspacesMembersTableHeader_Workspace
...SettingsSharedDeleteUserDialog_Workspace
team(limit: 250) {
items {
id
@@ -116,7 +116,6 @@ graphql(`
id
slug
name
...SettingsSharedDeleteUserDialog_Workspace
...SettingsWorkspacesMembersTableHeader_Workspace
team(limit: 250) {
items {
@@ -45,7 +45,7 @@
</template>
<script setup lang="ts">
import { workspacesRoute } from '~~/lib/common/helpers/route'
import { workspaceCreateRoute } from '~~/lib/common/helpers/route'
import { WizardSteps } from '~/lib/workspaces/helpers/types'
import { useWorkspacesWizard } from '~/lib/workspaces/composables/wizard'
import { useMixpanel } from '~/lib/core/composables/mp'
@@ -81,7 +81,7 @@ const requiresWorkspaceCreation = computed(() => {
const onCancelClick = () => {
if (isFirstStep.value) {
navigateTo(workspacesRoute)
navigateTo(workspaceCreateRoute())
resetWizardState()
mixpanel.stop_session_recording()
} else {
@@ -18,9 +18,15 @@
/>
<div class="text-body-2xs py-2">
You can move up to
<span class="font-medium">{{ remainingProjects }} projects</span>
<span class="font-medium">
{{ Math.max(0, remainingProjectCount) }}
{{ remainingProjectCount === 1 ? 'project' : 'projects' }}
</span>
and
<span class="font-medium">{{ remainingModels }} models</span>
<span class="font-medium">
{{ Math.max(0, remainingModelCount) }}
{{ remainingModelCount === 1 ? 'model' : 'models' }}
</span>
in total.
</div>
<div
@@ -67,12 +73,6 @@
:project="selectedProject"
event-source="move-projects-dialog"
/>
<WorkspacePlanLimitReachedDialog
v-if="activeLimit"
v-model:open="showLimitReachedDialog"
:limit="activeLimit"
:limit-type="limitType"
/>
</LayoutDialog>
</template>
<script setup lang="ts">
@@ -89,11 +89,7 @@ import type {
import { usePaginatedQuery } from '~/lib/common/composables/graphql'
import { moveProjectsDialogQuery } from '~~/lib/workspaces/graphql/queries'
import { Roles } from '@speckle/shared'
import {
useWorkspaceModelLimits,
useWorkspaceProjectLimits
} from '~/lib/workspaces/composables/limits'
import { useGetWorkspacePlanUsage } from '~/lib/workspaces/composables/usage'
import { useWorkspaceLimits } from '~/lib/workspaces/composables/limits'
graphql(`
fragment MoveProjectsDialog_Workspace on Workspace {
@@ -102,12 +98,6 @@ graphql(`
projects {
items {
id
modelCount: models(limit: 0) {
totalCount
}
versions(limit: 0) {
totalCount
}
}
}
}
@@ -162,13 +152,10 @@ const {
const selectedProject = ref<ProjectsMoveToWorkspaceDialog_ProjectFragment | null>(null)
const showMoveToWorkspaceDialog = ref(false)
const showLimitReachedDialog = ref(false)
const { projectCount, modelCount } = useGetWorkspacePlanUsage(props.workspace.slug)
const { remainingProjects, canAddProject, projectLimit } =
useWorkspaceProjectLimits(projectCount)
const { remainingModels, canAddModel, modelLimit } = useWorkspaceModelLimits(modelCount)
const { remainingModelCount, remainingProjectCount } = useWorkspaceLimits(
props.workspace.slug
)
const workspaceProjects = computed(() =>
props.workspace.projects.items.map((project) => project.id)
@@ -179,6 +166,7 @@ const moveableProjects = computed(() =>
userProjects.value.filter((project) => !workspaceProjects.value.includes(project.id))
)
const hasMoveableProjects = computed(() => moveableProjects.value.length > 0)
const buttons = computed((): LayoutDialogButton[] => [
{
text: 'Done',
@@ -189,34 +177,8 @@ const buttons = computed((): LayoutDialogButton[] => [
}
])
const limitReached = computed(() => !canAddProject.value || !canAddModel.value)
const limitType = computed(() => {
if (!canAddProject.value) {
return 'project'
}
if (!canAddModel.value) {
return 'model'
}
return null
})
const activeLimit = computed(() => {
if (!canAddProject.value) {
return projectLimit.value
}
if (!canAddModel.value) {
return modelLimit.value
}
return null
})
const onMoveClick = (project: ProjectsMoveToWorkspaceDialog_ProjectFragment) => {
selectedProject.value = project
if (limitReached.value) {
showLimitReachedDialog.value = true
} else {
showMoveToWorkspaceDialog.value = true
}
showMoveToWorkspaceDialog.value = true
}
</script>
@@ -105,7 +105,6 @@ graphql(`
...WorkspaceTeam_Workspace
...WorkspaceSecurity_Workspace
...BillingAlert_Workspace
...MoveProjectsDialog_Workspace
...InviteDialogWorkspace_Workspace
projects {
...WorkspaceProjectList_ProjectCollection
@@ -14,7 +14,8 @@
<div class="flex flex-col justify-between h-full px-5 py-4">
<NuxtImg src="/images/logo.png" alt="Speckle logo" class="h-8 w-8" />
<h3 class="text-white limit-reached-text-shadow text-base">
Plan limit reached.
<span class="capitalize">{{ props.limitType }}</span>
limit reached.
</h3>
</div>
</div>
@@ -46,7 +47,7 @@ import { settingsWorkspaceRoutes } from '~/lib/common/helpers/route'
const isOpen = defineModel<boolean>('open', { required: true })
const props = defineProps<{
limit: number
limit: Nullable<number>
limitType: Nullable<'project' | 'model'>
}>()
</script>
@@ -16,7 +16,7 @@
<script setup lang="ts">
import type { LayoutDialogButton } from '@speckle/ui-components'
import { useMixpanel } from '~/lib/core/composables/mp'
import { workspacesRoute } from '~/lib/common/helpers/route'
import { homeRoute } from '~/lib/common/helpers/route'
import {
convertThrowIntoFetchResult,
modifyObjectFields
@@ -93,7 +93,7 @@ const onConfirm = async () => {
}
}
router.push(workspacesRoute)
router.push(homeRoute)
isOpen.value = false
resetWizardState()
mixpanel.track('Workspace Creation Canceled')
@@ -101,7 +101,7 @@ type Documents = {
"\n fragment ProjectsDashboardFilledUser on UserProjectCollection {\n items {\n ...ProjectDashboardItem\n }\n }\n": typeof types.ProjectsDashboardFilledUserFragmentDoc,
"\n fragment ProjectsDeleteDialog_Project on Project {\n id\n name\n role\n models(limit: 0) {\n totalCount\n }\n workspace {\n slug\n id\n }\n versions(limit: 0) {\n totalCount\n }\n }\n": typeof types.ProjectsDeleteDialog_ProjectFragmentDoc,
"\n fragment ProjectsHiddenProjectWarning_User on User {\n id\n expiredSsoSessions {\n id\n slug\n name\n logo\n }\n }\n": typeof types.ProjectsHiddenProjectWarning_UserFragmentDoc,
"\n fragment ProjectsMoveToWorkspaceDialog_Workspace on Workspace {\n id\n role\n projectCount: projects(limit: 0) {\n totalCount\n }\n name\n logo\n ...WorkspaceHasCustomDataResidency_Workspace\n ...ProjectsWorkspaceSelect_Workspace\n }\n": typeof types.ProjectsMoveToWorkspaceDialog_WorkspaceFragmentDoc,
"\n fragment ProjectsMoveToWorkspaceDialog_Workspace on Workspace {\n id\n role\n name\n logo\n slug\n ...WorkspaceHasCustomDataResidency_Workspace\n ...ProjectsWorkspaceSelect_Workspace\n }\n": typeof types.ProjectsMoveToWorkspaceDialog_WorkspaceFragmentDoc,
"\n fragment ProjectsMoveToWorkspaceDialog_User on User {\n workspaces {\n items {\n ...ProjectsMoveToWorkspaceDialog_Workspace\n }\n }\n }\n": typeof types.ProjectsMoveToWorkspaceDialog_UserFragmentDoc,
"\n fragment ProjectsMoveToWorkspaceDialog_Project on Project {\n id\n name\n modelCount: models(limit: 0) {\n totalCount\n }\n versions(limit: 0) {\n totalCount\n }\n }\n": typeof types.ProjectsMoveToWorkspaceDialog_ProjectFragmentDoc,
"\n query ProjectsMoveToWorkspaceDialog {\n activeUser {\n id\n ...ProjectsMoveToWorkspaceDialog_User\n }\n }\n": typeof types.ProjectsMoveToWorkspaceDialogDocument,
@@ -111,7 +111,6 @@ type Documents = {
"\n fragment SettingsSidebar_User on User {\n id\n workspaces {\n items {\n ...SettingsSidebar_Workspace\n }\n }\n }\n": typeof types.SettingsSidebar_UserFragmentDoc,
"\n fragment SettingsServerRegionsAddEditDialog_ServerRegionItem on ServerRegionItem {\n id\n name\n description\n key\n }\n": typeof types.SettingsServerRegionsAddEditDialog_ServerRegionItemFragmentDoc,
"\n fragment SettingsServerRegionsTable_ServerRegionItem on ServerRegionItem {\n id\n name\n key\n description\n }\n": typeof types.SettingsServerRegionsTable_ServerRegionItemFragmentDoc,
"\n fragment SettingsSharedDeleteUserDialog_Workspace on Workspace {\n id\n plan {\n status\n name\n }\n subscription {\n currentBillingCycleEnd\n seats {\n guest\n plan\n }\n }\n }\n": typeof types.SettingsSharedDeleteUserDialog_WorkspaceFragmentDoc,
"\n fragment SettingsSharedProjects_Project on Project {\n ...ProjectsDeleteDialog_Project\n id\n name\n visibility\n createdAt\n updatedAt\n models(limit: 0) {\n totalCount\n }\n versions(limit: 0) {\n totalCount\n }\n team {\n id\n user {\n name\n id\n avatar\n }\n }\n }\n": typeof types.SettingsSharedProjects_ProjectFragmentDoc,
"\n fragment SettingsUserProfileChangePassword_User on User {\n id\n email\n }\n": typeof types.SettingsUserProfileChangePassword_UserFragmentDoc,
"\n fragment SettingsUserProfileDeleteAccount_User on User {\n id\n email\n }\n": typeof types.SettingsUserProfileDeleteAccount_UserFragmentDoc,
@@ -121,27 +120,25 @@ type Documents = {
"\n fragment SettingsWorkspacesGeneralEditAvatar_Workspace on Workspace {\n id\n logo\n name\n }\n": typeof types.SettingsWorkspacesGeneralEditAvatar_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesGeneralEditSlugDialog_Workspace on Workspace {\n id\n name\n slug\n }\n": typeof types.SettingsWorkspacesGeneralEditSlugDialog_WorkspaceFragmentDoc,
"\n fragment WorkspaceBillingPage_Workspace on Workspace {\n id\n role\n }\n": typeof types.WorkspaceBillingPage_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesMembersChangeRoleDialog_Workspace on Workspace {\n id\n plan {\n status\n name\n }\n subscription {\n currentBillingCycleEnd\n seats {\n guest\n plan\n }\n }\n }\n": typeof types.SettingsWorkspacesMembersChangeRoleDialog_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n seatType\n joinDate\n user {\n id\n avatar\n name\n workspaceDomainPolicyCompliant(workspaceSlug: $slug)\n }\n projectRoles {\n role\n project {\n id\n name\n }\n }\n }\n": typeof types.SettingsWorkspacesMembersGuestsTable_WorkspaceCollaboratorFragmentDoc,
"\n fragment SettingsWorkspacesMembersGuestsTable_Workspace on Workspace {\n id\n slug\n name\n ...SettingsWorkspacesMembersTableHeader_Workspace\n ...SettingsSharedDeleteUserDialog_Workspace\n team(limit: 250) {\n items {\n id\n ...SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator\n }\n }\n }\n": typeof types.SettingsWorkspacesMembersGuestsTable_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesMembersGuestsTable_Workspace on Workspace {\n id\n slug\n name\n ...SettingsWorkspacesMembersTableHeader_Workspace\n team(limit: 250) {\n items {\n id\n ...SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator\n }\n }\n }\n": typeof types.SettingsWorkspacesMembersGuestsTable_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n inviteId\n role\n title\n updatedAt\n user {\n id\n ...LimitedUserAvatar\n }\n invitedBy {\n id\n ...LimitedUserAvatar\n }\n }\n": typeof types.SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaboratorFragmentDoc,
"\n fragment SettingsWorkspacesMembersInvitesTable_Workspace on Workspace {\n id\n ...SettingsWorkspacesMembersTableHeader_Workspace\n invitedTeam {\n ...SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator\n }\n }\n": typeof types.SettingsWorkspacesMembersInvitesTable_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesMembersRequestsTable_Workspace on Workspace {\n ...SettingsWorkspacesMembersTableHeader_Workspace\n id\n adminWorkspacesJoinRequests {\n totalCount\n items {\n ...WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequest\n id\n createdAt\n status\n user {\n id\n avatar\n name\n }\n }\n }\n }\n": typeof types.SettingsWorkspacesMembersRequestsTable_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesMembersTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n seatType\n joinDate\n user {\n id\n avatar\n name\n workspaceDomainPolicyCompliant(workspaceSlug: $slug)\n }\n }\n": typeof types.SettingsWorkspacesMembersTable_WorkspaceCollaboratorFragmentDoc,
"\n fragment SettingsWorkspacesMembersTable_Workspace on Workspace {\n id\n slug\n name\n ...SettingsSharedDeleteUserDialog_Workspace\n ...SettingsWorkspacesMembersTableHeader_Workspace\n team(limit: 250) {\n items {\n id\n ...SettingsWorkspacesMembersTable_WorkspaceCollaborator\n }\n }\n }\n": typeof types.SettingsWorkspacesMembersTable_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesMembersTable_Workspace on Workspace {\n id\n slug\n name\n ...SettingsWorkspacesMembersTableHeader_Workspace\n team(limit: 250) {\n items {\n id\n ...SettingsWorkspacesMembersTable_WorkspaceCollaborator\n }\n }\n }\n": typeof types.SettingsWorkspacesMembersTable_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesMembersTableHeader_Workspace on Workspace {\n id\n role\n ...InviteDialogWorkspace_Workspace\n }\n": typeof types.SettingsWorkspacesMembersTableHeader_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesRegionsSelect_ServerRegionItem on ServerRegionItem {\n id\n key\n name\n description\n }\n": typeof types.SettingsWorkspacesRegionsSelect_ServerRegionItemFragmentDoc,
"\n fragment SettingsWorkspacesSecurityDomainRemoveDialog_WorkspaceDomain on WorkspaceDomain {\n id\n domain\n }\n": typeof types.SettingsWorkspacesSecurityDomainRemoveDialog_WorkspaceDomainFragmentDoc,
"\n fragment SettingsWorkspacesSecurityDomainRemoveDialog_Workspace on Workspace {\n id\n domains {\n ...SettingsWorkspacesSecurityDomainRemoveDialog_WorkspaceDomain\n }\n }\n": typeof types.SettingsWorkspacesSecurityDomainRemoveDialog_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesSecuritySsoWrapper_Workspace on Workspace {\n id\n role\n slug\n sso {\n provider {\n id\n name\n clientId\n issuerUrl\n }\n }\n hasAccessToSSO: hasAccessToFeature(featureName: oidcSso)\n }\n": typeof types.SettingsWorkspacesSecuritySsoWrapper_WorkspaceFragmentDoc,
"\n fragment Sidebar_User on User {\n id\n automateFunctions {\n items {\n id\n name\n description\n logo\n }\n }\n }\n": typeof types.Sidebar_UserFragmentDoc,
"\n fragment ModelPageProject on Project {\n id\n createdAt\n name\n visibility\n workspace {\n id\n slug\n name\n }\n }\n": typeof types.ModelPageProjectFragmentDoc,
"\n fragment ThreadCommentAttachment on Comment {\n text {\n attachments {\n id\n fileName\n fileType\n fileSize\n }\n }\n }\n": typeof types.ThreadCommentAttachmentFragmentDoc,
"\n fragment ViewerCommentsListItem on Comment {\n id\n rawText\n archived\n author {\n ...LimitedUserAvatar\n }\n createdAt\n viewedAt\n replies {\n totalCount\n cursor\n items {\n ...ViewerCommentsReplyItem\n }\n }\n replyAuthors(limit: 4) {\n totalCount\n items {\n ...FormUsersSelectItem\n }\n }\n resources {\n resourceId\n resourceType\n }\n }\n": typeof types.ViewerCommentsListItemFragmentDoc,
"\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 MoveProjectsDialog_Workspace on Workspace {\n id\n ...ProjectsMoveToWorkspaceDialog_Workspace\n projects {\n items {\n id\n modelCount: models(limit: 0) {\n totalCount\n }\n versions(limit: 0) {\n totalCount\n }\n }\n }\n }\n": typeof types.MoveProjectsDialog_WorkspaceFragmentDoc,
"\n fragment MoveProjectsDialog_Workspace on Workspace {\n id\n ...ProjectsMoveToWorkspaceDialog_Workspace\n projects {\n items {\n id\n }\n }\n }\n": typeof types.MoveProjectsDialog_WorkspaceFragmentDoc,
"\n fragment MoveProjectsDialog_User on User {\n projects(cursor: $cursor, filter: $filter, limit: 10) {\n totalCount\n cursor\n items {\n ...ProjectsMoveToWorkspaceDialog_Project\n role\n workspace {\n id\n }\n }\n }\n }\n": typeof types.MoveProjectsDialog_UserFragmentDoc,
"\n fragment WorkspaceProjectList_Workspace on Workspace {\n id\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...WorkspaceSecurity_Workspace\n ...BillingAlert_Workspace\n ...MoveProjectsDialog_Workspace\n ...InviteDialogWorkspace_Workspace\n projects {\n ...WorkspaceProjectList_ProjectCollection\n }\n creationState {\n completed\n state\n }\n readOnly\n }\n": typeof types.WorkspaceProjectList_WorkspaceFragmentDoc,
"\n fragment WorkspaceProjectList_Workspace on Workspace {\n id\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...WorkspaceSecurity_Workspace\n ...BillingAlert_Workspace\n ...InviteDialogWorkspace_Workspace\n projects {\n ...WorkspaceProjectList_ProjectCollection\n }\n creationState {\n completed\n state\n }\n readOnly\n }\n": typeof types.WorkspaceProjectList_WorkspaceFragmentDoc,
"\n fragment WorkspaceProjectList_ProjectCollection on ProjectCollection {\n totalCount\n items {\n ...ProjectDashboardItem\n }\n cursor\n }\n": typeof types.WorkspaceProjectList_ProjectCollectionFragmentDoc,
"\n fragment WorkspaceHeader_Workspace on Workspace {\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...BillingAlert_Workspace\n slug\n readOnly\n }\n": typeof types.WorkspaceHeader_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,
@@ -310,7 +307,6 @@ type Documents = {
"\n mutation SettingsLeaveWorkspace($leaveId: ID!) {\n workspaceMutations {\n leave(id: $leaveId)\n }\n }\n": typeof types.SettingsLeaveWorkspaceDocument,
"\n mutation SettingsBillingCancelCheckoutSession($input: CancelCheckoutSessionInput!) {\n workspaceMutations {\n billing {\n cancelCheckoutSession(input: $input)\n }\n }\n }\n": typeof types.SettingsBillingCancelCheckoutSessionDocument,
"\n query SettingsSidebar {\n activeUser {\n ...SettingsSidebar_User\n }\n }\n": typeof types.SettingsSidebarDocument,
"\n query SettingsSidebarAutomateFunctions {\n activeUser {\n ...Sidebar_User\n }\n }\n": typeof types.SettingsSidebarAutomateFunctionsDocument,
"\n query SettingsWorkspaceGeneral($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesGeneral_Workspace\n }\n }\n": typeof types.SettingsWorkspaceGeneralDocument,
"\n query SettingsWorkspaceBilling($slug: String!) {\n workspaceBySlug(slug: $slug) {\n id\n ...WorkspaceBillingPage_Workspace\n }\n }\n": typeof types.SettingsWorkspaceBillingDocument,
"\n query SettingsWorkspaceBillingCustomerPortal($workspaceId: String!) {\n workspace(id: $workspaceId) {\n customerPortalUrl\n }\n }\n": typeof types.SettingsWorkspaceBillingCustomerPortalDocument,
@@ -353,14 +349,15 @@ type Documents = {
"\n fragment LinkableComment on Comment {\n id\n viewerResources {\n modelId\n versionId\n objectId\n }\n }\n": typeof types.LinkableCommentFragmentDoc,
"\n fragment DiscoverableList_Discoverable on User {\n discoverableWorkspaces {\n id\n name\n logo\n description\n slug\n team {\n totalCount\n items {\n avatar\n }\n }\n }\n }\n": typeof types.DiscoverableList_DiscoverableFragmentDoc,
"\n fragment DiscoverableList_Requests on User {\n workspaceJoinRequests {\n items {\n id\n status\n workspace {\n id\n name\n logo\n slug\n team {\n totalCount\n items {\n avatar\n }\n }\n }\n }\n }\n }\n": typeof types.DiscoverableList_RequestsFragmentDoc,
"\n fragment WorkspacePlanLimits_Workspace on Workspace {\n id\n plan {\n name\n }\n }\n": typeof types.WorkspacePlanLimits_WorkspaceFragmentDoc,
"\n fragment UseWorkspaceInviteManager_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n token\n workspaceId\n workspaceSlug\n user {\n id\n }\n }\n": typeof types.UseWorkspaceInviteManager_PendingWorkspaceCollaboratorFragmentDoc,
"\n fragment WorkspacesPlan_Workspace on Workspace {\n id\n plan {\n status\n createdAt\n name\n paymentMethod\n usage {\n projectCount\n modelCount\n }\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n seats {\n totalCount\n assigned\n viewersCount\n }\n }\n }\n": typeof types.WorkspacesPlan_WorkspaceFragmentDoc,
"\n fragment WorkspacePlanLimits_Workspace on Workspace {\n id\n projects(limit: 0) {\n totalCount\n items {\n id\n models(limit: 0) {\n totalCount\n }\n }\n }\n plan {\n name\n }\n }\n": typeof types.WorkspacePlanLimits_WorkspaceFragmentDoc,
"\n fragment WorkspacesPlan_Workspace on Workspace {\n id\n plan {\n status\n createdAt\n name\n paymentMethod\n usage {\n projectCount\n modelCount\n }\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n seats {\n editors {\n available\n assigned\n }\n viewers {\n available\n assigned\n }\n }\n }\n }\n": typeof types.WorkspacesPlan_WorkspaceFragmentDoc,
"\n subscription OnWorkspaceProjectsUpdate($slug: String!) {\n workspaceProjectsUpdated(workspaceId: null, workspaceSlug: $slug) {\n projectId\n workspaceId\n type\n project {\n ...ProjectDashboardItem\n }\n }\n }\n ": typeof types.OnWorkspaceProjectsUpdateDocument,
"\n fragment WorkspaceHasCustomDataResidency_Workspace on Workspace {\n id\n defaultRegion {\n id\n name\n }\n }\n": typeof types.WorkspaceHasCustomDataResidency_WorkspaceFragmentDoc,
"\n query CheckProjectWorkspaceDataResidency($projectId: String!) {\n project(id: $projectId) {\n id\n workspace {\n ...WorkspaceHasCustomDataResidency_Workspace\n }\n }\n }\n": typeof types.CheckProjectWorkspaceDataResidencyDocument,
"\n fragment WorkspaceSsoStatus_Workspace on Workspace {\n id\n sso {\n provider {\n id\n name\n clientId\n issuerUrl\n }\n session {\n validUntil\n }\n }\n }\n ": typeof types.WorkspaceSsoStatus_WorkspaceFragmentDoc,
"\n fragment WorkspaceSsoStatus_User on User {\n expiredSsoSessions {\n id\n slug\n }\n }\n ": typeof types.WorkspaceSsoStatus_UserFragmentDoc,
"\n fragment WorkspaceUsage_Workspace on Workspace {\n id\n plan {\n usage {\n projectCount\n modelCount\n }\n }\n }\n": typeof types.WorkspaceUsage_WorkspaceFragmentDoc,
"\n fragment WorkspaceBase_Workspace on Workspace {\n id\n name\n slug\n role\n description\n logo\n plan {\n status\n createdAt\n }\n }\n": typeof types.WorkspaceBase_WorkspaceFragmentDoc,
"\n fragment WorkspaceDashboardAbout_Workspace on Workspace {\n id\n name\n description\n }\n": typeof types.WorkspaceDashboardAbout_WorkspaceFragmentDoc,
"\n fragment WorkspaceInvitedTeam_Workspace on Workspace {\n id\n invitedTeam(filter: $invitesFilter) {\n id\n role\n email\n }\n }\n": typeof types.WorkspaceInvitedTeam_WorkspaceFragmentDoc,
@@ -396,7 +393,8 @@ type Documents = {
"\n query DiscoverableWorkspacesRequests {\n activeUser {\n id\n ...DiscoverableList_Requests\n }\n }\n": typeof types.DiscoverableWorkspacesRequestsDocument,
"\n query WorkspacePlan($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacesPlan_Workspace\n }\n }\n": typeof types.WorkspacePlanDocument,
"\n query WorkspaceLastAdminCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspaceLastAdminCheck_Workspace\n }\n }\n": typeof types.WorkspaceLastAdminCheckDocument,
"\n query WorkspacePlanLimits($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacePlanLimits_Workspace\n }\n }\n": typeof types.WorkspacePlanLimitsDocument,
"\n query WorkspaceLimits($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacePlanLimits_Workspace\n }\n }\n": typeof types.WorkspaceLimitsDocument,
"\n query WorkspaceUsage($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspaceUsage_Workspace\n }\n }\n": typeof types.WorkspaceUsageDocument,
"\n subscription onWorkspaceUpdated(\n $workspaceId: String\n $workspaceSlug: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceUpdated(workspaceId: $workspaceId, workspaceSlug: $workspaceSlug) {\n id\n workspace {\n id\n ...WorkspaceProjectList_Workspace\n }\n }\n }\n": typeof types.OnWorkspaceUpdatedDocument,
"\n query LegacyBranchRedirectMetadata($streamId: String!, $branchName: String!) {\n project(id: $streamId) {\n modelByName(name: $branchName) {\n id\n }\n }\n }\n": typeof types.LegacyBranchRedirectMetadataDocument,
"\n query LegacyViewerCommitRedirectMetadata($streamId: String!, $commitId: String!) {\n project(id: $streamId) {\n version(id: $commitId) {\n id\n model {\n id\n }\n }\n }\n }\n": typeof types.LegacyViewerCommitRedirectMetadataDocument,
@@ -507,7 +505,7 @@ const documents: Documents = {
"\n fragment ProjectsDashboardFilledUser on UserProjectCollection {\n items {\n ...ProjectDashboardItem\n }\n }\n": types.ProjectsDashboardFilledUserFragmentDoc,
"\n fragment ProjectsDeleteDialog_Project on Project {\n id\n name\n role\n models(limit: 0) {\n totalCount\n }\n workspace {\n slug\n id\n }\n versions(limit: 0) {\n totalCount\n }\n }\n": types.ProjectsDeleteDialog_ProjectFragmentDoc,
"\n fragment ProjectsHiddenProjectWarning_User on User {\n id\n expiredSsoSessions {\n id\n slug\n name\n logo\n }\n }\n": types.ProjectsHiddenProjectWarning_UserFragmentDoc,
"\n fragment ProjectsMoveToWorkspaceDialog_Workspace on Workspace {\n id\n role\n projectCount: projects(limit: 0) {\n totalCount\n }\n name\n logo\n ...WorkspaceHasCustomDataResidency_Workspace\n ...ProjectsWorkspaceSelect_Workspace\n }\n": types.ProjectsMoveToWorkspaceDialog_WorkspaceFragmentDoc,
"\n fragment ProjectsMoveToWorkspaceDialog_Workspace on Workspace {\n id\n role\n name\n logo\n slug\n ...WorkspaceHasCustomDataResidency_Workspace\n ...ProjectsWorkspaceSelect_Workspace\n }\n": types.ProjectsMoveToWorkspaceDialog_WorkspaceFragmentDoc,
"\n fragment ProjectsMoveToWorkspaceDialog_User on User {\n workspaces {\n items {\n ...ProjectsMoveToWorkspaceDialog_Workspace\n }\n }\n }\n": types.ProjectsMoveToWorkspaceDialog_UserFragmentDoc,
"\n fragment ProjectsMoveToWorkspaceDialog_Project on Project {\n id\n name\n modelCount: models(limit: 0) {\n totalCount\n }\n versions(limit: 0) {\n totalCount\n }\n }\n": types.ProjectsMoveToWorkspaceDialog_ProjectFragmentDoc,
"\n query ProjectsMoveToWorkspaceDialog {\n activeUser {\n id\n ...ProjectsMoveToWorkspaceDialog_User\n }\n }\n": types.ProjectsMoveToWorkspaceDialogDocument,
@@ -517,7 +515,6 @@ const documents: Documents = {
"\n fragment SettingsSidebar_User on User {\n id\n workspaces {\n items {\n ...SettingsSidebar_Workspace\n }\n }\n }\n": types.SettingsSidebar_UserFragmentDoc,
"\n fragment SettingsServerRegionsAddEditDialog_ServerRegionItem on ServerRegionItem {\n id\n name\n description\n key\n }\n": types.SettingsServerRegionsAddEditDialog_ServerRegionItemFragmentDoc,
"\n fragment SettingsServerRegionsTable_ServerRegionItem on ServerRegionItem {\n id\n name\n key\n description\n }\n": types.SettingsServerRegionsTable_ServerRegionItemFragmentDoc,
"\n fragment SettingsSharedDeleteUserDialog_Workspace on Workspace {\n id\n plan {\n status\n name\n }\n subscription {\n currentBillingCycleEnd\n seats {\n guest\n plan\n }\n }\n }\n": types.SettingsSharedDeleteUserDialog_WorkspaceFragmentDoc,
"\n fragment SettingsSharedProjects_Project on Project {\n ...ProjectsDeleteDialog_Project\n id\n name\n visibility\n createdAt\n updatedAt\n models(limit: 0) {\n totalCount\n }\n versions(limit: 0) {\n totalCount\n }\n team {\n id\n user {\n name\n id\n avatar\n }\n }\n }\n": types.SettingsSharedProjects_ProjectFragmentDoc,
"\n fragment SettingsUserProfileChangePassword_User on User {\n id\n email\n }\n": types.SettingsUserProfileChangePassword_UserFragmentDoc,
"\n fragment SettingsUserProfileDeleteAccount_User on User {\n id\n email\n }\n": types.SettingsUserProfileDeleteAccount_UserFragmentDoc,
@@ -527,27 +524,25 @@ const documents: Documents = {
"\n fragment SettingsWorkspacesGeneralEditAvatar_Workspace on Workspace {\n id\n logo\n name\n }\n": types.SettingsWorkspacesGeneralEditAvatar_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesGeneralEditSlugDialog_Workspace on Workspace {\n id\n name\n slug\n }\n": types.SettingsWorkspacesGeneralEditSlugDialog_WorkspaceFragmentDoc,
"\n fragment WorkspaceBillingPage_Workspace on Workspace {\n id\n role\n }\n": types.WorkspaceBillingPage_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesMembersChangeRoleDialog_Workspace on Workspace {\n id\n plan {\n status\n name\n }\n subscription {\n currentBillingCycleEnd\n seats {\n guest\n plan\n }\n }\n }\n": types.SettingsWorkspacesMembersChangeRoleDialog_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n seatType\n joinDate\n user {\n id\n avatar\n name\n workspaceDomainPolicyCompliant(workspaceSlug: $slug)\n }\n projectRoles {\n role\n project {\n id\n name\n }\n }\n }\n": types.SettingsWorkspacesMembersGuestsTable_WorkspaceCollaboratorFragmentDoc,
"\n fragment SettingsWorkspacesMembersGuestsTable_Workspace on Workspace {\n id\n slug\n name\n ...SettingsWorkspacesMembersTableHeader_Workspace\n ...SettingsSharedDeleteUserDialog_Workspace\n team(limit: 250) {\n items {\n id\n ...SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator\n }\n }\n }\n": types.SettingsWorkspacesMembersGuestsTable_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesMembersGuestsTable_Workspace on Workspace {\n id\n slug\n name\n ...SettingsWorkspacesMembersTableHeader_Workspace\n team(limit: 250) {\n items {\n id\n ...SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator\n }\n }\n }\n": types.SettingsWorkspacesMembersGuestsTable_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n inviteId\n role\n title\n updatedAt\n user {\n id\n ...LimitedUserAvatar\n }\n invitedBy {\n id\n ...LimitedUserAvatar\n }\n }\n": types.SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaboratorFragmentDoc,
"\n fragment SettingsWorkspacesMembersInvitesTable_Workspace on Workspace {\n id\n ...SettingsWorkspacesMembersTableHeader_Workspace\n invitedTeam {\n ...SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator\n }\n }\n": types.SettingsWorkspacesMembersInvitesTable_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesMembersRequestsTable_Workspace on Workspace {\n ...SettingsWorkspacesMembersTableHeader_Workspace\n id\n adminWorkspacesJoinRequests {\n totalCount\n items {\n ...WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequest\n id\n createdAt\n status\n user {\n id\n avatar\n name\n }\n }\n }\n }\n": types.SettingsWorkspacesMembersRequestsTable_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesMembersTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n seatType\n joinDate\n user {\n id\n avatar\n name\n workspaceDomainPolicyCompliant(workspaceSlug: $slug)\n }\n }\n": types.SettingsWorkspacesMembersTable_WorkspaceCollaboratorFragmentDoc,
"\n fragment SettingsWorkspacesMembersTable_Workspace on Workspace {\n id\n slug\n name\n ...SettingsSharedDeleteUserDialog_Workspace\n ...SettingsWorkspacesMembersTableHeader_Workspace\n team(limit: 250) {\n items {\n id\n ...SettingsWorkspacesMembersTable_WorkspaceCollaborator\n }\n }\n }\n": types.SettingsWorkspacesMembersTable_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesMembersTable_Workspace on Workspace {\n id\n slug\n name\n ...SettingsWorkspacesMembersTableHeader_Workspace\n team(limit: 250) {\n items {\n id\n ...SettingsWorkspacesMembersTable_WorkspaceCollaborator\n }\n }\n }\n": types.SettingsWorkspacesMembersTable_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesMembersTableHeader_Workspace on Workspace {\n id\n role\n ...InviteDialogWorkspace_Workspace\n }\n": types.SettingsWorkspacesMembersTableHeader_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesRegionsSelect_ServerRegionItem on ServerRegionItem {\n id\n key\n name\n description\n }\n": types.SettingsWorkspacesRegionsSelect_ServerRegionItemFragmentDoc,
"\n fragment SettingsWorkspacesSecurityDomainRemoveDialog_WorkspaceDomain on WorkspaceDomain {\n id\n domain\n }\n": types.SettingsWorkspacesSecurityDomainRemoveDialog_WorkspaceDomainFragmentDoc,
"\n fragment SettingsWorkspacesSecurityDomainRemoveDialog_Workspace on Workspace {\n id\n domains {\n ...SettingsWorkspacesSecurityDomainRemoveDialog_WorkspaceDomain\n }\n }\n": types.SettingsWorkspacesSecurityDomainRemoveDialog_WorkspaceFragmentDoc,
"\n fragment SettingsWorkspacesSecuritySsoWrapper_Workspace on Workspace {\n id\n role\n slug\n sso {\n provider {\n id\n name\n clientId\n issuerUrl\n }\n }\n hasAccessToSSO: hasAccessToFeature(featureName: oidcSso)\n }\n": types.SettingsWorkspacesSecuritySsoWrapper_WorkspaceFragmentDoc,
"\n fragment Sidebar_User on User {\n id\n automateFunctions {\n items {\n id\n name\n description\n logo\n }\n }\n }\n": types.Sidebar_UserFragmentDoc,
"\n fragment ModelPageProject on Project {\n id\n createdAt\n name\n visibility\n workspace {\n id\n slug\n name\n }\n }\n": types.ModelPageProjectFragmentDoc,
"\n fragment ThreadCommentAttachment on Comment {\n text {\n attachments {\n id\n fileName\n fileType\n fileSize\n }\n }\n }\n": types.ThreadCommentAttachmentFragmentDoc,
"\n fragment ViewerCommentsListItem on Comment {\n id\n rawText\n archived\n author {\n ...LimitedUserAvatar\n }\n createdAt\n viewedAt\n replies {\n totalCount\n cursor\n items {\n ...ViewerCommentsReplyItem\n }\n }\n replyAuthors(limit: 4) {\n totalCount\n items {\n ...FormUsersSelectItem\n }\n }\n resources {\n resourceId\n resourceType\n }\n }\n": types.ViewerCommentsListItemFragmentDoc,
"\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 MoveProjectsDialog_Workspace on Workspace {\n id\n ...ProjectsMoveToWorkspaceDialog_Workspace\n projects {\n items {\n id\n modelCount: models(limit: 0) {\n totalCount\n }\n versions(limit: 0) {\n totalCount\n }\n }\n }\n }\n": types.MoveProjectsDialog_WorkspaceFragmentDoc,
"\n fragment MoveProjectsDialog_Workspace on Workspace {\n id\n ...ProjectsMoveToWorkspaceDialog_Workspace\n projects {\n items {\n id\n }\n }\n }\n": types.MoveProjectsDialog_WorkspaceFragmentDoc,
"\n fragment MoveProjectsDialog_User on User {\n projects(cursor: $cursor, filter: $filter, limit: 10) {\n totalCount\n cursor\n items {\n ...ProjectsMoveToWorkspaceDialog_Project\n role\n workspace {\n id\n }\n }\n }\n }\n": types.MoveProjectsDialog_UserFragmentDoc,
"\n fragment WorkspaceProjectList_Workspace on Workspace {\n id\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...WorkspaceSecurity_Workspace\n ...BillingAlert_Workspace\n ...MoveProjectsDialog_Workspace\n ...InviteDialogWorkspace_Workspace\n projects {\n ...WorkspaceProjectList_ProjectCollection\n }\n creationState {\n completed\n state\n }\n readOnly\n }\n": types.WorkspaceProjectList_WorkspaceFragmentDoc,
"\n fragment WorkspaceProjectList_Workspace on Workspace {\n id\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...WorkspaceSecurity_Workspace\n ...BillingAlert_Workspace\n ...InviteDialogWorkspace_Workspace\n projects {\n ...WorkspaceProjectList_ProjectCollection\n }\n creationState {\n completed\n state\n }\n readOnly\n }\n": types.WorkspaceProjectList_WorkspaceFragmentDoc,
"\n fragment WorkspaceProjectList_ProjectCollection on ProjectCollection {\n totalCount\n items {\n ...ProjectDashboardItem\n }\n cursor\n }\n": types.WorkspaceProjectList_ProjectCollectionFragmentDoc,
"\n fragment WorkspaceHeader_Workspace on Workspace {\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...BillingAlert_Workspace\n slug\n readOnly\n }\n": types.WorkspaceHeader_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,
@@ -716,7 +711,6 @@ const documents: Documents = {
"\n mutation SettingsLeaveWorkspace($leaveId: ID!) {\n workspaceMutations {\n leave(id: $leaveId)\n }\n }\n": types.SettingsLeaveWorkspaceDocument,
"\n mutation SettingsBillingCancelCheckoutSession($input: CancelCheckoutSessionInput!) {\n workspaceMutations {\n billing {\n cancelCheckoutSession(input: $input)\n }\n }\n }\n": types.SettingsBillingCancelCheckoutSessionDocument,
"\n query SettingsSidebar {\n activeUser {\n ...SettingsSidebar_User\n }\n }\n": types.SettingsSidebarDocument,
"\n query SettingsSidebarAutomateFunctions {\n activeUser {\n ...Sidebar_User\n }\n }\n": types.SettingsSidebarAutomateFunctionsDocument,
"\n query SettingsWorkspaceGeneral($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesGeneral_Workspace\n }\n }\n": types.SettingsWorkspaceGeneralDocument,
"\n query SettingsWorkspaceBilling($slug: String!) {\n workspaceBySlug(slug: $slug) {\n id\n ...WorkspaceBillingPage_Workspace\n }\n }\n": types.SettingsWorkspaceBillingDocument,
"\n query SettingsWorkspaceBillingCustomerPortal($workspaceId: String!) {\n workspace(id: $workspaceId) {\n customerPortalUrl\n }\n }\n": types.SettingsWorkspaceBillingCustomerPortalDocument,
@@ -759,14 +753,15 @@ const documents: Documents = {
"\n fragment LinkableComment on Comment {\n id\n viewerResources {\n modelId\n versionId\n objectId\n }\n }\n": types.LinkableCommentFragmentDoc,
"\n fragment DiscoverableList_Discoverable on User {\n discoverableWorkspaces {\n id\n name\n logo\n description\n slug\n team {\n totalCount\n items {\n avatar\n }\n }\n }\n }\n": types.DiscoverableList_DiscoverableFragmentDoc,
"\n fragment DiscoverableList_Requests on User {\n workspaceJoinRequests {\n items {\n id\n status\n workspace {\n id\n name\n logo\n slug\n team {\n totalCount\n items {\n avatar\n }\n }\n }\n }\n }\n }\n": types.DiscoverableList_RequestsFragmentDoc,
"\n fragment WorkspacePlanLimits_Workspace on Workspace {\n id\n plan {\n name\n }\n }\n": types.WorkspacePlanLimits_WorkspaceFragmentDoc,
"\n fragment UseWorkspaceInviteManager_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n token\n workspaceId\n workspaceSlug\n user {\n id\n }\n }\n": types.UseWorkspaceInviteManager_PendingWorkspaceCollaboratorFragmentDoc,
"\n fragment WorkspacesPlan_Workspace on Workspace {\n id\n plan {\n status\n createdAt\n name\n paymentMethod\n usage {\n projectCount\n modelCount\n }\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n seats {\n totalCount\n assigned\n viewersCount\n }\n }\n }\n": types.WorkspacesPlan_WorkspaceFragmentDoc,
"\n fragment WorkspacePlanLimits_Workspace on Workspace {\n id\n projects(limit: 0) {\n totalCount\n items {\n id\n models(limit: 0) {\n totalCount\n }\n }\n }\n plan {\n name\n }\n }\n": types.WorkspacePlanLimits_WorkspaceFragmentDoc,
"\n fragment WorkspacesPlan_Workspace on Workspace {\n id\n plan {\n status\n createdAt\n name\n paymentMethod\n usage {\n projectCount\n modelCount\n }\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n seats {\n editors {\n available\n assigned\n }\n viewers {\n available\n assigned\n }\n }\n }\n }\n": types.WorkspacesPlan_WorkspaceFragmentDoc,
"\n subscription OnWorkspaceProjectsUpdate($slug: String!) {\n workspaceProjectsUpdated(workspaceId: null, workspaceSlug: $slug) {\n projectId\n workspaceId\n type\n project {\n ...ProjectDashboardItem\n }\n }\n }\n ": types.OnWorkspaceProjectsUpdateDocument,
"\n fragment WorkspaceHasCustomDataResidency_Workspace on Workspace {\n id\n defaultRegion {\n id\n name\n }\n }\n": types.WorkspaceHasCustomDataResidency_WorkspaceFragmentDoc,
"\n query CheckProjectWorkspaceDataResidency($projectId: String!) {\n project(id: $projectId) {\n id\n workspace {\n ...WorkspaceHasCustomDataResidency_Workspace\n }\n }\n }\n": types.CheckProjectWorkspaceDataResidencyDocument,
"\n fragment WorkspaceSsoStatus_Workspace on Workspace {\n id\n sso {\n provider {\n id\n name\n clientId\n issuerUrl\n }\n session {\n validUntil\n }\n }\n }\n ": types.WorkspaceSsoStatus_WorkspaceFragmentDoc,
"\n fragment WorkspaceSsoStatus_User on User {\n expiredSsoSessions {\n id\n slug\n }\n }\n ": types.WorkspaceSsoStatus_UserFragmentDoc,
"\n fragment WorkspaceUsage_Workspace on Workspace {\n id\n plan {\n usage {\n projectCount\n modelCount\n }\n }\n }\n": types.WorkspaceUsage_WorkspaceFragmentDoc,
"\n fragment WorkspaceBase_Workspace on Workspace {\n id\n name\n slug\n role\n description\n logo\n plan {\n status\n createdAt\n }\n }\n": types.WorkspaceBase_WorkspaceFragmentDoc,
"\n fragment WorkspaceDashboardAbout_Workspace on Workspace {\n id\n name\n description\n }\n": types.WorkspaceDashboardAbout_WorkspaceFragmentDoc,
"\n fragment WorkspaceInvitedTeam_Workspace on Workspace {\n id\n invitedTeam(filter: $invitesFilter) {\n id\n role\n email\n }\n }\n": types.WorkspaceInvitedTeam_WorkspaceFragmentDoc,
@@ -802,7 +797,8 @@ const documents: Documents = {
"\n query DiscoverableWorkspacesRequests {\n activeUser {\n id\n ...DiscoverableList_Requests\n }\n }\n": types.DiscoverableWorkspacesRequestsDocument,
"\n query WorkspacePlan($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacesPlan_Workspace\n }\n }\n": types.WorkspacePlanDocument,
"\n query WorkspaceLastAdminCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspaceLastAdminCheck_Workspace\n }\n }\n": types.WorkspaceLastAdminCheckDocument,
"\n query WorkspacePlanLimits($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacePlanLimits_Workspace\n }\n }\n": types.WorkspacePlanLimitsDocument,
"\n query WorkspaceLimits($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacePlanLimits_Workspace\n }\n }\n": types.WorkspaceLimitsDocument,
"\n query WorkspaceUsage($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspaceUsage_Workspace\n }\n }\n": types.WorkspaceUsageDocument,
"\n subscription onWorkspaceUpdated(\n $workspaceId: String\n $workspaceSlug: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceUpdated(workspaceId: $workspaceId, workspaceSlug: $workspaceSlug) {\n id\n workspace {\n id\n ...WorkspaceProjectList_Workspace\n }\n }\n }\n": types.OnWorkspaceUpdatedDocument,
"\n query LegacyBranchRedirectMetadata($streamId: String!, $branchName: String!) {\n project(id: $streamId) {\n modelByName(name: $branchName) {\n id\n }\n }\n }\n": types.LegacyBranchRedirectMetadataDocument,
"\n query LegacyViewerCommitRedirectMetadata($streamId: String!, $commitId: String!) {\n project(id: $streamId) {\n version(id: $commitId) {\n id\n model {\n id\n }\n }\n }\n }\n": types.LegacyViewerCommitRedirectMetadataDocument,
@@ -1191,7 +1187,7 @@ export function graphql(source: "\n fragment ProjectsHiddenProjectWarning_User
/**
* 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 ProjectsMoveToWorkspaceDialog_Workspace on Workspace {\n id\n role\n projectCount: projects(limit: 0) {\n totalCount\n }\n name\n logo\n ...WorkspaceHasCustomDataResidency_Workspace\n ...ProjectsWorkspaceSelect_Workspace\n }\n"): (typeof documents)["\n fragment ProjectsMoveToWorkspaceDialog_Workspace on Workspace {\n id\n role\n projectCount: projects(limit: 0) {\n totalCount\n }\n name\n logo\n ...WorkspaceHasCustomDataResidency_Workspace\n ...ProjectsWorkspaceSelect_Workspace\n }\n"];
export function graphql(source: "\n fragment ProjectsMoveToWorkspaceDialog_Workspace on Workspace {\n id\n role\n name\n logo\n slug\n ...WorkspaceHasCustomDataResidency_Workspace\n ...ProjectsWorkspaceSelect_Workspace\n }\n"): (typeof documents)["\n fragment ProjectsMoveToWorkspaceDialog_Workspace on Workspace {\n id\n role\n name\n logo\n slug\n ...WorkspaceHasCustomDataResidency_Workspace\n ...ProjectsWorkspaceSelect_Workspace\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
@@ -1228,10 +1224,6 @@ export function graphql(source: "\n fragment SettingsServerRegionsAddEditDialog
* 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 SettingsServerRegionsTable_ServerRegionItem on ServerRegionItem {\n id\n name\n key\n description\n }\n"): (typeof documents)["\n fragment SettingsServerRegionsTable_ServerRegionItem on ServerRegionItem {\n id\n name\n key\n description\n }\n"];
/**
* 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 SettingsSharedDeleteUserDialog_Workspace on Workspace {\n id\n plan {\n status\n name\n }\n subscription {\n currentBillingCycleEnd\n seats {\n guest\n plan\n }\n }\n }\n"): (typeof documents)["\n fragment SettingsSharedDeleteUserDialog_Workspace on Workspace {\n id\n plan {\n status\n name\n }\n subscription {\n currentBillingCycleEnd\n seats {\n guest\n plan\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
@@ -1268,10 +1260,6 @@ export function graphql(source: "\n fragment SettingsWorkspacesGeneralEditSlugD
* 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 WorkspaceBillingPage_Workspace on Workspace {\n id\n role\n }\n"): (typeof documents)["\n fragment WorkspaceBillingPage_Workspace on 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.
*/
export function graphql(source: "\n fragment SettingsWorkspacesMembersChangeRoleDialog_Workspace on Workspace {\n id\n plan {\n status\n name\n }\n subscription {\n currentBillingCycleEnd\n seats {\n guest\n plan\n }\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesMembersChangeRoleDialog_Workspace on Workspace {\n id\n plan {\n status\n name\n }\n subscription {\n currentBillingCycleEnd\n seats {\n guest\n plan\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
@@ -1279,7 +1267,7 @@ export function graphql(source: "\n fragment SettingsWorkspacesMembersGuestsTab
/**
* 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 SettingsWorkspacesMembersGuestsTable_Workspace on Workspace {\n id\n slug\n name\n ...SettingsWorkspacesMembersTableHeader_Workspace\n ...SettingsSharedDeleteUserDialog_Workspace\n team(limit: 250) {\n items {\n id\n ...SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator\n }\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesMembersGuestsTable_Workspace on Workspace {\n id\n slug\n name\n ...SettingsWorkspacesMembersTableHeader_Workspace\n ...SettingsSharedDeleteUserDialog_Workspace\n team(limit: 250) {\n items {\n id\n ...SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator\n }\n }\n }\n"];
export function graphql(source: "\n fragment SettingsWorkspacesMembersGuestsTable_Workspace on Workspace {\n id\n slug\n name\n ...SettingsWorkspacesMembersTableHeader_Workspace\n team(limit: 250) {\n items {\n id\n ...SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator\n }\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesMembersGuestsTable_Workspace on Workspace {\n id\n slug\n name\n ...SettingsWorkspacesMembersTableHeader_Workspace\n team(limit: 250) {\n items {\n id\n ...SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
@@ -1299,7 +1287,7 @@ export function graphql(source: "\n fragment SettingsWorkspacesMembersTable_Wor
/**
* 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 SettingsWorkspacesMembersTable_Workspace on Workspace {\n id\n slug\n name\n ...SettingsSharedDeleteUserDialog_Workspace\n ...SettingsWorkspacesMembersTableHeader_Workspace\n team(limit: 250) {\n items {\n id\n ...SettingsWorkspacesMembersTable_WorkspaceCollaborator\n }\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesMembersTable_Workspace on Workspace {\n id\n slug\n name\n ...SettingsSharedDeleteUserDialog_Workspace\n ...SettingsWorkspacesMembersTableHeader_Workspace\n team(limit: 250) {\n items {\n id\n ...SettingsWorkspacesMembersTable_WorkspaceCollaborator\n }\n }\n }\n"];
export function graphql(source: "\n fragment SettingsWorkspacesMembersTable_Workspace on Workspace {\n id\n slug\n name\n ...SettingsWorkspacesMembersTableHeader_Workspace\n team(limit: 250) {\n items {\n id\n ...SettingsWorkspacesMembersTable_WorkspaceCollaborator\n }\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesMembersTable_Workspace on Workspace {\n id\n slug\n name\n ...SettingsWorkspacesMembersTableHeader_Workspace\n team(limit: 250) {\n items {\n id\n ...SettingsWorkspacesMembersTable_WorkspaceCollaborator\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
@@ -1320,10 +1308,6 @@ export function graphql(source: "\n fragment SettingsWorkspacesSecurityDomainRe
* 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 SettingsWorkspacesSecuritySsoWrapper_Workspace on Workspace {\n id\n role\n slug\n sso {\n provider {\n id\n name\n clientId\n issuerUrl\n }\n }\n hasAccessToSSO: hasAccessToFeature(featureName: oidcSso)\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesSecuritySsoWrapper_Workspace on Workspace {\n id\n role\n slug\n sso {\n provider {\n id\n name\n clientId\n issuerUrl\n }\n }\n hasAccessToSSO: hasAccessToFeature(featureName: oidcSso)\n }\n"];
/**
* 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 Sidebar_User on User {\n id\n automateFunctions {\n items {\n id\n name\n description\n logo\n }\n }\n }\n"): (typeof documents)["\n fragment Sidebar_User on User {\n id\n automateFunctions {\n items {\n id\n name\n description\n logo\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
@@ -1343,7 +1327,7 @@ export function graphql(source: "\n fragment ViewerModelVersionCardItem on Vers
/**
* 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 MoveProjectsDialog_Workspace on Workspace {\n id\n ...ProjectsMoveToWorkspaceDialog_Workspace\n projects {\n items {\n id\n modelCount: models(limit: 0) {\n totalCount\n }\n versions(limit: 0) {\n totalCount\n }\n }\n }\n }\n"): (typeof documents)["\n fragment MoveProjectsDialog_Workspace on Workspace {\n id\n ...ProjectsMoveToWorkspaceDialog_Workspace\n projects {\n items {\n id\n modelCount: models(limit: 0) {\n totalCount\n }\n versions(limit: 0) {\n totalCount\n }\n }\n }\n }\n"];
export function graphql(source: "\n fragment MoveProjectsDialog_Workspace on Workspace {\n id\n ...ProjectsMoveToWorkspaceDialog_Workspace\n projects {\n items {\n id\n }\n }\n }\n"): (typeof documents)["\n fragment MoveProjectsDialog_Workspace on Workspace {\n id\n ...ProjectsMoveToWorkspaceDialog_Workspace\n projects {\n items {\n id\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
@@ -1351,7 +1335,7 @@ export function graphql(source: "\n fragment MoveProjectsDialog_User on User {\
/**
* 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 WorkspaceProjectList_Workspace on Workspace {\n id\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...WorkspaceSecurity_Workspace\n ...BillingAlert_Workspace\n ...MoveProjectsDialog_Workspace\n ...InviteDialogWorkspace_Workspace\n projects {\n ...WorkspaceProjectList_ProjectCollection\n }\n creationState {\n completed\n state\n }\n readOnly\n }\n"): (typeof documents)["\n fragment WorkspaceProjectList_Workspace on Workspace {\n id\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...WorkspaceSecurity_Workspace\n ...BillingAlert_Workspace\n ...MoveProjectsDialog_Workspace\n ...InviteDialogWorkspace_Workspace\n projects {\n ...WorkspaceProjectList_ProjectCollection\n }\n creationState {\n completed\n state\n }\n readOnly\n }\n"];
export function graphql(source: "\n fragment WorkspaceProjectList_Workspace on Workspace {\n id\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...WorkspaceSecurity_Workspace\n ...BillingAlert_Workspace\n ...InviteDialogWorkspace_Workspace\n projects {\n ...WorkspaceProjectList_ProjectCollection\n }\n creationState {\n completed\n state\n }\n readOnly\n }\n"): (typeof documents)["\n fragment WorkspaceProjectList_Workspace on Workspace {\n id\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...WorkspaceSecurity_Workspace\n ...BillingAlert_Workspace\n ...InviteDialogWorkspace_Workspace\n projects {\n ...WorkspaceProjectList_ProjectCollection\n }\n creationState {\n completed\n state\n }\n readOnly\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
@@ -2024,10 +2008,6 @@ export function graphql(source: "\n mutation SettingsBillingCancelCheckoutSessi
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query SettingsSidebar {\n activeUser {\n ...SettingsSidebar_User\n }\n }\n"): (typeof documents)["\n query SettingsSidebar {\n activeUser {\n ...SettingsSidebar_User\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query SettingsSidebarAutomateFunctions {\n activeUser {\n ...Sidebar_User\n }\n }\n"): (typeof documents)["\n query SettingsSidebarAutomateFunctions {\n activeUser {\n ...Sidebar_User\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
@@ -2196,6 +2176,10 @@ export function graphql(source: "\n fragment DiscoverableList_Discoverable on U
* 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 DiscoverableList_Requests on User {\n workspaceJoinRequests {\n items {\n id\n status\n workspace {\n id\n name\n logo\n slug\n team {\n totalCount\n items {\n avatar\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n fragment DiscoverableList_Requests on User {\n workspaceJoinRequests {\n items {\n id\n status\n workspace {\n id\n name\n logo\n slug\n team {\n totalCount\n items {\n avatar\n }\n }\n }\n }\n }\n }\n"];
/**
* 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 WorkspacePlanLimits_Workspace on Workspace {\n id\n plan {\n name\n }\n }\n"): (typeof documents)["\n fragment WorkspacePlanLimits_Workspace on Workspace {\n id\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.
*/
@@ -2203,11 +2187,7 @@ export function graphql(source: "\n fragment UseWorkspaceInviteManager_PendingW
/**
* 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 WorkspacesPlan_Workspace on Workspace {\n id\n plan {\n status\n createdAt\n name\n paymentMethod\n usage {\n projectCount\n modelCount\n }\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n seats {\n totalCount\n assigned\n viewersCount\n }\n }\n }\n"): (typeof documents)["\n fragment WorkspacesPlan_Workspace on Workspace {\n id\n plan {\n status\n createdAt\n name\n paymentMethod\n usage {\n projectCount\n modelCount\n }\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n seats {\n totalCount\n assigned\n viewersCount\n }\n }\n }\n"];
/**
* 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 WorkspacePlanLimits_Workspace on Workspace {\n id\n projects(limit: 0) {\n totalCount\n items {\n id\n models(limit: 0) {\n totalCount\n }\n }\n }\n plan {\n name\n }\n }\n"): (typeof documents)["\n fragment WorkspacePlanLimits_Workspace on Workspace {\n id\n projects(limit: 0) {\n totalCount\n items {\n id\n models(limit: 0) {\n totalCount\n }\n }\n }\n plan {\n name\n }\n }\n"];
export function graphql(source: "\n fragment WorkspacesPlan_Workspace on Workspace {\n id\n plan {\n status\n createdAt\n name\n paymentMethod\n usage {\n projectCount\n modelCount\n }\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n seats {\n editors {\n available\n assigned\n }\n viewers {\n available\n assigned\n }\n }\n }\n }\n"): (typeof documents)["\n fragment WorkspacesPlan_Workspace on Workspace {\n id\n plan {\n status\n createdAt\n name\n paymentMethod\n usage {\n projectCount\n modelCount\n }\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n seats {\n editors {\n available\n assigned\n }\n viewers {\n available\n assigned\n }\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
@@ -2228,6 +2208,10 @@ export function graphql(source: "\n fragment WorkspaceSsoStatus_Workspace on
* 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 WorkspaceSsoStatus_User on User {\n expiredSsoSessions {\n id\n slug\n }\n }\n "): (typeof documents)["\n fragment WorkspaceSsoStatus_User on User {\n expiredSsoSessions {\n id\n slug\n }\n }\n "];
/**
* 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 WorkspaceUsage_Workspace on Workspace {\n id\n plan {\n usage {\n projectCount\n modelCount\n }\n }\n }\n"): (typeof documents)["\n fragment WorkspaceUsage_Workspace on Workspace {\n id\n plan {\n usage {\n projectCount\n modelCount\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
@@ -2371,7 +2355,11 @@ export function graphql(source: "\n query WorkspaceLastAdminCheck($slug: String
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query WorkspacePlanLimits($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacePlanLimits_Workspace\n }\n }\n"): (typeof documents)["\n query WorkspacePlanLimits($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacePlanLimits_Workspace\n }\n }\n"];
export function graphql(source: "\n query WorkspaceLimits($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacePlanLimits_Workspace\n }\n }\n"): (typeof documents)["\n query WorkspaceLimits($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacePlanLimits_Workspace\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query WorkspaceUsage($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspaceUsage_Workspace\n }\n }\n"): (typeof documents)["\n query WorkspaceUsage($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspaceUsage_Workspace\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
@@ -7,7 +7,6 @@ export const profileRoute = '/profile'
export const authBlockedDueToVerificationRoute = '/error-email-verify'
export const homeRoute = '/'
export const projectsRoute = '/projects'
export const workspacesRoute = '/workspaces'
export const loginRoute = '/authn/login'
export const registerRoute = '/authn/register'
export const ssoLoginRoute = '/authn/sso'
@@ -8,14 +8,6 @@ export const settingsSidebarQuery = graphql(`
}
`)
export const settingsSidebarAutomateFunctionsQuery = graphql(`
query SettingsSidebarAutomateFunctions {
activeUser {
...Sidebar_User
}
}
`)
export const settingsWorkspaceGeneralQuery = graphql(`
query SettingsWorkspaceGeneral($slug: String!) {
workspaceBySlug(slug: $slug) {
@@ -1,82 +1,71 @@
import dayjs from 'dayjs'
import { graphql } from '~/lib/common/generated/gql/gql'
import { useQuery } from '@vue/apollo-composable'
import { workspaceLimitsQuery } from '~/lib/workspaces/graphql/queries'
import { WorkspacePlanConfigs } from '@speckle/shared'
import { useWorkspaceUsage } from '~/lib/workspaces/composables/usage'
export const useWorkspacePlanLimits = () => {
const projectLimit = computed(() => 3)
const modelLimit = computed(() => 8)
const commentLimit = computed(() => 10)
const versionLimit = computed(() => 10)
const isCommentOlderThanLimit = (createdAt: string) => {
return dayjs().diff(dayjs(createdAt), 'day') > commentLimit.value
graphql(`
fragment WorkspacePlanLimits_Workspace on Workspace {
id
plan {
name
}
}
`)
return {
projectLimit,
modelLimit,
commentLimit,
versionLimit,
isCommentOlderThanLimit
}
}
export const useWorkspaceLimits = (slug: string) => {
const { modelCount, projectCount } = useWorkspaceUsage(slug)
export const useWorkspaceProjectLimits = (projectCount: ComputedRef<number>) => {
const { projectLimit } = useWorkspacePlanLimits()
const remainingProjects = computed(() => {
return projectLimit.value - projectCount?.value
})
const canAddProject = computed(
() => remainingProjects.value !== null && remainingProjects.value > 0
const { result } = useQuery(
workspaceLimitsQuery,
() => ({
slug
}),
() => ({
enabled: !!slug
})
)
return {
projectLimit,
remainingProjects,
canAddProject
}
}
// Plan limits
const limits = computed(() => {
const planName = result.value?.workspaceBySlug?.plan?.name
if (!planName) return { projectCount: 0, modelCount: 0 }
export const useWorkspaceModelLimits = (modelCount: ComputedRef<number>) => {
const { modelLimit } = useWorkspacePlanLimits()
const remainingModels = computed(() => {
return modelLimit.value - (modelCount?.value ?? 0)
const planConfig = WorkspacePlanConfigs[planName]
return planConfig?.limits
})
const canAddModel = computed(
() => remainingModels.value !== null && remainingModels.value > 0
const remainingProjectCount = computed(() =>
limits.value.projectCount ? limits.value.projectCount - projectCount.value : 0
)
const remainingModelCount = computed(() =>
limits.value.modelCount ? limits.value.modelCount - modelCount.value : 0
)
return {
modelLimit,
remainingModels,
canAddModel
}
}
const canAddProject = computed(() => {
// Unlimited
if (limits.value.projectCount === null) return true
export const useWorkspaceCommentLimits = () => {
const { commentLimit } = useWorkspacePlanLimits()
return projectCount.value + 1 <= limits.value.projectCount
})
const isCommentOlderThanLimit = (createdAt: string) => {
return dayjs().diff(dayjs(createdAt), 'day') > commentLimit.value
const canAddModels = (additionalModels?: number) => {
// Unlimited
if (limits.value.modelCount === null) return true
if (!additionalModels) {
return remainingModelCount.value > 0
}
return modelCount.value + additionalModels <= limits.value.modelCount
}
return {
commentLimit,
isCommentOlderThanLimit
}
}
export const useWorkspaceVersionLimits = () => {
const { versionLimit } = useWorkspacePlanLimits()
const isVersionOlderThanLimit = (createdAt: string) => {
return dayjs().diff(dayjs(createdAt), 'day') > versionLimit.value
}
return {
versionLimit,
isVersionOlderThanLimit
projectCount,
modelCount,
limits,
remainingProjectCount,
remainingModelCount,
canAddProject,
canAddModels
}
}
@@ -28,9 +28,14 @@ graphql(`
billingInterval
currentBillingCycleEnd
seats {
totalCount
assigned
viewersCount
editors {
assigned
available
}
viewers {
assigned
available
}
}
}
}
@@ -117,9 +122,9 @@ export const useWorkspacePlan = (slug: string) => {
return { limit: 0, used: 0, hasSeatAvailable: false, seatPrice: editorSeatPrice }
return {
limit: seats.totalCount,
used: seats.assigned,
hasSeatAvailable: seats.totalCount > seats.assigned,
limit: seats.editors.available,
used: seats.editors.assigned,
hasSeatAvailable: seats.editors.available > seats.editors.assigned,
seatPrice: editorSeatPrice
}
})
@@ -141,21 +146,3 @@ export const useWorkspacePlan = (slug: string) => {
editorSeats
}
}
graphql(`
fragment WorkspacePlanLimits_Workspace on Workspace {
id
projects(limit: 0) {
totalCount
items {
id
models(limit: 0) {
totalCount
}
}
}
plan {
name
}
}
`)
@@ -1,9 +1,22 @@
import { graphql } from '~/lib/common/generated/gql/gql'
import { useQuery } from '@vue/apollo-composable'
import { workspacePlanLimitsQuery } from '~/lib/workspaces/graphql/queries'
import { workspaceUsageQuery } from '~/lib/workspaces/graphql/queries'
export const useGetWorkspacePlanUsage = (slug: string) => {
graphql(`
fragment WorkspaceUsage_Workspace on Workspace {
id
plan {
usage {
projectCount
modelCount
}
}
}
`)
export const useWorkspaceUsage = (slug: string) => {
const { result } = useQuery(
workspacePlanLimitsQuery,
workspaceUsageQuery,
() => ({
slug
}),
@@ -13,14 +26,10 @@ export const useGetWorkspacePlanUsage = (slug: string) => {
)
const projectCount = computed(
() => result.value?.workspaceBySlug?.projects?.totalCount ?? 0
() => result.value?.workspaceBySlug?.plan?.usage.projectCount ?? 0
)
const modelCount = computed(
() =>
result.value?.workspaceBySlug?.projects?.items?.reduce(
(total, project) => total + (project?.models?.totalCount ?? 0),
0
) ?? 0
() => result.value?.workspaceBySlug?.plan?.usage.modelCount ?? 0
)
return {
@@ -158,10 +158,18 @@ export const workspaceLastAdminCheckQuery = graphql(`
}
`)
export const workspacePlanLimitsQuery = graphql(`
query WorkspacePlanLimits($slug: String!) {
export const workspaceLimitsQuery = graphql(`
query WorkspaceLimits($slug: String!) {
workspaceBySlug(slug: $slug) {
...WorkspacePlanLimits_Workspace
}
}
`)
export const workspaceUsageQuery = graphql(`
query WorkspaceUsage($slug: String!) {
workspaceBySlug(slug: $slug) {
...WorkspaceUsage_Workspace
}
}
`)
+19
View File
@@ -142,6 +142,25 @@ const onShutdown = async () => {
}
createTerminus(server, {
healthChecks: {
'/liveness': () => Promise.resolve('ok'),
'/readiness': async (args: { state: { isShuttingDown: boolean } }) => {
const { isShuttingDown } = args.state
if (isShuttingDown) {
return Promise.reject(new Error('Preview service is shutting down'))
}
const isReady = await jobQueue.isReady()
if (!isReady)
return Promise.reject(
new Error(
'Preview service is not ready. Redis or Bull is not either reachable or ready.'
)
)
return Promise.resolve('ok')
}
},
beforeShutdown,
onShutdown,
logger: (msg, err) => {
@@ -98,20 +98,19 @@ type WorkspacePlan {
}
type WorkspaceSubscriptionSeats {
plan: Int! @deprecated
guest: Int! @deprecated
editors: WorkspaceSubscriptionSeatCount!
viewers: WorkspaceSubscriptionSeatCount!
}
type WorkspaceSubscriptionSeatCount {
"""
Total number of seats purchased and available in the current subscription cycle
"""
totalCount: Int!
available: Int!
"""
Number assigned seats in the current billing cycle
Total number of seats in use by workspace users
"""
assigned: Int!
"""
Number of viewer seats currently assigned in the workspace
"""
viewersCount: Int!
}
type WorkspaceSubscription {
@@ -19,10 +19,6 @@ extend type Workspace {
Active user's seat type for this workspace. `null` if request is not authenticated, or the workspace is not explicitly shared with you.
"""
seatType: WorkspaceSeatType
seatsByType: WorkspaceSeatsByType
@hasServerRole(role: SERVER_USER)
@hasScope(scope: "workspace:read")
@hasWorkspaceRole(role: ADMIN)
}
type WorkspaceSeatsByType {
@@ -275,6 +275,7 @@ type Workspace {
cursor: String
filter: WorkspaceTeamFilter
): WorkspaceCollaboratorCollection!
teamByRole: WorkspaceTeamByRole!
"""
Only available to workspace owners/members
"""
@@ -318,13 +319,9 @@ type Workspace {
@hasServerRole(role: SERVER_USER)
@hasScope(scope: "workspace:read")
@hasWorkspaceRole(role: ADMIN)
membersByRole: WorkspaceMembersByRole
@hasServerRole(role: SERVER_USER)
@hasScope(scope: "workspace:read")
@hasWorkspaceRole(role: ADMIN)
}
type WorkspaceMembersByRole {
type WorkspaceTeamByRole {
admins: WorkspaceRoleCollection
members: WorkspaceRoleCollection
guests: WorkspaceRoleCollection
+1
View File
@@ -69,6 +69,7 @@ generates:
WorkspaceBillingMutations: '@/modules/gatekeeper/helpers/graphTypes#WorkspaceBillingMutationsGraphQLReturn'
PendingWorkspaceCollaborator: '@/modules/workspacesCore/helpers/graphTypes#PendingWorkspaceCollaboratorGraphQLReturn'
WorkspaceCollaborator: '@/modules/workspacesCore/helpers/graphTypes#WorkspaceCollaboratorGraphQLReturn'
WorkspaceSubscriptionSeats: '@/modules/gatekeeper/helpers/graphTypes#WorkspaceSubscriptionSeatsGraphQLReturn'
WorkspaceJoinRequest: '@/modules/workspacesCore/helpers/graphTypes#WorkspaceJoinRequestGraphQLReturn'
LimitedWorkspaceJoinRequest: '@/modules/workspacesCore/helpers/graphTypes#LimitedWorkspaceJoinRequestGraphQLReturn'
Webhook: '@/modules/webhooks/helpers/graphTypes#WebhookGraphQLReturn'
@@ -7,7 +7,7 @@ import { FileUploadGraphQLReturn } from '@/modules/fileuploads/helpers/types';
import { AutomateFunctionGraphQLReturn, AutomateFunctionReleaseGraphQLReturn, AutomationGraphQLReturn, AutomationRevisionGraphQLReturn, AutomationRevisionFunctionGraphQLReturn, AutomateRunGraphQLReturn, AutomationRunTriggerGraphQLReturn, AutomationRevisionTriggerDefinitionGraphQLReturn, AutomateFunctionRunGraphQLReturn, TriggeredAutomationsStatusGraphQLReturn, ProjectAutomationMutationsGraphQLReturn, ProjectTriggeredAutomationsStatusUpdatedMessageGraphQLReturn, ProjectAutomationsUpdatedMessageGraphQLReturn, UserAutomateInfoGraphQLReturn } from '@/modules/automate/helpers/graphTypes';
import { WorkspaceGraphQLReturn, WorkspaceSsoGraphQLReturn, WorkspaceMutationsGraphQLReturn, WorkspaceJoinRequestMutationsGraphQLReturn, WorkspaceInviteMutationsGraphQLReturn, WorkspaceProjectMutationsGraphQLReturn, PendingWorkspaceCollaboratorGraphQLReturn, WorkspaceCollaboratorGraphQLReturn, WorkspaceJoinRequestGraphQLReturn, LimitedWorkspaceJoinRequestGraphQLReturn, ProjectRoleGraphQLReturn, WorkspacePermissionChecksGraphQLReturn } from '@/modules/workspacesCore/helpers/graphTypes';
import { WorkspacePlanGraphQLReturn, WorkspacePlanUsageGraphQLReturn, PriceGraphQLReturn } from '@/modules/gatekeeperCore/helpers/graphTypes';
import { WorkspaceBillingMutationsGraphQLReturn, WorkspaceSubscriptionGraphQLReturn } from '@/modules/gatekeeper/helpers/graphTypes';
import { WorkspaceBillingMutationsGraphQLReturn, WorkspaceSubscriptionSeatsGraphQLReturn, WorkspaceSubscriptionGraphQLReturn } from '@/modules/gatekeeper/helpers/graphTypes';
import { WebhookGraphQLReturn } from '@/modules/webhooks/helpers/graphTypes';
import { SmartTextEditorValueGraphQLReturn } from '@/modules/core/services/richTextEditorService';
import { BlobStorageItem } from '@/modules/blobstorage/domain/types';
@@ -4371,7 +4371,6 @@ export type Workspace = {
invitedTeam?: Maybe<Array<PendingWorkspaceCollaborator>>;
/** Logo image as base64-encoded string */
logo?: Maybe<Scalars['String']['output']>;
membersByRole?: Maybe<WorkspaceMembersByRole>;
name: Scalars['String']['output'];
permissions: WorkspacePermissionChecks;
plan?: Maybe<WorkspacePlan>;
@@ -4382,12 +4381,12 @@ export type Workspace = {
role?: Maybe<Scalars['String']['output']>;
/** Active user's seat type for this workspace. `null` if request is not authenticated, or the workspace is not explicitly shared with you. */
seatType?: Maybe<WorkspaceSeatType>;
seatsByType?: Maybe<WorkspaceSeatsByType>;
slug: Scalars['String']['output'];
/** Information about the workspace's SSO configuration and the current user's SSO session, if present */
sso?: Maybe<WorkspaceSso>;
subscription?: Maybe<WorkspaceSubscription>;
team: WorkspaceCollaboratorCollection;
teamByRole: WorkspaceTeamByRole;
updatedAt: Scalars['DateTime']['output'];
};
@@ -4630,13 +4629,6 @@ export const WorkspaceJoinRequestStatus = {
} as const;
export type WorkspaceJoinRequestStatus = typeof WorkspaceJoinRequestStatus[keyof typeof WorkspaceJoinRequestStatus];
export type WorkspaceMembersByRole = {
__typename?: 'WorkspaceMembersByRole';
admins?: Maybe<WorkspaceRoleCollection>;
guests?: Maybe<WorkspaceRoleCollection>;
members?: Maybe<WorkspaceRoleCollection>;
};
export type WorkspaceMutations = {
__typename?: 'WorkspaceMutations';
addDomain: Workspace;
@@ -4944,18 +4936,25 @@ export type WorkspaceSubscription = {
updatedAt: Scalars['DateTime']['output'];
};
export type WorkspaceSubscriptionSeatCount = {
__typename?: 'WorkspaceSubscriptionSeatCount';
/** Total number of seats in use by workspace users */
assigned: Scalars['Int']['output'];
/** Total number of seats purchased and available in the current subscription cycle */
available: Scalars['Int']['output'];
};
export type WorkspaceSubscriptionSeats = {
__typename?: 'WorkspaceSubscriptionSeats';
/** Number assigned seats in the current billing cycle */
assigned: Scalars['Int']['output'];
/** @deprecated Field no longer supported */
guest: Scalars['Int']['output'];
/** @deprecated Field no longer supported */
plan: Scalars['Int']['output'];
/** Total number of seats purchased and available in the current subscription cycle */
totalCount: Scalars['Int']['output'];
/** Number of viewer seats currently assigned in the workspace */
viewersCount: Scalars['Int']['output'];
editors: WorkspaceSubscriptionSeatCount;
viewers: WorkspaceSubscriptionSeatCount;
};
export type WorkspaceTeamByRole = {
__typename?: 'WorkspaceTeamByRole';
admins?: Maybe<WorkspaceRoleCollection>;
guests?: Maybe<WorkspaceRoleCollection>;
members?: Maybe<WorkspaceRoleCollection>;
};
export type WorkspaceTeamFilter = {
@@ -5356,7 +5355,6 @@ export type ResolversTypes = {
WorkspaceJoinRequestFilter: WorkspaceJoinRequestFilter;
WorkspaceJoinRequestMutations: ResolverTypeWrapper<WorkspaceJoinRequestMutationsGraphQLReturn>;
WorkspaceJoinRequestStatus: WorkspaceJoinRequestStatus;
WorkspaceMembersByRole: ResolverTypeWrapper<WorkspaceMembersByRole>;
WorkspaceMutations: ResolverTypeWrapper<WorkspaceMutationsGraphQLReturn>;
WorkspacePaymentMethod: WorkspacePaymentMethod;
WorkspacePermissionChecks: ResolverTypeWrapper<WorkspacePermissionChecksGraphQLReturn>;
@@ -5383,7 +5381,9 @@ export type ResolversTypes = {
WorkspaceSsoProvider: ResolverTypeWrapper<WorkspaceSsoProvider>;
WorkspaceSsoSession: ResolverTypeWrapper<WorkspaceSsoSession>;
WorkspaceSubscription: ResolverTypeWrapper<WorkspaceSubscriptionGraphQLReturn>;
WorkspaceSubscriptionSeats: ResolverTypeWrapper<WorkspaceSubscriptionSeats>;
WorkspaceSubscriptionSeatCount: ResolverTypeWrapper<WorkspaceSubscriptionSeatCount>;
WorkspaceSubscriptionSeats: ResolverTypeWrapper<WorkspaceSubscriptionSeatsGraphQLReturn>;
WorkspaceTeamByRole: ResolverTypeWrapper<WorkspaceTeamByRole>;
WorkspaceTeamFilter: WorkspaceTeamFilter;
WorkspaceUpdateInput: WorkspaceUpdateInput;
WorkspaceUpdateSeatTypeInput: WorkspaceUpdateSeatTypeInput;
@@ -5657,7 +5657,6 @@ export type ResolversParentTypes = {
WorkspaceJoinRequestCollection: Omit<WorkspaceJoinRequestCollection, 'items'> & { items: Array<ResolversParentTypes['WorkspaceJoinRequest']> };
WorkspaceJoinRequestFilter: WorkspaceJoinRequestFilter;
WorkspaceJoinRequestMutations: WorkspaceJoinRequestMutationsGraphQLReturn;
WorkspaceMembersByRole: WorkspaceMembersByRole;
WorkspaceMutations: WorkspaceMutationsGraphQLReturn;
WorkspacePermissionChecks: WorkspacePermissionChecksGraphQLReturn;
WorkspacePlan: WorkspacePlanGraphQLReturn;
@@ -5678,7 +5677,9 @@ export type ResolversParentTypes = {
WorkspaceSsoProvider: WorkspaceSsoProvider;
WorkspaceSsoSession: WorkspaceSsoSession;
WorkspaceSubscription: WorkspaceSubscriptionGraphQLReturn;
WorkspaceSubscriptionSeats: WorkspaceSubscriptionSeats;
WorkspaceSubscriptionSeatCount: WorkspaceSubscriptionSeatCount;
WorkspaceSubscriptionSeats: WorkspaceSubscriptionSeatsGraphQLReturn;
WorkspaceTeamByRole: WorkspaceTeamByRole;
WorkspaceTeamFilter: WorkspaceTeamFilter;
WorkspaceUpdateInput: WorkspaceUpdateInput;
WorkspaceUpdateSeatTypeInput: WorkspaceUpdateSeatTypeInput;
@@ -7182,7 +7183,6 @@ export type WorkspaceResolvers<ContextType = GraphQLContext, ParentType extends
id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
invitedTeam?: Resolver<Maybe<Array<ResolversTypes['PendingWorkspaceCollaborator']>>, ParentType, ContextType, Partial<WorkspaceInvitedTeamArgs>>;
logo?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
membersByRole?: Resolver<Maybe<ResolversTypes['WorkspaceMembersByRole']>, ParentType, ContextType>;
name?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
permissions?: Resolver<ResolversTypes['WorkspacePermissionChecks'], ParentType, ContextType>;
plan?: Resolver<Maybe<ResolversTypes['WorkspacePlan']>, ParentType, ContextType>;
@@ -7190,11 +7190,11 @@ export type WorkspaceResolvers<ContextType = GraphQLContext, ParentType extends
readOnly?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
role?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
seatType?: Resolver<Maybe<ResolversTypes['WorkspaceSeatType']>, ParentType, ContextType>;
seatsByType?: Resolver<Maybe<ResolversTypes['WorkspaceSeatsByType']>, ParentType, ContextType>;
slug?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
sso?: Resolver<Maybe<ResolversTypes['WorkspaceSso']>, ParentType, ContextType>;
subscription?: Resolver<Maybe<ResolversTypes['WorkspaceSubscription']>, ParentType, ContextType>;
team?: Resolver<ResolversTypes['WorkspaceCollaboratorCollection'], ParentType, ContextType, RequireFields<WorkspaceTeamArgs, 'limit'>>;
teamByRole?: Resolver<ResolversTypes['WorkspaceTeamByRole'], ParentType, ContextType>;
updatedAt?: Resolver<ResolversTypes['DateTime'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
@@ -7273,13 +7273,6 @@ export type WorkspaceJoinRequestMutationsResolvers<ContextType = GraphQLContext,
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type WorkspaceMembersByRoleResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['WorkspaceMembersByRole'] = ResolversParentTypes['WorkspaceMembersByRole']> = {
admins?: Resolver<Maybe<ResolversTypes['WorkspaceRoleCollection']>, ParentType, ContextType>;
guests?: Resolver<Maybe<ResolversTypes['WorkspaceRoleCollection']>, ParentType, ContextType>;
members?: Resolver<Maybe<ResolversTypes['WorkspaceRoleCollection']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type WorkspaceMutationsResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['WorkspaceMutations'] = ResolversParentTypes['WorkspaceMutations']> = {
addDomain?: Resolver<ResolversTypes['Workspace'], ParentType, ContextType, RequireFields<WorkspaceMutationsAddDomainArgs, 'input'>>;
billing?: Resolver<ResolversTypes['WorkspaceBillingMutations'], ParentType, ContextType>;
@@ -7389,12 +7382,22 @@ export type WorkspaceSubscriptionResolvers<ContextType = GraphQLContext, ParentT
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type WorkspaceSubscriptionSeatsResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['WorkspaceSubscriptionSeats'] = ResolversParentTypes['WorkspaceSubscriptionSeats']> = {
export type WorkspaceSubscriptionSeatCountResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['WorkspaceSubscriptionSeatCount'] = ResolversParentTypes['WorkspaceSubscriptionSeatCount']> = {
assigned?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
guest?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
plan?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
totalCount?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
viewersCount?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
available?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type WorkspaceSubscriptionSeatsResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['WorkspaceSubscriptionSeats'] = ResolversParentTypes['WorkspaceSubscriptionSeats']> = {
editors?: Resolver<ResolversTypes['WorkspaceSubscriptionSeatCount'], ParentType, ContextType>;
viewers?: Resolver<ResolversTypes['WorkspaceSubscriptionSeatCount'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type WorkspaceTeamByRoleResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['WorkspaceTeamByRole'] = ResolversParentTypes['WorkspaceTeamByRole']> = {
admins?: Resolver<Maybe<ResolversTypes['WorkspaceRoleCollection']>, ParentType, ContextType>;
guests?: Resolver<Maybe<ResolversTypes['WorkspaceRoleCollection']>, ParentType, ContextType>;
members?: Resolver<Maybe<ResolversTypes['WorkspaceRoleCollection']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
@@ -7560,7 +7563,6 @@ export type Resolvers<ContextType = GraphQLContext> = {
WorkspaceJoinRequest?: WorkspaceJoinRequestResolvers<ContextType>;
WorkspaceJoinRequestCollection?: WorkspaceJoinRequestCollectionResolvers<ContextType>;
WorkspaceJoinRequestMutations?: WorkspaceJoinRequestMutationsResolvers<ContextType>;
WorkspaceMembersByRole?: WorkspaceMembersByRoleResolvers<ContextType>;
WorkspaceMutations?: WorkspaceMutationsResolvers<ContextType>;
WorkspacePermissionChecks?: WorkspacePermissionChecksResolvers<ContextType>;
WorkspacePlan?: WorkspacePlanResolvers<ContextType>;
@@ -7575,7 +7577,9 @@ export type Resolvers<ContextType = GraphQLContext> = {
WorkspaceSsoProvider?: WorkspaceSsoProviderResolvers<ContextType>;
WorkspaceSsoSession?: WorkspaceSsoSessionResolvers<ContextType>;
WorkspaceSubscription?: WorkspaceSubscriptionResolvers<ContextType>;
WorkspaceSubscriptionSeatCount?: WorkspaceSubscriptionSeatCountResolvers<ContextType>;
WorkspaceSubscriptionSeats?: WorkspaceSubscriptionSeatsResolvers<ContextType>;
WorkspaceTeamByRole?: WorkspaceTeamByRoleResolvers<ContextType>;
WorkspaceUpdatedMessage?: WorkspaceUpdatedMessageResolvers<ContextType>;
};
@@ -4351,7 +4351,6 @@ export type Workspace = {
invitedTeam?: Maybe<Array<PendingWorkspaceCollaborator>>;
/** Logo image as base64-encoded string */
logo?: Maybe<Scalars['String']['output']>;
membersByRole?: Maybe<WorkspaceMembersByRole>;
name: Scalars['String']['output'];
permissions: WorkspacePermissionChecks;
plan?: Maybe<WorkspacePlan>;
@@ -4362,12 +4361,12 @@ export type Workspace = {
role?: Maybe<Scalars['String']['output']>;
/** Active user's seat type for this workspace. `null` if request is not authenticated, or the workspace is not explicitly shared with you. */
seatType?: Maybe<WorkspaceSeatType>;
seatsByType?: Maybe<WorkspaceSeatsByType>;
slug: Scalars['String']['output'];
/** Information about the workspace's SSO configuration and the current user's SSO session, if present */
sso?: Maybe<WorkspaceSso>;
subscription?: Maybe<WorkspaceSubscription>;
team: WorkspaceCollaboratorCollection;
teamByRole: WorkspaceTeamByRole;
updatedAt: Scalars['DateTime']['output'];
};
@@ -4610,13 +4609,6 @@ export const WorkspaceJoinRequestStatus = {
} as const;
export type WorkspaceJoinRequestStatus = typeof WorkspaceJoinRequestStatus[keyof typeof WorkspaceJoinRequestStatus];
export type WorkspaceMembersByRole = {
__typename?: 'WorkspaceMembersByRole';
admins?: Maybe<WorkspaceRoleCollection>;
guests?: Maybe<WorkspaceRoleCollection>;
members?: Maybe<WorkspaceRoleCollection>;
};
export type WorkspaceMutations = {
__typename?: 'WorkspaceMutations';
addDomain: Workspace;
@@ -4924,18 +4916,25 @@ export type WorkspaceSubscription = {
updatedAt: Scalars['DateTime']['output'];
};
export type WorkspaceSubscriptionSeatCount = {
__typename?: 'WorkspaceSubscriptionSeatCount';
/** Total number of seats in use by workspace users */
assigned: Scalars['Int']['output'];
/** Total number of seats purchased and available in the current subscription cycle */
available: Scalars['Int']['output'];
};
export type WorkspaceSubscriptionSeats = {
__typename?: 'WorkspaceSubscriptionSeats';
/** Number assigned seats in the current billing cycle */
assigned: Scalars['Int']['output'];
/** @deprecated Field no longer supported */
guest: Scalars['Int']['output'];
/** @deprecated Field no longer supported */
plan: Scalars['Int']['output'];
/** Total number of seats purchased and available in the current subscription cycle */
totalCount: Scalars['Int']['output'];
/** Number of viewer seats currently assigned in the workspace */
viewersCount: Scalars['Int']['output'];
editors: WorkspaceSubscriptionSeatCount;
viewers: WorkspaceSubscriptionSeatCount;
};
export type WorkspaceTeamByRole = {
__typename?: 'WorkspaceTeamByRole';
admins?: Maybe<WorkspaceRoleCollection>;
guests?: Maybe<WorkspaceRoleCollection>;
members?: Maybe<WorkspaceRoleCollection>;
};
export type WorkspaceTeamFilter = {
@@ -1,8 +1,5 @@
import { getFeatureFlags, getFrontendOrigin } from '@/modules/shared/helpers/envHelper'
import type {
Resolvers,
WorkspaceSeatsByType
} from '@/modules/core/graph/generated/graphql'
import type { Resolvers } from '@/modules/core/graph/generated/graphql'
import { authorizeResolver } from '@/modules/shared'
import {
ensureError,
@@ -41,7 +38,6 @@ import {
import { canWorkspaceAccessFeatureFactory } from '@/modules/gatekeeper/services/featureAuthorization'
import { isWorkspaceReadOnlyFactory } from '@/modules/gatekeeper/services/readOnly'
import {
calculateSubscriptionSeats,
CreateCheckoutSession,
CreateCheckoutSessionOld,
WorkspaceSeatType
@@ -75,7 +71,7 @@ import { getTotalSeatsCountByPlanFactory } from '@/modules/gatekeeper/services/s
import { queryAllWorkspaceProjectsFactory } from '@/modules/workspaces/services/projects'
import { legacyGetStreamsFactory } from '@/modules/core/repositories/streams'
import { getProjectDbClient } from '@/modules/multiregion/utils/dbSelector'
import { getStreamBranchCountFactory } from '@/modules/core/repositories/branches'
import { getPaginatedProjectModelsTotalCountFactory } from '@/modules/core/repositories/branches'
const { FF_GATEKEEPER_MODULE_ENABLED, FF_BILLING_INTEGRATION_ENABLED } =
getFeatureFlags()
@@ -124,12 +120,7 @@ export = FF_GATEKEEPER_MODULE_ENABLED
const subscription = await getWorkspaceSubscriptionFactory({ db })({
workspaceId
})
if (!subscription) return subscription
const seats = calculateSubscriptionSeats({
subscriptionData: subscription.subscriptionData,
guestSeatProductId: getWorkspacePlanProductId({ workspacePlan: 'guest' })
})
return { ...subscription, seats }
return subscription
},
customerPortalUrl: async (parent) => {
const workspaceId = parent.id
@@ -176,22 +167,7 @@ export = FF_GATEKEEPER_MODULE_ENABLED
// Defaults to Editor for old plans that don't have seat types
return seat?.type || WorkspaceSeatType.Editor
},
seatsByType: (parent) =>
({
editors: async () => ({
totalCount: await countSeatsByTypeInWorkspaceFactory({ db })({
workspaceId: parent.id,
type: 'editor'
})
}),
viewers: async () => ({
totalCount: await countSeatsByTypeInWorkspaceFactory({ db })({
workspaceId: parent.id,
type: 'viewer'
})
})
} as unknown as WorkspaceSeatsByType)
}
},
WorkspacePlan: {
usage: async (parent) => {
@@ -218,9 +194,15 @@ export = FF_GATEKEEPER_MODULE_ENABLED
for await (const projects of queryAllWorkspaceProjects({ workspaceId })) {
for (const project of projects) {
const regionDb = await getProjectDbClient({ projectId: project.id })
const projectModelCount = await getStreamBranchCountFactory({
db: regionDb
})(project.id)
const projectModelCount =
await getPaginatedProjectModelsTotalCountFactory({ db: regionDb })(
project.id,
{
filter: {
onlyWithVersions: true
}
}
)
modelCount = modelCount + projectModelCount
}
}
@@ -230,40 +212,42 @@ export = FF_GATEKEEPER_MODULE_ENABLED
},
WorkspaceSubscription: {
seats: async (parent) => {
return parent
}
},
WorkspaceSubscriptionSeats: {
editors: async (parent) => {
const { workspaceId, subscriptionData } = parent
const workspacePlan = await getWorkspacePlanFactory({ db })({
workspaceId: parent.workspaceId
workspaceId
})
if (!workspacePlan || !isNewPlanType(workspacePlan.name)) {
if (!workspacePlan) {
return {
...calculateSubscriptionSeats({
subscriptionData: parent.subscriptionData,
guestSeatProductId: getWorkspacePlanProductId({
workspacePlan: 'guest'
})
}),
// These values have no reference in the old plans FF_WORKSPACES_NEW_PLANS_ENABLED
totalCount: 0,
assigned: 0
assigned: 0,
available: 0
}
}
// Only editor seats are considered
const assignedSeatsCount = await countSeatsByTypeInWorkspaceFactory({ db })({
workspaceId: parent.workspaceId,
type: 'editor'
})
return {
assigned: assignedSeatsCount,
totalCount: getTotalSeatsCountByPlanFactory({ getWorkspacePlanProductId })({
workspacePlan,
subscriptionData: parent.subscriptionData
assigned: await countSeatsByTypeInWorkspaceFactory({ db })({
workspaceId,
type: 'editor'
}),
viewersCount: await countSeatsByTypeInWorkspaceFactory({ db })({
workspaceId: parent.workspaceId,
available: getTotalSeatsCountByPlanFactory({ getWorkspacePlanProductId })({
workspacePlan,
subscriptionData
})
}
},
viewers: async ({ workspaceId }) => {
return {
assigned: await countSeatsByTypeInWorkspaceFactory({ db })({
workspaceId,
type: 'viewer'
}),
// These values have no reference in the new plans
guest: 0,
plan: 0
available: 0
}
}
},
@@ -6,3 +6,4 @@ export type WorkspaceBillingMutationsGraphQLReturn = MutationsObjectGraphQLRetur
export type WorkspaceSubscriptionGraphQLReturn = WorkspaceSubscription & {
parent: Workspace
}
export type WorkspaceSubscriptionSeatsGraphQLReturn = WorkspaceSubscription
@@ -21,7 +21,6 @@ import {
import {
GetWorkspaceDocument,
GetWorkspacePlanUsageDocument,
GetWorkspaceWithSeatsByTypeDocument,
GetWorkspaceWithSubscriptionDocument
} from '@/test/graphql/generated/graphql'
import {
@@ -30,7 +29,14 @@ import {
TestApolloServer
} from '@/test/graphqlHelper'
import { beforeEachContext } from '@/test/hooks'
import { createTestBranches } from '@/test/speckle-helpers/branchHelper'
import {
BasicTestBranch,
createTestBranches
} from '@/test/speckle-helpers/branchHelper'
import {
createTestCommits,
createTestObject
} from '@/test/speckle-helpers/commitHelper'
import { BasicTestStream, createTestStream } from '@/test/speckle-helpers/streamHelper'
import { Roles } from '@speckle/shared'
import { expect } from 'chai'
@@ -176,7 +182,7 @@ describe('Workspaces Billing', () => {
expect(res).to.not.haveGraphQLErrors()
const seats = res.data?.workspace.subscription?.seats
expect(seats?.assigned).to.eq(1)
expect(seats?.editors.assigned).to.eq(1)
})
it('should return the number of viewers', async () => {
const user = await createTestUser({
@@ -251,15 +257,15 @@ describe('Workspaces Billing', () => {
expect(res).to.not.haveGraphQLErrors()
const seats = res.data?.workspace.subscription?.seats
expect(seats?.viewersCount).to.eq(2)
expect(seats?.viewers.assigned).to.eq(2)
})
})
}
)
;(FF_WORKSPACES_MODULE_ENABLED ? describe : describe.skip)(
'workspace.seatsByType',
'workspace.subscription.usage',
() => {
it('should return the number of editors and viewers in a workspace', async () => {
it('should return accurate usage information', async () => {
const user = await createTestUser({
name: createRandomString(),
email: createRandomEmail(),
@@ -275,137 +281,71 @@ describe('Workspaces Billing', () => {
await createTestWorkspace(workspace, user, {
addPlan: { name: 'pro', status: 'valid' }
})
const viewer1 = await createTestUser({
name: createRandomString(),
email: createRandomEmail(),
role: Roles.Server.User,
verified: true
})
await assignToWorkspace(
workspace,
viewer1,
Roles.Workspace.Member,
WorkspaceSeatType.Viewer
)
const viewer2 = await createTestUser({
name: createRandomString(),
email: createRandomEmail(),
role: Roles.Server.User,
verified: true
})
await assignToWorkspace(
workspace,
viewer2,
Roles.Workspace.Member,
WorkspaceSeatType.Viewer
)
const editor1 = await createTestUser({
const project: BasicTestStream = {
id: createRandomString(),
name: createRandomString(),
email: createRandomEmail(),
role: Roles.Server.User,
verified: true
})
await assignToWorkspace(
workspace,
editor1,
Roles.Workspace.Member,
WorkspaceSeatType.Editor
)
const editor2 = await createTestUser({
name: createRandomString(),
email: createRandomEmail(),
role: Roles.Server.User,
verified: true
})
await assignToWorkspace(
workspace,
editor2,
Roles.Workspace.Member,
WorkspaceSeatType.Editor
ownerId: user.id,
isPublic: true,
workspaceId: workspace.id
}
await createTestStream(project, user)
const models: BasicTestBranch[] = [
{
id: '',
streamId: project.id,
authorId: user.id,
name: createRandomString()
},
{
id: '',
streamId: project.id,
authorId: user.id,
name: createRandomString()
},
{
id: '',
streamId: project.id,
authorId: user.id,
name: createRandomString()
}
]
await createTestBranches(
models.map((branch) => ({
owner: user,
stream: project,
branch
}))
)
const objectId = await createTestObject({ projectId: project.id })
await createTestCommits([
{
id: '',
authorId: user.id,
objectId,
streamId: project.id,
branchName: models[0].name
},
{
id: '',
authorId: user.id,
objectId,
streamId: project.id,
branchName: models[1].name
}
])
const session = await login(user)
const res = await session.execute(GetWorkspaceWithSeatsByTypeDocument, {
const res = await session.execute(GetWorkspacePlanUsageDocument, {
workspaceId: workspace.id
})
expect(res).to.not.haveGraphQLErrors()
const seats = res.data?.workspace.seatsByType
expect(seats?.viewers?.totalCount).to.eq(2)
expect(seats?.editors?.totalCount).to.eq(3)
expect(res?.data?.workspace?.plan?.usage?.projectCount).to.equal(1)
expect(res?.data?.workspace?.plan?.usage?.modelCount).to.equal(2)
})
}
)
;(FF_WORKSPACES_MODULE_ENABLED ? describe : describe.skip)(
'workspace.subscription.usage',
async () => {
const user = await createTestUser({
name: createRandomString(),
email: createRandomEmail(),
role: Roles.Server.Admin,
verified: true
})
const workspace = {
id: createRandomString(),
name: createRandomString(),
slug: cryptoRandomString({ length: 10 }),
ownerId: user.id
}
await createTestWorkspace(workspace, user, {
addPlan: { name: 'pro', status: 'valid' }
})
const project: BasicTestStream = {
id: createRandomString(),
name: createRandomString(),
ownerId: user.id,
isPublic: true
}
await createTestStream(project, user)
await createTestBranches([
{
owner: user,
stream: project,
branch: {
id: createRandomString(),
streamId: project.id,
authorId: user.id,
name: createRandomString()
}
},
{
owner: user,
stream: project,
branch: {
id: createRandomString(),
streamId: project.id,
authorId: user.id,
name: createRandomString()
}
},
{
owner: user,
stream: project,
branch: {
id: createRandomString(),
streamId: project.id,
authorId: user.id,
name: createRandomString()
}
}
])
const session = await login(user)
const res = await session.execute(GetWorkspacePlanUsageDocument, {
workspaceId: workspace.id
})
expect(res).to.not.haveGraphQLErrors()
expect(res?.data?.workspace?.plan?.usage?.projectCount).to.equal(31)
expect(res?.data?.workspace?.plan?.usage?.modelCount).to.equal(3)
}
)
})
@@ -124,3 +124,9 @@ export const isUserGraphqlError = (error: GraphQLError): boolean => {
const code = error.extensions?.code as string
return userCodes.includes(code)
}
export type Collection<T> = {
cursor: string | null
totalCount: number
items: T[]
}
@@ -1,14 +1,9 @@
import {
decodeIsoDateCursor,
encodeIsoDateCursor
encodeIsoDateCursor,
Collection
} from '@/modules/shared/helpers/graphqlHelper'
type Collection<T> = {
cursor: string | null
totalCount: number
items: T[]
}
type GetPaginatedItemsArgs = {
limit: number
cursor?: string
@@ -1,8 +1,5 @@
import { db } from '@/db/knex'
import {
Resolvers,
WorkspaceMembersByRole
} from '@/modules/core/graph/generated/graphql'
import { Resolvers } from '@/modules/core/graph/generated/graphql'
import { removePrivateFields } from '@/modules/core/helpers/userHelper'
import {
getProjectCollaboratorsFactory,
@@ -1117,6 +1114,34 @@ export = FF_WORKSPACES_MODULE_ENABLED
})
return team
},
teamByRole: async (parent) => {
const { id: workspaceId } = parent
const countWorkspaceRole = countWorkspaceRoleWithOptionalProjectRoleFactory({
db
})
return {
admins: {
totalCount: await countWorkspaceRole({
workspaceId,
workspaceRole: Roles.Workspace.Admin
})
},
members: {
totalCount: await countWorkspaceRole({
workspaceId,
workspaceRole: Roles.Workspace.Member
})
},
guests: {
totalCount: await countWorkspaceRole({
workspaceId,
workspaceRole: Roles.Workspace.Guest
})
}
}
},
invitedTeam: async (parent, args) => {
const getPendingTeam = getPendingWorkspaceCollaboratorsFactory({
queryAllResourceInvites: queryAllResourceInvitesFactory({
@@ -1225,34 +1250,7 @@ export = FF_WORKSPACES_MODULE_ENABLED
return await getWorkspaceSsoProviderRecordFactory({ db })({
workspaceId: parent.id
})
},
membersByRole: (parent) =>
({
admins: async () => ({
totalCount: await countWorkspaceRoleWithOptionalProjectRoleFactory({
db
})({
workspaceId: parent.id,
workspaceRole: Roles.Workspace.Admin
})
}),
members: async () => ({
totalCount: await countWorkspaceRoleWithOptionalProjectRoleFactory({
db
})({
workspaceId: parent.id,
workspaceRole: Roles.Workspace.Member
})
}),
guests: async () => ({
totalCount: await countWorkspaceRoleWithOptionalProjectRoleFactory({
db
})({
workspaceId: parent.id,
workspaceRole: Roles.Workspace.Guest
})
})
} as unknown as WorkspaceMembersByRole)
}
},
WorkspaceSso: {
provider: async ({ workspaceId }) => {
@@ -373,28 +373,13 @@ export const getWorkspaceWithSubscriptionQuery = gql`
currentBillingCycleEnd
billingInterval
seats {
guest
plan
assigned
totalCount
viewersCount
}
}
}
}
${basicWorkspaceFragment}
`
export const getWorkspaceWithSeatsByType = gql`
query GetWorkspaceWithSeatsByType($workspaceId: String!) {
workspace(id: $workspaceId) {
...BasicWorkspace
seatsByType {
editors {
totalCount
}
viewers {
totalCount
editors {
available
assigned
}
viewers {
assigned
}
}
}
}
@@ -420,7 +405,7 @@ export const getWorkspaceWithMembersByRole = gql`
query GetWorkspaceWithMembersByRole($workspaceId: String!) {
workspace(id: $workspaceId) {
...BasicWorkspace
membersByRole {
teamByRole {
admins {
totalCount
}
@@ -856,10 +856,10 @@ describe('Workspaces GQL CRUD', () => {
})
expect(res).to.not.haveGraphQLErrors()
const seats = res.data?.workspace.membersByRole
expect(seats?.guests?.totalCount).to.eq(2)
expect(seats?.members?.totalCount).to.eq(3)
expect(seats?.admins?.totalCount).to.eq(1)
const roles = res.data?.workspace.teamByRole
expect(roles?.guests?.totalCount).to.eq(2)
expect(roles?.members?.totalCount).to.eq(3)
expect(roles?.admins?.totalCount).to.eq(1)
})
})
})
@@ -4352,7 +4352,6 @@ export type Workspace = {
invitedTeam?: Maybe<Array<PendingWorkspaceCollaborator>>;
/** Logo image as base64-encoded string */
logo?: Maybe<Scalars['String']['output']>;
membersByRole?: Maybe<WorkspaceMembersByRole>;
name: Scalars['String']['output'];
permissions: WorkspacePermissionChecks;
plan?: Maybe<WorkspacePlan>;
@@ -4363,12 +4362,12 @@ export type Workspace = {
role?: Maybe<Scalars['String']['output']>;
/** Active user's seat type for this workspace. `null` if request is not authenticated, or the workspace is not explicitly shared with you. */
seatType?: Maybe<WorkspaceSeatType>;
seatsByType?: Maybe<WorkspaceSeatsByType>;
slug: Scalars['String']['output'];
/** Information about the workspace's SSO configuration and the current user's SSO session, if present */
sso?: Maybe<WorkspaceSso>;
subscription?: Maybe<WorkspaceSubscription>;
team: WorkspaceCollaboratorCollection;
teamByRole: WorkspaceTeamByRole;
updatedAt: Scalars['DateTime']['output'];
};
@@ -4611,13 +4610,6 @@ export const WorkspaceJoinRequestStatus = {
} as const;
export type WorkspaceJoinRequestStatus = typeof WorkspaceJoinRequestStatus[keyof typeof WorkspaceJoinRequestStatus];
export type WorkspaceMembersByRole = {
__typename?: 'WorkspaceMembersByRole';
admins?: Maybe<WorkspaceRoleCollection>;
guests?: Maybe<WorkspaceRoleCollection>;
members?: Maybe<WorkspaceRoleCollection>;
};
export type WorkspaceMutations = {
__typename?: 'WorkspaceMutations';
addDomain: Workspace;
@@ -4925,18 +4917,25 @@ export type WorkspaceSubscription = {
updatedAt: Scalars['DateTime']['output'];
};
export type WorkspaceSubscriptionSeatCount = {
__typename?: 'WorkspaceSubscriptionSeatCount';
/** Total number of seats in use by workspace users */
assigned: Scalars['Int']['output'];
/** Total number of seats purchased and available in the current subscription cycle */
available: Scalars['Int']['output'];
};
export type WorkspaceSubscriptionSeats = {
__typename?: 'WorkspaceSubscriptionSeats';
/** Number assigned seats in the current billing cycle */
assigned: Scalars['Int']['output'];
/** @deprecated Field no longer supported */
guest: Scalars['Int']['output'];
/** @deprecated Field no longer supported */
plan: Scalars['Int']['output'];
/** Total number of seats purchased and available in the current subscription cycle */
totalCount: Scalars['Int']['output'];
/** Number of viewer seats currently assigned in the workspace */
viewersCount: Scalars['Int']['output'];
editors: WorkspaceSubscriptionSeatCount;
viewers: WorkspaceSubscriptionSeatCount;
};
export type WorkspaceTeamByRole = {
__typename?: 'WorkspaceTeamByRole';
admins?: Maybe<WorkspaceRoleCollection>;
guests?: Maybe<WorkspaceRoleCollection>;
members?: Maybe<WorkspaceRoleCollection>;
};
export type WorkspaceTeamFilter = {
@@ -5261,14 +5260,7 @@ export type GetWorkspaceWithSubscriptionQueryVariables = Exact<{
}>;
export type GetWorkspaceWithSubscriptionQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', id: string, name: string, slug: string, updatedAt: string, createdAt: string, role?: string | null, readOnly: boolean, subscription?: { __typename?: 'WorkspaceSubscription', createdAt: string, updatedAt: string, currentBillingCycleEnd: string, billingInterval: BillingInterval, seats: { __typename?: 'WorkspaceSubscriptionSeats', guest: number, plan: number, assigned: number, totalCount: number, viewersCount: number } } | null } };
export type GetWorkspaceWithSeatsByTypeQueryVariables = Exact<{
workspaceId: Scalars['String']['input'];
}>;
export type GetWorkspaceWithSeatsByTypeQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', id: string, name: string, slug: string, updatedAt: string, createdAt: string, role?: string | null, readOnly: boolean, seatsByType?: { __typename?: 'WorkspaceSeatsByType', editors?: { __typename?: 'WorkspaceSeatCollection', totalCount: number } | null, viewers?: { __typename?: 'WorkspaceSeatCollection', totalCount: number } | null } | null } };
export type GetWorkspaceWithSubscriptionQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', id: string, name: string, slug: string, updatedAt: string, createdAt: string, role?: string | null, readOnly: boolean, subscription?: { __typename?: 'WorkspaceSubscription', createdAt: string, updatedAt: string, currentBillingCycleEnd: string, billingInterval: BillingInterval, seats: { __typename?: 'WorkspaceSubscriptionSeats', editors: { __typename?: 'WorkspaceSubscriptionSeatCount', available: number, assigned: number }, viewers: { __typename?: 'WorkspaceSubscriptionSeatCount', assigned: number } } } | null } };
export type GetWorkspacePlanUsageQueryVariables = Exact<{
workspaceId: Scalars['String']['input'];
@@ -5282,7 +5274,7 @@ export type GetWorkspaceWithMembersByRoleQueryVariables = Exact<{
}>;
export type GetWorkspaceWithMembersByRoleQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', id: string, name: string, slug: string, updatedAt: string, createdAt: string, role?: string | null, readOnly: boolean, membersByRole?: { __typename?: 'WorkspaceMembersByRole', admins?: { __typename?: 'WorkspaceRoleCollection', totalCount: number } | null, members?: { __typename?: 'WorkspaceRoleCollection', totalCount: number } | null, guests?: { __typename?: 'WorkspaceRoleCollection', totalCount: number } | null } | null } };
export type GetWorkspaceWithMembersByRoleQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', id: string, name: string, slug: string, updatedAt: string, createdAt: string, role?: string | null, readOnly: boolean, teamByRole: { __typename?: 'WorkspaceTeamByRole', admins?: { __typename?: 'WorkspaceRoleCollection', totalCount: number } | null, members?: { __typename?: 'WorkspaceRoleCollection', totalCount: number } | null, guests?: { __typename?: 'WorkspaceRoleCollection', totalCount: number } | null } } };
export type UpdateWorkspaceProjectRoleMutationVariables = Exact<{
input: ProjectUpdateRoleInput;
@@ -6132,10 +6124,9 @@ export const OnWorkspaceUpdatedDocument = {"kind":"Document","definitions":[{"ki
export const DismissWorkspaceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"dismissWorkspace"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceDismissInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dismiss"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]}}]} as unknown as DocumentNode<DismissWorkspaceMutation, DismissWorkspaceMutationVariables>;
export const RequestToJoinWorkspaceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"requestToJoinWorkspace"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceRequestToJoinInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"requestToJoin"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]}}]} as unknown as DocumentNode<RequestToJoinWorkspaceMutation, RequestToJoinWorkspaceMutationVariables>;
export const GetWorkspaceWithJoinRequestsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetWorkspaceWithJoinRequests"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"AdminWorkspaceJoinRequestFilter"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspace"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BasicWorkspace"}},{"kind":"Field","name":{"kind":"Name","value":"adminWorkspacesJoinRequests"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}},{"kind":"Argument","name":{"kind":"Name","value":"cursor"},"value":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"workspace"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"readOnly"}}]}}]} as unknown as DocumentNode<GetWorkspaceWithJoinRequestsQuery, GetWorkspaceWithJoinRequestsQueryVariables>;
export const GetWorkspaceWithSubscriptionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetWorkspaceWithSubscription"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspace"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BasicWorkspace"}},{"kind":"Field","name":{"kind":"Name","value":"subscription"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"currentBillingCycleEnd"}},{"kind":"Field","name":{"kind":"Name","value":"billingInterval"}},{"kind":"Field","name":{"kind":"Name","value":"seats"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"guest"}},{"kind":"Field","name":{"kind":"Name","value":"plan"}},{"kind":"Field","name":{"kind":"Name","value":"assigned"}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"viewersCount"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"readOnly"}}]}}]} as unknown as DocumentNode<GetWorkspaceWithSubscriptionQuery, GetWorkspaceWithSubscriptionQueryVariables>;
export const GetWorkspaceWithSeatsByTypeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetWorkspaceWithSeatsByType"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspace"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BasicWorkspace"}},{"kind":"Field","name":{"kind":"Name","value":"seatsByType"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"editors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"viewers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"readOnly"}}]}}]} as unknown as DocumentNode<GetWorkspaceWithSeatsByTypeQuery, GetWorkspaceWithSeatsByTypeQueryVariables>;
export const GetWorkspaceWithSubscriptionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetWorkspaceWithSubscription"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspace"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BasicWorkspace"}},{"kind":"Field","name":{"kind":"Name","value":"subscription"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"currentBillingCycleEnd"}},{"kind":"Field","name":{"kind":"Name","value":"billingInterval"}},{"kind":"Field","name":{"kind":"Name","value":"seats"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"editors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"available"}},{"kind":"Field","name":{"kind":"Name","value":"assigned"}}]}},{"kind":"Field","name":{"kind":"Name","value":"viewers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assigned"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"readOnly"}}]}}]} as unknown as DocumentNode<GetWorkspaceWithSubscriptionQuery, GetWorkspaceWithSubscriptionQueryVariables>;
export const GetWorkspacePlanUsageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetWorkspacePlanUsage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspace"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BasicWorkspace"}},{"kind":"Field","name":{"kind":"Name","value":"plan"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"usage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"projectCount"}},{"kind":"Field","name":{"kind":"Name","value":"modelCount"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"readOnly"}}]}}]} as unknown as DocumentNode<GetWorkspacePlanUsageQuery, GetWorkspacePlanUsageQueryVariables>;
export const GetWorkspaceWithMembersByRoleDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetWorkspaceWithMembersByRole"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspace"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BasicWorkspace"}},{"kind":"Field","name":{"kind":"Name","value":"membersByRole"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"admins"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"guests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"readOnly"}}]}}]} as unknown as DocumentNode<GetWorkspaceWithMembersByRoleQuery, GetWorkspaceWithMembersByRoleQueryVariables>;
export const GetWorkspaceWithMembersByRoleDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetWorkspaceWithMembersByRole"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspace"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BasicWorkspace"}},{"kind":"Field","name":{"kind":"Name","value":"teamByRole"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"admins"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"guests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"readOnly"}}]}}]} as unknown as DocumentNode<GetWorkspaceWithMembersByRoleQuery, GetWorkspaceWithMembersByRoleQueryVariables>;
export const UpdateWorkspaceProjectRoleDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateWorkspaceProjectRole"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ProjectUpdateRoleInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"projects"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateRole"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BasicProjectFields"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicProjectFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"allowPublicComments"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<UpdateWorkspaceProjectRoleMutation, UpdateWorkspaceProjectRoleMutationVariables>;
export const UpdateWorkspaceSeatTypeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateWorkspaceSeatType"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceUpdateSeatTypeInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateSeatType"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"seatType"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode<UpdateWorkspaceSeatTypeMutation, UpdateWorkspaceSeatTypeMutationVariables>;
export const GetProjectInvitableCollaboratorsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetProjectInvitableCollaborators"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"search"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"invitableCollaborators"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"search"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode<GetProjectInvitableCollaboratorsQuery, GetProjectInvitableCollaboratorsQueryVariables>;
+2 -11
View File
@@ -1,10 +1,5 @@
apiVersion: v2
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
# Set by the build process to the correct value
# 'appVersion' is set by the build process to the correct value
appVersion: '0.1.0-local'
description: Speckle Server
home: 'https://speckle.systems/'
@@ -16,9 +11,5 @@ name: speckle-server
sources:
- 'https://github.com/specklesystems/speckle-server'
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
# Set by the build process to the correct value
# 'version' is set by the build process to the correct value
version: 0.1.0-local
@@ -615,112 +615,58 @@ Generate the environment variables for Speckle server and Speckle objects deploy
key: {{ .Values.server.billing.stripeEndpointSigningKey.secretKey }}
- name: WORKSPACE_GUEST_SEAT_STRIPE_PRODUCT_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspaceGuestSeatStripeProductId.secretKey }}
value: {{ .Values.server.billing.workspaceGuestSeatStripeProductId }}
- name: WORKSPACE_MONTHLY_GUEST_SEAT_STRIPE_PRICE_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspaceMonthlyGuestSeatStripePriceId.secretKey }}
value: {{ .Values.server.billing.workspaceMonthlyGuestSeatStripePriceId }}
- name: WORKSPACE_YEARLY_GUEST_SEAT_STRIPE_PRICE_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspaceYearlyGuestSeatStripePriceId.secretKey }}
value: {{ .Values.server.billing.workspaceYearlyGuestSeatStripePriceId }}
- name: WORKSPACE_STARTER_SEAT_STRIPE_PRODUCT_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspaceStarterSeatStripeProductId.secretKey }}
value: {{ .Values.server.billing.workspaceStarterSeatStripeProductId }}
- name: WORKSPACE_MONTHLY_STARTER_SEAT_STRIPE_PRICE_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspaceMonthlyStarterSeatStripePriceId.secretKey }}
value: {{ .Values.server.billing.workspaceMonthlyStarterSeatStripePriceId }}
- name: WORKSPACE_YEARLY_STARTER_SEAT_STRIPE_PRICE_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspaceYearlyStarterSeatStripePriceId.secretKey }}
value: {{ .Values.server.billing.workspaceYearlyStarterSeatStripePriceId }}
- name: WORKSPACE_PLUS_SEAT_STRIPE_PRODUCT_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspacePlusSeatStripeProductId.secretKey }}
value: {{ .Values.server.billing.workspacePlusSeatStripeProductId }}
- name: WORKSPACE_MONTHLY_PLUS_SEAT_STRIPE_PRICE_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspaceMonthlyPlusSeatStripePriceId.secretKey }}
value: {{ .Values.server.billing.workspaceMonthlyPlusSeatStripePriceId }}
- name: WORKSPACE_YEARLY_PLUS_SEAT_STRIPE_PRICE_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspaceYearlyPlusSeatStripePriceId.secretKey }}
value: {{ .Values.server.billing.workspaceYearlyPlusSeatStripePriceId }}
- name: WORKSPACE_BUSINESS_SEAT_STRIPE_PRODUCT_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspaceBusinessSeatStripeProductId.secretKey }}
value: {{ .Values.server.billing.workspaceBusinessSeatStripeProductId }}
- name: WORKSPACE_MONTHLY_BUSINESS_SEAT_STRIPE_PRICE_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspaceMonthlyBusinessSeatStripePriceId.secretKey }}
value: {{ .Values.server.billing.workspaceMonthlyBusinessSeatStripePriceId }}
- name: WORKSPACE_YEARLY_BUSINESS_SEAT_STRIPE_PRICE_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspaceYearlyBusinessSeatStripePriceId.secretKey }}
value: {{ .Values.server.billing.workspaceYearlyBusinessSeatStripePriceId }}
- name: WORKSPACE_TEAM_SEAT_STRIPE_PRODUCT_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspaceTeamSeatStripeProductId.secretKey }}
value: {{ .Values.server.billing.workspaceTeamSeatStripeProductId }}
- name: WORKSPACE_MONTHLY_TEAM_SEAT_STRIPE_PRICE_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspaceMonthlyTeamSeatStripePriceId.secretKey }}
value: {{ .Values.server.billing.workspaceMonthlyTeamSeatStripePriceId }}
- name: WORKSPACE_YEARLY_TEAM_SEAT_STRIPE_PRICE_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspaceYearlyTeamSeatStripePriceId.secretKey }}
value: {{ .Values.server.billing.workspaceYearlyTeamSeatStripePriceId }}
- name: WORKSPACE_PRO_SEAT_STRIPE_PRODUCT_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspaceProSeatStripeProductId.secretKey }}
value: {{ .Values.server.billing.workspaceProSeatStripeProductId }}
- name: WORKSPACE_MONTHLY_PRO_SEAT_STRIPE_PRICE_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspaceMonthlyProSeatStripePriceId.secretKey }}
value: {{ .Values.server.billing.workspaceMonthlyProSeatStripePriceId }}
- name: WORKSPACE_YEARLY_PRO_SEAT_STRIPE_PRICE_ID
valueFrom:
secretKeyRef:
name: "{{ default .Values.secretName .Values.server.billing.secretName }}"
key: {{ .Values.server.billing.workspaceYearlyProSeatStripePriceId.secretKey }}
value: {{ .Values.server.billing.workspaceYearlyProSeatStripePriceId }}
{{- end }}
@@ -806,7 +752,7 @@ Generate the environment variables for Speckle server and Speckle objects deploy
{{- end }}
# *** Preview service ***
{{- if .Values.preview_service.deployInCluster }}
{{- if .Values.preview_service.enabled }}
- name: PREVIEW_SERVICE_USE_PRIVATE_OBJECTS_SERVER_URL
value: "true"
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.fileimport_service.enabled }}
{{- if ( or .Values.s3.endpoint .Values.s3.configMap.enabled ) }}
apiVersion: apps/v1
kind: Deployment
@@ -12,8 +13,10 @@ spec:
matchLabels:
app: speckle-fileimport-service
project: speckle-server
{{- with .Values.fileimport_service.deploymentStrategy }}
strategy:
type: RollingUpdate
{{- toYaml . | nindent 4 }}
{{- end }}
template:
metadata:
labels:
@@ -44,12 +47,14 @@ spec:
- "process.exit((Date.now() - require('fs').readFileSync('/tmp/last_successful_query', 'utf8') > 25 * 60 * 1000) ? 1 : 0)"
resources:
{{- with .Values.fileimport_service.requests }}
requests:
cpu: {{ .Values.fileimport_service.requests.cpu }}
memory: {{ .Values.fileimport_service.requests.memory }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.fileimport_service.limits }}
limits:
cpu: {{ .Values.fileimport_service.limits.cpu }}
memory: {{ .Values.fileimport_service.limits.memory }}
{{- toYaml . | nindent 12 }}
{{- end }}
securityContext:
allowPrivilegeEscalation: false
@@ -167,3 +172,4 @@ spec:
path: "multi-region-config.json"
{{- end }}
{{- end }}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.fileimport_service.enabled }}
{{- if (and (.Values.fileimport_service.networkPolicy.enabled) (eq .Values.networkPlugin.type "cilium")) -}}
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
@@ -49,3 +50,4 @@ spec:
# postgres
{{ include "speckle.networkpolicy.egress.postgres.cilium" $ | indent 4 }}
{{- end }}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.fileimport_service.enabled }}
{{- if (and (.Values.fileimport_service.networkPolicy.enabled) (eq .Values.networkPlugin.type "kubernetes")) -}}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
@@ -46,3 +47,4 @@ spec:
# postgres
{{ include "speckle.networkpolicy.egress.postgres" $ | indent 4 }}
{{- end -}}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.fileimport_service.enabled }}
{{- if ( or .Values.s3.endpoint .Values.s3.configMap.enabled ) -}}
apiVersion: v1
kind: Service
@@ -16,3 +17,4 @@ spec:
port: 9093
targetPort: metrics
{{- end -}}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.fileimport_service.enabled }}
{{- if (and ( or .Values.s3.endpoint .Values.s3.configMap.enabled ) .Values.fileimport_service.serviceAccount.create) -}}
apiVersion: v1
kind: ServiceAccount
@@ -19,3 +20,4 @@ secrets:
- name: {{ default .Values.secretName .Values.multiRegion.config.secretName }}
{{- end }}
{{- end -}}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.frontend_2.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -34,12 +35,14 @@ spec:
protocol: TCP
resources:
{{- with .Values.frontend_2.requests }}
requests:
cpu: {{ .Values.frontend_2.requests.cpu }}
memory: {{ .Values.frontend_2.requests.memory }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.frontend_2.limits }}
limits:
cpu: {{ .Values.frontend_2.limits.cpu }}
memory: {{ .Values.frontend_2.limits.memory }}
{{- toYaml . | nindent 12 }}
{{- end }}
# Allow for k8s to remove the pod from the service endpoints to stop receive traffic
lifecycle:
@@ -169,3 +172,4 @@ spec:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.frontend_2.enabled }}
{{- if (and (.Values.frontend_2.networkPolicy.enabled) (eq .Values.networkPlugin.type "cilium")) -}}
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
@@ -44,3 +45,4 @@ spec:
# redis
{{ include "speckle.networkpolicy.egress.redis.cilium" $ | indent 4 }}
{{- end -}}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.frontend_2.enabled }}
{{- if (and (.Values.frontend_2.networkPolicy.enabled) (eq .Values.networkPlugin.type "kubernetes")) -}}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
@@ -43,3 +44,4 @@ spec:
# redis
{{ include "speckle.networkpolicy.egress.redis" $ | indent 4 }}
{{- end -}}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.frontend_2.enabled }}
apiVersion: v1
kind: Service
metadata:
@@ -14,3 +15,4 @@ spec:
name: web
port: 8080
targetPort: www
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.frontend_2.enabled }}
{{- if .Values.frontend_2.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
@@ -16,3 +17,4 @@ imagePullSecrets:
secrets:
- name: {{ default .Values.secretName .Values.redis.connectionString.secretName }}
{{- end -}}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
@@ -22,4 +23,4 @@ spec:
{{- end }}
rules:
- host: {{ .Values.domain }}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
@@ -73,3 +74,4 @@ spec:
name: speckle-objects
port:
name: web
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.monitoring.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -29,12 +30,14 @@ spec:
protocol: TCP
resources:
{{- with .Values.monitoring.requests }}
requests:
cpu: {{ .Values.monitoring.requests.cpu }}
memory: {{ .Values.monitoring.requests.memory }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.monitoring.limits }}
limits:
cpu: {{ .Values.monitoring.limits.cpu }}
memory: {{ .Values.monitoring.limits.memory }}
{{- toYaml . | nindent 12 }}
{{- end }}
securityContext:
allowPrivilegeEscalation: false
@@ -169,3 +172,4 @@ spec:
{{- if .Values.monitoring.topologySpreadConstraints }}
topologySpreadConstraints: {{- include "speckle.renderTpl" (dict "value" .Values.monitoring.topologySpreadConstraints "context" $) | nindent 8 }}
{{- end }}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.monitoring.enabled }}
{{- if (and (.Values.monitoring.networkPolicy.enabled) (eq .Values.networkPlugin.type "cilium")) -}}
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
@@ -38,3 +39,4 @@ spec:
# postgres
{{ include "speckle.networkpolicy.egress.postgres.cilium" $ | indent 4 }}
{{- end }}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.monitoring.enabled }}
{{- if (and (.Values.monitoring.networkPolicy.enabled) (eq .Values.networkPlugin.type "kubernetes")) -}}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
@@ -39,3 +40,4 @@ spec:
# postgres
{{ include "speckle.networkpolicy.egress.postgres" $ | indent 4 }}
{{- end -}}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.monitoring.enabled }}
apiVersion: v1
kind: Service
metadata:
@@ -14,3 +15,4 @@ spec:
name: web
port: {{ .Values.monitoring.port }}
targetPort: metrics
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.monitoring.enabled }}
{{- if .Values.monitoring.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
@@ -19,3 +20,4 @@ secrets:
- name: {{ default .Values.secretName .Values.multiRegion.config.secretName }}
{{- end }}
{{- end -}}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.objects.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -33,12 +34,14 @@ spec:
protocol: TCP
resources:
{{- with .Values.objects.requests }}
requests:
cpu: {{ .Values.objects.requests.cpu }}
memory: {{ .Values.objects.requests.memory }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.objects.limits }}
limits:
cpu: {{ .Values.objects.limits.cpu }}
memory: {{ .Values.objects.limits.memory }}
{{- toYaml . | nindent 12 }}
{{- end }}
securityContext:
allowPrivilegeEscalation: false
@@ -156,3 +159,4 @@ spec:
- key: {{ .Values.multiRegion.config.secretKey }}
path: "multi-region-config.json"
{{- end }}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.objects.enabled }}
{{- if (and (.Values.objects.networkPolicy.enabled) (eq .Values.networkPlugin.type "cilium")) -}}
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
@@ -177,3 +178,4 @@ spec:
- port: "443"
protocol: TCP
{{- end }}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.objects.enabled }}
{{- if (and (.Values.objects.networkPolicy.enabled) (eq .Values.networkPlugin.type "kubernetes")) -}}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
@@ -83,3 +84,4 @@ spec:
{{ include "test.selectorLabels" $ | indent 14}}
{{- end }}
{{- end -}}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.objects.enabled }}
apiVersion: v1
kind: Service
metadata:
@@ -14,3 +15,4 @@ spec:
name: web
port: 3000
targetPort: http
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.objects.enabled }}
{{- if .Values.objects.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
@@ -52,3 +53,4 @@ secrets:
- name: {{ default .Values.secretName .Values.redis.previewServiceConnectionString.secretName }}
{{- end }}
{{- end -}}
{{- end }}
@@ -1,4 +1,4 @@
{{- if .Values.preview_service.deployInCluster }}
{{- if .Values.preview_service.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -12,8 +12,10 @@ spec:
matchLabels:
app: speckle-preview-service
project: speckle-server
{{- with .Values.preview_service.deploymentStrategy }}
strategy:
type: RollingUpdate
{{- toYaml . | nindent 4 }}
{{- end }}
template:
metadata:
labels:
@@ -32,21 +34,24 @@ spec:
livenessProbe:
initialDelaySeconds: 60
periodSeconds: 60
exec:
command:
- node
- -e
# just a dummy output for now, not yet sure how to do liveliness with the new setup.
# if there is no job in the queue, the service does nothing, so the prev solution would not work
- {{ printf "console.log(%s)" .Values.preview_service.puppeteer.timeoutMilliseconds }}
httpGet:
path: /liveness
port: metrics
readinessProbe:
httpGet:
path: /readiness
port: metrics
resources:
{{- with .Values.preview_service.requests }}
requests:
cpu: {{ .Values.preview_service.requests.cpu }}
memory: {{ .Values.preview_service.requests.memory }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.preview_service.limits }}
limits:
cpu: {{ .Values.preview_service.limits.cpu }}
memory: {{ .Values.preview_service.limits.memory }}
{{- toYaml . | nindent 12 }}
{{- end }}
securityContext:
allowPrivilegeEscalation: false
@@ -125,7 +130,4 @@ spec:
runAsGroup: 30000
seccompProfile:
type: RuntimeDefault
# Should be > preview generation time ( 1 hour for good measure )
terminationGracePeriodSeconds: 3600
{{- end }}
@@ -0,0 +1,35 @@
{{- if .Values.preview_service.enabled }}
{{- if .Values.preview_service.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: speckle-preview-service
namespace: {{ .Values.namespace }}
labels:
{{ include "preview_service.labels" . | indent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: speckle-preview-service
minReplicas: {{ .Values.preview_service.autoscaling.minReplicas }}
maxReplicas: {{ .Values.preview_service.autoscaling.maxReplicas }}
metrics:
{{- if .Values.preview_service.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.preview_service.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.preview_service.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.preview_service.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- end }}
{{- end }}
@@ -1,4 +1,4 @@
{{- if .Values.preview_service.deployInCluster }}
{{- if .Values.preview_service.enabled }}
{{- if (and (.Values.preview_service.networkPolicy.enabled) (eq .Values.networkPlugin.type "cilium")) -}}
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
@@ -1,4 +1,4 @@
{{- if .Values.preview_service.deployInCluster }}
{{- if .Values.preview_service.enabled }}
{{- if (and (.Values.preview_service.networkPolicy.enabled) (eq .Values.networkPlugin.type "kubernetes")) -}}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
@@ -1,4 +1,4 @@
{{- if .Values.preview_service.deployInCluster }}
{{- if .Values.preview_service.enabled }}
apiVersion: v1
kind: Service
metadata:
@@ -1,4 +1,4 @@
{{- if .Values.preview_service.deployInCluster }}
{{- if .Values.preview_service.enabled }}
{{- if .Values.preview_service.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
@@ -1,3 +1,4 @@
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
@@ -42,3 +43,4 @@ spec:
name: speckle-server
port:
name: web
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.server.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -33,12 +34,14 @@ spec:
protocol: TCP
resources:
{{- with .Values.server.requests }}
requests:
cpu: {{ .Values.server.requests.cpu }}
memory: {{ .Values.server.requests.memory }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.server.limits }}
limits:
cpu: {{ .Values.server.limits.cpu }}
memory: {{ .Values.server.limits.memory }}
{{- toYaml . | nindent 12 }}
{{- end }}
securityContext:
allowPrivilegeEscalation: false
@@ -156,3 +159,4 @@ spec:
- key: {{ .Values.multiRegion.config.secretKey }}
path: "multi-region-config.json"
{{- end }}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.server.enabled }}
{{- if (and (.Values.server.networkPolicy.enabled) (eq .Values.networkPlugin.type "cilium")) -}}
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
@@ -177,3 +178,4 @@ spec:
- port: "443"
protocol: TCP
{{- end }}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.server.enabled }}
{{- if (and (.Values.server.networkPolicy.enabled) (eq .Values.networkPlugin.type "kubernetes")) -}}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
@@ -83,3 +84,4 @@ spec:
{{ include "test.selectorLabels" $ | indent 14}}
{{- end }}
{{- end -}}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.server.enabled }}
apiVersion: v1
kind: Service
metadata:
@@ -14,3 +15,4 @@ spec:
name: web
port: 3000
targetPort: http
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.server.enabled }}
{{- if .Values.server.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
@@ -52,3 +53,4 @@ secrets:
- name: {{ default .Values.secretName .Values.redis.previewServiceConnectionString.secretName }}
{{- end }}
{{- end -}}
{{- end }}
@@ -32,12 +32,14 @@ spec:
- name: LOG_PRETTY
value: {{ .Values.test.logPretty | quote }}
resources:
{{- with .Values.test.requests }}
requests:
cpu: {{ .Values.test.requests.cpu }}
memory: {{ .Values.test.requests.memory }}
{{- toYaml . | nindent 14 }}
{{- end }}
{{- with .Values.test.limits }}
limits:
cpu: {{ .Values.test.limits.cpu }}
memory: {{ .Values.test.limits.memory }}
{{- toYaml . | nindent 14 }}
{{- end }}
securityContext:
allowPrivilegeEscalation: false
capabilities:
@@ -1,3 +1,4 @@
{{- if .Values.webhook_service.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -11,8 +12,10 @@ spec:
matchLabels:
app: speckle-webhook-service
project: speckle-server
{{- with .Values.webhook_service.deploymentStrategy }}
strategy:
type: RollingUpdate
{{- toYaml . | nindent 4 }}
{{- end }}
template:
metadata:
labels:
@@ -38,12 +41,14 @@ spec:
- process.exit(Date.now() - require('fs').readFileSync('/tmp/last_successful_query', 'utf8') > 30 * 1000)
resources:
{{- with .Values.webhook_service.requests }}
requests:
cpu: {{ .Values.webhook_service.requests.cpu }}
memory: {{ .Values.webhook_service.requests.memory }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.webhook_service.limits }}
limits:
cpu: {{ .Values.webhook_service.limits.cpu }}
memory: {{ .Values.webhook_service.limits.memory }}
{{- toYaml . | nindent 12 }}
{{- end }}
securityContext:
allowPrivilegeEscalation: false
@@ -151,3 +156,4 @@ spec:
- key: {{ .Values.multiRegion.config.secretKey }}
path: "multi-region-config.json"
{{- end }}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.webhook_service.enabled }}
{{- if (and (.Values.webhook_service.networkPolicy.enabled) (eq .Values.networkPlugin.type "cilium")) -}}
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
@@ -43,3 +44,4 @@ spec:
- toEntities:
- world
{{- end }}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.webhook_service.enabled }}
{{- if (and (.Values.webhook_service.networkPolicy.enabled) (eq .Values.networkPlugin.type "kubernetes")) -}}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
@@ -43,3 +44,4 @@ spec:
- port: 53
protocol: UDP
{{- end -}}
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.webhook_service.enabled }}
apiVersion: v1
kind: Service
metadata:
@@ -14,3 +15,4 @@ spec:
name: web
port: 9095
targetPort: metrics
{{- end }}
@@ -1,3 +1,4 @@
{{- if .Values.webhook_service.enabled }}
{{- if .Values.webhook_service.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
@@ -19,3 +20,4 @@ secrets:
- name: {{ default .Values.secretName .Values.multiRegion.config.secretName }}
{{- end }}
{{- end -}}
{{- end }}
+141 -146
View File
@@ -135,6 +135,11 @@
"ingress": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"description": "If enabled, the ingress resources will be deployed",
"default": true
},
"namespace": {
"type": "string",
"description": "The namespace in which the ingress controller is deployed.",
@@ -149,7 +154,7 @@
},
"docker_image_tag": {
"type": "string",
"description": "Speckle is published as a Docker Image. The version of the image which will be deployed is specified by this tag.",
"description": "DEPRECATED: Use `{service}.image` with full image name instead. Speckle is published as a Docker Image. The version of the image which will be deployed is specified by this tag.",
"default": "2"
},
"imagePullPolicy": {
@@ -622,6 +627,11 @@
"server": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"description": "If enabled, the Speckle server will be deployed",
"default": true
},
"replicas": {
"type": "number",
"description": "The number of instances of the Server pod to be deployed within the cluster.",
@@ -821,184 +831,94 @@
}
},
"workspaceGuestSeatStripeProductId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspaceGuestSeatStripeProductId secret as its value.",
"default": "workspaceGuestSeatStripeProductId"
}
}
"type": "string",
"description": "The workspace Guest Seat Product Id as configured in Stripe.",
"default": ""
},
"workspaceMonthlyGuestSeatStripePriceId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspaceMonthlyGuestSeatStripePriceId secret as its value.",
"default": "workspaceMonthlyGuestSeatStripePriceId"
}
}
"type": "string",
"description": "The workspace Monthly Guest Seat Price Id as configured in Stripe.",
"default": ""
},
"workspaceYearlyGuestSeatStripePriceId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspaceYearlyGuestSeatStripePriceId secret as its value.",
"default": "workspaceYearlyGuestSeatStripePriceId"
}
}
"type": "string",
"description": "The workspace Yearly Guest Seat Price Id as configured in Stripe.",
"default": ""
},
"workspaceStarterSeatStripeProductId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspaceStarterSeatStripeProductId secret as its value.",
"default": "workspaceStarterSeatStripeProductId"
}
}
"type": "string",
"description": "The workspace Starter Seat Product Id as configured in Stripe.",
"default": ""
},
"workspaceMonthlyStarterSeatStripePriceId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspaceMonthlyStarterSeatStripePriceId secret as its value.",
"default": "workspaceMonthlyStarterSeatStripePriceId"
}
}
"type": "string",
"description": "The workspace Monthly Starter Seat Price Id as configured in Stripe.",
"default": ""
},
"workspaceYearlyStarterSeatStripePriceId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspaceYearlyStarterSeatStripePriceId secret as its value.",
"default": "workspaceYearlyStarterSeatStripePriceId"
}
}
"type": "string",
"description": "The workspace Yearly Starter Seat Price Id as configured in Stripe.",
"default": ""
},
"workspacePlusSeatStripeProductId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspacePlusSeatStripeProductId secret as its value.",
"default": "workspacePlusSeatStripeProductId"
}
}
"type": "string",
"description": "The workspace Plus Seat Product Id as configured in Stripe.",
"default": ""
},
"workspaceMonthlyPlusSeatStripePriceId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspaceMonthlyPlusSeatStripePriceId secret as its value.",
"default": "workspaceMonthlyPlusSeatStripePriceId"
}
}
"type": "string",
"description": "The workspace Monthly Plus Seat Price Id as configured in Stripe.",
"default": ""
},
"workspaceYearlyPlusSeatStripePriceId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspaceYearlyPlusSeatStripePriceId secret as its value.",
"default": "workspaceYearlyPlusSeatStripePriceId"
}
}
"type": "string",
"description": "The workspace Yearly Plus Seat Price Id as configured in Stripe.",
"default": ""
},
"workspaceBusinessSeatStripeProductId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspaceBusinessSeatStripeProductId secret as its value.",
"default": "workspaceBusinessSeatStripeProductId"
}
}
"type": "string",
"description": "The workspace Business Seat Product Id as configured in Stripe.",
"default": ""
},
"workspaceMonthlyBusinessSeatStripePriceId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspaceMonthlyBusinessSeatStripePriceId secret as its value.",
"default": "workspaceMonthlyBusinessSeatStripePriceId"
}
}
"type": "string",
"description": "The workspace Monthly Business Seat Price Id as configured in Stripe.",
"default": ""
},
"workspaceYearlyBusinessSeatStripePriceId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspaceYearlyBusinessSeatStripePriceId secret as its value.",
"default": "workspaceYearlyBusinessSeatStripePriceId"
}
}
"type": "string",
"description": "The workspace Yearly Business Seat Price Id as configured in Stripe.",
"default": ""
},
"workspaceTeamSeatStripeProductId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspaceTeamSeatStripeProductId secret as its value.",
"default": "workspaceTeamSeatStripeProductId"
}
}
"type": "string",
"description": "The workspace Team Seat Product Id as configured in Stripe.",
"default": ""
},
"workspaceMonthlyTeamSeatStripePriceId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspaceMonthlyTeamSeatStripePriceId secret as its value.",
"default": "workspaceMonthlyTeamSeatStripePriceId"
}
}
"type": "string",
"description": "The workspace Monthly Team Seat Price Id as configured in Stripe.",
"default": ""
},
"workspaceYearlyTeamSeatStripePriceId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspaceYearlyTeamSeatStripePriceId secret as its value.",
"default": "workspaceYearlyTeamSeatStripePriceId"
}
}
"type": "string",
"description": "The workspace Yearly Team Seat Price Id as configured in Stripe.",
"default": ""
},
"workspaceProSeatStripeProductId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspaceProSeatStripeProductId secret as its value.",
"default": "workspaceProSeatStripeProductId"
}
}
"type": "string",
"description": "The workspace Pro Seat Product Id as configured in Stripe.",
"default": ""
},
"workspaceMonthlyProSeatStripePriceId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspaceMonthlyProSeatStripePriceId secret as its value.",
"default": "workspaceMonthlyProSeatStripePriceId"
}
}
"type": "string",
"description": "The workspace Monthly Pro Seat Price Id as configured in Stripe.",
"default": ""
},
"workspaceYearlyProSeatStripePriceId": {
"type": "object",
"properties": {
"secretKey": {
"type": "string",
"description": "The key within the Kubernetes Secret holding the workspaceYearlyProSeatStripePriceId secret as its value.",
"default": "workspaceYearlyProSeatStripePriceId"
}
}
"type": "string",
"description": "The workspace Yearly Pro Seat Price Id as configured in Stripe.",
"default": ""
}
}
},
@@ -1616,6 +1536,11 @@
"objects": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"description": "If enabled, the Speckle server will be deployed with the Objects component enabled.",
"default": true
},
"replicas": {
"type": "number",
"description": "The number of instances of the Server pod to be deployed within the cluster.",
@@ -1890,7 +1815,7 @@
"preview_service": {
"type": "object",
"properties": {
"deployInCluster": {
"enabled": {
"type": "boolean",
"description": "If enabled, the Preview Service will be deployed within the cluster and speckle-server will be configured to send the kubernetes service url of the objects server to the Preview Service.",
"default": true
@@ -1905,6 +1830,16 @@
"description": "The number of instances of the Preview Service pod to be deployed within the cluster.",
"default": 1
},
"deploymentStrategy": {
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "The deployment strategy type to be used for the Preview Service. This can be set to either `Recreate` or `RollingUpdate`. The default is `Recreate` as preview service does not require 100% availability.",
"default": "Recreate"
}
}
},
"logLevel": {
"type": "string",
"description": "The minimum level of logs which will be output. Suitable values are trace, debug, info, warn, error, fatal, or silent",
@@ -1975,6 +1910,31 @@
}
}
},
"autoscaling": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"description": "",
"default": false
},
"minReplicas": {
"type": "number",
"description": "",
"default": 1
},
"maxReplicas": {
"type": "number",
"description": "",
"default": 10
},
"targetCPUUtilizationPercentage": {
"type": "number",
"description": "",
"default": 80
}
}
},
"networkPolicy": {
"type": "object",
"properties": {
@@ -2022,11 +1982,26 @@
"webhook_service": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"description": "If enabled, the Webhook Service will be deployed within the cluster.",
"default": true
},
"replicas": {
"type": "number",
"description": "The number of instances of the Webhook Service pod to be deployed within the cluster.",
"default": 1
},
"deploymentStrategy": {
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "The deployment strategy type to be used for the Webhook Service. This can be set to either `Recreate` or `RollingUpdate`. The default is `Recreate` as webhook service does not require 100% availability.",
"default": "Recreate"
}
}
},
"logLevel": {
"type": "string",
"description": "The minimum level of logs which will be output. Suitable values are trace, debug, info, warn, error, fatal, or silent",
@@ -2124,11 +2099,26 @@
"fileimport_service": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"description": "If enabled, the File Import Service will be deployed within the cluster.",
"default": true
},
"replicas": {
"type": "number",
"description": "The number of instances of the FileImport Service pod to be deployed within the cluster.",
"default": 1
},
"deploymentStrategy": {
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "The deployment strategy type to be used for the FileImport Service. This can be set to either `Recreate` or `RollingUpdate`. The default is `Recreate` as file import service does not require 100% availability.",
"default": "Recreate"
}
}
},
"logLevel": {
"type": "string",
"description": "The minimum level of logs which will be output. Suitable values are trace, debug, info, warn, error, fatal, or silent",
@@ -2246,6 +2236,11 @@
"monitoring": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"description": "If enabled, database monitoring will be deployed within the cluster.",
"default": true
},
"replicas": {
"type": "number",
"description": "The number of instances of the Monitoring pod to be deployed within the cluster.",
+90 -57
View File
@@ -88,6 +88,9 @@ networkPlugin:
## @descriptionEnd
##
ingress:
## @param ingress.enabled If enabled, the ingress resources will be deployed
##
enabled: true
## @param ingress.namespace The namespace in which the ingress controller is deployed.
namespace: ingress-nginx
## @param ingress.controllerName The name of the Kubernetes pod in which the ingress controller is deployed.
@@ -95,7 +98,7 @@ ingress:
## @section Common parameters
##
## @param docker_image_tag Speckle is published as a Docker Image. The version of the image which will be deployed is specified by this tag.
## @param docker_image_tag DEPRECATED: Use `{service}.image` with full image name instead. Speckle is published as a Docker Image. The version of the image which will be deployed is specified by this tag.
##
docker_image_tag: '2'
@@ -461,6 +464,9 @@ imagePullSecrets: []
## @descriptionEnd
##
server:
## @param server.enabled If enabled, the Speckle server will be deployed
##
enabled: true
## @param server.replicas The number of instances of the Server pod to be deployed within the cluster.
##
replicas: 1
@@ -553,65 +559,48 @@ server:
stripeEndpointSigningKey:
## @param server.billing.stripeEndpointSigningKey.secretKey The key within the Kubernetes Secret holding the stripeEndpointSigningKey secret as its value.
secretKey: 'stripeEndpointSigningKey'
workspaceGuestSeatStripeProductId:
## @param server.billing.workspaceGuestSeatStripeProductId.secretKey The key within the Kubernetes Secret holding the workspaceGuestSeatStripeProductId secret as its value.
secretKey: 'workspaceGuestSeatStripeProductId'
workspaceMonthlyGuestSeatStripePriceId:
## @param server.billing.workspaceMonthlyGuestSeatStripePriceId.secretKey The key within the Kubernetes Secret holding the workspaceMonthlyGuestSeatStripePriceId secret as its value.
secretKey: 'workspaceMonthlyGuestSeatStripePriceId'
workspaceYearlyGuestSeatStripePriceId:
## @param server.billing.workspaceYearlyGuestSeatStripePriceId.secretKey The key within the Kubernetes Secret holding the workspaceYearlyGuestSeatStripePriceId secret as its value.
secretKey: 'workspaceYearlyGuestSeatStripePriceId'
workspaceStarterSeatStripeProductId:
## @param server.billing.workspaceStarterSeatStripeProductId.secretKey The key within the Kubernetes Secret holding the workspaceStarterSeatStripeProductId secret as its value.
secretKey: 'workspaceStarterSeatStripeProductId'
workspaceMonthlyStarterSeatStripePriceId:
## @param server.billing.workspaceMonthlyStarterSeatStripePriceId.secretKey The key within the Kubernetes Secret holding the workspaceMonthlyStarterSeatStripePriceId secret as its value.
secretKey: 'workspaceMonthlyStarterSeatStripePriceId'
workspaceYearlyStarterSeatStripePriceId:
## @param server.billing.workspaceYearlyStarterSeatStripePriceId.secretKey The key within the Kubernetes Secret holding the workspaceYearlyStarterSeatStripePriceId secret as its value.
secretKey: 'workspaceYearlyStarterSeatStripePriceId'
## @param server.billing.workspaceGuestSeatStripeProductId The workspace Guest Seat Product Id as configured in Stripe.
workspaceGuestSeatStripeProductId: ''
## @param server.billing.workspaceMonthlyGuestSeatStripePriceId The workspace Monthly Guest Seat Price Id as configured in Stripe.
workspaceMonthlyGuestSeatStripePriceId: ''
## @param server.billing.workspaceYearlyGuestSeatStripePriceId The workspace Yearly Guest Seat Price Id as configured in Stripe.
workspaceYearlyGuestSeatStripePriceId: ''
workspacePlusSeatStripeProductId:
## @param server.billing.workspacePlusSeatStripeProductId.secretKey The key within the Kubernetes Secret holding the workspacePlusSeatStripeProductId secret as its value.
secretKey: 'workspacePlusSeatStripeProductId'
workspaceMonthlyPlusSeatStripePriceId:
## @param server.billing.workspaceMonthlyPlusSeatStripePriceId.secretKey The key within the Kubernetes Secret holding the workspaceMonthlyPlusSeatStripePriceId secret as its value.
secretKey: 'workspaceMonthlyPlusSeatStripePriceId'
workspaceYearlyPlusSeatStripePriceId:
## @param server.billing.workspaceYearlyPlusSeatStripePriceId.secretKey The key within the Kubernetes Secret holding the workspaceYearlyPlusSeatStripePriceId secret as its value.
secretKey: 'workspaceYearlyPlusSeatStripePriceId'
## @param server.billing.workspaceStarterSeatStripeProductId The workspace Starter Seat Product Id as configured in Stripe.
workspaceStarterSeatStripeProductId: ''
## @param server.billing.workspaceMonthlyStarterSeatStripePriceId The workspace Monthly Starter Seat Price Id as configured in Stripe.
workspaceMonthlyStarterSeatStripePriceId: ''
## @param server.billing.workspaceYearlyStarterSeatStripePriceId The workspace Yearly Starter Seat Price Id as configured in Stripe.
workspaceYearlyStarterSeatStripePriceId: ''
workspaceBusinessSeatStripeProductId:
## @param server.billing.workspaceBusinessSeatStripeProductId.secretKey The key within the Kubernetes Secret holding the workspaceBusinessSeatStripeProductId secret as its value.
secretKey: 'workspaceBusinessSeatStripeProductId'
workspaceMonthlyBusinessSeatStripePriceId:
## @param server.billing.workspaceMonthlyBusinessSeatStripePriceId.secretKey The key within the Kubernetes Secret holding the workspaceMonthlyBusinessSeatStripePriceId secret as its value.
secretKey: 'workspaceMonthlyBusinessSeatStripePriceId'
workspaceYearlyBusinessSeatStripePriceId:
## @param server.billing.workspaceYearlyBusinessSeatStripePriceId.secretKey The key within the Kubernetes Secret holding the workspaceYearlyBusinessSeatStripePriceId secret as its value.
secretKey: 'workspaceYearlyBusinessSeatStripePriceId'
## @param server.billing.workspacePlusSeatStripeProductId The workspace Plus Seat Product Id as configured in Stripe.
workspacePlusSeatStripeProductId: ''
## @param server.billing.workspaceMonthlyPlusSeatStripePriceId The workspace Monthly Plus Seat Price Id as configured in Stripe.
workspaceMonthlyPlusSeatStripePriceId: ''
## @param server.billing.workspaceYearlyPlusSeatStripePriceId The workspace Yearly Plus Seat Price Id as configured in Stripe.
workspaceYearlyPlusSeatStripePriceId: ''
workspaceTeamSeatStripeProductId:
## @param server.billing.workspaceTeamSeatStripeProductId.secretKey The key within the Kubernetes Secret holding the workspaceTeamSeatStripeProductId secret as its value.
secretKey: 'workspaceTeamSeatStripeProductId'
workspaceMonthlyTeamSeatStripePriceId:
## @param server.billing.workspaceMonthlyTeamSeatStripePriceId.secretKey The key within the Kubernetes Secret holding the workspaceMonthlyTeamSeatStripePriceId secret as its value.
secretKey: 'workspaceMonthlyTeamSeatStripePriceId'
workspaceYearlyTeamSeatStripePriceId:
## @param server.billing.workspaceYearlyTeamSeatStripePriceId.secretKey The key within the Kubernetes Secret holding the workspaceYearlyTeamSeatStripePriceId secret as its value.
secretKey: 'workspaceYearlyTeamSeatStripePriceId'
## @param server.billing.workspaceBusinessSeatStripeProductId The workspace Business Seat Product Id as configured in Stripe.
workspaceBusinessSeatStripeProductId: ''
## @param server.billing.workspaceMonthlyBusinessSeatStripePriceId The workspace Monthly Business Seat Price Id as configured in Stripe.
workspaceMonthlyBusinessSeatStripePriceId: ''
## @param server.billing.workspaceYearlyBusinessSeatStripePriceId The workspace Yearly Business Seat Price Id as configured in Stripe.
workspaceYearlyBusinessSeatStripePriceId: ''
workspaceProSeatStripeProductId:
## @param server.billing.workspaceProSeatStripeProductId.secretKey The key within the Kubernetes Secret holding the workspaceProSeatStripeProductId secret as its value.
secretKey: 'workspaceProSeatStripeProductId'
workspaceMonthlyProSeatStripePriceId:
## @param server.billing.workspaceMonthlyProSeatStripePriceId.secretKey The key within the Kubernetes Secret holding the workspaceMonthlyProSeatStripePriceId secret as its value.
secretKey: 'workspaceMonthlyProSeatStripePriceId'
workspaceYearlyProSeatStripePriceId:
## @param server.billing.workspaceYearlyProSeatStripePriceId.secretKey The key within the Kubernetes Secret holding the workspaceYearlyProSeatStripePriceId secret as its value.
secretKey: 'workspaceYearlyProSeatStripePriceId'
## @param server.billing.workspaceTeamSeatStripeProductId The workspace Team Seat Product Id as configured in Stripe.
workspaceTeamSeatStripeProductId: ''
## @param server.billing.workspaceMonthlyTeamSeatStripePriceId The workspace Monthly Team Seat Price Id as configured in Stripe.
workspaceMonthlyTeamSeatStripePriceId: ''
## @param server.billing.workspaceYearlyTeamSeatStripePriceId The workspace Yearly Team Seat Price Id as configured in Stripe.
workspaceYearlyTeamSeatStripePriceId: ''
## @param server.billing.workspaceProSeatStripeProductId The workspace Pro Seat Product Id as configured in Stripe.
workspaceProSeatStripeProductId: ''
## @param server.billing.workspaceMonthlyProSeatStripePriceId The workspace Monthly Pro Seat Price Id as configured in Stripe.
workspaceMonthlyProSeatStripePriceId: ''
## @param server.billing.workspaceYearlyProSeatStripePriceId The workspace Yearly Pro Seat Price Id as configured in Stripe.
workspaceYearlyProSeatStripePriceId: ''
sessionSecret:
## @param server.sessionSecret.secretName The name of the Kubernetes Secret containing the Session secret. This is a unique value (can be generated randomly). This is expected to be provided within the Kubernetes cluster as an opaque Kubernetes Secret. Ref: https://kubernetes.io/docs/concepts/configuration/secret/#opaque-secrets
@@ -936,6 +925,9 @@ server:
## @descriptionEnd
##
objects:
## @param objects.enabled If enabled, the Speckle server will be deployed with the Objects component enabled.
##
enabled: true
## @param objects.replicas The number of instances of the Server pod to be deployed within the cluster.
##
replicas: 1
@@ -1109,14 +1101,19 @@ frontend_2:
## @descriptionEnd
##
preview_service:
## @param preview_service.deployInCluster If enabled, the Preview Service will be deployed within the cluster and speckle-server will be configured to send the kubernetes service url of the objects server to the Preview Service.
deployInCluster: true
## @param preview_service.enabled If enabled, the Preview Service will be deployed within the cluster and speckle-server will be configured to send the kubernetes service url of the objects server to the Preview Service.
enabled: true
## @param preview_service.dedicatedPreviewsQueue Allows using a dedicated redis url for the preview service job queue
##
dedicatedPreviewsQueue: false
## @param preview_service.replicas The number of instances of the Preview Service pod to be deployed within the cluster.
##
replicas: 1
deploymentStrategy:
## @param preview_service.deploymentStrategy.type The deployment strategy type to be used for the Preview Service. This can be set to either `Recreate` or `RollingUpdate`. The default is `Recreate` as preview service does not require 100% availability.
##
type: 'Recreate'
## @param preview_service.logLevel The minimum level of logs which will be output. Suitable values are trace, debug, info, warn, error, fatal, or silent
##
logLevel: 'info'
@@ -1162,6 +1159,28 @@ preview_service:
## ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
##
memory: 4Gi
autoscaling:
## @param preview_service.autoscaling.enabled
## @descriptionStart
## Enables the Horizontal Pod Autoscaler
## @descriptionEnd
enabled: false
## @param preview_service.autoscaling.minReplicas
## @descriptionStart
## Minimum number of replicas to scale down to
## @descriptionEnd
minReplicas: 1
## @param preview_service.autoscaling.maxReplicas
## @descriptionStart
## Maximum number of replicas to scale up to
## @descriptionEnd
maxReplicas: 10
## @param preview_service.autoscaling.targetCPUUtilizationPercentage
## @descriptionStart
## Target CPU utilization percentage
## @descriptionEnd
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80
networkPolicy:
## @param preview_service.networkPolicy.enabled If enabled, will provide additional security be limiting network traffic into and out of the pod to only the required endpoints and ports.
## If enabled, the `db.networkPolicy` parameters need be configured.
@@ -1198,9 +1217,15 @@ preview_service:
## @descriptionEnd
##
webhook_service:
## @param webhook_service.enabled If enabled, the Webhook Service will be deployed within the cluster.
enabled: true
## @param webhook_service.replicas The number of instances of the Webhook Service pod to be deployed within the cluster.
##
replicas: 1
deploymentStrategy:
## @param webhook_service.deploymentStrategy.type The deployment strategy type to be used for the Webhook Service. This can be set to either `Recreate` or `RollingUpdate`. The default is `Recreate` as webhook service does not require 100% availability.
##
type: 'Recreate'
## @param webhook_service.logLevel The minimum level of logs which will be output. Suitable values are trace, debug, info, warn, error, fatal, or silent
##
logLevel: 'info'
@@ -1271,9 +1296,15 @@ webhook_service:
## @descriptionEnd
##
fileimport_service:
## @param fileimport_service.enabled If enabled, the File Import Service will be deployed within the cluster.
enabled: true
## @param fileimport_service.replicas The number of instances of the FileImport Service pod to be deployed within the cluster.
##
replicas: 1
deploymentStrategy:
## @param fileimport_service.deploymentStrategy.type The deployment strategy type to be used for the FileImport Service. This can be set to either `Recreate` or `RollingUpdate`. The default is `Recreate` as file import service does not require 100% availability.
##
type: 'Recreate'
## @param fileimport_service.logLevel The minimum level of logs which will be output. Suitable values are trace, debug, info, warn, error, fatal, or silent
##
logLevel: 'info'
@@ -1359,6 +1390,8 @@ fileimport_service:
## @descriptionEnd
##
monitoring:
## @param monitoring.enabled If enabled, database monitoring will be deployed within the cluster.
enabled: true
## @param monitoring.replicas The number of instances of the Monitoring pod to be deployed within the cluster.
##
replicas: 1