mirror of
https://github.com/langgenius/dify.git
synced 2026-05-13 08:57:28 +08:00
style
This commit is contained in:
parent
e16988d8a9
commit
bdd73d2846
@ -139,7 +139,7 @@ function CreateInstanceForm() {
|
|||||||
type="text"
|
type="text"
|
||||||
placeholder={sourceApp?.name ?? t('createModal.namePlaceholder')}
|
placeholder={sourceApp?.name ?? t('createModal.namePlaceholder')}
|
||||||
required
|
required
|
||||||
className="flex h-8 items-center rounded-lg border-[0.5px] border-components-input-border-active bg-components-input-bg-normal px-3 text-[13px] font-medium text-text-secondary outline-hidden placeholder:text-text-quaternary"
|
className="flex h-8 items-center rounded-lg border border-components-input-border-active bg-components-input-bg-normal px-3 system-sm-medium text-text-secondary outline-hidden placeholder:text-text-quaternary"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -151,7 +151,7 @@ function CreateInstanceForm() {
|
|||||||
id="instance-desc"
|
id="instance-desc"
|
||||||
name="description"
|
name="description"
|
||||||
placeholder={t('createModal.descriptionPlaceholder')}
|
placeholder={t('createModal.descriptionPlaceholder')}
|
||||||
className="min-h-[80px] rounded-lg border-[0.5px] border-components-input-border-active bg-components-input-bg-normal px-3 py-2 text-[13px] text-text-secondary outline-hidden placeholder:text-text-quaternary"
|
className="min-h-20 rounded-lg border border-components-input-border-active bg-components-input-bg-normal px-3 py-2 system-sm-regular text-text-secondary outline-hidden placeholder:text-text-quaternary"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ export function CreateInstanceModal() {
|
|||||||
open={open}
|
open={open}
|
||||||
onOpenChange={next => !next && closeModal()}
|
onOpenChange={next => !next && closeModal()}
|
||||||
>
|
>
|
||||||
<DialogContent className="w-[520px] max-w-[90vw]">
|
<DialogContent className="w-130 max-w-[90vw]">
|
||||||
<DialogCloseButton />
|
<DialogCloseButton />
|
||||||
{open && <CreateInstanceForm />}
|
{open && <CreateInstanceForm />}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
@ -49,14 +49,14 @@ export function DeployDrawer() {
|
|||||||
open={open}
|
open={open}
|
||||||
onOpenChange={next => !next && closeDeployDrawer()}
|
onOpenChange={next => !next && closeDeployDrawer()}
|
||||||
>
|
>
|
||||||
<DialogContent className="w-[560px] max-w-[90vw]">
|
<DialogContent className="w-140 max-w-[90vw]">
|
||||||
<DialogCloseButton />
|
<DialogCloseButton />
|
||||||
{!drawerAppInstanceId
|
{!drawerAppInstanceId
|
||||||
? <div className="p-4 text-text-tertiary">{t('deployDrawer.notFound')}</div>
|
? <div className="p-4 text-text-tertiary">{t('deployDrawer.notFound')}</div>
|
||||||
: (!releaseHistory || !environmentOptionsReply)
|
: (!releaseHistory || !environmentOptionsReply)
|
||||||
? (
|
? (
|
||||||
<div className="flex items-center gap-2 p-4 system-sm-regular text-text-tertiary">
|
<div className="flex items-center gap-2 p-4 system-sm-regular text-text-tertiary">
|
||||||
<span className="h-4 w-4 animate-spin rounded-full border-2 border-components-panel-border border-t-transparent" />
|
<span className="size-4 animate-spin rounded-full border-2 border-components-panel-border border-t-transparent" />
|
||||||
{t('createModal.loadingApps')}
|
{t('createModal.loadingApps')}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -53,7 +53,7 @@ export function DeploymentSelect({ value, onChange, options, placeholder }: Sele
|
|||||||
>
|
>
|
||||||
<SelectTrigger
|
<SelectTrigger
|
||||||
className={cn(
|
className={cn(
|
||||||
'h-8 min-w-0 border-[0.5px] border-components-input-border-active px-2 text-left system-sm-medium',
|
'h-8 min-w-0 border border-components-input-border-active px-2 text-left system-sm-medium',
|
||||||
!selectedOption && 'text-text-quaternary',
|
!selectedOption && 'text-text-quaternary',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -25,7 +25,7 @@ export function StatusBadge({ status, className }: {
|
|||||||
return (
|
return (
|
||||||
<span className={cn(baseBadge, statusStyles[status], className)}>
|
<span className={cn(baseBadge, statusStyles[status], className)}>
|
||||||
{status === 'deploying' && (
|
{status === 'deploying' && (
|
||||||
<span className="h-1.5 w-1.5 animate-pulse rounded-full bg-current" />
|
<span className="size-1.5 animate-pulse rounded-full bg-current" />
|
||||||
)}
|
)}
|
||||||
{t(statusKey[status])}
|
{t(statusKey[status])}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@ -8,7 +8,7 @@ export function AccessTab({ appInstanceId }: {
|
|||||||
appInstanceId: string
|
appInstanceId: string
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="flex w-full max-w-[960px] flex-col gap-5 p-6">
|
<div className="flex w-full max-w-240 flex-col gap-5 p-6">
|
||||||
<AccessPermissionsSection appInstanceId={appInstanceId} />
|
<AccessPermissionsSection appInstanceId={appInstanceId} />
|
||||||
<AccessChannelsSection appInstanceId={appInstanceId} />
|
<AccessChannelsSection appInstanceId={appInstanceId} />
|
||||||
<DeveloperApiSection appInstanceId={appInstanceId} />
|
<DeveloperApiSection appInstanceId={appInstanceId} />
|
||||||
|
|||||||
@ -39,23 +39,23 @@ function ApiKeyRow({ appInstanceId, apiKey }: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-3 py-1.5">
|
<div className="flex items-center gap-3 py-1.5">
|
||||||
<div className="flex min-w-[140px] flex-col">
|
<div className="flex min-w-35 flex-col">
|
||||||
<span className="system-sm-medium text-text-primary">{apiKey.name || apiKey.id}</span>
|
<span className="system-sm-medium text-text-primary">{apiKey.name || apiKey.id}</span>
|
||||||
<span className="system-xs-regular text-text-tertiary">
|
<span className="system-xs-regular text-text-tertiary">
|
||||||
{t('access.api.envPrefix', { env: environmentLabel })}
|
{t('access.api.envPrefix', { env: environmentLabel })}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex min-w-0 flex-1 items-center gap-1 rounded-lg border-[0.5px] border-components-input-border-active bg-components-input-bg-normal pr-1 pl-2">
|
<div className="flex min-w-0 flex-1 items-center gap-1 rounded-lg border border-components-input-border-active bg-components-input-bg-normal pr-1 pl-2">
|
||||||
<div className="min-w-0 flex-1 truncate font-mono text-[13px] font-medium text-text-secondary">
|
<div className="min-w-0 flex-1 truncate font-mono system-sm-medium text-text-secondary">
|
||||||
{displayValue}
|
{displayValue}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={handleRevoke}
|
onClick={handleRevoke}
|
||||||
aria-label={t('access.revoke')}
|
aria-label={t('access.revoke')}
|
||||||
className="flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-text-tertiary hover:bg-state-destructive-hover hover:text-text-destructive"
|
className="flex size-6 shrink-0 items-center justify-center rounded-md text-text-tertiary hover:bg-state-destructive-hover hover:text-text-destructive"
|
||||||
>
|
>
|
||||||
<span className="i-ri-delete-bin-line h-3.5 w-3.5" />
|
<span className="i-ri-delete-bin-line size-3.5" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -131,12 +131,12 @@ export function ApiKeyGenerateMenu({ appInstanceId, environments, apiKeys }: {
|
|||||||
disabled && 'cursor-not-allowed opacity-50',
|
disabled && 'cursor-not-allowed opacity-50',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span className="i-ri-add-line h-3.5 w-3.5" />
|
<span className="i-ri-add-line size-3.5" />
|
||||||
{t('access.api.newKey')}
|
{t('access.api.newKey')}
|
||||||
<span className="i-ri-arrow-down-s-line h-3.5 w-3.5" />
|
<span className="i-ri-arrow-down-s-line size-3.5" />
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
{open && !disabled && (
|
{open && !disabled && (
|
||||||
<DropdownMenuContent placement="bottom-end" sideOffset={4} popupClassName="w-[220px]">
|
<DropdownMenuContent placement="bottom-end" sideOffset={4} popupClassName="w-55">
|
||||||
{selectableEnvironments.map(env => (
|
{selectableEnvironments.map(env => (
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
key={env.id}
|
key={env.id}
|
||||||
|
|||||||
@ -115,7 +115,7 @@ export function AccessChannelsSection({
|
|||||||
<CopyPill
|
<CopyPill
|
||||||
label={t('access.cli.domain')}
|
label={t('access.cli.domain')}
|
||||||
value={cliDomain}
|
value={cliDomain}
|
||||||
className="min-w-[260px] flex-1"
|
className="min-w-65 flex-1"
|
||||||
/>
|
/>
|
||||||
<a
|
<a
|
||||||
href={cliDocsUrl}
|
href={cliDocsUrl}
|
||||||
@ -123,7 +123,7 @@ export function AccessChannelsSection({
|
|||||||
rel="noreferrer"
|
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"
|
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-download-cloud-2-line h-3.5 w-3.5" />
|
<span className="i-ri-download-cloud-2-line size-3.5" />
|
||||||
{t('access.cli.install')}
|
{t('access.cli.install')}
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
@ -132,7 +132,7 @@ export function AccessChannelsSection({
|
|||||||
rel="noreferrer"
|
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"
|
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-book-open-line h-3.5 w-3.5" />
|
<span className="i-ri-book-open-line size-3.5" />
|
||||||
{t('access.cli.docs')}
|
{t('access.cli.docs')}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -24,25 +24,25 @@ export function CopyPill({ label, value, prefix, className }: CopyPillProps) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex h-8 items-center rounded-lg border-[0.5px] border-components-input-border-active bg-components-input-bg-normal pr-1 pl-1.5',
|
'flex h-8 items-center gap-1 rounded-lg border border-components-input-border-active bg-components-input-bg-normal pr-1 pl-1.5',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="mr-0.5 flex h-5 shrink-0 items-center rounded-md border border-divider-subtle px-1.5 text-[11px] font-medium text-text-tertiary">
|
<div className="flex h-5 shrink-0 items-center rounded-md border border-divider-subtle px-1.5 system-2xs-medium text-text-tertiary">
|
||||||
{label}
|
{label}
|
||||||
</div>
|
</div>
|
||||||
{prefix}
|
{prefix}
|
||||||
<div className="min-w-0 flex-1 truncate px-1 font-mono text-[13px] font-medium text-text-secondary">
|
<div className="min-w-0 flex-1 truncate px-1 font-mono system-sm-medium text-text-secondary">
|
||||||
{value}
|
{value}
|
||||||
</div>
|
</div>
|
||||||
<div className="mx-1 h-[14px] w-px shrink-0 bg-divider-regular" />
|
<div className="h-3.5 w-px shrink-0 bg-divider-regular" />
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => copy(value)}
|
onClick={() => copy(value)}
|
||||||
aria-label={t('access.copy')}
|
aria-label={t('access.copy')}
|
||||||
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"
|
className="flex size-6 shrink-0 items-center justify-center rounded-md text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary"
|
||||||
>
|
>
|
||||||
<span className={cn(copied ? 'i-ri-check-line' : 'i-ri-file-copy-line', 'h-3.5 w-3.5')} />
|
<span className={cn(copied ? 'i-ri-check-line' : 'i-ri-file-copy-line', 'size-3.5')} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@ -58,10 +58,10 @@ type EndpointRowProps = {
|
|||||||
export function EndpointRow({ envName, label, value, openLabel }: EndpointRowProps) {
|
export function EndpointRow({ envName, label, value, openLabel }: EndpointRowProps) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap items-center gap-x-3 gap-y-1.5">
|
<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">
|
<span className="min-w-35 system-xs-regular text-text-tertiary">
|
||||||
{envName}
|
{envName}
|
||||||
</span>
|
</span>
|
||||||
<CopyPill label={label} value={value} className="min-w-[260px] flex-1" />
|
<CopyPill label={label} value={value} className="min-w-65 flex-1" />
|
||||||
{openLabel && (
|
{openLabel && (
|
||||||
<a
|
<a
|
||||||
href={value}
|
href={value}
|
||||||
@ -69,7 +69,7 @@ export function EndpointRow({ envName, label, value, openLabel }: EndpointRowPro
|
|||||||
rel="noreferrer"
|
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"
|
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" />
|
<span className="i-ri-external-link-line size-3.5" />
|
||||||
{openLabel}
|
{openLabel}
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -69,9 +69,9 @@ function CreatedApiTokenCard({ appInstanceId }: {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={() => setCreatedApiToken(undefined)}
|
onClick={() => setCreatedApiToken(undefined)}
|
||||||
aria-label={t('access.api.dismissToken')}
|
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"
|
className="flex size-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" />
|
<span className="i-ri-close-line size-3.5" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<CopyPill
|
<CopyPill
|
||||||
|
|||||||
@ -50,15 +50,15 @@ function PermissionPicker({ value, disabled, onChange }: {
|
|||||||
<DropdownMenuTrigger
|
<DropdownMenuTrigger
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex h-8 min-w-[220px] items-center gap-2 rounded-lg border-[0.5px] border-components-input-border-active bg-components-input-bg-normal px-2.5 system-sm-regular text-text-secondary hover:bg-state-base-hover',
|
'inline-flex h-8 min-w-55 items-center gap-2 rounded-lg border border-components-input-border-active bg-components-input-bg-normal px-2.5 system-sm-regular text-text-secondary hover:bg-state-base-hover',
|
||||||
disabled && 'opacity-50',
|
disabled && 'opacity-50',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span className={cn(icon, 'h-4 w-4 shrink-0 text-text-tertiary')} />
|
<span className={cn(icon, 'size-4 shrink-0 text-text-tertiary')} />
|
||||||
<span className="flex-1 truncate text-left">{label}</span>
|
<span className="flex-1 truncate text-left">{label}</span>
|
||||||
<span className="i-ri-arrow-down-s-line h-4 w-4 shrink-0 text-text-tertiary" />
|
<span className="i-ri-arrow-down-s-line size-4 shrink-0 text-text-tertiary" />
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent placement="bottom-start" popupClassName="w-[340px] p-1">
|
<DropdownMenuContent placement="bottom-start" popupClassName="w-85 p-1">
|
||||||
{permissionOrder.map((kind) => {
|
{permissionOrder.map((kind) => {
|
||||||
const itemIcon = permissionIcon[kind]
|
const itemIcon = permissionIcon[kind]
|
||||||
const isSelected = kind === value
|
const isSelected = kind === value
|
||||||
@ -68,7 +68,7 @@ function PermissionPicker({ value, disabled, onChange }: {
|
|||||||
onSelect={() => onChange(kind)}
|
onSelect={() => onChange(kind)}
|
||||||
className="mx-0 h-auto items-start gap-3 rounded-lg px-2.5 py-2"
|
className="mx-0 h-auto items-start gap-3 rounded-lg px-2.5 py-2"
|
||||||
>
|
>
|
||||||
<span className={cn(itemIcon, 'mt-0.5 h-4 w-4 shrink-0 text-text-tertiary')} />
|
<span className={cn(itemIcon, 'mt-0.5 size-4 shrink-0 text-text-tertiary')} />
|
||||||
<div className="flex min-w-0 flex-1 flex-col">
|
<div className="flex min-w-0 flex-1 flex-col">
|
||||||
<div className="flex min-w-0 items-center gap-2">
|
<div className="flex min-w-0 items-center gap-2">
|
||||||
<span className="truncate system-sm-medium text-text-primary">
|
<span className="truncate system-sm-medium text-text-primary">
|
||||||
@ -80,7 +80,7 @@ function PermissionPicker({ value, disabled, onChange }: {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{isSelected && (
|
{isSelected && (
|
||||||
<span className="mt-0.5 i-ri-check-line h-4 w-4 shrink-0 text-text-accent" />
|
<span className="mt-0.5 i-ri-check-line size-4 shrink-0 text-text-accent" />
|
||||||
)}
|
)}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)
|
)
|
||||||
@ -149,7 +149,7 @@ function SubjectPill({ subject, disabled, onRemove }: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="inline-flex max-w-full items-center gap-1 rounded-full border border-divider-subtle bg-components-badge-white-to-dark px-2 py-1">
|
<div className="inline-flex max-w-full items-center gap-1 rounded-full border border-divider-subtle bg-components-badge-white-to-dark px-2 py-1">
|
||||||
<span className={cn(isGroup ? 'i-ri-group-line' : 'i-ri-user-line', 'h-3.5 w-3.5 shrink-0 text-text-tertiary')} />
|
<span className={cn(isGroup ? 'i-ri-group-line' : 'i-ri-user-line', 'size-3.5 shrink-0 text-text-tertiary')} />
|
||||||
<span className="truncate system-xs-medium text-text-secondary">{subject.name || subject.id}</span>
|
<span className="truncate system-xs-medium text-text-secondary">{subject.name || subject.id}</span>
|
||||||
{isGroup && subject.memberCount != null && (
|
{isGroup && subject.memberCount != null && (
|
||||||
<span className="system-2xs-regular text-text-tertiary">{subject.memberCount}</span>
|
<span className="system-2xs-regular text-text-tertiary">{subject.memberCount}</span>
|
||||||
@ -160,11 +160,11 @@ function SubjectPill({ subject, disabled, onRemove }: {
|
|||||||
onClick={onRemove}
|
onClick={onRemove}
|
||||||
aria-label={t('operation.remove', { ns: 'common' })}
|
aria-label={t('operation.remove', { ns: 'common' })}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-text-quaternary hover:text-text-secondary',
|
'flex size-4 shrink-0 items-center justify-center rounded-full text-text-quaternary hover:text-text-secondary',
|
||||||
disabled && 'cursor-not-allowed opacity-40',
|
disabled && 'cursor-not-allowed opacity-40',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span className="i-ri-close-circle-fill h-3.5 w-3.5" />
|
<span className="i-ri-close-circle-fill size-3.5" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@ -226,22 +226,22 @@ function SubjectPicker({
|
|||||||
disabled && 'cursor-not-allowed opacity-50',
|
disabled && 'cursor-not-allowed opacity-50',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span className="i-ri-add-line h-3.5 w-3.5" />
|
<span className="i-ri-add-line size-3.5" />
|
||||||
{t('access.members.pickPlaceholder')}
|
{t('access.members.pickPlaceholder')}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{open && (
|
{open && (
|
||||||
<PopoverContent placement="bottom-start" sideOffset={4} popupClassName="w-[360px] p-0">
|
<PopoverContent placement="bottom-start" sideOffset={4} popupClassName="w-90 p-0">
|
||||||
<div className="flex max-h-[420px] flex-col overflow-hidden rounded-xl border border-components-panel-border bg-components-panel-bg shadow-lg">
|
<div className="flex max-h-105 flex-col overflow-hidden rounded-xl border border-components-panel-border bg-components-panel-bg shadow-lg">
|
||||||
<div className="border-b border-divider-subtle p-2">
|
<div className="border-b border-divider-subtle p-2">
|
||||||
<div className="flex h-8 items-center gap-2 rounded-lg border-[0.5px] border-components-input-border-active bg-components-input-bg-normal px-2">
|
<div className="flex h-8 items-center gap-2 rounded-lg border border-components-input-border-active bg-components-input-bg-normal px-2">
|
||||||
<span className="i-ri-search-line h-4 w-4 shrink-0 text-text-tertiary" />
|
<span className="i-ri-search-line size-4 shrink-0 text-text-tertiary" />
|
||||||
<input
|
<input
|
||||||
value={keyword}
|
value={keyword}
|
||||||
onChange={e => setKeyword(e.target.value)}
|
onChange={e => setKeyword(e.target.value)}
|
||||||
placeholder={t('access.members.searchPlaceholder')}
|
placeholder={t('access.members.searchPlaceholder')}
|
||||||
className="min-w-0 flex-1 bg-transparent system-sm-regular text-text-primary outline-none placeholder:text-text-quaternary"
|
className="min-w-0 flex-1 bg-transparent system-sm-regular text-text-primary outline-hidden placeholder:text-text-quaternary"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -249,7 +249,7 @@ function SubjectPicker({
|
|||||||
{subjectsQuery.isLoading
|
{subjectsQuery.isLoading
|
||||||
? (
|
? (
|
||||||
<div className="flex h-16 items-center justify-center">
|
<div className="flex h-16 items-center justify-center">
|
||||||
<span className="h-4 w-4 animate-spin rounded-full border-2 border-components-panel-border border-t-transparent" />
|
<span className="size-4 animate-spin rounded-full border-2 border-components-panel-border border-t-transparent" />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
: subjects.length === 0
|
: subjects.length === 0
|
||||||
@ -268,7 +268,7 @@ function SubjectPicker({
|
|||||||
onClick={() => toggleSubject(subject)}
|
onClick={() => toggleSubject(subject)}
|
||||||
className="flex w-full items-center gap-2 rounded-lg px-2 py-2 text-left hover:bg-state-base-hover"
|
className="flex w-full items-center gap-2 rounded-lg px-2 py-2 text-left hover:bg-state-base-hover"
|
||||||
>
|
>
|
||||||
<span className={cn(isGroup ? 'i-ri-group-line' : 'i-ri-user-line', 'h-4 w-4 shrink-0 text-text-tertiary')} />
|
<span className={cn(isGroup ? 'i-ri-group-line' : 'i-ri-user-line', 'size-4 shrink-0 text-text-tertiary')} />
|
||||||
<span className="min-w-0 flex-1 truncate system-sm-medium text-text-secondary">
|
<span className="min-w-0 flex-1 truncate system-sm-medium text-text-secondary">
|
||||||
{subject.name || subject.id}
|
{subject.name || subject.id}
|
||||||
</span>
|
</span>
|
||||||
@ -278,7 +278,7 @@ function SubjectPicker({
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{isSelected && (
|
{isSelected && (
|
||||||
<span className="i-ri-check-line h-4 w-4 shrink-0 text-text-accent" />
|
<span className="i-ri-check-line size-4 shrink-0 text-text-accent" />
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
@ -390,7 +390,7 @@ export function EnvironmentPermissionRow({
|
|||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-1.5">
|
<div className="flex flex-col gap-1.5">
|
||||||
<div className="flex flex-wrap items-center gap-x-3 gap-y-1.5">
|
<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">
|
<span className="min-w-35 system-xs-regular text-text-tertiary">
|
||||||
{environmentName(environment)}
|
{environmentName(environment)}
|
||||||
</span>
|
</span>
|
||||||
<PermissionPicker
|
<PermissionPicker
|
||||||
@ -400,7 +400,7 @@ export function EnvironmentPermissionRow({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{permissionKind === 'specific' && (
|
{permissionKind === 'specific' && (
|
||||||
<div className="flex flex-col gap-2 pl-0 sm:pl-[152px]">
|
<div className="flex flex-col gap-2 pl-0 sm:pl-38">
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
<SubjectPicker
|
<SubjectPicker
|
||||||
appInstanceId={appInstanceId}
|
appInstanceId={appInstanceId}
|
||||||
|
|||||||
@ -38,12 +38,12 @@ function NewDeploymentMenu({ appInstanceId, availableEnvs }: {
|
|||||||
'hover:bg-components-button-primary-bg-hover',
|
'hover:bg-components-button-primary-bg-hover',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span className="i-ri-rocket-line h-3.5 w-3.5" />
|
<span className="i-ri-rocket-line size-3.5" />
|
||||||
{t('deployTab.newDeployment')}
|
{t('deployTab.newDeployment')}
|
||||||
<span className="i-ri-arrow-down-s-line h-3.5 w-3.5" />
|
<span className="i-ri-arrow-down-s-line size-3.5" />
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
{open && (
|
{open && (
|
||||||
<DropdownMenuContent placement="bottom-end" sideOffset={4} popupClassName="w-[220px]">
|
<DropdownMenuContent placement="bottom-end" sideOffset={4} popupClassName="w-55">
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
className="gap-2 px-3"
|
className="gap-2 px-3"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -99,7 +99,7 @@ export function DeployTab({ appInstanceId }: {
|
|||||||
const availableEnvs = environmentOptions.filter(env => env.id && !deployedEnvIds.has(env.id))
|
const availableEnvs = environmentOptions.filter(env => env.id && !deployedEnvIds.has(env.id))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex w-full max-w-[960px] flex-col gap-4 p-6">
|
<div className="flex w-full max-w-240 flex-col gap-4 p-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="system-sm-semibold text-text-primary">
|
<div className="system-sm-semibold text-text-primary">
|
||||||
{t('deployTab.envCount')}
|
{t('deployTab.envCount')}
|
||||||
|
|||||||
@ -95,12 +95,12 @@ function DeploymentRowActions({ appInstanceId, envId, row }: {
|
|||||||
<DropdownMenu modal={false} open={menuOpen} onOpenChange={setMenuOpen}>
|
<DropdownMenu modal={false} open={menuOpen} onOpenChange={setMenuOpen}>
|
||||||
<DropdownMenuTrigger
|
<DropdownMenuTrigger
|
||||||
aria-label={t('deployTab.moreActions')}
|
aria-label={t('deployTab.moreActions')}
|
||||||
className="flex h-7 w-7 items-center justify-center rounded-md text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary"
|
className="flex size-7 items-center justify-center rounded-md text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary"
|
||||||
>
|
>
|
||||||
<span className="i-ri-more-line h-4 w-4" />
|
<span className="i-ri-more-line size-4" />
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
{menuOpen && (
|
{menuOpen && (
|
||||||
<DropdownMenuContent placement="bottom-end" sideOffset={4} popupClassName="w-[200px]">
|
<DropdownMenuContent placement="bottom-end" sideOffset={4} popupClassName="w-50">
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
className="gap-2 px-3"
|
className="gap-2 px-3"
|
||||||
onClick={handleRuntimeAction}
|
onClick={handleRuntimeAction}
|
||||||
@ -130,7 +130,7 @@ function DeploymentEnvironmentRow({ appInstanceId, row, isExpanded, onToggle }:
|
|||||||
const chevron = !isUndeployed && (
|
const chevron = !isUndeployed && (
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
'i-ri-arrow-down-s-line h-4 w-4 shrink-0 text-text-tertiary transition-transform',
|
'i-ri-arrow-down-s-line size-4 shrink-0 text-text-tertiary transition-transform',
|
||||||
isExpanded && 'rotate-180',
|
isExpanded && 'rotate-180',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -16,7 +16,7 @@ export function DeploymentStatusSummary({ row }: {
|
|||||||
if (isUndeployedDeploymentRow(row)) {
|
if (isUndeployedDeploymentRow(row)) {
|
||||||
return (
|
return (
|
||||||
<span className="inline-flex items-center gap-1.5 system-sm-medium text-text-tertiary">
|
<span className="inline-flex items-center gap-1.5 system-sm-medium text-text-tertiary">
|
||||||
<span className="h-1.5 w-1.5 rounded-full bg-text-quaternary" />
|
<span className="size-1.5 rounded-full bg-text-quaternary" />
|
||||||
{t('status.notDeployed')}
|
{t('status.notDeployed')}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
@ -27,7 +27,7 @@ export function DeploymentStatusSummary({ row }: {
|
|||||||
if (status === 'deploying') {
|
if (status === 'deploying') {
|
||||||
return (
|
return (
|
||||||
<span className="inline-flex items-center gap-1.5 system-sm-medium text-util-colors-blue-blue-700">
|
<span className="inline-flex items-center gap-1.5 system-sm-medium text-util-colors-blue-blue-700">
|
||||||
<span className="i-ri-loader-4-line h-3.5 w-3.5 animate-spin" />
|
<span className="i-ri-loader-4-line size-3.5 animate-spin" />
|
||||||
{t('deployTab.status.deployingRelease', { release: releaseLabel(activeRelease(row)) })}
|
{t('deployTab.status.deployingRelease', { release: releaseLabel(activeRelease(row)) })}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
@ -37,7 +37,7 @@ export function DeploymentStatusSummary({ row }: {
|
|||||||
const hasRunningRelease = !!activeRelease(row)?.id
|
const hasRunningRelease = !!activeRelease(row)?.id
|
||||||
return (
|
return (
|
||||||
<span className="inline-flex items-center gap-1.5 system-sm-medium text-util-colors-warning-warning-700">
|
<span className="inline-flex items-center gap-1.5 system-sm-medium text-util-colors-warning-warning-700">
|
||||||
<span className="i-ri-alert-line h-3.5 w-3.5" />
|
<span className="i-ri-alert-line size-3.5" />
|
||||||
{t(hasRunningRelease ? 'deployTab.status.runningWithFailed' : 'deployTab.status.deployFailed')}
|
{t(hasRunningRelease ? 'deployTab.status.runningWithFailed' : 'deployTab.status.deployFailed')}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
@ -45,7 +45,7 @@ export function DeploymentStatusSummary({ row }: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<span className="inline-flex items-center gap-1.5 system-sm-medium text-util-colors-green-green-700">
|
<span className="inline-flex items-center gap-1.5 system-sm-medium text-util-colors-green-green-700">
|
||||||
<span className="h-1.5 w-1.5 rounded-full bg-util-colors-green-green-500" />
|
<span className="size-1.5 rounded-full bg-util-colors-green-green-500" />
|
||||||
{t('status.ready')}
|
{t('status.ready')}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -129,7 +129,7 @@ export function DeploymentSidebar({
|
|||||||
ref={sidebarRef}
|
ref={sidebarRef}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex shrink-0 flex-col border-r border-divider-burn bg-background-default-subtle transition-all',
|
'flex shrink-0 flex-col border-r border-divider-burn bg-background-default-subtle transition-all',
|
||||||
expand ? 'w-[216px]' : 'w-14',
|
expand ? 'w-54' : 'w-14',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className={cn('shrink-0', expand ? 'p-2' : 'p-1')}>
|
<div className={cn('shrink-0', expand ? 'p-2' : 'p-1')}>
|
||||||
@ -178,7 +178,7 @@ export function DeploymentSidebar({
|
|||||||
/>
|
/>
|
||||||
{!isMobile && isHoveringSidebar && (
|
{!isMobile && isHoveringSidebar && (
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
className="absolute top-[-3.5px] -right-3 z-20"
|
className="absolute -top-1 -right-3 z-20"
|
||||||
expand={expand}
|
expand={expand}
|
||||||
handleToggle={toggleSidebarMode}
|
handleToggle={toggleSidebarMode}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -35,7 +35,7 @@ export function InstanceDetail({ appInstanceId, children }: {
|
|||||||
if (!resolvedAppInstanceId && overviewQuery.isLoading) {
|
if (!resolvedAppInstanceId && overviewQuery.isLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full items-center justify-center bg-background-body">
|
<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" />
|
<span className="size-6 animate-spin rounded-full border-2 border-components-panel-border border-t-transparent" />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -45,7 +45,7 @@ export function InstanceDetail({ appInstanceId, children }: {
|
|||||||
<div className="flex h-full flex-col items-center justify-center gap-3 bg-background-body">
|
<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>
|
<div className="title-xl-semi-bold text-text-primary">{t('detail.notFound')}</div>
|
||||||
<Button nativeButton={false} variant="secondary" render={<Link href="/deployments" />}>
|
<Button nativeButton={false} variant="secondary" render={<Link href="/deployments" />}>
|
||||||
<span aria-hidden className="i-ri-arrow-left-line h-4 w-4" />
|
<span aria-hidden className="i-ri-arrow-left-line size-4" />
|
||||||
{t('detail.backToInstances')}
|
{t('detail.backToInstances')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@ -54,7 +54,7 @@ export function InstanceDetail({ appInstanceId, children }: {
|
|||||||
|
|
||||||
return (
|
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)]">
|
<div className="relative flex h-full overflow-hidden rounded-t-2xl shadow-xs">
|
||||||
<DeploymentSidebar
|
<DeploymentSidebar
|
||||||
app={app}
|
app={app}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -54,7 +54,7 @@ function AccessOverviewRow({ label, enabled, hint, meta }: AccessOverviewRowProp
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span className={cn(
|
<span className={cn(
|
||||||
'h-1.5 w-1.5 rounded-full',
|
'size-1.5 rounded-full',
|
||||||
enabled ? 'bg-util-colors-green-green-500' : 'bg-text-quaternary',
|
enabled ? 'bg-util-colors-green-green-500' : 'bg-text-quaternary',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -147,14 +147,14 @@ function DeploymentStatusSection({ appInstanceId }: {
|
|||||||
action={(
|
action={(
|
||||||
<Button nativeButton={false} size="small" variant="secondary" render={<Link href={`/deployments/${appInstanceId}/deploy`} />}>
|
<Button nativeButton={false} size="small" variant="secondary" render={<Link href={`/deployments/${appInstanceId}/deploy`} />}>
|
||||||
{t('overview.viewDeployments')}
|
{t('overview.viewDeployments')}
|
||||||
<span className="i-ri-arrow-right-up-line h-3.5 w-3.5" />
|
<span className="i-ri-arrow-right-up-line size-3.5" />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{deployments.length === 0
|
{deployments.length === 0
|
||||||
? (
|
? (
|
||||||
<div className="flex flex-col items-center gap-3 rounded-lg border border-dashed border-components-panel-border bg-components-panel-bg-blur px-4 py-8 text-center">
|
<div className="flex flex-col items-center gap-3 rounded-lg border border-dashed border-components-panel-border bg-components-panel-bg-blur px-4 py-8 text-center">
|
||||||
<span className="i-ri-rocket-line h-5 w-5 text-text-quaternary" />
|
<span className="i-ri-rocket-line size-5 text-text-quaternary" />
|
||||||
<div className="system-sm-regular text-text-tertiary">
|
<div className="system-sm-regular text-text-tertiary">
|
||||||
{releaseRows.length === 0
|
{releaseRows.length === 0
|
||||||
? t(canCreateRelease ? 'overview.noReleaseYet' : 'overview.noReleaseSourceUnavailable')
|
? t(canCreateRelease ? 'overview.noReleaseYet' : 'overview.noReleaseSourceUnavailable')
|
||||||
@ -221,7 +221,7 @@ function AccessStatusSection({ appInstanceId }: {
|
|||||||
action={(
|
action={(
|
||||||
<Button nativeButton={false} size="small" variant="secondary" render={<Link href={`/deployments/${appInstanceId}/access`} />}>
|
<Button nativeButton={false} size="small" variant="secondary" render={<Link href={`/deployments/${appInstanceId}/access`} />}>
|
||||||
{t('overview.configureAccess')}
|
{t('overview.configureAccess')}
|
||||||
<span className="i-ri-arrow-right-up-line h-3.5 w-3.5" />
|
<span className="i-ri-arrow-right-up-line size-3.5" />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@ -255,7 +255,7 @@ export function OverviewTab({ appInstanceId }: {
|
|||||||
appInstanceId: string
|
appInstanceId: string
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="flex w-full max-w-[960px] flex-col gap-5 p-6">
|
<div className="flex w-full max-w-240 flex-col gap-5 p-6">
|
||||||
<BasicInfoSection appInstanceId={appInstanceId} />
|
<BasicInfoSection appInstanceId={appInstanceId} />
|
||||||
<DeploymentStatusSection appInstanceId={appInstanceId} />
|
<DeploymentStatusSection appInstanceId={appInstanceId} />
|
||||||
<AccessStatusSection appInstanceId={appInstanceId} />
|
<AccessStatusSection appInstanceId={appInstanceId} />
|
||||||
|
|||||||
@ -80,7 +80,7 @@ function DeleteInstanceButton({
|
|||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<AlertDialog open={showDeleteConfirm} onOpenChange={open => !open && setShowDeleteConfirm(false)}>
|
<AlertDialog open={showDeleteConfirm} onOpenChange={open => !open && setShowDeleteConfirm(false)}>
|
||||||
<AlertDialogContent className="w-[520px]">
|
<AlertDialogContent className="w-130">
|
||||||
<div className="flex flex-col gap-3 px-6 pt-6 pb-2">
|
<div className="flex flex-col gap-3 px-6 pt-6 pb-2">
|
||||||
<AlertDialogTitle className="title-2xl-semi-bold text-text-primary">
|
<AlertDialogTitle className="title-2xl-semi-bold text-text-primary">
|
||||||
{t('settings.deleteConfirmTitle')}
|
{t('settings.deleteConfirmTitle')}
|
||||||
@ -183,7 +183,7 @@ function SettingsForm({ app, settings }: SettingsFormProps) {
|
|||||||
type="text"
|
type="text"
|
||||||
value={name}
|
value={name}
|
||||||
onChange={e => setName(e.target.value)}
|
onChange={e => setName(e.target.value)}
|
||||||
className="flex h-8 items-center rounded-lg border-[0.5px] border-components-input-border-active bg-components-input-bg-normal px-3 text-[13px] font-medium text-text-secondary outline-hidden placeholder:text-text-quaternary"
|
className="flex h-8 items-center rounded-lg border border-components-input-border-active bg-components-input-bg-normal px-3 system-sm-medium text-text-secondary outline-hidden placeholder:text-text-quaternary"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
@ -194,7 +194,7 @@ function SettingsForm({ app, settings }: SettingsFormProps) {
|
|||||||
id="settings-desc"
|
id="settings-desc"
|
||||||
value={description}
|
value={description}
|
||||||
onChange={e => setDescription(e.target.value)}
|
onChange={e => setDescription(e.target.value)}
|
||||||
className="min-h-[96px] rounded-lg border-[0.5px] border-components-input-border-active bg-components-input-bg-normal px-3 py-2 text-[13px] text-text-secondary outline-hidden placeholder:text-text-quaternary"
|
className="min-h-24 rounded-lg border border-components-input-border-active bg-components-input-bg-normal px-3 py-2 system-sm-regular text-text-secondary outline-hidden placeholder:text-text-quaternary"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-end gap-2">
|
<div className="flex justify-end gap-2">
|
||||||
@ -276,7 +276,7 @@ export function SettingsTab({ appInstanceId }: {
|
|||||||
appInstanceId: string
|
appInstanceId: string
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="flex max-w-[640px] flex-col gap-5 p-6">
|
<div className="flex max-w-160 flex-col gap-5 p-6">
|
||||||
<SettingsFormSection appInstanceId={appInstanceId} />
|
<SettingsFormSection appInstanceId={appInstanceId} />
|
||||||
<DeleteInstanceControlSection appInstanceId={appInstanceId} />
|
<DeleteInstanceControlSection appInstanceId={appInstanceId} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -57,12 +57,12 @@ function CreateReleaseControl({ appInstanceId, canCreateRelease }: {
|
|||||||
disabled={!canCreateRelease}
|
disabled={!canCreateRelease}
|
||||||
onClick={() => setIsCreating(true)}
|
onClick={() => setIsCreating(true)}
|
||||||
>
|
>
|
||||||
<span className="i-ri-add-line h-3.5 w-3.5" />
|
<span className="i-ri-add-line size-3.5" />
|
||||||
{t('versions.createRelease')}
|
{t('versions.createRelease')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Dialog open={isCreating} onOpenChange={setIsCreating}>
|
<Dialog open={isCreating} onOpenChange={setIsCreating}>
|
||||||
<DialogContent className="w-[560px] overflow-hidden p-0">
|
<DialogContent className="w-140 overflow-hidden p-0">
|
||||||
<DialogCloseButton />
|
<DialogCloseButton />
|
||||||
<form
|
<form
|
||||||
onSubmit={(event) => {
|
onSubmit={(event) => {
|
||||||
@ -114,7 +114,7 @@ function CreateReleaseControl({ appInstanceId, canCreateRelease }: {
|
|||||||
name="description"
|
name="description"
|
||||||
placeholder={t('versions.releaseDescriptionPlaceholder')}
|
placeholder={t('versions.releaseDescriptionPlaceholder')}
|
||||||
maxLength={512}
|
maxLength={512}
|
||||||
className="min-h-[96px] w-full resize-none appearance-none rounded-md border border-transparent bg-components-input-bg-normal p-2 system-sm-regular text-components-input-text-filled caret-primary-600 outline-hidden placeholder:text-components-input-text-placeholder hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs"
|
className="min-h-24 w-full resize-none appearance-none rounded-md border border-transparent bg-components-input-bg-normal p-2 system-sm-regular text-components-input-text-filled caret-primary-600 outline-hidden placeholder:text-components-input-text-placeholder hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -135,7 +135,7 @@ function CreateReleaseControl({ appInstanceId, canCreateRelease }: {
|
|||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
variant="primary"
|
variant="primary"
|
||||||
className="min-w-[88px]"
|
className="min-w-22"
|
||||||
disabled={!canCreateRelease || createRelease.isPending}
|
disabled={!canCreateRelease || createRelease.isPending}
|
||||||
>
|
>
|
||||||
{createRelease.isPending ? t('versions.creating') : t('versions.create')}
|
{createRelease.isPending ? t('versions.creating') : t('versions.create')}
|
||||||
@ -174,7 +174,7 @@ export function VersionsTab({ appInstanceId }: {
|
|||||||
const canCreateRelease = overview?.instance?.canCreateRelease ?? true
|
const canCreateRelease = overview?.instance?.canCreateRelease ?? true
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex w-full max-w-[960px] flex-col gap-4 p-6">
|
<div className="flex w-full max-w-240 flex-col gap-4 p-6">
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div className="system-sm-semibold text-text-primary">
|
<div className="system-sm-semibold text-text-primary">
|
||||||
{t('versions.releaseHistory')}
|
{t('versions.releaseHistory')}
|
||||||
|
|||||||
@ -53,10 +53,10 @@ export function DeployReleaseMenu({ appInstanceId, releaseId }: {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{t('versions.deploy')}
|
{t('versions.deploy')}
|
||||||
<span className="i-ri-arrow-down-s-line h-3.5 w-3.5" />
|
<span className="i-ri-arrow-down-s-line size-3.5" />
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
{open && (
|
{open && (
|
||||||
<DropdownMenuContent placement="bottom-end" sideOffset={4} popupClassName="w-[220px]">
|
<DropdownMenuContent placement="bottom-end" sideOffset={4} popupClassName="w-55">
|
||||||
{environments.map((env) => {
|
{environments.map((env) => {
|
||||||
const envId = env.id!
|
const envId = env.id!
|
||||||
const row = deploymentRows.find(item => environmentId(item.environment) === envId)
|
const row = deploymentRows.find(item => environmentId(item.environment) === envId)
|
||||||
|
|||||||
@ -28,10 +28,10 @@ export function DeployedToBadge({ item }: {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{item.state === 'deploying'
|
{item.state === 'deploying'
|
||||||
? <span className="i-ri-loader-4-line h-3.5 w-3.5 animate-spin" />
|
? <span className="i-ri-loader-4-line size-3.5 animate-spin" />
|
||||||
: item.state === 'failed'
|
: item.state === 'failed'
|
||||||
? <span className="i-ri-alert-line h-3.5 w-3.5" />
|
? <span className="i-ri-alert-line size-3.5" />
|
||||||
: <span className="h-1.5 w-1.5 rounded-full bg-current" />}
|
: <span className="size-1.5 rounded-full bg-current" />}
|
||||||
{item.environmentName}
|
{item.environmentName}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -32,7 +32,7 @@ function getEnvironmentFilterOption(env: DeploymentEnvironmentOption & { id: str
|
|||||||
return {
|
return {
|
||||||
value: env.id,
|
value: env.id,
|
||||||
text: env.name || env.id,
|
text: env.name || env.id,
|
||||||
icon: <span className="i-ri-stack-line h-[14px] w-[14px]" />,
|
icon: <span className="i-ri-stack-line size-[14px]" />,
|
||||||
disabled: env.deployable === false,
|
disabled: env.deployable === false,
|
||||||
disabledReason: env.disabledReason,
|
disabledReason: env.disabledReason,
|
||||||
}
|
}
|
||||||
@ -53,13 +53,13 @@ export function EnvironmentFilter() {
|
|||||||
{
|
{
|
||||||
value: 'all',
|
value: 'all',
|
||||||
text: t('filter.allEnvs'),
|
text: t('filter.allEnvs'),
|
||||||
icon: <span className="i-ri-apps-2-line h-[14px] w-[14px]" />,
|
icon: <span className="i-ri-apps-2-line size-[14px]" />,
|
||||||
},
|
},
|
||||||
...environments.map(getEnvironmentFilterOption),
|
...environments.map(getEnvironmentFilterOption),
|
||||||
{
|
{
|
||||||
value: 'not-deployed',
|
value: 'not-deployed',
|
||||||
text: t('filter.notDeployed'),
|
text: t('filter.notDeployed'),
|
||||||
icon: <span className="i-ri-inbox-line h-[14px] w-[14px]" />,
|
icon: <span className="i-ri-inbox-line size-[14px]" />,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
const selectedOption = filterOptions.find(option => option.value === activeFilter) ?? filterOptions[0]
|
const selectedOption = filterOptions.find(option => option.value === activeFilter) ?? filterOptions[0]
|
||||||
@ -68,25 +68,25 @@ export function EnvironmentFilter() {
|
|||||||
<DropdownMenu modal={false} open={open} onOpenChange={setOpen}>
|
<DropdownMenu modal={false} open={open} onOpenChange={setOpen}>
|
||||||
<DropdownMenuTrigger
|
<DropdownMenuTrigger
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex h-8 cursor-pointer items-center gap-1 rounded-lg border-[0.5px] border-transparent bg-components-input-bg-normal px-2 text-left select-none',
|
'flex h-8 cursor-pointer items-center gap-1 rounded-lg border border-transparent bg-components-input-bg-normal px-2 text-left select-none',
|
||||||
open && 'shadow-xs',
|
open && 'shadow-xs',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="p-px text-text-tertiary">
|
<div className="p-px text-text-tertiary">
|
||||||
{selectedOption?.icon}
|
{selectedOption?.icon}
|
||||||
</div>
|
</div>
|
||||||
<div className="max-w-[160px] min-w-0 truncate text-[13px] leading-[18px] text-text-secondary">
|
<div className="max-w-40 min-w-0 truncate system-sm-regular text-text-secondary">
|
||||||
{selectedOption?.text}
|
{selectedOption?.text}
|
||||||
</div>
|
</div>
|
||||||
<div className="shrink-0 p-px">
|
<div className="shrink-0 p-px">
|
||||||
<span className={cn('i-ri-arrow-down-s-line h-3.5 w-3.5 text-text-tertiary transition-transform', open && 'rotate-180')} />
|
<span className={cn('i-ri-arrow-down-s-line size-3.5 text-text-tertiary transition-transform', open && 'rotate-180')} />
|
||||||
</div>
|
</div>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
{open && (
|
{open && (
|
||||||
<DropdownMenuContent
|
<DropdownMenuContent
|
||||||
placement="bottom-start"
|
placement="bottom-start"
|
||||||
sideOffset={4}
|
sideOffset={4}
|
||||||
popupClassName="w-[240px] rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-[5px]"
|
popupClassName="w-60 rounded-lg border border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-xs"
|
||||||
>
|
>
|
||||||
<div className="max-h-72 overflow-auto p-1">
|
<div className="max-h-72 overflow-auto p-1">
|
||||||
{filterOptions.map(option => (
|
{filterOptions.map(option => (
|
||||||
@ -101,16 +101,16 @@ export function EnvironmentFilter() {
|
|||||||
title={option.disabled ? option.disabledReason : undefined}
|
title={option.disabled ? option.disabledReason : undefined}
|
||||||
aria-disabled={option.disabled}
|
aria-disabled={option.disabled}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex items-center gap-2 rounded-lg py-[6px] pr-2 pl-3 select-none',
|
'flex items-center gap-2 rounded-lg py-1.5 pr-2 pl-3 select-none',
|
||||||
option.disabled
|
option.disabled
|
||||||
? 'cursor-not-allowed opacity-50'
|
? 'cursor-not-allowed opacity-50'
|
||||||
: 'cursor-pointer hover:bg-state-base-hover',
|
: 'cursor-pointer hover:bg-state-base-hover',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span className="shrink-0 text-text-tertiary">{option.icon}</span>
|
<span className="shrink-0 text-text-tertiary">{option.icon}</span>
|
||||||
<span className="grow truncate text-sm leading-5 text-text-tertiary">{option.text}</span>
|
<span className="grow truncate text-sm/5 text-text-tertiary">{option.text}</span>
|
||||||
{option.value === activeFilter && (
|
{option.value === activeFilter && (
|
||||||
<span className="i-custom-vender-line-general-check h-4 w-4 shrink-0 text-text-secondary" />
|
<span className="i-custom-vender-line-general-check size-4 shrink-0 text-text-secondary" />
|
||||||
)}
|
)}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -27,7 +27,7 @@ function DeploymentsSearchInput() {
|
|||||||
<Input
|
<Input
|
||||||
showLeftIcon
|
showLeftIcon
|
||||||
showClearIcon
|
showClearIcon
|
||||||
wrapperClassName="w-[200px]"
|
wrapperClassName="w-50"
|
||||||
placeholder={t('filter.searchPlaceholder')}
|
placeholder={t('filter.searchPlaceholder')}
|
||||||
value={keywords}
|
value={keywords}
|
||||||
onChange={e => handleKeywordsChange(e.target.value)}
|
onChange={e => handleKeywordsChange(e.target.value)}
|
||||||
@ -72,7 +72,7 @@ function DeploymentsList() {
|
|||||||
return (
|
return (
|
||||||
<div className="relative flex h-0 shrink-0 grow flex-col overflow-y-auto bg-background-body">
|
<div className="relative flex h-0 shrink-0 grow flex-col overflow-y-auto bg-background-body">
|
||||||
<DeploymentsListControls />
|
<DeploymentsListControls />
|
||||||
<div className="relative grid grow grid-cols-1 content-start gap-4 px-12 pt-2 2k:grid-cols-6 sm:grid-cols-1 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-5">
|
<div className="relative grid grow grid-cols-1 content-start gap-4 px-12 pt-2 2k:grid-cols-6 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-5">
|
||||||
<NewInstanceCard />
|
<NewInstanceCard />
|
||||||
{apps.map(app => (
|
{apps.map(app => (
|
||||||
<InstanceCard
|
<InstanceCard
|
||||||
|
|||||||
@ -22,16 +22,16 @@ function NewInstanceAction({ icon, label, disabled, onClick }: NewInstanceAction
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
title={disabled ? t('newInstance.comingSoon') : undefined}
|
title={disabled ? t('newInstance.comingSoon') : undefined}
|
||||||
className={cn(
|
className={cn(
|
||||||
'mb-1 flex w-full items-center rounded-lg px-6 py-[7px] text-left text-[13px] leading-[18px] font-medium text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
|
'mb-1 flex h-8 w-full items-center gap-2 rounded-lg px-6 text-left system-sm-medium text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary',
|
||||||
disabled
|
disabled
|
||||||
? 'cursor-not-allowed opacity-50 hover:bg-transparent hover:text-text-tertiary'
|
? 'cursor-not-allowed opacity-50 hover:bg-transparent hover:text-text-tertiary'
|
||||||
: 'cursor-pointer',
|
: 'cursor-pointer',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span aria-hidden className={cn('mr-2 h-4 w-4 shrink-0', icon)} />
|
<span aria-hidden className={cn('size-4 shrink-0', icon)} />
|
||||||
<span className="min-w-0 flex-1 truncate">{label}</span>
|
<span className="min-w-0 flex-1 truncate">{label}</span>
|
||||||
{disabled && (
|
{disabled && (
|
||||||
<span className="ml-2 shrink-0 rounded-md bg-state-base-hover px-1.5 system-2xs-medium text-text-tertiary">
|
<span className="shrink-0 rounded-md bg-state-base-hover px-1.5 system-2xs-medium text-text-tertiary">
|
||||||
{t('newInstance.comingSoon')}
|
{t('newInstance.comingSoon')}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@ -56,9 +56,9 @@ export function NewInstanceCard() {
|
|||||||
const { t } = useTranslation('deployments')
|
const { t } = useTranslation('deployments')
|
||||||
|
|
||||||
return (
|
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">
|
<div className="relative col-span-1 inline-flex h-40 flex-col justify-between rounded-xl border border-components-card-border bg-components-card-bg">
|
||||||
<div className="grow rounded-t-xl p-2">
|
<div className="grow rounded-t-xl p-2">
|
||||||
<div className="px-6 pt-2 pb-1 text-xs leading-[18px] font-medium text-text-tertiary">
|
<div className="px-6 pt-2 pb-1 text-xs/[18px] font-medium text-text-tertiary">
|
||||||
{t('newInstance.title')}
|
{t('newInstance.title')}
|
||||||
</div>
|
</div>
|
||||||
<CreateFromStudioAction />
|
<CreateFromStudioAction />
|
||||||
|
|||||||
@ -94,8 +94,8 @@ export function DeploymentsNav() {
|
|||||||
return (
|
return (
|
||||||
<Nav
|
<Nav
|
||||||
isApp={false}
|
isApp={false}
|
||||||
icon={<span aria-hidden className="i-ri-rocket-line h-4 w-4" />}
|
icon={<span aria-hidden className="i-ri-rocket-line size-4" />}
|
||||||
activeIcon={<span aria-hidden className="i-ri-rocket-fill h-4 w-4" />}
|
activeIcon={<span aria-hidden className="i-ri-rocket-fill size-4" />}
|
||||||
text={t('menus.deployments', { ns: 'common' })}
|
text={t('menus.deployments', { ns: 'common' })}
|
||||||
activeSegment="deployments"
|
activeSegment="deployments"
|
||||||
link="/deployments"
|
link="/deployments"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user