Feat: Add cancel billing sessions, billing alerts, assume no plan is trial plan (#3467)
This commit is contained in:
Родитель
adeb529826
Коммит
423350eb64
|
@ -0,0 +1,102 @@
|
|||
<template>
|
||||
<CommonCard class="bg-foundation py-3 px-4">
|
||||
<div class="flex gap-x-2">
|
||||
<ExclamationCircleIcon v-if="showIcon" class="h-4 w-4 text-danger mt-1" />
|
||||
<div class="flex-1 flex gap-x-4 items-center">
|
||||
<div class="flex-1">
|
||||
<h5 class="text-body-xs font-medium text-foreground">{{ title }}</h5>
|
||||
<p class="text-body-xs text-foreground-2">{{ description }}</p>
|
||||
</div>
|
||||
<FormButton
|
||||
v-if="isPaymentFailed"
|
||||
:icon-right="ArrowTopRightOnSquareIcon"
|
||||
@click="billingPortalRedirect(workspace.id)"
|
||||
>
|
||||
Update payment information
|
||||
</FormButton>
|
||||
</div>
|
||||
</div>
|
||||
</CommonCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
ExclamationCircleIcon,
|
||||
ArrowTopRightOnSquareIcon
|
||||
} from '@heroicons/vue/24/outline'
|
||||
import { graphql } from '~/lib/common/generated/gql'
|
||||
import {
|
||||
type BillingAlert_WorkspaceFragment,
|
||||
WorkspacePlanStatuses,
|
||||
WorkspacePlans
|
||||
} from '~/lib/common/generated/gql/graphql'
|
||||
import { useBillingActions } from '~/lib/billing/composables/actions'
|
||||
|
||||
graphql(`
|
||||
fragment BillingAlert_Workspace on Workspace {
|
||||
id
|
||||
plan {
|
||||
name
|
||||
status
|
||||
}
|
||||
subscription {
|
||||
billingInterval
|
||||
currentBillingCycleEnd
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
const props = defineProps<{
|
||||
workspace: BillingAlert_WorkspaceFragment
|
||||
}>()
|
||||
|
||||
const { billingPortalRedirect } = useBillingActions()
|
||||
|
||||
const planStatus = computed(() => props.workspace.plan?.status)
|
||||
// If there is no plan status, we assume it's a trial
|
||||
const isTrial = computed(
|
||||
() => !planStatus.value || planStatus.value === WorkspacePlanStatuses.Trial
|
||||
)
|
||||
const isPaymentFailed = computed(
|
||||
() => planStatus.value === WorkspacePlanStatuses.PaymentFailed
|
||||
)
|
||||
const title = computed(() => {
|
||||
if (isTrial.value) {
|
||||
return `You are currently on a free ${
|
||||
props.workspace.plan?.name ?? WorkspacePlans.Team
|
||||
} plan trial`
|
||||
}
|
||||
switch (planStatus.value) {
|
||||
case WorkspacePlanStatuses.CancelationScheduled:
|
||||
return `Your ${props.workspace.plan?.name} plan subscription is scheduled for cancelation`
|
||||
case WorkspacePlanStatuses.Canceled:
|
||||
return `Your ${props.workspace.plan?.name} plan subscription has been canceled`
|
||||
case WorkspacePlanStatuses.Expired:
|
||||
return `Your free ${props.workspace.plan?.name} plan trial has ended`
|
||||
case WorkspacePlanStatuses.PaymentFailed:
|
||||
return "Your last payment didn't go through"
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
})
|
||||
const description = computed(() => {
|
||||
if (isTrial.value) {
|
||||
return 'Upgrade to a paid plan to start your subscription.'
|
||||
}
|
||||
switch (planStatus.value) {
|
||||
case WorkspacePlanStatuses.CancelationScheduled:
|
||||
return 'Your workspace subscription is scheduled for cancelation. After the cancelation, your workspace will be in read-only mode.'
|
||||
case WorkspacePlanStatuses.Canceled:
|
||||
return 'Your workspace has been canceled and is in read-only mode. Upgrade your plan to continue.'
|
||||
case WorkspacePlanStatuses.Expired:
|
||||
return "The workspace is in a read-only locked state until there's an active subscription. Upgrade your plan to continue."
|
||||
case WorkspacePlanStatuses.PaymentFailed:
|
||||
return "Update your payment information now to ensure your workspace doesn't go into maintenance mode."
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
})
|
||||
const showIcon = computed(() => {
|
||||
return !!planStatus.value && planStatus.value !== WorkspacePlanStatuses.Trial
|
||||
})
|
||||
</script>
|
|
@ -1,59 +0,0 @@
|
|||
<template>
|
||||
<ul>
|
||||
<li
|
||||
v-for="(item, index) in billingItems"
|
||||
:key="item.name"
|
||||
class="text-body-xs flex"
|
||||
:class="[index === billingItems.length - 1 ? 'border-b border-outline-3' : null]"
|
||||
>
|
||||
<p
|
||||
class="text-foreground flex-1 py-2 px-3"
|
||||
:class="[index < billingItems.length - 1 ? 'border-b border-outline-3' : null]"
|
||||
>
|
||||
{{ item.label }}
|
||||
<span class="text-foreground-2">x</span>
|
||||
£{{ item.cost }}
|
||||
</p>
|
||||
<p
|
||||
class="text-right text-foreground ml-4 w-32 md:w-40 py-2 px-3"
|
||||
:class="[index < billingItems.length - 1 ? 'border-b border-outline-3' : null]"
|
||||
>
|
||||
£{{ item.count * item.cost }} / month
|
||||
</p>
|
||||
</li>
|
||||
<li class="flex justify-between text-foreground font-medium">
|
||||
<p class="flex-1 p-3">Total</p>
|
||||
<p class="text-right w-32 md:w-40 ml-4 p-3">
|
||||
£{{ workspaceCost.subTotal }} / month
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { graphql } from '~/lib/common/generated/gql'
|
||||
import type { BillingSummary_WorkspaceCostFragment } from '~~/lib/common/generated/gql/graphql'
|
||||
|
||||
graphql(`
|
||||
fragment BillingSummary_WorkspaceCost on WorkspaceCost {
|
||||
items {
|
||||
cost
|
||||
count
|
||||
name
|
||||
label
|
||||
}
|
||||
discount {
|
||||
amount
|
||||
name
|
||||
}
|
||||
subTotal
|
||||
total
|
||||
}
|
||||
`)
|
||||
|
||||
const props = defineProps<{
|
||||
workspaceCost: BillingSummary_WorkspaceCostFragment
|
||||
}>()
|
||||
|
||||
const billingItems = computed(() => props.workspaceCost.items)
|
||||
</script>
|
|
@ -3,22 +3,28 @@
|
|||
<div class="md:max-w-4xl md:mx-auto pb-6 md:pb-0">
|
||||
<SettingsSectionHeader title="Billing" text="Your workspace billing details" />
|
||||
<template v-if="isBillingIntegrationEnabled">
|
||||
<BillingAlert
|
||||
v-if="workspaceResult && !isValidPlan"
|
||||
:workspace="workspaceResult.workspace"
|
||||
class="mb-4"
|
||||
/>
|
||||
<div class="flex flex-col gap-y-4 md:gap-y-6">
|
||||
<SettingsSectionHeader title="Billing summary" subheading class="pt-4" />
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-3">
|
||||
<CommonCard class="gap-y-1 bg-foundation">
|
||||
<p class="text-body-xs text-foreground-2 font-medium">
|
||||
<p class="text-body-xs text-foreground-2">
|
||||
{{ isTrialPeriod ? 'Trial plan' : 'Current plan' }}
|
||||
</p>
|
||||
<h4 class="text-heading-lg text-foreground capitalize">
|
||||
{{ currentPlan?.name }} plan
|
||||
{{ currentPlan?.name ?? WorkspacePlans.Team }} plan
|
||||
</h4>
|
||||
<p
|
||||
v-if="currentPlan?.name && subscription?.billingInterval"
|
||||
class="text-body-xs text-foreground-2"
|
||||
>
|
||||
<p class="text-body-xs text-foreground-2">
|
||||
£{{ seatPrice }} per seat/month, billed
|
||||
{{ subscription?.billingInterval }}
|
||||
{{
|
||||
subscription?.billingInterval === BillingInterval.Yearly
|
||||
? 'yearly'
|
||||
: 'monthly'
|
||||
}}
|
||||
</p>
|
||||
</CommonCard>
|
||||
<CommonCard class="gap-y-1 bg-foundation">
|
||||
|
@ -26,9 +32,9 @@
|
|||
{{
|
||||
isTrialPeriod
|
||||
? 'Expected bill'
|
||||
: subscription?.billingInterval === BillingInterval.Monthly
|
||||
? 'Monthly bill'
|
||||
: 'Yearly bill'
|
||||
: subscription?.billingInterval === BillingInterval.Yearly
|
||||
? 'Yearly bill'
|
||||
: 'Monthly bill'
|
||||
}}
|
||||
</p>
|
||||
<h4 class="text-heading-lg text-foreground capitalize">Coming soon</h4>
|
||||
|
@ -38,14 +44,16 @@
|
|||
{{ isTrialPeriod ? 'First payment due' : 'Next payment due' }}
|
||||
</p>
|
||||
<h4 class="text-heading-lg text-foreground capitalize">
|
||||
{{
|
||||
isPaidPlan
|
||||
? dayjs(subscription?.currentBillingCycleEnd).format('MMMM D, YYYY')
|
||||
: 'Never'
|
||||
}}
|
||||
{{ nextPaymentDue }}
|
||||
</h4>
|
||||
<p v-if="isPaidPlan" class="text-body-xs text-foreground-2">
|
||||
<span class="capitalize">{{ subscription?.billingInterval }}</span>
|
||||
<span class="capitalize">
|
||||
{{
|
||||
subscription?.billingInterval === BillingInterval.Yearly
|
||||
? 'Yearly'
|
||||
: 'Monthly'
|
||||
}}
|
||||
</span>
|
||||
billing period
|
||||
</p>
|
||||
</CommonCard>
|
||||
|
@ -60,7 +68,7 @@
|
|||
<FormButton
|
||||
color="outline"
|
||||
:icon-right="ArrowTopRightOnSquareIcon"
|
||||
@click="openCustomerPortal"
|
||||
@click="billingPortalRedirect(workspaceId)"
|
||||
>
|
||||
Open billing portal
|
||||
</FormButton>
|
||||
|
@ -110,11 +118,10 @@
|
|||
<script setup lang="ts">
|
||||
import dayjs from 'dayjs'
|
||||
import { graphql } from '~/lib/common/generated/gql'
|
||||
import { useQuery, useApolloClient } from '@vue/apollo-composable'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import {
|
||||
settingsWorkspaceBillingQuery,
|
||||
settingsWorkspacePricingPlansQuery,
|
||||
settingsWorkspaceBillingCustomerPortalQuery
|
||||
settingsWorkspacePricingPlansQuery
|
||||
} from '~/lib/settings/graphql/queries'
|
||||
import { useIsBillingIntegrationEnabled } from '~/composables/globals'
|
||||
import {
|
||||
|
@ -124,9 +131,13 @@ import {
|
|||
} from '~/lib/common/generated/gql/graphql'
|
||||
import { ArrowTopRightOnSquareIcon } from '@heroicons/vue/24/outline'
|
||||
import { isWorkspacePricingPlans } from '~/lib/settings/helpers/types'
|
||||
import { useBillingActions } from '~/lib/billing/composables/actions'
|
||||
import type { SeatPrices } from '~/lib/billing/helpers/types'
|
||||
import { seatPricesConfig } from '~/lib/billing/helpers/constants'
|
||||
|
||||
graphql(`
|
||||
fragment SettingsWorkspacesBilling_Workspace on Workspace {
|
||||
...BillingAlert_Workspace
|
||||
id
|
||||
plan {
|
||||
name
|
||||
|
@ -139,33 +150,33 @@ graphql(`
|
|||
}
|
||||
`)
|
||||
|
||||
type SeatPrices = {
|
||||
[key in WorkspacePlans]: {
|
||||
[BillingInterval.Monthly]: number
|
||||
[BillingInterval.Yearly]: number
|
||||
}
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
workspaceId: string
|
||||
}>()
|
||||
|
||||
const isBillingIntegrationEnabled = useIsBillingIntegrationEnabled()
|
||||
const isYearlyPlan = ref(false)
|
||||
// TODO: get these from the backend when available
|
||||
const seatPrices = ref<SeatPrices>({
|
||||
[WorkspacePlans.Team]: { monthly: 12, yearly: 10 },
|
||||
[WorkspacePlans.Pro]: { monthly: 40, yearly: 36 },
|
||||
[WorkspacePlans.Business]: { monthly: 79, yearly: 63 },
|
||||
[WorkspacePlans.Academia]: { monthly: 0, yearly: 0 },
|
||||
[WorkspacePlans.Unlimited]: { monthly: 0, yearly: 0 }
|
||||
})
|
||||
const seatPrices = ref<SeatPrices>(seatPricesConfig)
|
||||
|
||||
const { client: apollo } = useApolloClient()
|
||||
const { result: workspaceResult } = useQuery(settingsWorkspaceBillingQuery, () => ({
|
||||
workspaceId: props.workspaceId
|
||||
}))
|
||||
const { result: pricingPlansResult } = useQuery(settingsWorkspacePricingPlansQuery)
|
||||
const route = useRoute()
|
||||
const { result: workspaceResult } = useQuery(
|
||||
settingsWorkspaceBillingQuery,
|
||||
() => ({
|
||||
workspaceId: props.workspaceId
|
||||
}),
|
||||
() => ({
|
||||
enabled: isBillingIntegrationEnabled
|
||||
})
|
||||
)
|
||||
const { result: pricingPlansResult } = useQuery(
|
||||
settingsWorkspacePricingPlansQuery,
|
||||
null,
|
||||
() => ({
|
||||
enabled: isBillingIntegrationEnabled
|
||||
})
|
||||
)
|
||||
const { billingPortalRedirect, upgradePlanRedirect, cancelCheckoutSession } =
|
||||
useBillingActions()
|
||||
|
||||
const currentPlan = computed(() => workspaceResult.value?.workspace.plan)
|
||||
const subscription = computed(() => workspaceResult.value?.workspace.subscription)
|
||||
|
@ -175,39 +186,50 @@ const isPaidPlan = computed(
|
|||
currentPlan.value?.name !== WorkspacePlans.Unlimited
|
||||
)
|
||||
const isTrialPeriod = computed(
|
||||
() => currentPlan.value?.status === WorkspacePlanStatuses.Trial
|
||||
() =>
|
||||
currentPlan.value?.status === WorkspacePlanStatuses.Trial ||
|
||||
!currentPlan.value?.status
|
||||
)
|
||||
const isActivePlan = computed(
|
||||
() =>
|
||||
currentPlan.value &&
|
||||
currentPlan.value?.status !== WorkspacePlanStatuses.Trial &&
|
||||
currentPlan.value?.status !== WorkspacePlanStatuses.Canceled
|
||||
)
|
||||
const isValidPlan = computed(
|
||||
() => currentPlan.value?.status === WorkspacePlanStatuses.Valid
|
||||
)
|
||||
const seatPrice = computed(() =>
|
||||
currentPlan.value && subscription.value
|
||||
? seatPrices.value[currentPlan.value?.name][subscription.value?.billingInterval]
|
||||
: 0
|
||||
: seatPrices.value[WorkspacePlans.Team][BillingInterval.Monthly]
|
||||
)
|
||||
const pricingPlans = computed(() =>
|
||||
isWorkspacePricingPlans(pricingPlansResult.value)
|
||||
? pricingPlansResult.value?.workspacePricingPlans.workspacePlanInformation
|
||||
: undefined
|
||||
)
|
||||
|
||||
const nextPaymentDue = computed(() =>
|
||||
currentPlan.value
|
||||
? isPaidPlan.value
|
||||
? dayjs(subscription.value?.currentBillingCycleEnd).format('MMMM D, YYYY')
|
||||
: 'Never'
|
||||
: dayjs().add(30, 'days').format('MMMM D, YYYY')
|
||||
)
|
||||
const onUpgradePlanClick = (plan: WorkspacePlans) => {
|
||||
const cycle = isYearlyPlan.value ? BillingInterval.Yearly : BillingInterval.Monthly
|
||||
window.location.href = `/api/v1/billing/workspaces/${props.workspaceId}/checkout-session/${plan}/${cycle}`
|
||||
}
|
||||
|
||||
const openCustomerPortal = async () => {
|
||||
// We need to fetch this on click because the link expires very quickly
|
||||
const result = await apollo.query({
|
||||
query: settingsWorkspaceBillingCustomerPortalQuery,
|
||||
variables: { workspaceId: props.workspaceId },
|
||||
fetchPolicy: 'no-cache'
|
||||
upgradePlanRedirect({
|
||||
plan,
|
||||
cycle: isYearlyPlan.value ? BillingInterval.Yearly : BillingInterval.Monthly,
|
||||
workspaceId: props.workspaceId
|
||||
})
|
||||
|
||||
if (result.data?.workspace.customerPortalUrl) {
|
||||
window.location.href = result.data.workspace.customerPortalUrl
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const paymentStatusQuery = route.query?.payment_status
|
||||
const sessionIdQuery = route.query?.session_id
|
||||
|
||||
if (sessionIdQuery && String(paymentStatusQuery) === WorkspacePlanStatuses.Canceled) {
|
||||
cancelCheckoutSession(String(sessionIdQuery), props.workspaceId)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
:separator="false"
|
||||
/>
|
||||
</Portal>
|
||||
<BillingAlert
|
||||
v-if="initialQueryResult && !hasValidPlan"
|
||||
:workspace="initialQueryResult.workspaceBySlug"
|
||||
class="mb-4"
|
||||
/>
|
||||
<WorkspaceHeader
|
||||
v-if="workspace"
|
||||
:icon="Squares2X2Icon"
|
||||
|
@ -127,6 +132,7 @@ import {
|
|||
SettingMenuKeys,
|
||||
type AvailableSettingsMenuKeys
|
||||
} from '~/lib/settings/helpers/types'
|
||||
import { WorkspacePlanStatuses } from '~/lib/common/generated/gql/graphql'
|
||||
|
||||
graphql(`
|
||||
fragment WorkspaceProjectList_ProjectCollection on ProjectCollection {
|
||||
|
@ -205,6 +211,9 @@ const { query, identifier, onInfiniteLoad } = usePaginatedQuery({
|
|||
const projects = computed(() => query.result.value?.workspaceBySlug?.projects)
|
||||
const workspaceInvite = computed(() => initialQueryResult.value?.workspaceInvite)
|
||||
const workspace = computed(() => initialQueryResult.value?.workspaceBySlug)
|
||||
const hasValidPlan = computed(
|
||||
() => workspace.value?.plan?.status === WorkspacePlanStatuses.Valid
|
||||
)
|
||||
const isWorkspaceGuest = computed(() => workspace.value?.role === Roles.Workspace.Guest)
|
||||
const isWorkspaceAdmin = computed(() => workspace.value?.role === Roles.Workspace.Admin)
|
||||
const showEmptyState = computed(() => {
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import { useApolloClient, useMutation } from '@vue/apollo-composable'
|
||||
import { settingsWorkspaceBillingCustomerPortalQuery } from '~/lib/settings/graphql/queries'
|
||||
import type {
|
||||
WorkspacePlans,
|
||||
BillingInterval
|
||||
} from '~/lib/common/generated/gql/graphql'
|
||||
import { settingsBillingCancelCheckoutSessionMutation } from '~/lib/settings/graphql/mutations'
|
||||
|
||||
export const useBillingActions = () => {
|
||||
const { client: apollo } = useApolloClient()
|
||||
const { mutate: cancelCheckoutSessionMutation } = useMutation(
|
||||
settingsBillingCancelCheckoutSessionMutation
|
||||
)
|
||||
|
||||
const billingPortalRedirect = async (workspaceId: string) => {
|
||||
// We need to fetch this on click because the link expires very quickly
|
||||
const result = await apollo.query({
|
||||
query: settingsWorkspaceBillingCustomerPortalQuery,
|
||||
variables: { workspaceId },
|
||||
fetchPolicy: 'no-cache'
|
||||
})
|
||||
|
||||
if (result.data?.workspace.customerPortalUrl) {
|
||||
window.location.href = result.data.workspace.customerPortalUrl
|
||||
}
|
||||
}
|
||||
|
||||
const upgradePlanRedirect = (args: {
|
||||
plan: WorkspacePlans
|
||||
cycle: BillingInterval
|
||||
workspaceId: string
|
||||
}) => {
|
||||
const { plan, cycle, workspaceId } = args
|
||||
window.location.href = `/api/v1/billing/workspaces/${workspaceId}/checkout-session/${plan}/${cycle}`
|
||||
}
|
||||
|
||||
const cancelCheckoutSession = async (sessionId: string, workspaceId: string) => {
|
||||
await cancelCheckoutSessionMutation({
|
||||
input: { sessionId, workspaceId }
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
billingPortalRedirect,
|
||||
upgradePlanRedirect,
|
||||
cancelCheckoutSession
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import { WorkspacePlans, BillingInterval } from '~/lib/common/generated/gql/graphql'
|
||||
import type { SeatPrices } from '~/lib/billing/helpers/types'
|
||||
|
||||
// TODO: get these from the backend when available
|
||||
export const seatPricesConfig: SeatPrices = {
|
||||
[WorkspacePlans.Team]: {
|
||||
[BillingInterval.Monthly]: 12,
|
||||
[BillingInterval.Yearly]: 10
|
||||
},
|
||||
[WorkspacePlans.Pro]: {
|
||||
[BillingInterval.Monthly]: 40,
|
||||
[BillingInterval.Yearly]: 36
|
||||
},
|
||||
[WorkspacePlans.Business]: {
|
||||
[BillingInterval.Monthly]: 79,
|
||||
[BillingInterval.Yearly]: 63
|
||||
},
|
||||
[WorkspacePlans.Academia]: {
|
||||
[BillingInterval.Monthly]: 0,
|
||||
[BillingInterval.Yearly]: 0
|
||||
},
|
||||
[WorkspacePlans.Unlimited]: {
|
||||
[BillingInterval.Monthly]: 0,
|
||||
[BillingInterval.Yearly]: 0
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import type {
|
||||
WorkspacePlans,
|
||||
BillingInterval
|
||||
} from '~/lib/common/generated/gql/graphql'
|
||||
|
||||
export type SeatPrices = {
|
||||
[key in WorkspacePlans]: {
|
||||
[BillingInterval.Monthly]: number
|
||||
[BillingInterval.Yearly]: number
|
||||
}
|
||||
}
|
|
@ -40,7 +40,7 @@ const documents = {
|
|||
"\n fragment AutomateRunsTriggerStatusDialogRunsRows_AutomateRun on AutomateRun {\n id\n functionRuns {\n id\n ...AutomateRunsTriggerStatusDialogFunctionRun_AutomateFunctionRun\n }\n ...AutomationsStatusOrderedRuns_AutomationRun\n }\n": types.AutomateRunsTriggerStatusDialogRunsRows_AutomateRunFragmentDoc,
|
||||
"\n fragment AutomateViewerPanel_AutomateRun on AutomateRun {\n id\n functionRuns {\n id\n ...AutomateViewerPanelFunctionRunRow_AutomateFunctionRun\n }\n ...AutomationsStatusOrderedRuns_AutomationRun\n }\n": types.AutomateViewerPanel_AutomateRunFragmentDoc,
|
||||
"\n fragment AutomateViewerPanelFunctionRunRow_AutomateFunctionRun on AutomateFunctionRun {\n id\n results\n status\n statusMessage\n contextView\n function {\n id\n logo\n name\n }\n createdAt\n updatedAt\n }\n": types.AutomateViewerPanelFunctionRunRow_AutomateFunctionRunFragmentDoc,
|
||||
"\n fragment BillingSummary_WorkspaceCost on WorkspaceCost {\n items {\n cost\n count\n name\n label\n }\n discount {\n amount\n name\n }\n subTotal\n total\n }\n": types.BillingSummary_WorkspaceCostFragmentDoc,
|
||||
"\n fragment BillingAlert_Workspace on Workspace {\n id\n plan {\n name\n status\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n }\n }\n": types.BillingAlert_WorkspaceFragmentDoc,
|
||||
"\n fragment CommonModelSelectorModel on Model {\n id\n name\n }\n": types.CommonModelSelectorModelFragmentDoc,
|
||||
"\n fragment DashboardProjectCard_Project on Project {\n id\n name\n role\n updatedAt\n models {\n totalCount\n }\n team {\n user {\n ...LimitedUserAvatar\n }\n }\n workspace {\n id\n slug\n name\n ...WorkspaceAvatar_Workspace\n }\n }\n": types.DashboardProjectCard_ProjectFragmentDoc,
|
||||
"\n fragment FormSelectModels_Model on Model {\n id\n name\n }\n": types.FormSelectModels_ModelFragmentDoc,
|
||||
|
@ -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 id\n plan {\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 plan {\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,
|
||||
|
@ -288,6 +288,7 @@ const documents = {
|
|||
"\n mutation AddWorkspaceDomain($input: AddDomainToWorkspaceInput!) {\n workspaceMutations {\n addDomain(input: $input) {\n ...SettingsWorkspacesSecurity_Workspace\n }\n }\n }\n": types.AddWorkspaceDomainDocument,
|
||||
"\n mutation DeleteWorkspaceDomain($input: WorkspaceDomainDeleteInput!) {\n workspaceMutations {\n deleteDomain(input: $input) {\n ...SettingsWorkspacesSecurityDomainRemoveDialog_Workspace\n }\n }\n }\n": types.DeleteWorkspaceDomainDocument,
|
||||
"\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 ...SettingsDialog_User\n }\n }\n": types.SettingsSidebarDocument,
|
||||
"\n query SettingsWorkspaceGeneral($id: String!) {\n workspace(id: $id) {\n ...SettingsWorkspacesGeneral_Workspace\n }\n }\n": types.SettingsWorkspaceGeneralDocument,
|
||||
"\n query SettingsWorkspaceBilling($workspaceId: String!) {\n workspace(id: $workspaceId) {\n id\n ...SettingsWorkspacesBilling_Workspace\n }\n }\n": types.SettingsWorkspaceBillingDocument,
|
||||
|
@ -333,7 +334,7 @@ const documents = {
|
|||
"\n mutation ProcessWorkspaceInvite($input: WorkspaceInviteUseInput!) {\n workspaceMutations {\n invites {\n use(input: $input)\n }\n }\n }\n": types.ProcessWorkspaceInviteDocument,
|
||||
"\n mutation SetDefaultWorkspaceRegion($workspaceId: String!, $regionKey: String!) {\n workspaceMutations {\n setDefaultRegion(workspaceId: $workspaceId, regionKey: $regionKey) {\n id\n defaultRegion {\n id\n ...SettingsWorkspacesRegionsSelect_ServerRegionItem\n }\n }\n }\n }\n": types.SetDefaultWorkspaceRegionDocument,
|
||||
"\n query WorkspaceAccessCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n id\n }\n }\n": types.WorkspaceAccessCheckDocument,
|
||||
"\n query WorkspacePageQuery(\n $workspaceSlug: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $token: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n id\n ...MoveProjectsDialog_Workspace\n ...WorkspaceHeader_Workspace\n ...WorkspaceMixpanelUpdateGroup_Workspace\n projectListProject: projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n workspaceInvite(\n workspaceId: $workspaceSlug\n token: $token\n options: { useSlug: true }\n ) {\n id\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n": types.WorkspacePageQueryDocument,
|
||||
"\n query WorkspacePageQuery(\n $workspaceSlug: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $token: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n id\n ...MoveProjectsDialog_Workspace\n ...WorkspaceHeader_Workspace\n ...WorkspaceMixpanelUpdateGroup_Workspace\n ...BillingAlert_Workspace\n projectListProject: projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n workspaceInvite(\n workspaceId: $workspaceSlug\n token: $token\n options: { useSlug: true }\n ) {\n id\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n": types.WorkspacePageQueryDocument,
|
||||
"\n query WorkspaceProjectsQuery(\n $workspaceSlug: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n id\n projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n }\n": types.WorkspaceProjectsQueryDocument,
|
||||
"\n query WorkspaceInvite(\n $workspaceId: String\n $token: String\n $options: WorkspaceInviteLookupOptions\n ) {\n workspaceInvite(workspaceId: $workspaceId, token: $token, options: $options) {\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n": types.WorkspaceInviteDocument,
|
||||
"\n query MoveProjectsDialog {\n activeUser {\n ...MoveProjectsDialog_User\n }\n }\n": types.MoveProjectsDialogDocument,
|
||||
|
@ -473,7 +474,7 @@ export function graphql(source: "\n fragment AutomateViewerPanelFunctionRunRow_
|
|||
/**
|
||||
* 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 BillingSummary_WorkspaceCost on WorkspaceCost {\n items {\n cost\n count\n name\n label\n }\n discount {\n amount\n name\n }\n subTotal\n total\n }\n"): (typeof documents)["\n fragment BillingSummary_WorkspaceCost on WorkspaceCost {\n items {\n cost\n count\n name\n label\n }\n discount {\n amount\n name\n }\n subTotal\n total\n }\n"];
|
||||
export function graphql(source: "\n fragment BillingAlert_Workspace on Workspace {\n id\n plan {\n name\n status\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n }\n }\n"): (typeof documents)["\n fragment BillingAlert_Workspace on Workspace {\n id\n plan {\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.
|
||||
*/
|
||||
|
@ -769,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 id\n plan {\n name\n status\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesBilling_Workspace on Workspace {\n id\n plan {\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 plan {\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 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.
|
||||
*/
|
||||
|
@ -1462,6 +1463,10 @@ export function graphql(source: "\n mutation DeleteWorkspaceDomain($input: Work
|
|||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n mutation SettingsLeaveWorkspace($leaveId: ID!) {\n workspaceMutations {\n leave(id: $leaveId)\n }\n }\n"): (typeof documents)["\n mutation SettingsLeaveWorkspace($leaveId: ID!) {\n workspaceMutations {\n leave(id: $leaveId)\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 mutation SettingsBillingCancelCheckoutSession($input: CancelCheckoutSessionInput!) {\n workspaceMutations {\n billing {\n cancelCheckoutSession(input: $input)\n }\n }\n }\n"): (typeof documents)["\n mutation SettingsBillingCancelCheckoutSession($input: CancelCheckoutSessionInput!) {\n workspaceMutations {\n billing {\n cancelCheckoutSession(input: $input)\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
|
@ -1645,7 +1650,7 @@ export function graphql(source: "\n query WorkspaceAccessCheck($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 WorkspacePageQuery(\n $workspaceSlug: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $token: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n id\n ...MoveProjectsDialog_Workspace\n ...WorkspaceHeader_Workspace\n ...WorkspaceMixpanelUpdateGroup_Workspace\n projectListProject: projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n workspaceInvite(\n workspaceId: $workspaceSlug\n token: $token\n options: { useSlug: true }\n ) {\n id\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n"): (typeof documents)["\n query WorkspacePageQuery(\n $workspaceSlug: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $token: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n id\n ...MoveProjectsDialog_Workspace\n ...WorkspaceHeader_Workspace\n ...WorkspaceMixpanelUpdateGroup_Workspace\n projectListProject: projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n workspaceInvite(\n workspaceId: $workspaceSlug\n token: $token\n options: { useSlug: true }\n ) {\n id\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n"];
|
||||
export function graphql(source: "\n query WorkspacePageQuery(\n $workspaceSlug: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $token: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n id\n ...MoveProjectsDialog_Workspace\n ...WorkspaceHeader_Workspace\n ...WorkspaceMixpanelUpdateGroup_Workspace\n ...BillingAlert_Workspace\n projectListProject: projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n workspaceInvite(\n workspaceId: $workspaceSlug\n token: $token\n options: { useSlug: true }\n ) {\n id\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n"): (typeof documents)["\n query WorkspacePageQuery(\n $workspaceSlug: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $token: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n id\n ...MoveProjectsDialog_Workspace\n ...WorkspaceHeader_Workspace\n ...WorkspaceMixpanelUpdateGroup_Workspace\n ...BillingAlert_Workspace\n projectListProject: projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n workspaceInvite(\n workspaceId: $workspaceSlug\n token: $token\n options: { useSlug: true }\n ) {\n id\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -117,6 +117,7 @@ export const settingsDeleteWorkspaceDomainMutation = graphql(`
|
|||
}
|
||||
}
|
||||
`)
|
||||
|
||||
export const settingsLeaveWorkspaceMutation = graphql(`
|
||||
mutation SettingsLeaveWorkspace($leaveId: ID!) {
|
||||
workspaceMutations {
|
||||
|
@ -124,3 +125,13 @@ export const settingsLeaveWorkspaceMutation = graphql(`
|
|||
}
|
||||
}
|
||||
`)
|
||||
|
||||
export const settingsBillingCancelCheckoutSessionMutation = graphql(`
|
||||
mutation SettingsBillingCancelCheckoutSession($input: CancelCheckoutSessionInput!) {
|
||||
workspaceMutations {
|
||||
billing {
|
||||
cancelCheckoutSession(input: $input)
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
|
|
@ -21,6 +21,7 @@ export const workspacePageQuery = graphql(`
|
|||
...MoveProjectsDialog_Workspace
|
||||
...WorkspaceHeader_Workspace
|
||||
...WorkspaceMixpanelUpdateGroup_Workspace
|
||||
...BillingAlert_Workspace
|
||||
projectListProject: projects(filter: $filter, cursor: $cursor, limit: 10) {
|
||||
...WorkspaceProjectList_ProjectCollection
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче