This commit is contained in:
Stephen Zhou 2026-04-30 14:33:55 +08:00
parent 53f224a2c5
commit 63c0921936
No known key found for this signature in database
7 changed files with 162 additions and 189 deletions

View File

@ -2,14 +2,12 @@
import type { FC } from 'react'
import { Dialog, DialogCloseButton, DialogContent } from '@langgenius/dify-ui/dialog'
import { skipToken, useQuery } from '@tanstack/react-query'
import { 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 { deploymentReleaseHistoryQueryOptions } from '../queries'
import { useDeploymentsStore } from '../store'
import { environmentOptionsFromOptionsReply } from '../utils'
import { DeployForm } from './deploy-drawer/form'
@ -21,18 +19,10 @@ const DeployDrawer: FC = () => {
const closeDeployDrawer = useDeploymentsStore(state => state.closeDeployDrawer)
const startDeploy = useStartDeployment()
const open = drawer.open
const { data: releaseHistory } = useQuery(consoleQuery.deployments.releaseHistory.queryOptions({
input: drawerAppId
? {
params: { appInstanceId: drawerAppId },
query: {
pageNumber: 1,
resultsPerPage: DEPLOYMENT_PAGE_SIZE,
},
}
: skipToken,
const { data: releaseHistory } = useQuery({
...deploymentReleaseHistoryQueryOptions(drawerAppId),
enabled: open && Boolean(drawerAppId),
}))
})
const { data: environmentOptionsReply } = useQuery({
...consoleQuery.deployments.deploymentEnvironmentOptions.queryOptions(),
enabled: open,

View File

@ -9,17 +9,15 @@ import {
AlertDialogDescription,
AlertDialogTitle,
} from '@langgenius/dify-ui/alert-dialog'
import { skipToken, useQuery } from '@tanstack/react-query'
import { 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 {
deploymentEnvironmentDeploymentsQueryOptions,
deploymentOverviewQueryOptions,
deploymentReleaseHistoryQueryOptions,
} from '../queries'
import { useDeploymentsStore } from '../store'
import {
@ -47,18 +45,6 @@ const RollbackModal: FC = () => {
const modal = useDeploymentsStore(state => state.rollbackModal)
const closeRollbackModal = useDeploymentsStore(state => state.closeRollbackModal)
const rollbackDeployment = useStartDeployment()
const appInput = modal.appId
? { params: { appInstanceId: modal.appId } }
: undefined
const pagedInput = appInput
? {
...appInput,
query: {
pageNumber: 1,
resultsPerPage: DEPLOYMENT_PAGE_SIZE,
},
}
: undefined
const { data: overview } = useQuery({
...deploymentOverviewQueryOptions(modal.appId),
enabled: modal.open && Boolean(modal.appId),
@ -71,10 +57,10 @@ const RollbackModal: FC = () => {
...consoleQuery.deployments.deploymentEnvironmentOptions.queryOptions(),
enabled: modal.open,
})
const { data: releaseHistory } = useQuery(consoleQuery.deployments.releaseHistory.queryOptions({
input: pagedInput ?? skipToken,
const { data: releaseHistory } = useQuery({
...deploymentReleaseHistoryQueryOptions(modal.appId),
enabled: modal.open && Boolean(modal.appId),
}))
})
const environmentOptions = useMemo(
() => environmentOptionsFromOptionsReply(environmentOptionsReply),
[environmentOptionsReply],

View File

@ -78,7 +78,15 @@ const AccessTab: FC<AccessTabProps> = ({ instanceId: appId }) => {
}
const handleGenerateApiKey = (environmentId: string) => {
generateApiKey.mutate(
{ appId, environmentId, name: createApiKeyLabel(environmentId) },
{
params: {
appInstanceId: appId,
},
body: {
environmentId,
name: createApiKeyLabel(environmentId),
},
},
{
onSuccess: (response) => {
if (response.apiToken?.token)
@ -87,8 +95,13 @@ const AccessTab: FC<AccessTabProps> = ({ instanceId: appId }) => {
},
)
}
const handleRevokeApiKey = (environmentId: string, apiKeyId: string) => {
revokeApiKey.mutate({ appId, environmentId, apiKeyId })
const handleRevokeApiKey = (_environmentId: string, apiKeyId: string) => {
revokeApiKey.mutate({
params: {
appInstanceId: appId,
apiKeyId,
},
})
}
const handleSetEnvironmentAccessPolicy = async (
appId: string,
@ -97,10 +110,14 @@ const AccessTab: FC<AccessTabProps> = ({ instanceId: appId }) => {
subjects: AccessSubject[],
) => {
await setEnvironmentAccessPolicy.mutateAsync({
appId,
environmentId,
accessMode,
subjects,
params: {
appInstanceId: appId,
environmentId,
},
body: {
accessMode,
subjects,
},
})
}
const webappRows = accessConfig?.accessChannels?.webappRows?.filter(row => row.url) ?? []

View File

@ -212,12 +212,18 @@ const SettingsTab: FC<SettingsTabProps> = ({ instanceId }) => {
hasDeployments={hasDeployments}
onSave={async (patch) => {
await updateInstance.mutateAsync({
appId: instanceId,
...patch,
params: {
appInstanceId: instanceId,
},
body: patch,
})
}}
onDelete={async () => {
await deleteInstance.mutateAsync(instanceId)
await deleteInstance.mutateAsync({
params: {
appInstanceId: instanceId,
},
})
router.push('/deployments')
}}
/>

View File

@ -5,9 +5,10 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/too
import { 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 { deploymentEnvironmentDeploymentsQueryOptions } from '../queries'
import {
deploymentEnvironmentDeploymentsQueryOptions,
deploymentReleaseHistoryQueryOptions,
} from '../queries'
import {
deployedRows,
formatDate,
@ -26,16 +27,7 @@ type VersionsTabProps = {
const VersionsTab: FC<VersionsTabProps> = ({ instanceId: appId }) => {
const { t } = useTranslation('deployments')
const query = {
pageNumber: 1,
resultsPerPage: DEPLOYMENT_PAGE_SIZE,
}
const { data: releaseHistory } = useQuery(consoleQuery.deployments.releaseHistory.queryOptions({
input: {
params: { appInstanceId: appId },
query,
},
}))
const { data: releaseHistory } = useQuery(deploymentReleaseHistoryQueryOptions(appId))
const { data: environmentDeployments } = useQuery(deploymentEnvironmentDeploymentsQueryOptions(appId))
const releaseRows = useMemo(
() => releaseHistory?.data?.filter(row => (row.release ?? row).id) ?? [],

View File

@ -1,12 +1,11 @@
'use client'
import type {
AccessSubject,
ConsoleReleaseSummary,
} from '@/contract/console/deployments'
import type { QueryClient, QueryKey } from '@tanstack/react-query'
import type { ConsoleReleaseSummary } from '@/contract/console/deployments'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { consoleClient, consoleQuery } from '@/service/client'
import { DEPLOYMENT_PAGE_SIZE } from '../data'
import { deploymentReleaseHistoryQueryOptions } from '../queries'
export type CreateDeploymentInstanceResult = {
appInstanceId: string
@ -26,50 +25,85 @@ type CreateInstanceParams = {
description?: string
}
type UpdateInstanceParams = {
name: string
description?: string
}
type UpdateDeploymentInstanceParams = {
appId: string
} & UpdateInstanceParams
type UndeployDeploymentParams = {
appId: string
runtimeInstanceId?: string
runtimeInstanceId: string
isDeploying?: boolean
}
type GenerateApiKeyParams = {
appId: string
environmentId: string
name: string
}
type RevokeApiKeyParams = {
appId: string
environmentId: string
apiKeyId: string
}
type ToggleAccessChannelParams = {
appId: string
channel: string
enabled: boolean
}
type SetEnvironmentAccessPolicyParams = {
appId: string
environmentId: string
accessMode: string
subjects: AccessSubject[]
}
const DEPLOYMENT_READINESS_RETRY_DELAYS = [0, 300, 700, 1200]
const wait = (delay: number) => new Promise(resolve => setTimeout(resolve, delay))
const appInstanceInput = (appInstanceId: string) => ({
input: {
params: { appInstanceId },
},
})
const environmentAccessPolicyInput = (appInstanceId: string, environmentId: string) => ({
input: {
params: {
appInstanceId,
environmentId,
},
},
})
const invalidateQueries = (queryClient: QueryClient, queryKeys: QueryKey[]) => {
void Promise.all(queryKeys.map(queryKey => queryClient.invalidateQueries({ queryKey })))
}
const invalidateInstanceList = (queryClient: QueryClient) => {
void queryClient.invalidateQueries({
queryKey: consoleQuery.deployments.list.key(),
})
}
const invalidateInstanceIdentity = (queryClient: QueryClient, appInstanceId: string) => {
invalidateQueries(queryClient, [
consoleQuery.deployments.list.key(),
consoleQuery.deployments.overview.queryKey(appInstanceInput(appInstanceId)),
consoleQuery.deployments.settings.queryKey(appInstanceInput(appInstanceId)),
])
}
const invalidateDeploymentState = (queryClient: QueryClient, appInstanceId: string) => {
invalidateQueries(queryClient, [
consoleQuery.deployments.list.key(),
consoleQuery.deployments.overview.queryKey(appInstanceInput(appInstanceId)),
consoleQuery.deployments.environmentDeployments.queryKey(appInstanceInput(appInstanceId)),
deploymentReleaseHistoryQueryOptions(appInstanceId).queryKey,
consoleQuery.deployments.accessConfig.queryKey(appInstanceInput(appInstanceId)),
])
}
const invalidateAccessState = (queryClient: QueryClient, appInstanceId: string) => {
invalidateQueries(queryClient, [
consoleQuery.deployments.overview.queryKey(appInstanceInput(appInstanceId)),
consoleQuery.deployments.accessConfig.queryKey(appInstanceInput(appInstanceId)),
])
}
const invalidateEnvironmentAccessPolicy = (
queryClient: QueryClient,
appInstanceId: string,
environmentId: string,
) => {
invalidateQueries(queryClient, [
consoleQuery.deployments.accessConfig.queryKey(appInstanceInput(appInstanceId)),
consoleQuery.deployments.environmentAccessPolicy.queryKey(
environmentAccessPolicyInput(appInstanceId, environmentId),
),
])
}
export const useCreateDeploymentInstance = () => {
const queryClient = useQueryClient()
@ -105,10 +139,8 @@ export const useCreateDeploymentInstance = () => {
initialRelease: response.initialRelease,
}
},
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: consoleQuery.deployments.key(),
})
onSuccess: () => {
invalidateInstanceList(queryClient)
},
})
}
@ -116,42 +148,21 @@ export const useCreateDeploymentInstance = () => {
export const useUpdateDeploymentInstance = () => {
const queryClient = useQueryClient()
return useMutation({
mutationKey: consoleQuery.deployments.updateInstance.mutationKey(),
mutationFn: ({ appId, ...patch }: UpdateDeploymentInstanceParams) =>
consoleClient.deployments.updateInstance({
params: {
appInstanceId: appId,
},
body: {
name: patch.name,
description: patch.description,
},
}),
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: consoleQuery.deployments.key(),
})
return useMutation(consoleQuery.deployments.updateInstance.mutationOptions({
onSuccess: (_data, variables) => {
invalidateInstanceIdentity(queryClient, variables.params.appInstanceId)
},
})
}))
}
export const useDeleteDeploymentInstance = () => {
const queryClient = useQueryClient()
return useMutation({
mutationKey: consoleQuery.deployments.deleteInstance.mutationKey(),
mutationFn: (appId: string) => consoleClient.deployments.deleteInstance({
params: {
appInstanceId: appId,
},
}),
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: consoleQuery.deployments.key(),
})
return useMutation(consoleQuery.deployments.deleteInstance.mutationOptions({
onSuccess: () => {
invalidateInstanceList(queryClient)
},
})
}))
}
export const useStartDeployment = () => {
@ -204,10 +215,8 @@ export const useStartDeployment = () => {
},
})
},
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: consoleQuery.deployments.key(),
})
onSuccess: (_data, variables) => {
invalidateDeploymentState(queryClient, variables.appId)
},
})
}
@ -219,7 +228,7 @@ export const useUndeployDeployment = () => {
mutationKey: consoleQuery.deployments.undeployEnvironment.mutationKey(),
mutationFn: ({ appId, runtimeInstanceId, isDeploying }: UndeployDeploymentParams) => {
if (!runtimeInstanceId)
return Promise.resolve(undefined)
throw new Error('runtimeInstanceId is required to undeploy a deployment.')
if (isDeploying) {
return consoleClient.deployments.cancelDeployment({
params: {
@ -235,10 +244,8 @@ export const useUndeployDeployment = () => {
},
})
},
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: consoleQuery.deployments.key(),
})
onSuccess: (_data, variables) => {
invalidateDeploymentState(queryClient, variables.appId)
},
})
}
@ -246,43 +253,21 @@ export const useUndeployDeployment = () => {
export const useGenerateDeploymentApiKey = () => {
const queryClient = useQueryClient()
return useMutation({
mutationKey: consoleQuery.deployments.createEnvironmentAPIToken.mutationKey(),
mutationFn: ({ appId, environmentId, name }: GenerateApiKeyParams) =>
consoleClient.deployments.createEnvironmentAPIToken({
params: {
appInstanceId: appId,
},
body: {
environmentId,
name,
},
}),
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: consoleQuery.deployments.key(),
})
return useMutation(consoleQuery.deployments.createEnvironmentAPIToken.mutationOptions({
onSuccess: (_data, variables) => {
invalidateAccessState(queryClient, variables.params.appInstanceId)
},
})
}))
}
export const useRevokeDeploymentApiKey = () => {
const queryClient = useQueryClient()
return useMutation({
mutationKey: consoleQuery.deployments.deleteEnvironmentAPIToken.mutationKey(),
mutationFn: ({ appId, apiKeyId }: RevokeApiKeyParams) => consoleClient.deployments.deleteEnvironmentAPIToken({
params: {
appInstanceId: appId,
apiKeyId,
},
}),
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: consoleQuery.deployments.key(),
})
return useMutation(consoleQuery.deployments.deleteEnvironmentAPIToken.mutationOptions({
onSuccess: (_data, variables) => {
invalidateAccessState(queryClient, variables.params.appInstanceId)
},
})
}))
}
export const useToggleDeploymentAccessChannel = () => {
@ -310,10 +295,8 @@ export const useToggleDeploymentAccessChannel = () => {
},
})
},
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: consoleQuery.deployments.key(),
})
onSuccess: (_data, variables) => {
invalidateAccessState(queryClient, variables.appId)
},
})
}
@ -321,27 +304,13 @@ export const useToggleDeploymentAccessChannel = () => {
export const useSetEnvironmentAccessPolicy = () => {
const queryClient = useQueryClient()
return useMutation({
mutationKey: consoleQuery.deployments.updateEnvironmentAccessPolicy.mutationKey(),
mutationFn: ({
appId,
environmentId,
accessMode,
subjects,
}: SetEnvironmentAccessPolicyParams) => consoleClient.deployments.updateEnvironmentAccessPolicy({
params: {
appInstanceId: appId,
environmentId,
},
body: {
accessMode,
subjects,
},
}),
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: consoleQuery.deployments.key(),
})
return useMutation(consoleQuery.deployments.updateEnvironmentAccessPolicy.mutationOptions({
onSuccess: (_data, variables) => {
invalidateEnvironmentAccessPolicy(
queryClient,
variables.params.appInstanceId,
variables.params.environmentId,
)
},
})
}))
}

View File

@ -1,7 +1,7 @@
import type { ListAppDeploymentsQuery } from '@/contract/console/deployments'
import { skipToken } from '@tanstack/react-query'
import { consoleQuery } from '@/service/client'
import { SOURCE_APPS_PAGE_SIZE } from './data'
import { DEPLOYMENT_PAGE_SIZE, SOURCE_APPS_PAGE_SIZE } from './data'
export const deploymentsListQueryOptions = (query: ListAppDeploymentsQuery = {}) =>
consoleQuery.deployments.list.queryOptions({
@ -27,3 +27,16 @@ export const deploymentEnvironmentDeploymentsQueryOptions = (appInstanceId?: str
? { params: { appInstanceId } }
: skipToken,
})
export const deploymentReleaseHistoryQueryOptions = (appInstanceId?: string) =>
consoleQuery.deployments.releaseHistory.queryOptions({
input: appInstanceId
? {
params: { appInstanceId },
query: {
pageNumber: 1,
resultsPerPage: DEPLOYMENT_PAGE_SIZE,
},
}
: skipToken,
})