mirror of
https://github.com/langgenius/dify.git
synced 2026-05-09 04:36:31 +08:00
tweaks
This commit is contained in:
parent
ea6e7a9ed0
commit
3f36471ec0
@ -1,5 +1,4 @@
|
||||
'use client'
|
||||
import type { AppInfo, AppMode } from '../types'
|
||||
import type { App, AppModeEnum } from '@/types/app'
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
@ -18,11 +17,22 @@ import { useDeploymentsStore } from '../store'
|
||||
|
||||
const MAX_STUDIO_SOURCE_APPS = 100
|
||||
|
||||
function toStudioSourceAppInfo(app: App): AppInfo {
|
||||
type StudioSourceApp = {
|
||||
id: string
|
||||
name: string
|
||||
mode: string
|
||||
iconType?: App['icon_type']
|
||||
icon?: string
|
||||
iconBackground?: string
|
||||
iconUrl?: string | null
|
||||
description?: string
|
||||
}
|
||||
|
||||
function toStudioSourceAppInfo(app: App): StudioSourceApp {
|
||||
return {
|
||||
id: app.id,
|
||||
name: app.name,
|
||||
mode: (app.mode || 'workflow') as AppMode,
|
||||
mode: app.mode || 'workflow',
|
||||
iconType: app.icon_type,
|
||||
icon: app.icon,
|
||||
iconBackground: app.icon_background ?? undefined,
|
||||
@ -32,13 +42,13 @@ function toStudioSourceAppInfo(app: App): AppInfo {
|
||||
}
|
||||
|
||||
type AppPickerProps = {
|
||||
apps: AppInfo[]
|
||||
apps: StudioSourceApp[]
|
||||
isLoading: boolean
|
||||
value: string
|
||||
onChange: (appId: string) => void
|
||||
}
|
||||
|
||||
export function AppPicker({ apps, isLoading, value, onChange }: AppPickerProps) {
|
||||
function AppPicker({ apps, isLoading, value, onChange }: AppPickerProps) {
|
||||
const { t } = useTranslation('deployments')
|
||||
const [open, setOpen] = useState(false)
|
||||
const [keywords, setKeywords] = useState('')
|
||||
|
||||
@ -21,7 +21,6 @@ import {
|
||||
environmentOptionsFromOptionsReply,
|
||||
releaseCommit,
|
||||
releaseLabel,
|
||||
toAppInfoFromOverview,
|
||||
} from '../utils'
|
||||
|
||||
function InfoRow({ label, value }: {
|
||||
@ -77,7 +76,9 @@ export function RollbackModal() {
|
||||
const currentRelease = activeRelease(currentRow)
|
||||
const environment = currentRow?.environment
|
||||
?? environmentOptions.find(env => env.id === modal.environmentId)
|
||||
const app = toAppInfoFromOverview(overview?.instance)
|
||||
const app = overview?.instance
|
||||
const appName = app?.name ?? '-'
|
||||
const sourceAppName = app?.sourceAppName ?? appName
|
||||
|
||||
const confirm = () => {
|
||||
if (!modal.appInstanceId || !modal.environmentId || !modal.targetReleaseId)
|
||||
@ -110,8 +111,8 @@ export function RollbackModal() {
|
||||
</AlertDialogDescription>
|
||||
|
||||
<div className="mt-2 flex flex-col gap-2 rounded-lg border border-components-panel-border bg-components-panel-bg-blur p-3">
|
||||
<InfoRow label={t('rollback.instance')} value={app?.name ?? '-'} />
|
||||
<InfoRow label={t('rollback.sourceApp')} value={app?.name ?? '-'} />
|
||||
<InfoRow label={t('rollback.instance')} value={appName} />
|
||||
<InfoRow label={t('rollback.sourceApp')} value={sourceAppName} />
|
||||
<InfoRow label={t('rollback.environment')} value={environmentName(environment)} />
|
||||
<InfoRow
|
||||
label={t('rollback.currentRelease')}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import type { AppInstanceBasicInfo } from '@dify/contracts/enterprise/types.gen'
|
||||
import type { ComponentProps, PropsWithoutRef } from 'react'
|
||||
import type { AppInfo } from '../types'
|
||||
import type { InstanceDetailTabKey } from './tabs'
|
||||
import type { NavIcon } from '@/app/components/app-sidebar/nav-link'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
@ -81,7 +81,7 @@ type DeploymentSidebarProps = {
|
||||
instanceName: string
|
||||
instanceDescription?: string
|
||||
appModeLabel: string
|
||||
app?: AppInfo
|
||||
app?: AppInstanceBasicInfo
|
||||
}
|
||||
|
||||
export function DeploymentSidebar({
|
||||
@ -140,10 +140,9 @@ export function DeploymentSidebar({
|
||||
? (
|
||||
<AppIcon
|
||||
size={expand ? 'large' : 'medium'}
|
||||
iconType={app.iconType}
|
||||
iconType="emoji"
|
||||
icon={app.icon}
|
||||
background={app.iconBackground}
|
||||
imageUrl={app.iconUrl}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
|
||||
@ -11,7 +11,6 @@ import { useRouter, useSelectedLayoutSegment } from '@/next/navigation'
|
||||
import { consoleQuery } from '@/service/client'
|
||||
import { DeployDrawer } from '../components/deploy-drawer'
|
||||
import { RollbackModal } from '../components/rollback-modal'
|
||||
import { toAppInfoFromOverview } from '../utils'
|
||||
import { DeploymentSidebar } from './deployment-sidebar'
|
||||
import { isInstanceDetailTabKey } from './tabs'
|
||||
|
||||
@ -33,9 +32,10 @@ export function InstanceDetail({ instanceId, children }: {
|
||||
|
||||
useDocumentTitle(t('documentTitle.detail'))
|
||||
|
||||
const app = toAppInfoFromOverview(overviewQuery.data?.instance)
|
||||
const app = overviewQuery.data?.instance
|
||||
const appId = app?.id
|
||||
|
||||
if (!app && overviewQuery.isLoading) {
|
||||
if (!appId && overviewQuery.isLoading) {
|
||||
return (
|
||||
<div className="flex h-full items-center justify-center bg-background-body">
|
||||
<span className="h-6 w-6 animate-spin rounded-full border-2 border-components-panel-border border-t-transparent" />
|
||||
@ -43,7 +43,7 @@ export function InstanceDetail({ instanceId, children }: {
|
||||
)
|
||||
}
|
||||
|
||||
if (!app) {
|
||||
if (!appId || !app) {
|
||||
return (
|
||||
<div className="flex h-full flex-col items-center justify-center gap-3 bg-background-body">
|
||||
<div className="title-xl-semi-bold text-text-primary">{t('detail.notFound')}</div>
|
||||
@ -54,14 +54,15 @@ export function InstanceDetail({ instanceId, children }: {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
const appModeLabel = app ? getAppModeLabel(app.mode, tCommon) : t('detail.sourceAppDeleted')
|
||||
const appName = app.name ?? appId
|
||||
const appModeLabel = getAppModeLabel(app.mode ?? 'workflow', tCommon)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="relative flex h-full overflow-hidden rounded-t-2xl shadow-[0_0_5px_rgba(0,0,0,0.05),0_0_2px_-1px_rgba(0,0,0,0.03)]">
|
||||
<DeploymentSidebar
|
||||
instanceId={instanceId}
|
||||
instanceName={app.name}
|
||||
instanceId={appId}
|
||||
instanceName={appName}
|
||||
instanceDescription={app.description}
|
||||
appModeLabel={appModeLabel}
|
||||
app={app}
|
||||
|
||||
@ -12,7 +12,6 @@ import { DEPLOYMENT_PAGE_SIZE } from '../data'
|
||||
import { useDeploymentsStore } from '../store'
|
||||
import {
|
||||
releaseLabel,
|
||||
toAppInfoFromOverview,
|
||||
webappUrl,
|
||||
} from '../utils'
|
||||
|
||||
@ -112,20 +111,21 @@ export function OverviewTab({ instanceId }: {
|
||||
input,
|
||||
}))
|
||||
const openDeployDrawer = useDeploymentsStore(state => state.openDeployDrawer)
|
||||
const app = toAppInfoFromOverview(overview?.instance)
|
||||
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) ?? []
|
||||
const canCreateRelease = overviewApp?.canCreateRelease ?? true
|
||||
|
||||
if (!app)
|
||||
if (!overviewApp?.id)
|
||||
return null
|
||||
|
||||
const appId = overviewApp.id
|
||||
const appName = overviewApp.name ?? appId
|
||||
const switchTab = (tab: SwitchableTab) => {
|
||||
router.push(`/deployments/${instanceId}/${tab}`)
|
||||
router.push(`/deployments/${appId}/${tab}`)
|
||||
}
|
||||
|
||||
const appModeLabel = getAppModeLabel(overviewApp?.mode ?? app.mode, tCommon)
|
||||
const appModeLabel = getAppModeLabel(overviewApp.mode ?? 'workflow', tCommon)
|
||||
const webappAccessUrl = webappUrl(overview?.access?.webappUrl)
|
||||
const cliUrl = overview?.access?.cliUrl
|
||||
const apiUrl = overview?.access?.apiUrl ?? accessConfig?.developerApi?.apiUrl
|
||||
@ -135,9 +135,9 @@ export function OverviewTab({ instanceId }: {
|
||||
<div className="flex w-full max-w-[960px] flex-col gap-5 p-6">
|
||||
<Section title={t('overview.basicInfo')}>
|
||||
<div className="flex flex-col divide-y divide-divider-subtle">
|
||||
<InfoRow label={t('overview.name')} value={overviewApp?.name ?? app.name} />
|
||||
<InfoRow label={t('overview.description')} value={overviewApp?.description ?? app.description ?? t('overview.emptyValue')} />
|
||||
<InfoRow label={t('overview.sourceApp')} value={overviewApp?.sourceAppName ?? app.sourceAppName ?? app.name} />
|
||||
<InfoRow label={t('overview.name')} value={appName} />
|
||||
<InfoRow label={t('overview.description')} value={overviewApp.description ?? t('overview.emptyValue')} />
|
||||
<InfoRow label={t('overview.sourceApp')} value={overviewApp.sourceAppName ?? appName} />
|
||||
<InfoRow label={t('overview.appMode')} value={appModeLabel} />
|
||||
</div>
|
||||
</Section>
|
||||
@ -169,7 +169,7 @@ export function OverviewTab({ instanceId }: {
|
||||
switchTab('versions')
|
||||
return
|
||||
}
|
||||
openDeployDrawer({ appInstanceId: app.id })
|
||||
openDeployDrawer({ appInstanceId: appId })
|
||||
}}
|
||||
>
|
||||
{releaseRows.length === 0 ? t('overview.createRelease') : t('overview.deploy')}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
'use client'
|
||||
import type { AppInfo } from '../types'
|
||||
import type { AppInstanceBasicInfo } from '@dify/contracts/enterprise/types.gen'
|
||||
import type { GetAppInstanceSettingsReply } from '@/features/deployments/types'
|
||||
import {
|
||||
AlertDialog,
|
||||
@ -17,27 +17,25 @@ import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useRouter } from '@/next/navigation'
|
||||
import { consoleQuery } from '@/service/client'
|
||||
import {
|
||||
deployedRows,
|
||||
toAppInfoFromOverview,
|
||||
} from '../utils'
|
||||
import { deployedRows } from '../utils'
|
||||
|
||||
type SettingsFormProps = {
|
||||
app: AppInfo
|
||||
app: AppInstanceBasicInfo
|
||||
settings?: GetAppInstanceSettingsReply
|
||||
hasDeployments: boolean
|
||||
onSave: (patch: Pick<AppInfo, 'name' | 'description'>) => Promise<void>
|
||||
onSave: (patch: Pick<AppInstanceBasicInfo, 'name' | 'description'>) => Promise<void>
|
||||
onDelete: () => Promise<void>
|
||||
}
|
||||
|
||||
function SettingsForm({ app, settings, hasDeployments, onSave, onDelete }: SettingsFormProps) {
|
||||
const { t } = useTranslation('deployments')
|
||||
const [name, setName] = useState(settings?.name ?? app.name)
|
||||
const appName = app.name ?? app.id ?? ''
|
||||
const [name, setName] = useState(settings?.name ?? appName)
|
||||
const [description, setDescription] = useState(settings?.description ?? app.description ?? '')
|
||||
const [isSaving, setIsSaving] = useState(false)
|
||||
const [isDeleting, setIsDeleting] = useState(false)
|
||||
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
|
||||
const initialName = settings?.name ?? app.name
|
||||
const initialName = settings?.name ?? appName
|
||||
const initialDescription = settings?.description ?? app.description ?? ''
|
||||
const canSave = Boolean(name.trim() && (name !== initialName || description !== initialDescription) && !isSaving)
|
||||
const canDelete = !hasDeployments && Boolean(settings) && settings?.deleteGuard?.canDelete !== false
|
||||
@ -153,7 +151,7 @@ function SettingsForm({ app, settings, hasDeployments, onSave, onDelete }: Setti
|
||||
{t('settings.deleteConfirmTitle')}
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription className="system-md-regular text-text-tertiary">
|
||||
{t('settings.deleteConfirmDesc', { name: app.name })}
|
||||
{t('settings.deleteConfirmDesc', { name: appName })}
|
||||
</AlertDialogDescription>
|
||||
</div>
|
||||
<AlertDialogActions>
|
||||
@ -183,16 +181,17 @@ export function SettingsTab({ instanceId }: {
|
||||
const { data: environmentDeployments } = useQuery(consoleQuery.enterprise.appDeploy.listRuntimeInstances.queryOptions({
|
||||
input: appInput,
|
||||
}))
|
||||
const app = toAppInfoFromOverview(overview?.instance)
|
||||
const app = overview?.instance
|
||||
const settingsQuery = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceSettings.queryOptions({
|
||||
input: appInput,
|
||||
}))
|
||||
|
||||
if (!app)
|
||||
if (!app?.id)
|
||||
return null
|
||||
|
||||
const hasDeployments = deployedRows(environmentDeployments?.data).length > 0
|
||||
const formKey = `${app.id}-${settingsQuery.data?.name ?? app.name}-${settingsQuery.data?.description ?? app.description ?? ''}`
|
||||
const appName = app.name ?? app.id
|
||||
const formKey = `${app.id}-${settingsQuery.data?.name ?? appName}-${settingsQuery.data?.description ?? app.description ?? ''}`
|
||||
|
||||
return (
|
||||
<SettingsForm
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import type * as EnterpriseContract from '@dify/contracts/enterprise/types.gen'
|
||||
import type { AppIconType } from '@/types/app'
|
||||
|
||||
type Timestamp = string
|
||||
|
||||
@ -8,25 +7,8 @@ export type EnvironmentHealth = 'ready' | 'degraded'
|
||||
|
||||
export type DeployStatus = 'ready' | 'deploying' | 'deploy_failed'
|
||||
|
||||
export type AppMode = 'chat' | 'agent-chat' | 'workflow' | 'completion' | 'advanced-chat' | (string & {})
|
||||
|
||||
export type AccessPermissionKind = 'organization' | 'specific' | 'anyone'
|
||||
|
||||
export type AppInfo = {
|
||||
id: string
|
||||
name: string
|
||||
mode: AppMode
|
||||
iconType?: AppIconType | null
|
||||
icon?: string
|
||||
iconBackground?: string
|
||||
iconUrl?: string | null
|
||||
description?: string
|
||||
sourceAppId?: string
|
||||
sourceAppName?: string
|
||||
sourceAppAvailable?: boolean
|
||||
canCreateRelease?: boolean
|
||||
}
|
||||
|
||||
export type ConsoleEnvironmentSummary = EnterpriseContract.ConsoleEnvironment & {
|
||||
backend?: string
|
||||
description?: string
|
||||
@ -44,8 +26,6 @@ type ConsoleUser = EnterpriseContract.ConsoleUser & {
|
||||
displayName?: string
|
||||
}
|
||||
|
||||
export type AppInstanceOverview = EnterpriseContract.AppInstanceBasicInfo
|
||||
|
||||
export type RuntimeBindingDisplay = EnterpriseContract.ReleaseRuntimeBinding & {
|
||||
displayName?: string
|
||||
maskedValue?: string
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
import type {
|
||||
AccessPermissionKind,
|
||||
AppInfo,
|
||||
AppInstanceOverview,
|
||||
AppMode,
|
||||
ConsoleEnvironmentSummary,
|
||||
ConsoleReleaseSummary,
|
||||
EnvironmentDeploymentRow,
|
||||
@ -134,25 +131,6 @@ export function deployedRows(rows?: EnvironmentDeploymentRow[]) {
|
||||
}) ?? []
|
||||
}
|
||||
|
||||
export function toAppInfoFromOverview(instance?: AppInstanceOverview): AppInfo | undefined {
|
||||
if (!instance?.id)
|
||||
return undefined
|
||||
|
||||
return {
|
||||
id: instance.id,
|
||||
name: instance.name ?? instance.id,
|
||||
mode: (instance.mode || 'workflow') as AppMode,
|
||||
iconType: 'emoji',
|
||||
icon: instance.icon,
|
||||
iconBackground: instance.iconBackground,
|
||||
description: instance.description ?? undefined,
|
||||
sourceAppId: instance.sourceAppId,
|
||||
sourceAppName: instance.sourceAppName,
|
||||
sourceAppAvailable: instance.sourceAppAvailable,
|
||||
canCreateRelease: instance.canCreateRelease,
|
||||
}
|
||||
}
|
||||
|
||||
export function environmentOptionsFromOptionsReply(response?: ListDeploymentEnvironmentOptionsReply): EnvironmentOption[] {
|
||||
return response?.environments
|
||||
?.filter(environment => environment.id)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user