diff --git a/webui/src/lib/components/display/UpAttribute.svelte b/webui/src/lib/components/display/UpAttribute.svelte new file mode 100644 index 0000000..e723107 --- /dev/null +++ b/webui/src/lib/components/display/UpAttribute.svelte @@ -0,0 +1,53 @@ + + +
+ + + +
+ + diff --git a/webui/src/lib/components/display/UpEntry.svelte b/webui/src/lib/components/display/UpEntry.svelte index 0cd28af..20fe84f 100644 --- a/webui/src/lib/components/display/UpEntry.svelte +++ b/webui/src/lib/components/display/UpEntry.svelte @@ -1,8 +1,8 @@ + +
+ + {#if value.t === 'Address'} + + {:else} +
+ +
+ {/if} +
+
diff --git a/webui/src/lib/components/widgets/EntityList.svelte b/webui/src/lib/components/widgets/EntityList.svelte index 2526980..21fe0a1 100644 --- a/webui/src/lib/components/widgets/EntityList.svelte +++ b/webui/src/lib/components/widgets/EntityList.svelte @@ -153,7 +153,7 @@ {/if}
{#each sortedEntities as entity (entity)} -
+
{#if visible.has(entity)} {#if thumbnails} (); @@ -40,7 +42,7 @@ $: templateColumns = ( (displayColumns || []).map((column, idx) => { - if (columnWidths?.[idx]) return columnWidths[idx]; + if (columnWidths?.[idx]) return columnWidths?.[idx]; return 'minmax(6em, auto)'; }) as string[] ) @@ -193,25 +195,6 @@ value: $i18n.t('Value') }; - function formatValue(value: string | number | null, attribute: string): string { - try { - switch (attribute) { - case 'FILE_SIZE': - return filesize(parseInt(String(value), 10), { base: 2 }); - case ATTR_ADDED: - case 'LAST_VISITED': - return formatRelative(fromUnixTime(parseInt(String(value), 10)), new Date()); - case 'NUM_VISITED': - return `${value} times`; - case 'MEDIA_DURATION': - return formatDuration(parseInt(String(value), 10)); - } - } catch { - // noop. - } - return String(value); - } - // Unused attributes let unusedAttributes: string[] = []; @@ -255,42 +238,19 @@ />
{:else if column == ATTR_COL} -
- - - +
+
{:else if column == VALUE_COL} -
- updateEntry(entry, ev.detail)}> - {#if entry.value.t === 'Address'} - { - addSortKeys(String(entry.value.c), event.detail, true); - }} - /> - {:else} -
- -
- {/if} -
+
+ updateEntry(entry, ev.detail)} + on:resolved={(event) => { + addSortKeys(String(entry.value.c), event.detail, true); + }} + />
{:else}
?
diff --git a/webui/src/lib/components/widgets/Table.svelte b/webui/src/lib/components/widgets/Table.svelte new file mode 100644 index 0000000..4946950 --- /dev/null +++ b/webui/src/lib/components/widgets/Table.svelte @@ -0,0 +1,224 @@ + + +
+ {#if !sortedEntities.length} +
+ {$i18n.t('No entries.')} +
+ {/if} +
+
+ {$i18n.t('Name')} +
+ {#each currentColumns as attribute} + + {/each} +
+ {#each sortedEntities as entity (entity)} +
+ {#if visible.has(entity)} +
+ { + addSortKeys(entity, event.detail, true); + }} + /> +
+ {#each currentColumns as attribute} + {@const value = values?.getObject(entity)?.get(attribute)} + {#if value} + + {:else} +
X
+ {/if} + {/each} + {:else} +
...
+ {/if} +
+ {/each} +
+ + diff --git a/webui/src/lib/util/labels.ts b/webui/src/lib/util/labels.ts index 6c4376a..9bc7203 100644 --- a/webui/src/lib/util/labels.ts +++ b/webui/src/lib/util/labels.ts @@ -2,10 +2,15 @@ import api from '$lib/api'; import { i18n } from '$lib/i18n'; import { derived, readable, type Readable } from 'svelte/store'; import type { AttributeListingResult } from '@upnd/upend/types'; +import debug from 'debug'; + +const dbg = debug('kestrel:labels'); const databaseAttributeLabels: Readable<{ [key: string]: string }> = readable({}, (set) => { const result: Record = {}; + dbg('Fetching all attributes'); api.fetchAllAttributes().then((attributes: AttributeListingResult) => { + dbg('Fetched all attributes: %o', attributes); attributes.forEach((attribute) => { if (attribute.labels.length) { result[attribute.name] = attribute.labels.sort()[0]; diff --git a/webui/src/stories/Table.stories.ts b/webui/src/stories/Table.stories.ts new file mode 100644 index 0000000..122395c --- /dev/null +++ b/webui/src/stories/Table.stories.ts @@ -0,0 +1,23 @@ +import type { Meta, StoryObj } from '@storybook/svelte'; +import Table from '../lib/components/widgets/Table.svelte'; +import { imageAddress, imageVerticalAddress, videoAddress, videoVerticalAddress } from './common'; + +const meta: Meta = { + title: 'Widgets/Table', + component: Table, + tags: ['autodocs'], + args: { + entities: [imageAddress, imageVerticalAddress, videoAddress, videoVerticalAddress] + } +}; + +export default meta; +type Story = StoryObj
; + +export const Default: Story = {}; + +export const Mixed: Story = { + args: { + columns: ['MEDIA_DURATION', 'FILE_SIZE'] + } +};