This commit is contained in:
Stephen Zhou 2026-05-07 17:43:32 +08:00
parent f5a262817d
commit b70c9d7835
No known key found for this signature in database
9 changed files with 422 additions and 439 deletions

View File

@ -7,7 +7,7 @@ import { cn } from '@langgenius/dify-ui/cn'
import { Dialog, DialogCloseButton, DialogContent, DialogDescription, DialogTitle } from '@langgenius/dify-ui/dialog'
import { Popover, PopoverContent, PopoverTrigger } from '@langgenius/dify-ui/popover'
import { toast } from '@langgenius/dify-ui/toast'
import { useQuery } from '@tanstack/react-query'
import { useMutation, useQuery } from '@tanstack/react-query'
import { useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { AppTypeIcon } from '@/app/components/app/type-selector'
@ -15,7 +15,6 @@ import AppIcon from '@/app/components/base/app-icon'
import Input from '@/app/components/base/input'
import { useRouter } from '@/next/navigation'
import { consoleQuery } from '@/service/client'
import { useCreateDeploymentInstance } from '../hooks/use-deployment-mutations'
import { useDeploymentsStore } from '../store'
const MAX_STUDIO_SOURCE_APPS = 100
@ -208,7 +207,7 @@ export const AppPicker: FC<AppPickerProps> = ({ apps, isLoading, value, onChange
const CreateInstanceForm: FC<{ onClose: () => void }> = ({ onClose }) => {
const { t } = useTranslation('deployments')
const router = useRouter()
const createInstance = useCreateDeploymentInstance()
const createInstance = useMutation(consoleQuery.enterprise.appDeploy.createAppInstance.mutationOptions())
const { data: appList, isLoading } = useQuery(consoleQuery.apps.list.queryOptions({
input: {
query: {
@ -225,31 +224,30 @@ const CreateInstanceForm: FC<{ onClose: () => void }> = ({ onClose }) => {
const [appId, setAppId] = useState<string>('')
const [name, setName] = useState('')
const [description, setDescription] = useState('')
const [isSubmitting, setIsSubmitting] = useState(false)
const selectedApp = apps.find(a => a.id === appId)
const canCreate = Boolean(appId && name.trim() && !isSubmitting)
const canCreate = Boolean(appId && name.trim() && !createInstance.isPending)
const handleCreate = async () => {
if (!canCreate)
return
setIsSubmitting(true)
try {
const result = await createInstance.mutateAsync({
sourceAppId: appId,
name: name.trim(),
description: description.trim() || undefined,
body: {
sourceAppId: appId,
name: name.trim(),
description: description.trim() || undefined,
},
})
if (!result.appInstanceId)
throw new Error('Create app instance did not return an appInstanceId.')
onClose()
router.push(`/deployments/${result.appInstanceId}/overview`)
}
catch {
toast.error(t('createModal.createFailed'))
}
finally {
setIsSubmitting(false)
}
}
return (

View File

@ -3,12 +3,11 @@
import type { FC } from 'react'
import { Dialog, DialogCloseButton, DialogContent } from '@langgenius/dify-ui/dialog'
import { toast } from '@langgenius/dify-ui/toast'
import { skipToken, useQuery } from '@tanstack/react-query'
import { skipToken, useMutation, useQuery } from '@tanstack/react-query'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { consoleQuery } from '@/service/client'
import { DEPLOYMENT_PAGE_SIZE } from '../data'
import { useStartDeployment } from '../hooks/use-deployment-mutations'
import { useDeploymentsStore } from '../store'
import { environmentOptionsFromOptionsReply } from '../utils'
import { DeployForm } from './deploy-drawer/form'
@ -18,7 +17,7 @@ const DeployDrawer: FC = () => {
const drawer = useDeploymentsStore(state => state.deployDrawer)
const drawerAppInstanceId = drawer.appInstanceId
const closeDeployDrawer = useDeploymentsStore(state => state.closeDeployDrawer)
const startDeploy = useStartDeployment()
const startDeploy = useMutation(consoleQuery.enterprise.appDeploy.createDeployment.mutationOptions())
const open = drawer.open
const { data: releaseHistory } = useQuery(consoleQuery.enterprise.appDeploy.listReleases.queryOptions({
input: drawerAppInstanceId
@ -75,10 +74,14 @@ const DeployDrawer: FC = () => {
onSubmit={async ({ environmentId, releaseId, bindings }) => {
try {
await startDeploy.mutateAsync({
appInstanceId: drawerAppInstanceId,
environmentId,
releaseId,
bindings,
params: {
appInstanceId: drawerAppInstanceId,
},
body: {
environmentId,
releaseId,
bindings,
},
})
closeDeployDrawer()
}

View File

@ -9,12 +9,11 @@ import {
AlertDialogDescription,
AlertDialogTitle,
} from '@langgenius/dify-ui/alert-dialog'
import { skipToken, useQuery } from '@tanstack/react-query'
import { skipToken, useMutation, useQuery } from '@tanstack/react-query'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { consoleQuery } from '@/service/client'
import { DEPLOYMENT_PAGE_SIZE } from '../data'
import { useStartDeployment } from '../hooks/use-deployment-mutations'
import { useDeploymentsStore } from '../store'
import {
activeRelease,
@ -40,7 +39,7 @@ const RollbackModal: FC = () => {
const { t } = useTranslation('deployments')
const modal = useDeploymentsStore(state => state.rollbackModal)
const closeRollbackModal = useDeploymentsStore(state => state.closeRollbackModal)
const rollbackDeployment = useStartDeployment()
const rollbackDeployment = useMutation(consoleQuery.enterprise.appDeploy.createDeployment.mutationOptions())
const appInput = modal.appInstanceId
? { params: { appInstanceId: modal.appInstanceId } }
: skipToken
@ -87,10 +86,14 @@ const RollbackModal: FC = () => {
return
closeRollbackModal()
rollbackDeployment.mutate({
appInstanceId: modal.appInstanceId,
environmentId: modal.environmentId,
releaseId: modal.targetReleaseId,
bindings: [],
params: {
appInstanceId: modal.appInstanceId,
},
body: {
environmentId: modal.environmentId,
releaseId: modal.targetReleaseId,
bindings: [],
},
})
}

View File

@ -6,16 +6,9 @@ import type {
AccessSubject,
ConsoleEnvironmentSummary,
} from '@/features/deployments/types'
import { useQuery } from '@tanstack/react-query'
import { useMutation, useQuery } from '@tanstack/react-query'
import { useMemo, useState } from 'react'
import { consoleClient, consoleQuery } from '@/service/client'
import {
useGenerateDeploymentApiKey,
useRevokeDeploymentApiKey,
useSetEnvironmentAccessPolicy,
useToggleDeploymentAccessChannel,
useToggleDeploymentDeveloperAPI,
} from '../hooks/use-deployment-mutations'
import {
deployedRows,
} from '../utils'
@ -50,11 +43,11 @@ const AccessTab: FC<AccessTabProps> = ({ instanceId: appId }) => {
appId: string
token: string
}>()
const generateApiKey = useGenerateDeploymentApiKey()
const revokeApiKey = useRevokeDeploymentApiKey()
const toggleAccessChannel = useToggleDeploymentAccessChannel()
const toggleDeveloperAPI = useToggleDeploymentDeveloperAPI()
const setEnvironmentAccessPolicy = useSetEnvironmentAccessPolicy()
const generateApiKey = useMutation(consoleQuery.enterprise.appDeploy.createDeveloperApiKey.mutationOptions())
const revokeApiKey = useMutation(consoleQuery.enterprise.appDeploy.deleteDeveloperApiKey.mutationOptions())
const toggleAccessChannel = useMutation(consoleQuery.enterprise.appDeploy.updateAccessChannels.mutationOptions())
const toggleDeveloperAPI = useMutation(consoleQuery.enterprise.appDeploy.updateDeveloperApi.mutationOptions())
const setEnvironmentAccessPolicy = useMutation(consoleQuery.enterprise.appDeploy.updateEnvironmentAccessPolicy.mutationOptions())
const deploymentRows = useMemo(
() => deployedRows(environmentDeployments?.data),

View File

@ -8,11 +8,10 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from '@langgenius/dify-ui/dropdown-menu'
import { useQuery } from '@tanstack/react-query'
import { useMutation, useQuery } from '@tanstack/react-query'
import { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { consoleQuery } from '@/service/client'
import { useUndeployDeployment } from '../hooks/use-deployment-mutations'
import { useDeploymentsStore } from '../store'
import {
activeRelease,
@ -46,7 +45,8 @@ const DeployTab: FC<DeployTabProps> = ({ instanceId: appInstanceId }) => {
}))
const { data: environmentOptionsReply } = useQuery(consoleQuery.enterprise.appDeploy.listDeploymentEnvironmentOptions.queryOptions())
const openDeployDrawer = useDeploymentsStore(state => state.openDeployDrawer)
const undeployDeployment = useUndeployDeployment()
const cancelDeployment = useMutation(consoleQuery.enterprise.appDeploy.cancelRuntimeDeployment.mutationOptions())
const undeployDeployment = useMutation(consoleQuery.enterprise.appDeploy.undeployRuntimeInstance.mutationOptions())
const environmentOptions = useMemo(
() => environmentOptionsFromOptionsReply(environmentOptionsReply),
[environmentOptionsReply],
@ -193,11 +193,33 @@ const DeployTab: FC<DeployTabProps> = ({ instanceId: appInstanceId }) => {
<DropdownMenuContent placement="bottom-end" sideOffset={4} popupClassName="w-[200px]">
<DropdownMenuItem
className="gap-2 px-3"
onClick={() => undeployDeployment.mutate({
appInstanceId,
runtimeInstanceId: deploymentId(row),
isDeploying: status === 'deploying',
})}
onClick={() => {
const runtimeInstanceId = deploymentId(row)
if (status === 'deploying') {
cancelDeployment.mutate({
params: {
appInstanceId,
runtimeInstanceId,
},
body: {
appInstanceId,
runtimeInstanceId,
},
})
return
}
undeployDeployment.mutate({
params: {
appInstanceId,
runtimeInstanceId,
},
body: {
appInstanceId,
runtimeInstanceId,
},
})
}}
>
<span className="system-sm-regular text-text-destructive">
{status === 'deploying' ? t('deployTab.cancelDeployment') : t('deployTab.undeploy')}

View File

@ -13,15 +13,11 @@ import {
} from '@langgenius/dify-ui/alert-dialog'
import { Button } from '@langgenius/dify-ui/button'
import { toast } from '@langgenius/dify-ui/toast'
import { useQuery } from '@tanstack/react-query'
import { useMutation, useQuery } from '@tanstack/react-query'
import { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useRouter } from '@/next/navigation'
import { consoleQuery } from '@/service/client'
import {
useDeleteDeploymentInstance,
useUpdateDeploymentInstance,
} from '../hooks/use-deployment-mutations'
import {
deployedRows,
toAppInfoFromOverview,
@ -181,8 +177,8 @@ const SettingsForm: FC<SettingsFormProps> = ({ app, settings, hasDeployments, on
const SettingsTab: FC<SettingsTabProps> = ({ instanceId }) => {
const router = useRouter()
const updateInstance = useUpdateDeploymentInstance()
const deleteInstance = useDeleteDeploymentInstance()
const updateInstance = useMutation(consoleQuery.enterprise.appDeploy.updateAppInstance.mutationOptions())
const deleteInstance = useMutation(consoleQuery.enterprise.appDeploy.deleteAppInstance.mutationOptions())
const appInput = { params: { appInstanceId: instanceId } }
const { data: overview } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceOverview.queryOptions({
input: appInput,

View File

@ -5,14 +5,13 @@ import { cn } from '@langgenius/dify-ui/cn'
import { Dialog, DialogCloseButton, DialogContent, DialogDescription, DialogTitle } from '@langgenius/dify-ui/dialog'
import { toast } from '@langgenius/dify-ui/toast'
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import { useQuery } from '@tanstack/react-query'
import { useMutation, useQuery } from '@tanstack/react-query'
import { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Input from '@/app/components/base/input'
import Textarea from '@/app/components/base/textarea'
import { consoleQuery } from '@/service/client'
import { DEPLOYMENT_PAGE_SIZE } from '../data'
import { useCreateDeploymentRelease } from '../hooks/use-deployment-mutations'
import {
deployedRows,
formatDate,
@ -47,7 +46,7 @@ const VersionsTab: FC<VersionsTabProps> = ({ instanceId: appId }) => {
const { data: environmentDeployments } = useQuery(consoleQuery.enterprise.appDeploy.listRuntimeInstances.queryOptions({
input,
}))
const createRelease = useCreateDeploymentRelease()
const createRelease = useMutation(consoleQuery.enterprise.appDeploy.createRelease.mutationOptions())
const [isCreating, setIsCreating] = useState(false)
const [releaseName, setReleaseName] = useState('')
const [releaseDescription, setReleaseDescription] = useState('')
@ -68,11 +67,17 @@ const VersionsTab: FC<VersionsTabProps> = ({ instanceId: appId }) => {
return
try {
await createRelease.mutateAsync({
appInstanceId: appId,
name: trimmedReleaseName,
description: releaseDescription.trim() || undefined,
const response = await createRelease.mutateAsync({
params: {
appInstanceId: appId,
},
body: {
name: trimmedReleaseName,
description: releaseDescription.trim() || undefined,
},
})
if (!response.release?.id)
throw new Error('Create release did not return a release.')
setReleaseName('')
setReleaseDescription('')
setIsCreating(false)

View File

@ -1,376 +0,0 @@
'use client'
import type { DeploymentRuntimeBinding } from '@dify/contracts/enterprise/types.gen'
import type { QueryClient, QueryKey } from '@tanstack/react-query'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { consoleClient, consoleQuery } from '@/service/client'
import { SOURCE_APPS_PAGE_SIZE } from '../data'
export type CreateDeploymentInstanceResult = {
appInstanceId: string
}
type CreateDeploymentParams = {
appInstanceId: string
environmentId: string
releaseId: string
bindings: DeploymentRuntimeBinding[]
}
type CreateReleaseParams = {
appInstanceId: string
name: string
description?: string
}
type CreateInstanceParams = {
sourceAppId: string
name: string
description?: string
}
type UndeployDeploymentParams = {
appInstanceId: string
runtimeInstanceId: string
isDeploying?: boolean
}
const DEPLOYMENT_READINESS_RETRY_DELAYS = [0, 300, 700, 1200]
const wait = (delay: number) => new Promise(resolve => setTimeout(resolve, delay))
const invalidateQueries = async (queryClient: QueryClient, queryKeys: readonly QueryKey[]): Promise<void> => {
await Promise.all(queryKeys.map(queryKey => queryClient.invalidateQueries({ queryKey })))
}
const removeQueries = (queryClient: QueryClient, queryKeys: readonly QueryKey[]): void => {
queryKeys.forEach(queryKey => queryClient.removeQueries({ queryKey }))
}
const invalidateInstanceList = (queryClient: QueryClient): Promise<void> => {
return queryClient.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.listAppInstances.key({ type: 'query' }),
})
}
const invalidateInstanceIdentity = (queryClient: QueryClient, appInstanceId: string): Promise<void> => {
return invalidateQueries(queryClient, [
consoleQuery.enterprise.appDeploy.listAppInstances.key({ type: 'query' }),
consoleQuery.enterprise.appDeploy.getAppInstanceOverview.key({
type: 'query',
input: { params: { appInstanceId } },
}),
consoleQuery.enterprise.appDeploy.getAppInstanceSettings.key({
type: 'query',
input: { params: { appInstanceId } },
}),
])
}
const invalidateDeploymentState = (queryClient: QueryClient, appInstanceId: string): Promise<void> => {
return invalidateQueries(queryClient, [
consoleQuery.enterprise.appDeploy.listAppInstances.key({ type: 'query' }),
consoleQuery.enterprise.appDeploy.getAppInstanceOverview.key({
type: 'query',
input: { params: { appInstanceId } },
}),
consoleQuery.enterprise.appDeploy.listRuntimeInstances.key({
type: 'query',
input: { params: { appInstanceId } },
}),
consoleQuery.enterprise.appDeploy.listReleases.key({
type: 'query',
input: { params: { appInstanceId } },
}),
consoleQuery.enterprise.appDeploy.getAppInstanceAccess.key({
type: 'query',
input: { params: { appInstanceId } },
}),
])
}
const invalidateAccessState = (queryClient: QueryClient, appInstanceId: string): Promise<void> => {
return invalidateQueries(queryClient, [
consoleQuery.enterprise.appDeploy.getAppInstanceOverview.key({
type: 'query',
input: { params: { appInstanceId } },
}),
consoleQuery.enterprise.appDeploy.getAppInstanceAccess.key({
type: 'query',
input: { params: { appInstanceId } },
}),
])
}
const invalidateEnvironmentAccessPolicy = (
queryClient: QueryClient,
appInstanceId: string,
environmentId: string,
): Promise<void> => {
return invalidateQueries(queryClient, [
consoleQuery.enterprise.appDeploy.getAppInstanceAccess.key({
type: 'query',
input: { params: { appInstanceId } },
}),
consoleQuery.enterprise.appDeploy.getEnvironmentAccessPolicy.key({
type: 'query',
input: {
params: {
appInstanceId,
environmentId,
},
},
}),
])
}
const removeDeletedInstanceState = (queryClient: QueryClient, appInstanceId: string): Promise<void> => {
removeQueries(queryClient, [
consoleQuery.enterprise.appDeploy.getAppInstanceOverview.key({
type: 'query',
input: { params: { appInstanceId } },
}),
consoleQuery.enterprise.appDeploy.getAppInstanceSettings.key({
type: 'query',
input: { params: { appInstanceId } },
}),
consoleQuery.enterprise.appDeploy.listRuntimeInstances.key({
type: 'query',
input: { params: { appInstanceId } },
}),
consoleQuery.enterprise.appDeploy.listReleases.key({
type: 'query',
input: { params: { appInstanceId } },
}),
consoleQuery.enterprise.appDeploy.getAppInstanceAccess.key({
type: 'query',
input: { params: { appInstanceId } },
}),
consoleQuery.enterprise.appDeploy.getEnvironmentAccessPolicy.key({
type: 'query',
input: { params: { appInstanceId } },
}),
])
return invalidateInstanceList(queryClient)
}
export const useCreateDeploymentInstance = () => {
const queryClient = useQueryClient()
return useMutation({
mutationKey: consoleQuery.enterprise.appDeploy.createAppInstance.mutationKey(),
mutationFn: async (params: CreateInstanceParams): Promise<CreateDeploymentInstanceResult> => {
const response = await consoleClient.enterprise.appDeploy.createAppInstance({
body: {
sourceAppId: params.sourceAppId,
name: params.name,
description: params.description,
},
})
if (!response.appInstanceId)
throw new Error('Create app instance did not return an appInstanceId.')
for (const delay of DEPLOYMENT_READINESS_RETRY_DELAYS) {
if (delay > 0)
await wait(delay)
const listResponse = await queryClient
.fetchQuery(consoleQuery.enterprise.appDeploy.listAppInstances.queryOptions({
input: {
query: {
pageNumber: 1,
resultsPerPage: SOURCE_APPS_PAGE_SIZE,
},
},
}))
.catch(() => undefined)
if (listResponse?.data?.some(app => app.id === response.appInstanceId))
break
}
return {
appInstanceId: response.appInstanceId,
}
},
onSuccess: () => {
return invalidateInstanceList(queryClient)
},
})
}
export const useCreateDeploymentRelease = () => {
const queryClient = useQueryClient()
return useMutation({
mutationKey: consoleQuery.enterprise.appDeploy.createRelease.mutationKey(),
mutationFn: async ({ appInstanceId, name, description }: CreateReleaseParams) => {
const response = await consoleClient.enterprise.appDeploy.createRelease({
params: {
appInstanceId,
},
body: {
name,
description,
},
})
if (!response.release?.id)
throw new Error('Create release did not return a release.')
return response.release
},
onSuccess: (_data, variables) => {
return invalidateQueries(queryClient, [
consoleQuery.enterprise.appDeploy.listReleases.key({
type: 'query',
input: { params: { appInstanceId: variables.appInstanceId } },
}),
consoleQuery.enterprise.appDeploy.getAppInstanceOverview.key({
type: 'query',
input: { params: { appInstanceId: variables.appInstanceId } },
}),
])
},
})
}
export const useUpdateDeploymentInstance = () => {
const queryClient = useQueryClient()
return useMutation(consoleQuery.enterprise.appDeploy.updateAppInstance.mutationOptions({
onSuccess: (_data, variables) => {
return invalidateInstanceIdentity(queryClient, variables.params.appInstanceId)
},
}))
}
export const useDeleteDeploymentInstance = () => {
const queryClient = useQueryClient()
return useMutation(consoleQuery.enterprise.appDeploy.deleteAppInstance.mutationOptions({
onSuccess: (_data, variables) => {
return removeDeletedInstanceState(queryClient, variables.params.appInstanceId)
},
}))
}
export const useStartDeployment = () => {
const queryClient = useQueryClient()
return useMutation({
mutationKey: consoleQuery.enterprise.appDeploy.createDeployment.mutationKey(),
mutationFn: async ({
appInstanceId,
environmentId,
releaseId,
bindings,
}: CreateDeploymentParams) => {
if (!releaseId)
throw new Error('releaseId is required to start a deployment.')
return consoleClient.enterprise.appDeploy.createDeployment({
params: {
appInstanceId,
},
body: {
environmentId,
releaseId,
bindings,
},
})
},
onSuccess: (_data, variables) => {
return invalidateDeploymentState(queryClient, variables.appInstanceId)
},
})
}
export const useUndeployDeployment = () => {
const queryClient = useQueryClient()
return useMutation({
mutationKey: consoleQuery.enterprise.appDeploy.undeployRuntimeInstance.mutationKey(),
mutationFn: ({ appInstanceId, runtimeInstanceId, isDeploying }: UndeployDeploymentParams) => {
if (!runtimeInstanceId)
throw new Error('runtimeInstanceId is required to undeploy a deployment.')
if (isDeploying) {
return consoleClient.enterprise.appDeploy.cancelRuntimeDeployment({
params: {
appInstanceId,
runtimeInstanceId,
},
body: {
appInstanceId,
runtimeInstanceId,
},
})
}
return consoleClient.enterprise.appDeploy.undeployRuntimeInstance({
params: {
appInstanceId,
runtimeInstanceId,
},
body: {
appInstanceId,
runtimeInstanceId,
},
})
},
onSuccess: (_data, variables) => {
return invalidateDeploymentState(queryClient, variables.appInstanceId)
},
})
}
export const useGenerateDeploymentApiKey = () => {
const queryClient = useQueryClient()
return useMutation(consoleQuery.enterprise.appDeploy.createDeveloperApiKey.mutationOptions({
onSuccess: (_data, variables) => {
return invalidateAccessState(queryClient, variables.params.appInstanceId)
},
}))
}
export const useRevokeDeploymentApiKey = () => {
const queryClient = useQueryClient()
return useMutation(consoleQuery.enterprise.appDeploy.deleteDeveloperApiKey.mutationOptions({
onSuccess: (_data, variables) => {
return invalidateAccessState(queryClient, variables.params.appInstanceId)
},
}))
}
export const useToggleDeploymentAccessChannel = () => {
const queryClient = useQueryClient()
return useMutation(consoleQuery.enterprise.appDeploy.updateAccessChannels.mutationOptions({
onSuccess: (_data, variables) => {
return invalidateAccessState(queryClient, variables.params.appInstanceId)
},
}))
}
export const useToggleDeploymentDeveloperAPI = () => {
const queryClient = useQueryClient()
return useMutation(consoleQuery.enterprise.appDeploy.updateDeveloperApi.mutationOptions({
onSuccess: (_data, variables) => {
return invalidateAccessState(queryClient, variables.params.appInstanceId)
},
}))
}
export const useSetEnvironmentAccessPolicy = () => {
const queryClient = useQueryClient()
return useMutation(consoleQuery.enterprise.appDeploy.updateEnvironmentAccessPolicy.mutationOptions({
onSuccess: (_data, variables) => {
return invalidateEnvironmentAccessPolicy(
queryClient,
variables.params.appInstanceId,
variables.params.environmentId,
)
},
}))
}

View File

@ -1,5 +1,6 @@
import type { ContractRouterClient } from '@orpc/contract'
import type { JsonifiedClient } from '@orpc/openapi-client'
import type { RouterUtils } from '@orpc/tanstack-query'
import { createORPCClient, onError } from '@orpc/client'
import { OpenAPILink } from '@orpc/openapi-client/fetch'
import { createTanstackQueryUtils } from '@orpc/tanstack-query'
@ -64,6 +65,9 @@ const marketplaceLink = new OpenAPILink(marketplaceRouterContract, {
export const marketplaceClient: JsonifiedClient<ContractRouterClient<typeof marketplaceRouterContract>> = createORPCClient(marketplaceLink)
export const marketplaceQuery = createTanstackQueryUtils(marketplaceClient, { path: ['marketplace'] })
const APP_DEPLOY_SOURCE_APPS_PAGE_SIZE = 100
const APP_DEPLOY_READINESS_RETRY_DELAYS = [0, 300, 700, 1200]
const consoleLink = new OpenAPILink(consoleRouterContract, {
url: getBaseURL(API_PREFIX),
fetch: (input, init) => {
@ -84,7 +88,342 @@ const consoleLink = new OpenAPILink(consoleRouterContract, {
})
export const consoleClient: JsonifiedClient<ContractRouterClient<typeof consoleRouterContract>> = createORPCClient(consoleLink)
export const consoleQuery = createTanstackQueryUtils(consoleClient, {
export const consoleQuery: RouterUtils<typeof consoleClient> = createTanstackQueryUtils(consoleClient, {
path: ['console'],
experimental_defaults: { },
experimental_defaults: {
enterprise: {
appDeploy: {
createAppInstance: {
mutationOptions: {
onSuccess: async (data, _variables, _result, context) => {
if (data.appInstanceId) {
for (const delay of APP_DEPLOY_READINESS_RETRY_DELAYS) {
if (delay > 0)
await new Promise(resolve => setTimeout(resolve, delay))
const listResponse = await context.client
.fetchQuery(consoleQuery.enterprise.appDeploy.listAppInstances.queryOptions({
input: {
query: {
pageNumber: 1,
resultsPerPage: APP_DEPLOY_SOURCE_APPS_PAGE_SIZE,
},
},
}))
.catch(() => undefined)
if (listResponse?.data?.some(app => app.id === data.appInstanceId))
break
}
}
await context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.listAppInstances.key({ type: 'query' }),
})
},
},
},
updateAppInstance: {
mutationOptions: {
onSuccess: (_data, variables, _result, context) => {
const appInstanceId = variables.params.appInstanceId
return Promise.all([
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.listAppInstances.key({ type: 'query' }),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceOverview.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceSettings.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
])
},
},
},
deleteAppInstance: {
mutationOptions: {
onSuccess: (_data, variables, _result, context) => {
const appInstanceId = variables.params.appInstanceId
;[
consoleQuery.enterprise.appDeploy.getAppInstanceOverview.key({
type: 'query',
input: { params: { appInstanceId } },
}),
consoleQuery.enterprise.appDeploy.getAppInstanceSettings.key({
type: 'query',
input: { params: { appInstanceId } },
}),
consoleQuery.enterprise.appDeploy.listRuntimeInstances.key({
type: 'query',
input: { params: { appInstanceId } },
}),
consoleQuery.enterprise.appDeploy.listReleases.key({
type: 'query',
input: { params: { appInstanceId } },
}),
consoleQuery.enterprise.appDeploy.getAppInstanceAccess.key({
type: 'query',
input: { params: { appInstanceId } },
}),
consoleQuery.enterprise.appDeploy.getEnvironmentAccessPolicy.key({
type: 'query',
input: { params: { appInstanceId } },
}),
].forEach(queryKey => context.client.removeQueries({ queryKey }))
return context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.listAppInstances.key({ type: 'query' }),
})
},
},
},
createRelease: {
mutationOptions: {
onSuccess: (_data, variables, _result, context) => {
const appInstanceId = variables.params.appInstanceId
return Promise.all([
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.listReleases.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceOverview.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
])
},
},
},
createDeployment: {
mutationOptions: {
onSuccess: (_data, variables, _result, context) => {
const appInstanceId = variables.params.appInstanceId
return Promise.all([
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.listAppInstances.key({ type: 'query' }),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceOverview.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.listRuntimeInstances.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.listReleases.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceAccess.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
])
},
},
},
cancelRuntimeDeployment: {
mutationOptions: {
onSuccess: (_data, variables, _result, context) => {
const appInstanceId = variables.params.appInstanceId
return Promise.all([
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.listAppInstances.key({ type: 'query' }),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceOverview.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.listRuntimeInstances.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.listReleases.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceAccess.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
])
},
},
},
undeployRuntimeInstance: {
mutationOptions: {
onSuccess: (_data, variables, _result, context) => {
const appInstanceId = variables.params.appInstanceId
return Promise.all([
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.listAppInstances.key({ type: 'query' }),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceOverview.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.listRuntimeInstances.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.listReleases.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceAccess.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
])
},
},
},
createDeveloperApiKey: {
mutationOptions: {
onSuccess: (_data, variables, _result, context) => {
const appInstanceId = variables.params.appInstanceId
return Promise.all([
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceOverview.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceAccess.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
])
},
},
},
deleteDeveloperApiKey: {
mutationOptions: {
onSuccess: (_data, variables, _result, context) => {
const appInstanceId = variables.params.appInstanceId
return Promise.all([
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceOverview.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceAccess.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
])
},
},
},
updateAccessChannels: {
mutationOptions: {
onSuccess: (_data, variables, _result, context) => {
const appInstanceId = variables.params.appInstanceId
return Promise.all([
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceOverview.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceAccess.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
])
},
},
},
updateDeveloperApi: {
mutationOptions: {
onSuccess: (_data, variables, _result, context) => {
const appInstanceId = variables.params.appInstanceId
return Promise.all([
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceOverview.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceAccess.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
])
},
},
},
updateEnvironmentAccessPolicy: {
mutationOptions: {
onSuccess: (_data, variables, _result, context) => {
const { appInstanceId, environmentId } = variables.params
return Promise.all([
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getAppInstanceAccess.key({
type: 'query',
input: { params: { appInstanceId } },
}),
}),
context.client.invalidateQueries({
queryKey: consoleQuery.enterprise.appDeploy.getEnvironmentAccessPolicy.key({
type: 'query',
input: {
params: {
appInstanceId,
environmentId,
},
},
}),
}),
])
},
},
},
},
},
},
})