From b07b68b5314e5847de2c05fa70d9baba29abfd83 Mon Sep 17 00:00:00 2001
From: Stephen Zhou <38493346+hyoban@users.noreply.github.com>
Date: Sat, 9 May 2026 16:58:29 +0800
Subject: [PATCH] tweak dropdown menuy
---
.../skills/how-to-write-component/SKILL.md | 2 +
.../deployments/list/instance-card.tsx | 113 +++++++-----------
2 files changed, 45 insertions(+), 70 deletions(-)
diff --git a/.agents/skills/how-to-write-component/SKILL.md b/.agents/skills/how-to-write-component/SKILL.md
index 5d916645f7..e7de1fe09f 100644
--- a/.agents/skills/how-to-write-component/SKILL.md
+++ b/.agents/skills/how-to-write-component/SKILL.md
@@ -59,6 +59,8 @@ Do not copy existing code patterns blindly. Existing implementations are referen
- Split deeper components by the data and state each layer actually needs. Each component should access only necessary data, and state should be pushed down to the lowest owner.
- Keep cohesive forms, menu bodies, and one-off helpers local unless they need their own state, reuse, or semantic boundary.
- Separate hidden secondary surfaces from the trigger's main flow. For dialogs, dropdowns, popovers, and similar branches, extract a small local component that owns the trigger, open state, and hidden content when that branch obscures the parent flow.
+- Preserve composability by separating behavior ownership from layout ownership. A dropdown action may own its trigger, open state, and menu content; the caller should own placement such as slots, offsets, and alignment.
+- Avoid unnecessary DOM hierarchy. Do not add wrapper elements unless they provide layout, semantics, accessibility, state ownership, or integration with a library API; prefer fragments or styling an existing element when possible.
- Avoid shallow wrappers and prop renaming. Call the original function directly unless the wrapper adds validation, orchestration, error handling, state ownership, or a real semantic boundary.
## Navigation
diff --git a/web/features/deployments/list/instance-card.tsx b/web/features/deployments/list/instance-card.tsx
index dd58089400..dcff431ad9 100644
--- a/web/features/deployments/list/instance-card.tsx
+++ b/web/features/deployments/list/instance-card.tsx
@@ -1,26 +1,28 @@
'use client'
import type { AppInstanceCard } from '@dify/contracts/enterprise/types.gen'
+import type { InstanceDetailTabKey } from '../detail/tabs'
import { cn } from '@langgenius/dify-ui/cn'
import {
DropdownMenu,
DropdownMenuContent,
- DropdownMenuItem,
DropdownMenuLinkItem,
- DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@langgenius/dify-ui/dropdown-menu'
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
-import { useSetAtom } from 'jotai'
-import { useState } from 'react'
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 Link from '@/next/link'
-import { openDeployDrawerAtom } from '../store'
import { toAppMode } from '../utils'
+const INSTANCE_CARD_MENU_TAB_KEYS = ['deploy', 'versions', 'access', 'settings'] satisfies InstanceDetailTabKey[]
+
+function getInstanceTabHref(appInstanceId: string, tabKey: InstanceDetailTabKey) {
+ return `/deployments/${appInstanceId}/${tabKey}`
+}
+
export function InstanceCard({ app }: {
app: AppInstanceCard
}) {
@@ -184,72 +186,43 @@ export function InstanceCard({ app }: {
-