Skip to content

Commit 061f3c3

Browse files
authored
feat: refine settings tables ui (#689)
* feat: refine settings tables ui Signed-off-by: Bob Du <i@bobdu.cc> * docs: clarify branching and git permissions Signed-off-by: Bob Du <i@bobdu.cc> * feat: align settings table actions and locales Signed-off-by: Bob Du <i@bobdu.cc> --------- Signed-off-by: Bob Du <i@bobdu.cc>
1 parent bb08436 commit 061f3c3

15 files changed

Lines changed: 173 additions & 295 deletions

File tree

AGENTS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,15 @@
4747
## Commit & Pull Request Guidelines
4848
- Use Conventional Commits (e.g., `feat: add user settings`).
4949
- Always work on a feature branch; do not commit directly to `main`.
50+
- If no feature branch exists for the task, create one before making changes.
5051
- Create or switch to a feature branch before any changes and always confirm the current branch before committing (e.g., `git checkout -b feature/my-change`).
5152
- New features target the `feature` branch; other changes target `main`.
5253
- PRs should include a clear description, link related issues, and note any UI changes with screenshots.
5354
- Commit with signed-off and signed commits: `git commit -s -S -m "feat: ..."`.
5455

56+
## Git Permissions & Operations
57+
- Direct modification of the `.git` directory is not permitted; use git commands for all branch switches, staging, and commits.
58+
5559
## Configuration & Environment
5660
- Backend secrets live in `service/.env` (copy from `service/.env.example`).
5761
- Frontend API base URL is in root `.env` as `VITE_GLOB_API_URL`.

auto-imports.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ declare global {
1414
const IconMdiReorderHorizontal: typeof import('~icons/mdi/reorder-horizontal').default
1515
const IconRiContrastLine: typeof import('~icons/ri/contrast-line').default
1616
const IconRiDeleteBinLine: typeof import('~icons/ri/delete-bin-line').default
17+
const IconRiEdit2Line: typeof import('~icons/ri/edit2-line').default
1718
const IconRiExternalLinkLine: typeof import('~icons/ri/external-link-line').default
1819
const IconRiFileCopy2Line: typeof import('~icons/ri/file-copy2-line').default
1920
const IconRiMoonFoggyLine: typeof import('~icons/ri/moon-foggy-line').default

components.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ declare module 'vue' {
1919
IconMdiLightbulbOutline: typeof import('~icons/mdi/lightbulb-outline')['default']
2020
IconMdiReorderHorizontal: typeof import('~icons/mdi/reorder-horizontal')['default']
2121
IconMdiWeb: typeof import('~icons/mdi/web')['default']
22+
IconRiAddLine: typeof import('~icons/ri/add-line')['default']
2223
IconRiAlignJustify: typeof import('~icons/ri/align-justify')['default']
2324
IconRiAlignRight: typeof import('~icons/ri/align-right')['default']
2425
IconRiArrowDownSLine: typeof import('~icons/ri/arrow-down-s-line')['default']
@@ -36,7 +37,6 @@ declare module 'vue' {
3637
IconRiDownload2Line: typeof import('~icons/ri/download2-line')['default']
3738
IconRiDownloadLine: typeof import('~icons/ri/download-line')['default']
3839
IconRiEditLine: typeof import('~icons/ri/edit-line')['default']
39-
IconRiEqualizerLine: typeof import('~icons/ri/equalizer-line')['default']
4040
IconRiFileUserLine: typeof import('~icons/ri/file-user-line')['default']
4141
IconRiImageEditLine: typeof import('~icons/ri/image-edit-line')['default']
4242
IconRiInboxLine: typeof import('~icons/ri/inbox-line')['default']
@@ -48,6 +48,7 @@ declare module 'vue' {
4848
IconRiQuestionAnswerLine: typeof import('~icons/ri/question-answer-line')['default']
4949
IconRiRestartLine: typeof import('~icons/ri/restart-line')['default']
5050
IconRiSaveLine: typeof import('~icons/ri/save-line')['default']
51+
IconRiSearchLine: typeof import('~icons/ri/search-line')['default']
5152
IconRiSendPlaneFill: typeof import('~icons/ri/send-plane-fill')['default']
5253
IconRiSettings4Line: typeof import('~icons/ri/settings4-line')['default']
5354
IconRiSettingsLine: typeof import('~icons/ri/settings-line')['default']

service/src/storage/config.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ export async function getApiKeys() {
140140
if (result.keys.length <= 0) {
141141
const defaultModel = config.siteConfig.chatModels.split(',')[0] || ''
142142
result.keys.push(await upsertKey(new KeyConfig(config.apiKey, 'ChatGPTAPI', defaultModel, [], '')))
143-
result.total++
144143
}
145144
result.keys.forEach((key) => {
146145
if (key.userRoles == null || key.userRoles.length <= 0) {

service/src/storage/mongo.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,14 +1162,13 @@ export async function getUserStatisticsByModel(start?: number, end?: number): Pr
11621162
return result
11631163
}
11641164

1165-
export async function getKeys(): Promise<{ keys: KeyConfig[], total: number }> {
1165+
export async function getKeys(): Promise<{ keys: KeyConfig[] }> {
11661166
const query = { status: { $ne: Status.Disabled } }
11671167
const cursor = keyCol.find(query)
1168-
const total = await keyCol.countDocuments(query)
11691168
const keys = []
11701169
for await (const doc of cursor)
11711170
keys.push(doc)
1172-
return { keys, total }
1171+
return { keys }
11731172
}
11741173

11751174
export async function upsertKey(key: KeyConfig): Promise<KeyConfig> {

src/api/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,10 +516,9 @@ export function fetchUserStatisticsByModel<T = any>(start?: number, end?: number
516516
})
517517
}
518518

519-
export function fetchGetKeys<T = any>(page: number, size: number) {
519+
export function fetchGetKeys<T = any>() {
520520
return get<T>({
521521
url: '/setting-keys',
522-
data: { page, size },
523522
})
524523
}
525524

src/components/common/Setting/BuiltInPrompt.vue

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ function createColumns(): DataTableColumns<BuiltInPrompt> {
293293
type: 'info',
294294
onClick: () => openModal('edit', row),
295295
},
296-
{ default: () => t('common.edit') },
296+
{ default: () => [h(IconRiEdit2Line, { class: 'mr-1 text-base' }), t('common.edit')] },
297297
), h(
298298
NButton,
299299
{
@@ -302,7 +302,7 @@ function createColumns(): DataTableColumns<BuiltInPrompt> {
302302
type: 'error',
303303
onClick: () => handleDeletePrompt(row),
304304
},
305-
{ default: () => t('common.delete') },
305+
{ default: () => [h(IconRiDeleteBinLine, { class: 'mr-1 text-base' }), t('common.delete')] },
306306
)],
307307
})
308308
},
@@ -377,24 +377,24 @@ onMounted(async () => {
377377
</script>
378378

379379
<template>
380-
<div class="p-4 space-y-5 min-h-[300px]">
381-
<div class="space-y-6">
382-
<NSpace vertical :size="12">
383-
<NSpace>
384-
<NButton @click="openModal('add')">
385-
{{ t('common.add') }}
386-
</NButton>
387-
</NSpace>
388-
<NDataTable
389-
:loading="loading"
390-
:row-key="(rowData) => rowData._id"
391-
:columns="columns"
392-
:data="promptList"
393-
:row-props="rowProps"
394-
:max-height="444"
395-
striped
396-
/>
397-
</NSpace>
380+
<div class="box-border h-full flex-1 min-h-0 overflow-hidden px-4 pb-4 pt-2" style="height: 100%;">
381+
<div class="flex h-full min-h-0 flex-col gap-3">
382+
<div class="flex items-center justify-end shrink-0">
383+
<NButton size="small" type="primary" @click="openModal('add')">
384+
<IconRiAddLine class="mr-1 text-base" />
385+
{{ t('common.add') }}
386+
</NButton>
387+
</div>
388+
<NDataTable
389+
class="flex-1 min-h-0"
390+
:loading="loading"
391+
:row-key="(rowData) => rowData._id"
392+
:columns="columns"
393+
:data="promptList"
394+
:row-props="rowProps"
395+
flex-height
396+
striped
397+
/>
398398
</div>
399399
</div>
400400

src/components/common/Setting/Keys.vue

Lines changed: 51 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,10 @@ const keyConfig = ref(new KeyConfig('', 'ChatGPTAPI', '', [], ''))
2121
const keys = ref([])
2222
function createColumns(): DataTableColumns {
2323
return [
24-
{
25-
title: () => t('setting.model.table.key'),
26-
key: 'key',
27-
resizable: true,
28-
width: 120,
29-
minWidth: 50,
30-
maxWidth: 120,
31-
ellipsis: true,
32-
},
3324
{
3425
title: () => t('setting.model.table.apiModel'),
3526
key: 'keyModel',
36-
width: 150,
27+
width: 90,
3728
},
3829
{
3930
title: () => t('setting.model.table.baseUrl'),
@@ -43,23 +34,32 @@ function createColumns(): DataTableColumns {
4334
{
4435
title: () => t('setting.model.table.chatModel'),
4536
key: 'chatModel',
46-
width: 200,
37+
width: 140,
4738
render(row: any) {
4839
return row.chatModel || '-'
4940
},
5041
},
5142
{
5243
title: () => t('setting.model.table.alias'),
5344
key: 'modelAlias',
54-
width: 150,
45+
width: 110,
5546
render(row: any) {
5647
return row.modelAlias || '-'
5748
},
5849
},
50+
{
51+
title: () => t('setting.model.table.key'),
52+
key: 'key',
53+
resizable: true,
54+
width: 90,
55+
minWidth: 50,
56+
maxWidth: 90,
57+
ellipsis: true,
58+
},
5959
{
6060
title: () => t('setting.model.table.userRoles'),
6161
key: 'userRoles',
62-
width: 180,
62+
width: 140,
6363
render(row: any) {
6464
const tags = row.userRoles.map((userRole: UserRole) => {
6565
return h(
@@ -70,6 +70,7 @@ function createColumns(): DataTableColumns {
7070
},
7171
type: 'info',
7272
bordered: false,
73+
size: 'small',
7374
},
7475
{
7576
default: () => UserRole[userRole],
@@ -82,41 +83,40 @@ function createColumns(): DataTableColumns {
8283
{
8384
title: () => t('setting.model.table.remark'),
8485
key: 'remark',
85-
width: 150,
86+
width: 120,
8687
},
8788
{
8889
title: () => t('setting.model.table.action'),
8990
key: '_id',
90-
width: 220,
91+
width: 140,
9192
fixed: 'right',
9293
render(row: any) {
9394
const actions: any[] = []
94-
actions.push(h(
95-
NButton,
96-
{
97-
size: 'small',
98-
style: {
99-
marginRight: '6px',
100-
},
101-
type: 'error',
102-
onClick: () => handleUpdateApiKeyStatus(row._id as string, Status.Disabled),
103-
},
104-
{ default: () => t('common.delete') },
105-
))
10695
if (row.status === Status.Normal) {
10796
actions.push(h(
10897
NButton,
10998
{
99+
tertiary: true,
110100
size: 'small',
111101
style: {
112102
marginRight: '6px',
113103
},
114104
type: 'info',
115105
onClick: () => handleEditKey(row as KeyConfig),
116106
},
117-
{ default: () => t('common.edit') },
107+
{ default: () => [h(IconRiEdit2Line, { class: 'mr-1 text-base' }), t('common.edit')] },
118108
))
119109
}
110+
actions.push(h(
111+
NButton,
112+
{
113+
tertiary: true,
114+
size: 'small',
115+
type: 'error',
116+
onClick: () => handleUpdateApiKeyStatus(row._id as string, Status.Disabled),
117+
},
118+
{ default: () => [h(IconRiDeleteBinLine, { class: 'mr-1 text-base' }), t('common.delete')] },
119+
))
120120
return actions
121121
},
122122
},
@@ -125,41 +125,16 @@ function createColumns(): DataTableColumns {
125125
126126
const columns = createColumns()
127127
128-
const pagination = reactive({
129-
page: 1,
130-
pageSize: 100,
131-
pageCount: 1,
132-
itemCount: 1,
133-
prefix({ itemCount }: { itemCount: number | undefined }) {
134-
return t('setting.model.total', { count: itemCount ?? 0 })
135-
},
136-
showSizePicker: true,
137-
pageSizes: [100],
138-
onChange: (page: number) => {
139-
pagination.page = page
140-
handleGetKeys(pagination.page)
141-
},
142-
onUpdatePageSize: (pageSize: number) => {
143-
pagination.pageSize = pageSize
144-
pagination.page = 1
145-
handleGetKeys(pagination.page)
146-
},
147-
})
148-
149-
async function handleGetKeys(page: number) {
128+
async function handleGetKeys() {
150129
if (loading.value)
151130
return
152131
keys.value.length = 0
153132
loading.value = true
154-
const size = pagination.pageSize
155-
const data = (await fetchGetKeys(page, size)).data
133+
const data = (await fetchGetKeys()).data
156134
data.keys.forEach((key: never) => {
157135
keys.value.push(key)
158136
})
159137
keyConfig.value = keys.value[0]
160-
pagination.page = page
161-
pagination.pageCount = data.total / size + (data.total % size === 0 ? 0 : 1)
162-
pagination.itemCount = data.total
163138
loading.value = false
164139
}
165140
@@ -172,7 +147,7 @@ async function handleUpdateApiKeyStatus(id: string, status: Status) {
172147
onPositiveClick: async () => {
173148
await fetchUpdateApiKeyStatus(id, status)
174149
ms.info(t('common.success'))
175-
await handleGetKeys(pagination.page)
150+
await handleGetKeys()
176151
},
177152
})
178153
}
@@ -185,7 +160,7 @@ async function handleUpdateKeyConfig() {
185160
handleSaving.value = true
186161
try {
187162
await fetchUpsertApiKey(keyConfig.value)
188-
await handleGetKeys(pagination.page)
163+
await handleGetKeys()
189164
show.value = false
190165
}
191166
catch (error: any) {
@@ -205,31 +180,29 @@ function handleEditKey(key: KeyConfig) {
205180
}
206181
207182
onMounted(async () => {
208-
await handleGetKeys(pagination.page)
183+
await handleGetKeys()
209184
})
210185
</script>
211186

212187
<template>
213-
<div class="p-4 space-y-5 min-h-[300px]">
214-
<div class="space-y-6">
215-
<NSpace vertical :size="12">
216-
<NSpace>
217-
<NButton @click="handleNewKey()">
218-
{{ t('setting.model.new') }}
219-
</NButton>
220-
</NSpace>
221-
<NDataTable
222-
remote
223-
:loading="loading"
224-
:row-key="(rowData) => rowData._id"
225-
:columns="columns"
226-
:data="keys"
227-
:pagination="pagination"
228-
:max-height="444"
229-
:scroll-x="1500"
230-
striped @update:page="handleGetKeys"
231-
/>
232-
</NSpace>
188+
<div class="box-border h-full flex-1 min-h-0 overflow-hidden px-4 pb-4 pt-2" style="height: 100%;">
189+
<div class="flex h-full min-h-0 flex-col gap-3">
190+
<div class="shrink-0 flex items-center justify-end">
191+
<NButton size="small" type="primary" @click="handleNewKey()">
192+
<IconRiAddLine class="mr-1 text-base" />
193+
{{ t('common.add') }}
194+
</NButton>
195+
</div>
196+
<NDataTable
197+
class="flex-1 min-h-0"
198+
:loading="loading"
199+
:row-key="(rowData) => rowData._id"
200+
:columns="columns"
201+
:data="keys"
202+
flex-height
203+
:scroll-x="1150"
204+
striped
205+
/>
233206
</div>
234207
</div>
235208

0 commit comments

Comments
 (0)