- {app
- ? (
-
- )
- : (
-
-
-
- )}
+
{expand && (
@@ -168,12 +154,12 @@ export function DeploymentSidebar({
{appModeLabel}
- {instanceDescription && (
+ {app.description && (
- {instanceDescription}
+ {app.description}
)}
diff --git a/web/features/deployments/detail/index.tsx b/web/features/deployments/detail/index.tsx
index 720c23b1e5..dbb8deb2b8 100644
--- a/web/features/deployments/detail/index.tsx
+++ b/web/features/deployments/detail/index.tsx
@@ -5,7 +5,6 @@ import type { InstanceDetailTabKey } from './tabs'
import { Button } from '@langgenius/dify-ui/button'
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 Link from '@/next/link'
import { useSelectedLayoutSegment } from '@/next/navigation'
@@ -20,7 +19,6 @@ export function InstanceDetail({ instanceId, children }: {
children: ReactNode
}) {
const { t } = useTranslation('deployments')
- const { t: tCommon } = useTranslation()
const selectedSegment = useSelectedLayoutSegment()
const selectedTab = selectedSegment ?? undefined
const activeTab: InstanceDetailTabKey = isInstanceDetailTabKey(selectedTab) ? selectedTab : 'overview'
@@ -54,17 +52,11 @@ export function InstanceDetail({ instanceId, children }: {
)
}
- const appName = app.name ?? appId
- const appModeLabel = getAppModeLabel(app.mode ?? 'workflow', tCommon)
return (
<>
diff --git a/web/features/deployments/detail/overview-tab.tsx b/web/features/deployments/detail/overview-tab.tsx
index 4b41dd5b2f..47e6b30d20 100644
--- a/web/features/deployments/detail/overview-tab.tsx
+++ b/web/features/deployments/detail/overview-tab.tsx
@@ -13,6 +13,7 @@ import { DEPLOYMENT_PAGE_SIZE } from '../data'
import { openDeployDrawerAtom } from '../store'
import {
releaseLabel,
+ toAppMode,
webappUrl,
} from '../utils'
@@ -119,7 +120,7 @@ export function OverviewTab({ instanceId }: {
const appId = overviewApp.id
const appName = overviewApp.name ?? appId
- const appModeLabel = getAppModeLabel(overviewApp.mode ?? 'workflow', tCommon)
+ const appModeLabel = getAppModeLabel(toAppMode(overviewApp.mode), tCommon)
const webappAccessUrl = webappUrl(overview?.access?.webappUrl)
const cliUrl = overview?.access?.cliUrl
const apiUrl = overview?.access?.apiUrl ?? accessConfig?.developerApi?.apiUrl
diff --git a/web/features/deployments/detail/settings-tab.tsx b/web/features/deployments/detail/settings-tab.tsx
index d039df3931..52ca4926d8 100644
--- a/web/features/deployments/detail/settings-tab.tsx
+++ b/web/features/deployments/detail/settings-tab.tsx
@@ -21,19 +21,16 @@ import { deployedRows } from '../utils'
type SettingsFormProps = {
app: AppInstanceBasicInfo
settings?: GetAppInstanceSettingsReply
- onSave: (patch: Pick
) => Promise
}
type DeleteInstanceControlProps = {
- appId: string
- appName: string
+ app: AppInstanceBasicInfo
settings?: GetAppInstanceSettingsReply
hasDeployments: boolean
}
function DeleteInstanceControl({
- appId,
- appName,
+ app,
settings,
hasDeployments,
}: DeleteInstanceControlProps) {
@@ -42,9 +39,14 @@ function DeleteInstanceControl({
const deleteInstance = useMutation(consoleQuery.enterprise.appDeploy.deleteAppInstance.mutationOptions())
const [isDeleting, setIsDeleting] = useState(false)
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
+ const appId = app.id
+ const appName = app.name ?? appId ?? ''
const canDelete = !hasDeployments && Boolean(settings) && settings?.deleteGuard?.canDelete !== false
const handleDelete = () => {
+ if (!appId)
+ return
+
void (async () => {
setIsDeleting(true)
try {
@@ -114,8 +116,9 @@ function DeleteInstanceControl({
)
}
-function SettingsForm({ app, settings, onSave }: SettingsFormProps) {
+function SettingsForm({ app, settings }: SettingsFormProps) {
const { t } = useTranslation('deployments')
+ const updateInstance = useMutation(consoleQuery.enterprise.appDeploy.updateAppInstance.mutationOptions())
const appName = app.name ?? app.id ?? ''
const [name, setName] = useState(settings?.name ?? appName)
const [description, setDescription] = useState(settings?.description ?? app.description ?? '')
@@ -125,14 +128,20 @@ function SettingsForm({ app, settings, onSave }: SettingsFormProps) {
const canSave = Boolean(name.trim() && (name !== initialName || description !== initialDescription) && !isSaving)
const handleSave = () => {
- if (!canSave)
+ const appId = app.id
+ if (!canSave || !appId)
return
void (async () => {
setIsSaving(true)
try {
- await onSave({
- name: name.trim(),
- description: description.trim() || undefined,
+ await updateInstance.mutateAsync({
+ params: {
+ appInstanceId: appId,
+ },
+ body: {
+ name: name.trim(),
+ description: description.trim() || undefined,
+ },
})
toast.success(t('settings.updated'))
}
@@ -194,7 +203,6 @@ function SettingsForm({ app, settings, onSave }: SettingsFormProps) {
export function SettingsTab({ instanceId }: {
instanceId: string
}) {
- const updateInstance = useMutation(consoleQuery.enterprise.appDeploy.updateAppInstance.mutationOptions())
const appInput = { params: { appInstanceId: instanceId } }
const { data: overview } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceOverview.queryOptions({
input: appInput,
@@ -220,18 +228,9 @@ export function SettingsTab({ instanceId }: {
key={formKey}
app={app}
settings={settingsQuery.data}
- onSave={async (patch) => {
- await updateInstance.mutateAsync({
- params: {
- appInstanceId: instanceId,
- },
- body: patch,
- })
- }}
/>
diff --git a/web/features/deployments/list/instance-card.tsx b/web/features/deployments/list/instance-card.tsx
index 97ee9deef4..0baac1ade5 100644
--- a/web/features/deployments/list/instance-card.tsx
+++ b/web/features/deployments/list/instance-card.tsx
@@ -1,7 +1,6 @@
'use client'
import type { AppInstanceCard } from '@dify/contracts/enterprise/types.gen'
-import type { AppModeEnum } from '@/types/app'
import { cn } from '@langgenius/dify-ui/cn'
import {
DropdownMenu,
@@ -20,6 +19,7 @@ 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'
export function InstanceCard({ app }: {
app: AppInstanceCard
@@ -32,7 +32,7 @@ export function InstanceCard({ app }: {
const appId = app.id
const appName = app.name ?? appId
- const appMode = app.mode ?? 'workflow'
+ const appMode = toAppMode(app.mode)
const detailHref = `/deployments/${appId}/overview`
const statusCount = (status: string) =>
@@ -128,7 +128,7 @@ export function InstanceCard({ app }: {
background={app.iconBackground}
/>
diff --git a/web/features/deployments/nav/index.tsx b/web/features/deployments/nav/index.tsx
index 07977cddd3..18165e58ea 100644
--- a/web/features/deployments/nav/index.tsx
+++ b/web/features/deployments/nav/index.tsx
@@ -2,7 +2,6 @@
import type { AppInstanceBasicInfo, AppInstanceCard } from '@dify/contracts/enterprise/types.gen'
import type { NavItem } from '@/app/components/header/nav/nav-selector'
-import type { AppModeEnum } from '@/types/app'
import { skipToken, useQuery } from '@tanstack/react-query'
import { useSetAtom } from 'jotai'
import { useTranslation } from 'react-i18next'
@@ -11,6 +10,7 @@ import { useParams, useRouter, useSelectedLayoutSegment } from '@/next/navigatio
import { consoleQuery } from '@/service/client'
import { SOURCE_APPS_PAGE_SIZE } from '../data'
import { openCreateInstanceModalAtom } from '../store'
+import { toAppMode } from '../utils'
function navItemFromListApp(app: AppInstanceCard): NavItem[] {
if (!app.id || !app.name)
@@ -24,7 +24,7 @@ function navItemFromListApp(app: AppInstanceCard): NavItem[] {
icon: app.icon ?? '',
icon_background: app.iconBackground ?? null,
icon_url: null,
- mode: app.mode as AppModeEnum | undefined,
+ mode: toAppMode(app.mode),
}]
}
@@ -42,7 +42,7 @@ function navItemFromOverview(instance?: AppInstanceBasicInfo): NavItem | undefin
icon: instance.icon ?? '',
icon_background: instance.iconBackground ?? null,
icon_url: null,
- mode: instance.mode as AppModeEnum | undefined,
+ mode: toAppMode(instance.mode),
}
}
diff --git a/web/features/deployments/store.ts b/web/features/deployments/store.ts
index faf8e63a1e..59fe2e41d3 100644
--- a/web/features/deployments/store.ts
+++ b/web/features/deployments/store.ts
@@ -13,6 +13,11 @@ type OpenRollbackParams = {
deploymentId?: string
}
+type CreatedDeveloperApiToken = {
+ appId: string
+ token: string
+}
+
export const deployDrawerOpenAtom = atom(false)
export const deployDrawerAppInstanceIdAtom = atom(undefined)
export const deployDrawerEnvironmentIdAtom = atom(undefined)
@@ -25,6 +30,7 @@ export const rollbackModalDeploymentIdAtom = atom(undefined)
export const rollbackModalTargetReleaseIdAtom = atom(undefined)
export const createInstanceModalOpenAtom = atom(false)
+export const createdDeveloperApiTokenAtom = atom(undefined)
export const openDeployDrawerAtom = atom(null, (_get, set, params: OpenDeployDrawerParams) => {
set(deployDrawerAppInstanceIdAtom, params.appInstanceId)
diff --git a/web/features/deployments/utils.ts b/web/features/deployments/utils.ts
index c492bdadf5..67b8d170ca 100644
--- a/web/features/deployments/utils.ts
+++ b/web/features/deployments/utils.ts
@@ -11,9 +11,16 @@ import type {
EnvironmentOption,
} from './types'
import { PUBLIC_API_PREFIX } from '@/config'
+import { AppModeEnum } from '@/types/app'
export type DeploymentUiStatus = 'ready' | 'deploying' | 'deploy_failed'
+const appModeValues = new Set(Object.values(AppModeEnum))
+
+export function toAppMode(mode?: string): AppModeEnum {
+ return appModeValues.has(mode ?? '') ? (mode as AppModeEnum) : AppModeEnum.WORKFLOW
+}
+
export function formatDate(value?: string) {
if (!value)
return '—'