diff --git a/frontend/src/i18n/locales/en/admin/overview.ts b/frontend/src/i18n/locales/en/admin/overview.ts
index 2a643ae192..51449dc883 100644
--- a/frontend/src/i18n/locales/en/admin/overview.ts
+++ b/frontend/src/i18n/locales/en/admin/overview.ts
@@ -757,6 +757,7 @@ export default {
public: 'Public',
columns: {
name: 'Name',
+ id: 'ID',
platform: 'Platform',
rateMultiplier: 'Rate Multiplier',
rpmOverride: 'RPM Override',
diff --git a/frontend/src/i18n/locales/zh/admin/overview.ts b/frontend/src/i18n/locales/zh/admin/overview.ts
index 125e29cc38..e1e41bbeb7 100644
--- a/frontend/src/i18n/locales/zh/admin/overview.ts
+++ b/frontend/src/i18n/locales/zh/admin/overview.ts
@@ -750,6 +750,7 @@ export default {
"确定要删除订阅分组 '{name}' 吗?此操作会让所有绑定此订阅的用户的 API Key 失效,并删除所有相关的订阅记录。此操作无法撤销。",
columns: {
name: '名称',
+ id: 'ID',
platform: '平台',
rateMultiplier: '费率倍数',
rpmOverride: 'RPM 覆盖',
diff --git a/frontend/src/views/admin/GroupsView.vue b/frontend/src/views/admin/GroupsView.vue
index d7cf9dd717..81310c43af 100644
--- a/frontend/src/views/admin/GroupsView.vue
+++ b/frontend/src/views/admin/GroupsView.vue
@@ -128,6 +128,12 @@
}}
+
+ #{{ value }}
+
+
= {
+ 2: ["id"],
+};
const allColumns = computed(() => [
{ key: "name", label: t("admin.groups.columns.name"), sortable: true },
+ { key: "id", label: t("admin.groups.columns.id"), sortable: true },
{
key: "platform",
label: t("admin.groups.columns.platform"),
@@ -3665,16 +3680,51 @@ const loadSavedColumns = () => {
hiddenColumns.clear();
try {
const saved = localStorage.getItem(HIDDEN_COLUMNS_KEY);
- if (!saved) return;
- const parsed = JSON.parse(saved);
- if (!Array.isArray(parsed)) return;
-
const validKeys = getValidHiddenColumnKeys();
- parsed
- .filter((key): key is string => typeof key === "string" && validKeys.has(key))
- .forEach((key) => hiddenColumns.add(key));
+
+ if (saved) {
+ const parsed = JSON.parse(saved);
+ if (Array.isArray(parsed)) {
+ parsed
+ .filter(
+ (key): key is string =>
+ typeof key === "string" && validKeys.has(key),
+ )
+ .forEach((key) => hiddenColumns.add(key));
+ }
+
+ // Existing admins: auto-hide columns newly added as default-hidden.
+ const storedVersion = Number(
+ localStorage.getItem(COLUMN_SETTINGS_VERSION_KEY) ?? "1",
+ );
+ if (storedVersion < COLUMN_SETTINGS_VERSION) {
+ let mutated = false;
+ for (let v = storedVersion + 1; v <= COLUMN_SETTINGS_VERSION; v++) {
+ for (const key of VERSION_NEW_HIDDEN_COLUMNS[v] ?? []) {
+ if (validKeys.has(key) && !hiddenColumns.has(key)) {
+ hiddenColumns.add(key);
+ mutated = true;
+ }
+ }
+ }
+ if (mutated) {
+ saveColumnsToStorage();
+ } else {
+ localStorage.setItem(
+ COLUMN_SETTINGS_VERSION_KEY,
+ String(COLUMN_SETTINGS_VERSION),
+ );
+ }
+ }
+ } else {
+ DEFAULT_HIDDEN_COLUMNS.forEach((key) => {
+ if (validKeys.has(key)) hiddenColumns.add(key);
+ });
+ saveColumnsToStorage();
+ }
} catch (error) {
console.error("Failed to load group column settings:", error);
+ DEFAULT_HIDDEN_COLUMNS.forEach((key) => hiddenColumns.add(key));
}
};
@@ -3683,6 +3733,10 @@ const saveColumnsToStorage = () => {
const validKeys = getValidHiddenColumnKeys();
const keys = [...hiddenColumns].filter((key) => validKeys.has(key));
localStorage.setItem(HIDDEN_COLUMNS_KEY, JSON.stringify(keys));
+ localStorage.setItem(
+ COLUMN_SETTINGS_VERSION_KEY,
+ String(COLUMN_SETTINGS_VERSION),
+ );
} catch (error) {
console.error("Failed to save group column settings:", error);
}
diff --git a/frontend/src/views/admin/__tests__/GroupsView.columnSettings.spec.ts b/frontend/src/views/admin/__tests__/GroupsView.columnSettings.spec.ts
index e634bdd5d7..3faa22898c 100644
--- a/frontend/src/views/admin/__tests__/GroupsView.columnSettings.spec.ts
+++ b/frontend/src/views/admin/__tests__/GroupsView.columnSettings.spec.ts
@@ -31,6 +31,7 @@ const {
const messages: Record = {
'admin.groups.columnSettings': 'Column Settings',
'admin.groups.columns.name': 'Name',
+ 'admin.groups.columns.id': 'ID',
'admin.groups.columns.platform': 'Platform',
'admin.groups.columns.billingType': 'Billing Type',
'admin.groups.columns.rateMultiplier': 'Rate Multiplier',
@@ -251,7 +252,7 @@ describe('admin GroupsView column settings', () => {
localStorage.clear()
})
- it('renders all group columns by default in the current order', async () => {
+ it('hides the id column by default while keeping other group columns visible', async () => {
const wrapper = await mountView()
expect(columnKeys(wrapper)).toEqual([
@@ -266,6 +267,8 @@ describe('admin GroupsView column settings', () => {
'status',
'actions',
])
+ expect(localStorage.getItem('group-hidden-columns')).toBe(JSON.stringify(['id']))
+ expect(localStorage.getItem('group-column-settings-version')).toBe('2')
})
it('applies saved hidden columns on mount and ignores unknown keys', async () => {
@@ -273,6 +276,26 @@ describe('admin GroupsView column settings', () => {
'group-hidden-columns',
JSON.stringify(['usage', 'capacity', 'removed_column', 'name', 'actions']),
)
+ localStorage.setItem('group-column-settings-version', '2')
+
+ const wrapper = await mountView()
+
+ expect(columnKeys(wrapper)).toEqual([
+ 'name',
+ 'id',
+ 'platform',
+ 'billing_type',
+ 'rate_multiplier',
+ 'is_exclusive',
+ 'account_count',
+ 'status',
+ 'actions',
+ ])
+ })
+
+ it('auto-hides id for existing saved column prefs after version bump', async () => {
+ localStorage.setItem('group-hidden-columns', JSON.stringify(['usage']))
+ // No version key → treated as version 1, migrate to 2 and hide id.
const wrapper = await mountView()
@@ -283,9 +306,14 @@ describe('admin GroupsView column settings', () => {
'rate_multiplier',
'is_exclusive',
'account_count',
+ 'capacity',
'status',
'actions',
])
+ expect(JSON.parse(localStorage.getItem('group-hidden-columns')!)).toEqual(
+ expect.arrayContaining(['usage', 'id']),
+ )
+ expect(localStorage.getItem('group-column-settings-version')).toBe('2')
})
it('toggles a column and persists hidden column keys', async () => {
@@ -305,7 +333,31 @@ describe('admin GroupsView column settings', () => {
'status',
'actions',
])
- expect(localStorage.getItem('group-hidden-columns')).toBe(JSON.stringify(['usage']))
+ expect(JSON.parse(localStorage.getItem('group-hidden-columns')!)).toEqual(
+ expect.arrayContaining(['id', 'usage']),
+ )
+ })
+
+ it('can show the id column from column settings', async () => {
+ const wrapper = await mountView()
+
+ await openColumnSettings(wrapper)
+ await clickColumnToggle(wrapper, 'ID')
+
+ expect(columnKeys(wrapper)).toEqual([
+ 'name',
+ 'id',
+ 'platform',
+ 'billing_type',
+ 'rate_multiplier',
+ 'is_exclusive',
+ 'account_count',
+ 'capacity',
+ 'usage',
+ 'status',
+ 'actions',
+ ])
+ expect(localStorage.getItem('group-hidden-columns')).toBe(JSON.stringify([]))
})
it('skips usage and capacity fetches until consuming columns are shown', async () => {