Skip to content

Commit c69ee65

Browse files
author
fuyoo
committed
optimize
1 parent 46f303c commit c69ee65

File tree

9 files changed

+176
-48
lines changed

9 files changed

+176
-48
lines changed

components.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ declare module 'vue' {
1010
export interface GlobalComponents {
1111
CoHostTab: typeof import('./src/components/CoHostTab.vue')['default']
1212
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
13+
NAlert: typeof import('naive-ui')['NAlert']
1314
NButton: typeof import('naive-ui')['NButton']
1415
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
1516
NDataTable: typeof import('naive-ui')['NDataTable']

src/i18n/en-US/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default {
99
['Github', 'github.com/fuyoo/bs-redis-desktop-client'],
1010
],
1111
settings: ['Settings', 'Language', 'Version'],
12-
actions: ['Ok', 'Cancel', 'Delete', 'Edit', 'Add', 'Insert'],
12+
actions: ['Ok', 'Cancel', 'Delete', 'Edit', 'Add', 'Insert','Download'],
1313
home: {
1414
form: {
1515
lable: ['Name', 'Host', 'Port', 'Database', 'Username', 'Password', 'Cluster'],
@@ -31,5 +31,6 @@ export default {
3131
normal: ['Database', 'Please select a key.'],
3232
timeFormat: ['d', 'h', 'm', 's', 'mill','never'],
3333
table: ['Data','Operate'],
34-
tips: ['Current data type unsupported yet.']
34+
tips: ['Current data type unsupported yet.',
35+
'Due to the data being larger than {size}, the displayed data is truncated. You can click the button next to it to download the original data']
3536
}

src/i18n/zh-CN/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export default {
66
['Github', 'github.com/fuyoo/bs-redis-desktop-client'],
77
],
88
settings: ['设置', '语言', '版本'],
9-
actions: ['确定', '取消', '删除', '修改', '添加','插入'],
9+
actions: ['确定', '取消', '删除', '修改', '添加','插入','下载'],
1010
home: {
1111
form: {
1212
lable: ['名称', '地址', '端口', '数据库', '用户名', '密码', '是否集群'],
@@ -29,5 +29,5 @@ export default {
2929
normal: ['数据库', '请选择一个键'],
3030
timeFormat: ['天', '时', '分', '秒', '毫秒', '永不过期'],
3131
table: ['数据', '操作'],
32-
tips: ['该数据类型尚不支持']
32+
tips: ['该数据类型尚不支持','由于数据大于{size},当前显示的是被截断的数据。你可以点击旁边的按钮下载原始数据']
3333
}

src/pages/host/components/CoKeys/index.vue

Lines changed: 132 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
<script setup lang="ts">
22
import { useReqStore } from '@/stores/req.ts'
3-
import { reactive, ref, h } from 'vue'
3+
import { reactive, ref, h,computed } from 'vue'
44
import { useRoute, useRouter } from 'vue-router'
55
import type { DropdownOption } from 'naive-ui'
6-
import { Folder, FolderOpenOutline, Trash } from '@vicons/ionicons5'
6+
import { Folder, FolderOpenOutline, KeyOutline, Trash } from '@vicons/ionicons5'
77
import { NIcon } from 'naive-ui'
88
import { useResize } from '@/hooks/life.ts'
9-
import { ID, parseTreeWithNameSpace } from '@/tools/keys.ts'
9+
import { ID } from '@/tools/keys.ts'
1010
import type { Tree } from '@/types.ts'
11+
import KeysWorker from '@/worker/keys.ts?worker'
1112
13+
const keysWorker = new KeysWorker()
1214
const router = useRouter()
1315
const reqStore = useReqStore()
1416
const route = useRoute()
@@ -39,40 +41,105 @@ const original = reactive<{
3941
// todo: enable name space by configure.
4042
const nameSpaceEnable = ref(true)
4143
// here we do some no search patten logic.
42-
const queryOriginalData = async () => {
43-
original.loading = true
44+
const queryData = async (isSearch?: boolean) => {
45+
if (isSearch) search.loading = true
46+
else original.loading = true
4447
try {
4548
// fetch data pass through rust side.
4649
const resp = await reqStore.reqWithHost<string>({
4750
path: '/cmd',
48-
data: JSON.stringify(['scan', original.cursor, 'MATCH', '*', 'COUNT', '5000']),
51+
data: JSON.stringify([
52+
'scan',
53+
isSearch ? search.cursor : original.cursor,
54+
'MATCH',
55+
isSearch ? search.match : '*',
56+
'COUNT',
57+
'5000',
58+
]),
4959
})
5060
// parse data
5161
const v = resp.data.split('\n')
62+
if (isSearch) {
63+
let arr = []
5264
53-
if (original.cursor === '0') {
54-
originalKeyList = v
55-
.splice(1)
56-
.map((e) => ({ type: 'key', label: e, icon: 'key', id: ID() }) as Tree)
65+
if (search.cursor === '0') {
66+
arr = v.splice(1).map((e) => ({ type: 'key', label: e, icon: 'key', id: ID() }) as Tree)
67+
} else {
68+
arr = search.tree.concat(
69+
v.splice(1).map(
70+
(e) =>
71+
({
72+
type: 'key',
73+
label: e,
74+
icon: 'key',
75+
id: ID(),
76+
}) as Tree,
77+
),
78+
)
79+
}
80+
search.cursor = v[0]
81+
// const data = [] as Tree[]
82+
// arr.forEach((e) => {
83+
// parseTreeWithNameSpace(data, e.label)
84+
// })
85+
// search.tree = data
86+
keysWorker.postMessage({
87+
type: 'parse',
88+
data: arr,
89+
})
90+
search.tree = await new Promise((resolve) => {
91+
keysWorker.onmessage = (e) => {
92+
resolve(e.data)
93+
}
94+
})
5795
} else {
58-
v.splice(1).forEach((e) => {
59-
originalKeyList.push({ type: 'key', label: e, icon: 'key', id: ID() })
96+
// no search match
97+
if (original.cursor === '0') {
98+
originalKeyList = v
99+
.splice(1)
100+
.map((e) => ({ type: 'key', label: e, icon: 'key', id: ID() }) as Tree)
101+
} else {
102+
v.splice(1).forEach((e) => {
103+
originalKeyList.push({ type: 'key', label: e, icon: 'key', id: ID() })
104+
})
105+
}
106+
original.cursor = v[0]
107+
// const arr = [] as Tree[]
108+
// originalKeyList.forEach((e) => {
109+
// parseTreeWithNameSpace(arr, e.label)
110+
// })
111+
// original.tree = arr
112+
keysWorker.postMessage({
113+
type: 'parse',
114+
data: originalKeyList,
115+
})
116+
original.tree = await new Promise((resolve) => {
117+
keysWorker.onmessage = (e) => {
118+
resolve(e.data)
119+
}
60120
})
61-
console.log(originalKeyList.length)
62121
}
63-
original.cursor = v[0]
64-
const arr = [] as Tree[]
65-
originalKeyList.forEach((e) => {
66-
parseTreeWithNameSpace(arr, e.label)
67-
})
68-
original.tree = arr
69-
} catch (e) {}
122+
} catch (e) {
123+
console.error(e)
124+
}
70125
original.loading = false
126+
search.loading = false
71127
}
72-
queryOriginalData()
73-
74-
const { height } = useResize(120)
128+
queryData()
75129
130+
const { height } = useResize(115)
131+
const calcHeight = computed(() => {
132+
if (search.match !== '') {
133+
if (search.cursor === '0') {
134+
return height.value + 30 + 'px'
135+
}
136+
return height.value + 'px'
137+
}
138+
if (original.cursor === '0') {
139+
return height.value + 30 + 'px'
140+
}
141+
return height.value + 'px'
142+
})
76143
const updatePrefixWithExpand = (
77144
_keys: Array<string | number>,
78145
_option: Array<Tree | null>,
@@ -81,6 +148,7 @@ const updatePrefixWithExpand = (
81148
action: 'expand' | 'collapse' | 'filter'
82149
},
83150
) => {
151+
console.log ('updatePrefixWithExpand', _keys, _option, meta)
84152
if (!meta.node) return
85153
switch (meta.action) {
86154
case 'expand':
@@ -100,8 +168,9 @@ const updatePrefixWithExpand = (
100168
101169
const loadMoreFn = () => {
102170
if (search.match !== '') {
171+
queryData(true)
103172
} else {
104-
queryOriginalData()
173+
queryData()
105174
}
106175
}
107176
@@ -154,6 +223,7 @@ const nodeProps = ({ option }: { option: Tree }) => {
154223
},
155224
}
156225
}
226+
// contextmenu selected function.
157227
const handleSelect = async (act: string) => {
158228
showDropdownRef.value = false
159229
const data = focusNodeData
@@ -164,7 +234,7 @@ const handleSelect = async (act: string) => {
164234
data: ['del', data.value],
165235
})
166236
if (code === 0) {
167-
await queryOriginalData()
237+
await queryData(search.match !== "")
168238
}
169239
return
170240
}
@@ -180,16 +250,33 @@ const handleSelect = async (act: string) => {
180250
}
181251
}
182252
findKeys(data?.children || [])
183-
// todo: need implement batch delete at 'rust' end. this implementation so ugly.
253+
// todo: need implement batch delete at 'rust' end. this implementation is so ugly.
184254
for (const key of keys) {
185255
await reqStore.reqWithHost<string>({
186256
path: '/cmd',
187257
data: ['del', key],
188258
})
189259
}
190-
await queryOriginalData()
260+
await queryData(search.match !== "")
191261
}
192262
}
263+
// throttle
264+
let timer = -1 as any
265+
const doFilter = async () => {
266+
console.log(search)
267+
search.cursor = '0'
268+
clearTimeout(timer)
269+
if (search.match === '') return
270+
timer = setTimeout(async () => {
271+
await queryData(true)
272+
}, 100)
273+
}
274+
275+
function renderPrefix(data: { option: Tree }) {
276+
return h(NIcon, null, {
277+
default: () => h(data.option.type === 'key' ? KeyOutline : Folder),
278+
})
279+
}
193280
</script>
194281
<template>
195282
<div ref="treeBoxRef" class="w-full flex flex-col flex-1 justify-start items-start">
@@ -199,6 +286,7 @@ const handleSelect = async (act: string) => {
199286
class="flex-1"
200287
size="tiny"
201288
v-model:value="search.match"
289+
@update:value="doFilter"
202290
placeholder="redis query format"
203291
>
204292
<template #prefix>
@@ -213,17 +301,31 @@ const handleSelect = async (act: string) => {
213301
ref="treeInstRef"
214302
block-line
215303
show-line
304+
:render-prefix="renderPrefix"
216305
:on-update:expanded-keys="updatePrefixWithExpand"
217-
:data="original.tree"
306+
:data="search.match != '' ? search.tree : original.tree"
218307
virtual-scroll
219308
expand-on-click
220309
:node-props="nodeProps"
221-
:style="{ height: height + 'px' }"
310+
:style="{ height: calcHeight }"
222311
key-field="id"
223312
children-field="children"
224313
class="whitespace-nowrap"
225314
/>
226-
<div class="flex flex-1 w-full justify-center items-center" v-show="original.cursor != '0'">
315+
<div
316+
class="flex flex-1 w-full justify-center items-center"
317+
v-if="!search.match"
318+
v-show="original.cursor != '0'"
319+
>
320+
<n-button size="small" type="primary" :loading="reqStore.reqLoading" @click="loadMoreFn"
321+
>加载更多
322+
</n-button>
323+
</div>
324+
<div
325+
v-else
326+
class="flex flex-1 w-full justify-center items-center"
327+
v-show="search.cursor != '0'"
328+
>
227329
<n-button size="small" type="primary" :loading="reqStore.reqLoading" @click="loadMoreFn"
228330
>加载更多
229331
</n-button>

src/pages/host/key-types/co-list/index.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ const { height } = useResize()
7979
<template>
8080
<div class="w-full h-full">
8181
<co-info-header v-model:size="size" type="string">
82-
<div><n-button size="tiny" type="primary">{{ $t('actions[5]') }}</n-button></div>
82+
<div><n-button size="tiny" type="primary">
83+
<template #icon><i class="i-pajamas:insert"></i></template>
84+
{{ $t('actions[5]') }}</n-button></div>
8385
</co-info-header>
8486
<div class="p-5">
8587
<n-data-table

src/pages/host/key-types/co-string/index.vue

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,46 @@
11
<script setup lang="tsx">
22
import { useReqStore } from '@/stores/req.ts'
3-
import { ref, shallowRef } from 'vue'
3+
import { ref, shallowRef,computed } from 'vue'
44
import { useRoute } from 'vue-router'
55
import { useModal,type ModalReactive } from 'naive-ui'
66
import { useI18n } from 'vue-i18n'
77
import CoInfoHeader from '@/pages/host/components/CoInfoHeader/index.vue'
88
import { Key } from '@/tools/keys.ts'
9-
9+
// redis key
1010
const key = Key()
11+
// i18n helper function
1112
const { t } = useI18n()
13+
// route
1214
const route = useRoute()
15+
// hook, packaged request helper
1316
const reqStore = useReqStore()
17+
// redis key data
1418
const content = shallowRef<string>('')
19+
// redis key used space size. unit byte
1520
const size = ref<string>('')
21+
// key space size whether larger than limit size.
22+
const largerThan = computed(() => {
23+
return Number(size.value) > 1024 * 1024
24+
})
25+
// fetch data
1626
const fetchData = async () => {
1727
const { data } = await reqStore.reqWithHost<string>({
1828
path: '/cmd',
1929
data: ['get', atob(route.params.key as string)],
2030
})
2131
// more than 1Mb, we are truncate it.
22-
if (Number(size.value) > 1024 * 1024) {
32+
if (largerThan.value) {
2333
content.value = data.slice(0, 1024 * 1024) + '...'
2434
return
2535
}
2636
content.value = data
2737
}
2838
fetchData()
39+
// change value model.
2940
const vModel = ref<string>('')
41+
// naive ui modal
3042
const modal = useModal()
43+
// submit to change value
3144
const submitFn = (m: ModalReactive) => {
3245
reqStore
3346
.reqWithHost({
@@ -39,6 +52,7 @@ const submitFn = (m: ModalReactive) => {
3952
fetchData()
4053
})
4154
}
55+
// create modal func.
4256
const changeValue = () => {
4357
vModel.value = content.value
4458
const m = modal.create({
@@ -79,12 +93,15 @@ const changeValue = () => {
7993
<co-info-header v-model:size="size" type="string">
8094
<n-space>
8195
<n-button type="primary" size="tiny" @click="changeValue">
82-
<i class="i-material-symbols:edit-square-rounded"></i> {{ $t('actions[3]') }}
96+
<template #icon><i class="i-material-symbols:edit-square-rounded"></i></template> {{ $t('actions[3]') }}
8397
</n-button>
8498
</n-space>
8599
</co-info-header>
86100
<div class="p-4">
87-
<textarea readonly class="w-full h-full resize-none b-none outline-none" v-model="content" />
101+
<n-alert v-if="largerThan" type="info" :bordered="false">
102+
{{$t('tips[1]',{size: '1Mb'})}} <n-button size="tiny" type="primary" quaternary>{{$t("actions.6")}}</n-button>
103+
</n-alert>
104+
<textarea readonly class="mt-4 w-full h-full resize-none b-none outline-none" v-model="content" />
88105
</div>
89106
</div>
90107
</template>

src/tools/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export const showHostConfigureDetail = async (id: string) => {
1717

1818
export const dataToHuman = (data: string): string => {
1919
const bytes = parseInt(data, 10);
20+
console.log(bytes);
2021
if (isNaN(bytes) || bytes < 0) return '0 B';
2122

2223
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];

0 commit comments

Comments
 (0)