Skip to content

Commit 16cb414

Browse files
feat: Add API Key Page
1 parent 06e79f5 commit 16cb414

File tree

7 files changed

+399
-1
lines changed

7 files changed

+399
-1
lines changed
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 6 additions & 0 deletions
Loading
Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
<script lang="ts" setup>
2+
import { computed, reactive, ref } from 'vue'
3+
import { useI18n } from 'vue-i18n'
4+
import icon_warning_filled from '@/assets/svg/icon_info_colorful.svg'
5+
import icon_add_outlined from '@/assets/svg/icon_add_outlined.svg'
6+
import icon_visible_outlined_blod from '@/assets/embedded/icon_visible_outlined_blod.svg'
7+
import icon_copy_outlined from '@/assets/svg/icon_copy_outlined.svg'
8+
import IconOpeDelete from '@/assets/svg/icon_delete.svg'
9+
import icon_invisible_outlined from '@/assets/embedded/icon_invisible_outlined.svg'
10+
import icon_visible_outlined from '@/assets/embedded/icon_visible_outlined.svg'
11+
import { formatTimestamp } from '@/utils/date'
12+
import { useClipboard } from '@vueuse/core'
13+
import EmptyBackground from '@/views/dashboard/common/EmptyBackground.vue'
14+
const { t } = useI18n()
15+
16+
const limitCount = ref(5)
17+
const limitValid = ref(true)
18+
19+
const triggerLimit = computed(() => {
20+
return limitValid.value && state.tableData.length >= limitCount.value
21+
})
22+
const state = reactive({
23+
tableData: [] as any,
24+
})
25+
26+
state.tableData = [
27+
{
28+
access_key: 'fwafwafwafwaf',
29+
secret_key: '1234567',
30+
status: false,
31+
create_time: 1766455902237,
32+
},
33+
{
34+
access_key: 'asdasdasdasd',
35+
secret_key: '987654321',
36+
status: true,
37+
create_time: 1766455902237,
38+
},
39+
{
40+
access_key: 'asdasdasdasd',
41+
secret_key: '987654321',
42+
status: true,
43+
create_time: 1766455902237,
44+
},
45+
{
46+
access_key: 'asdasdasdasd',
47+
secret_key: '987654321',
48+
status: true,
49+
create_time: 1766455902237,
50+
},
51+
]
52+
const handleAdd = () => {
53+
if (triggerLimit.value) {
54+
return
55+
}
56+
console.log('Add API Key')
57+
}
58+
const pwd = ref('**********')
59+
const toApiDoc = () => {
60+
console.log('Add API Key')
61+
const url = '/docs'
62+
window.open(url, '_blank')
63+
}
64+
65+
const statusHandler = (row: any) => {
66+
/* state.form = { ...row }
67+
editTerm() */
68+
const param = {
69+
id: row.id,
70+
status: row.status,
71+
}
72+
console.log(row, param)
73+
// userApi.status(param)
74+
}
75+
const { copy } = useClipboard({ legacy: true })
76+
77+
const copyCode = (row: any, key: any = 'secret_key') => {
78+
copy(row[key])
79+
.then(function () {
80+
ElMessage.success(t('embedded.copy_successful'))
81+
})
82+
.catch(function () {
83+
ElMessage.error(t('embedded.copy_failed'))
84+
})
85+
}
86+
const deleteHandler = (row: any) => {
87+
ElMessageBox.confirm(t('user.del_user', { msg: row.name }), {
88+
confirmButtonType: 'danger',
89+
confirmButtonText: t('dashboard.delete'),
90+
cancelButtonText: t('common.cancel'),
91+
customClass: 'confirm-no_icon',
92+
autofocus: false,
93+
}).then(() => {
94+
/* userApi.delete(row.id).then(() => {
95+
multipleSelectionAll.value = multipleSelectionAll.value.filter((ele) => ele.id !== row.id)
96+
ElMessage({
97+
type: 'success',
98+
message: t('dashboard.delete_success'),
99+
})
100+
search()
101+
}) */
102+
console.log('execute delete')
103+
})
104+
}
105+
</script>
106+
107+
<template>
108+
<div class="sqlbot-apikey-container">
109+
<div class="warn-template">
110+
<span class="icon-span">
111+
<el-icon>
112+
<Icon name="icon_warning_filled"><icon_warning_filled class="svg-icon" /></Icon>
113+
</el-icon>
114+
</span>
115+
<div class="warn-template-content">
116+
<span>{{ t('api_key.info_tips') }}</span>
117+
</div>
118+
</div>
119+
120+
<div class="api-key-btn">
121+
<el-tooltip
122+
v-if="triggerLimit"
123+
:offset="14"
124+
effect="dark"
125+
:content="t('api_key.trigger_limit', [limitCount])"
126+
placement="top"
127+
>
128+
<el-button v-if="triggerLimit" type="info" disabled>
129+
<template #icon>
130+
<icon_add_outlined></icon_add_outlined>
131+
</template>
132+
{{ $t('api_key.create') }}
133+
</el-button>
134+
</el-tooltip>
135+
<el-button v-else type="primary" @click="handleAdd">
136+
<template #icon>
137+
<icon_add_outlined></icon_add_outlined>
138+
</template>
139+
{{ $t('api_key.create') }}
140+
</el-button>
141+
142+
<el-button secondary @click="toApiDoc">
143+
<template #icon>
144+
<icon_visible_outlined_blod></icon_visible_outlined_blod>
145+
</template>
146+
{{ $t('api_key.to_doc') }}
147+
</el-button>
148+
</div>
149+
<div class="api-key-grid">
150+
<el-table ref="multipleTableRef" :data="state.tableData" style="width: 100%">
151+
<el-table-column prop="access_key" label="Access Key" width="256">
152+
<template #default="scope">
153+
<div class="user-status-container">
154+
<div :title="scope.row.access_key" class="ellipsis" style="max-width: 208px">
155+
{{ scope.row.access_key }}
156+
</div>
157+
<el-tooltip
158+
:offset="12"
159+
effect="dark"
160+
:content="t('datasource.copy')"
161+
placement="top"
162+
>
163+
<el-icon
164+
size="16"
165+
class="hover-icon_with_bg"
166+
@click="copyCode(scope.row, 'access_key')"
167+
>
168+
<icon_copy_outlined></icon_copy_outlined>
169+
</el-icon>
170+
</el-tooltip>
171+
</div>
172+
</template>
173+
</el-table-column>
174+
<el-table-column prop="secret_key" label="Secret Key" width="256">
175+
<template #default="scope">
176+
<div class="user-status-container">
177+
<div
178+
:title="scope.row.showPwd ? scope.row.secret_key : pwd"
179+
class="ellipsis"
180+
style="max-width: 208px"
181+
>
182+
{{ scope.row.showPwd ? scope.row.secret_key : pwd }}
183+
</div>
184+
<el-tooltip
185+
:offset="12"
186+
effect="dark"
187+
:content="t('datasource.copy')"
188+
placement="top"
189+
>
190+
<el-icon class="hover-icon_with_bg" size="16" @click="copyCode(scope.row)">
191+
<icon_copy_outlined></icon_copy_outlined>
192+
</el-icon>
193+
</el-tooltip>
194+
195+
<el-tooltip
196+
v-if="scope.row.showPwd"
197+
:offset="12"
198+
effect="dark"
199+
:content="t('embedded.click_to_hide')"
200+
placement="top"
201+
>
202+
<el-icon class="hover-icon_with_bg" size="16" @click="scope.row.showPwd = false">
203+
<icon_visible_outlined></icon_visible_outlined>
204+
</el-icon>
205+
</el-tooltip>
206+
207+
<el-tooltip
208+
v-if="!scope.row.showPwd"
209+
:offset="12"
210+
effect="dark"
211+
:content="t('embedded.click_to_show')"
212+
placement="top"
213+
>
214+
<el-icon class="hover-icon_with_bg" size="16" @click="scope.row.showPwd = true">
215+
<icon_invisible_outlined></icon_invisible_outlined>
216+
</el-icon>
217+
</el-tooltip>
218+
</div>
219+
</template>
220+
</el-table-column>
221+
<el-table-column prop="create_time" width="180" sortable :label="t('user.creation_time')">
222+
<template #default="scope">
223+
<span>{{ formatTimestamp(scope.row.create_time, 'YYYY-MM-DD HH:mm:ss') }}</span>
224+
</template>
225+
</el-table-column>
226+
<el-table-column fixed="right" width="100" :label="$t('ds.actions')">
227+
<template #default="scope">
228+
<div class="table-operate">
229+
<el-switch
230+
v-model="scope.row.status"
231+
:active-value="true"
232+
:inactive-value="false"
233+
size="small"
234+
@change="statusHandler(scope.row)"
235+
/>
236+
<div class="line"></div>
237+
<el-tooltip
238+
:offset="14"
239+
effect="dark"
240+
:content="$t('dashboard.delete')"
241+
placement="top"
242+
>
243+
<el-icon class="action-btn" size="16" @click="deleteHandler(scope.row)">
244+
<IconOpeDelete></IconOpeDelete>
245+
</el-icon>
246+
</el-tooltip>
247+
</div>
248+
</template>
249+
</el-table-column>
250+
<template #empty>
251+
<EmptyBackground
252+
v-if="!state.tableData.length"
253+
:description="$t('datasource.relevant_content_found')"
254+
img-type="none"
255+
/>
256+
</template>
257+
</el-table>
258+
</div>
259+
</div>
260+
</template>
261+
262+
<style lang="less" scoped>
263+
.sqlbot-apikey-container {
264+
background: #ffffff;
265+
border-radius: 8px;
266+
row-gap: 24px;
267+
display: flex;
268+
flex-direction: column;
269+
270+
.warn-template {
271+
display: flex;
272+
align-items: center;
273+
background: #d2f1e9;
274+
// border: 1px solid #ffe7ba;
275+
border-radius: 6px;
276+
padding: 9px 16px;
277+
278+
.icon-span {
279+
width: 16px;
280+
height: 16px;
281+
margin-right: 8px;
282+
display: flex;
283+
align-items: center;
284+
margin-top: -20px;
285+
i {
286+
width: 16px;
287+
height: 16px;
288+
}
289+
290+
.svg-icon {
291+
width: 16px;
292+
height: 16px;
293+
}
294+
}
295+
296+
.warn-template-content {
297+
font-size: 14px;
298+
color: #1f2329;
299+
}
300+
}
301+
302+
.api-key-btn {
303+
margin-bottom: 0px;
304+
305+
.el-button {
306+
margin-right: 8px;
307+
}
308+
}
309+
310+
.api-key-grid {
311+
width: 100%;
312+
.el-table {
313+
width: 100%;
314+
}
315+
316+
.table-operate {
317+
display: flex;
318+
align-items: center;
319+
320+
.line {
321+
width: 1px;
322+
height: 16px;
323+
background: #e8e8e8;
324+
margin: 0 12px;
325+
}
326+
327+
.action-btn {
328+
width: 24px;
329+
height: 24px;
330+
border-radius: 6px;
331+
cursor: pointer;
332+
color: #646a73;
333+
334+
&:hover {
335+
background-color: #1f23291a;
336+
}
337+
}
338+
}
339+
.user-status-container {
340+
display: flex;
341+
align-items: center;
342+
font-weight: 400;
343+
font-size: 14px;
344+
line-height: 22px;
345+
height: 24px;
346+
347+
.ed-icon {
348+
margin-left: 8px;
349+
}
350+
351+
.ed-icon + .ed-icon {
352+
margin-left: 12px;
353+
}
354+
}
355+
}
356+
}
357+
</style>

0 commit comments

Comments
 (0)