From cfb1e0217f88b319aec484cac1b3cebad3fa187d Mon Sep 17 00:00:00 2001
From: Stephen Zhou <38493346+hyoban@users.noreply.github.com>
Date: Thu, 7 May 2026 20:08:54 +0800
Subject: [PATCH] tweaks
---
web/features/deployments/detail/index.tsx | 6 +-
.../deployments/detail/overview-tab.tsx | 48 +++---
.../deployments/list/instance-card.tsx | 154 +++++++++---------
3 files changed, 102 insertions(+), 106 deletions(-)
diff --git a/web/features/deployments/detail/index.tsx b/web/features/deployments/detail/index.tsx
index 805d87124e..720c23b1e5 100644
--- a/web/features/deployments/detail/index.tsx
+++ b/web/features/deployments/detail/index.tsx
@@ -7,7 +7,8 @@ import { useQuery } from '@tanstack/react-query'
import { useTranslation } from 'react-i18next'
import { getAppModeLabel } from '@/app/components/app-sidebar/app-info/app-mode-labels'
import useDocumentTitle from '@/hooks/use-document-title'
-import { useRouter, useSelectedLayoutSegment } from '@/next/navigation'
+import Link from '@/next/link'
+import { useSelectedLayoutSegment } from '@/next/navigation'
import { consoleQuery } from '@/service/client'
import { DeployDrawer } from '../components/deploy-drawer'
import { RollbackModal } from '../components/rollback-modal'
@@ -20,7 +21,6 @@ export function InstanceDetail({ instanceId, children }: {
}) {
const { t } = useTranslation('deployments')
const { t: tCommon } = useTranslation()
- const router = useRouter()
const selectedSegment = useSelectedLayoutSegment()
const selectedTab = selectedSegment ?? undefined
const activeTab: InstanceDetailTabKey = isInstanceDetailTabKey(selectedTab) ? selectedTab : 'overview'
@@ -47,7 +47,7 @@ export function InstanceDetail({ instanceId, children }: {
return (
{t('detail.notFound')}
-
diff --git a/web/features/deployments/detail/overview-tab.tsx b/web/features/deployments/detail/overview-tab.tsx
index 8e69bdc1ae..474aafd5d6 100644
--- a/web/features/deployments/detail/overview-tab.tsx
+++ b/web/features/deployments/detail/overview-tab.tsx
@@ -5,7 +5,7 @@ import { cn } from '@langgenius/dify-ui/cn'
import { useQuery } from '@tanstack/react-query'
import { useTranslation } from 'react-i18next'
import { getAppModeLabel } from '@/app/components/app-sidebar/app-info/app-mode-labels'
-import { useRouter } from '@/next/navigation'
+import Link from '@/next/link'
import { consoleQuery } from '@/service/client'
import { StatusBadge } from '../components/status-badge'
import { DEPLOYMENT_PAGE_SIZE } from '../data'
@@ -17,6 +17,10 @@ import {
type SwitchableTab = 'deploy' | 'versions' | 'access' | 'settings'
+function tabHref(appId: string, tab: SwitchableTab): string {
+ return `/deployments/${appId}/${tab}`
+}
+
function Section({ title, action, children }: {
title: string
action?: ReactNode
@@ -79,7 +83,7 @@ function AccessOverviewRow({ label, enabled, hint, meta }: AccessOverviewRowProp
)
}
-function overviewDeploymentStatus(status?: string) {
+function overviewDeploymentStatus(status?: string): 'deploying' | 'deploy_failed' | 'ready' {
const normalized = status?.toLowerCase() ?? ''
if (normalized.includes('deploying') || normalized.includes('pending'))
return 'deploying'
@@ -93,7 +97,6 @@ export function OverviewTab({ instanceId }: {
}) {
const { t } = useTranslation('deployments')
const { t: tCommon } = useTranslation()
- const router = useRouter()
const input = { params: { appInstanceId: instanceId } }
const { data: overview } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceOverview.queryOptions({
input,
@@ -121,10 +124,6 @@ export function OverviewTab({ instanceId }: {
const appId = overviewApp.id
const appName = overviewApp.name ?? appId
- const switchTab = (tab: SwitchableTab) => {
- router.push(`/deployments/${appId}/${tab}`)
- }
-
const appModeLabel = getAppModeLabel(overviewApp.mode ?? 'workflow', tCommon)
const webappAccessUrl = webappUrl(overview?.access?.webappUrl)
const cliUrl = overview?.access?.cliUrl
@@ -145,7 +144,7 @@ export function OverviewTab({ instanceId }: {
switchTab('deploy')}>
+ }>
{t('overview.viewDeployments')}
@@ -160,20 +159,23 @@ export function OverviewTab({ instanceId }: {
? t(canCreateRelease ? 'overview.noReleaseYet' : 'overview.noReleaseSourceUnavailable')
: t('overview.notDeployedYet')}
- {
- if (releaseRows.length === 0) {
- switchTab('versions')
- return
- }
- openDeployDrawer({ appInstanceId: appId })
- }}
- >
- {releaseRows.length === 0 ? t('overview.createRelease') : t('overview.deploy')}
-
+ {releaseRows.length === 0
+ ? canCreateRelease
+ ? (
+ }>
+ {t('overview.createRelease')}
+
+ )
+ : (
+
+ {t('overview.createRelease')}
+
+ )
+ : (
+ openDeployDrawer({ appInstanceId: appId })}>
+ {t('overview.deploy')}
+
+ )}
)
: (
@@ -199,7 +201,7 @@ export function OverviewTab({ instanceId }: {
switchTab('access')}>
+ }>
{t('overview.configureAccess')}
diff --git a/web/features/deployments/list/instance-card.tsx b/web/features/deployments/list/instance-card.tsx
index b560d7182c..8a8d8e143c 100644
--- a/web/features/deployments/list/instance-card.tsx
+++ b/web/features/deployments/list/instance-card.tsx
@@ -1,13 +1,13 @@
'use client'
import type { AppInstanceCard } from '@dify/contracts/enterprise/types.gen'
-import type { MouseEvent } from 'react'
import type { AppModeEnum } from '@/types/app'
import { cn } from '@langgenius/dify-ui/cn'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
+ DropdownMenuLinkItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@langgenius/dify-ui/dropdown-menu'
@@ -17,14 +17,13 @@ import { useTranslation } from 'react-i18next'
import { AppTypeIcon } from '@/app/components/app/type-selector'
import AppIcon from '@/app/components/base/app-icon'
import { useFormatTimeFromNow } from '@/hooks/use-format-time-from-now'
-import { useRouter } from '@/next/navigation'
+import Link from '@/next/link'
import { useDeploymentsStore } from '../store'
export function InstanceCard({ app }: {
app: AppInstanceCard
}) {
const { t } = useTranslation('deployments')
- const router = useRouter()
const { formatTimeFromNow } = useFormatTimeFromNow()
const [menuOpen, setMenuOpen] = useState(false)
const openDeployDrawer = useDeploymentsStore(state => state.openDeployDrawer)
@@ -35,14 +34,7 @@ export function InstanceCard({ app }: {
const appId = app.id
const appName = app.name ?? appId
const appMode = app.mode ?? 'workflow'
- const navigateToDetail = () => router.push(`/deployments/${appId}/overview`)
-
- const handleMenuAction = (e: MouseEvent, action: () => void) => {
- e.stopPropagation()
- e.preventDefault()
- setMenuOpen(false)
- action()
- }
+ const detailHref = `/deployments/${appId}/overview`
const statusCount = (status: string) =>
app.statuses?.find(item => item.status === status)?.count ?? 0
@@ -122,75 +114,78 @@ export function InstanceCard({ app }: {
return (
{
- e.preventDefault()
- navigateToDetail()
- }}
className="group relative col-span-1 inline-flex h-[160px] cursor-pointer flex-col rounded-xl border border-solid border-components-card-border bg-components-card-bg shadow-sm transition-all duration-200 ease-in-out hover:shadow-lg"
>
-
-
-
-
-
{appName}
+
+
-
-
-
-
-
- {primaryText}
-
- {secondaryParts.length > 0 && (
-
- {secondaryParts.join(' · ')}
+
+
+
+
+
+ {primaryText}
- )}
-
- )}
- />
- {statusTooltip}
-
-
-
-
- {t('card.fromApp', { name: app.sourceAppName ?? appName })}
-
+ {secondaryParts.length > 0 && (
+
+ {secondaryParts.join(' · ')}
+
+ )}
+
+ )}
+ />
+
{statusTooltip}
+
+
+
+
+ {t('card.fromApp', { name: app.sourceAppName ?? appName })}
+
+
-
-
-
-
-
- {lastDeployedAt
- ? t('card.lastDeployed', { time: formatTimeFromNow(lastDeployedAt) })
- : t('card.neverDeployed')}
-
+
+
+
+
+ {lastDeployedAt
+ ? t('card.lastDeployed', { time: formatTimeFromNow(lastDeployedAt) })
+ : t('card.neverDeployed')}
+
+
+
+
{
- e.stopPropagation()
- e.preventDefault()
- }}
>
@@ -217,16 +208,19 @@ export function InstanceCard({ app }: {
handleMenuAction(e, () => openDeployDrawer({ appInstanceId: appId }))}
+ onClick={() => {
+ setMenuOpen(false)
+ openDeployDrawer({ appInstanceId: appId })
+ }}
>
{t('card.menu.deploy')}
- handleMenuAction(e, navigateToDetail)}
+ render={}
>
{t('card.menu.viewDetail')}
-
+