/** * Hash key type renderer — exact port of Angular key-hash.component. * Table with hashkey + value, paging, add/delete/edit/copy/json/download per row. */ import { useState, useEffect, useCallback } from 'react' import { Box, Tooltip } from '@mui/material' import { Delete, TableChart, ContentCopy, Download, Edit, Add } from '@mui/icons-material' import { useTheme } from '@mui/material' import { useI18nStore } from '../../../stores/i18n.store' import { useRedisStateStore } from '../../../stores/redis-state.store' import { useCommonStore } from '../../../stores/common.store' import { request } from '../../../stores/socket.service' import { KeyTypeProps, createPaging, Paging, formatValue, truncateDisplay, isTruncated, copyValue, downloadBuffer } from './key-type-base' import KeyPagerInline from './KeyPagerInline' import KeyNewOrSetDialog from '../../../dialogs/KeyNewOrSetDialog' import JsonViewDialog from '../../../dialogs/JsonViewDialog' export default function KeyHash({ response, value, valueBuffer, keyName, valueFormat, onRefresh }: KeyTypeProps) { const strings = useI18nStore(s => s.strings) const connection = useRedisStateStore(s => s.connection) const { toast, confirm, generalHandleError } = useCommonStore() const muiTheme = useTheme() const isReadonly = connection?.readonly === true const isDark = muiTheme.palette.mode === 'dark' const [paging, setPaging] = useState(() => createPaging(value ? Object.keys(value).length : 0)) const [pagedItems, setPagedItems] = useState>([]) const [editDialogOpen, setEditDialogOpen] = useState(false) const [editDialogData, setEditDialogData] = useState(null) const [jsonViewOpen, setJsonViewOpen] = useState(false) const [jsonViewValue, setJsonViewValue] = useState('') useEffect(() => { if (!value) return const keys = Object.keys(value) const p = createPaging(keys.length) setPaging(p) setPagedItems(keys.slice(p.startIndex, p.endIndex).map(k => ({ key: k, value: value[k] }))) }, [value]) const updatePagedItems = useCallback((p: Paging) => { setPaging(p) if (!value) { setPagedItems([]); return } const keys = Object.keys(value) setPagedItems(keys.slice(p.startIndex, p.endIndex).map(k => ({ key: k, value: value[k] }))) }, [value]) const addHash = useCallback(() => { setEditDialogData({ type: 'append', model: { type: 'hash', key: keyName } }) setEditDialogOpen(true) }, [keyName]) const deleteHashKey = useCallback(async (hashKey: string) => { try { await confirm({ message: strings?.confirm?.deleteHashKey ?? strings?.confirm?.areYouSure ?? 'Are you sure?' }) await request({ action: 'key-hash-delete-field', payload: { key: keyName, hashKey } }) toast(strings?.status?.deletedHashKey) onRefresh() } catch (e) { generalHandleError(e) } }, [keyName, strings, confirm, toast, onRefresh, generalHandleError]) const editValue = useCallback((hashKey: string, val: any) => { const editVal = typeof val === 'string' && val.length >= (useRedisStateStore.getState() as any).maxValueAsBuffer ? valueBuffer?.[hashKey] : val setEditDialogData({ type: 'edit', model: { type: 'hash', key: keyName, hashKey, value: editVal } }) setEditDialogOpen(true) }, [keyName, valueBuffer]) const handleEditClose = useCallback((result?: any) => { setEditDialogOpen(false) setEditDialogData(null) if (result) onRefresh() }, [onRefresh]) const hoverBg = isDark ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.1)' const oddBg = isDark ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.04)' const listBorder = isDark ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.06)' const iconSx = (color: string) => ({ fontSize: 18, cursor: 'pointer', mx: '2px', opacity: 0.7, color, '&:hover': { opacity: 1 } }) return ( {strings?.page?.key?.hash?.table?.hashkey ?? 'Hash Key'} {strings?.page?.key?.hash?.table?.value ?? 'Value'} {!isReadonly && ( )} {pagedItems.map((item, i) => ( editValue(item.key, item.value)}>{item.key} editValue(item.key, item.value)}> {formatValue(truncateDisplay(item.value), valueFormat)} {isTruncated(item.value) && ...} {!isReadonly && deleteHashKey(item.key)} />} { setJsonViewValue(String(item.value ?? '')); setJsonViewOpen(true) }} /> copyValue(item.value)} /> downloadBuffer(valueBuffer?.[item.key], keyName, `${keyName}-${item.key}.bin`)} /> {!isReadonly && editValue(item.key, item.value)} />} ))} setJsonViewOpen(false)} /> ) }