From 4f434ec525f321f1ca3e1f601683bcbbcfe67aa3 Mon Sep 17 00:00:00 2001 From: Zyy Date: Sun, 6 Sep 2026 12:08:34 +0800 Subject: [PATCH] fix(theme): restore semantic color roles Separate semantic text on neutral surfaces from high-contrast text on tinted backgrounds, derive each role against its actual surfaces, and migrate badges and alerts to explicit on-background tokens. Restore vivid usage-table accents and align input hover, active, and error outlines across light and dark themes. Validated with semantic contrast checks across presets and custom seeds, frontend typecheck, lint and production build. Co-authored-by: Codex --- frontend/src/components/base/BaseButton.vue | 2 +- .../src/components/base/BaseIconButton.vue | 4 +- frontend/src/components/base/BaseMenuItem.vue | 2 +- frontend/src/components/base/BaseSelect.vue | 2 +- frontend/src/layout/components/AppSidebar.vue | 4 +- .../components/SystemUpdateModal/index.vue | 2 +- .../components/SystemUpdateModal/presenter.ts | 6 +- frontend/src/styles/index.css | 4 ++ frontend/src/theme/core/resolve.ts | 2 +- frontend/src/theme/core/tokens.ts | 1 + frontend/src/theme/derive/colors.ts | 59 ++++++++++++++++--- frontend/src/theme/derive/components.ts | 8 +-- frontend/src/theme/derive/roles.ts | 6 +- frontend/src/theme/types.ts | 5 ++ frontend/src/views/account-groups/index.vue | 2 +- .../components/AccountOverviewCards.vue | 2 +- .../AccountQuotaPanel/ResetCredits.vue | 6 +- .../AccountStatusBadge/presenter.ts | 16 ++--- .../composables/useAccountConnectionTest.ts | 6 +- .../api-keys/components/ApiKeyCreateModal.vue | 2 +- .../api-keys/components/ApiKeyScopeCell.vue | 2 +- .../api-keys/components/ApiKeyStatusBadge.vue | 2 +- .../dashboard/components/WireProfileCard.vue | 8 +-- frontend/src/views/dashboard/constants.ts | 8 +-- .../ClientDesktopOfflineDownloads.vue | 4 +- .../components/ThemeComponentPreview.vue | 22 +++---- .../views/usage/components/OpsErrorPanel.vue | 2 +- .../usage/components/UsageLatencyCell.vue | 2 +- .../usage/components/UsageStatusCodeBadge.vue | 6 +- 29 files changed, 126 insertions(+), 71 deletions(-) diff --git a/frontend/src/components/base/BaseButton.vue b/frontend/src/components/base/BaseButton.vue index 835432b73..56e393a87 100644 --- a/frontend/src/components/base/BaseButton.vue +++ b/frontend/src/components/base/BaseButton.vue @@ -35,7 +35,7 @@ const variantClasses: Record = { 'bg-cp-fill-tertiary text-cp-text shadow-cp-tertiary hover:bg-cp-bg-text-active active:bg-cp-bg-text-active', ghost: 'bg-transparent text-cp-text-secondary shadow-none hover:bg-cp-fill-quaternary hover:text-cp-text active:bg-cp-fill-tertiary', - destructive: 'bg-cp-error-bg text-cp-error-text shadow-none hover:bg-cp-error-bg-hover active:bg-cp-error-bg-active', + destructive: 'bg-cp-error-bg text-cp-error-text-on-bg shadow-none hover:bg-cp-error-bg-hover active:bg-cp-error-bg-active', } const sizeClasses: Record = { diff --git a/frontend/src/components/base/BaseIconButton.vue b/frontend/src/components/base/BaseIconButton.vue index 331fefb1c..bb4e2ee30 100644 --- a/frontend/src/components/base/BaseIconButton.vue +++ b/frontend/src/components/base/BaseIconButton.vue @@ -36,10 +36,10 @@ const variantClasses: Record = { secondary: 'bg-cp-bg-container text-cp-text-secondary shadow-cp-tertiary hover:bg-cp-bg-text-hover hover:text-cp-text active:bg-cp-bg-text-active', success: - 'bg-cp-success-bg text-cp-success-text shadow-none hover:bg-cp-success-bg-hover active:bg-cp-success-bg-active', + 'bg-cp-success-bg text-cp-success-text-on-bg shadow-none hover:bg-cp-success-bg-hover active:bg-cp-success-bg-active', ghost: 'bg-transparent text-cp-text-secondary shadow-none hover:bg-cp-fill-quaternary hover:text-cp-text active:bg-cp-fill-tertiary', - destructive: 'bg-transparent text-cp-error-text shadow-none hover:bg-cp-error-bg-hover active:bg-cp-error-bg-active', + destructive: 'bg-transparent text-cp-error-text shadow-none hover:bg-cp-error-bg-hover hover:text-cp-error-text-on-bg active:bg-cp-error-bg-active active:text-cp-error-text-on-bg', } const sizeClasses: Record = { diff --git a/frontend/src/components/base/BaseMenuItem.vue b/frontend/src/components/base/BaseMenuItem.vue index 50488c03e..6bdeb00e1 100644 --- a/frontend/src/components/base/BaseMenuItem.vue +++ b/frontend/src/components/base/BaseMenuItem.vue @@ -26,7 +26,7 @@ const classes = computed(() => [ 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-cp-control-outline', 'disabled:cursor-not-allowed disabled:text-cp-text-disabled', props.tone === 'destructive' - ? 'text-cp-error-text hover:bg-cp-error-bg-hover' + ? 'text-cp-error-text hover:bg-cp-error-bg-hover hover:text-cp-error-text-on-bg' : 'text-cp-text hover:bg-cp-bg-text-hover', ]) diff --git a/frontend/src/components/base/BaseSelect.vue b/frontend/src/components/base/BaseSelect.vue index 7445d920b..a3bbe93e2 100644 --- a/frontend/src/components/base/BaseSelect.vue +++ b/frontend/src/components/base/BaseSelect.vue @@ -98,7 +98,7 @@ const triggerClasses = computed(() => [ props.disabled ? 'cursor-not-allowed bg-cp-bg-container-disabled text-cp-text-disabled shadow-none' : invalid.value - ? 'cursor-pointer bg-(--cp-input-error-active-bg) text-cp-error-text shadow-cp-input-error-active' + ? 'cursor-pointer bg-(--cp-input-error-active-bg) text-cp-error-text-on-bg shadow-cp-input-error-active' : open.value ? 'cursor-pointer bg-(--cp-input-active-bg) text-cp-text shadow-cp-input-active' : [ diff --git a/frontend/src/layout/components/AppSidebar.vue b/frontend/src/layout/components/AppSidebar.vue index ca2932b5c..04fad0492 100644 --- a/frontend/src/layout/components/AppSidebar.vue +++ b/frontend/src/layout/components/AppSidebar.vue @@ -342,7 +342,7 @@ onBeforeUnmount(() => { class="inline-flex h-4.5 min-w-0 cursor-pointer items-center gap-1 rounded-cp-sm border-0 px-1.5 font-mono text-[10px] leading-none font-bold transition-colors outline-none focus-visible:ring-2 focus-visible:ring-cp-control-outline focus-visible:ring-offset-2 focus-visible:ring-offset-cp-bg-container" :class="[ hasUpdate - ? 'bg-cp-success-bg text-cp-success-text hover:bg-cp-success-bg-hover' + ? 'bg-cp-success-bg text-cp-success-text-on-bg hover:bg-cp-success-bg-hover' : 'bg-cp-fill-quaternary text-cp-text-quaternary hover:bg-cp-fill-tertiary hover:text-cp-text-secondary', ]" :title="updateButtonLabel" @@ -399,7 +399,7 @@ onBeforeUnmount(() => { > 在线 diff --git a/frontend/src/layout/components/SystemUpdateModal/index.vue b/frontend/src/layout/components/SystemUpdateModal/index.vue index e3ee78759..cecc6a278 100644 --- a/frontend/src/layout/components/SystemUpdateModal/index.vue +++ b/frontend/src/layout/components/SystemUpdateModal/index.vue @@ -257,7 +257,7 @@ watch(

{{ updateError || updateInfo?.warning }}

diff --git a/frontend/src/layout/components/SystemUpdateModal/presenter.ts b/frontend/src/layout/components/SystemUpdateModal/presenter.ts index 5d0468fa2..20f41cbd9 100644 --- a/frontend/src/layout/components/SystemUpdateModal/presenter.ts +++ b/frontend/src/layout/components/SystemUpdateModal/presenter.ts @@ -47,7 +47,7 @@ function resolveStatus(input: SystemUpdatePresentationInput) { return { label: input.restarting ? '重启中' : '更新中', icon: RefreshCw, - badge: 'bg-cp-info-bg text-cp-info-text', + badge: 'bg-cp-info-bg text-cp-info-text-on-bg', iconClass: 'text-cp-info', } } @@ -55,7 +55,7 @@ function resolveStatus(input: SystemUpdatePresentationInput) { return { label: '异常', icon: XCircle, - badge: 'bg-cp-error-bg text-cp-error-text', + badge: 'bg-cp-error-bg text-cp-error-text-on-bg', iconClass: 'text-cp-error', } } @@ -63,7 +63,7 @@ function resolveStatus(input: SystemUpdatePresentationInput) { return { label: input.updateSuccess ? '已更新' : input.hasUpdate ? '有新版本' : '已是最新', icon: input.hasUpdate ? ArrowUpCircle : CheckCircle2, - badge: 'bg-cp-success-bg text-cp-success-text', + badge: 'bg-cp-success-bg text-cp-success-text-on-bg', iconClass: 'text-cp-success', } } diff --git a/frontend/src/styles/index.css b/frontend/src/styles/index.css index 60c8488ff..3324fde42 100644 --- a/frontend/src/styles/index.css +++ b/frontend/src/styles/index.css @@ -72,6 +72,7 @@ --color-cp-info-active: var(--cp-color-info-active); --color-cp-info-text-hover: var(--cp-color-info-text-hover); --color-cp-info-text: var(--cp-color-info-text); + --color-cp-info-text-on-bg: var(--cp-color-info-text-on-bg); --color-cp-info-text-active: var(--cp-color-info-text-active); --color-cp-success-bg: var(--cp-color-success-bg); --color-cp-success-bg-hover: var(--cp-color-success-bg-hover); @@ -83,6 +84,7 @@ --color-cp-success-active: var(--cp-color-success-active); --color-cp-success-text-hover: var(--cp-color-success-text-hover); --color-cp-success-text: var(--cp-color-success-text); + --color-cp-success-text-on-bg: var(--cp-color-success-text-on-bg); --color-cp-success-text-active: var(--cp-color-success-text-active); --color-cp-warning-bg: var(--cp-color-warning-bg); --color-cp-warning-bg-hover: var(--cp-color-warning-bg-hover); @@ -94,6 +96,7 @@ --color-cp-warning-active: var(--cp-color-warning-active); --color-cp-warning-text-hover: var(--cp-color-warning-text-hover); --color-cp-warning-text: var(--cp-color-warning-text); + --color-cp-warning-text-on-bg: var(--cp-color-warning-text-on-bg); --color-cp-warning-text-active: var(--cp-color-warning-text-active); --color-cp-error-bg: var(--cp-color-error-bg); --color-cp-error-bg-hover: var(--cp-color-error-bg-hover); @@ -105,6 +108,7 @@ --color-cp-error-active: var(--cp-color-error-active); --color-cp-error-text-hover: var(--cp-color-error-text-hover); --color-cp-error-text: var(--cp-color-error-text); + --color-cp-error-text-on-bg: var(--cp-color-error-text-on-bg); --color-cp-error-text-active: var(--cp-color-error-text-active); /* 颜色 · 预设(色系按字母排序,角色顺序固定) */ diff --git a/frontend/src/theme/core/resolve.ts b/frontend/src/theme/core/resolve.ts index 459b8fccd..ce563c34e 100644 --- a/frontend/src/theme/core/resolve.ts +++ b/frontend/src/theme/core/resolve.ts @@ -100,7 +100,7 @@ function deriveThemeMap( const aliases = deriveThemeAliasMap(surfaces) const primary = deriveThemePrimaryMap(seed, name, surfaces.colorBgContainer) const link = deriveThemeLinkMap(seedTokens.colorLink, name, surfaces.colorBgContainer) - const semantics = deriveThemeSemanticMap(name, surfaces.colorBgContainer, seedTokens) + const semantics = deriveThemeSemanticMap(name, surfaces, seedTokens) return { surfaces, diff --git a/frontend/src/theme/core/tokens.ts b/frontend/src/theme/core/tokens.ts index 9234869b5..c768c5bb3 100644 --- a/frontend/src/theme/core/tokens.ts +++ b/frontend/src/theme/core/tokens.ts @@ -38,6 +38,7 @@ const FUNCTIONAL_TOKEN_ROLES = [ ['active', '-active'], ['textHover', '-text-hover'], ['text', '-text'], + ['textOnBackground', '-text-on-bg'], ['textActive', '-text-active'], ] as const satisfies readonly (readonly [keyof FunctionalColorMap, FunctionalTokenSuffix])[] diff --git a/frontend/src/theme/derive/colors.ts b/frontend/src/theme/derive/colors.ts index fed0c6522..1d9b6f836 100644 --- a/frontend/src/theme/derive/colors.ts +++ b/frontend/src/theme/derive/colors.ts @@ -133,16 +133,51 @@ export function deriveThemeLinkMap( export function deriveThemeSemanticMap( theme: ThemeName, - containerBg: string, + surfaces: ThemeSurfaceMap, seedTokens: ResolvedThemeSeedTokens, ): ThemeSemanticMap { const recipe = THEME_COLOR_ROLE_RECIPES[theme].semantic + const containerBg = surfaces.colorBgContainer + const textBackgrounds = [ + surfaces.colorBgLayout, + surfaces.colorBgContainer, + surfaces.colorBgElevated, + surfaces.colorBgTextHover, + surfaces.colorBgTextActive, + surfaces.colorFillSecondary, + surfaces.colorFillTertiary, + surfaces.colorFillQuaternary, + ] return { - info: deriveColorRoleMap(seedTokens.colorInfo, theme, containerBg, recipe), - success: deriveColorRoleMap(seedTokens.colorSuccess, theme, containerBg, recipe), - warning: deriveColorRoleMap(seedTokens.colorWarning, theme, containerBg, recipe), - error: deriveColorRoleMap(seedTokens.colorError, theme, containerBg, recipe), + info: deriveColorRoleMap( + seedTokens.colorInfo, + theme, + containerBg, + recipe, + textBackgrounds, + ), + success: deriveColorRoleMap( + seedTokens.colorSuccess, + theme, + containerBg, + recipe, + textBackgrounds, + ), + warning: deriveColorRoleMap( + seedTokens.colorWarning, + theme, + containerBg, + recipe, + textBackgrounds, + ), + error: deriveColorRoleMap( + seedTokens.colorError, + theme, + containerBg, + recipe, + textBackgrounds, + ), } } @@ -409,6 +444,7 @@ function deriveColorRoleMap( theme: ThemeName, containerBg: string, recipe: ThemeColorRoleRecipe, + textBackgrounds: string | readonly string[] = containerBg, ): FunctionalColorMap { const normalizedSeed = normalizeHexColor(seed) ?? DEFAULT_CUSTOM_THEME_COLOR const palette = generateColorPalette(normalizedSeed, theme, containerBg) @@ -421,13 +457,16 @@ function deriveColorRoleMap( const background = mix(containerBg, color, recipe.backgroundMix) const backgroundHover = mix(containerBg, hover, recipe.backgroundHoverMix) const backgroundActive = mix(containerBg, active, recipe.backgroundActiveMix) - const textBackgrounds = [containerBg, background, backgroundHover, backgroundActive] - const resolveText = (source: ThemePaletteSource): string => { + const semanticBackgrounds = [background, backgroundHover, backgroundActive] + const resolveText = ( + source: ThemePaletteSource, + backgrounds: string | readonly string[] = textBackgrounds, + ): string => { const value = resolve(source) const toned = recipe.minimumTextLightness === undefined ? value : ensureLightness(value, recipe.minimumTextLightness) - return ensureContrast(toned, textBackgrounds, 4.5) + return ensureContrast(toned, backgrounds, 4.5) } return { @@ -445,6 +484,10 @@ function deriveColorRoleMap( : ensureContrast(active, containerBg, recipe.activeContrast), textHover: resolveText(recipe.textHover), text: resolveText(recipe.text), + textOnBackground: resolveText( + recipe.textOnBackground ?? recipe.text, + semanticBackgrounds, + ), textActive: resolveText(recipe.textActive), } } diff --git a/frontend/src/theme/derive/components.ts b/frontend/src/theme/derive/components.ts index d0cd9f647..f73f578f8 100644 --- a/frontend/src/theme/derive/components.ts +++ b/frontend/src/theme/derive/components.ts @@ -184,8 +184,8 @@ function deriveDarkComponentMap( `0 0 0 3px ${inputOutlineColor}, 0 14px 28px -22px ${withAlpha(BLACK, 0.72)}`, shadowStrength, ), - inputActiveShadow: '0 0 0 3px var(--cp-control-outline)', - inputErrorActiveShadow: `0 0 0 3px ${error.border}`, + inputActiveShadow: `0 0 0 3px ${inputOutlineColor}`, + inputErrorActiveShadow: `0 0 0 3px ${withAlpha(error.color, 0.28)}`, layoutSiderShadow: scaleShadowAlpha(`2px 0 18px -14px ${withAlpha(BLACK, 0.72)}`, shadowStrength), scrollbarThumbBg: mix(surfaces.colorBorderSecondary, surfaces.colorTextSecondary, 0.16), scrollbarThumbHoverBg: mix(surfaces.colorBorderSecondary, surfaces.colorTextSecondary, 0.3), @@ -237,8 +237,8 @@ function deriveLightComponentMap( `0 0 0 3px ${inputOutlineColor}, 0 12px 24px -16px ${withAlpha(LIGHT_SHADOW_BASE, 0.12)}`, shadowStrength, ), - inputActiveShadow: '0 0 0 3px var(--cp-control-outline)', - inputErrorActiveShadow: `0 0 0 3px ${error.border}`, + inputActiveShadow: `0 0 0 3px ${inputOutlineColor}`, + inputErrorActiveShadow: `0 0 0 3px ${withAlpha(error.color, 0.18)}`, layoutSiderShadow: scaleShadowAlpha(`2px 0 12px -12px ${withAlpha(LIGHT_SHADOW_BASE, 0.027)}`, shadowStrength), scrollbarThumbBg: mix(surfaces.colorBgLayout, surfaces.colorTextSecondary, 0.2), scrollbarThumbHoverBg: mix(surfaces.colorBgLayout, surfaces.colorTextSecondary, 0.34), diff --git a/frontend/src/theme/derive/roles.ts b/frontend/src/theme/derive/roles.ts index cd885474d..b0aac78c3 100644 --- a/frontend/src/theme/derive/roles.ts +++ b/frontend/src/theme/derive/roles.ts @@ -24,7 +24,8 @@ export const THEME_COLOR_ROLE_RECIPES = { hover: 5, active: 7, textHover: 5, - text: 6, + text: 7, + textOnBackground: 6, textActive: 7, backgroundMix: 0.08, backgroundHoverMix: 0.12, @@ -62,7 +63,8 @@ export const THEME_COLOR_ROLE_RECIPES = { hover: 8, active: 6, textHover: 8, - text: 9, + text: 7, + textOnBackground: 9, textActive: 10, backgroundMix: 0.18, backgroundHoverMix: 0.24, diff --git a/frontend/src/theme/types.ts b/frontend/src/theme/types.ts index a46edb0cc..4a6229d99 100644 --- a/frontend/src/theme/types.ts +++ b/frontend/src/theme/types.ts @@ -90,6 +90,7 @@ export interface ThemeColorRoleRecipe { active: ThemePaletteSource textHover: ThemePaletteSource text: ThemePaletteSource + textOnBackground?: ThemePaletteSource textActive: ThemePaletteSource backgroundMix: number backgroundHoverMix: number @@ -211,7 +212,10 @@ export interface FunctionalColorMap { border: string borderHover: string textHover: string + /** 语义色在中性表面上的强调文字。 */ text: string + /** 语义色在自身背景上的高对比文字。 */ + textOnBackground: string textActive: string } @@ -308,6 +312,7 @@ export type FunctionalTokenSuffix | '-border-hover' | '-text-hover' | '-text' + | '-text-on-bg' | '-text-active' type SemanticColorName = Extract diff --git a/frontend/src/views/account-groups/index.vue b/frontend/src/views/account-groups/index.vue index 74280ea91..19e51090e 100644 --- a/frontend/src/views/account-groups/index.vue +++ b/frontend/src/views/account-groups/index.vue @@ -121,7 +121,7 @@ const { allSelected, indeterminate, selectedRowKeys, toggleSelection, toggleAll {{ row.enabled ? '已启用' : '已禁用' }} diff --git a/frontend/src/views/accounts/components/AccountOverviewCards.vue b/frontend/src/views/accounts/components/AccountOverviewCards.vue index 1e58e82b7..faa51b67c 100644 --- a/frontend/src/views/accounts/components/AccountOverviewCards.vue +++ b/frontend/src/views/accounts/components/AccountOverviewCards.vue @@ -50,7 +50,7 @@ function overviewIconClass(tone: string) { return 'bg-cp-orange-bg text-cp-orange-text-on-bg' } if (tone === 'danger') { - return 'bg-cp-error-bg text-cp-error-text' + return 'bg-cp-error-bg text-cp-error-text-on-bg' } return 'bg-cp-blue-bg text-cp-blue-text-on-bg' } diff --git a/frontend/src/views/accounts/components/AccountQuotaPanel/ResetCredits.vue b/frontend/src/views/accounts/components/AccountQuotaPanel/ResetCredits.vue index 854eae4c8..d32bc75c7 100644 --- a/frontend/src/views/accounts/components/AccountQuotaPanel/ResetCredits.vue +++ b/frontend/src/views/accounts/components/AccountQuotaPanel/ResetCredits.vue @@ -140,9 +140,9 @@ async function handleConfirmConsume() {
- +
-

+

上次操作结果待确认

@@ -193,7 +193,7 @@ async function handleConfirmConsume() {

{{ loadError }},请刷新重试。 diff --git a/frontend/src/views/accounts/components/AccountStatusBadge/presenter.ts b/frontend/src/views/accounts/components/AccountStatusBadge/presenter.ts index b6be604f4..6dd7546de 100644 --- a/frontend/src/views/accounts/components/AccountStatusBadge/presenter.ts +++ b/frontend/src/views/accounts/components/AccountStatusBadge/presenter.ts @@ -53,26 +53,26 @@ const statusStyles: Record = { success: { text: 'text-cp-success-text', dot: 'bg-cp-success', - badge: 'bg-cp-success-bg text-cp-success-text', - icon: 'bg-cp-success-bg text-cp-success-text', + badge: 'bg-cp-success-bg text-cp-success-text-on-bg', + icon: 'bg-cp-success-bg text-cp-success-text-on-bg', }, danger: { text: 'text-cp-error-text', dot: 'bg-cp-error', - badge: 'bg-cp-error-bg text-cp-error-text', - icon: 'bg-cp-error-bg text-cp-error-text', + badge: 'bg-cp-error-bg text-cp-error-text-on-bg', + icon: 'bg-cp-error-bg text-cp-error-text-on-bg', }, warning: { text: 'text-cp-warning-text', dot: 'bg-cp-warning', - badge: 'bg-cp-warning-bg text-cp-warning-text', - icon: 'bg-cp-warning-bg text-cp-warning-text', + badge: 'bg-cp-warning-bg text-cp-warning-text-on-bg', + icon: 'bg-cp-warning-bg text-cp-warning-text-on-bg', }, info: { text: 'text-cp-info-text', dot: 'bg-cp-info', - badge: 'bg-cp-info-bg text-cp-info-text', - icon: 'bg-cp-info-bg text-cp-info-text', + badge: 'bg-cp-info-bg text-cp-info-text-on-bg', + icon: 'bg-cp-info-bg text-cp-info-text-on-bg', }, normal: { text: 'text-cp-text-secondary', diff --git a/frontend/src/views/accounts/composables/useAccountConnectionTest.ts b/frontend/src/views/accounts/composables/useAccountConnectionTest.ts index b9c20fadc..06c7214fb 100644 --- a/frontend/src/views/accounts/composables/useAccountConnectionTest.ts +++ b/frontend/src/views/accounts/composables/useAccountConnectionTest.ts @@ -191,7 +191,7 @@ export function useAccountConnectionTest(options: { reload: () => Promise Promise Promise props.editing ? '编辑 API Key' : '创建 API Key' >

-

+

该密钥具有网关访问权限,请仅发送给可信调用方

diff --git a/frontend/src/views/api-keys/components/ApiKeyScopeCell.vue b/frontend/src/views/api-keys/components/ApiKeyScopeCell.vue index 1fb38f099..f22ccef3e 100644 --- a/frontend/src/views/api-keys/components/ApiKeyScopeCell.vue +++ b/frontend/src/views/api-keys/components/ApiKeyScopeCell.vue @@ -11,7 +11,7 @@ defineProps<{