import { create } from 'zustand'
import { useI18nStore } from './i18n.store'
import { useRedisStateStore } from './redis-state.store'
import { useSettingsStore } from './settings.store'
import { parseRedisInfo } from './redis-parser'
// --- Event bus for tree commands ---
type VoidCallback = () => void
const treeListeners: Record<string, Set<VoidCallback>> = {}
export function onTreeEvent(event: string, cb: VoidCallback): VoidCallback {
if (!treeListeners[event]) treeListeners[event] = new Set()
treeListeners[event].add(cb)
return () => { treeListeners[event].delete(cb) }
}
export function emitTreeEvent(event: string) {
treeListeners[event]?.forEach(cb => cb())
}
// --- Dialog state ---
interface ConfirmOptions {
title?: string
message: string
disableCancel?: boolean
onOk?: () => void
onCancel?: () => void
}
interface PromptOptions {
title: string
placeholder: string
initialValue?: string
okLabel: string
cancelLabel: string
onOk?: (value: string) => void
onCancel?: () => void
}
interface CommonState {
// Toast
toastMessage: string
toastOpen: boolean
toast: (message: string, hideDelay?: number) => void
closeToast: () => void
// Confirm dialog
confirmOpen: boolean
confirmOptions: ConfirmOptions | null
confirm: (options: ConfirmOptions) => Promise<void>
resolveConfirm: ((ok: boolean) => void) | null
// Prompt dialog
promptOpen: boolean
promptOptions: PromptOptions | null
prompt: (options: PromptOptions) => Promise<string>
resolvePrompt: ((value: string | null) => void) | null
// Error handling
generalHandleError: (dataOrError: any) => boolean
// Redis info loading
loadRedisInfoResponse: (options: { response?: any }) => void
}
let lastResponse: any = null
export const useCommonStore = create<CommonState>((set, get) => ({
toastMessage: '',
toastOpen: false,
toast: (message: string, _hideDelay?: number) => {
set({ toastMessage: message, toastOpen: true })
},
closeToast: () => set({ toastOpen: false }),
confirmOpen: false,
confirmOptions: null,
resolveConfirm: null,
confirm: (options: ConfirmOptions) => {
return new Promise<void>((resolve, reject) => {
const strings = useI18nStore.getState().strings
const isAlert = options.disableCancel === true
set({
confirmOpen: true,
confirmOptions: {
title: options.title || (isAlert ? strings?.confirm?.info : strings?.confirm?.title),
message: options.message,
disableCancel: isAlert,
},
resolveConfirm: (ok: boolean) => {
set({ confirmOpen: false, confirmOptions: null, resolveConfirm: null })
ok ? resolve() : reject()
},
})
})
},
promptOpen: false,
promptOptions: null,
resolvePrompt: null,
prompt: (options: PromptOptions) => {
return new Promise<string>((resolve, reject) => {
set({
promptOpen: true,
promptOptions: options,
resolvePrompt: (value: string | null) => {
set({ promptOpen: false, promptOptions: null, resolvePrompt: null })
value !== null ? resolve(value) : reject()
},
})
})
},
generalHandleError: (dataOrError: any): boolean => {
if (dataOrError === undefined) return true
if (!(dataOrError instanceof Error || dataOrError instanceof Object)) {
dataOrError = new Error(String(dataOrError))
}
if (dataOrError instanceof Error || dataOrError.status === 'error') {
let error: any = dataOrError instanceof Error ? dataOrError : dataOrError.error
console.warn('generalHandleError')
console.error(error)
const strings = useI18nStore.getState().strings
const codes = strings?.code || {}
if (typeof error === 'string' && codes.hasOwnProperty(error)) {
error = new Error(codes[error])
} else if (error?.code && codes.hasOwnProperty(error.code)) {
error.message = codes[error.code]
} else if (error?.message && codes.hasOwnProperty(error.message)) {
error.message = codes[error.message]
}
if (error?.message === 'Connection is closed.') {
useRedisStateStore.setState({ connection: undefined })
}
// Show as alert
get().confirm({
title: strings?.title?.error,
message: error?.message || String(error),
disableCancel: true,
}).catch(() => {})
return false
}
return true
},
loadRedisInfoResponse: (options: { response?: any } = {}) => {
let response = options.response || lastResponse
lastResponse = response
if (!response) return
const settings = useSettingsStore.getState()
const info = parseRedisInfo(response.info)
const keys = settings.keysSort && response.keys.length <= settings.maxLightKeysCount
? [...response.keys].sort()
: response.keys
useRedisStateStore.setState({
info,
keysRaw: keys,
keysInfo: response.keysInfo,
keysInfoFetchedAt: Date.now(),
})
},
}))