perf: support batch update ttl of keys
This commit is contained in:
parent
ed18d8b5ee
commit
1d1fab54d8
|
@ -1836,14 +1836,13 @@ func (b *browserService) SetKeyTTL(connName string, db int, k any, ttl int64) (r
|
|||
|
||||
client, ctx := item.client, item.ctx
|
||||
key := strutil.DecodeRedisKey(k)
|
||||
var expiration time.Duration
|
||||
if ttl < 0 {
|
||||
if err = client.Persist(ctx, key).Err(); err != nil {
|
||||
resp.Msg = err.Error()
|
||||
return
|
||||
}
|
||||
} else {
|
||||
expiration = time.Duration(ttl) * time.Second
|
||||
expiration := time.Duration(ttl) * time.Second
|
||||
if err = client.Expire(ctx, key, expiration).Err(); err != nil {
|
||||
resp.Msg = err.Error()
|
||||
return
|
||||
|
@ -1854,6 +1853,95 @@ func (b *browserService) SetKeyTTL(connName string, db int, k any, ttl int64) (r
|
|||
return
|
||||
}
|
||||
|
||||
// BatchSetTTL batch set ttl
|
||||
func (b *browserService) BatchSetTTL(server string, db int, ks []any, ttl int64, serialNo string) (resp types.JSResp) {
|
||||
conf := Connection().getConnection(server)
|
||||
if conf == nil {
|
||||
resp.Msg = fmt.Sprintf("no connection profile named: %s", server)
|
||||
return
|
||||
}
|
||||
var client redis.UniversalClient
|
||||
var err error
|
||||
var connConfig = conf.ConnectionConfig
|
||||
connConfig.LastDB = db
|
||||
if client, err = b.createRedisClient(connConfig); err != nil {
|
||||
resp.Msg = err.Error()
|
||||
return
|
||||
}
|
||||
ctx, cancelFunc := context.WithCancel(b.ctx)
|
||||
defer client.Close()
|
||||
defer cancelFunc()
|
||||
|
||||
//cancelEvent := "ttling:stop:" + serialNo
|
||||
//runtime.EventsOnce(ctx, cancelEvent, func(data ...any) {
|
||||
// cancelFunc()
|
||||
//})
|
||||
//processEvent := "ttling:" + serialNo
|
||||
total := len(ks)
|
||||
var failed, updated atomic.Int64
|
||||
var canceled bool
|
||||
|
||||
expiration := time.Now().Add(time.Duration(ttl) * time.Second)
|
||||
del := func(ctx context.Context, cli redis.UniversalClient) error {
|
||||
startTime := time.Now().Add(-10 * time.Second)
|
||||
for i, k := range ks {
|
||||
// emit progress per second
|
||||
//param := map[string]any{
|
||||
// "total": total,
|
||||
// "progress": i + 1,
|
||||
// "processing": k,
|
||||
//}
|
||||
if i >= total-1 || time.Now().Sub(startTime).Milliseconds() > 100 {
|
||||
startTime = time.Now()
|
||||
//runtime.EventsEmit(b.ctx, processEvent, param)
|
||||
// do some sleep to prevent blocking the Redis server
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
|
||||
key := strutil.DecodeRedisKey(k)
|
||||
var expErr error
|
||||
if ttl < 0 {
|
||||
expErr = cli.Persist(ctx, key).Err()
|
||||
} else {
|
||||
expErr = cli.ExpireAt(ctx, key, expiration).Err()
|
||||
}
|
||||
if err != nil {
|
||||
failed.Add(1)
|
||||
} else {
|
||||
// save deleted key
|
||||
updated.Add(1)
|
||||
}
|
||||
if errors.Is(expErr, context.Canceled) || canceled {
|
||||
canceled = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if cluster, ok := client.(*redis.ClusterClient); ok {
|
||||
// cluster mode
|
||||
err = cluster.ForEachMaster(ctx, func(ctx context.Context, cli *redis.Client) error {
|
||||
return del(ctx, cli)
|
||||
})
|
||||
} else {
|
||||
err = del(ctx, client)
|
||||
}
|
||||
|
||||
//runtime.EventsOff(ctx, cancelEvent)
|
||||
resp.Success = true
|
||||
resp.Data = struct {
|
||||
Canceled bool `json:"canceled"`
|
||||
Updated int64 `json:"updated"`
|
||||
Failed int64 `json:"failed"`
|
||||
}{
|
||||
Canceled: canceled,
|
||||
Updated: updated.Load(),
|
||||
Failed: failed.Load(),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteKey remove redis key
|
||||
func (b *browserService) DeleteKey(server string, db int, k any, async bool) (resp types.JSResp) {
|
||||
item, err := b.getRedisClient(server, db)
|
||||
|
@ -2007,13 +2095,13 @@ func (b *browserService) DeleteKeys(server string, db int, ks []any, serialNo st
|
|||
startTime := time.Now().Add(-10 * time.Second)
|
||||
for i, k := range ks {
|
||||
// emit progress per second
|
||||
param := map[string]any{
|
||||
"total": total,
|
||||
"progress": i + 1,
|
||||
"processing": k,
|
||||
}
|
||||
if i >= total-1 || time.Now().Sub(startTime).Milliseconds() > 100 {
|
||||
startTime = time.Now()
|
||||
param := map[string]any{
|
||||
"total": total,
|
||||
"progress": i + 1,
|
||||
"processing": k,
|
||||
}
|
||||
runtime.EventsEmit(b.ctx, processEvent, param)
|
||||
// do some sleep to prevent blocking the Redis server
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
|
|
@ -72,6 +72,15 @@ const onCopyKey = () => {
|
|||
$message.error(e.message)
|
||||
})
|
||||
}
|
||||
|
||||
const onTTL = () => {
|
||||
dialogStore.openTTLDialog({
|
||||
server: props.server,
|
||||
db: props.db,
|
||||
key: binaryKey.value ? props.keyCode : props.keyPath,
|
||||
ttl: props.ttl,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -93,7 +102,7 @@ const onCopyKey = () => {
|
|||
<n-button-group>
|
||||
<n-tooltip>
|
||||
<template #trigger>
|
||||
<n-button :focusable="false" @click="dialogStore.openTTLDialog(props.ttl)">
|
||||
<n-button :focusable="false" @click="onTTL">
|
||||
<template #icon>
|
||||
<n-icon :component="Timer" size="18" />
|
||||
</template>
|
||||
|
|
|
@ -222,7 +222,7 @@ const actionColumn = {
|
|||
})
|
||||
if (success) {
|
||||
props.value.splice(index, 1)
|
||||
$message.success(i18n.t('dialogue.delete_key_succ', { key: row.k }))
|
||||
$message.success(i18n.t('dialogue.delete.success', { key: row.k }))
|
||||
} else {
|
||||
$message.error(msg)
|
||||
}
|
||||
|
|
|
@ -194,7 +194,7 @@ const actionColumn = {
|
|||
index,
|
||||
})
|
||||
if (success) {
|
||||
$message.success(i18n.t('dialogue.delete_key_succ', { key: `#${index + 1}` }))
|
||||
$message.success(i18n.t('dialogue.delete.success', { key: `#${index + 1}` }))
|
||||
} else {
|
||||
$message.error(msg)
|
||||
}
|
||||
|
|
|
@ -191,7 +191,7 @@ const actionColumn = {
|
|||
value: row.v,
|
||||
})
|
||||
if (success) {
|
||||
$message.success(i18n.t('dialogue.delete_key_succ', { key: row.v }))
|
||||
$message.success(i18n.t('dialogue.delete.success', { key: row.v }))
|
||||
} else {
|
||||
$message.error(msg)
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ const actionColumn = {
|
|||
ids: row.id,
|
||||
})
|
||||
if (success) {
|
||||
$message.success(i18n.t('dialogue.delete_key_succ', { key: row.id }))
|
||||
$message.success(i18n.t('dialogue.delete.success', { key: row.id }))
|
||||
} else {
|
||||
$message.error(msg)
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ const onDelete = () => {
|
|||
const { name, db } = data.value
|
||||
browserStore.deleteKey(name, db, keyName.value).then((success) => {
|
||||
if (success) {
|
||||
$message.success(i18n.t('dialogue.delete_key_succ', { key: data.value.keyPath }))
|
||||
$message.success(i18n.t('dialogue.delete.success', { key: data.value.keyPath }))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
@ -238,7 +238,7 @@ const actionColumn = {
|
|||
value: row.v,
|
||||
})
|
||||
if (success) {
|
||||
$message.success(i18n.t('dialogue.delete_key_succ', { key: row.v }))
|
||||
$message.success(i18n.t('dialogue.delete.success', { key: row.v }))
|
||||
} else {
|
||||
$message.error(msg)
|
||||
}
|
||||
|
|
|
@ -214,7 +214,7 @@ const onClose = () => {
|
|||
</template>
|
||||
</n-input-number>
|
||||
<n-button :focusable="false" secondary type="primary" @click="() => (newForm.ttl = -1)">
|
||||
{{ $t('dialogue.key.persist_key') }}
|
||||
{{ $t('interface.forever') }}
|
||||
</n-button>
|
||||
</n-input-group>
|
||||
</n-form-item>
|
||||
|
|
|
@ -1,45 +1,46 @@
|
|||
<script setup>
|
||||
import { computed, reactive, watchEffect } from 'vue'
|
||||
import { computed, reactive, ref, watchEffect } from 'vue'
|
||||
import useDialog from 'stores/dialog'
|
||||
import useTabStore from 'stores/tab.js'
|
||||
import Binary from '@/components/icons/Binary.vue'
|
||||
import { isEmpty } from 'lodash'
|
||||
import useBrowserStore from 'stores/browser.js'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { isEmpty, size } from 'lodash'
|
||||
|
||||
const ttlForm = reactive({
|
||||
server: '',
|
||||
db: 0,
|
||||
key: '',
|
||||
keyCode: null,
|
||||
keys: [],
|
||||
ttl: -1,
|
||||
unit: 1,
|
||||
})
|
||||
|
||||
const dialogStore = useDialog()
|
||||
const browserStore = useBrowserStore()
|
||||
const tabStore = useTabStore()
|
||||
|
||||
watchEffect(() => {
|
||||
if (dialogStore.ttlDialogVisible) {
|
||||
// get ttl from current tab
|
||||
const tab = tabStore.currentTab
|
||||
if (tab != null) {
|
||||
ttlForm.server = tab.name
|
||||
ttlForm.db = tab.db
|
||||
ttlForm.key = tab.key
|
||||
ttlForm.keyCode = tab.keyCode
|
||||
ttlForm.unit = 1
|
||||
if (tab.ttl < 0) {
|
||||
// forever
|
||||
ttlForm.ttl = -1
|
||||
} else {
|
||||
ttlForm.ttl = tab.ttl
|
||||
}
|
||||
const { server, db, key, keys, ttl } = dialogStore.ttlParam
|
||||
ttlForm.server = server
|
||||
ttlForm.db = db
|
||||
ttlForm.key = key
|
||||
ttlForm.keys = keys
|
||||
ttlForm.unit = 1
|
||||
if (ttl < 0) {
|
||||
// forever
|
||||
ttlForm.ttl = -1
|
||||
} else {
|
||||
ttlForm.ttl = ttl
|
||||
}
|
||||
procssing.value = false
|
||||
}
|
||||
})
|
||||
|
||||
const procssing = ref(false)
|
||||
const isBatchAction = computed(() => {
|
||||
return !isEmpty(ttlForm.keys)
|
||||
})
|
||||
|
||||
const i18n = useI18n()
|
||||
const unit = computed(() => [
|
||||
{ value: 1, label: i18n.t('common.second') },
|
||||
|
@ -76,24 +77,20 @@ const onClose = () => {
|
|||
|
||||
const onConfirm = async () => {
|
||||
try {
|
||||
const tab = tabStore.currentTab
|
||||
if (tab == null) {
|
||||
return
|
||||
}
|
||||
const key = isEmpty(ttlForm.keyCode) ? ttlForm.key : ttlForm.keyCode
|
||||
procssing.value = true
|
||||
const ttl = ttlForm.ttl * (ttlForm.unit || 1)
|
||||
const success = await browserStore.setTTL(tab.name, tab.db, key, ttl)
|
||||
let success = false
|
||||
if (isBatchAction.value) {
|
||||
success = await browserStore.setTTLs(ttlForm.server, ttlForm.db, ttlForm.keys, ttl)
|
||||
} else {
|
||||
success = await browserStore.setTTL(ttlForm.server, ttlForm.db, ttlForm.key, ttl)
|
||||
}
|
||||
if (success) {
|
||||
tabStore.updateTTL({
|
||||
server: ttlForm.server,
|
||||
db: ttlForm.db,
|
||||
key: ttlForm.key,
|
||||
ttl: ttl,
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
$message.error(e.message || 'set ttl fail')
|
||||
} finally {
|
||||
procssing.value = false
|
||||
dialogStore.closeTTLDialog()
|
||||
}
|
||||
}
|
||||
|
@ -109,19 +106,17 @@ const onConfirm = async () => {
|
|||
:negative-text="$t('common.cancel')"
|
||||
:on-negative-click="onClose"
|
||||
:on-positive-click="onConfirm"
|
||||
:positive-button-props="{ focusable: false, size: 'medium' }"
|
||||
:positive-button-props="{ focusable: false, size: 'medium', loading: procssing }"
|
||||
:positive-text="$t('common.save')"
|
||||
:show-icon="false"
|
||||
:title="$t('dialogue.ttl.title')"
|
||||
:title="
|
||||
isBatchAction ? $t('dialogue.ttl.title_batch', { count: size(ttlForm.keys) }) : $t('dialogue.ttl.title')
|
||||
"
|
||||
preset="dialog"
|
||||
transform-origin="center">
|
||||
<n-form :model="ttlForm" :show-require-mark="false" label-placement="top">
|
||||
<n-form-item :label="$t('common.key')">
|
||||
<n-input :value="ttlForm.key" readonly>
|
||||
<template #prefix>
|
||||
<n-icon v-if="!!ttlForm.keyCode" :component="Binary" size="20" />
|
||||
</template>
|
||||
</n-input>
|
||||
<n-form-item v-if="!isBatchAction" :label="$t('common.key')">
|
||||
<n-input :value="ttlForm.key" readonly />
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('interface.ttl')" required>
|
||||
<n-input-group>
|
||||
|
|
|
@ -27,6 +27,7 @@ import { ConnectionType } from '@/consts/connection_type.js'
|
|||
import Import from '@/components/icons/Import.vue'
|
||||
import Down from '@/components/icons/Down.vue'
|
||||
import Checkbox from '@/components/icons/Checkbox.vue'
|
||||
import Timer from '@/components/icons/Timer.vue'
|
||||
|
||||
const props = defineProps({
|
||||
server: String,
|
||||
|
@ -170,6 +171,10 @@ const onExportChecked = () => {
|
|||
browserTreeRef.value?.exportCheckedItems()
|
||||
}
|
||||
|
||||
const onUpdateTTLChecked = () => {
|
||||
browserTreeRef.value?.updateTTLCheckedItems()
|
||||
}
|
||||
|
||||
const onImportData = () => {
|
||||
dialogStore.openImportKeyDialog(props.server, props.db)
|
||||
}
|
||||
|
@ -348,7 +353,7 @@ watch(
|
|||
:icon="LoadList"
|
||||
:loading="loading"
|
||||
:stroke-width="3.5"
|
||||
size="20"
|
||||
size="21"
|
||||
t-tooltip="interface.load_more"
|
||||
@click="onLoadMore" />
|
||||
<icon-button
|
||||
|
@ -357,7 +362,7 @@ watch(
|
|||
:icon="LoadAll"
|
||||
:loading="loading"
|
||||
:stroke-width="3.5"
|
||||
size="20"
|
||||
size="21"
|
||||
t-tooltip="interface.load_all"
|
||||
@click="onLoadAll" />
|
||||
<div class="flex-item-expand" style="min-width: 10px" />
|
||||
|
@ -365,7 +370,7 @@ watch(
|
|||
:button-class="['nav-pane-func-btn']"
|
||||
:icon="Checkbox"
|
||||
:stroke-width="3.5"
|
||||
size="20"
|
||||
size="19"
|
||||
t-tooltip="interface.check_mode"
|
||||
@click="inCheckState = true" />
|
||||
<n-dropdown
|
||||
|
@ -387,6 +392,14 @@ watch(
|
|||
size="20"
|
||||
t-tooltip="interface.export_checked"
|
||||
@click="onExportChecked" />
|
||||
<icon-button
|
||||
:button-class="['nav-pane-func-btn']"
|
||||
:disabled="checkedCount <= 0"
|
||||
:icon="Timer"
|
||||
:stroke-width="3.5"
|
||||
size="20"
|
||||
t-tooltip="interface.ttl_checked"
|
||||
@click="onUpdateTTLChecked" />
|
||||
<icon-button
|
||||
:button-class="['nav-pane-func-btn']"
|
||||
:disabled="checkedCount <= 0"
|
||||
|
|
|
@ -233,7 +233,7 @@ const handleSelectContextMenu = (key) => {
|
|||
$dialog.warning(i18n.t('dialogue.remove_tip', { name: redisKeyName }), () => {
|
||||
browserStore.deleteKey(props.server, db, redisKey).then((success) => {
|
||||
if (success) {
|
||||
$message.success(i18n.t('dialogue.delete_key_succ', { key: redisKeyName }))
|
||||
$message.success(i18n.t('dialogue.delete.success', { key: redisKeyName }))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -589,6 +589,17 @@ defineExpose({
|
|||
dialogStore.openExportKeyDialog(props.server, props.db, redisKeys)
|
||||
}
|
||||
},
|
||||
updateTTLCheckedItems: () => {
|
||||
const checkedKeys = tabStore.currentCheckedKeys
|
||||
const redisKeys = map(checkedKeys, 'redisKey')
|
||||
if (!isEmpty(redisKeys)) {
|
||||
dialogStore.openTTLDialog({
|
||||
server: props.server,
|
||||
db: props.db,
|
||||
keys: redisKeys,
|
||||
})
|
||||
}
|
||||
},
|
||||
getSelectedKey: () => {
|
||||
return selectedKeys.value || []
|
||||
},
|
||||
|
|
|
@ -84,6 +84,7 @@
|
|||
"quit_check_mode": "Quit Check Mode",
|
||||
"delete_checked": "Delete Checked Items",
|
||||
"export_checked": "Export Checked Items",
|
||||
"ttl_checked": "Update TTL for Checked Items",
|
||||
"copy_value": "Copy Value",
|
||||
"edit_value": "Edit Value",
|
||||
"save_update": "Save Update",
|
||||
|
@ -147,9 +148,6 @@
|
|||
"interrupt_connection": "Cancel",
|
||||
"remove_tip": "{type} \"{name}\" will be deleted",
|
||||
"remove_group_tip": "Group \"{name}\" and all connections in it will be deleted",
|
||||
"delete_key_succ": "\"{key}\" has been deleted",
|
||||
"deleting_key": "Deleting key({index}/{count})",
|
||||
"delete_completed": "Deletion process has been completed, {success} successed, {fail} failed",
|
||||
"rename_binary_key_fail": "Rename binary key name is unsupported",
|
||||
"handle_succ": "Success!",
|
||||
"handle_cancel": "The operation has been canceled.",
|
||||
|
@ -241,7 +239,6 @@
|
|||
"key": {
|
||||
"new": "New Key",
|
||||
"new_name": "New Key Name",
|
||||
"persist_key": "Persist Key",
|
||||
"server": "Connection",
|
||||
"db_index": "Database Index",
|
||||
"key_expression": "Key Expression",
|
||||
|
@ -253,6 +250,11 @@
|
|||
"confirm_flush": "I know what I'm doing!",
|
||||
"confirm_flush_db": "Confirm Flush Database"
|
||||
},
|
||||
"delete": {
|
||||
"success": "\"{key}\" has been deleted",
|
||||
"doing": "Deleting key({index}/{count})",
|
||||
"completed": "Deletion process has been completed, {success} successed, {fail} failed"
|
||||
},
|
||||
"field": {
|
||||
"new": "Add New Field",
|
||||
"new_item": "Add New Item",
|
||||
|
@ -301,8 +303,10 @@
|
|||
"import_completed": "Import completed, {success} successes, {ignored} failed"
|
||||
},
|
||||
"ttl": {
|
||||
"title": "Set Key TTL",
|
||||
"quick_set": "Quick Settings"
|
||||
"title": "Update TTL",
|
||||
"title_batch": "Batch Update TTL({count})",
|
||||
"quick_set": "Quick Settings",
|
||||
"success": "All TTL of keys have been updated"
|
||||
},
|
||||
"upgrade": {
|
||||
"title": "New Version Available",
|
||||
|
|
|
@ -215,7 +215,6 @@
|
|||
"key": {
|
||||
"new": "Nova Chave",
|
||||
"new_name": "Novo Nome da Chave",
|
||||
"persist_key": "Persistir Chave",
|
||||
"server": "Conexão",
|
||||
"db_index": "Índice do Banco de Dados",
|
||||
"key_expression": "Expressão da Chave",
|
||||
|
|
|
@ -84,6 +84,7 @@
|
|||
"quit_check_mode": "退出勾选模式",
|
||||
"delete_checked": "删除所选项",
|
||||
"export_checked": "导出所选项",
|
||||
"ttl_checked": "为所选项更新TTL",
|
||||
"copy_value": "复制值",
|
||||
"edit_value": "修改值",
|
||||
"save_update": "保存修改",
|
||||
|
@ -147,9 +148,6 @@
|
|||
"interrupt_connection": "中断连接",
|
||||
"remove_tip": "{type} \"{name}\" 将会被删除",
|
||||
"remove_group_tip": "分组 \"{name}\"及其所有连接将会被删除",
|
||||
"delete_key_succ": "{key} 已被删除",
|
||||
"deleting_key": "正在删除键({index}/{count})",
|
||||
"delete_completed": "已完成删除操作,成功{success}个,失败{fail}个",
|
||||
"rename_binary_key_fail": "不支持重命名二进制键名",
|
||||
"handle_succ": "操作成功",
|
||||
"handle_cancel": "操作已取消",
|
||||
|
@ -241,7 +239,6 @@
|
|||
"key": {
|
||||
"new": "添加新键",
|
||||
"new_name": "新键名",
|
||||
"persist_key": "持久化键",
|
||||
"server": "所属连接",
|
||||
"db_index": "数据库编号",
|
||||
"key_expression": "键名表达式",
|
||||
|
@ -253,6 +250,11 @@
|
|||
"confirm_flush": "我知道我正在执行的操作!",
|
||||
"confirm_flush_db": "确认清空数据库"
|
||||
},
|
||||
"delete": {
|
||||
"success": "{key} 已被删除",
|
||||
"doing": "正在删除键({index}/{count})",
|
||||
"completed": "已完成删除操作,成功{success}个,失败{fail}个"
|
||||
},
|
||||
"field": {
|
||||
"new": "添加新字段",
|
||||
"new_item": "添加新元素",
|
||||
|
@ -302,7 +304,9 @@
|
|||
},
|
||||
"ttl": {
|
||||
"title": "设置键存活时间",
|
||||
"quick_set": "快捷设置"
|
||||
"title_batch": "批量设置键存活时间({count})",
|
||||
"quick_set": "快捷设置",
|
||||
"success": "已全部更新TTL"
|
||||
},
|
||||
"upgrade": {
|
||||
"title": "有可用新版本",
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
AddListItem,
|
||||
AddStreamValue,
|
||||
AddZSetValue,
|
||||
BatchSetTTL,
|
||||
CleanCmdHistory,
|
||||
CloseConnection,
|
||||
ConvertValue,
|
||||
|
@ -1484,19 +1485,81 @@ const useBrowserStore = defineStore('browser', {
|
|||
* reset key's ttl
|
||||
* @param {string} server
|
||||
* @param {number} db
|
||||
* @param {string} key
|
||||
* @param {string|number[]} key
|
||||
* @param {number} ttl
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async setTTL(server, db, key, ttl) {
|
||||
try {
|
||||
const { success, msg } = await SetKeyTTL(server, db, key, ttl)
|
||||
if (success) {
|
||||
const tabStore = useTabStore()
|
||||
tabStore.updateTTL({
|
||||
server,
|
||||
db,
|
||||
key,
|
||||
ttl,
|
||||
})
|
||||
}
|
||||
return success === true
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
async setTTLs(server, db, keys, ttl) {
|
||||
// const msgRef = $message.loading('', { duration: 0, closable: true })
|
||||
// let updated = []
|
||||
// let failCount = 0
|
||||
// let canceled = false
|
||||
const serialNo = Date.now().valueOf().toString()
|
||||
// const eventName = 'ttling:' + serialNo
|
||||
// const cancelEvent = 'ttling:stop:' + serialNo
|
||||
try {
|
||||
// let maxProgress = 0
|
||||
// EventsOn(eventName, ({ total, progress, processing }) => {
|
||||
// // update delete progress
|
||||
// if (progress > maxProgress) {
|
||||
// maxProgress = progress
|
||||
// }
|
||||
// const k = decodeRedisKey(processing)
|
||||
// msgRef.content = i18nGlobal.t('dialogue.delete.doing', {
|
||||
// key: k,
|
||||
// index: maxProgress,
|
||||
// count: total,
|
||||
// })
|
||||
// })
|
||||
// msgRef.onClose = () => {
|
||||
// EventsEmit(cancelEvent)
|
||||
// }
|
||||
const { data, success, msg } = await BatchSetTTL(server, db, keys, ttl, serialNo)
|
||||
if (success) {
|
||||
// canceled = get(data, 'canceled', false)
|
||||
// updated = get(data, 'updated', [])
|
||||
// failCount = get(data, 'failed', 0)
|
||||
} else {
|
||||
$message.error(msg)
|
||||
}
|
||||
} finally {
|
||||
// msgRef.destroy()
|
||||
// EventsOff(eventName)
|
||||
}
|
||||
$message.success(i18nGlobal.t('dialogue.ttl.success'))
|
||||
// const deletedCount = size(updated)
|
||||
// if (canceled) {
|
||||
// $message.info(i18nGlobal.t('dialogue.handle_cancel'))
|
||||
// } else if (failCount <= 0) {
|
||||
// // no fail
|
||||
// $message.success(i18nGlobal.t('dialogue.delete.completed', { success: deletedCount, fail: failCount }))
|
||||
// } else if (failCount >= deletedCount) {
|
||||
// // all fail
|
||||
// $message.error(i18nGlobal.t('dialogue.delete.completed', { success: deletedCount, fail: failCount }))
|
||||
// } else {
|
||||
// // some fail
|
||||
// $message.warn(i18nGlobal.t('dialogue.delete.completed', { success: deletedCount, fail: failCount }))
|
||||
// }
|
||||
},
|
||||
|
||||
/**
|
||||
* delete redis key
|
||||
* @param {string} server
|
||||
|
@ -1557,7 +1620,7 @@ const useBrowserStore = defineStore('browser', {
|
|||
maxProgress = progress
|
||||
}
|
||||
const k = decodeRedisKey(processing)
|
||||
msgRef.content = i18nGlobal.t('dialogue.deleting_key', {
|
||||
msgRef.content = i18nGlobal.t('dialogue.delete.doing', {
|
||||
key: k,
|
||||
index: maxProgress,
|
||||
count: total,
|
||||
|
@ -1587,13 +1650,13 @@ const useBrowserStore = defineStore('browser', {
|
|||
$message.info(i18nGlobal.t('dialogue.handle_cancel'))
|
||||
} else if (failCount <= 0) {
|
||||
// no fail
|
||||
$message.success(i18nGlobal.t('dialogue.delete_completed', { success: deletedCount, fail: failCount }))
|
||||
$message.success(i18nGlobal.t('dialogue.delete.completed', { success: deletedCount, fail: failCount }))
|
||||
} else if (failCount >= deletedCount) {
|
||||
// all fail
|
||||
$message.error(i18nGlobal.t('dialogue.delete_completed', { success: deletedCount, fail: failCount }))
|
||||
$message.error(i18nGlobal.t('dialogue.delete.completed', { success: deletedCount, fail: failCount }))
|
||||
} else {
|
||||
// some fail
|
||||
$message.warn(i18nGlobal.t('dialogue.delete_completed', { success: deletedCount, fail: failCount }))
|
||||
$message.warn(i18nGlobal.t('dialogue.delete.completed', { success: deletedCount, fail: failCount }))
|
||||
}
|
||||
// update ui
|
||||
timeout(100).then(async () => {
|
||||
|
|
|
@ -82,8 +82,14 @@ const useDialogStore = defineStore('dialog', {
|
|||
},
|
||||
flushDBDialogVisible: false,
|
||||
|
||||
selectTTL: -1,
|
||||
ttlDialogVisible: false,
|
||||
ttlParam: {
|
||||
server: '',
|
||||
db: 0,
|
||||
key: '',
|
||||
keys: [],
|
||||
ttl: 0,
|
||||
},
|
||||
|
||||
preferencesDialogVisible: false,
|
||||
aboutDialogVisible: false,
|
||||
|
@ -264,12 +270,23 @@ const useDialogStore = defineStore('dialog', {
|
|||
this.addFieldsDialogVisible = false
|
||||
},
|
||||
|
||||
openTTLDialog(ttl) {
|
||||
this.selectTTL = ttl
|
||||
/**
|
||||
*
|
||||
* @param {string} server
|
||||
* @param {number} db
|
||||
* @param {string|number[]} [key]
|
||||
* @param {string[]|number[][]} [keys]
|
||||
* @param {number} [ttl]
|
||||
*/
|
||||
openTTLDialog({ server, db, key, keys, ttl = -1 }) {
|
||||
this.ttlDialogVisible = true
|
||||
this.ttlParam.server = server
|
||||
this.ttlParam.db = db
|
||||
this.ttlParam.key = key
|
||||
this.ttlParam.keys = keys
|
||||
this.ttlParam.ttl = ttl
|
||||
},
|
||||
closeTTLDialog() {
|
||||
this.selectTTL = -1
|
||||
this.ttlDialogVisible = false
|
||||
},
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { assign, find, findIndex, get, isEmpty, pullAt, remove, set, size } from 'lodash'
|
||||
import { defineStore } from 'pinia'
|
||||
import { TabItem } from '@/objects/tabItem.js'
|
||||
import { decodeRedisKey } from '@/utils/key_convert.js'
|
||||
|
||||
const useTabStore = defineStore('tab', {
|
||||
/**
|
||||
|
@ -546,7 +547,7 @@ const useTabStore = defineStore('tab', {
|
|||
* @param {number} ttl
|
||||
*/
|
||||
updateTTL({ server, db, key, ttl }) {
|
||||
let tab = find(this.tabList, { name: server, db, key })
|
||||
let tab = find(this.tabList, { name: server, db, key: decodeRedisKey(key) })
|
||||
if (tab == null) {
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue