Skip to content

Commit 1372e6d

Browse files
authored
feat: support to show databases and tables on ui (#631)
* feat: support to show databases and tables * support to show database and tables * support to show databases and tables * feat: add urlEncode and urlDecode functions to template rendering * fix: update copyright year and add password placeholder handling in store update * feat(DataManager): add support for multiple databases - Add currentDatabase parameter to DataQuery function - Update API request to include X-Database header - Modify query object for atest-store-orm to include database key * feat(console): enhance database manager functionality and layout - Add queryDataFromTable and queryTables functions - Implement database and table selection - Adjust layout for better usability - Optimize SQL query execution * fix the scrollbar issues on the data manager page * add etcd and orm compitable * add redis key-value query support * support to let user to choose store param from list * update readme file * fix the frontend unit test issues --------- Co-authored-by: rick <[email protected]>
1 parent 6908433 commit 1372e6d

File tree

24 files changed

+2362
-1947
lines changed

24 files changed

+2362
-1947
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ console/atest-desktop/atest
2020
console/atest-desktop/atest.exe
2121
console/atest-desktop/coverage
2222
atest-store-git
23+
.db

console/atest-ui/src/views/DataManager.vue

Lines changed: 83 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ const sqlQuery = ref('')
1010
const queryResult = ref([])
1111
const columns = ref([])
1212
const queryTip = ref('')
13+
const databases = ref([])
14+
const tables = ref([])
15+
const currentDatabase = ref('')
16+
const loadingStores = ref(true)
1317
18+
const tablesTree = ref([])
1419
watch(store, (s) => {
1520
stores.value.forEach((e: Store) => {
1621
if (e.name === s) {
@@ -19,27 +24,37 @@ watch(store, (s) => {
1924
}
2025
})
2126
})
27+
const queryDataFromTable = (data) => {
28+
sqlQuery.value = `select * from ${data.label} limit 10`
29+
executeQuery()
30+
}
31+
const queryTables = () => {
32+
sqlQuery.value = `show tables`
33+
executeQuery()
34+
}
2235
watch(kind, (k) => {
2336
switch (k) {
2437
case 'atest-store-orm':
2538
sqlQuery.value = 'show tables'
2639
queryTip.value = 'Enter SQL query'
2740
break;
28-
case 'atest-store-etcd':
41+
case 'atest-store-etcd', 'atest-store-redis':
2942
sqlQuery.value = ''
3043
queryTip.value = 'Enter key'
3144
break;
3245
}
3346
})
3447
3548
API.GetStores((data) => {
36-
stores.value = data.data
49+
stores.value = data.data
3750
}, (e) => {
38-
ElMessage({
39-
showClose: true,
40-
message: e.message,
41-
type: 'error'
42-
});
51+
ElMessage({
52+
showClose: true,
53+
message: e.message,
54+
type: 'error'
55+
});
56+
}, () => {
57+
loadingStores.value = false
4358
})
4459
4560
const ormDataHandler = (data) => {
@@ -55,12 +70,22 @@ const ormDataHandler = (data) => {
5570
result.push(obj)
5671
})
5772
73+
databases.value = data.meta.databases
74+
tables.value = data.meta.tables
75+
currentDatabase.value = data.meta.currentDatabase
5876
queryResult.value = result
5977
columns.value = Array.from(cols).sort((a, b) => {
6078
if (a === 'id') return -1;
6179
if (b === 'id') return 1;
6280
return a.localeCompare(b);
6381
})
82+
83+
tablesTree.value = []
84+
tables.value.forEach((i) => {
85+
tablesTree.value.push({
86+
label: i,
87+
})
88+
})
6489
}
6590
6691
const keyValueDataHandler = (data) => {
@@ -76,14 +101,23 @@ const keyValueDataHandler = (data) => {
76101
}
77102
78103
const executeQuery = async () => {
79-
API.DataQuery(store.value, kind.value, sqlQuery.value, (data) => {
104+
switch (kind.value) {
105+
case 'atest-store-etcd':
106+
sqlQuery.value = '*'
107+
break;
108+
}
109+
110+
API.DataQuery(store.value, kind.value, currentDatabase.value, sqlQuery.value, (data) => {
80111
switch (kind.value) {
81112
case 'atest-store-orm':
82113
ormDataHandler(data)
83114
break;
84115
case 'atest-store-etcd':
85116
keyValueDataHandler(data)
86117
break;
118+
case 'atest-store-redis':
119+
keyValueDataHandler(data)
120+
break;
87121
default:
88122
ElMessage({
89123
showClose: true,
@@ -103,30 +137,47 @@ const executeQuery = async () => {
103137

104138
<template>
105139
<div>
106-
<el-form @submit.prevent="executeQuery">
107-
<el-row :gutter="10">
108-
<el-col :span="2">
109-
<el-form-item>
110-
<el-select v-model="store" placeholder="Select store">
111-
<el-option v-for="item in stores" :key="item.name" :label="item.name"
112-
:value="item.name" :disabled="!item.ready" :kind="item.kind.name"></el-option>
140+
<el-container style="height: calc(100vh - 45px);">
141+
<el-aside v-if="kind === 'atest-store-orm'">
142+
<el-scrollbar>
143+
<el-select v-model="currentDatabase" placeholder="Select database" @change="queryTables" filterable>
144+
<el-option v-for="item in databases" :key="item" :label="item"
145+
:value="item"></el-option>
113146
</el-select>
114-
</el-form-item>
115-
</el-col>
116-
<el-col :span="18">
117-
<el-form-item>
118-
<el-input v-model="sqlQuery" :placeholder="queryTip" @keyup.enter="executeQuery"></el-input>
119-
</el-form-item>
120-
</el-col>
121-
<el-col :span="2">
122-
<el-form-item>
123-
<el-button type="primary" @click="executeQuery">Execute</el-button>
124-
</el-form-item>
125-
</el-col>
126-
</el-row>
127-
</el-form>
128-
<el-table :data="queryResult">
129-
<el-table-column v-for="col in columns" :key="col" :prop="col" :label="col"></el-table-column>
130-
</el-table>
147+
<el-tree :data="tablesTree" node-key="label" @node-click="queryDataFromTable" highlight-current draggable/>
148+
</el-scrollbar>
149+
</el-aside>
150+
<el-container>
151+
<el-header>
152+
<el-form @submit.prevent="executeQuery">
153+
<el-row :gutter="10">
154+
<el-col :span="4">
155+
<el-form-item>
156+
<el-select v-model="store" placeholder="Select store" filterable :loading="loadingStores">
157+
<el-option v-for="item in stores" :key="item.name" :label="item.name"
158+
:value="item.name" :disabled="!item.ready" :kind="item.kind.name"></el-option>
159+
</el-select>
160+
</el-form-item>
161+
</el-col>
162+
<el-col :span="17">
163+
<el-form-item>
164+
<el-input v-model="sqlQuery" :placeholder="queryTip" @keyup.enter="executeQuery"></el-input>
165+
</el-form-item>
166+
</el-col>
167+
<el-col :span="2">
168+
<el-form-item>
169+
<el-button type="primary" @click="executeQuery">Execute</el-button>
170+
</el-form-item>
171+
</el-col>
172+
</el-row>
173+
</el-form>
174+
</el-header>
175+
<el-main>
176+
<el-table :data="queryResult">
177+
<el-table-column v-for="col in columns" :key="col" :prop="col" :label="col"></el-table-column>
178+
</el-table>
179+
</el-main>
180+
</el-container>
181+
</el-container>
131182
</div>
132183
</template>

console/atest-ui/src/views/StoreManager.vue

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ watch(() => storeForm.kind.name, (name) => {
150150
value: '',
151151
defaultValue: p.defaultValue,
152152
description: p.description,
153+
type: p.type,
154+
enum: p.enum
153155
} as Pair)
154156
} else {
155157
pro[index].description = p.description
@@ -318,15 +320,21 @@ const storeExtLink = ref('')
318320
<el-table-column label="Value">
319321
<template #default="scope">
320322
<div style="display: flex; align-items: center">
321-
<el-input v-model="scope.row.value" :placeholder="scope.row.defaultValue">
322-
<template #append v-if="scope.row.description">
323-
<el-tooltip :content="scope.row.description">
323+
<el-select v-model="scope.row.value" v-if="scope.row.enum">
324+
<el-option
325+
v-for="item in scope.row.enum"
326+
:key="item"
327+
:label="item"
328+
:value="item"
329+
/>
330+
</el-select>
331+
<el-input-number v-model="scope.row.value" v-else-if="scope.row.type === 'number'"/>
332+
<el-input v-model="scope.row.value" :placeholder="scope.row.defaultValue" v-else/>
333+
<el-tooltip :content="scope.row.description" v-if="scope.row.description">
324334
<el-icon>
325335
<QuestionFilled/>
326336
</el-icon>
327337
</el-tooltip>
328-
</template>
329-
</el-input>
330338
</div>
331339
</template>
332340
</el-table-column>

console/atest-ui/src/views/__test__/store.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {SupportedExtension, SupportedExtensions} from "../store";
1919
describe("SupportedExtensions", () => {
2020
test('length check', () => {
2121
const extensions = SupportedExtensions()
22-
expect(extensions.length).toBe(5)
22+
expect(extensions.length).toBe(6)
2323
})
2424

2525
for (const extension of SupportedExtensions()) {

console/atest-ui/src/views/net.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -773,20 +773,25 @@ var SBOM = (callback: (d: any) => void) => {
773773
.then(callback)
774774
}
775775

776-
var DataQuery = (store: string, kind: string, query: string, callback: (d: any) => void, errHandler: (d: any) => void) => {
776+
var DataQuery = (store: string, kind: string, currentDatabase: string, query: string, callback: (d: any) => void, errHandler: (d: any) => void) => {
777777
const queryObj = {}
778778
switch (kind) {
779779
case 'atest-store-orm':
780780
queryObj['sql'] = query;
781+
queryObj['key'] = currentDatabase;
781782
break;
782783
case 'atest-store-etcd':
783784
queryObj['key'] = query;
784785
break;
786+
case 'atest-store-redis':
787+
queryObj['key'] = query;
788+
break;
785789
}
786790
const requestOptions = {
787791
method: 'POST',
788792
headers: {
789-
'X-Store-Name': store
793+
'X-Store-Name': store,
794+
'X-Database': currentDatabase
790795
},
791796
body: JSON.stringify(queryObj)
792797
}

0 commit comments

Comments
 (0)