mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-09-24 16:05:44 +08:00
feat(keys): add optional ID column on /keys page
Expose API key ID in the keys table column settings so users can show or hide it. Hidden by default; bump column-settings version so existing preferences also keep ID hidden until toggled on.
This commit is contained in:
@@ -85,6 +85,7 @@ export default {
|
||||
editKey: 'Edit API Key',
|
||||
deleteKey: 'Delete API Key',
|
||||
deleteConfirmMessage: "Are you sure you want to delete '{name}'? This action cannot be undone.",
|
||||
id: 'ID',
|
||||
apiKey: 'API Key',
|
||||
group: 'Group',
|
||||
currentConcurrency: 'Current Concurrency',
|
||||
|
||||
@@ -85,6 +85,7 @@ export default {
|
||||
editKey: '编辑密钥',
|
||||
deleteKey: '删除密钥',
|
||||
deleteConfirmMessage: "确定要删除 '{name}' 吗?此操作无法撤销。",
|
||||
id: 'ID',
|
||||
apiKey: 'API 密钥',
|
||||
group: '分组',
|
||||
currentConcurrency: '当前并发',
|
||||
|
||||
@@ -90,6 +90,10 @@
|
||||
default-sort-order="desc"
|
||||
@sort="handleSort"
|
||||
>
|
||||
<template #cell-id="{ value }">
|
||||
<span class="font-mono text-xs text-gray-500 dark:text-gray-400">#{{ value }}</span>
|
||||
</template>
|
||||
|
||||
<template #cell-key="{ value, row }">
|
||||
<div class="flex items-center gap-2">
|
||||
<code class="code text-xs">
|
||||
@@ -1173,6 +1177,7 @@ const { copyToClipboard: clipboardCopy } = useClipboard()
|
||||
|
||||
const allColumns = computed<Column[]>(() => [
|
||||
{ key: 'name', label: t('common.name'), sortable: true },
|
||||
{ key: 'id', label: t('keys.id'), sortable: true },
|
||||
{ key: 'key', label: t('keys.apiKey'), sortable: false },
|
||||
{ key: 'group', label: t('keys.group'), sortable: false },
|
||||
{ key: 'current_concurrency', label: t('keys.currentConcurrency'), sortable: true },
|
||||
@@ -1187,12 +1192,13 @@ const allColumns = computed<Column[]>(() => [
|
||||
])
|
||||
|
||||
const ALWAYS_VISIBLE_COLUMNS = new Set(['name', 'actions'])
|
||||
const DEFAULT_HIDDEN_COLUMNS = ['rate_limit', 'last_used_at', 'last_used_ip']
|
||||
const DEFAULT_HIDDEN_COLUMNS = ['id', 'rate_limit', 'last_used_at', 'last_used_ip']
|
||||
const HIDDEN_COLUMNS_KEY = 'api-key-hidden-columns'
|
||||
const COLUMN_SETTINGS_VERSION_KEY = 'api-key-column-settings-version'
|
||||
const COLUMN_SETTINGS_VERSION = 2
|
||||
const COLUMN_SETTINGS_VERSION = 3
|
||||
const VERSION_NEW_HIDDEN_COLUMNS: Record<number, string[]> = {
|
||||
2: ['last_used_ip']
|
||||
2: ['last_used_ip'],
|
||||
3: ['id']
|
||||
}
|
||||
|
||||
const toggleableColumns = computed(() =>
|
||||
|
||||
@@ -42,6 +42,7 @@ const messages: Record<string, string> = {
|
||||
'keys.created': 'Created',
|
||||
'keys.expiresAt': 'Expires',
|
||||
'keys.group': 'Group',
|
||||
'keys.id': 'ID',
|
||||
'keys.currentConcurrency': 'Current Concurrency',
|
||||
'keys.lastUsedAt': 'Last Used',
|
||||
'keys.lastUsedIP': 'Last Used IP',
|
||||
@@ -162,6 +163,12 @@ const DataTableStub = {
|
||||
Sort Current Concurrency
|
||||
</button>
|
||||
<div v-for="row in data" :key="row.id">
|
||||
<div
|
||||
v-if="columns.some((col) => col.key === 'id')"
|
||||
data-test="key-id"
|
||||
>
|
||||
<slot name="cell-id" :value="row.id" :row="row" />
|
||||
</div>
|
||||
<slot name="cell-name" :value="row.name" :row="row" />
|
||||
<div data-test="current-concurrency">
|
||||
<slot name="cell-current_concurrency" :value="row.current_concurrency" :row="row" />
|
||||
@@ -295,6 +302,7 @@ describe('user KeysView column settings', () => {
|
||||
expect(visibleColumnKeys(wrapper)).not.toContain('rate_limit')
|
||||
expect(visibleColumnKeys(wrapper)).not.toContain('last_used_at')
|
||||
expect(visibleColumnKeys(wrapper)).not.toContain('last_used_ip')
|
||||
expect(visibleColumnKeys(wrapper)).not.toContain('id')
|
||||
})
|
||||
|
||||
it('shows a hidden column when toggled and persists the preference', async () => {
|
||||
@@ -306,9 +314,21 @@ describe('user KeysView column settings', () => {
|
||||
|
||||
expect(visibleColumnKeys(wrapper)).toContain('rate_limit')
|
||||
expect(localStorage.getItem('api-key-hidden-columns')).toBe(
|
||||
JSON.stringify(['last_used_at', 'last_used_ip'])
|
||||
JSON.stringify(['id', 'last_used_at', 'last_used_ip'])
|
||||
)
|
||||
expect(localStorage.getItem('api-key-column-settings-version')).toBe('2')
|
||||
expect(localStorage.getItem('api-key-column-settings-version')).toBe('3')
|
||||
})
|
||||
|
||||
it('shows the API key ID column when toggled', async () => {
|
||||
const wrapper = await mountView()
|
||||
|
||||
await wrapper.get('button[title="Column Settings"]').trigger('click')
|
||||
await getButtonByText(wrapper, 'ID').trigger('click')
|
||||
await nextTick()
|
||||
|
||||
expect(visibleColumnKeys(wrapper)).toContain('id')
|
||||
expect(wrapper.get('[data-test="key-id"]').text()).toBe('#1')
|
||||
expect(visibleColumnMeta(wrapper).find((column) => column.key === 'id')?.sortable).toBe(true)
|
||||
})
|
||||
|
||||
it('shows the last used IP column when toggled', async () => {
|
||||
@@ -347,9 +367,9 @@ describe('user KeysView column settings', () => {
|
||||
'actions',
|
||||
])
|
||||
expect(localStorage.getItem('api-key-hidden-columns')).toBe(
|
||||
JSON.stringify(['group', 'created_at', 'last_used_ip'])
|
||||
JSON.stringify(['group', 'created_at', 'last_used_ip', 'id'])
|
||||
)
|
||||
expect(localStorage.getItem('api-key-column-settings-version')).toBe('2')
|
||||
expect(localStorage.getItem('api-key-column-settings-version')).toBe('3')
|
||||
})
|
||||
|
||||
it('does not include always-visible columns in the toggleable menu', async () => {
|
||||
@@ -360,6 +380,7 @@ describe('user KeysView column settings', () => {
|
||||
|
||||
const columnMenuText = wrapper.text()
|
||||
expect(columnMenuText).toContain('API Key')
|
||||
expect(columnMenuText).toContain('ID')
|
||||
expect(columnMenuText).toContain('Current Concurrency')
|
||||
expect(columnMenuText).toContain('Rate Limit')
|
||||
expect(columnMenuText).toContain('Last Used IP')
|
||||
|
||||
Reference in New Issue
Block a user