Refactor DbKeyTab to integrate new DbKeyValue components for improved Redis data type handling

This commit is contained in:
Stela Augustinova
2025-12-18 16:05:48 +01:00
parent f9c47ab233
commit 6905e4a2a1
6 changed files with 533 additions and 10 deletions

View File

@@ -28,6 +28,9 @@
.props { .props {
flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: row;
gap: 10px;
padding: 10px;
overflow: hidden;
} }
</style> </style>

View File

@@ -0,0 +1,97 @@
<script lang="ts">
import _ from 'lodash';
import TextField from '../forms/TextField.svelte';
import FormFieldTemplateLarge from '../forms/FormFieldTemplateLarge.svelte';
import FontIcon from '../icons/FontIcon.svelte';
export let dbKeyFields;
export let item;
export let onChangeItem = null;
export let keyColumn = null;
let records = [{ value: '' }];
$: console.log('DbKeyValueListEdit', { item, dbKeyFields, keyColumn, onChangeItem: !!onChangeItem });
function handleFieldChange(index, fieldName, value) {
records = records.map((record, idx) =>
idx === index ? { ...record, [fieldName]: value } : record
);
if (onChangeItem && fieldName !== keyColumn) {
onChangeItem?.({
...item,
records: records,
});
}
}
function addRecord() {
records = [...records, { value: '' }];
}
</script>
<div class="container">
{#each records as record, index}
<div class="props flex">
<div class="field-wrapper col-12">
<FormFieldTemplateLarge label="Value" type="text" noMargin>
<TextField
value={record.value}
on:change={e => handleFieldChange(index, 'value', e.target.value)}
disabled={keyColumn === 'value'}
/>
</FormFieldTemplateLarge>
</div>
</div>
{/each}
<div class="add-button-wrapper">
<button class="add-button" on:click={addRecord}>
<FontIcon icon="icon add" />
</button>
</div>
</div>
<style>
.container {
flex: 1;
display: flex;
flex-direction: column;
gap: 10px;
overflow-y: auto;
}
.props {
display: flex;
flex-direction: row;
gap: 10px;
}
.field-wrapper {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
}
.add-button-wrapper {
display: flex;
justify-content: flex-end;
margin-top: 10px;
}
.add-button {
background: none;
border: none;
padding: 0;
cursor: pointer;
color: var(--theme-font-3);
transition: color 0.2s;
font-size: 24px;
}
.add-button:hover {
color: var(--theme-font-hover);
}
</style>

View File

@@ -0,0 +1,97 @@
<script lang="ts">
import _ from 'lodash';
import TextField from '../forms/TextField.svelte';
import FormFieldTemplateLarge from '../forms/FormFieldTemplateLarge.svelte';
import FontIcon from '../icons/FontIcon.svelte';
export let dbKeyFields;
export let item;
export let onChangeItem = null;
export let keyColumn = null;
let records = [{ value: '' }];
$: console.log('DbKeyValueSetEdit', { item, dbKeyFields, keyColumn, onChangeItem: !!onChangeItem });
function handleFieldChange(index, fieldName, value) {
records = records.map((record, idx) =>
idx === index ? { ...record, [fieldName]: value } : record
);
if (onChangeItem && fieldName !== keyColumn) {
onChangeItem?.({
...item,
records: records,
});
}
}
function addRecord() {
records = [...records, { value: '' }];
}
</script>
<div class="container">
{#each records as record, index}
<div class="props flex">
<div class="field-wrapper col-12">
<FormFieldTemplateLarge label="Value" type="text" noMargin>
<TextField
value={record.value}
on:change={e => handleFieldChange(index, 'value', e.target.value)}
disabled={keyColumn === 'value'}
/>
</FormFieldTemplateLarge>
</div>
</div>
{/each}
<div class="add-button-wrapper">
<button class="add-button" on:click={addRecord}>
<FontIcon icon="icon add" />
</button>
</div>
</div>
<style>
.container {
flex: 1;
display: flex;
flex-direction: column;
gap: 10px;
overflow-y: auto;
}
.props {
display: flex;
flex-direction: row;
gap: 10px;
}
.field-wrapper {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
}
.add-button-wrapper {
display: flex;
justify-content: flex-end;
margin-top: 10px;
}
.add-button {
background: none;
border: none;
padding: 0;
cursor: pointer;
color: var(--theme-font-3);
transition: color 0.2s;
font-size: 24px;
}
.add-button:hover {
color: var(--theme-font-hover);
}
</style>

View File

@@ -0,0 +1,112 @@
<script lang="ts">
import _ from 'lodash';
import TextField from '../forms/TextField.svelte';
import FormFieldTemplateLarge from '../forms/FormFieldTemplateLarge.svelte';
import FontIcon from '../icons/FontIcon.svelte';
export let dbKeyFields;
export let item;
export let onChangeItem = null;
export let keyColumn = null;
let records = [{ id: '', value: '' }];
$: console.log('DbKeyValueStreamEdit', { item, dbKeyFields, keyColumn, onChangeItem: !!onChangeItem });
function getValueAsString(value) {
if (value === null || value === undefined) return '';
if (typeof value === 'string') return value;
if (typeof value === 'number') return String(value);
return JSON.stringify(value);
}
function handleFieldChange(index, fieldName, value) {
records = records.map((record, idx) => (idx === index ? { ...record, [fieldName]: value } : record));
if (onChangeItem && fieldName !== keyColumn) {
onChangeItem?.({
...item,
records: records,
});
}
}
function addRecord() {
records = [...records, { id: '', value: '' }];
}
</script>
<div class="container">
{#each records as record, index}
<div class="props flex">
<div class="field-wrapper col-3">
<FormFieldTemplateLarge label="ID" type="text" noMargin>
<TextField
value={record.id}
on:change={e => handleFieldChange(index, 'id', e.target.value)}
disabled={keyColumn === 'id'}
placeholder="* for auto"
/>
</FormFieldTemplateLarge>
</div>
<div class="field-wrapper col-9">
<FormFieldTemplateLarge label="Value" type="text" noMargin>
<TextField
value={record.value}
on:change={e => handleFieldChange(index, 'value', e.target.value)}
disabled={keyColumn === 'value'}
/>
</FormFieldTemplateLarge>
</div>
</div>
{/each}
<div class="add-button-wrapper">
<button class="add-button" on:click={addRecord}>
<FontIcon icon="icon add" />
</button>
</div>
</div>
<style>
.container {
flex: 1;
display: flex;
flex-direction: column;
gap: 10px;
overflow-y: auto;
}
.props {
display: flex;
flex-direction: row;
gap: 10px;
}
.field-wrapper {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
}
.add-button-wrapper {
display: flex;
justify-content: flex-end;
margin-top: 10px;
}
.add-button {
background: none;
border: none;
padding: 0;
cursor: pointer;
color: var(--theme-font-3);
transition: color 0.2s;
font-size: 24px;
}
.add-button:hover {
color: var(--theme-font-hover);
}
</style>

View File

@@ -0,0 +1,111 @@
<script lang="ts">
import _ from 'lodash';
import TextField from '../forms/TextField.svelte';
import FormFieldTemplateLarge from '../forms/FormFieldTemplateLarge.svelte';
import FontIcon from '../icons/FontIcon.svelte';
export let dbKeyFields;
export let item;
export let onChangeItem = null;
export let keyColumn = null;
let records = [{ member: '', score: '' }];
$: console.log('DbKeyValueZSetEdit', { item, dbKeyFields, keyColumn, onChangeItem: !!onChangeItem });
function getValueAsString(value) {
if (value === null || value === undefined) return '';
if (typeof value === 'string') return value;
if (typeof value === 'number') return String(value);
return JSON.stringify(value);
}
function handleFieldChange(index, fieldName, value) {
records = records.map((record, idx) => (idx === index ? { ...record, [fieldName]: value } : record));
if (onChangeItem && fieldName !== keyColumn) {
onChangeItem?.({
...item,
records: records,
});
}
}
function addRecord() {
records = [...records, { member: '', score: '' }];
}
</script>
<div class="container">
{#each records as record, index}
<div class="props flex">
<div class="field-wrapper col-8">
<FormFieldTemplateLarge label="Member" type="text" noMargin>
<TextField
value={record.member}
on:change={e => handleFieldChange(index, 'member', e.target.value)}
disabled={keyColumn === 'member'}
/>
</FormFieldTemplateLarge>
</div>
<div class="field-wrapper col-4">
<FormFieldTemplateLarge label="Score" type="text" noMargin>
<TextField
value={record.score}
on:change={e => handleFieldChange(index, 'score', e.target.value)}
disabled={keyColumn === 'score'}
/>
</FormFieldTemplateLarge>
</div>
</div>
{/each}
<div class="add-button-wrapper">
<button class="add-button" on:click={addRecord}>
<FontIcon icon="icon add" />
</button>
</div>
</div>
<style>
.container {
flex: 1;
display: flex;
flex-direction: column;
gap: 10px;
overflow-y: auto;
}
.props {
display: flex;
flex-direction: row;
gap: 10px;
}
.field-wrapper {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
}
.add-button-wrapper {
display: flex;
justify-content: flex-end;
margin-top: 10px;
}
.add-button {
background: none;
border: none;
padding: 0;
cursor: pointer;
color: var(--theme-font-3);
transition: color 0.2s;
font-size: 24px;
}
.add-button:hover {
color: var(--theme-font-hover);
}
</style>

View File

@@ -1,6 +1,10 @@
<script lang="ts"> <script lang="ts">
import DbKeyItemDetail from '../dbkeyvalue/DbKeyItemDetail.svelte'; import DbKeyValueDetail from '../dbkeyvalue/DbKeyValueDetail.svelte';
import DbKeyValueHashEdit from '../dbkeyvalue/DbKeyValueHashEdit.svelte'; import DbKeyValueHashEdit from '../dbkeyvalue/DbKeyValueHashEdit.svelte';
import DbKeyValueListEdit from '../dbkeyvalue/DbKeyValueListEdit.svelte';
import DbKeyValueSetEdit from '../dbkeyvalue/DbKeyValueSetEdit.svelte';
import DbKeyValueZSetEdit from '../dbkeyvalue/DbKeyValueZSetEdit.svelte';
import DbKeyValueStreamEdit from '../dbkeyvalue/DbKeyValueStreamEdit.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';
import SelectField from '../forms/SelectField.svelte'; import SelectField from '../forms/SelectField.svelte';
@@ -33,12 +37,79 @@
const typeConfig = driver.supportedKeyTypes.find(x => x.name == type); const typeConfig = driver.supportedKeyTypes.find(x => x.name == type);
await apiCall('database-connections/call-method', { if (type === 'hash' && item.records && Array.isArray(item.records)) {
conid, for (const record of item.records) {
database, if (record.key && record.value) {
method: typeConfig.addMethod, await apiCall('database-connections/call-method', {
args: [keyName, ...typeConfig.dbKeyFields.map(fld => item[fld.name])], conid,
}); database,
method: typeConfig.addMethod,
args: [keyName, record.key, record.value],
});
}
}
} else if (type === 'list' && item.records && Array.isArray(item.records)) {
const values = item.records
.map(record => record.value)
.filter(value => value);
if (values.length > 0) {
await apiCall('database-connections/call-method', {
conid,
database,
method: typeConfig.addMethod,
args: [keyName, ...values],
});
}
} else if (type === 'set' && item.records && Array.isArray(item.records)) {
const values = item.records
.map(record => record.value)
.filter(value => value);
if (values.length > 0) {
await apiCall('database-connections/call-method', {
conid,
database,
method: typeConfig.addMethod,
args: [keyName, ...values],
});
}
} else if (type === 'zset' && item.records && Array.isArray(item.records)) {
const pairs = [];
item.records.forEach(record => {
if (record.member && record.score) {
pairs.push(record.score, record.member);
}
});
if (pairs.length > 0) {
await apiCall('database-connections/call-method', {
conid,
database,
method: typeConfig.addMethod,
args: [keyName, ...pairs],
});
}
} else if (type === 'stream' && item.records && Array.isArray(item.records)) {
for (const record of item.records) {
if (record.value) {
const streamId = record.id || '*';
await apiCall('database-connections/call-method', {
conid,
database,
method: typeConfig.addMethod,
args: [keyName, streamId, record.value],
});
}
}
} else {
await apiCall('database-connections/call-method', {
conid,
database,
method: typeConfig.addMethod,
args: [keyName, ...typeConfig.dbKeyFields.map(fld => item[fld.name])],
});
}
showSnackbarSuccess('Key created successfully'); showSnackbarSuccess('Key created successfully');
@@ -107,14 +178,46 @@
item = value; item = value;
}} }}
/> />
{:else} {:else if type === 'list'}
<DbKeyItemDetail <DbKeyValueListEdit
dbKeyFields={driver.supportedKeyTypes.find(x => x.name == type).dbKeyFields} dbKeyFields={driver.supportedKeyTypes.find(x => x.name == type).dbKeyFields}
{item} {item}
onChangeItem={value => { onChangeItem={value => {
item = value; item = value;
}} }}
/> />
{:else if type === 'set'}
<DbKeyValueSetEdit
dbKeyFields={driver.supportedKeyTypes.find(x => x.name == type).dbKeyFields}
{item}
onChangeItem={value => {
item = value;
}}
/>
{:else if type === 'zset'}
<DbKeyValueZSetEdit
dbKeyFields={driver.supportedKeyTypes.find(x => x.name == type).dbKeyFields}
{item}
onChangeItem={value => {
item = value;
}}
/>
{:else if type === 'stream'}
<DbKeyValueStreamEdit
dbKeyFields={driver.supportedKeyTypes.find(x => x.name == type).dbKeyFields}
{item}
onChangeItem={value => {
item = value;
}}
/>
{:else}
<DbKeyValueDetail
columnTitle="Value"
value={item.value}
onChangeValue={value => {
item = { ...item, value };
}}
/>
{/if} {/if}
<div class="m-3" /> <div class="m-3" />