From bcda94bf21f0d40db0cde6a7a2abe9fd5bbd418f Mon Sep 17 00:00:00 2001 From: tbphp Date: Sat, 1 Aug 2026 13:00:42 +0800 Subject: [PATCH] =?UTF-8?q?feat(access-key):=20=E4=BC=98=E5=8C=96=E6=9D=83?= =?UTF-8?q?=E9=99=90=E8=81=94=E5=8A=A8=E7=BC=96=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/ui/SearchableMultiSelect.vue | 276 ++++++++++++++++++ .../access-keys/AccessKeyDeleteDialog.vue | 44 ++- .../features/access-keys/AccessKeyDrawer.vue | 110 +++++-- .../access-keys/AccessKeyScopeEditor.vue | 169 ++++++----- web/src/i18n/locales/en-US/access-keys.ts | 20 ++ web/src/i18n/locales/ja-JP/access-keys.ts | 20 ++ web/src/i18n/locales/zh-CN/access-keys.ts | 19 ++ 7 files changed, 555 insertions(+), 103 deletions(-) create mode 100644 web/src/components/ui/SearchableMultiSelect.vue diff --git a/web/src/components/ui/SearchableMultiSelect.vue b/web/src/components/ui/SearchableMultiSelect.vue new file mode 100644 index 00000000..c9450f18 --- /dev/null +++ b/web/src/components/ui/SearchableMultiSelect.vue @@ -0,0 +1,276 @@ + + + + + diff --git a/web/src/features/access-keys/AccessKeyDeleteDialog.vue b/web/src/features/access-keys/AccessKeyDeleteDialog.vue index 5a2b4de7..bab4c0de 100644 --- a/web/src/features/access-keys/AccessKeyDeleteDialog.vue +++ b/web/src/features/access-keys/AccessKeyDeleteDialog.vue @@ -1,6 +1,6 @@ @@ -194,7 +226,7 @@ small { input, select { width: 100%; - min-height: 44px; + min-height: var(--touch-target); border: 1px solid var(--color-border-control); border-radius: var(--radius-control); background: var(--color-surface-sunken); @@ -204,7 +236,7 @@ select { } .access-key-drawer__check { display: flex; - min-height: 44px; + min-height: var(--touch-target); align-items: center; gap: var(--space-2); } @@ -216,6 +248,16 @@ select { display: grid; gap: var(--space-1); } +.access-key-drawer__unsupported, +.access-key-drawer__model-risk { + color: var(--color-warning); +} +.access-key-drawer__model-risk { + border: 1px solid var(--color-warning); + border-radius: var(--radius-control); + background: var(--color-warning-bg); + padding: var(--space-2) var(--space-3); +} .access-key-drawer__model-entry { display: flex; flex-wrap: wrap; @@ -225,29 +267,4 @@ select { .access-key-drawer__model-entry input { flex: 1 1 220px; } -.access-key-drawer__models { - display: flex; - flex-wrap: wrap; - gap: var(--space-2); -} -.access-key-drawer__model { - display: inline-flex; - min-height: 44px; - align-items: center; - gap: var(--space-1); - border-radius: var(--radius-tag); - background: var(--color-tag); - padding-left: var(--space-2); -} -.access-key-drawer__model button { - display: inline-flex; - width: 44px; - height: 44px; - align-items: center; - justify-content: center; - border: 0; - background: transparent; - color: var(--color-text-muted); - cursor: pointer; -} diff --git a/web/src/i18n/locales/en-US/access-keys.ts b/web/src/i18n/locales/en-US/access-keys.ts index bc7aab5a..ecadbd9d 100644 --- a/web/src/i18n/locales/en-US/access-keys.ts +++ b/web/src/i18n/locales/en-US/access-keys.ts @@ -98,6 +98,25 @@ export default { scopeRestricted: 'Restricted', expandScopeConfirmation: 'Switching to All expands this AccessKey permission. Continue?', unknownGroup: 'Unknown Group #{id}', + groupEnabled: 'Active', + groupDisabled: 'Disabled', + groupDangling: 'No longer in the current Group catalog', + groupSelectorLabel: 'Select Groups', + modelSelectorLabel: 'Select models', + searchGroups: 'Search Groups', + searchGroupsPlaceholder: 'Search by name or ID', + searchModels: 'Search models', + searchModelsPlaceholder: 'Search by model ID or alias', + noGroupOptions: 'No matching Groups.', + noModelOptions: 'No matching models.', + groupOptionsLoading: 'Loading Group catalog…', + selectedCount: '{count} selected', + clearSelected: 'Clear selected', + removeSelection: 'Remove {label}', + protocolUnsupported: 'Unsupported by the selected Groups', + groupProtocolMismatch: 'The selected Groups and protocols have no routable overlap.', + modelRouteRisk: + 'A selected model is not in the current Group catalog, so requests may fail to route.', emptyMeansAll: 'No selection means all.', modelsDescription: 'Choose known models or enter any valid model string.', modelPlaceholder: 'Enter a model ID or alias', @@ -132,6 +151,7 @@ export default { close: 'Close AccessKey deletion confirmation', lastWarning: 'This is the last AccessKey. Deleting it leaves data-plane clients without an issued credential.', + typeName: 'Type {name} to confirm', confirm: 'Delete AccessKey', failed: 'Unable to delete the AccessKey.', deletedAnnouncement: 'Deleted AccessKey “{name}”.', diff --git a/web/src/i18n/locales/ja-JP/access-keys.ts b/web/src/i18n/locales/ja-JP/access-keys.ts index 34afcc4c..862b57f3 100644 --- a/web/src/i18n/locales/ja-JP/access-keys.ts +++ b/web/src/i18n/locales/ja-JP/access-keys.ts @@ -99,6 +99,25 @@ export default { expandScopeConfirmation: '「すべて」に切り替えると、この AccessKey の権限が拡大します。続行しますか?', unknownGroup: '不明な Group #{id}', + groupEnabled: '有効', + groupDisabled: '無効', + groupDangling: '現在の Group カタログにはありません', + groupSelectorLabel: 'Group を選択', + modelSelectorLabel: 'モデルを選択', + searchGroups: 'Group を検索', + searchGroupsPlaceholder: '名前または ID で検索', + searchModels: 'モデルを検索', + searchModelsPlaceholder: 'モデル ID またはエイリアスで検索', + noGroupOptions: '一致する Group はありません。', + noModelOptions: '一致するモデルはありません。', + groupOptionsLoading: 'Group カタログを読み込み中…', + selectedCount: '{count} 件を選択', + clearSelected: '選択を解除', + removeSelection: '{label} を削除', + protocolUnsupported: '選択した Group はこのプロトコルをサポートしていません', + groupProtocolMismatch: '選択した Group とプロトコルにルーティング可能な重複がありません。', + modelRouteRisk: + '選択したモデルは現在の Group カタログにないため、リクエストのルーティングに失敗する可能性があります。', emptyMeansAll: '未選択はすべてを意味します。', modelsDescription: '既知のモデルを選ぶか、有効なモデル文字列を入力できます。', modelPlaceholder: 'モデル ID またはエイリアスを入力', @@ -132,6 +151,7 @@ export default { close: 'AccessKey の削除確認を閉じる', lastWarning: 'これは最後の AccessKey です。削除すると、データプレーンクライアントに発行済み資格情報がなくなります。', + typeName: '確認のため {name} と入力', confirm: 'AccessKey を削除', failed: 'AccessKey を削除できません。', deletedAnnouncement: 'AccessKey「{name}」を削除しました。', diff --git a/web/src/i18n/locales/zh-CN/access-keys.ts b/web/src/i18n/locales/zh-CN/access-keys.ts index 3a29e413..78fec11b 100644 --- a/web/src/i18n/locales/zh-CN/access-keys.ts +++ b/web/src/i18n/locales/zh-CN/access-keys.ts @@ -94,6 +94,24 @@ export default { scopeRestricted: '限制', expandScopeConfirmation: '切换为“全部”会扩大此 AccessKey 的权限,是否继续?', unknownGroup: '未知 Group #{id}', + groupEnabled: '已启用', + groupDisabled: '已停用', + groupDangling: '已不在当前 Group 目录中', + groupSelectorLabel: '选择 Group', + modelSelectorLabel: '选择模型', + searchGroups: '搜索 Group', + searchGroupsPlaceholder: '按名称或 ID 搜索', + searchModels: '搜索模型', + searchModelsPlaceholder: '按模型 ID 或别名搜索', + noGroupOptions: '没有匹配的 Group。', + noModelOptions: '没有匹配的模型。', + groupOptionsLoading: '正在加载 Group 目录…', + selectedCount: '已选择 {count} 项', + clearSelected: '清除所选', + removeSelection: '移除 {label}', + protocolUnsupported: '所选 Group 不支持此协议', + groupProtocolMismatch: '所选 Group 与协议没有可路由的交集。', + modelRouteRisk: '所选模型不在当前 Group 的模型目录中,路由请求可能失败。', emptyMeansAll: '不选择表示全部。', modelsDescription: '可选择已知模型,也可输入任意有效模型字符串。', modelPlaceholder: '输入模型 ID 或别名', @@ -121,6 +139,7 @@ export default { description: '删除“{name}”。此操作无法撤销。', close: '关闭 AccessKey 删除确认', lastWarning: '这是最后一个 AccessKey。删除后,数据面客户端将没有已签发凭据。', + typeName: '输入 {name} 以确认', confirm: '删除 AccessKey', failed: '无法删除 AccessKey。', deletedAnnouncement: '已删除 AccessKey“{name}”。',