wip
ci/woodpecker/push/woodpecker Pipeline failed
Details
ci/woodpecker/push/woodpecker Pipeline failed
Details
parent
cb6460032d
commit
4a2305722c
|
@ -0,0 +1,53 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { attributeLabels } from '$lib/util/labels';
|
||||||
|
import UpLink from '$lib/components/display/UpLink.svelte';
|
||||||
|
import Ellipsis from '$lib/components/utils/Ellipsis.svelte';
|
||||||
|
|
||||||
|
export let attribute: string;
|
||||||
|
export let mark = false;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="attribute mark-attribute"
|
||||||
|
class:formatted={Boolean(Object.keys($attributeLabels).includes(attribute))}
|
||||||
|
class:mark
|
||||||
|
>
|
||||||
|
<UpLink to={{ attribute }}>
|
||||||
|
<Ellipsis
|
||||||
|
value={$attributeLabels[attribute] || attribute}
|
||||||
|
title={$attributeLabels[attribute]
|
||||||
|
? `${$attributeLabels[attribute]} (${attribute})`
|
||||||
|
: attribute}
|
||||||
|
/>
|
||||||
|
</UpLink>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.attribute {
|
||||||
|
min-width: 0;
|
||||||
|
font-family: var(--monospace-font);
|
||||||
|
&.formatted {
|
||||||
|
font-family: var(--default-font);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mark {
|
||||||
|
position: relative;
|
||||||
|
top: 0.2em;
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 0.9em;
|
||||||
|
&::after {
|
||||||
|
content: '\00a0→';
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: calc(-50% + 2px);
|
||||||
|
left: calc(50% - 2px);
|
||||||
|
|
||||||
|
transform: translateX(-50%);
|
||||||
|
font-size: 0.66em;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,8 +1,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { UpEntry } from '@upnd/upend';
|
import type { UpEntry } from '@upnd/upend';
|
||||||
import { attributeLabels } from '$lib/util/labels';
|
|
||||||
import UpObject from './UpObject.svelte';
|
import UpObject from './UpObject.svelte';
|
||||||
import Ellipsis from '$lib/components/utils/Ellipsis.svelte';
|
import Ellipsis from '$lib/components/utils/Ellipsis.svelte';
|
||||||
|
import UpAttribute from '$lib/components/display/UpAttribute.svelte';
|
||||||
export let resolve = true;
|
export let resolve = true;
|
||||||
|
|
||||||
export let entry: UpEntry;
|
export let entry: UpEntry;
|
||||||
|
@ -12,9 +12,7 @@
|
||||||
<div class="entity">
|
<div class="entity">
|
||||||
<UpObject plain link address={entry.entity} labels={resolve ? undefined : []} />
|
<UpObject plain link address={entry.entity} labels={resolve ? undefined : []} />
|
||||||
</div>
|
</div>
|
||||||
<div class="attribute" title={entry.attribute}>
|
<UpAttribute attribute={entry.attribute} mark />
|
||||||
<Ellipsis value={$attributeLabels[entry.attribute] || entry.attribute} />
|
|
||||||
</div>
|
|
||||||
<div class="value value-{entry.value.t.toLowerCase()}">
|
<div class="value value-{entry.value.t.toLowerCase()}">
|
||||||
{#if entry.value.t === 'Address'}
|
{#if entry.value.t === 'Address'}
|
||||||
<UpObject link address={entry.value.c} labels={resolve ? undefined : []} />
|
<UpObject link address={entry.value.c} labels={resolve ? undefined : []} />
|
||||||
|
@ -41,26 +39,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.attribute {
|
|
||||||
position: relative;
|
|
||||||
top: 0.2em;
|
|
||||||
flex-grow: 1;
|
|
||||||
text-align: center;
|
|
||||||
font-weight: 300;
|
|
||||||
font-size: 0.9em;
|
|
||||||
&::after {
|
|
||||||
content: '\00a0→';
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
top: calc(-50% + 2px);
|
|
||||||
left: calc(50% - 2px);
|
|
||||||
|
|
||||||
transform: translateX(-50%);
|
|
||||||
font-size: 0.66em;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.value-value) {
|
:global(.value-value) {
|
||||||
font-family: var(--monospace-font);
|
font-family: var(--monospace-font);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { formatDuration } from '$lib/util/fragments/time';
|
||||||
|
import Ellipsis from '$lib/components/utils/Ellipsis.svelte';
|
||||||
|
import Editable from '$lib/components/utils/Editable.svelte';
|
||||||
|
import UpObject from '$lib/components/display/UpObject.svelte';
|
||||||
|
import { IValue } from '@upnd/upend';
|
||||||
|
import { formatRelative, fromUnixTime } from 'date-fns';
|
||||||
|
import filesize from 'filesize';
|
||||||
|
import { ATTR_ADDED } from '@upnd/upend/constants';
|
||||||
|
|
||||||
|
export let value: IValue;
|
||||||
|
export let attribute: string | undefined;
|
||||||
|
export let labels: string[] | undefined = undefined;
|
||||||
|
|
||||||
|
function formatValue(value: string | number | null, attribute: string | undefined): string {
|
||||||
|
if (attribute) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="cell value mark-value" data-address={value.t === 'Address' ? value.c : undefined}>
|
||||||
|
<Editable {value} on:edit>
|
||||||
|
{#if value.t === 'Address'}
|
||||||
|
<UpObject link address={String(value.c)} {labels} on:resolved />
|
||||||
|
{:else}
|
||||||
|
<div class:formatted={Boolean(formatValue(value.c, attribute))}>
|
||||||
|
<Ellipsis value={formatValue(value.c, attribute) || String(value.c)} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</Editable>
|
||||||
|
</div>
|
|
@ -153,7 +153,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
<div class="items">
|
<div class="items">
|
||||||
{#each sortedEntities as entity (entity)}
|
{#each sortedEntities as entity (entity)}
|
||||||
<div data-address={entity} data-select-mode={select} use:observe class="item">
|
<div data-address={entity} data-select-mode={select} use:observe class="row">
|
||||||
{#if visible.has(entity)}
|
{#if visible.has(entity)}
|
||||||
{#if thumbnails}
|
{#if thumbnails}
|
||||||
<UpObjectCard
|
<UpObjectCard
|
||||||
|
@ -247,7 +247,7 @@
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
.row {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
@ -259,7 +259,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.entitylist:not(.has-thumbnails) {
|
.entitylist:not(.has-thumbnails) {
|
||||||
.item {
|
.row {
|
||||||
display: flex;
|
display: flex;
|
||||||
.object {
|
.object {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -280,7 +280,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.entitylist.has-thumbnails {
|
.entitylist.has-thumbnails {
|
||||||
.item {
|
.row {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
import { i18n } from '$lib/i18n';
|
import { i18n } from '$lib/i18n';
|
||||||
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';
|
||||||
|
import UpAttribute from '$lib/components/display/UpAttribute.svelte';
|
||||||
|
import UpValue from '$lib/components/display/UpValue.svelte';
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<{ change: WidgetChange }>();
|
const dispatch = createEventDispatcher<{ change: WidgetChange }>();
|
||||||
|
|
||||||
|
@ -40,7 +42,7 @@
|
||||||
|
|
||||||
$: templateColumns = (
|
$: templateColumns = (
|
||||||
(displayColumns || []).map((column, idx) => {
|
(displayColumns || []).map((column, idx) => {
|
||||||
if (columnWidths?.[idx]) return columnWidths[idx];
|
if (columnWidths?.[idx]) return columnWidths?.[idx];
|
||||||
return 'minmax(6em, auto)';
|
return 'minmax(6em, auto)';
|
||||||
}) as string[]
|
}) as string[]
|
||||||
)
|
)
|
||||||
|
@ -193,25 +195,6 @@
|
||||||
value: $i18n.t('Value')
|
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
|
// Unused attributes
|
||||||
let unusedAttributes: string[] = [];
|
let unusedAttributes: string[] = [];
|
||||||
|
|
||||||
|
@ -255,42 +238,19 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{:else if column == ATTR_COL}
|
{:else if column == ATTR_COL}
|
||||||
<div
|
<div class="cell">
|
||||||
class="cell mark-attribute"
|
<UpAttribute attribute={entry.attribute} />
|
||||||
class:formatted={Boolean(Object.keys($attributeLabels).includes(entry.attribute))}
|
|
||||||
>
|
|
||||||
<UpLink to={{ attribute: entry.attribute }}>
|
|
||||||
<Ellipsis
|
|
||||||
value={$attributeLabels[entry.attribute] || entry.attribute}
|
|
||||||
title={$attributeLabels[entry.attribute]
|
|
||||||
? `${$attributeLabels[entry.attribute]} (${entry.attribute})`
|
|
||||||
: entry.attribute}
|
|
||||||
/>
|
|
||||||
</UpLink>
|
|
||||||
</div>
|
</div>
|
||||||
{:else if column == VALUE_COL}
|
{:else if column == VALUE_COL}
|
||||||
<div
|
<div class="cell">
|
||||||
class="cell value mark-value"
|
<UpValue
|
||||||
data-address={entry.value.t === 'Address' ? entry.value.c : undefined}
|
value={entry.value}
|
||||||
>
|
labels={$labelListing?.getObject(String(entry.value.c))?.identify() || []}
|
||||||
<Editable value={entry.value} on:edit={(ev) => updateEntry(entry, ev.detail)}>
|
on:edit={(ev) => updateEntry(entry, ev.detail)}
|
||||||
{#if entry.value.t === 'Address'}
|
on:resolved={(event) => {
|
||||||
<UpObject
|
addSortKeys(String(entry.value.c), event.detail, true);
|
||||||
link
|
}}
|
||||||
address={String(entry.value.c)}
|
/>
|
||||||
labels={$labelListing?.getObject(String(entry.value.c))?.identify() || []}
|
|
||||||
on:resolved={(event) => {
|
|
||||||
addSortKeys(String(entry.value.c), event.detail, true);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{:else}
|
|
||||||
<div class:formatted={Boolean(formatValue(entry.value.c, entry.attribute))}>
|
|
||||||
<Ellipsis
|
|
||||||
value={formatValue(entry.value.c, entry.attribute) || String(entry.value.c)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</Editable>
|
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div>?</div>
|
<div>?</div>
|
||||||
|
|
|
@ -0,0 +1,224 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { readable, type Readable } from 'svelte/store';
|
||||||
|
import { Query, type UpListing } from '@upnd/upend';
|
||||||
|
import { Any } from '@upnd/upend/query';
|
||||||
|
import type { Address } from '@upnd/upend/types';
|
||||||
|
import { query } from '$lib/entity';
|
||||||
|
import UpObject from '../display/UpObject.svelte';
|
||||||
|
import UpObjectCard from '../display/UpObjectCard.svelte';
|
||||||
|
import { ATTR_LABEL } from '@upnd/upend/constants';
|
||||||
|
import { i18n } from '$lib/i18n';
|
||||||
|
import IconButton from '../utils/IconButton.svelte';
|
||||||
|
import Selector, { type SelectorValue } from '../utils/Selector.svelte';
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
import type { WidgetChange } from '$lib/types/base';
|
||||||
|
import debug from 'debug';
|
||||||
|
import api from '$lib/api';
|
||||||
|
import UpAttribute from '$lib/components/display/UpAttribute.svelte';
|
||||||
|
import UpValue from '$lib/components/display/UpValue.svelte';
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
const dbg = debug(`kestrel:Table`);
|
||||||
|
|
||||||
|
export let entities: Address[];
|
||||||
|
export let sort = true;
|
||||||
|
export let address: Address | undefined = undefined;
|
||||||
|
export let columns: string[] = [];
|
||||||
|
|
||||||
|
let currentColumns: string[] = columns;
|
||||||
|
|
||||||
|
let values: UpListing | undefined = undefined;
|
||||||
|
$: update(entities, currentColumns);
|
||||||
|
async function update(entities: Address[], columns: string[]) {
|
||||||
|
values = await api.query(
|
||||||
|
Query.matches(
|
||||||
|
entities.map((entity) => `@${entity}`),
|
||||||
|
columns,
|
||||||
|
Any
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$: deduplicatedEntities = Array.from(new Set(entities));
|
||||||
|
|
||||||
|
// Sorting
|
||||||
|
let sortedEntities: Address[] = [];
|
||||||
|
|
||||||
|
let sortKeys: { [key: string]: string[] } = {};
|
||||||
|
function addSortKeys(key: string, vals: string[], resort: boolean) {
|
||||||
|
if (!sortKeys[key]) {
|
||||||
|
sortKeys[key] = [];
|
||||||
|
}
|
||||||
|
let changed = false;
|
||||||
|
vals.forEach((val) => {
|
||||||
|
if (!sortKeys[key].includes(val)) {
|
||||||
|
changed = true;
|
||||||
|
sortKeys[key].push(val);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (resort && changed) sortEntities();
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortEntities() {
|
||||||
|
if (!sort) return;
|
||||||
|
|
||||||
|
sortedEntities = deduplicatedEntities.concat();
|
||||||
|
|
||||||
|
sortedEntities.sort((a, b) => {
|
||||||
|
if (!sortKeys[a]?.length || !sortKeys[b]?.length) {
|
||||||
|
if (Boolean(sortKeys[a]?.length) && !sortKeys[b]?.length) {
|
||||||
|
return -1;
|
||||||
|
} else if (!sortKeys[a]?.length && Boolean(sortKeys[b]?.length)) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return a.localeCompare(b);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return sortKeys[a][0].localeCompare(sortKeys[b][0], undefined, {
|
||||||
|
numeric: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Labelling
|
||||||
|
let labelListing: Readable<UpListing | undefined> = readable(undefined);
|
||||||
|
$: {
|
||||||
|
const addressesString = deduplicatedEntities.map((addr) => `@${addr}`).join(' ');
|
||||||
|
|
||||||
|
labelListing = query(`(matches (in ${addressesString}) "${ATTR_LABEL}" ? )`).result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if ($labelListing) {
|
||||||
|
deduplicatedEntities.forEach((address) => {
|
||||||
|
addSortKeys(address, $labelListing?.getObject(address).identify() || [], false);
|
||||||
|
});
|
||||||
|
sortEntities();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sort) {
|
||||||
|
sortedEntities = entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visibility
|
||||||
|
let visible: Set<string> = new Set();
|
||||||
|
let observer = new IntersectionObserver((intersections) => {
|
||||||
|
intersections.forEach((intersection) => {
|
||||||
|
const address = (intersection.target as HTMLElement).dataset['address'];
|
||||||
|
if (!address) {
|
||||||
|
console.warn('Intersected wrong element?');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intersection.isIntersecting) {
|
||||||
|
visible.add(address);
|
||||||
|
}
|
||||||
|
visible = visible;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function observe(node: HTMLElement) {
|
||||||
|
observer.observe(node);
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy() {
|
||||||
|
observer.unobserve(node);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// // Adding
|
||||||
|
// let addSelector: Selector | undefined;
|
||||||
|
// let adding = false;
|
||||||
|
//
|
||||||
|
// $: if (adding && addSelector) addSelector.focus();
|
||||||
|
//
|
||||||
|
// function addEntity(ev: CustomEvent<SelectorValue>) {
|
||||||
|
// dbg('Adding entity', ev.detail);
|
||||||
|
// const addAddress = ev.detail?.t == 'Address' ? ev.detail.c : undefined;
|
||||||
|
// if (!addAddress) return;
|
||||||
|
//
|
||||||
|
// dispatch('change', {
|
||||||
|
// type: 'entry-add',
|
||||||
|
// address: addAddress
|
||||||
|
// } as WidgetChange);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// function removeEntity(address: string) {
|
||||||
|
// if (confirm($i18n.t('Are you sure you want to remove this entry from members?') || '')) {
|
||||||
|
// dbg('Removing entity', address);
|
||||||
|
// dispatch('change', {
|
||||||
|
// type: 'entry-delete',
|
||||||
|
// address
|
||||||
|
// } as WidgetChange);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="table" style="--columns-count: {currentColumns.length}">
|
||||||
|
{#if !sortedEntities.length}
|
||||||
|
<div class="message">
|
||||||
|
{$i18n.t('No entries.')}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div class="header">
|
||||||
|
<div>
|
||||||
|
{$i18n.t('Name')}
|
||||||
|
</div>
|
||||||
|
{#each currentColumns as attribute}
|
||||||
|
<UpAttribute {attribute} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{#each sortedEntities as entity (entity)}
|
||||||
|
<div data-address={entity} use:observe class="row" class:visible={visible.has(entity)}>
|
||||||
|
{#if visible.has(entity)}
|
||||||
|
<div class="object">
|
||||||
|
<UpObject
|
||||||
|
link
|
||||||
|
address={entity}
|
||||||
|
labels={sortKeys[entity]}
|
||||||
|
on:resolved={(event) => {
|
||||||
|
addSortKeys(entity, event.detail, true);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{#each currentColumns as attribute}
|
||||||
|
{@const value = values?.getObject(entity)?.get(attribute)}
|
||||||
|
{#if value}
|
||||||
|
<UpValue {value} {attribute} />
|
||||||
|
{:else}
|
||||||
|
<div class="null">X</div>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
{:else}
|
||||||
|
<div class="skeleton" style="text-align: center">...</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@use '../../styles/colors';
|
||||||
|
|
||||||
|
.table {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr repeat(var(--columns-count), 1fr);
|
||||||
|
|
||||||
|
gap: 0.2em;
|
||||||
|
|
||||||
|
.header,
|
||||||
|
.row.visible {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row:not(.visible) {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -2,10 +2,15 @@ import api from '$lib/api';
|
||||||
import { i18n } from '$lib/i18n';
|
import { i18n } from '$lib/i18n';
|
||||||
import { derived, readable, type Readable } from 'svelte/store';
|
import { derived, readable, type Readable } from 'svelte/store';
|
||||||
import type { AttributeListingResult } from '@upnd/upend/types';
|
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 databaseAttributeLabels: Readable<{ [key: string]: string }> = readable({}, (set) => {
|
||||||
const result: Record<string, string> = {};
|
const result: Record<string, string> = {};
|
||||||
|
dbg('Fetching all attributes');
|
||||||
api.fetchAllAttributes().then((attributes: AttributeListingResult) => {
|
api.fetchAllAttributes().then((attributes: AttributeListingResult) => {
|
||||||
|
dbg('Fetched all attributes: %o', attributes);
|
||||||
attributes.forEach((attribute) => {
|
attributes.forEach((attribute) => {
|
||||||
if (attribute.labels.length) {
|
if (attribute.labels.length) {
|
||||||
result[attribute.name] = attribute.labels.sort()[0];
|
result[attribute.name] = attribute.labels.sort()[0];
|
||||||
|
|
|
@ -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<Table> = {
|
||||||
|
title: 'Widgets/Table',
|
||||||
|
component: Table,
|
||||||
|
tags: ['autodocs'],
|
||||||
|
args: {
|
||||||
|
entities: [imageAddress, imageVerticalAddress, videoAddress, videoVerticalAddress]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<Table>;
|
||||||
|
|
||||||
|
export const Default: Story = {};
|
||||||
|
|
||||||
|
export const Mixed: Story = {
|
||||||
|
args: {
|
||||||
|
columns: ['MEDIA_DURATION', 'FILE_SIZE']
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue