Feat: Add mobile pricing plan (#3509)
This commit is contained in:
Родитель
5562d4115e
Коммит
a0fb2edc2b
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<section>
|
||||
<div class="md:mx-auto pb-6 md:pb-0">
|
||||
<div class="md:max-w-5xl md:mx-auto pb-6 md:pb-0">
|
||||
<SettingsSectionHeader title="Billing" text="Your workspace billing details" />
|
||||
<template v-if="isBillingIntegrationEnabled">
|
||||
<div class="flex flex-col gap-y-4 md:gap-y-6">
|
||||
|
@ -14,7 +14,7 @@
|
|||
<SettingsSectionHeader title="Billing summary" subheading class="pt-4" />
|
||||
<div class="border border-outline-3 rounded-lg">
|
||||
<div
|
||||
class="grid grid-cols-1 md:grid-cols-3 divide-y md:divide-y-0 md:divide-x"
|
||||
class="grid grid-cols-1 md:grid-cols-3 divide-y divide-outline-3 md:divide-y-0 md:divide-x"
|
||||
>
|
||||
<div class="p-5 pt-4 flex flex-col gap-y-1">
|
||||
<h3 class="text-body-xs text-foreground-2 pb-2">
|
||||
|
@ -89,6 +89,7 @@
|
|||
class="pt-6"
|
||||
:workspace-id="workspaceId"
|
||||
:current-plan="currentPlan"
|
||||
:is-admin="isAdmin"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -111,10 +112,12 @@ import {
|
|||
import { useBillingActions } from '~/lib/billing/composables/actions'
|
||||
import { pricingPlansConfig } from '~/lib/billing/helpers/constants'
|
||||
import { Roles } from '@speckle/shared'
|
||||
|
||||
graphql(`
|
||||
fragment SettingsWorkspacesBilling_Workspace on Workspace {
|
||||
...BillingAlert_Workspace
|
||||
id
|
||||
role
|
||||
plan {
|
||||
...SettingsWorkspacesBillingPricingTable_WorkspacePlan
|
||||
name
|
||||
|
@ -186,6 +189,9 @@ const nextPaymentDue = computed(() =>
|
|||
: 'Never'
|
||||
: dayjs().add(30, 'days').format('MMMM D, YYYY')
|
||||
)
|
||||
const isAdmin = computed(
|
||||
() => workspaceResult.value?.workspace.role === Roles.Workspace.Admin
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
const paymentStatusQuery = route.query?.payment_status
|
||||
|
|
|
@ -1,156 +0,0 @@
|
|||
<template>
|
||||
<div class="flex flex-col gap-y-6">
|
||||
<div class="flex justify-between">
|
||||
<SettingsSectionHeader
|
||||
:title="hasTrialPlan ? 'Start your subscription' : 'Upgrade your plan'"
|
||||
subheading
|
||||
/>
|
||||
<div class="flex items-center gap-x-4">
|
||||
<p class="text-foreground-3 text-body-xs">Save 20% with annual billing</p>
|
||||
<FormSwitch v-model="isYearlyPlan" :show-label="false" name="annual billing" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="w-full flex flex-col">
|
||||
<thead>
|
||||
<tr class="w-full flex">
|
||||
<th class="w-1/4 flex pl-5 pr-6 pt-4 pb-2 font-medium">
|
||||
<h4>Compare plans</h4>
|
||||
</th>
|
||||
<th
|
||||
v-for="plan in pricingPlans"
|
||||
:key="plan.name"
|
||||
class="w-1/4 flex flex-col gap-y-1 px-6 pt-4 pb-2 font-normal"
|
||||
:class="[
|
||||
plan.name === WorkspacePlans.Team
|
||||
? 'border border-b-0 border-outline-3 bg-foundation-2 rounded-t-lg'
|
||||
: ''
|
||||
]"
|
||||
scope="col"
|
||||
>
|
||||
<h4 class="text-foreground text-body-xs">
|
||||
Workspace
|
||||
<span class="capitalize">{{ plan.name }}</span>
|
||||
</h4>
|
||||
<p class="text-foreground text-heading font-normal">
|
||||
£{{
|
||||
isYearlyPlan
|
||||
? plan.cost.yearly[Roles.Workspace.Member]
|
||||
: plan.cost.monthly[Roles.Workspace.Member]
|
||||
}}
|
||||
per seat/month
|
||||
</p>
|
||||
<p class="text-foreground-2 text-body-2xs pt-1">
|
||||
Billed {{ isYearlyPlan ? 'annually' : 'monthly' }}
|
||||
</p>
|
||||
<FormButton
|
||||
:color="plan.name === WorkspacePlans.Team ? 'primary' : 'outline'"
|
||||
:disabled="!hasTrialPlan && !canUpgradeToPlan(plan.name)"
|
||||
class="mt-3"
|
||||
@click="onUpgradePlanClick(plan.name)"
|
||||
>
|
||||
{{ hasTrialPlan ? 'Subscribe' : 'Upgrade' }} to
|
||||
<span class="capitalize">{{ plan.name }}</span>
|
||||
</FormButton>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="w-full flex flex-col">
|
||||
<tr v-for="(feature, key, index) in features" :key="key" class="flex">
|
||||
<th
|
||||
class="font-normal text-foreground text-body-xs w-1/4 pr-3 pt-1"
|
||||
scope="row"
|
||||
>
|
||||
<div class="border-b border-outline-3 min-h-[42px] pl-5 flex items-center">
|
||||
{{ feature.name }}
|
||||
</div>
|
||||
</th>
|
||||
<td
|
||||
v-for="plan in pricingPlans"
|
||||
:key="plan.name"
|
||||
class="px-3 w-1/4 pt-1"
|
||||
:class="[
|
||||
plan.name === WorkspacePlans.Team
|
||||
? 'border-l border-r border-outline-3 bg-foundation-2'
|
||||
: '',
|
||||
plan.name === WorkspacePlans.Team &&
|
||||
index === Object.values(features).length - 1
|
||||
? 'pb-6 border-b rounded-b-lg'
|
||||
: ''
|
||||
]"
|
||||
>
|
||||
<div class="border-b border-outline-3 flex items-center px-3 min-h-[42px]">
|
||||
<CheckIcon
|
||||
v-if="plan.features.includes(feature.name)"
|
||||
class="w-3 h-3 text-foreground"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { SettingsWorkspacesBillingPricingTable_WorkspacePlanFragment } from '~/lib/common/generated/gql/graphql'
|
||||
import {
|
||||
WorkspacePlans,
|
||||
BillingInterval,
|
||||
WorkspacePlanStatuses
|
||||
} from '~/lib/common/generated/gql/graphql'
|
||||
import { pricingPlansConfig } from '~/lib/billing/helpers/constants'
|
||||
import { CheckIcon } from '@heroicons/vue/24/outline'
|
||||
import { useBillingActions } from '~/lib/billing/composables/actions'
|
||||
import { graphql } from '~/lib/common/generated/gql'
|
||||
import type { MaybeNullOrUndefined } from '@speckle/shared'
|
||||
import { Roles } from '@speckle/shared'
|
||||
|
||||
graphql(`
|
||||
fragment SettingsWorkspacesBillingPricingTable_WorkspacePlan on WorkspacePlan {
|
||||
name
|
||||
status
|
||||
}
|
||||
`)
|
||||
|
||||
const props = defineProps<{
|
||||
workspaceId: string
|
||||
currentPlan: MaybeNullOrUndefined<SettingsWorkspacesBillingPricingTable_WorkspacePlanFragment>
|
||||
}>()
|
||||
|
||||
const { upgradePlanRedirect } = useBillingActions()
|
||||
|
||||
const pricingPlans = ref([
|
||||
pricingPlansConfig.plans[WorkspacePlans.Team],
|
||||
pricingPlansConfig.plans[WorkspacePlans.Pro],
|
||||
pricingPlansConfig.plans[WorkspacePlans.Business]
|
||||
])
|
||||
const features = ref(pricingPlansConfig.features)
|
||||
const isYearlyPlan = ref(false)
|
||||
|
||||
const onUpgradePlanClick = (plan: WorkspacePlans) => {
|
||||
upgradePlanRedirect({
|
||||
plan,
|
||||
cycle: isYearlyPlan.value ? BillingInterval.Yearly : BillingInterval.Monthly,
|
||||
workspaceId: props.workspaceId
|
||||
})
|
||||
}
|
||||
|
||||
const hasTrialPlan = computed(
|
||||
() => props.currentPlan?.status === WorkspacePlanStatuses.Trial || !props.currentPlan
|
||||
)
|
||||
|
||||
const canUpgradeToPlan = (plan: WorkspacePlans) => {
|
||||
if (!props.currentPlan?.name) return false
|
||||
|
||||
const allowedUpgrades: Record<WorkspacePlans, WorkspacePlans[]> = {
|
||||
[WorkspacePlans.Team]: [WorkspacePlans.Pro, WorkspacePlans.Business],
|
||||
[WorkspacePlans.Pro]: [WorkspacePlans.Business],
|
||||
[WorkspacePlans.Business]: [],
|
||||
[WorkspacePlans.Academia]: [],
|
||||
[WorkspacePlans.Unlimited]: []
|
||||
}
|
||||
|
||||
return allowedUpgrades[props.currentPlan.name]?.includes(plan) ?? false
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,82 @@
|
|||
<template>
|
||||
<table class="w-full flex flex-col">
|
||||
<thead>
|
||||
<tr class="w-full flex">
|
||||
<th class="w-1/4 flex pl-5 pr-6 pt-4 pb-2 font-medium">
|
||||
<h4>Compare plans</h4>
|
||||
</th>
|
||||
<th
|
||||
v-for="plan in plans"
|
||||
:key="`desktop-${plan.name}`"
|
||||
class="w-1/4 px-6 pt-4 pb-2"
|
||||
:class="[
|
||||
plan.name === WorkspacePlans.Team
|
||||
? 'border border-b-0 border-outline-3 bg-foundation-2 rounded-t-lg'
|
||||
: ''
|
||||
]"
|
||||
scope="col"
|
||||
>
|
||||
<SettingsWorkspacesBillingPricingTableHeader
|
||||
:plan="plan"
|
||||
:is-yearly-plan="isYearlyPlan"
|
||||
:current-plan="currentPlan"
|
||||
:workspace-id="workspaceId"
|
||||
:is-admin="isAdmin"
|
||||
/>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="w-full flex flex-col">
|
||||
<tr v-for="(feature, key, index) in features" :key="key" class="flex">
|
||||
<th
|
||||
class="font-normal text-foreground text-body-xs w-1/4 pr-3 pt-1"
|
||||
scope="row"
|
||||
>
|
||||
<div class="border-b border-outline-3 min-h-[42px] pl-5 flex items-center">
|
||||
{{ feature.name }}
|
||||
</div>
|
||||
</th>
|
||||
<td
|
||||
v-for="plan in plans"
|
||||
:key="plan.name"
|
||||
class="px-3 w-1/4 pt-1"
|
||||
:class="[
|
||||
plan.name === WorkspacePlans.Team
|
||||
? 'border-l border-r border-outline-3 bg-foundation-2'
|
||||
: '',
|
||||
plan.name === WorkspacePlans.Team &&
|
||||
index === Object.values(features).length - 1
|
||||
? 'pb-6 border-b rounded-b-lg'
|
||||
: ''
|
||||
]"
|
||||
>
|
||||
<div class="border-b border-outline-3 flex items-center px-3 min-h-[42px]">
|
||||
<CheckIcon
|
||||
v-if="plan.features.includes(feature.name as PlanFeaturesList)"
|
||||
class="w-3 h-3 text-foreground"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { WorkspacePlan } from '~/lib/common/generated/gql/graphql'
|
||||
import { WorkspacePlans } from '~/lib/common/generated/gql/graphql'
|
||||
import { pricingPlansConfig } from '~/lib/billing/helpers/constants'
|
||||
import type { PlanFeaturesList } from '~/lib/billing/helpers/types'
|
||||
import { CheckIcon } from '@heroicons/vue/24/outline'
|
||||
import type { MaybeNullOrUndefined } from '@speckle/shared'
|
||||
|
||||
defineProps<{
|
||||
isYearlyPlan: boolean
|
||||
currentPlan: MaybeNullOrUndefined<WorkspacePlan>
|
||||
workspaceId: string
|
||||
isAdmin: boolean
|
||||
}>()
|
||||
|
||||
const plans = ref(pricingPlansConfig.plans)
|
||||
const features = ref(pricingPlansConfig.features)
|
||||
</script>
|
|
@ -0,0 +1,79 @@
|
|||
<template>
|
||||
<div class="flex flex-col gap-y-1 font-normal">
|
||||
<h4 class="text-foreground text-body-xs">
|
||||
Workspace
|
||||
<span class="capitalize">{{ plan.name }}</span>
|
||||
</h4>
|
||||
<p class="text-foreground text-heading">
|
||||
£{{
|
||||
isYearlyPlan
|
||||
? plan.cost.yearly[Roles.Workspace.Member]
|
||||
: plan.cost.monthly[Roles.Workspace.Member]
|
||||
}}
|
||||
per seat/month
|
||||
</p>
|
||||
<p class="text-foreground-2 text-body-2xs pt-1">
|
||||
Billed {{ isYearlyPlan ? 'annually' : 'monthly' }}
|
||||
</p>
|
||||
<div class="w-full">
|
||||
<FormButton
|
||||
:color="plan.name === WorkspacePlans.Team ? 'primary' : 'outline'"
|
||||
:disabled="(!hasTrialPlan && !canUpgradeToPlan) || !isAdmin"
|
||||
class="mt-3"
|
||||
full-width
|
||||
@click="onUpgradePlanClick(plan.name)"
|
||||
>
|
||||
{{ hasTrialPlan ? 'Subscribe' : 'Upgrade' }} to
|
||||
<span class="capitalize">{{ plan.name }}</span>
|
||||
</FormButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { type PricingPlan } from '@/lib/billing/helpers/types'
|
||||
import { Roles } from '@speckle/shared'
|
||||
import {
|
||||
type WorkspacePlan,
|
||||
WorkspacePlanStatuses,
|
||||
WorkspacePlans,
|
||||
BillingInterval
|
||||
} from '~/lib/common/generated/gql/graphql'
|
||||
import { useBillingActions } from '~/lib/billing/composables/actions'
|
||||
import type { MaybeNullOrUndefined } from '@speckle/shared'
|
||||
|
||||
const props = defineProps<{
|
||||
plan: PricingPlan
|
||||
isYearlyPlan: boolean
|
||||
currentPlan: MaybeNullOrUndefined<WorkspacePlan>
|
||||
workspaceId: string
|
||||
isAdmin: boolean
|
||||
}>()
|
||||
|
||||
const { upgradePlanRedirect } = useBillingActions()
|
||||
|
||||
const canUpgradeToPlan = computed(() => {
|
||||
if (!props.currentPlan) return false
|
||||
|
||||
const allowedUpgrades: Record<WorkspacePlans, WorkspacePlans[]> = {
|
||||
[WorkspacePlans.Team]: [WorkspacePlans.Pro, WorkspacePlans.Business],
|
||||
[WorkspacePlans.Pro]: [WorkspacePlans.Business],
|
||||
[WorkspacePlans.Business]: [],
|
||||
[WorkspacePlans.Academia]: [],
|
||||
[WorkspacePlans.Unlimited]: []
|
||||
}
|
||||
|
||||
return allowedUpgrades[props.currentPlan.name].includes(props.plan.name)
|
||||
})
|
||||
const hasTrialPlan = computed(
|
||||
() => props.currentPlan?.status === WorkspacePlanStatuses.Trial || !props.currentPlan
|
||||
)
|
||||
|
||||
const onUpgradePlanClick = (plan: WorkspacePlans) => {
|
||||
upgradePlanRedirect({
|
||||
plan,
|
||||
cycle: props.isYearlyPlan ? BillingInterval.Yearly : BillingInterval.Monthly,
|
||||
workspaceId: props.workspaceId
|
||||
})
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,48 @@
|
|||
<template>
|
||||
<div class="flex flex-col gap-y-4">
|
||||
<div
|
||||
v-for="plan in plans"
|
||||
:key="`mobile-${plan.name}`"
|
||||
class="border border-outline-3 bg-foundation rounded-lg p-4 pb-2"
|
||||
>
|
||||
<SettingsWorkspacesBillingPricingTableHeader
|
||||
:plan="plan"
|
||||
:is-yearly-plan="isYearlyPlan"
|
||||
:current-plan="currentPlan"
|
||||
:workspace-id="workspaceId"
|
||||
:is-admin="isAdmin"
|
||||
/>
|
||||
<ul class="flex flex-col gap-y-2 mt-6">
|
||||
<li
|
||||
v-for="feature in features"
|
||||
:key="feature.name"
|
||||
class="flex items-center justify-between border-b last:border-b-0 border-outline-3 pb-2"
|
||||
>
|
||||
{{ feature.name }}
|
||||
<CheckIcon
|
||||
v-if="plan.features.includes(feature.name as PlanFeaturesList)"
|
||||
class="w-3 h-3 text-foreground"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { WorkspacePlan } from '~/lib/common/generated/gql/graphql'
|
||||
import { pricingPlansConfig } from '~/lib/billing/helpers/constants'
|
||||
import type { PlanFeaturesList } from '~/lib/billing/helpers/types'
|
||||
import { CheckIcon } from '@heroicons/vue/24/outline'
|
||||
import type { MaybeNullOrUndefined } from '@speckle/shared'
|
||||
|
||||
defineProps<{
|
||||
isYearlyPlan: boolean
|
||||
currentPlan: MaybeNullOrUndefined<WorkspacePlan>
|
||||
workspaceId: string
|
||||
isAdmin: boolean
|
||||
}>()
|
||||
|
||||
const plans = ref(pricingPlansConfig.plans)
|
||||
const features = ref(pricingPlansConfig.features)
|
||||
</script>
|
|
@ -0,0 +1,60 @@
|
|||
<template>
|
||||
<div class="flex flex-col gap-y-6">
|
||||
<div class="flex flex-col lg:flex-row justify-between gap-y-4">
|
||||
<SettingsSectionHeader
|
||||
:title="hasTrialPlan ? 'Start your subscription' : 'Upgrade your plan'"
|
||||
subheading
|
||||
/>
|
||||
<div class="flex items-center gap-x-4">
|
||||
<p class="text-foreground-3 text-body-xs">Save 20% with annual billing</p>
|
||||
<FormSwitch v-model="isYearlyPlan" :show-label="false" name="annual billing" />
|
||||
</div>
|
||||
</div>
|
||||
<component
|
||||
:is="isDesktop ? DesktopTable : MobileTable"
|
||||
:workspace-id="workspaceId"
|
||||
:current-plan="currentPlan"
|
||||
:is-yearly-plan="isYearlyPlan"
|
||||
:is-admin="isAdmin"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useBreakpoints } from '@vueuse/core'
|
||||
import { TailwindBreakpoints } from '~~/lib/common/helpers/tailwind'
|
||||
import {
|
||||
WorkspacePlanStatuses,
|
||||
type WorkspacePlan
|
||||
} from '~/lib/common/generated/gql/graphql'
|
||||
import { graphql } from '~/lib/common/generated/gql'
|
||||
import type { MaybeNullOrUndefined } from '@speckle/shared'
|
||||
|
||||
graphql(`
|
||||
fragment SettingsWorkspacesBillingPricingTable_WorkspacePlan on WorkspacePlan {
|
||||
name
|
||||
status
|
||||
}
|
||||
`)
|
||||
|
||||
const props = defineProps<{
|
||||
workspaceId: string
|
||||
currentPlan: MaybeNullOrUndefined<WorkspacePlan>
|
||||
isAdmin: boolean
|
||||
}>()
|
||||
|
||||
const breakpoints = useBreakpoints(TailwindBreakpoints)
|
||||
|
||||
const DesktopTable = defineAsyncComponent(
|
||||
() => import('@/components/settings/workspaces/billing/PricingTable/Desktop.vue')
|
||||
)
|
||||
const MobileTable = defineAsyncComponent(
|
||||
() => import('@/components/settings/workspaces/billing/PricingTable/Mobile.vue')
|
||||
)
|
||||
const isDesktop = breakpoints.greaterOrEqual('lg')
|
||||
const isYearlyPlan = ref(false)
|
||||
|
||||
const hasTrialPlan = computed(
|
||||
() => props.currentPlan?.status === WorkspacePlanStatuses.Trial || !props.currentPlan
|
||||
)
|
||||
</script>
|
|
@ -1,16 +1,6 @@
|
|||
import { WorkspacePlans, BillingInterval } from '~/lib/common/generated/gql/graphql'
|
||||
import { Roles } from '@speckle/shared'
|
||||
|
||||
enum PlanFeaturesList {
|
||||
Workspaces = 'Workspaces',
|
||||
RoleManagement = 'Role management',
|
||||
GuestUsers = 'Guest users',
|
||||
PrivateAutomateFunctions = 'Private automate functions',
|
||||
DomainSecurity = 'Domain security',
|
||||
SSO = 'Single Sign-On (SSO)',
|
||||
CustomerDataRegion = 'Customer data region',
|
||||
PrioritySupport = 'Priority support'
|
||||
}
|
||||
import { PlanFeaturesList, type PricingPlan } from '@/lib/billing/helpers/types'
|
||||
|
||||
const baseFeatures = [
|
||||
PlanFeaturesList.Workspaces,
|
||||
|
@ -20,7 +10,13 @@ const baseFeatures = [
|
|||
PlanFeaturesList.DomainSecurity
|
||||
]
|
||||
|
||||
export const pricingPlansConfig = {
|
||||
export const pricingPlansConfig: {
|
||||
features: Record<PlanFeaturesList, { name: string; description: string }>
|
||||
plans: Record<
|
||||
WorkspacePlans.Team | WorkspacePlans.Pro | WorkspacePlans.Business,
|
||||
PricingPlan
|
||||
>
|
||||
} = {
|
||||
features: {
|
||||
[PlanFeaturesList.Workspaces]: {
|
||||
name: PlanFeaturesList.Workspaces,
|
||||
|
@ -46,8 +42,8 @@ export const pricingPlansConfig = {
|
|||
name: PlanFeaturesList.SSO,
|
||||
description: ''
|
||||
},
|
||||
[PlanFeaturesList.CustomerDataRegion]: {
|
||||
name: PlanFeaturesList.CustomerDataRegion,
|
||||
[PlanFeaturesList.CustomDataRegion]: {
|
||||
name: PlanFeaturesList.CustomDataRegion,
|
||||
description: ''
|
||||
},
|
||||
[PlanFeaturesList.PrioritySupport]: {
|
||||
|
@ -93,7 +89,7 @@ export const pricingPlansConfig = {
|
|||
features: [
|
||||
...baseFeatures,
|
||||
PlanFeaturesList.SSO,
|
||||
PlanFeaturesList.CustomerDataRegion,
|
||||
PlanFeaturesList.CustomDataRegion,
|
||||
PlanFeaturesList.PrioritySupport
|
||||
],
|
||||
cost: {
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import type {
|
||||
BillingInterval,
|
||||
WorkspacePlans
|
||||
} from '~/lib/common/generated/gql/graphql'
|
||||
import type { WorkspaceRoles } from '@speckle/shared'
|
||||
|
||||
export enum PlanFeaturesList {
|
||||
Workspaces = 'Workspaces',
|
||||
RoleManagement = 'Role management',
|
||||
GuestUsers = 'Guest users',
|
||||
PrivateAutomateFunctions = 'Private automate functions',
|
||||
DomainSecurity = 'Domain security',
|
||||
SSO = 'Single Sign-On (SSO)',
|
||||
CustomDataRegion = 'Custom data region',
|
||||
PrioritySupport = 'Priority support'
|
||||
}
|
||||
|
||||
export type PricingPlan = {
|
||||
name: WorkspacePlans
|
||||
features: PlanFeaturesList[]
|
||||
cost: {
|
||||
[I in BillingInterval]: Record<WorkspaceRoles, number>
|
||||
}
|
||||
}
|
|
@ -114,7 +114,7 @@ const documents = {
|
|||
"\n fragment SettingsUserProfileDeleteAccount_User on User {\n id\n email\n }\n": types.SettingsUserProfileDeleteAccount_UserFragmentDoc,
|
||||
"\n fragment SettingsUserProfileDetails_User on User {\n id\n name\n company\n ...UserProfileEditDialogAvatar_User\n }\n": types.SettingsUserProfileDetails_UserFragmentDoc,
|
||||
"\n fragment UserProfileEditDialogAvatar_User on User {\n id\n avatar\n ...ActiveUserAvatar\n }\n": types.UserProfileEditDialogAvatar_UserFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesBilling_Workspace on Workspace {\n ...BillingAlert_Workspace\n id\n plan {\n ...SettingsWorkspacesBillingPricingTable_WorkspacePlan\n name\n status\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n }\n }\n": types.SettingsWorkspacesBilling_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesBilling_Workspace on Workspace {\n ...BillingAlert_Workspace\n id\n role\n plan {\n ...SettingsWorkspacesBillingPricingTable_WorkspacePlan\n name\n status\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n }\n }\n": types.SettingsWorkspacesBilling_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesGeneral_Workspace on Workspace {\n ...SettingsWorkspacesGeneralEditAvatar_Workspace\n ...SettingsWorkspaceGeneralDeleteDialog_Workspace\n ...SettingsWorkspacesGeneralEditSlugDialog_Workspace\n id\n name\n slug\n description\n logo\n role\n defaultProjectRole\n }\n": types.SettingsWorkspacesGeneral_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspaceGeneralDeleteDialog_Workspace on Workspace {\n id\n name\n }\n": types.SettingsWorkspaceGeneralDeleteDialog_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesGeneralEditAvatar_Workspace on Workspace {\n id\n logo\n name\n defaultLogoIndex\n }\n": types.SettingsWorkspacesGeneralEditAvatar_WorkspaceFragmentDoc,
|
||||
|
@ -770,7 +770,7 @@ export function graphql(source: "\n fragment UserProfileEditDialogAvatar_User o
|
|||
/**
|
||||
* 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 SettingsWorkspacesBilling_Workspace on Workspace {\n ...BillingAlert_Workspace\n id\n plan {\n ...SettingsWorkspacesBillingPricingTable_WorkspacePlan\n name\n status\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesBilling_Workspace on Workspace {\n ...BillingAlert_Workspace\n id\n plan {\n ...SettingsWorkspacesBillingPricingTable_WorkspacePlan\n name\n status\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n }\n }\n"];
|
||||
export function graphql(source: "\n fragment SettingsWorkspacesBilling_Workspace on Workspace {\n ...BillingAlert_Workspace\n id\n role\n plan {\n ...SettingsWorkspacesBillingPricingTable_WorkspacePlan\n name\n status\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesBilling_Workspace on Workspace {\n ...BillingAlert_Workspace\n id\n role\n plan {\n ...SettingsWorkspacesBillingPricingTable_WorkspacePlan\n name\n status\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Загрузка…
Ссылка в новой задаче