Files
dify/web/features/deployments/detail/access-tab/developer-api-section.tsx
Stephen Zhou 1aea4e00a4 tweaks
2026-04-29 13:25:41 +08:00

120 lines
4.4 KiB
TypeScript

'use client'
import type { FC } from 'react'
import type { ConsoleEnvironmentSummary, DeveloperAPIKeySummary } from '@/contract/console/deployments'
import { Switch } from '@langgenius/dify-ui/switch'
import { useTranslation } from 'react-i18next'
import { ApiKeyGenerateMenu, ApiKeyRow } from './api-keys'
import { CopyPill, Section } from './common'
type DeveloperApiSectionProps = {
apiEnabled: boolean
environments: ConsoleEnvironmentSummary[]
apiKeys: DeveloperAPIKeySummary[]
createdToken?: string
onToggle: (enabled: boolean) => void
onGenerate: (environmentId: string) => void
onRevoke: (environmentId: string, apiKeyId: string) => void
onClearCreatedToken: () => void
}
export const DeveloperApiSection: FC<DeveloperApiSectionProps> = ({
apiEnabled,
environments,
apiKeys,
createdToken,
onToggle,
onGenerate,
onRevoke,
onClearCreatedToken,
}) => {
const { t } = useTranslation('deployments')
return (
<Section
title={t('access.api.developerTitle')}
description={t('access.api.description')}
action={(
<Switch
checked={apiEnabled}
onCheckedChange={onToggle}
/>
)}
>
{apiEnabled
? (
<div className="flex flex-col gap-2">
<div className="flex items-center justify-between gap-3">
<div className="flex min-w-0 flex-col">
<span className="system-sm-medium text-text-primary">
{t('access.api.backendTitle')}
</span>
<span className="system-xs-regular text-text-tertiary">
{t('access.api.keyList')}
</span>
</div>
<ApiKeyGenerateMenu
environments={environments}
onGenerate={onGenerate}
/>
</div>
{createdToken && (
<div className="flex flex-col gap-2 rounded-lg border border-components-panel-border bg-components-panel-bg-blur p-3">
<div className="flex items-start justify-between gap-3">
<div className="flex min-w-0 flex-col">
<span className="system-sm-medium text-text-primary">
{t('access.api.newTokenTitle')}
</span>
<span className="system-xs-regular text-text-tertiary">
{t('access.api.newTokenDescription')}
</span>
</div>
<button
type="button"
onClick={onClearCreatedToken}
aria-label={t('access.api.dismissToken')}
className="flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary"
>
<span className="i-ri-close-line h-3.5 w-3.5" />
</button>
</div>
<CopyPill
label={t('access.api.newTokenLabel')}
value={createdToken}
/>
</div>
)}
{apiKeys.length === 0
? (
<div className="rounded-lg border border-dashed border-components-panel-border bg-components-panel-bg-blur px-4 py-6 text-center system-sm-regular text-text-tertiary">
{environments.length === 0
? t('access.api.empty')
: t('access.api.noKeys')}
</div>
)
: (
<div className="flex flex-col divide-y divide-divider-subtle">
{apiKeys.map((apiKey) => {
if (!apiKey.id || !apiKey.environmentId)
return null
return (
<ApiKeyRow
key={apiKey.id}
apiKey={apiKey}
onRevoke={() => onRevoke(apiKey.environmentId!, apiKey.id!)}
/>
)
})}
</div>
)}
</div>
)
: (
<div className="system-xs-regular text-text-tertiary">
{t('access.api.disabled')}
</div>
)}
</Section>
)
}