From a223869a23f39081846994d2df8b1e1537d71e3d Mon Sep 17 00:00:00 2001
From: Stephen Zhou <38493346+hyoban@users.noreply.github.com>
Date: Fri, 8 May 2026 16:42:18 +0800
Subject: [PATCH] tweaks
---
.../deployments/detail/access-tab.tsx | 63 +----
.../detail/access-tab/channels-section.tsx | 21 +-
.../access-tab/developer-api-section.tsx | 14 +-
.../detail/access-tab/permissions-section.tsx | 7 +-
.../use-access-environment-scope.ts | 40 +++
.../deployments/detail/overview-tab.tsx | 248 ++++++++++--------
.../deployments/detail/settings-tab.tsx | 63 +++--
.../deployments/detail/versions-tab.tsx | 118 +--------
.../versions-tab/release-history-table.tsx | 125 +++++++++
9 files changed, 382 insertions(+), 317 deletions(-)
create mode 100644 web/features/deployments/detail/access-tab/use-access-environment-scope.ts
create mode 100644 web/features/deployments/detail/versions-tab/release-history-table.tsx
diff --git a/web/features/deployments/detail/access-tab.tsx b/web/features/deployments/detail/access-tab.tsx
index 49f683835e..1f4ec0d700 100644
--- a/web/features/deployments/detail/access-tab.tsx
+++ b/web/features/deployments/detail/access-tab.tsx
@@ -1,74 +1,17 @@
'use client'
-import type {
- ConsoleEnvironment,
- EnvironmentAccessRow,
-} from '@dify/contracts/enterprise/types.gen'
-import { useQuery } from '@tanstack/react-query'
-import { consoleQuery } from '@/service/client'
-import {
- deployedRows,
-} from '../utils'
import { AccessChannelsSection } from './access-tab/channels-section'
import { DeveloperApiSection } from './access-tab/developer-api-section'
import { AccessPermissionsSection } from './access-tab/permissions-section'
-import { getUrlOrigin } from './access-tab/url'
-
-const EMPTY_ACCESS_PERMISSIONS: EnvironmentAccessRow[] = []
-
-function uniqueEnvironments(environments: (ConsoleEnvironment | undefined)[]) {
- return environments.filter((environment, index): environment is ConsoleEnvironment => {
- if (!environment?.id)
- return false
- return environments.findIndex(candidate => candidate?.id === environment.id) === index
- })
-}
export function AccessTab({ instanceId: appId }: {
instanceId: string
}) {
- const appInput = { params: { appInstanceId: appId } }
- const { data: accessConfig } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceAccess.queryOptions({
- input: appInput,
- }))
- const { data: environmentDeployments } = useQuery(consoleQuery.enterprise.appDeploy.listRuntimeInstances.queryOptions({
- input: appInput,
- }))
- const deploymentRows = deployedRows(environmentDeployments?.data)
- const policies = accessConfig?.permissions ?? EMPTY_ACCESS_PERMISSIONS
- const deployedEnvs = uniqueEnvironments([
- ...deploymentRows.map(row => row.environment),
- ...policies.map(policy => policy.environment),
- ...(accessConfig?.accessChannels?.webappRows?.map(row => row.environment) ?? []),
- ])
- const apiEnabled = accessConfig?.developerApi?.enabled ?? false
- const apiKeys = accessConfig?.developerApi?.apiKeys ?? []
- const webappRows = accessConfig?.accessChannels?.webappRows?.filter(row => row.url) ?? []
- const runEnabled = accessConfig?.accessChannels?.enabled ?? false
- const cliDomain = getUrlOrigin(accessConfig?.accessChannels?.cli?.url)
- const cliDocsUrl = cliDomain ? `${cliDomain}/cli` : undefined
-
return (
)
}
diff --git a/web/features/deployments/detail/access-tab/channels-section.tsx b/web/features/deployments/detail/access-tab/channels-section.tsx
index 842ee329cd..900b459c0a 100644
--- a/web/features/deployments/detail/access-tab/channels-section.tsx
+++ b/web/features/deployments/detail/access-tab/channels-section.tsx
@@ -1,19 +1,15 @@
'use client'
-import type { WebAppAccessRow } from '@dify/contracts/enterprise/types.gen'
import { Switch } from '@langgenius/dify-ui/switch'
-import { useMutation } from '@tanstack/react-query'
+import { useMutation, useQuery } from '@tanstack/react-query'
import { useTranslation } from 'react-i18next'
import { consoleQuery } from '@/service/client'
import { environmentName, webappUrl } from '../../utils'
import { CopyPill, EndpointRow, Section } from './common'
+import { getUrlOrigin } from './url'
type AccessChannelsSectionProps = {
appId: string
- runEnabled: boolean
- webappRows: WebAppAccessRow[]
- cliDomain?: string
- cliDocsUrl?: string
}
function AccessChannelsSwitch({ appId, checked }: {
@@ -37,12 +33,17 @@ function AccessChannelsSwitch({ appId, checked }: {
export function AccessChannelsSection({
appId,
- runEnabled,
- webappRows,
- cliDomain,
- cliDocsUrl,
}: AccessChannelsSectionProps) {
const { t } = useTranslation('deployments')
+ const { data: accessConfig } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceAccess.queryOptions({
+ input: {
+ params: { appInstanceId: appId },
+ },
+ }))
+ const runEnabled = accessConfig?.accessChannels?.enabled ?? false
+ const webappRows = accessConfig?.accessChannels?.webappRows?.filter(row => row.url) ?? []
+ const cliDomain = getUrlOrigin(accessConfig?.accessChannels?.cli?.url)
+ const cliDocsUrl = cliDomain ? `${cliDomain}/cli` : undefined
return (
{
+ if (!environment?.id)
+ return false
+ return environments.findIndex(candidate => candidate?.id === environment.id) === index
+ })
+}
+
+export function useAccessEnvironmentScope(appId: string) {
+ const appInput = { params: { appInstanceId: appId } }
+ const { data: accessConfig } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceAccess.queryOptions({
+ input: appInput,
+ }))
+ const { data: environmentDeployments } = useQuery(consoleQuery.enterprise.appDeploy.listRuntimeInstances.queryOptions({
+ input: appInput,
+ }))
+ const deploymentRows = deployedRows(environmentDeployments?.data)
+ const policies = accessConfig?.permissions ?? EMPTY_ACCESS_PERMISSIONS
+ const environments = uniqueEnvironments([
+ ...deploymentRows.map(row => row.environment),
+ ...policies.map(policy => policy.environment),
+ ...(accessConfig?.accessChannels?.webappRows?.map(row => row.environment) ?? []),
+ ])
+
+ return {
+ accessConfig,
+ environments,
+ policies,
+ }
+}
diff --git a/web/features/deployments/detail/overview-tab.tsx b/web/features/deployments/detail/overview-tab.tsx
index 25e9a722e6..423299e331 100644
--- a/web/features/deployments/detail/overview-tab.tsx
+++ b/web/features/deployments/detail/overview-tab.tsx
@@ -101,12 +101,41 @@ function DeployFromOverviewButton({ appId }: {
)
}
-export function OverviewTab({ instanceId }: {
- instanceId: string
+function BasicInfoSection({ appId }: {
+ appId: string
}) {
const { t } = useTranslation('deployments')
const { t: tCommon } = useTranslation()
- const input = { params: { appInstanceId: instanceId } }
+ const { data: overview } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceOverview.queryOptions({
+ input: {
+ params: { appInstanceId: appId },
+ },
+ }))
+ const overviewApp = overview?.instance
+
+ if (!overviewApp?.id)
+ return null
+
+ const appName = overviewApp.name ?? overviewApp.id
+ const appModeLabel = getAppModeLabel(toAppMode(overviewApp.mode), tCommon)
+
+ return (
+
+ )
+}
+
+function DeploymentStatusSection({ appId }: {
+ appId: string
+}) {
+ const { t } = useTranslation('deployments')
+ const input = { params: { appInstanceId: appId } }
const { data: overview } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceOverview.queryOptions({
input,
}))
@@ -119,9 +148,6 @@ export function OverviewTab({ instanceId }: {
},
},
}))
- const { data: accessConfig } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceAccess.queryOptions({
- input,
- }))
const overviewApp = overview?.instance
const deployments = overview?.deployments?.filter(row => row.environment?.id && row.status?.toLowerCase() !== 'undeployed') ?? []
const releaseRows = releaseHistory?.data?.filter(row => row.id) ?? []
@@ -130,112 +156,124 @@ export function OverviewTab({ instanceId }: {
if (!overviewApp?.id)
return null
- const appId = overviewApp.id
- const appName = overviewApp.name ?? appId
- const appModeLabel = getAppModeLabel(toAppMode(overviewApp.mode), tCommon)
+ return (
+ }>
+ {t('overview.viewDeployments')}
+
+
+ )}
+ >
+ {deployments.length === 0
+ ? (
+
+
+
+ {releaseRows.length === 0
+ ? t(canCreateRelease ? 'overview.noReleaseYet' : 'overview.noReleaseSourceUnavailable')
+ : t('overview.notDeployedYet')}
+
+ {releaseRows.length === 0
+ ? canCreateRelease
+ ? (
+
}>
+ {t('overview.createRelease')}
+
+ )
+ : (
+
+ )
+ : (
+
+ )}
+
+ )
+ : (
+
+ {deployments.map((row) => {
+ const status = overviewDeploymentStatus(row.status)
+ return (
+
+
+ {row.environment?.name || row.environment?.id}
+
+ {releaseLabel(row.release) || t('overview.emptyValue')}
+
+
+
+
+ )
+ })}
+
+ )}
+
+ )
+}
+
+function AccessStatusSection({ appId }: {
+ appId: string
+}) {
+ const { t } = useTranslation('deployments')
+ const input = { params: { appInstanceId: appId } }
+ const { data: overview } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceOverview.queryOptions({
+ input,
+ }))
+ const { data: accessConfig } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceAccess.queryOptions({
+ input,
+ }))
const webappAccessUrl = webappUrl(overview?.access?.webappUrl)
const cliUrl = overview?.access?.cliUrl
const apiUrl = overview?.access?.apiUrl ?? accessConfig?.developerApi?.apiUrl
const apiKeysCount = overview?.access?.apiKeyCount ?? accessConfig?.developerApi?.apiKeys?.length ?? 0
+ return (
+ }>
+ {t('overview.configureAccess')}
+
+
+ )}
+ >
+
+
+ )
+}
+
+export function OverviewTab({ instanceId: appId }: {
+ instanceId: string
+}) {
return (
-
-
-
}>
- {t('overview.viewDeployments')}
-
-
- )}
- >
- {deployments.length === 0
- ? (
-
-
-
- {releaseRows.length === 0
- ? t(canCreateRelease ? 'overview.noReleaseYet' : 'overview.noReleaseSourceUnavailable')
- : t('overview.notDeployedYet')}
-
- {releaseRows.length === 0
- ? canCreateRelease
- ? (
-
}>
- {t('overview.createRelease')}
-
- )
- : (
-
- )
- : (
-
- )}
-
- )
- : (
-
- {deployments.map((row) => {
- const status = overviewDeploymentStatus(row.status)
- return (
-
-
- {row.environment?.name || row.environment?.id}
-
- {releaseLabel(row.release) || t('overview.emptyValue')}
-
-
-
-
- )
- })}
-
- )}
-
-
-
}>
- {t('overview.configureAccess')}
-
-
- )}
- >
-
-
+
+
+
)
}
diff --git a/web/features/deployments/detail/settings-tab.tsx b/web/features/deployments/detail/settings-tab.tsx
index d87552d781..d3278872e6 100644
--- a/web/features/deployments/detail/settings-tab.tsx
+++ b/web/features/deployments/detail/settings-tab.tsx
@@ -216,16 +216,13 @@ function SettingsForm({ app, settings }: SettingsFormProps) {
)
}
-export function SettingsTab({ instanceId }: {
- instanceId: string
+function SettingsFormSection({ appId }: {
+ appId: string
}) {
- const appInput = { params: { appInstanceId: instanceId } }
+ const appInput = { params: { appInstanceId: appId } }
const { data: overview } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceOverview.queryOptions({
input: appInput,
}))
- const { data: environmentDeployments } = useQuery(consoleQuery.enterprise.appDeploy.listRuntimeInstances.queryOptions({
- input: appInput,
- }))
const app = overview?.instance
const settingsQuery = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceSettings.queryOptions({
input: appInput,
@@ -234,22 +231,54 @@ export function SettingsTab({ instanceId }: {
if (!app?.id)
return null
- const hasDeployments = deployedRows(environmentDeployments?.data).length > 0
const appName = app.name ?? app.id
const formKey = `${app.id}-${settingsQuery.data?.name ?? appName}-${settingsQuery.data?.description ?? app.description ?? ''}`
+ return (
+
+ )
+}
+
+function DeleteInstanceControlSection({ appId }: {
+ appId: string
+}) {
+ const appInput = { params: { appInstanceId: appId } }
+ const { data: overview } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceOverview.queryOptions({
+ input: appInput,
+ }))
+ const { data: environmentDeployments } = useQuery(consoleQuery.enterprise.appDeploy.listRuntimeInstances.queryOptions({
+ input: appInput,
+ }))
+ const settingsQuery = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceSettings.queryOptions({
+ input: appInput,
+ }))
+ const app = overview?.instance
+
+ if (!app?.id)
+ return null
+
+ const hasDeployments = deployedRows(environmentDeployments?.data).length > 0
+
+ return (
+
+ )
+}
+
+export function SettingsTab({ instanceId: appId }: {
+ instanceId: string
+}) {
return (
-
-
+
+
)
}
diff --git a/web/features/deployments/detail/versions-tab.tsx b/web/features/deployments/detail/versions-tab.tsx
index 83a68e5ffc..b2bbb60349 100644
--- a/web/features/deployments/detail/versions-tab.tsx
+++ b/web/features/deployments/detail/versions-tab.tsx
@@ -1,26 +1,15 @@
'use client'
import { Button } from '@langgenius/dify-ui/button'
-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 { useMutation, useQuery } from '@tanstack/react-query'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import Input from '@/app/components/base/input'
import { consoleQuery } from '@/service/client'
import { DEPLOYMENT_PAGE_SIZE } from '../data'
-import {
- deployedRows,
- formatDate,
- releaseCommit,
- releaseLabel,
-} from '../utils'
-import { DeployReleaseMenu } from './versions-tab/deploy-release-menu'
-import { DeployedToBadge } from './versions-tab/deployed-to-badge'
-import { getReleaseDeployments } from './versions-tab/release-deployments'
-
-const GRID_TEMPLATE = 'grid-cols-[minmax(0,0.9fr)_minmax(0,1fr)_minmax(0,0.8fr)_minmax(0,1.5fr)_96px]'
+import { deployedRows } from '../utils'
+import { ReleaseHistoryTable } from './versions-tab/release-history-table'
function CreateReleaseControl({ appId, canCreateRelease }: {
appId: string
@@ -212,104 +201,11 @@ export function VersionsTab({ instanceId: appId }: {
)
: (
-
-
-
{t('versions.col.release')}
-
{t('versions.col.createdAt')}
-
{t('versions.col.author')}
-
{t('versions.col.deployedTo')}
-
{t('versions.col.action')}
-
-
- {releaseRows.map((row) => {
- const release = row
- const releaseDeployments = getReleaseDeployments(row, deploymentRows)
- return (
-
-
-
-
-
-
- {releaseLabel(release)}
-
- )}
- />
-
- {t('versions.commitTooltip', { commit: releaseCommit(release) })}
-
-
-
- {formatDate(release.createdAt)}
- ·
- {row.createdBy?.name ?? '—'}
-
-
-
-
-
-
-
-
- {t('versions.col.deployedTo')}
-
-
- {releaseDeployments.length === 0
- ? —
- : releaseDeployments.map(item => (
-
- ))}
-
-
-
-
-
-
-
- {releaseLabel(release)}
-
- )}
- />
-
- {t('versions.commitTooltip', { commit: releaseCommit(release) })}
-
-
-
-
{formatDate(release.createdAt)}
-
{row.createdBy?.name ?? '—'}
-
- {releaseDeployments.length === 0
- ? —
- : releaseDeployments.map(item => (
-
- ))}
-
-
-
-
-
-
- )
- })}
-
+
)}
)
diff --git a/web/features/deployments/detail/versions-tab/release-history-table.tsx b/web/features/deployments/detail/versions-tab/release-history-table.tsx
new file mode 100644
index 0000000000..0dc1d1aeda
--- /dev/null
+++ b/web/features/deployments/detail/versions-tab/release-history-table.tsx
@@ -0,0 +1,125 @@
+'use client'
+
+import type { ReleaseRow, RuntimeInstanceRow } from '@dify/contracts/enterprise/types.gen'
+import { cn } from '@langgenius/dify-ui/cn'
+import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
+import { useTranslation } from 'react-i18next'
+import {
+ formatDate,
+ releaseCommit,
+ releaseLabel,
+} from '../../utils'
+import { DeployReleaseMenu } from './deploy-release-menu'
+import { DeployedToBadge } from './deployed-to-badge'
+import { getReleaseDeployments } from './release-deployments'
+
+const GRID_TEMPLATE = 'grid-cols-[minmax(0,0.9fr)_minmax(0,1fr)_minmax(0,0.8fr)_minmax(0,1.5fr)_96px]'
+
+export function ReleaseHistoryTable({ appId, releaseRows, deploymentRows }: {
+ appId: string
+ releaseRows: ReleaseRow[]
+ deploymentRows: RuntimeInstanceRow[]
+}) {
+ const { t } = useTranslation('deployments')
+
+ return (
+
+
+
{t('versions.col.release')}
+
{t('versions.col.createdAt')}
+
{t('versions.col.author')}
+
{t('versions.col.deployedTo')}
+
{t('versions.col.action')}
+
+
+ {releaseRows.map((row) => {
+ const release = row
+ const releaseDeployments = getReleaseDeployments(row, deploymentRows)
+ return (
+
+
+
+
+
+
+ {releaseLabel(release)}
+
+ )}
+ />
+
+ {t('versions.commitTooltip', { commit: releaseCommit(release) })}
+
+
+
+ {formatDate(release.createdAt)}
+ ·
+ {row.createdBy?.name ?? '—'}
+
+
+
+
+
+
+
+
+ {t('versions.col.deployedTo')}
+
+
+ {releaseDeployments.length === 0
+ ? —
+ : releaseDeployments.map(item => (
+
+ ))}
+
+
+
+
+
+
+
+ {releaseLabel(release)}
+
+ )}
+ />
+
+ {t('versions.commitTooltip', { commit: releaseCommit(release) })}
+
+
+
+
{formatDate(release.createdAt)}
+
{row.createdBy?.name ?? '—'}
+
+ {releaseDeployments.length === 0
+ ? —
+ : releaseDeployments.map(item => (
+
+ ))}
+
+
+
+
+
+
+ )
+ })}
+
+ )
+}