Added delete functionality for list, hash, set, zset and stream fields.

This commit is contained in:
Stela Augustinova
2025-12-23 09:05:04 +01:00
parent 7ff84a9932
commit 4c12ee3b14
10 changed files with 239 additions and 24 deletions

View File

@@ -10,7 +10,7 @@
<div class="props"> <div class="props">
{#each dbKeyFields as column} {#each dbKeyFields as column}
<DbKeyValueDetail <DbKeyValueDetail
value={item && item[column.name]} value={item && item[column.name] != null ? String(item[column.name]) : ''}
columnTitle={_.startCase(column.name)} columnTitle={_.startCase(column.name)}
onChangeValue={onChangeItem && !column.readOnly onChangeValue={onChangeItem && !column.readOnly
? value => { ? value => {

View File

@@ -39,8 +39,6 @@
<style> <style>
.props { .props {
flex: 1; flex: 1;
display: flex;
flex-direction: row;
gap: 10px; gap: 10px;
padding: 10px; padding: 10px;
overflow: hidden; overflow: hidden;
@@ -49,8 +47,6 @@
.field-wrapper { .field-wrapper {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
display: flex;
flex-direction: column;
overflow: hidden; overflow: hidden;
max-height: 100px; max-height: 100px;
} }

View File

@@ -34,7 +34,7 @@
<div class="editor-wrapper"> <div class="editor-wrapper">
<AceEditor <AceEditor
readOnly={!onChangeValue} readOnly={!onChangeValue}
{value} value={value != null ? String(value) : ''}
mode={keyType === 'JSON' ? 'json' : undefined} mode={keyType === 'JSON' ? 'json' : undefined}
on:input={e => { on:input={e => {
onChangeValue?.(e.detail); onChangeValue?.(e.detail);

View File

@@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import _ from 'lodash'; import _ from 'lodash';
import { onMount } from 'svelte';
import TextField from '../forms/TextField.svelte'; import TextField from '../forms/TextField.svelte';
import FormFieldTemplateLarge from '../forms/FormFieldTemplateLarge.svelte'; import FormFieldTemplateLarge from '../forms/FormFieldTemplateLarge.svelte';
import FontIcon from '../icons/FontIcon.svelte'; import FontIcon from '../icons/FontIcon.svelte';
@@ -10,6 +11,16 @@
export let keyColumn = null; export let keyColumn = null;
let records = [{ key: '', value: '', ttl: '' }]; let records = [{ key: '', value: '', ttl: '' }];
let lastItem = null;
$: if (item !== lastItem) {
if (item?.records && Array.isArray(item.records)) {
records = [...item.records];
} else if (!item) {
records = [{ key: '', value: '', ttl: '' }];
}
lastItem = item;
}
$: console.log('DbKeyItemEdit', { item, dbKeyFields, keyColumn, onChangeItem: !!onChangeItem }); $: console.log('DbKeyItemEdit', { item, dbKeyFields, keyColumn, onChangeItem: !!onChangeItem });
@@ -50,7 +61,7 @@
/> />
</FormFieldTemplateLarge> </FormFieldTemplateLarge>
</div> </div>
<div class="field-wrapper col-7"> <div class="field-wrapper col-6">
<FormFieldTemplateLarge label="Value" type="text" noMargin> <FormFieldTemplateLarge label="Value" type="text" noMargin>
<TextField <TextField
value={record.value} value={record.value}
@@ -68,6 +79,13 @@
/> />
</FormFieldTemplateLarge> </FormFieldTemplateLarge>
</div> </div>
<div class="delete-wrapper col-1">
<button class="delete-button" on:click={() => {
records = records.filter((_, idx) => idx !== index);
}}>
<FontIcon icon="icon delete" />
</button>
</div>
</div> </div>
{/each} {/each}
@@ -91,6 +109,7 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
gap: 10px; gap: 10px;
align-items: center;
} }
.field-wrapper { .field-wrapper {
@@ -100,6 +119,27 @@
flex-direction: column; flex-direction: column;
} }
.delete-wrapper {
display: flex;
align-items: center;
justify-content: center;
margin-top: 10px;
}
.delete-button {
background: none;
border: none;
padding: 0;
cursor: pointer;
color: var(--theme-font-3);
transition: color 0.2s;
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
margin-top: 10px;
}
.add-button-wrapper { .add-button-wrapper {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;

View File

@@ -10,6 +10,16 @@
export let keyColumn = null; export let keyColumn = null;
let records = [{ value: '' }]; let records = [{ value: '' }];
let lastItem = null;
$: if (item !== lastItem) {
if (item?.records && Array.isArray(item.records)) {
records = [...item.records];
} else if (!item) {
records = [{ value: '' }];
}
lastItem = item;
}
$: console.log('DbKeyValueListEdit', { item, dbKeyFields, keyColumn, onChangeItem: !!onChangeItem }); $: console.log('DbKeyValueListEdit', { item, dbKeyFields, keyColumn, onChangeItem: !!onChangeItem });
@@ -34,7 +44,7 @@
<div class="container"> <div class="container">
{#each records as record, index} {#each records as record, index}
<div class="props flex"> <div class="props flex">
<div class="field-wrapper col-12"> <div class="field-wrapper col-11">
<FormFieldTemplateLarge label="Value" type="text" noMargin> <FormFieldTemplateLarge label="Value" type="text" noMargin>
<TextField <TextField
value={record.value} value={record.value}
@@ -43,6 +53,13 @@
/> />
</FormFieldTemplateLarge> </FormFieldTemplateLarge>
</div> </div>
<div class="delete-wrapper col-1">
<button class="delete-button" on:click={() => {
records = records.filter((_, idx) => idx !== index);
}}>
<FontIcon icon="icon delete" />
</button>
</div>
</div> </div>
{/each} {/each}
@@ -75,6 +92,31 @@
flex-direction: column; flex-direction: column;
} }
.delete-wrapper {
display: flex;
align-items: center;
justify-content: center;
margin-top: 10px;
}
.delete-button {
background: none;
border: none;
padding: 0;
cursor: pointer;
color: var(--theme-font-3);
transition: color 0.2s;
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
margin-top: 10px;
}
.delete-button:hover {
color: var(--theme-font-hover);
}
.add-button-wrapper { .add-button-wrapper {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;

View File

@@ -10,6 +10,16 @@
export let keyColumn = null; export let keyColumn = null;
let records = [{ value: '' }]; let records = [{ value: '' }];
let lastItem = null;
$: if (item !== lastItem) {
if (item?.records && Array.isArray(item.records)) {
records = [...item.records];
} else if (!item) {
records = [{ value: '' }];
}
lastItem = item;
}
$: console.log('DbKeyValueSetEdit', { item, dbKeyFields, keyColumn, onChangeItem: !!onChangeItem }); $: console.log('DbKeyValueSetEdit', { item, dbKeyFields, keyColumn, onChangeItem: !!onChangeItem });
@@ -34,7 +44,7 @@
<div class="container"> <div class="container">
{#each records as record, index} {#each records as record, index}
<div class="props flex"> <div class="props flex">
<div class="field-wrapper col-12"> <div class="field-wrapper col-11">
<FormFieldTemplateLarge label="Value" type="text" noMargin> <FormFieldTemplateLarge label="Value" type="text" noMargin>
<TextField <TextField
value={record.value} value={record.value}
@@ -43,6 +53,13 @@
/> />
</FormFieldTemplateLarge> </FormFieldTemplateLarge>
</div> </div>
<div class="delete-wrapper col-1">
<button class="delete-button" on:click={() => {
records = records.filter((_, idx) => idx !== index);
}}>
<FontIcon icon="icon delete" />
</button>
</div>
</div> </div>
{/each} {/each}
@@ -75,6 +92,31 @@
flex-direction: column; flex-direction: column;
} }
.delete-wrapper {
display: flex;
align-items: center;
justify-content: center;
margin-top: 10px;
}
.delete-button {
background: none;
border: none;
padding: 0;
cursor: pointer;
color: var(--theme-font-3);
transition: color 0.2s;
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
margin-top: 10px;
}
.delete-button:hover {
color: var(--theme-font-hover);
}
.add-button-wrapper { .add-button-wrapper {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;

View File

@@ -10,6 +10,16 @@
export let keyColumn = null; export let keyColumn = null;
let records = [{ id: '', value: '' }]; let records = [{ id: '', value: '' }];
let lastItem = null;
$: if (item !== lastItem) {
if (item?.records && Array.isArray(item.records)) {
records = [...item.records];
} else if (!item) {
records = [{ id: '', value: '' }];
}
lastItem = item;
}
$: console.log('DbKeyValueStreamEdit', { item, dbKeyFields, keyColumn, onChangeItem: !!onChangeItem }); $: console.log('DbKeyValueStreamEdit', { item, dbKeyFields, keyColumn, onChangeItem: !!onChangeItem });
@@ -49,7 +59,7 @@
/> />
</FormFieldTemplateLarge> </FormFieldTemplateLarge>
</div> </div>
<div class="field-wrapper col-9"> <div class="field-wrapper col-8">
<FormFieldTemplateLarge label="Value" type="text" noMargin> <FormFieldTemplateLarge label="Value" type="text" noMargin>
<TextField <TextField
value={record.value} value={record.value}
@@ -58,6 +68,13 @@
/> />
</FormFieldTemplateLarge> </FormFieldTemplateLarge>
</div> </div>
<div class="delete-wrapper col-1">
<button class="delete-button" on:click={() => {
records = records.filter((_, idx) => idx !== index);
}}>
<FontIcon icon="icon delete" />
</button>
</div>
</div> </div>
{/each} {/each}
@@ -90,6 +107,31 @@
flex-direction: column; flex-direction: column;
} }
.delete-wrapper {
display: flex;
align-items: center;
justify-content: center;
margin-top: 10px;
}
.delete-button {
background: none;
border: none;
padding: 0;
cursor: pointer;
color: var(--theme-font-3);
transition: color 0.2s;
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
margin-top: 10px;
}
.delete-button:hover {
color: var(--theme-font-hover);
}
.add-button-wrapper { .add-button-wrapper {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;

View File

@@ -10,6 +10,16 @@
export let keyColumn = null; export let keyColumn = null;
let records = [{ member: '', score: '' }]; let records = [{ member: '', score: '' }];
let lastItem = null;
$: if (item !== lastItem) {
if (item?.records && Array.isArray(item.records)) {
records = [...item.records];
} else if (!item) {
records = [{ member: '', score: '' }];
}
lastItem = item;
}
$: console.log('DbKeyValueZSetEdit', { item, dbKeyFields, keyColumn, onChangeItem: !!onChangeItem }); $: console.log('DbKeyValueZSetEdit', { item, dbKeyFields, keyColumn, onChangeItem: !!onChangeItem });
@@ -39,7 +49,7 @@
<div class="container"> <div class="container">
{#each records as record, index} {#each records as record, index}
<div class="props flex"> <div class="props flex">
<div class="field-wrapper col-8"> <div class="field-wrapper col-7">
<FormFieldTemplateLarge label="Member" type="text" noMargin> <FormFieldTemplateLarge label="Member" type="text" noMargin>
<TextField <TextField
value={record.member} value={record.member}
@@ -57,6 +67,13 @@
/> />
</FormFieldTemplateLarge> </FormFieldTemplateLarge>
</div> </div>
<div class="delete-wrapper col-1">
<button class="delete-button" on:click={() => {
records = records.filter((_, idx) => idx !== index);
}}>
<FontIcon icon="icon delete" />
</button>
</div>
</div> </div>
{/each} {/each}
@@ -89,6 +106,31 @@
flex-direction: column; flex-direction: column;
} }
.delete-wrapper {
display: flex;
align-items: center;
justify-content: center;
margin-top: 10px;
}
.delete-button {
background: none;
border: none;
padding: 0;
cursor: pointer;
color: var(--theme-font-3);
transition: color 0.2s;
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
margin-top: 10px;
}
.delete-button:hover {
color: var(--theme-font-hover);
}
.add-button-wrapper { .add-button-wrapper {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;

View File

@@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import FormStyledButton from '../buttons/FormStyledButton.svelte'; import FormStyledButton from '../buttons/FormStyledButton.svelte';
import DbKeyItemDetail from '../dbkeyvalue/DbKeyItemDetail.svelte'; import DbKeyItemDetail from '../dbkeyvalue/DbKeyItemDetail.svelte';
import DbKeyValueHashEdit from '../dbkeyvalue/DbKeyValueHashEdit.svelte';
import FormFieldTemplateLarge from '../forms/FormFieldTemplateLarge.svelte'; import FormFieldTemplateLarge from '../forms/FormFieldTemplateLarge.svelte';
import FormProvider from '../forms/FormProvider.svelte'; import FormProvider from '../forms/FormProvider.svelte';
@@ -53,13 +54,23 @@
/> />
</FormFieldTemplateLarge> </FormFieldTemplateLarge>
<DbKeyItemDetail {#if type === 'hash'}
dbKeyFields={driver.supportedKeyTypes.find(x => x.name == type).dbKeyFields} <DbKeyValueHashEdit
{item} dbKeyFields={driver.supportedKeyTypes.find(x => x.name == type).dbKeyFields}
onChangeItem={value => { {item}
item = value; onChangeItem={value => {
}} item = value;
/> }}
/>
{:else}
<DbKeyItemDetail
dbKeyFields={driver.supportedKeyTypes.find(x => x.name == type).dbKeyFields}
{item}
onChangeItem={value => {
item = value;
}}
/>
{/if}
</div> </div>
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">

View File

@@ -165,7 +165,7 @@
// @ts-ignore // @ts-ignore
const update = existingChange.updates?.find(u => u.key === row.key); const update = existingChange.updates?.find(u => u.key === row.key);
if (update) { if (update) {
return { ...row, value: update.value }; return { ...row, value: update.value, TTL: update.ttl !== undefined ? update.ttl : row.TTL };
} }
} else if (keyInfo.type === 'list') { } else if (keyInfo.type === 'list') {
// @ts-ignore // @ts-ignore
@@ -189,7 +189,7 @@
c => c.key === keyInfo.key && c.type === keyInfo.type c => c.key === keyInfo.key && c.type === keyInfo.type
); );
if (existingChange && (keyInfo.type === 'string' || keyInfo.type === 'json')) { if (existingChange && (keyInfo.type === 'string' || keyInfo.type === 'JSON')) {
// @ts-ignore // @ts-ignore
return existingChange.value || keyInfo.value; return existingChange.value || keyInfo.value;
} }
@@ -316,10 +316,10 @@
const updateIndex = hashChange.updates?.findIndex(u => u.key === item.key) ?? -1; const updateIndex = hashChange.updates?.findIndex(u => u.key === item.key) ?? -1;
if (updateIndex >= 0) { if (updateIndex >= 0) {
// @ts-ignore // @ts-ignore
hashChange.updates[updateIndex] = { key: item.key, value: item.value, ttl: keyInfo.ttl }; hashChange.updates[updateIndex] = { key: item.key, value: item.value, ttl: item.TTL };
} else { } else {
// @ts-ignore // @ts-ignore
hashChange.updates = [...(hashChange.updates || []), { key: item.key, value: item.value, ttl: keyInfo.ttl }]; hashChange.updates = [...(hashChange.updates || []), { key: item.key, value: item.value, ttl: item.TTL }];
} }
addOrUpdateChange(hashChange); addOrUpdateChange(hashChange);
} else if (keyInfo.type === 'list') { } else if (keyInfo.type === 'list') {
@@ -367,7 +367,7 @@
type: 'string', type: 'string',
value: value, value: value,
}); });
} else if (keyInfo.type === 'json') { } else if (keyInfo.type === 'JSON') {
addOrUpdateChange({ addOrUpdateChange({
key: key, key: key,
type: 'json', type: 'json',
@@ -388,7 +388,7 @@
disabled={!hasChanges} disabled={!hasChanges}
>{_t('common.save', { defaultMessage: 'Save' })}</ToolStripButton> >{_t('common.save', { defaultMessage: 'Save' })}</ToolStripButton>
{#if keyInfo.keyType?.addMethod && keyInfo.keyType?.showItemList} {#if keyInfo.keyType?.addMethod && keyInfo.keyType?.showItemList}
<ToolStripButton icon="icon add" on:click={() => addItem(keyInfo)}>Add field</ToolStripButton> <ToolStripButton icon="icon add" on:click={() => { showAddForm = true; }}>Add field</ToolStripButton>
{/if} {/if}
<ToolStripButton icon="icon refresh" on:click={refresh}>{_t('common.refresh', { defaultMessage: 'Refresh' })}</ToolStripButton> <ToolStripButton icon="icon refresh" on:click={refresh}>{_t('common.refresh', { defaultMessage: 'Refresh' })}</ToolStripButton>
</svelte:fragment> </svelte:fragment>