feat: add full search for list

This commit is contained in:
Lykin 2023-11-20 16:23:27 +08:00
parent aafa0c5432
commit db4e2385fc
10 changed files with 199 additions and 78 deletions

View File

@ -595,7 +595,7 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
} }
// define get entry cursor function // define get entry cursor function
getEntryCursor := func() (uint64, string) { getEntryCursor := func() (uint64, string, bool) {
if entry, ok := entryCors[param.DB]; !ok || entry.Key != key || entry.Pattern != matchPattern { if entry, ok := entryCors[param.DB]; !ok || entry.Key != key || entry.Pattern != matchPattern {
// not the same key or match pattern, reset cursor // not the same key or match pattern, reset cursor
entry = entryCursor{ entry = entryCursor{
@ -605,9 +605,9 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
Cursor: 0, Cursor: 0,
} }
entryCors[param.DB] = entry entryCors[param.DB] = entry
return 0, "" return 0, "", true
} else { } else {
return entry.Cursor, entry.XLast return entry.Cursor, entry.XLast, false
} }
} }
// define set entry cursor function // define set entry cursor function
@ -639,19 +639,21 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
//data.Value, data.Decode, data.Format = strutil.ConvertTo(str, param.Decode, param.Format) //data.Value, data.Decode, data.Format = strutil.ConvertTo(str, param.Decode, param.Format)
case "list": case "list":
loadListHandle := func() ([]types.ListEntryItem, bool, error) { loadListHandle := func() ([]types.ListEntryItem, bool, bool, error) {
var loadVal []string var loadVal []string
var cursor uint64 var cursor uint64
var reset bool
var subErr error var subErr error
if param.Full { doFilter := matchPattern != "*"
if param.Full || matchPattern != "*" {
// load all // load all
cursor = 0 cursor, reset = 0, true
loadVal, subErr = client.LRange(ctx, key, 0, -1).Result() loadVal, subErr = client.LRange(ctx, key, 0, -1).Result()
} else { } else {
if param.Reset { if param.Reset {
cursor = 0 cursor, reset = 0, true
} else { } else {
cursor, _ = getEntryCursor() cursor, _, reset = getEntryCursor()
} }
scanSize := int64(Preferences().GetScanSize()) scanSize := int64(Preferences().GetScanSize())
loadVal, subErr = client.LRange(ctx, key, int64(cursor), int64(cursor)+scanSize-1).Result() loadVal, subErr = client.LRange(ctx, key, int64(cursor), int64(cursor)+scanSize-1).Result()
@ -662,42 +664,48 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
} }
setEntryCursor(cursor) setEntryCursor(cursor)
items := make([]types.ListEntryItem, len(loadVal)) items := make([]types.ListEntryItem, 0, len(loadVal))
for i, val := range loadVal { for _, val := range loadVal {
items[i].Value = val if doFilter && !strings.Contains(val, param.MatchPattern) {
continue
}
items = append(items, types.ListEntryItem{
Value: val,
})
if doConvert { if doConvert {
if dv, _, _ := strutil.ConvertTo(val, param.Decode, param.Format); dv != val { if dv, _, _ := strutil.ConvertTo(val, param.Decode, param.Format); dv != val {
items[i].DisplayValue = dv items[len(items)-1].DisplayValue = dv
} }
} }
} }
if subErr != nil { if subErr != nil {
return items, false, subErr return items, reset, false, subErr
} }
return items, cursor == 0, nil return items, reset, cursor == 0, nil
} }
data.Value, data.End, err = loadListHandle() data.Value, data.Reset, data.End, err = loadListHandle()
data.Decode, data.Format = param.Decode, param.Format data.Match, data.Decode, data.Format = param.MatchPattern, param.Decode, param.Format
if err != nil { if err != nil {
resp.Msg = err.Error() resp.Msg = err.Error()
return return
} }
case "hash": case "hash":
loadHashHandle := func() ([]types.HashEntryItem, bool, error) { loadHashHandle := func() ([]types.HashEntryItem, bool, bool, error) {
var items []types.HashEntryItem var items []types.HashEntryItem
var loadedVal []string var loadedVal []string
var cursor uint64 var cursor uint64
var reset bool
var subErr error var subErr error
scanSize := int64(Preferences().GetScanSize()) scanSize := int64(Preferences().GetScanSize())
if param.Full { if param.Full {
// load all // load all
cursor = 0 cursor, reset = 0, true
for { for {
loadedVal, cursor, subErr = client.HScan(ctx, key, cursor, "*", scanSize).Result() loadedVal, cursor, subErr = client.HScan(ctx, key, cursor, "*", scanSize).Result()
if subErr != nil { if subErr != nil {
return nil, false, subErr return nil, reset, false, subErr
} }
for i := 0; i < len(loadedVal); i += 2 { for i := 0; i < len(loadedVal); i += 2 {
items = append(items, types.HashEntryItem{ items = append(items, types.HashEntryItem{
@ -716,13 +724,13 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
} }
} else { } else {
if param.Reset { if param.Reset {
cursor = 0 cursor, reset = 0, true
} else { } else {
cursor, _ = getEntryCursor() cursor, _, reset = getEntryCursor()
} }
loadedVal, cursor, subErr = client.HScan(ctx, key, cursor, matchPattern, scanSize).Result() loadedVal, cursor, subErr = client.HScan(ctx, key, cursor, matchPattern, scanSize).Result()
if subErr != nil { if subErr != nil {
return nil, false, subErr return nil, reset, false, subErr
} }
loadedLen := len(loadedVal) loadedLen := len(loadedVal)
items = make([]types.HashEntryItem, loadedLen/2) items = make([]types.HashEntryItem, loadedLen/2)
@ -737,30 +745,31 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
} }
} }
setEntryCursor(cursor) setEntryCursor(cursor)
return items, cursor == 0, nil return items, reset, cursor == 0, nil
} }
data.Value, data.End, err = loadHashHandle() data.Value, data.Reset, data.End, err = loadHashHandle()
data.Decode, data.Format = param.Decode, param.Format data.Match, data.Decode, data.Format = param.MatchPattern, param.Decode, param.Format
if err != nil { if err != nil {
resp.Msg = err.Error() resp.Msg = err.Error()
return return
} }
case "set": case "set":
loadSetHandle := func() ([]types.SetEntryItem, bool, error) { loadSetHandle := func() ([]types.SetEntryItem, bool, bool, error) {
var items []types.SetEntryItem var items []types.SetEntryItem
var cursor uint64 var cursor uint64
var reset bool
var subErr error var subErr error
var loadedKey []string var loadedKey []string
scanSize := int64(Preferences().GetScanSize()) scanSize := int64(Preferences().GetScanSize())
if param.Full { if param.Full {
// load all // load all
cursor = 0 cursor, reset = 0, true
for { for {
loadedKey, cursor, subErr = client.SScan(ctx, key, cursor, param.MatchPattern, scanSize).Result() loadedKey, cursor, subErr = client.SScan(ctx, key, cursor, param.MatchPattern, scanSize).Result()
if subErr != nil { if subErr != nil {
return items, false, subErr return items, reset, false, subErr
} }
for _, val := range loadedKey { for _, val := range loadedKey {
items = append(items, types.SetEntryItem{ items = append(items, types.SetEntryItem{
@ -778,9 +787,9 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
} }
} else { } else {
if param.Reset { if param.Reset {
cursor = 0 cursor, reset = 0, true
} else { } else {
cursor, _ = getEntryCursor() cursor, _, reset = getEntryCursor()
} }
loadedKey, cursor, subErr = client.SScan(ctx, key, cursor, param.MatchPattern, scanSize).Result() loadedKey, cursor, subErr = client.SScan(ctx, key, cursor, param.MatchPattern, scanSize).Result()
items = make([]types.SetEntryItem, len(loadedKey)) items = make([]types.SetEntryItem, len(loadedKey))
@ -794,29 +803,30 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
} }
} }
setEntryCursor(cursor) setEntryCursor(cursor)
return items, cursor == 0, nil return items, reset, cursor == 0, nil
} }
data.Value, data.End, err = loadSetHandle() data.Value, data.Reset, data.End, err = loadSetHandle()
data.Decode, data.Format = param.Decode, param.Format data.Match, data.Decode, data.Format = param.MatchPattern, param.Decode, param.Format
if err != nil { if err != nil {
resp.Msg = err.Error() resp.Msg = err.Error()
return return
} }
case "zset": case "zset":
loadZSetHandle := func() ([]types.ZSetEntryItem, bool, error) { loadZSetHandle := func() ([]types.ZSetEntryItem, bool, bool, error) {
var items []types.ZSetEntryItem var items []types.ZSetEntryItem
var reset bool
var cursor uint64 var cursor uint64
scanSize := int64(Preferences().GetScanSize()) scanSize := int64(Preferences().GetScanSize())
var loadedVal []string var loadedVal []string
if param.Full { if param.Full {
// load all // load all
cursor = 0 cursor, reset = 0, true
for { for {
loadedVal, cursor, err = client.ZScan(ctx, key, cursor, param.MatchPattern, scanSize).Result() loadedVal, cursor, err = client.ZScan(ctx, key, cursor, param.MatchPattern, scanSize).Result()
if err != nil { if err != nil {
return items, false, err return items, reset, false, err
} }
var score float64 var score float64
for i := 0; i < len(loadedVal); i += 2 { for i := 0; i < len(loadedVal); i += 2 {
@ -838,9 +848,9 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
} }
} else { } else {
if param.Reset { if param.Reset {
cursor = 0 cursor, reset = 0, true
} else { } else {
cursor, _ = getEntryCursor() cursor, _, reset = getEntryCursor()
} }
loadedVal, cursor, err = client.ZScan(ctx, key, cursor, param.MatchPattern, scanSize).Result() loadedVal, cursor, err = client.ZScan(ctx, key, cursor, param.MatchPattern, scanSize).Result()
loadedLen := len(loadedVal) loadedLen := len(loadedVal)
@ -859,30 +869,31 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
} }
} }
setEntryCursor(cursor) setEntryCursor(cursor)
return items, cursor == 0, nil return items, reset, cursor == 0, nil
} }
data.Value, data.End, err = loadZSetHandle() data.Value, data.Reset, data.End, err = loadZSetHandle()
data.Decode, data.Format = param.Decode, param.Format data.Match, data.Decode, data.Format = param.MatchPattern, param.Decode, param.Format
if err != nil { if err != nil {
resp.Msg = err.Error() resp.Msg = err.Error()
return return
} }
case "stream": case "stream":
loadStreamHandle := func() ([]types.StreamEntryItem, bool, error) { loadStreamHandle := func() ([]types.StreamEntryItem, bool, bool, error) {
var msgs []redis.XMessage var msgs []redis.XMessage
var last string var last string
var reset bool
if param.Full { if param.Full {
// load all // load all
last = "" last, reset = "", true
msgs, err = client.XRevRange(ctx, key, "+", "-").Result() msgs, err = client.XRevRange(ctx, key, "+", "-").Result()
} else { } else {
scanSize := int64(Preferences().GetScanSize()) scanSize := int64(Preferences().GetScanSize())
if param.Reset { if param.Reset {
last = "" last = ""
} else { } else {
_, last = getEntryCursor() _, last, reset = getEntryCursor()
} }
if len(last) <= 0 { if len(last) <= 0 {
last = "+" last = "+"
@ -913,13 +924,13 @@ func (b *browserService) GetKeyDetail(param types.KeyDetailParam) (resp types.JS
} }
} }
if err != nil { if err != nil {
return items, false, err return items, reset, false, err
} }
return items, last == "", nil return items, reset, last == "", nil
} }
data.Value, data.End, err = loadStreamHandle() data.Value, data.Reset, data.End, err = loadStreamHandle()
data.Decode, data.Format = param.Decode, param.Format data.Match, data.Decode, data.Format = param.MatchPattern, param.Decode, param.Format
if err != nil { if err != nil {
resp.Msg = err.Error() resp.Msg = err.Error()
return return

View File

@ -35,6 +35,8 @@ type KeyDetail struct {
Length int64 `json:"length,omitempty"` Length int64 `json:"length,omitempty"`
Format string `json:"format,omitempty"` Format string `json:"format,omitempty"`
Decode string `json:"decode,omitempty"` Decode string `json:"decode,omitempty"`
Match string `json:"match,omitempty"`
Reset bool `json:"reset"`
End bool `json:"end"` End bool `json:"end"`
} }

View File

@ -57,6 +57,7 @@ const tabContent = computed(() => {
length: tab.length || 0, length: tab.length || 0,
decode: tab.decode || decodeTypes.NONE, decode: tab.decode || decodeTypes.NONE,
format: tab.format || formatTypes.RAW, format: tab.format || formatTypes.RAW,
matchPattern: tab.matchPattern || '',
end: tab.end === true, end: tab.end === true,
loading: tab.loading === true, loading: tab.loading === true,
} }

View File

@ -0,0 +1,85 @@
<script setup>
import { computed, reactive } from 'vue'
import { isEmpty, trim } from 'lodash'
import { NButton, NInput } from 'naive-ui'
const props = defineProps({})
const emit = defineEmits(['filterChanged', 'matchChanged'])
/**
*
* @type {UnwrapNestedRefs<{filter: string, match: string}>}
*/
const inputData = reactive({
match: '',
filter: '',
})
const hasMatch = computed(() => {
return !isEmpty(trim(inputData.match))
})
const hasFilter = computed(() => {
return !isEmpty(trim(inputData.filter))
})
const onFullSearch = () => {
inputData.filter = trim(inputData.filter)
if (!isEmpty(inputData.filter)) {
inputData.match = inputData.filter
inputData.filter = ''
emit('matchChanged', inputData.match, inputData.filter)
}
}
const onInput = () => {
emit('filterChanged', inputData.filter)
}
const onClearFilter = () => {
inputData.filter = ''
onClearMatch()
}
const onClearMatch = () => {
const changed = !isEmpty(inputData.match)
inputData.match = ''
if (changed) {
emit('matchChanged', inputData.match, inputData.filter)
} else {
emit('filterChanged', inputData.filter)
}
}
defineExpose({
reset: onClearFilter,
})
</script>
<template>
<n-input-group>
<n-input
v-model:value="inputData.filter"
:placeholder="$t('interface.filter')"
clearable
@clear="onClearFilter"
@input="onInput">
<template #prefix>
<n-tooltip v-if="hasMatch">
<template #trigger>
<n-tag closable size="small" @close="onClearMatch">
{{ inputData.match }}
</n-tag>
</template>
{{ $t('interface.full_search') }}
</n-tooltip>
</template>
</n-input>
<n-button :disabled="hasMatch && !hasFilter" :focusable="false" @click="onFullSearch">
{{ $t('interface.full_search') }}
</n-button>
</n-input-group>
</template>
<style lang="scss" scoped></style>

View File

@ -3,7 +3,7 @@ import { computed, h, reactive, ref } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import ContentToolbar from './ContentToolbar.vue' import ContentToolbar from './ContentToolbar.vue'
import AddLink from '@/components/icons/AddLink.vue' import AddLink from '@/components/icons/AddLink.vue'
import { NButton, NCode, NIcon, NInput, useThemeVars } from 'naive-ui' import { NButton, NCode, NIcon, useThemeVars } from 'naive-ui'
import { isEmpty, size } from 'lodash' import { isEmpty, size } from 'lodash'
import { types, types as redisTypes } from '@/consts/support_redis_type.js' import { types, types as redisTypes } from '@/consts/support_redis_type.js'
import EditableTableColumn from '@/components/common/EditableTableColumn.vue' import EditableTableColumn from '@/components/common/EditableTableColumn.vue'
@ -17,6 +17,7 @@ import IconButton from '@/components/common/IconButton.vue'
import ContentEntryEditor from '@/components/content_value/ContentEntryEditor.vue' import ContentEntryEditor from '@/components/content_value/ContentEntryEditor.vue'
import FormatSelector from '@/components/content_value/FormatSelector.vue' import FormatSelector from '@/components/content_value/FormatSelector.vue'
import Edit from '@/components/icons/Edit.vue' import Edit from '@/components/icons/Edit.vue'
import ContentSearchInput from '@/components/content_value/ContentSearchInput.vue'
const i18n = useI18n() const i18n = useI18n()
const themeVars = useThemeVars() const themeVars = useThemeVars()
@ -52,7 +53,7 @@ const props = defineProps({
loading: Boolean, loading: Boolean,
}) })
const emit = defineEmits(['loadmore', 'loadall', 'reload', 'rename', 'delete']) const emit = defineEmits(['loadmore', 'loadall', 'reload', 'rename', 'delete', 'match'])
/** /**
* *
@ -249,13 +250,13 @@ const onAddValue = (value) => {
dialogStore.openAddFieldsDialog(props.name, props.db, props.keyPath, props.keyCode, types.LIST) dialogStore.openAddFieldsDialog(props.name, props.db, props.keyPath, props.keyCode, types.LIST)
} }
const filterValue = ref('')
const onFilterInput = (val) => { const onFilterInput = (val) => {
valueFilterOption.value = val valueFilterOption.value = val
} }
const clearFilter = () => { const onMatchInput = (matchVal, filterVal) => {
valueFilterOption.value = null valueFilterOption.value = filterVal
emit('match', matchVal)
} }
const onUpdateFilter = (filters, sourceColumn) => { const onUpdateFilter = (filters, sourceColumn) => {
@ -266,10 +267,11 @@ const onFormatChanged = (selDecode, selFormat) => {
emit('reload', selDecode, selFormat) emit('reload', selDecode, selFormat)
} }
const searchInputRef = ref(null)
defineExpose({ defineExpose({
reset: () => { reset: () => {
clearFilter()
resetEdit() resetEdit()
searchInputRef.value?.reset()
}, },
}) })
</script> </script>
@ -290,12 +292,10 @@ defineExpose({
@rename="emit('rename')" /> @rename="emit('rename')" />
<div class="tb2 value-item-part flex-box-h"> <div class="tb2 value-item-part flex-box-h">
<div class="flex-box-h"> <div class="flex-box-h">
<n-input <content-search-input
v-model:value="filterValue" ref="searchInputRef"
:placeholder="$t('interface.search')" @filter-changed="onFilterInput"
clearable @match-changed="onMatchInput" />
@clear="clearFilter"
@update:value="onFilterInput" />
</div> </div>
<div class="flex-item-expand"></div> <div class="flex-item-expand"></div>
<n-button-group> <n-button-group>

View File

@ -64,7 +64,14 @@ const keyName = computed(() => {
return !isEmpty(data.value.keyCode) ? data.value.keyCode : data.value.keyPath return !isEmpty(data.value.keyCode) ? data.value.keyCode : data.value.keyPath
}) })
const loadData = async (reset, full) => { /**
*
* @param {boolean} reset
* @param {boolean} [full]
* @param {string} [selMatch]
* @return {Promise<void>}
*/
const loadData = async (reset, full, selMatch) => {
try { try {
if (!!props.blank) { if (!!props.blank) {
return return
@ -75,7 +82,7 @@ const loadData = async (reset, full) => {
server: name, server: name,
db: db, db: db,
key: keyName.value, key: keyName.value,
matchPattern: matchPattern, matchPattern: selMatch === undefined ? matchPattern : selMatch,
decode: reset ? decodeTypes.NONE : decode, decode: reset ? decodeTypes.NONE : decode,
format: reset ? formatTypes.RAW : format, format: reset ? formatTypes.RAW : format,
reset, reset,
@ -133,6 +140,10 @@ const onLoadAll = () => {
loadData(false, true) loadData(false, true)
} }
const onMatch = (match) => {
loadData(true, false, match || '')
}
const contentRef = ref(null) const contentRef = ref(null)
const initContent = async () => { const initContent = async () => {
// onReload() // onReload()
@ -141,7 +152,7 @@ const initContent = async () => {
if (contentRef.value?.reset != null) { if (contentRef.value?.reset != null) {
contentRef.value?.reset() contentRef.value?.reset()
} }
await loadData(true, false) await loadData(true, false, '')
if (contentRef.value?.beforeShow != null) { if (contentRef.value?.beforeShow != null) {
await contentRef.value?.beforeShow() await contentRef.value?.beforeShow()
} }
@ -185,6 +196,7 @@ watch(() => data.value?.keyPath, initContent)
@delete="onDelete" @delete="onDelete"
@loadall="onLoadAll" @loadall="onLoadAll"
@loadmore="onLoadMore" @loadmore="onLoadMore"
@match="onMatch"
@reload="onReload" @reload="onReload"
@rename="onRename" /> @rename="onRename" />
<!-- </keep-alive>--> <!-- </keep-alive>-->

View File

@ -81,6 +81,7 @@
"pin_edit": "Pin Editor(Do not close after save)", "pin_edit": "Pin Editor(Do not close after save)",
"unpin_edit": "Cancel Pin", "unpin_edit": "Cancel Pin",
"search": "Search", "search": "Search",
"full_search": "Full Search",
"filter_field": "Filter Field", "filter_field": "Filter Field",
"filter_value": "Filter Value", "filter_value": "Filter Value",
"length": "Length", "length": "Length",

View File

@ -81,6 +81,7 @@
"pin_edit": "固定编辑框(保存后不关闭)", "pin_edit": "固定编辑框(保存后不关闭)",
"unpin_edit": "取消固定", "unpin_edit": "取消固定",
"search": "搜索", "search": "搜索",
"full_search": "全文搜索",
"filter_field": "筛选字段", "filter_field": "筛选字段",
"filter_value": "筛选值", "filter_value": "筛选值",
"length": "长度", "length": "长度",

View File

@ -429,14 +429,15 @@ const useBrowserStore = defineStore('browser', {
* @param {string|number[]} key * @param {string|number[]} key
* @param {string} [decode] * @param {string} [decode]
* @param {string} [format] * @param {string} [format]
* @param {string} [matchPattern]
* @return {Promise<void>} * @return {Promise<void>}
*/ */
async reloadKey({ server, db, key, decode, format }) { async reloadKey({ server, db, key, decode, format, matchPattern }) {
const tab = useTabStore() const tab = useTabStore()
try { try {
tab.updateLoading({ server, db, loading: true }) tab.updateLoading({ server, db, loading: true })
await this.loadKeySummary({ server, db, key }) await this.loadKeySummary({ server, db, key })
await this.loadKeyDetail({ server, db, key, decode, format, reset: true }) await this.loadKeyDetail({ server, db, key, decode, format, matchPattern, reset: true })
} finally { } finally {
tab.updateLoading({ server, db, loading: false }) tab.updateLoading({ server, db, loading: false })
} }
@ -470,7 +471,7 @@ const useBrowserStore = defineStore('browser', {
lite: true, lite: true,
}) })
if (success) { if (success) {
const { value, decode: retDecode, format: retFormat, end } = data const { value, decode: retDecode, format: retFormat, match: retMatch, reset: retReset, end } = data
tab.updateValue({ tab.updateValue({
server, server,
db, db,
@ -478,7 +479,8 @@ const useBrowserStore = defineStore('browser', {
value, value,
decode: retDecode, decode: retDecode,
format: retFormat, format: retFormat,
reset: reset || full === true, reset: retReset,
matchPattern: retMatch || '',
end, end,
}) })
} else { } else {

View File

@ -21,6 +21,7 @@ const useTabStore = defineStore('tab', {
* @property {int} [ttl] ttl of current key * @property {int} [ttl] ttl of current key
* @param {string} [decode] * @param {string} [decode]
* @param {string} [format] * @param {string} [format]
* @param {string} [matchPattern]
* @param {boolean} [end] * @param {boolean} [end]
* @param {boolean} [loading] * @param {boolean} [loading]
*/ */
@ -159,9 +160,10 @@ const useTabStore = defineStore('tab', {
* @param {string} [keyCode] * @param {string} [keyCode]
* @param {number} [size] * @param {number} [size]
* @param {number} [length] * @param {number} [length]
* @param {string} [matchPattern]
* @param {*} [value] * @param {*} [value]
*/ */
upsertTab({ subTab, server, db, type, ttl, key, keyCode, size, length }) { upsertTab({ subTab, server, db, type, ttl, key, keyCode, size, length, matchPattern = '' }) {
let tabIndex = findIndex(this.tabList, { name: server }) let tabIndex = findIndex(this.tabList, { name: server })
if (tabIndex === -1) { if (tabIndex === -1) {
this.tabList.push({ this.tabList.push({
@ -176,6 +178,7 @@ const useTabStore = defineStore('tab', {
keyCode, keyCode,
size, size,
length, length,
matchPattern,
value: undefined, value: undefined,
}) })
tabIndex = this.tabList.length - 1 tabIndex = this.tabList.length - 1
@ -193,6 +196,7 @@ const useTabStore = defineStore('tab', {
tab.keyCode = keyCode tab.keyCode = keyCode
tab.size = size tab.size = size
tab.length = length tab.length = length
tab.matchPattern = matchPattern
tab.value = undefined tab.value = undefined
} }
this._setActivatedIndex(tabIndex, true, subTab) this._setActivatedIndex(tabIndex, true, subTab)
@ -207,29 +211,31 @@ const useTabStore = defineStore('tab', {
* @param {*} value * @param {*} value
* @param {string} [format] * @param {string} [format]
* @param {string] [decode] * @param {string] [decode]
* @param {string} [matchPattern]
* @param {boolean} reset * @param {boolean} reset
* @param {boolean} [end] keep end status if not set * @param {boolean} [end] keep end status if not set
*/ */
updateValue({ server, db, key, value, format, decode, reset, end }) { updateValue({ server, db, key, value, format, decode, matchPattern, reset, end }) {
const tab = find(this.tabList, { name: server, db, key }) const tabData = find(this.tabList, { name: server, db, key })
if (tab == null) { if (tabData == null) {
return return
} }
tab.format = format || tab.format tabData.format = format || tabData.format
tab.decode = decode || tab.decode tabData.decode = decode || tabData.decode
tabData.matchPattern = matchPattern || ''
if (typeof end === 'boolean') { if (typeof end === 'boolean') {
tab.end = end tabData.end = end
} }
if (!reset && typeof value === 'object') { if (!reset && typeof value === 'object') {
if (value instanceof Array) { if (value instanceof Array) {
tab.value = tab.value || [] tabData.value = tabData.value || []
tab.value.push(...value) tabData.value.push(...value)
} else { } else {
tab.value = assign(value, tab.value || {}) tabData.value = assign(value, tabData.value || {})
} }
} else { } else {
tab.value = value tabData.value = value
} }
}, },