diff --git a/packages/web/src/datagrid/DbKeyTableControl.svelte b/packages/web/src/datagrid/DbKeyTableControl.svelte index 22c32f16c..4fe8db978 100644 --- a/packages/web/src/datagrid/DbKeyTableControl.svelte +++ b/packages/web/src/datagrid/DbKeyTableControl.svelte @@ -9,6 +9,8 @@ export let database; export let keyInfo; export let onChangeSelected; + export let modifyRow = null; + export let changeSetRedis = null; let rows = []; let cursor = 0; @@ -73,6 +75,12 @@ onMount(() => { loadNextRows(); }); + + $: displayRows = modifyRow ? rows.map(row => modifyRow(row)) : rows; + $: { + changeSetRedis; + displayRows = modifyRow ? rows.map(row => modifyRow(row)) : rows; + } 0; + } + + export function resetChangeSet() { + changeSetRedis = { changes: [] }; + } let currentRow; $: key = $activeDbKeysStore[`${conid}:${database}`]; let refreshToken = 0; let editedValue = null; + let changeSetRedis: ChangeSetRedis = { changes: [] }; $: changeTab(tabid, tab => ({ ...tab, @@ -113,11 +127,86 @@ }); } + function addOrUpdateChange(change: ChangeSetRedisType) { + const existingIndex = changeSetRedis.changes.findIndex( + c => c.key === change.key && c.type === change.type + ); + + if (existingIndex >= 0) { + changeSetRedis.changes = changeSetRedis.changes.map((c, idx) => + idx === existingIndex ? change : c + ); + } else { + changeSetRedis.changes = [...changeSetRedis.changes, change]; + } + + console.log('ChangeSetRedis updated:', JSON.stringify(changeSetRedis, null, 2)); + } + + function getDisplayRow(row, keyInfo) { + if (!row) return row; + + const existingChange = changeSetRedis.changes.find( + c => c.key === keyInfo.key && c.type === keyInfo.type + ); + + if (!existingChange) return row; + + // Pre hash - skontroluj či existuje update pre tento key + if (keyInfo.type === 'hash') { + // @ts-ignore + const update = existingChange.updates?.find(u => u.key === row.key); + if (update) { + return { ...row, value: update.value }; + } + } else if (keyInfo.type === 'list') { + // @ts-ignore + const update = existingChange.updates?.find(u => u.index === row.rowNumber); + if (update) { + return { ...row, value: update.value }; + } + } else if (keyInfo.type === 'zset') { + // @ts-ignore + const update = existingChange.updates?.find(u => u.member === row.member); + if (update) { + return { ...row, score: update.score }; + } + } + + return row; + } + + function getDisplayValue(keyInfo) { + if (editedValue !== null) return editedValue; + + const existingChange = changeSetRedis.changes.find( + c => c.key === keyInfo.key && c.type === keyInfo.type + ); + + if (existingChange && (keyInfo.type === 'string' || keyInfo.type === 'json')) { + // @ts-ignore + return existingChange.value || keyInfo.value; + } + + return keyInfo.value; + } + function refresh() { editedValue = null; refreshToken += 1; } + async function saveAll() { + console.log('Saving all changes:', changeSetRedis); + await apiCall('database-connections/apply-redis-change-set', { + conid, + database, + changeSet: changeSetRedis, + }); + changeSetRedis = { changes: [] }; + refreshToken += 1; + } + async function saveString() { await apiCall('database-connections/call-method', { conid, @@ -125,13 +214,45 @@ method: 'set', args: [key, editedValue], }); - refresh(); + + editedValue = null; + refreshToken += 1; } async function addItem(keyInfo) { showModal(DbKeyAddItemModal, { keyInfo, onConfirm: async row => { + const existingChange = changeSetRedis.changes.find( + c => c.key === keyInfo.key && c.type === keyInfo.type + ); + + if (keyInfo.type === 'hash') { + // @ts-ignore + const hashChange = existingChange || { key: keyInfo.key, type: 'hash', inserts: [], updates: [], deletes: [] }; + // @ts-ignore + hashChange.inserts = [...(hashChange.inserts || []), { key: row.key, value: row.value, ttl: keyInfo.ttl }]; + addOrUpdateChange(hashChange); + } else if (keyInfo.type === 'list') { + // @ts-ignore + const listChange = existingChange || { key: keyInfo.key, type: 'list', inserts: [], updates: [], deletes: [] }; + // @ts-ignore + listChange.inserts = [...(listChange.inserts || []), { index: row.rowNumber, value: row.value }]; + addOrUpdateChange(listChange); + } else if (keyInfo.type === 'set') { + // @ts-ignore + const setChange = existingChange || { key: keyInfo.key, type: 'set', inserts: [], deletes: [] }; + // @ts-ignore + setChange.inserts = [...(setChange.inserts || []), row.member]; + addOrUpdateChange(setChange); + } else if (keyInfo.type === 'zset') { + // @ts-ignore + const zsetChange = existingChange || { key: keyInfo.key, type: 'zset', inserts: [], updates: [], deletes: [] }; + // @ts-ignore + zsetChange.inserts = [...(zsetChange.inserts || []), { member: row.member, score: row.score }]; + addOrUpdateChange(zsetChange); + } + const res = await apiCall('database-connections/call-method', { conid, database, @@ -142,7 +263,8 @@ showModal(ErrorMessageModal, { message: res.errorMessage }); return false; } - refresh(); + + refreshToken += 1; return true; }, }); @@ -174,9 +296,11 @@ {conid} {database} {keyInfo} + {changeSetRedis} onChangeSelected={row => { currentRow = row; }} + modifyRow={row => getDisplayRow(row, keyInfo)} /> @@ -184,7 +308,53 @@ dbKeyFields={keyInfo.type === 'hash' ? keyInfo.keyType.dbKeyFields.filter(f => f.name === 'value') : keyInfo.keyType.dbKeyFields} - item={currentRow} + item={getDisplayRow(currentRow, keyInfo)} + onChangeItem={item => { + const existingChange = changeSetRedis.changes.find( + c => c.key === keyInfo.key && c.type === keyInfo.type + ); + + if (keyInfo.type === 'hash') { + // @ts-ignore + const hashChange = existingChange || { key: keyInfo.key, type: 'hash', inserts: [], updates: [], deletes: [] }; + // @ts-ignore + const updateIndex = hashChange.updates?.findIndex(u => u.key === item.key) ?? -1; + if (updateIndex >= 0) { + // @ts-ignore + hashChange.updates[updateIndex] = { key: item.key, value: item.value, ttl: keyInfo.ttl }; + } else { + // @ts-ignore + hashChange.updates = [...(hashChange.updates || []), { key: item.key, value: item.value, ttl: keyInfo.ttl }]; + } + addOrUpdateChange(hashChange); + } else if (keyInfo.type === 'list') { + // @ts-ignore + const listChange = existingChange || { key: keyInfo.key, type: 'list', inserts: [], updates: [], deletes: [] }; + // @ts-ignore + const updateIndex = listChange.updates?.findIndex(u => u.index === item.rowNumber) ?? -1; + if (updateIndex >= 0) { + // @ts-ignore + listChange.updates[updateIndex] = { index: item.rowNumber, value: item.value }; + } else { + // @ts-ignore + listChange.updates = [...(listChange.updates || []), { index: item.rowNumber, value: item.value }]; + } + addOrUpdateChange(listChange); + } else if (keyInfo.type === 'zset') { + // @ts-ignore + const zsetChange = existingChange || { key: keyInfo.key, type: 'zset', inserts: [], updates: [], deletes: [] }; + // @ts-ignore + const updateIndex = zsetChange.updates?.findIndex(u => u.member === item.member) ?? -1; + if (updateIndex >= 0) { + // @ts-ignore + zsetChange.updates[updateIndex] = { member: item.member, score: item.score }; + } else { + // @ts-ignore + zsetChange.updates = [...(zsetChange.updates || []), { member: item.member, score: item.score }]; + } + addOrUpdateChange(zsetChange); + } + }} /> @@ -192,10 +362,24 @@
{ editedValue = value; + + if (keyInfo.type === 'string') { + addOrUpdateChange({ + key: key, + type: 'string', + value: value, + }); + } else if (keyInfo.type === 'json') { + addOrUpdateChange({ + key: key, + type: 'json', + value: value, + }); + } }} />
@@ -204,6 +388,11 @@ + Save All Changes {#if keyInfo.type == 'string'}