mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-17 22:14:08 +00:00
fix(codex-auth): close remaining review gaps
This commit is contained in:
1 parent
08fe63c626
commit
5c79df4311
20 files changed
+823
-93
No files matched your search
@@ -10,8 +10,9 @@
|
||||
*/
|
||||
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { TFunction } from 'i18next';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
@@ -28,6 +29,14 @@ import type { CodexAuthProfileEntry } from '@/hooks/use-codex-auth-profiles';
|
||||
|
||||
// ── Helpers ─────────────────────────────────────────────────────────────────
|
||||
|
||||
function InlineCode({ children }: { children?: ReactNode }) {
|
||||
return (
|
||||
<code className="rounded bg-muted px-1 py-0.5 font-mono text-[0.85em] text-foreground">
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
}
|
||||
|
||||
function formatLastUsed(iso: string | null): string {
|
||||
if (!iso) return 'never';
|
||||
try {
|
||||
@@ -60,8 +69,6 @@ function sourceLabel(source: 'default' | 'env' | 'explicit-codex-home', t: TFunc
|
||||
// ── Disabled action button with terminal-redirect tooltip ───────────────────
|
||||
|
||||
function TerminalOnlyButton({ label }: { label: string }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
@@ -73,7 +80,12 @@ function TerminalOnlyButton({ label }: { label: string }) {
|
||||
</Button>
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{t('codex.auth.terminalOnlyTooltip')}</TooltipContent>
|
||||
<TooltipContent>
|
||||
<Trans
|
||||
i18nKey="codex.auth.terminalOnlyTooltipRich"
|
||||
components={{ code: <InlineCode /> }}
|
||||
/>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
);
|
||||
@@ -155,8 +167,12 @@ export function CodexAuthProfilesCard() {
|
||||
if (data.profiles.length === 0) {
|
||||
return (
|
||||
<div className="rounded-md border bg-muted/30 px-4 py-3 text-sm text-muted-foreground space-y-1">
|
||||
<p>{t('codex.auth.emptyRegistry')}</p>
|
||||
<p>{t('codex.auth.legacyCodexHome')}</p>
|
||||
<p>
|
||||
<Trans i18nKey="codex.auth.emptyRegistryRich" components={{ code: <InlineCode /> }} />
|
||||
</p>
|
||||
<p>
|
||||
<Trans i18nKey="codex.auth.legacyCodexHomeRich" components={{ code: <InlineCode /> }} />
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -166,7 +182,7 @@ export function CodexAuthProfilesCard() {
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div className="rounded-md border bg-muted/30 px-4 py-3 text-sm text-muted-foreground">
|
||||
{t('codex.auth.legacyMode')}
|
||||
<Trans i18nKey="codex.auth.legacyModeRich" components={{ code: <InlineCode /> }} />
|
||||
</div>
|
||||
<ProfileTable data={data} />
|
||||
</div>
|
||||
@@ -178,7 +194,11 @@ export function CodexAuthProfilesCard() {
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div className="rounded-md border bg-muted/30 px-4 py-3 text-sm text-muted-foreground">
|
||||
{t('codex.auth.externalCodexHome', { path: data.active.codexHome })}
|
||||
<Trans
|
||||
i18nKey="codex.auth.externalCodexHomeRich"
|
||||
values={{ path: data.active.codexHome }}
|
||||
components={{ code: <InlineCode /> }}
|
||||
/>
|
||||
</div>
|
||||
<ProfileTable data={data} />
|
||||
</div>
|
||||
|
||||
@@ -2178,17 +2178,26 @@ const resources = {
|
||||
auth: {
|
||||
terminalOnlyTooltip:
|
||||
'Use ccsx auth switch <name> or ccsx auth remove <name> in terminal.',
|
||||
terminalOnlyTooltipRich:
|
||||
'Use <code>ccsx auth switch <name></code> or <code>ccsx auth remove <name></code> in terminal.',
|
||||
activeSourceBadge: '{{source}}',
|
||||
statusOk: 'OK',
|
||||
statusInvalid: '[!] auth invalid',
|
||||
loading: 'Loading auth profiles...',
|
||||
loadError: '[!] Failed to load codex-auth profiles.',
|
||||
emptyRegistry: '[i] No codex-auth profiles. Run ccsx auth create <name> to create one.',
|
||||
emptyRegistryRich:
|
||||
'[i] No codex-auth profiles. Run <code>ccsx auth create <name></code> to create one.',
|
||||
legacyCodexHome: 'Codex will use the default ~/.codex location.',
|
||||
legacyCodexHomeRich: 'Codex will use the default <code>~/.codex</code> location.',
|
||||
legacyMode:
|
||||
'[i] No active profile. Using ~/.codex (legacy). Run ccsx auth switch <name> in terminal to activate one.',
|
||||
legacyModeRich:
|
||||
'[i] No active profile. Using <code>~/.codex</code> (legacy). Run <code>ccsx auth switch <name></code> in terminal to activate one.',
|
||||
externalCodexHome:
|
||||
'[i] $CODEX_HOME set externally to {{path}}. Profile registry not in use for this session.',
|
||||
externalCodexHomeRich:
|
||||
'[i] <code>$CODEX_HOME</code> set externally to <code>{{path}}</code>. Profile registry not in use for this session.',
|
||||
activeProfile: 'Active profile:',
|
||||
unknownProfile: '(unknown)',
|
||||
planLabel: 'Plan:',
|
||||
@@ -2659,6 +2668,7 @@ const resources = {
|
||||
controlCenter: 'Control Center',
|
||||
overview: 'Overview',
|
||||
docs: 'Docs',
|
||||
authProfiles: 'Auth Profiles',
|
||||
nativeRuntime: 'Native Runtime',
|
||||
ccsProvider: 'CCS Provider',
|
||||
setup: 'Setup',
|
||||
@@ -4772,16 +4782,25 @@ const resources = {
|
||||
warningsTitle: '警告',
|
||||
auth: {
|
||||
terminalOnlyTooltip: '在终端使用 ccsx auth switch <name> 或 ccsx auth remove <name>。',
|
||||
terminalOnlyTooltipRich:
|
||||
'在终端使用 <code>ccsx auth switch <name></code> 或 <code>ccsx auth remove <name></code>。',
|
||||
activeSourceBadge: '{{source}}',
|
||||
statusOk: '正常',
|
||||
statusInvalid: '[!] 认证无效',
|
||||
loading: '正在加载认证配置...',
|
||||
loadError: '[!] 加载 codex-auth 配置失败。',
|
||||
emptyRegistry: '[i] 没有 codex-auth 配置。运行 ccsx auth create <name> 创建一个。',
|
||||
emptyRegistryRich:
|
||||
'[i] 没有 codex-auth 配置。运行 <code>ccsx auth create <name></code> 创建一个。',
|
||||
legacyCodexHome: 'Codex 将使用默认 ~/.codex 位置。',
|
||||
legacyCodexHomeRich: 'Codex 将使用默认 <code>~/.codex</code> 位置。',
|
||||
legacyMode:
|
||||
'[i] 没有活动配置。正在使用 ~/.codex(旧模式)。在终端运行 ccsx auth switch <name> 激活一个。',
|
||||
legacyModeRich:
|
||||
'[i] 没有活动配置。正在使用 <code>~/.codex</code>(旧模式)。在终端运行 <code>ccsx auth switch <name></code> 激活一个。',
|
||||
externalCodexHome: '[i] $CODEX_HOME 外部设置为 {{path}}。本会话未使用配置注册表。',
|
||||
externalCodexHomeRich:
|
||||
'[i] <code>$CODEX_HOME</code> 外部设置为 <code>{{path}}</code>。本会话未使用配置注册表。',
|
||||
activeProfile: '活动配置:',
|
||||
unknownProfile: '(未知)',
|
||||
planLabel: '套餐:',
|
||||
@@ -5228,6 +5247,7 @@ const resources = {
|
||||
controlCenter: '控制中心',
|
||||
overview: '概览',
|
||||
docs: '文档',
|
||||
authProfiles: '认证配置',
|
||||
nativeRuntime: '原生运行时',
|
||||
ccsProvider: 'CCS 提供商',
|
||||
setup: '安装',
|
||||
@@ -7452,17 +7472,26 @@ const resources = {
|
||||
auth: {
|
||||
terminalOnlyTooltip:
|
||||
'Dùng ccsx auth switch <name> hoặc ccsx auth remove <name> trong terminal.',
|
||||
terminalOnlyTooltipRich:
|
||||
'Dùng <code>ccsx auth switch <name></code> hoặc <code>ccsx auth remove <name></code> trong terminal.',
|
||||
activeSourceBadge: '{{source}}',
|
||||
statusOk: 'OK',
|
||||
statusInvalid: '[!] auth không hợp lệ',
|
||||
loading: 'Đang tải hồ sơ auth...',
|
||||
loadError: '[!] Không tải được hồ sơ codex-auth.',
|
||||
emptyRegistry: '[i] Chưa có hồ sơ codex-auth. Chạy ccsx auth create <name> để tạo.',
|
||||
emptyRegistryRich:
|
||||
'[i] Chưa có hồ sơ codex-auth. Chạy <code>ccsx auth create <name></code> để tạo.',
|
||||
legacyCodexHome: 'Codex sẽ dùng vị trí mặc định ~/.codex.',
|
||||
legacyCodexHomeRich: 'Codex sẽ dùng vị trí mặc định <code>~/.codex</code>.',
|
||||
legacyMode:
|
||||
'[i] Chưa có hồ sơ active. Đang dùng ~/.codex (legacy). Chạy ccsx auth switch <name> trong terminal để kích hoạt.',
|
||||
legacyModeRich:
|
||||
'[i] Chưa có hồ sơ active. Đang dùng <code>~/.codex</code> (legacy). Chạy <code>ccsx auth switch <name></code> trong terminal để kích hoạt.',
|
||||
externalCodexHome:
|
||||
'[i] $CODEX_HOME được đặt bên ngoài là {{path}}. Registry hồ sơ không dùng trong phiên này.',
|
||||
externalCodexHomeRich:
|
||||
'[i] <code>$CODEX_HOME</code> được đặt bên ngoài là <code>{{path}}</code>. Registry hồ sơ không dùng trong phiên này.',
|
||||
activeProfile: 'Hồ sơ active:',
|
||||
unknownProfile: '(không rõ)',
|
||||
planLabel: 'Gói:',
|
||||
@@ -7921,6 +7950,7 @@ const resources = {
|
||||
controlCenter: 'Trung tâm điều khiển',
|
||||
overview: 'Tổng quan',
|
||||
docs: 'Tài liệu',
|
||||
authProfiles: 'Hồ sơ auth',
|
||||
nativeRuntime: 'Runtime gốc',
|
||||
ccsProvider: 'CCS Provider',
|
||||
setup: 'Thiết lập',
|
||||
@@ -9859,6 +9889,8 @@ const resources = {
|
||||
auth: {
|
||||
terminalOnlyTooltip:
|
||||
'ターミナルで ccsx auth switch <name> または ccsx auth remove <name> を使用します。',
|
||||
terminalOnlyTooltipRich:
|
||||
'ターミナルで <code>ccsx auth switch <name></code> または <code>ccsx auth remove <name></code> を使用します。',
|
||||
activeSourceBadge: '{{source}}',
|
||||
statusOk: 'OK',
|
||||
statusInvalid: '[!] 認証が無効',
|
||||
@@ -9866,11 +9898,18 @@ const resources = {
|
||||
loadError: '[!] codex-auth プロファイルの読み込みに失敗しました。',
|
||||
emptyRegistry:
|
||||
'[i] codex-auth プロファイルがありません。ccsx auth create <name> を実行して作成します。',
|
||||
emptyRegistryRich:
|
||||
'[i] codex-auth プロファイルがありません。<code>ccsx auth create <name></code> を実行して作成します。',
|
||||
legacyCodexHome: 'Codex はデフォルトの ~/.codex を使用します。',
|
||||
legacyCodexHomeRich: 'Codex はデフォルトの <code>~/.codex</code> を使用します。',
|
||||
legacyMode:
|
||||
'[i] アクティブなプロファイルがありません。~/.codex(レガシー)を使用中です。ターミナルで ccsx auth switch <name> を実行して有効化します。',
|
||||
legacyModeRich:
|
||||
'[i] アクティブなプロファイルがありません。<code>~/.codex</code>(レガシー)を使用中です。ターミナルで <code>ccsx auth switch <name></code> を実行して有効化します。',
|
||||
externalCodexHome:
|
||||
'[i] $CODEX_HOME は外部で {{path}} に設定されています。このセッションではプロファイル registry は使われません。',
|
||||
externalCodexHomeRich:
|
||||
'[i] <code>$CODEX_HOME</code> は外部で <code>{{path}}</code> に設定されています。このセッションではプロファイル registry は使われません。',
|
||||
activeProfile: 'アクティブプロファイル:',
|
||||
unknownProfile: '(不明)',
|
||||
planLabel: 'プラン:',
|
||||
@@ -9894,6 +9933,7 @@ const resources = {
|
||||
controlCenter: 'コントロールセンター',
|
||||
overview: '概要',
|
||||
docs: 'ドキュメント',
|
||||
authProfiles: '認証プロファイル',
|
||||
nativeRuntime: 'ネイティブランタイム',
|
||||
ccsProvider: 'CCS プロバイダー',
|
||||
setup: 'セットアップ',
|
||||
@@ -12861,6 +12901,8 @@ const resources = {
|
||||
auth: {
|
||||
terminalOnlyTooltip:
|
||||
'터미널에서 ccsx auth switch <name> 또는 ccsx auth remove <name>을 사용하세요.',
|
||||
terminalOnlyTooltipRich:
|
||||
'터미널에서 <code>ccsx auth switch <name></code> 또는 <code>ccsx auth remove <name></code>을 사용하세요.',
|
||||
activeSourceBadge: '{{source}}',
|
||||
statusOk: 'OK',
|
||||
statusInvalid: '[!] 인증이 유효하지 않음',
|
||||
@@ -12868,11 +12910,18 @@ const resources = {
|
||||
loadError: '[!] codex-auth 프로필을 로드하지 못했습니다.',
|
||||
emptyRegistry:
|
||||
'[i] codex-auth 프로필이 없습니다. ccsx auth create <name>을 실행해 생성하세요.',
|
||||
emptyRegistryRich:
|
||||
'[i] codex-auth 프로필이 없습니다. <code>ccsx auth create <name></code>을 실행해 생성하세요.',
|
||||
legacyCodexHome: 'Codex는 기본 ~/.codex 위치를 사용합니다.',
|
||||
legacyCodexHomeRich: 'Codex는 기본 <code>~/.codex</code> 위치를 사용합니다.',
|
||||
legacyMode:
|
||||
'[i] 활성 프로필이 없습니다. ~/.codex(레거시)를 사용 중입니다. 터미널에서 ccsx auth switch <name>을 실행해 활성화하세요.',
|
||||
legacyModeRich:
|
||||
'[i] 활성 프로필이 없습니다. <code>~/.codex</code>(레거시)를 사용 중입니다. 터미널에서 <code>ccsx auth switch <name></code>을 실행해 활성화하세요.',
|
||||
externalCodexHome:
|
||||
'[i] $CODEX_HOME이 외부에서 {{path}}로 설정되었습니다. 이 세션에서는 프로필 registry를 사용하지 않습니다.',
|
||||
externalCodexHomeRich:
|
||||
'[i] <code>$CODEX_HOME</code>이 외부에서 <code>{{path}}</code>로 설정되었습니다. 이 세션에서는 프로필 registry를 사용하지 않습니다.',
|
||||
activeProfile: '활성 프로필:',
|
||||
unknownProfile: '(알 수 없음)',
|
||||
planLabel: '플랜:',
|
||||
@@ -13345,6 +13394,7 @@ const resources = {
|
||||
controlCenter: '제어 센터',
|
||||
overview: '개요',
|
||||
docs: '문서',
|
||||
authProfiles: '인증 프로필',
|
||||
nativeRuntime: '네이티브 런타임',
|
||||
ccsProvider: 'CCS 프로바이더',
|
||||
setup: '설정',
|
||||
|
||||
@@ -183,10 +183,7 @@ export function CodexPage() {
|
||||
<TabsTrigger value="overview">{t('codexPage.overview')}</TabsTrigger>
|
||||
<TabsTrigger value="controls">{t('codexPage.controlCenter')}</TabsTrigger>
|
||||
<TabsTrigger value="docs">{t('codexPage.docs')}</TabsTrigger>
|
||||
<TabsTrigger value="auth-profiles">
|
||||
{/* TODO i18n: missing key codexPage.authProfiles */}
|
||||
Auth Profiles
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="auth-profiles">{t('codexPage.authProfiles')}</TabsTrigger>
|
||||
</TabsList>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -4,15 +4,31 @@ import i18n from '@/lib/i18n';
|
||||
const locales = ['en', 'zh-CN', 'vi', 'ja', 'ko'] as const;
|
||||
|
||||
const codexAuthKeys = [
|
||||
['codex.auth.terminalOnlyTooltip'],
|
||||
['codex.auth.sourceDefault'],
|
||||
['codex.auth.sourceEnv'],
|
||||
['codex.auth.sourceExplicitCodexHome'],
|
||||
['codex.auth.terminalOnlyTooltipRich'],
|
||||
['codex.auth.activeSourceBadge', { source: 'default' }],
|
||||
['codex.auth.statusOk'],
|
||||
['codex.auth.statusInvalid'],
|
||||
['codex.auth.loading'],
|
||||
['codex.auth.loadError'],
|
||||
['codex.auth.emptyRegistry'],
|
||||
['codex.auth.externalCodexHome', { path: '/tmp/codex-home' }],
|
||||
['codex.auth.emptyRegistryRich'],
|
||||
['codex.auth.legacyCodexHomeRich'],
|
||||
['codex.auth.legacyModeRich'],
|
||||
['codex.auth.externalCodexHomeRich', { path: '/tmp/codex-home' }],
|
||||
['codex.auth.activeProfile'],
|
||||
['codex.auth.unknownProfile'],
|
||||
['codex.auth.planLabel'],
|
||||
['codex.auth.switchAction'],
|
||||
['codex.auth.removeAction'],
|
||||
['codex.auth.col.name'],
|
||||
['codex.auth.col.email'],
|
||||
['codex.auth.col.plan'],
|
||||
['codex.auth.col.lastUsed'],
|
||||
['codex.auth.col.status'],
|
||||
['codex.auth.col.actions'],
|
||||
['codexPage.authProfiles'],
|
||||
] as const;
|
||||
|
||||
const originalLanguage = i18n.language;
|
||||
@@ -30,6 +46,13 @@ describe('codex auth i18n', () => {
|
||||
|
||||
expect(translated).not.toBe(key);
|
||||
expect(translated).not.toContain('codex.auth.');
|
||||
expect(translated).not.toContain('codexPage.');
|
||||
if (key === 'codex.auth.externalCodexHomeRich') {
|
||||
expect(translated).toContain('/tmp/codex-home');
|
||||
}
|
||||
if (key === 'codex.auth.activeSourceBadge') {
|
||||
expect(translated).toContain('default');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user