This commit is contained in:
Stephen Zhou 2026-05-07 18:09:52 +08:00
parent b70c9d7835
commit 23ffbd2532
No known key found for this signature in database
40 changed files with 291 additions and 277 deletions

View File

@ -1,12 +1,10 @@
import AccessTab from '@/features/deployments/detail/access-tab'
import { AccessTab } from '@/features/deployments/detail/access-tab'
type PageProps = {
params: Promise<{ instanceId: string }>
}
const InstanceDetailAccessPage = async ({ params }: PageProps) => {
export default async function InstanceDetailAccessPage({ params }: PageProps) {
const { instanceId } = await params
return <AccessTab instanceId={instanceId} />
}
export default InstanceDetailAccessPage

View File

@ -1,12 +1,10 @@
import DeployTab from '@/features/deployments/detail/deploy-tab'
import { DeployTab } from '@/features/deployments/detail/deploy-tab'
type PageProps = {
params: Promise<{ instanceId: string }>
}
const InstanceDetailDeployPage = async ({ params }: PageProps) => {
export default async function InstanceDetailDeployPage({ params }: PageProps) {
const { instanceId } = await params
return <DeployTab instanceId={instanceId} />
}
export default InstanceDetailDeployPage

View File

@ -1,12 +1,12 @@
import type { ReactNode } from 'react'
import InstanceDetail from '@/features/deployments/detail'
import { InstanceDetail } from '@/features/deployments/detail'
type LayoutProps = {
children: ReactNode
params: Promise<{ instanceId: string }>
}
const InstanceDetailLayout = async ({ children, params }: LayoutProps) => {
export default async function InstanceDetailLayout({ children, params }: LayoutProps) {
const { instanceId } = await params
return (
@ -15,5 +15,3 @@ const InstanceDetailLayout = async ({ children, params }: LayoutProps) => {
</InstanceDetail>
)
}
export default InstanceDetailLayout

View File

@ -1,12 +1,10 @@
import OverviewTab from '@/features/deployments/detail/overview-tab'
import { OverviewTab } from '@/features/deployments/detail/overview-tab'
type PageProps = {
params: Promise<{ instanceId: string }>
}
const InstanceDetailOverviewPage = async ({ params }: PageProps) => {
export default async function InstanceDetailOverviewPage({ params }: PageProps) {
const { instanceId } = await params
return <OverviewTab instanceId={instanceId} />
}
export default InstanceDetailOverviewPage

View File

@ -4,9 +4,7 @@ type PageProps = {
params: Promise<{ instanceId: string }>
}
const InstanceDetailPage = async ({ params }: PageProps) => {
export default async function InstanceDetailPage({ params }: PageProps) {
const { instanceId } = await params
redirect(`/deployments/${instanceId}/overview`)
}
export default InstanceDetailPage

View File

@ -1,12 +1,10 @@
import SettingsTab from '@/features/deployments/detail/settings-tab'
import { SettingsTab } from '@/features/deployments/detail/settings-tab'
type PageProps = {
params: Promise<{ instanceId: string }>
}
const InstanceDetailSettingsPage = async ({ params }: PageProps) => {
export default async function InstanceDetailSettingsPage({ params }: PageProps) {
const { instanceId } = await params
return <SettingsTab instanceId={instanceId} />
}
export default InstanceDetailSettingsPage

View File

@ -1,12 +1,10 @@
import VersionsTab from '@/features/deployments/detail/versions-tab'
import { VersionsTab } from '@/features/deployments/detail/versions-tab'
type PageProps = {
params: Promise<{ instanceId: string }>
}
const InstanceDetailVersionsPage = async ({ params }: PageProps) => {
export default async function InstanceDetailVersionsPage({ params }: PageProps) {
const { instanceId } = await params
return <VersionsTab instanceId={instanceId} />
}
export default InstanceDetailVersionsPage

View File

@ -1,12 +1,10 @@
'use client'
import { useTranslation } from 'react-i18next'
import DeploymentsMain from '@/features/deployments/list'
import { DeploymentsMain } from '@/features/deployments/list'
import useDocumentTitle from '@/hooks/use-document-title'
const DeploymentsPage = () => {
export default function DeploymentsPage() {
const { t } = useTranslation('deployments')
useDocumentTitle(t('documentTitle.list'))
return <DeploymentsMain />
}
export default DeploymentsPage

View File

@ -9,7 +9,7 @@ type UseWorkflowOnlineUsersParams = {
enabled: boolean
}
const normalizeWorkflowOnlineUsers = (response?: WorkflowOnlineUsersResponse): WorkflowOnlineUsersMap => {
function normalizeWorkflowOnlineUsers(response?: WorkflowOnlineUsersResponse): WorkflowOnlineUsersMap {
const data = response?.data
if (!data)
@ -30,10 +30,10 @@ const normalizeWorkflowOnlineUsers = (response?: WorkflowOnlineUsersResponse): W
}, {})
}
export const useWorkflowOnlineUsers = ({
export function useWorkflowOnlineUsers({
appIds,
enabled,
}: UseWorkflowOnlineUsersParams) => {
}: UseWorkflowOnlineUsersParams) {
const shouldFetch = enabled && appIds.length > 0
const { data: onlineUsersMap = {} } = useQuery(consoleQuery.apps.workflowOnlineUsers.queryOptions({
input: {

View File

@ -8,7 +8,7 @@ import { useAppContext } from '@/context/app-context'
import { useModalContext } from '@/context/modal-context'
import { useProviderContext } from '@/context/provider-context'
import { WorkspaceProvider } from '@/context/workspace-context-provider'
import DeploymentsNav from '@/features/deployments/nav'
import { DeploymentsNav } from '@/features/deployments/nav'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import Link from '@/next/link'
import { systemFeaturesQueryOptions } from '@/service/system-features'

View File

@ -1,5 +1,4 @@
'use client'
import type { FC } from 'react'
import type { AppInfo, AppMode } from '../types'
import type { App, AppModeEnum } from '@/types/app'
import { Button } from '@langgenius/dify-ui/button'
@ -39,7 +38,7 @@ type AppPickerProps = {
onChange: (appId: string) => void
}
export const AppPicker: FC<AppPickerProps> = ({ apps, isLoading, value, onChange }) => {
export function AppPicker({ apps, isLoading, value, onChange }: AppPickerProps) {
const { t } = useTranslation('deployments')
const [open, setOpen] = useState(false)
const [keywords, setKeywords] = useState('')
@ -204,7 +203,11 @@ export const AppPicker: FC<AppPickerProps> = ({ apps, isLoading, value, onChange
)
}
const CreateInstanceForm: FC<{ onClose: () => void }> = ({ onClose }) => {
type CreateInstanceFormProps = {
onClose: () => void
}
function CreateInstanceForm({ onClose }: CreateInstanceFormProps) {
const { t } = useTranslation('deployments')
const router = useRouter()
const createInstance = useMutation(consoleQuery.enterprise.appDeploy.createAppInstance.mutationOptions())
@ -310,7 +313,7 @@ const CreateInstanceForm: FC<{ onClose: () => void }> = ({ onClose }) => {
)
}
const CreateInstanceModal: FC = () => {
export function CreateInstanceModal() {
const modal = useDeploymentsStore(state => state.createInstanceModal)
const closeModal = useDeploymentsStore(state => state.closeCreateInstanceModal)
@ -326,5 +329,3 @@ const CreateInstanceModal: FC = () => {
</Dialog>
)
}
export default CreateInstanceModal

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import { Dialog, DialogCloseButton, DialogContent } from '@langgenius/dify-ui/dialog'
import { toast } from '@langgenius/dify-ui/toast'
import { skipToken, useMutation, useQuery } from '@tanstack/react-query'
@ -12,7 +11,7 @@ import { useDeploymentsStore } from '../store'
import { environmentOptionsFromOptionsReply } from '../utils'
import { DeployForm } from './deploy-drawer/form'
const DeployDrawer: FC = () => {
export function DeployDrawer() {
const { t } = useTranslation('deployments')
const drawer = useDeploymentsStore(state => state.deployDrawer)
const drawerAppInstanceId = drawer.appInstanceId
@ -95,5 +94,3 @@ const DeployDrawer: FC = () => {
</Dialog>
)
}
export default DeployDrawer

View File

@ -1,7 +1,6 @@
'use client'
import type { DeploymentBindingOptionSlot, DeploymentRuntimeBinding } from '@dify/contracts/enterprise/types.gen'
import type { FC } from 'react'
import type { ConsoleReleaseSummary, EnvironmentOption } from '@/features/deployments/types'
import { Button } from '@langgenius/dify-ui/button'
import { DialogDescription, DialogTitle } from '@langgenius/dify-ui/dialog'
@ -54,12 +53,15 @@ type BindingOptionsPanelProps = {
onChange: (slot: string, value: string) => void
}
const isEnvBindingSlot = (slot: DeploymentBindingOptionSlot) =>
(slot.kind?.toLowerCase() ?? '').includes('env')
function isEnvBindingSlot(slot: DeploymentBindingOptionSlot) {
return (slot.kind?.toLowerCase() ?? '').includes('env')
}
const bindingSlotKey = (slot: DeploymentBindingOptionSlot) => slot.slot ?? ''
function bindingSlotKey(slot: DeploymentBindingOptionSlot) {
return slot.slot ?? ''
}
const bindingCandidateOptions = (slot: DeploymentBindingOptionSlot): BindingSelectOption[] => {
function bindingCandidateOptions(slot: DeploymentBindingOptionSlot): BindingSelectOption[] {
if (isEnvBindingSlot(slot)) {
return (slot.envVarCandidates ?? [])
.filter(candidate => candidate.envVarId)
@ -84,13 +86,11 @@ const bindingCandidateOptions = (slot: DeploymentBindingOptionSlot): BindingSele
}))
}
const hasMissingRequiredBinding = (slot: DeploymentBindingOptionSlot, selectedValue?: string) =>
Boolean(slot.required && !selectedValue)
function hasMissingRequiredBinding(slot: DeploymentBindingOptionSlot, selectedValue?: string) {
return Boolean(slot.required && !selectedValue)
}
const selectedDeploymentBindings = (
slots: DeploymentBindingOptionSlot[],
selections: BindingSelections,
): DeploymentRuntimeBinding[] => {
function selectedDeploymentBindings(slots: DeploymentBindingOptionSlot[], selections: BindingSelections): DeploymentRuntimeBinding[] {
return slots
.map((slot): DeploymentRuntimeBinding | undefined => {
const slotKey = bindingSlotKey(slot)
@ -105,13 +105,13 @@ const selectedDeploymentBindings = (
.filter((binding): binding is DeploymentRuntimeBinding => Boolean(binding))
}
const BindingOptionsPanel: FC<BindingOptionsPanelProps> = ({
function BindingOptionsPanel({
slots,
selections,
isLoading,
hasError,
onChange,
}) => {
}: BindingOptionsPanelProps) {
const { t } = useTranslation('deployments')
if (isLoading) {
@ -192,7 +192,7 @@ const BindingOptionsPanel: FC<BindingOptionsPanelProps> = ({
)
}
export const DeployForm: FC<DeployFormProps> = ({
export function DeployForm({
appInstanceId,
environments,
releases,
@ -202,7 +202,7 @@ export const DeployForm: FC<DeployFormProps> = ({
isSubmitting,
onCancel,
onSubmit,
}) => {
}: DeployFormProps) {
const { t } = useTranslation('deployments')
const presetRelease = useMemo(
() => presetReleaseId ? releases.find(r => r.id === presetReleaseId) : undefined,

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import type { EnvironmentOption } from '@/features/deployments/types'
import { cn } from '@langgenius/dify-ui/cn'
import { Select, SelectContent, SelectItem, SelectItemIndicator, SelectItemText, SelectTrigger } from '@langgenius/dify-ui/select'
@ -14,15 +13,17 @@ type FieldProps = {
children: React.ReactNode
}
export const Field: FC<FieldProps> = ({ label, hint, children }) => (
<div className="flex flex-col gap-2">
<div className="flex items-center justify-between">
<div className="system-xs-medium-uppercase text-text-tertiary">{label}</div>
{hint && <span className="system-xs-regular text-text-quaternary">{hint}</span>}
export function Field({ label, hint, children }: FieldProps) {
return (
<div className="flex flex-col gap-2">
<div className="flex items-center justify-between">
<div className="system-xs-medium-uppercase text-text-tertiary">{label}</div>
{hint && <span className="system-xs-regular text-text-quaternary">{hint}</span>}
</div>
{children}
</div>
{children}
</div>
)
)
}
type SelectOption = {
value: string
@ -38,7 +39,7 @@ type SelectProps = {
placeholder?: string
}
export const DeploymentSelect: FC<SelectProps> = ({ value, onChange, options, placeholder }) => {
export function DeploymentSelect({ value, onChange, options, placeholder }: SelectProps) {
const { t } = useTranslation('deployments')
const selectedOption = options.find(option => option.value === value)
@ -79,13 +80,15 @@ export const DeploymentSelect: FC<SelectProps> = ({ value, onChange, options, pl
type EnvironmentRowProps = { env: EnvironmentOption }
export const EnvironmentRow: FC<EnvironmentRowProps> = ({ env }) => (
<div className="flex items-center justify-between rounded-lg border border-components-panel-border bg-components-panel-bg-blur px-3 py-2">
<div className="flex items-center gap-2">
<span className="system-sm-semibold text-text-primary">{environmentName(env)}</span>
<ModeBadge mode={environmentMode(env)} />
<HealthBadge health={environmentHealth(env)} />
export function EnvironmentRow({ env }: EnvironmentRowProps) {
return (
<div className="flex items-center justify-between rounded-lg border border-components-panel-border bg-components-panel-bg-blur px-3 py-2">
<div className="flex items-center gap-2">
<span className="system-sm-semibold text-text-primary">{environmentName(env)}</span>
<ModeBadge mode={environmentMode(env)} />
<HealthBadge health={environmentHealth(env)} />
</div>
<span className="system-xs-regular text-text-tertiary uppercase">{env.type ?? 'env'}</span>
</div>
<span className="system-xs-regular text-text-tertiary uppercase">{env.type ?? 'env'}</span>
</div>
)
)
}

View File

@ -1,5 +1,4 @@
'use client'
import type { FC } from 'react'
import {
AlertDialog,
AlertDialogActions,
@ -26,7 +25,12 @@ import {
toAppInfoFromOverview,
} from '../utils'
const InfoRow: FC<{ label: string, value: string }> = ({ label, value }) => {
type InfoRowProps = {
label: string
value: string
}
function InfoRow({ label, value }: InfoRowProps) {
return (
<div className="flex items-start justify-between gap-4">
<span className="system-xs-medium-uppercase text-text-tertiary">{label}</span>
@ -35,7 +39,7 @@ const InfoRow: FC<{ label: string, value: string }> = ({ label, value }) => {
)
}
const RollbackModal: FC = () => {
export function RollbackModal() {
const { t } = useTranslation('deployments')
const modal = useDeploymentsStore(state => state.rollbackModal)
const closeRollbackModal = useDeploymentsStore(state => state.closeRollbackModal)
@ -146,5 +150,3 @@ const RollbackModal: FC = () => {
</AlertDialog>
)
}
export default RollbackModal

View File

@ -1,5 +1,4 @@
'use client'
import type { FC } from 'react'
import type { DeployStatus, EnvironmentHealth, EnvironmentMode } from '../types'
import { cn } from '@langgenius/dify-ui/cn'
import { useTranslation } from 'react-i18next'
@ -23,7 +22,7 @@ const statusKey = {
const baseBadge = 'inline-flex items-center gap-1 rounded-md border px-2 py-0.5 system-xs-medium whitespace-nowrap'
export const StatusBadge: FC<StatusBadgeProps> = ({ status, className }) => {
export function StatusBadge({ status, className }: StatusBadgeProps) {
const { t } = useTranslation('deployments')
return (
<span className={cn(baseBadge, statusStyles[status], className)}>
@ -40,7 +39,7 @@ type ModeBadgeProps = {
className?: string
}
export const ModeBadge: FC<ModeBadgeProps> = ({ mode, className }) => {
export function ModeBadge({ mode, className }: ModeBadgeProps) {
const { t } = useTranslation('deployments')
const style = mode === 'shared'
? 'border-util-colors-green-green-200 bg-util-colors-green-green-50 text-util-colors-green-green-700'
@ -57,7 +56,7 @@ type HealthBadgeProps = {
className?: string
}
export const HealthBadge: FC<HealthBadgeProps> = ({ health, className }) => {
export function HealthBadge({ health, className }: HealthBadgeProps) {
const { t } = useTranslation('deployments')
const style = health === 'ready'
? 'border-util-colors-green-green-200 bg-util-colors-green-green-50 text-util-colors-green-green-700'

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import type {
AccessPermission,
AccessSubject,
@ -31,7 +30,7 @@ type AccessTabProps = {
instanceId: string
}
const AccessTab: FC<AccessTabProps> = ({ instanceId: appId }) => {
export function AccessTab({ instanceId: appId }: AccessTabProps) {
const appInput = { params: { appInstanceId: appId } }
const { data: accessConfig } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceAccess.queryOptions({
input: appInput,
@ -171,5 +170,3 @@ const AccessTab: FC<AccessTabProps> = ({ instanceId: appId }) => {
</div>
)
}
export default AccessTab

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import type { ConsoleEnvironmentSummary, DeveloperAPIKeySummary } from '@/features/deployments/types'
import { cn } from '@langgenius/dify-ui/cn'
import {
@ -20,7 +19,7 @@ type ApiKeyRowProps = {
onRevoke: () => void
}
export const ApiKeyRow: FC<ApiKeyRowProps> = ({ apiKey, onCopy, onRevoke }) => {
export function ApiKeyRow({ apiKey, onCopy, onRevoke }: ApiKeyRowProps) {
const { t } = useTranslation('deployments')
const [copied, setCopied] = useState(false)
const displayValue = apiKey.maskedKey || apiKey.maskedPrefix || apiKey.id || '—'
@ -80,7 +79,7 @@ type ApiKeyGenerateMenuProps = {
onGenerate: (environmentId: string) => void
}
export const ApiKeyGenerateMenu: FC<ApiKeyGenerateMenuProps> = ({ environments, onGenerate }) => {
export function ApiKeyGenerateMenu({ environments, onGenerate }: ApiKeyGenerateMenuProps) {
const { t } = useTranslation('deployments')
const [open, setOpen] = useState(false)
const selectableEnvironments = environments.filter(env => env.id)

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import type { WebAppAccessRow } from '@/features/deployments/types'
import { Switch } from '@langgenius/dify-ui/switch'
import { useTranslation } from 'react-i18next'
@ -15,13 +14,13 @@ type AccessChannelsSectionProps = {
onToggle: (enabled: boolean) => void
}
export const AccessChannelsSection: FC<AccessChannelsSectionProps> = ({
export function AccessChannelsSection({
runEnabled,
webappRows,
cliDomain,
cliDocsUrl,
onToggle,
}) => {
}: AccessChannelsSectionProps) {
const { t } = useTranslation('deployments')
return (

View File

@ -1,6 +1,6 @@
'use client'
import type { FC, ReactNode } from 'react'
import type { ReactNode } from 'react'
import { cn } from '@langgenius/dify-ui/cn'
import { toast } from '@langgenius/dify-ui/toast'
import { useState } from 'react'
@ -13,20 +13,22 @@ type SectionProps = {
children: ReactNode
}
export const Section: FC<SectionProps> = ({ title, description, action, children }) => (
<div className="flex flex-col gap-3 rounded-xl border border-components-panel-border bg-components-panel-bg p-4">
<div className="flex items-start justify-between gap-3">
<div>
<div className="system-sm-semibold text-text-primary">{title}</div>
{description && (
<p className="mt-1 max-w-xl system-xs-regular text-text-tertiary">{description}</p>
)}
export function Section({ title, description, action, children }: SectionProps) {
return (
<div className="flex flex-col gap-3 rounded-xl border border-components-panel-border bg-components-panel-bg p-4">
<div className="flex items-start justify-between gap-3">
<div>
<div className="system-sm-semibold text-text-primary">{title}</div>
{description && (
<p className="mt-1 max-w-xl system-xs-regular text-text-tertiary">{description}</p>
)}
</div>
{action}
</div>
{action}
{children}
</div>
{children}
</div>
)
)
}
type CopyPillProps = {
label: string
@ -35,7 +37,7 @@ type CopyPillProps = {
className?: string
}
export const CopyPill: FC<CopyPillProps> = ({ label, value, prefix, className }) => {
export function CopyPill({ label, value, prefix, className }: CopyPillProps) {
const { t } = useTranslation('deployments')
const [copied, setCopied] = useState(false)
@ -85,22 +87,24 @@ type EndpointRowProps = {
openLabel?: string
}
export const EndpointRow: FC<EndpointRowProps> = ({ envName, label, value, openLabel }) => (
<div className="flex flex-wrap items-center gap-x-3 gap-y-1.5">
<span className="min-w-[140px] system-xs-regular text-text-tertiary">
{envName}
</span>
<CopyPill label={label} value={value} className="min-w-[260px] flex-1" />
{openLabel && (
<a
href={value}
target="_blank"
rel="noreferrer"
className="inline-flex h-8 shrink-0 items-center gap-1.5 rounded-lg border border-components-button-secondary-border bg-components-button-secondary-bg px-3 system-sm-medium text-components-button-secondary-text hover:bg-components-button-secondary-bg-hover"
>
<span className="i-ri-external-link-line h-3.5 w-3.5" />
{openLabel}
</a>
)}
</div>
)
export function EndpointRow({ envName, label, value, openLabel }: EndpointRowProps) {
return (
<div className="flex flex-wrap items-center gap-x-3 gap-y-1.5">
<span className="min-w-[140px] system-xs-regular text-text-tertiary">
{envName}
</span>
<CopyPill label={label} value={value} className="min-w-[260px] flex-1" />
{openLabel && (
<a
href={value}
target="_blank"
rel="noreferrer"
className="inline-flex h-8 shrink-0 items-center gap-1.5 rounded-lg border border-components-button-secondary-border bg-components-button-secondary-bg px-3 system-sm-medium text-components-button-secondary-text hover:bg-components-button-secondary-bg-hover"
>
<span className="i-ri-external-link-line h-3.5 w-3.5" />
{openLabel}
</a>
)}
</div>
)
}

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import type { ConsoleEnvironmentSummary, DeveloperAPIKeySummary } from '@/features/deployments/types'
import { Switch } from '@langgenius/dify-ui/switch'
import { useTranslation } from 'react-i18next'
@ -20,7 +19,7 @@ type DeveloperApiSectionProps = {
onClearCreatedToken: () => void
}
export const DeveloperApiSection: FC<DeveloperApiSectionProps> = ({
export function DeveloperApiSection({
apiEnabled,
apiUrl,
environments,
@ -31,7 +30,7 @@ export const DeveloperApiSection: FC<DeveloperApiSectionProps> = ({
onCopyApiKey,
onRevoke,
onClearCreatedToken,
}) => {
}: DeveloperApiSectionProps) {
const { t } = useTranslation('deployments')
return (

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import type { AccessPermission, AccessSubject, ConsoleEnvironmentSummary } from '@/features/deployments/types'
import { useTranslation } from 'react-i18next'
import { Section } from './common'
@ -18,12 +17,12 @@ type AccessPermissionsSectionProps = {
) => Promise<void>
}
export const AccessPermissionsSection: FC<AccessPermissionsSectionProps> = ({
export function AccessPermissionsSection({
appId,
environments,
policies,
onSetPolicy,
}) => {
}: AccessPermissionsSectionProps) {
const { t } = useTranslation('deployments')
return (

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import type { AccessPermissionKind } from '../../types'
import type {
AccessPermission,
@ -43,7 +42,7 @@ type PermissionPickerProps = {
onChange: (kind: AccessPermissionKind) => void
}
const PermissionPicker: FC<PermissionPickerProps> = ({ value, disabled, onChange }) => {
function PermissionPicker({ value, disabled, onChange }: PermissionPickerProps) {
const { t } = useTranslation('deployments')
const icon = permissionIcon[value]
const label = t(`access.permission.${value}`)
@ -142,7 +141,7 @@ type SubjectPillProps = {
onRemove: () => void
}
const SubjectPill: FC<SubjectPillProps> = ({ subject, disabled, onRemove }) => {
function SubjectPill({ subject, disabled, onRemove }: SubjectPillProps) {
const { t } = useTranslation('deployments')
const isGroup = subject.subjectType === 'group'
@ -176,12 +175,12 @@ type SubjectPickerProps = {
onChange: (subjects: SelectableAccessSubject[]) => void
}
const SubjectPicker: FC<SubjectPickerProps> = ({
function SubjectPicker({
appId,
disabled,
selectedSubjects,
onChange,
}) => {
}: SubjectPickerProps) {
const { t } = useTranslation('deployments')
const [open, setOpen] = useState(false)
const [keyword, setKeyword] = useState('')
@ -308,12 +307,12 @@ type EnvironmentPermissionRowProps = {
) => Promise<void>
}
export const EnvironmentPermissionRow: FC<EnvironmentPermissionRowProps> = ({
export function EnvironmentPermissionRow({
appId,
environment,
summaryPolicy,
onSetPolicy,
}) => {
}: EnvironmentPermissionRowProps) {
const { t } = useTranslation('deployments')
const environmentId = environment.id
const policyQuery = useQuery(consoleQuery.enterprise.appDeploy.getEnvironmentAccessPolicy.queryOptions({

View File

@ -1,5 +1,5 @@
'use client'
import type { FC, KeyboardEvent } from 'react'
import type { KeyboardEvent } from 'react'
import { Button } from '@langgenius/dify-ui/button'
import { cn } from '@langgenius/dify-ui/cn'
import {
@ -36,7 +36,7 @@ type DeployTabProps = {
instanceId: string
}
const DeployTab: FC<DeployTabProps> = ({ instanceId: appInstanceId }) => {
export function DeployTab({ instanceId: appInstanceId }: DeployTabProps) {
const { t } = useTranslation('deployments')
const { data: environmentDeployments } = useQuery(consoleQuery.enterprise.appDeploy.listRuntimeInstances.queryOptions({
input: {
@ -302,5 +302,3 @@ const DeployTab: FC<DeployTabProps> = ({ instanceId: appInstanceId }) => {
</div>
)
}
export default DeployTab

View File

@ -1,6 +1,6 @@
'use client'
import type { FC, ReactNode } from 'react'
import type { ReactNode } from 'react'
import type { EnvironmentDeploymentRow, RuntimeBindingDisplay } from '@/features/deployments/types'
import { cn } from '@langgenius/dify-ui/cn'
import { useTranslation } from 'react-i18next'
@ -23,12 +23,14 @@ type InfoBlockProps = {
children: ReactNode
}
const InfoBlock: FC<InfoBlockProps> = ({ title, children }) => (
<div className="min-w-0 rounded-lg bg-background-default px-3 py-2.5">
<div className="mb-2 system-xs-medium-uppercase text-text-tertiary">{title}</div>
<div className="flex flex-col gap-1.5">{children}</div>
</div>
)
function InfoBlock({ title, children }: InfoBlockProps) {
return (
<div className="min-w-0 rounded-lg bg-background-default px-3 py-2.5">
<div className="mb-2 system-xs-medium-uppercase text-text-tertiary">{title}</div>
<div className="flex flex-col gap-1.5">{children}</div>
</div>
)
}
type InfoRowProps = {
label: string
@ -37,21 +39,23 @@ type InfoRowProps = {
suffix?: string
}
const InfoRow: FC<InfoRowProps> = ({ label, value, mono, suffix }) => (
<div className="grid min-w-0 grid-cols-[minmax(88px,0.35fr)_minmax(0,1fr)] items-start gap-2">
<span className="system-xs-regular text-text-tertiary">{label}</span>
<span className={cn('min-w-0 system-sm-regular break-all text-text-primary', mono && 'font-mono')}>
{value}
{suffix && <span className="system-xs-regular text-text-tertiary">{suffix}</span>}
</span>
</div>
)
function InfoRow({ label, value, mono, suffix }: InfoRowProps) {
return (
<div className="grid min-w-0 grid-cols-[minmax(88px,0.35fr)_minmax(0,1fr)] items-start gap-2">
<span className="system-xs-regular text-text-tertiary">{label}</span>
<span className={cn('min-w-0 system-sm-regular break-all text-text-primary', mono && 'font-mono')}>
{value}
{suffix && <span className="system-xs-regular text-text-tertiary">{suffix}</span>}
</span>
</div>
)
}
type RuntimeBindingItemProps = {
binding: RuntimeBindingDisplay
}
const RuntimeBindingItem: FC<RuntimeBindingItemProps> = ({ binding }) => {
function RuntimeBindingItem({ binding }: RuntimeBindingItemProps) {
const summary = runtimeBindingSummary(binding)
return (
@ -67,7 +71,7 @@ type DeploymentPanelProps = {
row: EnvironmentDeploymentRow
}
export const DeploymentPanel: FC<DeploymentPanelProps> = ({ row }) => {
export function DeploymentPanel({ row }: DeploymentPanelProps) {
const { t } = useTranslation('deployments')
const observed = activeRelease(row)
const env = row.environment

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import type { EnvironmentDeploymentRow } from '@/features/deployments/types'
import { useTranslation } from 'react-i18next'
import {
@ -14,7 +13,7 @@ type DeploymentStatusSummaryProps = {
row: EnvironmentDeploymentRow
}
export const DeploymentStatusSummary: FC<DeploymentStatusSummaryProps> = ({ row }) => {
export function DeploymentStatusSummary({ row }: DeploymentStatusSummaryProps) {
const { t } = useTranslation('deployments')
if (isUndeployedDeploymentRow(row)) {
return (

View File

@ -1,6 +1,6 @@
'use client'
import type { ComponentProps, FC, PropsWithoutRef } from 'react'
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'
@ -28,16 +28,36 @@ type TailwindNavIconProps = PropsWithoutRef<ComponentProps<'svg'>> & {
titleId?: string
}
const OverviewIcon = ({ className }: TailwindNavIconProps) => <span aria-hidden className={cn('i-ri-dashboard-2-line', className)} />
const OverviewSelectedIcon = ({ className }: TailwindNavIconProps) => <span aria-hidden className={cn('i-ri-dashboard-2-fill', className)} />
const DeployIcon = ({ className }: TailwindNavIconProps) => <span aria-hidden className={cn('i-ri-rocket-line', className)} />
const DeploySelectedIcon = ({ className }: TailwindNavIconProps) => <span aria-hidden className={cn('i-ri-rocket-fill', className)} />
const VersionsIcon = ({ className }: TailwindNavIconProps) => <span aria-hidden className={cn('i-ri-stack-line', className)} />
const VersionsSelectedIcon = ({ className }: TailwindNavIconProps) => <span aria-hidden className={cn('i-ri-stack-fill', className)} />
const AccessIcon = ({ className }: TailwindNavIconProps) => <span aria-hidden className={cn('i-ri-plug-line', className)} />
const AccessSelectedIcon = ({ className }: TailwindNavIconProps) => <span aria-hidden className={cn('i-ri-plug-fill', className)} />
const SettingsIcon = ({ className }: TailwindNavIconProps) => <span aria-hidden className={cn('i-ri-settings-3-line', className)} />
const SettingsSelectedIcon = ({ className }: TailwindNavIconProps) => <span aria-hidden className={cn('i-ri-settings-3-fill', className)} />
function OverviewIcon({ className }: TailwindNavIconProps) {
return <span aria-hidden className={cn('i-ri-dashboard-2-line', className)} />
}
function OverviewSelectedIcon({ className }: TailwindNavIconProps) {
return <span aria-hidden className={cn('i-ri-dashboard-2-fill', className)} />
}
function DeployIcon({ className }: TailwindNavIconProps) {
return <span aria-hidden className={cn('i-ri-rocket-line', className)} />
}
function DeploySelectedIcon({ className }: TailwindNavIconProps) {
return <span aria-hidden className={cn('i-ri-rocket-fill', className)} />
}
function VersionsIcon({ className }: TailwindNavIconProps) {
return <span aria-hidden className={cn('i-ri-stack-line', className)} />
}
function VersionsSelectedIcon({ className }: TailwindNavIconProps) {
return <span aria-hidden className={cn('i-ri-stack-fill', className)} />
}
function AccessIcon({ className }: TailwindNavIconProps) {
return <span aria-hidden className={cn('i-ri-plug-line', className)} />
}
function AccessSelectedIcon({ className }: TailwindNavIconProps) {
return <span aria-hidden className={cn('i-ri-plug-fill', className)} />
}
function SettingsIcon({ className }: TailwindNavIconProps) {
return <span aria-hidden className={cn('i-ri-settings-3-line', className)} />
}
function SettingsSelectedIcon({ className }: TailwindNavIconProps) {
return <span aria-hidden className={cn('i-ri-settings-3-fill', className)} />
}
const TABS: TabDef[] = [
{ key: 'overview', icon: OverviewIcon, selectedIcon: OverviewSelectedIcon },
@ -47,7 +67,7 @@ const TABS: TabDef[] = [
{ key: 'settings', icon: SettingsIcon, selectedIcon: SettingsSelectedIcon },
]
const isShortcutFromInputArea = (target: EventTarget | null) => {
function isShortcutFromInputArea(target: EventTarget | null) {
if (!(target instanceof HTMLElement))
return false
@ -64,13 +84,13 @@ type DeploymentSidebarProps = {
app?: AppInfo
}
export const DeploymentSidebar: FC<DeploymentSidebarProps> = ({
export function DeploymentSidebar({
instanceId,
instanceName,
instanceDescription,
appModeLabel,
app,
}) => {
}: DeploymentSidebarProps) {
const { t } = useTranslation('deployments')
const sidebarRef = useRef<HTMLDivElement>(null)
const isHoveringSidebar = useHover(sidebarRef)

View File

@ -1,6 +1,6 @@
'use client'
import type { FC, ReactNode } from 'react'
import type { ReactNode } from 'react'
import type { InstanceDetailTabKey } from './tabs'
import { Button } from '@langgenius/dify-ui/button'
import { useQuery } from '@tanstack/react-query'
@ -10,8 +10,8 @@ import { getAppModeLabel } from '@/app/components/app-sidebar/app-info/app-mode-
import useDocumentTitle from '@/hooks/use-document-title'
import { useRouter, useSelectedLayoutSegment } from '@/next/navigation'
import { consoleQuery } from '@/service/client'
import DeployDrawer from '../components/deploy-drawer'
import RollbackModal from '../components/rollback-modal'
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'
@ -21,7 +21,7 @@ type InstanceDetailProps = {
children: ReactNode
}
const InstanceDetail: FC<InstanceDetailProps> = ({ instanceId, children }) => {
export function InstanceDetail({ instanceId, children }: InstanceDetailProps) {
const { t } = useTranslation('deployments')
const { t: tCommon } = useTranslation()
const router = useRouter()
@ -95,5 +95,3 @@ const InstanceDetail: FC<InstanceDetailProps> = ({ instanceId, children }) => {
</>
)
}
export default InstanceDetail

View File

@ -1,5 +1,5 @@
'use client'
import type { FC, ReactNode } from 'react'
import type { ReactNode } from 'react'
import { Button } from '@langgenius/dify-ui/button'
import { cn } from '@langgenius/dify-ui/cn'
import { useQuery } from '@tanstack/react-query'
@ -29,15 +29,17 @@ type SectionProps = {
children: ReactNode
}
const Section: FC<SectionProps> = ({ title, action, children }) => (
<div className="flex flex-col gap-3 rounded-xl border border-components-panel-border bg-components-panel-bg p-4">
<div className="flex items-center justify-between">
<div className="system-sm-semibold text-text-primary">{title}</div>
{action}
function Section({ title, action, children }: SectionProps) {
return (
<div className="flex flex-col gap-3 rounded-xl border border-components-panel-border bg-components-panel-bg p-4">
<div className="flex items-center justify-between">
<div className="system-sm-semibold text-text-primary">{title}</div>
{action}
</div>
{children}
</div>
{children}
</div>
)
)
}
type InfoRowProps = {
label: string
@ -45,12 +47,14 @@ type InfoRowProps = {
mono?: boolean
}
const InfoRow: FC<InfoRowProps> = ({ label, value, mono }) => (
<div className="flex items-start gap-3 py-1.5">
<span className="w-32 shrink-0 system-xs-regular text-text-tertiary">{label}</span>
<span className={cn('min-w-0 flex-1 system-sm-regular text-text-primary', mono && 'font-mono')}>{value}</span>
</div>
)
function InfoRow({ label, value, mono }: InfoRowProps) {
return (
<div className="flex items-start gap-3 py-1.5">
<span className="w-32 shrink-0 system-xs-regular text-text-tertiary">{label}</span>
<span className={cn('min-w-0 flex-1 system-sm-regular text-text-primary', mono && 'font-mono')}>{value}</span>
</div>
)
}
type AccessOverviewRowProps = {
label: string
@ -59,7 +63,7 @@ type AccessOverviewRowProps = {
meta?: string
}
const AccessOverviewRow: FC<AccessOverviewRowProps> = ({ label, enabled, hint, meta }) => {
function AccessOverviewRow({ label, enabled, hint, meta }: AccessOverviewRowProps) {
const { t } = useTranslation('deployments')
return (
@ -94,7 +98,7 @@ function overviewDeploymentStatus(status?: string) {
return 'ready'
}
const OverviewTab: FC<OverviewTabProps> = ({ instanceId }) => {
export function OverviewTab({ instanceId }: OverviewTabProps) {
const { t } = useTranslation('deployments')
const { t: tCommon } = useTranslation()
const router = useRouter()
@ -237,5 +241,3 @@ const OverviewTab: FC<OverviewTabProps> = ({ instanceId }) => {
</div>
)
}
export default OverviewTab

View File

@ -1,5 +1,4 @@
'use client'
import type { FC } from 'react'
import type { AppInfo } from '../types'
import type { GetAppInstanceSettingsReply } from '@/features/deployments/types'
import {
@ -35,7 +34,7 @@ type SettingsFormProps = {
onDelete: () => Promise<void>
}
const SettingsForm: FC<SettingsFormProps> = ({ app, settings, hasDeployments, onSave, onDelete }) => {
function SettingsForm({ app, settings, hasDeployments, onSave, onDelete }: SettingsFormProps) {
const { t } = useTranslation('deployments')
const [name, setName] = useState(settings?.name ?? app.name)
const [description, setDescription] = useState(settings?.description ?? app.description ?? '')
@ -175,7 +174,7 @@ const SettingsForm: FC<SettingsFormProps> = ({ app, settings, hasDeployments, on
)
}
const SettingsTab: FC<SettingsTabProps> = ({ instanceId }) => {
export function SettingsTab({ instanceId }: SettingsTabProps) {
const router = useRouter()
const updateInstance = useMutation(consoleQuery.enterprise.appDeploy.updateAppInstance.mutationOptions())
const deleteInstance = useMutation(consoleQuery.enterprise.appDeploy.deleteAppInstance.mutationOptions())
@ -225,5 +224,3 @@ const SettingsTab: FC<SettingsTabProps> = ({ instanceId }) => {
/>
)
}
export default SettingsTab

View File

@ -1,5 +1,4 @@
'use client'
import type { FC } from 'react'
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'
@ -28,7 +27,7 @@ type VersionsTabProps = {
instanceId: string
}
const VersionsTab: FC<VersionsTabProps> = ({ instanceId: appId }) => {
export function VersionsTab({ instanceId: appId }: VersionsTabProps) {
const { t } = useTranslation('deployments')
const input = { params: { appInstanceId: appId } }
const { data: overview } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceOverview.queryOptions({
@ -311,5 +310,3 @@ const VersionsTab: FC<VersionsTabProps> = ({ instanceId: appId }) => {
</div>
)
}
export default VersionsTab

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import { cn } from '@langgenius/dify-ui/cn'
import {
DropdownMenu,
@ -27,7 +26,7 @@ type DeployReleaseMenuProps = {
releaseId: string
}
export const DeployReleaseMenu: FC<DeployReleaseMenuProps> = ({ appInstanceId, releaseId }) => {
export function DeployReleaseMenu({ appInstanceId, releaseId }: DeployReleaseMenuProps) {
const { t } = useTranslation('deployments')
const openDeployDrawer = useDeploymentsStore(state => state.openDeployDrawer)
const [open, setOpen] = useState(false)

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import type { ReleaseDeployment, ReleaseDeploymentState } from './release-deployments'
import { cn } from '@langgenius/dify-ui/cn'
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
@ -16,7 +15,7 @@ type DeployedToBadgeProps = {
item: ReleaseDeployment
}
export const DeployedToBadge: FC<DeployedToBadgeProps> = ({ item }) => {
export function DeployedToBadge({ item }: DeployedToBadgeProps) {
const { t } = useTranslation('deployments')
const statusLabel = t(`versions.deployedStatus.${item.state}`)

View File

@ -1,6 +1,6 @@
'use client'
import type { FC, ReactNode } from 'react'
import type { ReactNode } from 'react'
import { cn } from '@langgenius/dify-ui/cn'
import {
DropdownMenu,
@ -24,7 +24,7 @@ type EnvironmentFilterProps = {
onChange: (value: string) => void
}
export const EnvironmentFilter: FC<EnvironmentFilterProps> = ({ value, options, onChange }) => {
export function EnvironmentFilter({ value, options, onChange }: EnvironmentFilterProps) {
const [open, setOpen] = useState(false)
const selectedOption = options.find(option => option.value === value) ?? options[0]

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import { useQuery } from '@tanstack/react-query'
import { useDebounce } from 'ahooks'
import { debounce, parseAsString, useQueryState } from 'nuqs'
@ -8,9 +7,9 @@ import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import Input from '@/app/components/base/input'
import { consoleQuery } from '@/service/client'
import CreateInstanceModal from '../components/create-instance-modal'
import DeployDrawer from '../components/deploy-drawer'
import RollbackModal from '../components/rollback-modal'
import { CreateInstanceModal } from '../components/create-instance-modal'
import { DeployDrawer } from '../components/deploy-drawer'
import { RollbackModal } from '../components/rollback-modal'
import { SOURCE_APPS_PAGE_SIZE } from '../data'
import { useDeploymentsStore } from '../store'
import {
@ -21,7 +20,7 @@ import { EnvironmentFilter } from './environment-filter'
import { InstanceCard } from './instance-card'
import { NewInstanceCard } from './new-instance-card'
const DeploymentsMain: FC = () => {
export function DeploymentsMain() {
const { t } = useTranslation('deployments')
const openCreateInstanceModal = useDeploymentsStore(state => state.openCreateInstanceModal)
@ -140,5 +139,3 @@ const DeploymentsMain: FC = () => {
</>
)
}
export default DeploymentsMain

View File

@ -1,6 +1,6 @@
'use client'
import type { FC, MouseEvent } from 'react'
import type { MouseEvent } from 'react'
import type { AppInfo } from '../types'
import type { AppDeploymentSummary } from '@/features/deployments/types'
import type { AppModeEnum } from '@/types/app'
@ -26,7 +26,7 @@ type InstanceCardProps = {
summary?: AppDeploymentSummary
}
export const InstanceCard: FC<InstanceCardProps> = ({ app, summary }) => {
export function InstanceCard({ app, summary }: InstanceCardProps) {
const { t } = useTranslation('deployments')
const router = useRouter()
const { formatTimeFromNow } = useFormatTimeFromNow()

View File

@ -1,6 +1,5 @@
'use client'
import type { FC } from 'react'
import { cn } from '@langgenius/dify-ui/cn'
import { useTranslation } from 'react-i18next'
@ -15,7 +14,7 @@ type NewInstanceActionProps = {
onClick?: () => void
}
const NewInstanceAction: FC<NewInstanceActionProps> = ({ icon, label, disabled, onClick }) => {
function NewInstanceAction({ icon, label, disabled, onClick }: NewInstanceActionProps) {
const { t } = useTranslation('deployments')
return (
@ -42,7 +41,7 @@ const NewInstanceAction: FC<NewInstanceActionProps> = ({ icon, label, disabled,
)
}
export const NewInstanceCard: FC<NewInstanceCardProps> = ({ onOpen }) => {
export function NewInstanceCard({ onOpen }: NewInstanceCardProps) {
const { t } = useTranslation('deployments')
return (
<div className="relative col-span-1 inline-flex h-[160px] flex-col justify-between rounded-xl border-[0.5px] border-components-card-border bg-components-card-bg">

View File

@ -15,7 +15,7 @@ import {
toAppInfoFromOverview,
} from '../utils'
const DeploymentsNav = () => {
export function DeploymentsNav() {
const { t } = useTranslation()
const router = useRouter()
const selectedSegment = useSelectedLayoutSegment()
@ -90,5 +90,3 @@ const DeploymentsNav = () => {
/>
)
}
export default DeploymentsNav

View File

@ -16,60 +16,78 @@ import { PUBLIC_API_PREFIX } from '@/config'
export type DeploymentUiStatus = 'ready' | 'deploying' | 'deploy_failed'
export const formatDate = (value?: string) => {
export function formatDate(value?: string) {
if (!value)
return '—'
return value.replace('T', ' ').replace(/\.\d+Z?$/, '').replace(/Z$/, '').slice(0, 16)
}
export const environmentId = (environment?: ConsoleEnvironmentSummary | EnvironmentOption) => environment?.id ?? ''
export function environmentId(environment?: ConsoleEnvironmentSummary | EnvironmentOption) {
return environment?.id ?? ''
}
export const environmentName = (environment?: ConsoleEnvironmentSummary | EnvironmentOption) => environment?.name || environment?.id || '—'
export function environmentName(environment?: ConsoleEnvironmentSummary | EnvironmentOption) {
return environment?.name || environment?.id || '—'
}
export const environmentMode = (environment?: ConsoleEnvironmentSummary | EnvironmentOption) => {
export function environmentMode(environment?: ConsoleEnvironmentSummary | EnvironmentOption) {
const type = environment?.type?.toLowerCase() ?? ''
return type.includes('isolated') ? 'isolated' : 'shared'
}
export const environmentBackend = (environment?: ConsoleEnvironmentSummary) => {
export function environmentBackend(environment?: ConsoleEnvironmentSummary) {
const runtime = (environment?.backend || environment?.runtime)?.toLowerCase() ?? ''
return runtime.includes('host') ? 'host' : 'k8s'
}
export const environmentHealth = (environment?: ConsoleEnvironmentSummary | EnvironmentOption) => {
export function environmentHealth(environment?: ConsoleEnvironmentSummary | EnvironmentOption) {
const status = environment?.status?.toLowerCase() ?? ''
return status.includes('ready') ? 'ready' : 'degraded'
}
export const releaseId = (release?: ConsoleReleaseSummary) => release?.id ?? ''
export function releaseId(release?: ConsoleReleaseSummary) {
return release?.id ?? ''
}
export const releaseLabel = (release?: ConsoleReleaseSummary) => release?.name || release?.displayId || release?.id || '—'
export function releaseLabel(release?: ConsoleReleaseSummary) {
return release?.name || release?.displayId || release?.id || '—'
}
export const releaseCommit = (release?: ConsoleReleaseSummary) => release?.shortCommitId || release?.commitId || '—'
export function releaseCommit(release?: ConsoleReleaseSummary) {
return release?.shortCommitId || release?.commitId || '—'
}
export const runtimeBindingLabel = (binding?: RuntimeBindingDisplay) =>
binding?.label || binding?.slot || binding?.kind || '—'
export function runtimeBindingLabel(binding?: RuntimeBindingDisplay) {
return binding?.label || binding?.slot || binding?.kind || '—'
}
export const runtimeBindingValue = (binding?: RuntimeBindingDisplay) =>
binding?.displayValue || binding?.maskedValue || binding?.displayName || '—'
export function runtimeBindingValue(binding?: RuntimeBindingDisplay) {
return binding?.displayValue || binding?.maskedValue || binding?.displayName || '—'
}
export const runtimeBindingSummary = (binding?: RuntimeBindingDisplay) =>
binding?.label || binding?.slot || binding?.displayName || binding?.displayValue || binding?.maskedValue || binding?.kind || '—'
export function runtimeBindingSummary(binding?: RuntimeBindingDisplay) {
return binding?.label || binding?.slot || binding?.displayName || binding?.displayValue || binding?.maskedValue || binding?.kind || '—'
}
export const isRuntimeEnvVarBinding = (binding?: RuntimeBindingDisplay) =>
(binding?.kind?.toLowerCase() ?? '').includes('env')
export function isRuntimeEnvVarBinding(binding?: RuntimeBindingDisplay) {
return (binding?.kind?.toLowerCase() ?? '').includes('env')
}
export const isRuntimeModelBinding = (binding?: RuntimeBindingDisplay) =>
(binding?.kind?.toLowerCase() ?? '').includes('model')
export function isRuntimeModelBinding(binding?: RuntimeBindingDisplay) {
return (binding?.kind?.toLowerCase() ?? '').includes('model')
}
export const isRuntimePluginBinding = (binding?: RuntimeBindingDisplay) =>
!isRuntimeEnvVarBinding(binding) && !isRuntimeModelBinding(binding)
export function isRuntimePluginBinding(binding?: RuntimeBindingDisplay) {
return !isRuntimeEnvVarBinding(binding) && !isRuntimeModelBinding(binding)
}
const absoluteUrlRegExp = /^[a-z][a-z\d+.-]*:\/\//i
const withLeadingSlash = (path: string) => path.startsWith('/') ? path : `/${path}`
function withLeadingSlash(path: string) {
return path.startsWith('/') ? path : `/${path}`
}
const publicWebappOrigin = () => {
function publicWebappOrigin() {
try {
return new URL(PUBLIC_API_PREFIX).origin
}
@ -78,7 +96,7 @@ const publicWebappOrigin = () => {
}
}
export const webappUrl = (url?: string) => {
export function webappUrl(url?: string) {
if (!url)
return ''
if (absoluteUrlRegExp.test(url))
@ -88,15 +106,19 @@ export const webappUrl = (url?: string) => {
return `${origin}${withLeadingSlash(url)}`
}
export const deploymentId = (row?: EnvironmentDeploymentRow) =>
row?.id || ''
export function deploymentId(row?: EnvironmentDeploymentRow) {
return row?.id || ''
}
export const activeRelease = (row?: EnvironmentDeploymentRow) => row?.currentRelease
export function activeRelease(row?: EnvironmentDeploymentRow) {
return row?.currentRelease
}
export const isUndeployedDeploymentRow = (row?: EnvironmentDeploymentRow) =>
(row?.status?.toLowerCase() ?? '').includes('undeployed') || (!row?.id && !row?.currentRelease && !row?.detail)
export function isUndeployedDeploymentRow(row?: EnvironmentDeploymentRow) {
return (row?.status?.toLowerCase() ?? '').includes('undeployed') || (!row?.id && !row?.currentRelease && !row?.detail)
}
export const deploymentStatus = (row: EnvironmentDeploymentRow): DeploymentUiStatus => {
export function deploymentStatus(row: EnvironmentDeploymentRow): DeploymentUiStatus {
const runtimeStatus = row.status?.toLowerCase() ?? ''
if (runtimeStatus.includes('deploying') || runtimeStatus.includes('pending'))
return 'deploying'
@ -105,13 +127,14 @@ export const deploymentStatus = (row: EnvironmentDeploymentRow): DeploymentUiSta
return 'ready'
}
export const deployedRows = (rows?: EnvironmentDeploymentRow[]) =>
rows?.filter((row) => {
export function deployedRows(rows?: EnvironmentDeploymentRow[]) {
return rows?.filter((row) => {
const runtimeStatus = row.status?.toLowerCase() ?? ''
return row.environment?.id
&& !isUndeployedDeploymentRow(row)
&& (row.id || runtimeStatus || row.currentRelease || row.detail)
}) ?? []
}
export function toAppInfoFromSummary(summary: AppDeploymentSummary): AppInfo | undefined {
if (!summary.id || !summary.name)
@ -149,13 +172,13 @@ export function toAppInfoFromOverview(instance?: AppInstanceOverview): AppInfo |
}
}
export const sourceAppsFromList = (response?: ListAppDeploymentsReply) => {
export function sourceAppsFromList(response?: ListAppDeploymentsReply) {
return (response?.data ?? [])
.map(toAppInfoFromSummary)
.filter((app): app is AppInfo => Boolean(app))
}
export const deploymentSummariesFromList = (response?: ListAppDeploymentsReply): Record<string, AppDeploymentSummary> => {
export function deploymentSummariesFromList(response?: ListAppDeploymentsReply): Record<string, AppDeploymentSummary> {
return Object.fromEntries(
(response?.data ?? [])
.filter(summary => summary.id)
@ -163,7 +186,7 @@ export const deploymentSummariesFromList = (response?: ListAppDeploymentsReply):
)
}
export const environmentOptionsFromOptionsReply = (response?: ListDeploymentEnvironmentOptionsReply): EnvironmentOption[] => {
export function environmentOptionsFromOptionsReply(response?: ListDeploymentEnvironmentOptionsReply): EnvironmentOption[] {
return response?.environments
?.filter(environment => environment.id)
.map(environment => ({
@ -172,7 +195,7 @@ export const environmentOptionsFromOptionsReply = (response?: ListDeploymentEnvi
})) ?? []
}
export const accessModeToPermissionKey = (mode?: string): AccessPermissionKind => {
export function accessModeToPermissionKey(mode?: string): AccessPermissionKind {
const normalized = mode?.toLowerCase() ?? ''
if (normalized === 'private')
return 'specific'
@ -181,7 +204,7 @@ export const accessModeToPermissionKey = (mode?: string): AccessPermissionKind =
return 'organization'
}
export const permissionKeyToAccessMode = (key: AccessPermissionKind) => {
export function permissionKeyToAccessMode(key: AccessPermissionKind) {
if (key === 'organization')
return 'private_all'
if (key === 'specific')

View File

@ -17,9 +17,11 @@ import {
import { isClient } from '@/utils/client'
import { request } from './base'
const getMarketplaceHeaders = () => new Headers({
'X-Dify-Version': !IS_MARKETPLACE ? APP_VERSION : '999.0.0',
})
function getMarketplaceHeaders() {
return new Headers({
'X-Dify-Version': !IS_MARKETPLACE ? APP_VERSION : '999.0.0',
})
}
function isURL(path: string) {
try {