mirror of
https://github.com/langgenius/dify.git
synced 2026-05-13 08:57:28 +08:00
tweaks
This commit is contained in:
parent
64fc1e8281
commit
04124edd70
@ -4,6 +4,7 @@ import type {
|
|||||||
AccessPermission,
|
AccessPermission,
|
||||||
AccessSubject,
|
AccessSubject,
|
||||||
ConsoleEnvironmentSummary,
|
ConsoleEnvironmentSummary,
|
||||||
|
DeveloperAPIKeySummary,
|
||||||
} from '@/features/deployments/types'
|
} from '@/features/deployments/types'
|
||||||
import { useMutation, useQuery } from '@tanstack/react-query'
|
import { useMutation, useQuery } from '@tanstack/react-query'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
@ -26,44 +27,39 @@ function uniqueEnvironments(environments: (ConsoleEnvironmentSummary | undefined
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AccessTab({ instanceId: appId }: {
|
type DeveloperApiAccessSectionProps = {
|
||||||
instanceId: string
|
appId: string
|
||||||
}) {
|
apiEnabled: boolean
|
||||||
const appInput = { params: { appInstanceId: appId } }
|
apiUrl?: string
|
||||||
const { data: accessConfig } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceAccess.queryOptions({
|
environments: ConsoleEnvironmentSummary[]
|
||||||
input: appInput,
|
apiKeys: DeveloperAPIKeySummary[]
|
||||||
}))
|
}
|
||||||
const { data: environmentDeployments } = useQuery(consoleQuery.enterprise.appDeploy.listRuntimeInstances.queryOptions({
|
|
||||||
input: appInput,
|
function DeveloperApiAccessSection({
|
||||||
}))
|
appId,
|
||||||
|
apiEnabled,
|
||||||
|
apiUrl,
|
||||||
|
environments,
|
||||||
|
apiKeys,
|
||||||
|
}: DeveloperApiAccessSectionProps) {
|
||||||
const [createdApiToken, setCreatedApiToken] = useState<{
|
const [createdApiToken, setCreatedApiToken] = useState<{
|
||||||
appId: string
|
appId: string
|
||||||
token: string
|
token: string
|
||||||
}>()
|
}>()
|
||||||
const generateApiKey = useMutation(consoleQuery.enterprise.appDeploy.createDeveloperApiKey.mutationOptions())
|
const generateApiKey = useMutation(consoleQuery.enterprise.appDeploy.createDeveloperApiKey.mutationOptions())
|
||||||
const revokeApiKey = useMutation(consoleQuery.enterprise.appDeploy.deleteDeveloperApiKey.mutationOptions())
|
const revokeApiKey = useMutation(consoleQuery.enterprise.appDeploy.deleteDeveloperApiKey.mutationOptions())
|
||||||
const toggleAccessChannel = useMutation(consoleQuery.enterprise.appDeploy.updateAccessChannels.mutationOptions())
|
|
||||||
const toggleDeveloperAPI = useMutation(consoleQuery.enterprise.appDeploy.updateDeveloperApi.mutationOptions())
|
const toggleDeveloperAPI = useMutation(consoleQuery.enterprise.appDeploy.updateDeveloperApi.mutationOptions())
|
||||||
const setEnvironmentAccessPolicy = useMutation(consoleQuery.enterprise.appDeploy.updateEnvironmentAccessPolicy.mutationOptions())
|
|
||||||
|
|
||||||
const deploymentRows = deployedRows(environmentDeployments?.data)
|
function createApiKeyLabel(environmentId: string) {
|
||||||
const policies = accessConfig?.permissions ?? EMPTY_ACCESS_PERMISSIONS
|
|
||||||
const deployedEnvs = uniqueEnvironments([
|
|
||||||
...deploymentRows.map(row => row.environment),
|
|
||||||
...policies.map(policy => policy.environment),
|
|
||||||
...(accessConfig?.accessChannels?.webappRows?.map(row => row.environment) ?? []),
|
|
||||||
])
|
|
||||||
const apiEnabled = accessConfig?.developerApi?.enabled ?? false
|
|
||||||
const apiKeys = accessConfig?.developerApi?.apiKeys ?? []
|
|
||||||
const createApiKeyLabel = (environmentId: string) => {
|
|
||||||
const existingCount = apiKeys.filter(key =>
|
const existingCount = apiKeys.filter(key =>
|
||||||
key.environment?.id === environmentId,
|
key.environment?.id === environmentId,
|
||||||
).length
|
).length
|
||||||
const name = deployedEnvs.find(env => env.id === environmentId)?.name ?? 'env'
|
const name = environments.find(env => env.id === environmentId)?.name ?? 'env'
|
||||||
|
|
||||||
return `${name}-key-${String(existingCount + 1).padStart(3, '0')}`
|
return `${name}-key-${String(existingCount + 1).padStart(3, '0')}`
|
||||||
}
|
}
|
||||||
const handleGenerateApiKey = (environmentId: string) => {
|
|
||||||
|
function handleGenerateApiKey(environmentId: string) {
|
||||||
generateApiKey.mutate(
|
generateApiKey.mutate(
|
||||||
{
|
{
|
||||||
params: {
|
params: {
|
||||||
@ -82,7 +78,8 @@ export function AccessTab({ instanceId: appId }: {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const handleRevokeApiKey = (_environmentId: string, apiKeyId: string) => {
|
|
||||||
|
function handleRevokeApiKey(_environmentId: string, apiKeyId: string) {
|
||||||
revokeApiKey.mutate({
|
revokeApiKey.mutate({
|
||||||
params: {
|
params: {
|
||||||
appInstanceId: appId,
|
appInstanceId: appId,
|
||||||
@ -90,7 +87,8 @@ export function AccessTab({ instanceId: appId }: {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const handleCopyApiKey = async (apiKeyId: string) => {
|
|
||||||
|
async function handleCopyApiKey(apiKeyId: string) {
|
||||||
const response = await consoleClient.enterprise.appDeploy.revealDeveloperApiKey({
|
const response = await consoleClient.enterprise.appDeploy.revealDeveloperApiKey({
|
||||||
params: {
|
params: {
|
||||||
appInstanceId: appId,
|
appInstanceId: appId,
|
||||||
@ -101,6 +99,52 @@ export function AccessTab({ instanceId: appId }: {
|
|||||||
throw new Error('Reveal developer API key did not return a token.')
|
throw new Error('Reveal developer API key did not return a token.')
|
||||||
return response.token
|
return response.token
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const visibleCreatedApiToken = createdApiToken?.appId === appId
|
||||||
|
? createdApiToken.token
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DeveloperApiSection
|
||||||
|
apiEnabled={apiEnabled}
|
||||||
|
apiUrl={apiUrl}
|
||||||
|
environments={environments}
|
||||||
|
apiKeys={apiKeys}
|
||||||
|
createdToken={visibleCreatedApiToken}
|
||||||
|
onToggle={enabled => toggleDeveloperAPI.mutate({
|
||||||
|
params: { appInstanceId: appId },
|
||||||
|
body: { enabled },
|
||||||
|
})}
|
||||||
|
onGenerate={handleGenerateApiKey}
|
||||||
|
onCopyApiKey={handleCopyApiKey}
|
||||||
|
onRevoke={handleRevokeApiKey}
|
||||||
|
onClearCreatedToken={() => setCreatedApiToken(undefined)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AccessTab({ instanceId: appId }: {
|
||||||
|
instanceId: string
|
||||||
|
}) {
|
||||||
|
const appInput = { params: { appInstanceId: appId } }
|
||||||
|
const { data: accessConfig } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceAccess.queryOptions({
|
||||||
|
input: appInput,
|
||||||
|
}))
|
||||||
|
const { data: environmentDeployments } = useQuery(consoleQuery.enterprise.appDeploy.listRuntimeInstances.queryOptions({
|
||||||
|
input: appInput,
|
||||||
|
}))
|
||||||
|
const toggleAccessChannel = useMutation(consoleQuery.enterprise.appDeploy.updateAccessChannels.mutationOptions())
|
||||||
|
const setEnvironmentAccessPolicy = useMutation(consoleQuery.enterprise.appDeploy.updateEnvironmentAccessPolicy.mutationOptions())
|
||||||
|
|
||||||
|
const deploymentRows = deployedRows(environmentDeployments?.data)
|
||||||
|
const policies = accessConfig?.permissions ?? EMPTY_ACCESS_PERMISSIONS
|
||||||
|
const deployedEnvs = uniqueEnvironments([
|
||||||
|
...deploymentRows.map(row => row.environment),
|
||||||
|
...policies.map(policy => policy.environment),
|
||||||
|
...(accessConfig?.accessChannels?.webappRows?.map(row => row.environment) ?? []),
|
||||||
|
])
|
||||||
|
const apiEnabled = accessConfig?.developerApi?.enabled ?? false
|
||||||
|
const apiKeys = accessConfig?.developerApi?.apiKeys ?? []
|
||||||
const handleSetEnvironmentAccessPolicy = async (
|
const handleSetEnvironmentAccessPolicy = async (
|
||||||
appId: string,
|
appId: string,
|
||||||
environmentId: string,
|
environmentId: string,
|
||||||
@ -120,9 +164,6 @@ export function AccessTab({ instanceId: appId }: {
|
|||||||
}
|
}
|
||||||
const webappRows = accessConfig?.accessChannels?.webappRows?.filter(row => row.url) ?? []
|
const webappRows = accessConfig?.accessChannels?.webappRows?.filter(row => row.url) ?? []
|
||||||
const runEnabled = accessConfig?.accessChannels?.enabled ?? false
|
const runEnabled = accessConfig?.accessChannels?.enabled ?? false
|
||||||
const visibleCreatedApiToken = createdApiToken?.appId === appId
|
|
||||||
? createdApiToken.token
|
|
||||||
: undefined
|
|
||||||
const cliDomain = getUrlOrigin(accessConfig?.accessChannels?.cli?.url)
|
const cliDomain = getUrlOrigin(accessConfig?.accessChannels?.cli?.url)
|
||||||
const cliDocsUrl = cliDomain ? `${cliDomain}/cli` : undefined
|
const cliDocsUrl = cliDomain ? `${cliDomain}/cli` : undefined
|
||||||
|
|
||||||
@ -144,20 +185,12 @@ export function AccessTab({ instanceId: appId }: {
|
|||||||
body: { enabled },
|
body: { enabled },
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<DeveloperApiSection
|
<DeveloperApiAccessSection
|
||||||
|
appId={appId}
|
||||||
apiEnabled={apiEnabled}
|
apiEnabled={apiEnabled}
|
||||||
apiUrl={accessConfig?.developerApi?.apiUrl}
|
apiUrl={accessConfig?.developerApi?.apiUrl}
|
||||||
environments={deployedEnvs}
|
environments={deployedEnvs}
|
||||||
apiKeys={apiKeys}
|
apiKeys={apiKeys}
|
||||||
createdToken={visibleCreatedApiToken}
|
|
||||||
onToggle={enabled => toggleDeveloperAPI.mutate({
|
|
||||||
params: { appInstanceId: appId },
|
|
||||||
body: { enabled },
|
|
||||||
})}
|
|
||||||
onGenerate={handleGenerateApiKey}
|
|
||||||
onCopyApiKey={handleCopyApiKey}
|
|
||||||
onRevoke={handleRevokeApiKey}
|
|
||||||
onClearCreatedToken={() => setCreatedApiToken(undefined)}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import type { KeyboardEvent } from 'react'
|
import type { KeyboardEvent } from 'react'
|
||||||
|
import type { EnvironmentOption } from '../types'
|
||||||
import { Button } from '@langgenius/dify-ui/button'
|
import { Button } from '@langgenius/dify-ui/button'
|
||||||
import { cn } from '@langgenius/dify-ui/cn'
|
import { cn } from '@langgenius/dify-ui/cn'
|
||||||
import {
|
import {
|
||||||
@ -32,6 +33,66 @@ import { DeploymentStatusSummary } from './deploy-tab/deployment-status-summary'
|
|||||||
|
|
||||||
const GRID_TEMPLATE = 'lg:grid-cols-[minmax(180px,1fr)_minmax(140px,0.75fr)_minmax(180px,0.85fr)_240px]'
|
const GRID_TEMPLATE = 'lg:grid-cols-[minmax(180px,1fr)_minmax(140px,0.75fr)_minmax(180px,0.85fr)_240px]'
|
||||||
|
|
||||||
|
function NewDeploymentMenu({ appInstanceId, availableEnvs }: {
|
||||||
|
appInstanceId: string
|
||||||
|
availableEnvs: EnvironmentOption[]
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation('deployments')
|
||||||
|
const openDeployDrawer = useDeploymentsStore(state => state.openDeployDrawer)
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownMenu modal={false} open={open} onOpenChange={setOpen}>
|
||||||
|
<DropdownMenuTrigger
|
||||||
|
className={cn(
|
||||||
|
'inline-flex h-8 shrink-0 items-center gap-1 rounded-lg px-3 system-sm-medium',
|
||||||
|
'border border-components-button-primary-border bg-components-button-primary-bg text-components-button-primary-text',
|
||||||
|
'hover:bg-components-button-primary-bg-hover',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<span className="i-ri-rocket-line h-3.5 w-3.5" />
|
||||||
|
{t('deployTab.newDeployment')}
|
||||||
|
<span className="i-ri-arrow-down-s-line h-3.5 w-3.5" />
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
{open && (
|
||||||
|
<DropdownMenuContent placement="bottom-end" sideOffset={4} popupClassName="w-[220px]">
|
||||||
|
<DropdownMenuItem
|
||||||
|
className="gap-2 px-3"
|
||||||
|
onClick={() => {
|
||||||
|
setOpen(false)
|
||||||
|
openDeployDrawer({ appInstanceId })
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="system-sm-regular text-text-secondary">{t('deployTab.deployToNewEnv')}</span>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
{availableEnvs.length > 0 && (
|
||||||
|
<>
|
||||||
|
<div className="px-3 py-1 system-xs-medium-uppercase text-text-quaternary">{t('deployTab.shortcut')}</div>
|
||||||
|
{availableEnvs.map(env => (
|
||||||
|
<DropdownMenuItem
|
||||||
|
key={env.id}
|
||||||
|
className="gap-2 px-3"
|
||||||
|
disabled={env.disabled}
|
||||||
|
onClick={() => {
|
||||||
|
if (env.disabled)
|
||||||
|
return
|
||||||
|
setOpen(false)
|
||||||
|
openDeployDrawer({ appInstanceId, environmentId: env.id })
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="system-sm-regular text-text-secondary">
|
||||||
|
{t('deployTab.deployToEnv', { name: environmentName(env) })}
|
||||||
|
</span>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</DropdownMenuContent>
|
||||||
|
)}
|
||||||
|
</DropdownMenu>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function DeployTab({ instanceId: appInstanceId }: {
|
export function DeployTab({ instanceId: appInstanceId }: {
|
||||||
instanceId: string
|
instanceId: string
|
||||||
}) {
|
}) {
|
||||||
@ -64,7 +125,6 @@ export function DeployTab({ instanceId: appInstanceId }: {
|
|||||||
return current === id ? null : id
|
return current === id ? null : id
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const [deployMenuOpen, setDeployMenuOpen] = useState(false)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex w-full max-w-[960px] flex-col gap-4 p-6">
|
<div className="flex w-full max-w-[960px] flex-col gap-4 p-6">
|
||||||
@ -78,54 +138,7 @@ export function DeployTab({ instanceId: appInstanceId }: {
|
|||||||
)
|
)
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<DropdownMenu modal={false} open={deployMenuOpen} onOpenChange={setDeployMenuOpen}>
|
<NewDeploymentMenu appInstanceId={appInstanceId} availableEnvs={availableEnvs} />
|
||||||
<DropdownMenuTrigger
|
|
||||||
className={cn(
|
|
||||||
'inline-flex h-8 shrink-0 items-center gap-1 rounded-lg px-3 system-sm-medium',
|
|
||||||
'border border-components-button-primary-border bg-components-button-primary-bg text-components-button-primary-text',
|
|
||||||
'hover:bg-components-button-primary-bg-hover',
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<span className="i-ri-rocket-line h-3.5 w-3.5" />
|
|
||||||
{t('deployTab.newDeployment')}
|
|
||||||
<span className="i-ri-arrow-down-s-line h-3.5 w-3.5" />
|
|
||||||
</DropdownMenuTrigger>
|
|
||||||
{deployMenuOpen && (
|
|
||||||
<DropdownMenuContent placement="bottom-end" sideOffset={4} popupClassName="w-[220px]">
|
|
||||||
<DropdownMenuItem
|
|
||||||
className="gap-2 px-3"
|
|
||||||
onClick={() => {
|
|
||||||
setDeployMenuOpen(false)
|
|
||||||
openDeployDrawer({ appInstanceId })
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span className="system-sm-regular text-text-secondary">{t('deployTab.deployToNewEnv')}</span>
|
|
||||||
</DropdownMenuItem>
|
|
||||||
{availableEnvs.length > 0 && (
|
|
||||||
<>
|
|
||||||
<div className="px-3 py-1 system-xs-medium-uppercase text-text-quaternary">{t('deployTab.shortcut')}</div>
|
|
||||||
{availableEnvs.map(env => (
|
|
||||||
<DropdownMenuItem
|
|
||||||
key={env.id}
|
|
||||||
className="gap-2 px-3"
|
|
||||||
disabled={env.disabled}
|
|
||||||
onClick={() => {
|
|
||||||
if (env.disabled)
|
|
||||||
return
|
|
||||||
setDeployMenuOpen(false)
|
|
||||||
openDeployDrawer({ appInstanceId, environmentId: env.id })
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span className="system-sm-regular text-text-secondary">
|
|
||||||
{t('deployTab.deployToEnv', { name: environmentName(env) })}
|
|
||||||
</span>
|
|
||||||
</DropdownMenuItem>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</DropdownMenuContent>
|
|
||||||
)}
|
|
||||||
</DropdownMenu>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{rows.length === 0
|
{rows.length === 0
|
||||||
|
|||||||
@ -23,37 +23,19 @@ import { getReleaseDeployments } from './versions-tab/release-deployments'
|
|||||||
|
|
||||||
const GRID_TEMPLATE = 'grid-cols-[minmax(0,0.9fr)_minmax(0,1fr)_minmax(0,0.8fr)_minmax(0,1.5fr)_96px]'
|
const GRID_TEMPLATE = 'grid-cols-[minmax(0,0.9fr)_minmax(0,1fr)_minmax(0,0.8fr)_minmax(0,1.5fr)_96px]'
|
||||||
|
|
||||||
export function VersionsTab({ instanceId: appId }: {
|
function CreateReleaseControl({ appId, canCreateRelease }: {
|
||||||
instanceId: string
|
appId: string
|
||||||
|
canCreateRelease: boolean
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation('deployments')
|
const { t } = useTranslation('deployments')
|
||||||
const input = { params: { appInstanceId: appId } }
|
|
||||||
const { data: overview } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceOverview.queryOptions({
|
|
||||||
input,
|
|
||||||
}))
|
|
||||||
const { data: releaseHistory } = useQuery(consoleQuery.enterprise.appDeploy.listReleases.queryOptions({
|
|
||||||
input: {
|
|
||||||
...input,
|
|
||||||
query: {
|
|
||||||
pageNumber: 1,
|
|
||||||
resultsPerPage: DEPLOYMENT_PAGE_SIZE,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
const { data: environmentDeployments } = useQuery(consoleQuery.enterprise.appDeploy.listRuntimeInstances.queryOptions({
|
|
||||||
input,
|
|
||||||
}))
|
|
||||||
const createRelease = useMutation(consoleQuery.enterprise.appDeploy.createRelease.mutationOptions())
|
const createRelease = useMutation(consoleQuery.enterprise.appDeploy.createRelease.mutationOptions())
|
||||||
const [isCreating, setIsCreating] = useState(false)
|
const [isCreating, setIsCreating] = useState(false)
|
||||||
const [releaseName, setReleaseName] = useState('')
|
const [releaseName, setReleaseName] = useState('')
|
||||||
const [releaseDescription, setReleaseDescription] = useState('')
|
const [releaseDescription, setReleaseDescription] = useState('')
|
||||||
const releaseRows = releaseHistory?.data?.filter(row => row.id) ?? []
|
|
||||||
const deploymentRows = deployedRows(environmentDeployments?.data)
|
|
||||||
const canCreateRelease = overview?.instance?.canCreateRelease ?? true
|
|
||||||
const trimmedReleaseName = releaseName.trim()
|
const trimmedReleaseName = releaseName.trim()
|
||||||
const canSubmitRelease = Boolean(canCreateRelease && trimmedReleaseName && !createRelease.isPending)
|
const canSubmitRelease = Boolean(canCreateRelease && trimmedReleaseName && !createRelease.isPending)
|
||||||
|
|
||||||
const handleCreateRelease = async () => {
|
async function handleCreateRelease() {
|
||||||
if (!canSubmitRelease)
|
if (!canSubmitRelease)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -79,33 +61,16 @@ export function VersionsTab({ instanceId: appId }: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex w-full max-w-[960px] flex-col gap-4 p-6">
|
<>
|
||||||
<div className="flex items-center justify-between gap-3">
|
<Button
|
||||||
<div className="system-sm-semibold text-text-primary">
|
size="small"
|
||||||
{t('versions.releaseHistory')}
|
variant="primary"
|
||||||
{' '}
|
disabled={!canCreateRelease}
|
||||||
<span className="system-sm-regular text-text-tertiary">
|
onClick={() => setIsCreating(true)}
|
||||||
(
|
>
|
||||||
{releaseRows.length}
|
<span className="i-ri-add-line h-3.5 w-3.5" />
|
||||||
)
|
{t('versions.createRelease')}
|
||||||
</span>
|
</Button>
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
variant="primary"
|
|
||||||
disabled={!canCreateRelease}
|
|
||||||
onClick={() => setIsCreating(true)}
|
|
||||||
>
|
|
||||||
<span className="i-ri-add-line h-3.5 w-3.5" />
|
|
||||||
{t('versions.createRelease')}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{!canCreateRelease && (
|
|
||||||
<div className="rounded-lg border border-divider-subtle bg-background-default-subtle px-3 py-2 system-sm-regular text-text-tertiary">
|
|
||||||
{t('versions.sourceAppUnavailable')}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Dialog open={isCreating} onOpenChange={setIsCreating}>
|
<Dialog open={isCreating} onOpenChange={setIsCreating}>
|
||||||
<DialogContent className="w-[560px] overflow-hidden p-0">
|
<DialogContent className="w-[560px] overflow-hidden p-0">
|
||||||
@ -192,6 +157,54 @@ export function VersionsTab({ instanceId: appId }: {
|
|||||||
</form>
|
</form>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function VersionsTab({ instanceId: appId }: {
|
||||||
|
instanceId: string
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation('deployments')
|
||||||
|
const input = { params: { appInstanceId: appId } }
|
||||||
|
const { data: overview } = useQuery(consoleQuery.enterprise.appDeploy.getAppInstanceOverview.queryOptions({
|
||||||
|
input,
|
||||||
|
}))
|
||||||
|
const { data: releaseHistory } = useQuery(consoleQuery.enterprise.appDeploy.listReleases.queryOptions({
|
||||||
|
input: {
|
||||||
|
...input,
|
||||||
|
query: {
|
||||||
|
pageNumber: 1,
|
||||||
|
resultsPerPage: DEPLOYMENT_PAGE_SIZE,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
const { data: environmentDeployments } = useQuery(consoleQuery.enterprise.appDeploy.listRuntimeInstances.queryOptions({
|
||||||
|
input,
|
||||||
|
}))
|
||||||
|
const releaseRows = releaseHistory?.data?.filter(row => row.id) ?? []
|
||||||
|
const deploymentRows = deployedRows(environmentDeployments?.data)
|
||||||
|
const canCreateRelease = overview?.instance?.canCreateRelease ?? true
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex w-full max-w-[960px] flex-col gap-4 p-6">
|
||||||
|
<div className="flex items-center justify-between gap-3">
|
||||||
|
<div className="system-sm-semibold text-text-primary">
|
||||||
|
{t('versions.releaseHistory')}
|
||||||
|
{' '}
|
||||||
|
<span className="system-sm-regular text-text-tertiary">
|
||||||
|
(
|
||||||
|
{releaseRows.length}
|
||||||
|
)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<CreateReleaseControl appId={appId} canCreateRelease={canCreateRelease} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{!canCreateRelease && (
|
||||||
|
<div className="rounded-lg border border-divider-subtle bg-background-default-subtle px-3 py-2 system-sm-regular text-text-tertiary">
|
||||||
|
{t('versions.sourceAppUnavailable')}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{releaseRows.length === 0
|
{releaseRows.length === 0
|
||||||
? (
|
? (
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user