fix(webui): Notes aren't duplicated (manifested as unreliable saving)
also rework semantics of `WidgetChange`
This commit is contained in:
parent
f1b608f824
commit
9d6ebfc31c
4 changed files with 64 additions and 79 deletions
|
@ -233,40 +233,42 @@
|
||||||
|
|
||||||
async function onChange(ev: CustomEvent<WidgetChange>) {
|
async function onChange(ev: CustomEvent<WidgetChange>) {
|
||||||
dbg('onChange', ev.detail);
|
dbg('onChange', ev.detail);
|
||||||
const change = ev.detail;
|
const changes = Array.isArray(ev.detail) ? ev.detail : [ev.detail];
|
||||||
switch (change.type) {
|
for (const change of changes) {
|
||||||
case 'create':
|
switch (change.type) {
|
||||||
await api.putEntry({
|
case 'create':
|
||||||
entity: address,
|
await api.putEntry({
|
||||||
attribute: change.attribute,
|
entity: address,
|
||||||
value: change.value
|
attribute: change.attribute,
|
||||||
});
|
value: change.value
|
||||||
break;
|
});
|
||||||
case 'delete':
|
break;
|
||||||
await api.deleteEntry(change.address);
|
case 'delete':
|
||||||
break;
|
await api.deleteEntry(change.address);
|
||||||
case 'update':
|
break;
|
||||||
await api.putEntityAttribute(address, change.attribute, change.value);
|
case 'upsert':
|
||||||
break;
|
await api.putEntityAttribute(address, change.attribute, change.value);
|
||||||
case 'entry-add':
|
break;
|
||||||
await api.putEntry({
|
case 'entry-add':
|
||||||
entity: change.address,
|
await api.putEntry({
|
||||||
attribute: ATTR_IN,
|
entity: change.address,
|
||||||
value: { t: 'Address', c: address }
|
attribute: ATTR_IN,
|
||||||
});
|
value: { t: 'Address', c: address }
|
||||||
break;
|
});
|
||||||
case 'entry-delete': {
|
break;
|
||||||
const inEntry = $entity?.attr[`~${ATTR_IN}`]?.find((e) => e.entity === change.address);
|
case 'entry-delete': {
|
||||||
if (inEntry) {
|
const inEntry = $entity?.attr[`~${ATTR_IN}`]?.find((e) => e.entity === change.address);
|
||||||
await api.deleteEntry(inEntry.address);
|
if (inEntry) {
|
||||||
} else {
|
await api.deleteEntry(inEntry.address);
|
||||||
console.warn("Couldn't find IN entry for entity %s?!", change.address);
|
} else {
|
||||||
|
console.warn("Couldn't find IN entry for entity %s?!", change.address);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
default:
|
||||||
|
console.error('Unimplemented AttributeChange', change);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
console.error('Unimplemented AttributeChange', change);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
revalidate();
|
revalidate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,45 +2,24 @@
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import { useEntity } from '$lib/entity';
|
import { useEntity } from '$lib/entity';
|
||||||
import type { AttributeCreate, AttributeUpdate } from '$lib/types/base';
|
import type { WidgetChange } from '$lib/types/base';
|
||||||
import type { UpEntry } from '@upnd/upend';
|
|
||||||
import LabelBorder from './LabelBorder.svelte';
|
import LabelBorder from './LabelBorder.svelte';
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher<{ change: WidgetChange }>();
|
||||||
|
|
||||||
export let address: string;
|
export let address: string;
|
||||||
|
|
||||||
$: ({ entity } = useEntity(address));
|
$: ({ entity } = useEntity(address));
|
||||||
|
|
||||||
let noteEntry: UpEntry | undefined;
|
$: notes = $entity?.get('NOTE')?.toString();
|
||||||
let notes: string | undefined = undefined;
|
|
||||||
$: {
|
|
||||||
if ($entity?.attr['NOTE']?.length && $entity?.attr['NOTE'][0]?.value?.c) {
|
|
||||||
noteEntry = $entity?.attr['NOTE'][0];
|
|
||||||
notes = String(noteEntry.value.c);
|
|
||||||
} else {
|
|
||||||
noteEntry = undefined;
|
|
||||||
notes = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let contentEl: HTMLDivElement;
|
let contentEl: HTMLDivElement;
|
||||||
|
|
||||||
const update = debounce(() => {
|
const update = debounce(() => {
|
||||||
if (noteEntry) {
|
dispatch('change', {
|
||||||
dispatch('change', {
|
type: 'upsert',
|
||||||
type: 'update',
|
attribute: 'NOTE',
|
||||||
address: noteEntry.address,
|
value: { t: 'String', c: contentEl.innerText }
|
||||||
attribute: 'NOTE',
|
});
|
||||||
value: { t: 'String', c: contentEl.innerText }
|
|
||||||
} as AttributeUpdate);
|
|
||||||
} else {
|
|
||||||
dispatch('change', {
|
|
||||||
type: 'create',
|
|
||||||
address: address,
|
|
||||||
attribute: 'NOTE',
|
|
||||||
value: { t: 'String', c: contentEl.innerText }
|
|
||||||
} as AttributeCreate);
|
|
||||||
}
|
|
||||||
}, 500);
|
}, 500);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import Ellipsis from '../utils/Ellipsis.svelte';
|
import Ellipsis from '../utils/Ellipsis.svelte';
|
||||||
import UpObject from '../display/UpObject.svelte';
|
import UpObject from '../display/UpObject.svelte';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import type { AttributeUpdate, WidgetChange } from '$lib/types/base';
|
import type { WidgetChange } from '$lib/types/base';
|
||||||
import type { UpEntry, UpListing } from '@upnd/upend';
|
import type { UpEntry, UpListing } from '@upnd/upend';
|
||||||
import IconButton from '../utils/IconButton.svelte';
|
import IconButton from '../utils/IconButton.svelte';
|
||||||
import Selector, { type SelectorValue, selectorValueAsValue } from '../utils/Selector.svelte';
|
import Selector, { type SelectorValue, selectorValueAsValue } from '../utils/Selector.svelte';
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
import UpLink from '../display/UpLink.svelte';
|
import UpLink from '../display/UpLink.svelte';
|
||||||
import { ATTR_ADDED, ATTR_LABEL } from '@upnd/upend/constants';
|
import { ATTR_ADDED, ATTR_LABEL } from '@upnd/upend/constants';
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher<{ change: WidgetChange }>();
|
||||||
|
|
||||||
export let columns: string | undefined = undefined;
|
export let columns: string | undefined = undefined;
|
||||||
export let header = true;
|
export let header = true;
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
type: 'create',
|
type: 'create',
|
||||||
attribute,
|
attribute,
|
||||||
value: await selectorValueAsValue(value)
|
value: await selectorValueAsValue(value)
|
||||||
} as WidgetChange);
|
});
|
||||||
newEntryAttribute = '';
|
newEntryAttribute = '';
|
||||||
newEntryValue = undefined;
|
newEntryValue = undefined;
|
||||||
}
|
}
|
||||||
|
@ -72,13 +72,18 @@
|
||||||
dispatch('change', { type: 'delete', address } as WidgetChange);
|
dispatch('change', { type: 'delete', address } as WidgetChange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function updateEntry(address: string, attribute: string, value: SelectorValue) {
|
async function updateEntry(oldEntry: UpEntry, value: SelectorValue) {
|
||||||
dispatch('change', {
|
dispatch('change', [
|
||||||
type: 'update',
|
{
|
||||||
address,
|
type: 'delete',
|
||||||
attribute,
|
address: oldEntry.address
|
||||||
value: await selectorValueAsValue(value)
|
},
|
||||||
} as AttributeUpdate);
|
{
|
||||||
|
type: 'create',
|
||||||
|
attribute: oldEntry.attribute,
|
||||||
|
value: await selectorValueAsValue(value)
|
||||||
|
}
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Labelling
|
// Labelling
|
||||||
|
@ -268,10 +273,7 @@
|
||||||
class="cell value mark-value"
|
class="cell value mark-value"
|
||||||
data-address={entry.value.t === 'Address' ? entry.value.c : undefined}
|
data-address={entry.value.t === 'Address' ? entry.value.c : undefined}
|
||||||
>
|
>
|
||||||
<Editable
|
<Editable value={entry.value} on:edit={(ev) => updateEntry(entry, ev.detail)}>
|
||||||
value={entry.value}
|
|
||||||
on:edit={(ev) => updateEntry(entry.address, entry.attribute, ev.detail)}
|
|
||||||
>
|
|
||||||
{#if entry.value.t === 'Address'}
|
{#if entry.value.t === 'Address'}
|
||||||
<UpObject
|
<UpObject
|
||||||
link
|
link
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
import type { IValue } from '@upnd/upend/types';
|
import type { IValue } from '@upnd/upend/types';
|
||||||
|
|
||||||
export type WidgetChange =
|
export type WidgetOperation =
|
||||||
| AttributeCreate
|
| AttributeCreate
|
||||||
| AttributeUpdate
|
| AttributeUpsert
|
||||||
| AttributeDelete
|
| AttributeDelete
|
||||||
| EntryInAdd
|
| EntryInAdd
|
||||||
| EntryInDelete;
|
| EntryInDelete;
|
||||||
|
|
||||||
|
export type WidgetChange = WidgetOperation | WidgetOperation[];
|
||||||
|
|
||||||
export interface AttributeCreate {
|
export interface AttributeCreate {
|
||||||
type: 'create';
|
type: 'create';
|
||||||
attribute: string;
|
attribute: string;
|
||||||
value: IValue;
|
value: IValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AttributeUpdate {
|
export interface AttributeUpsert {
|
||||||
type: 'update';
|
type: 'upsert';
|
||||||
attribute: string;
|
attribute: string;
|
||||||
value: IValue;
|
value: IValue;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue