wip: also pass `group` to all widgets, basic unused attr display
parent
1c858f8c44
commit
646f77b712
|
@ -7,7 +7,10 @@
|
|||
export interface Widget {
|
||||
name: string;
|
||||
icon?: string;
|
||||
components: (entries: UpEntry[]) => Array<WidgetComponent>;
|
||||
components: (input: {
|
||||
entries: UpEntry[];
|
||||
group?: string;
|
||||
}) => Array<WidgetComponent>;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -41,7 +44,7 @@
|
|||
{
|
||||
name: "Entry List",
|
||||
icon: "table",
|
||||
components: (entries) => [
|
||||
components: ({ entries }) => [
|
||||
{
|
||||
component: EntryList,
|
||||
props: { entries, columns: "entity, attribute, value" },
|
||||
|
@ -65,7 +68,7 @@
|
|||
$: {
|
||||
components = availableWidgets
|
||||
.find((w) => w.name === currentWidget)
|
||||
.components(entries);
|
||||
.components({ entries, group });
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -229,7 +229,7 @@
|
|||
{
|
||||
name: "List",
|
||||
icon: "list-check",
|
||||
components: (entries) => [
|
||||
components: ({ entries }) => [
|
||||
{
|
||||
component: EntryList,
|
||||
props: {
|
||||
|
@ -245,12 +245,13 @@
|
|||
{
|
||||
name: "List",
|
||||
icon: "list-check",
|
||||
components: (entries) => [
|
||||
components: ({ entries, group }) => [
|
||||
{
|
||||
component: EntryList,
|
||||
props: {
|
||||
entries,
|
||||
columns: "attribute, value",
|
||||
attributes: $allTypes[group]?.attributes || [],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -258,7 +259,7 @@
|
|||
{
|
||||
name: "Gallery",
|
||||
icon: "image",
|
||||
components: (entries) => [
|
||||
components: ({ entries }) => [
|
||||
{
|
||||
component: Gallery,
|
||||
props: {
|
||||
|
@ -276,7 +277,7 @@
|
|||
{
|
||||
name: "List",
|
||||
icon: "list-check",
|
||||
components: (entries) => [
|
||||
components: ({ entries }) => [
|
||||
{
|
||||
component: Gallery,
|
||||
props: {
|
||||
|
@ -289,7 +290,7 @@
|
|||
{
|
||||
name: "Gallery",
|
||||
icon: "image",
|
||||
components: (entries) => [
|
||||
components: ({ entries }) => [
|
||||
{
|
||||
component: Gallery,
|
||||
props: {
|
||||
|
@ -427,15 +428,6 @@
|
|||
</section>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<IconButton
|
||||
name="detail"
|
||||
title={$i18n.t("Show as entries")}
|
||||
active={showAsEntries}
|
||||
on:click={() => (showAsEntries = !showAsEntries)}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="error">
|
||||
{$error}
|
||||
|
@ -461,16 +453,23 @@
|
|||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="trash">
|
||||
<div class="footer">
|
||||
<IconButton
|
||||
name="trash"
|
||||
outline
|
||||
color="#dc322f"
|
||||
on:click={deleteObject}
|
||||
title={$i18n.t("Delete object")}
|
||||
name="detail"
|
||||
title={$i18n.t("Show as entries")}
|
||||
active={showAsEntries}
|
||||
on:click={() => (showAsEntries = !showAsEntries)}
|
||||
/>
|
||||
</div>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<IconButton
|
||||
name="trash"
|
||||
outline
|
||||
subdued
|
||||
color="#dc322f"
|
||||
on:click={deleteObject}
|
||||
title={$i18n.t("Delete object")}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
@ -545,6 +544,7 @@
|
|||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 2rem;
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
}
|
||||
|
@ -556,10 +556,4 @@
|
|||
.error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.trash {
|
||||
opacity: 0.66;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import { isEqual } from "lodash";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let editable: boolean;
|
||||
let editable = false;
|
||||
export let attribute: string | undefined = undefined;
|
||||
export let value: IValue;
|
||||
let newValue: IValue = value;
|
||||
|
@ -17,7 +17,7 @@
|
|||
FILE_SIZE: ["Number"],
|
||||
FILE_MIME: ["String"],
|
||||
ADDED: ["Number"],
|
||||
LAST_VISITED: ["Number"]
|
||||
LAST_VISITED: ["Number"],
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
export let disabled = false;
|
||||
export let title: string | undefined = undefined;
|
||||
export let outline = false;
|
||||
export let subdued = false;
|
||||
export let color: string | undefined = "var(--active-color, var(--primary))";
|
||||
</script>
|
||||
|
||||
|
@ -13,6 +14,7 @@
|
|||
on:click
|
||||
class:active
|
||||
class:outline
|
||||
class:subdued
|
||||
{disabled}
|
||||
{title}
|
||||
style="--color: {color}"
|
||||
|
@ -44,6 +46,10 @@
|
|||
border-color 0.2s;
|
||||
}
|
||||
|
||||
button.subdued {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.outline {
|
||||
border: 1px solid var(--foreground);
|
||||
border-radius: 4px;
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
import { i18n } from "../../i18n";
|
||||
import UpLink from "../display/UpLink.svelte";
|
||||
import { ATTR_ADDED, ATTR_LABEL } from "upend/constants";
|
||||
import api from "../../lib/api";
|
||||
import { AddressComponents } from "upend/api";
|
||||
import Icon from "../utils/Icon.svelte";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let columns: string | undefined = undefined;
|
||||
|
@ -27,7 +30,7 @@
|
|||
export let columnWidths: string[] | undefined = undefined;
|
||||
|
||||
export let entries: UpEntry[];
|
||||
export let editable = false;
|
||||
export let attributes: string[] = [];
|
||||
export let attributeOptions: string[] | undefined = undefined;
|
||||
|
||||
// Display
|
||||
|
@ -209,14 +212,25 @@
|
|||
return String(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Unused attributes
|
||||
let unusedAttributes = [];
|
||||
|
||||
$: (async () => {
|
||||
unusedAttributes = await Promise.all(
|
||||
attributes
|
||||
.filter((attr) => !entries.some((entry) => entry.attribute === attr))
|
||||
.map(async (attribute) => {
|
||||
const components = new AddressComponents("Attribute", attribute);
|
||||
return await api.componentsToAddress(components);
|
||||
}),
|
||||
);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<table>
|
||||
<colgroup>
|
||||
{#if editable}
|
||||
<col class="action-col" />
|
||||
{/if}
|
||||
{#each displayColumns as column, idx}
|
||||
{#if columnWidths?.length}
|
||||
<col
|
||||
|
@ -227,30 +241,21 @@
|
|||
<col class="{column}-col" />
|
||||
{/if}
|
||||
{/each}
|
||||
<col class="action-col" />
|
||||
</colgroup>
|
||||
|
||||
{#if header}
|
||||
<tr>
|
||||
{#if editable}
|
||||
<th />
|
||||
{/if}
|
||||
{#each displayColumns as column}
|
||||
<th>{COLUMN_LABELS[column] || $attributeLabels[column] || column}</th>
|
||||
{/each}
|
||||
<th />
|
||||
</tr>
|
||||
{/if}
|
||||
|
||||
{#each sortedEntries as entry (entry.address)}
|
||||
<tr data-address={entry.address} use:observe>
|
||||
{#if visible.has(entry.address)}
|
||||
{#if editable}
|
||||
<td class="attr-action">
|
||||
<IconButton
|
||||
name="x-circle"
|
||||
on:click={() => removeEntry(entry.address)}
|
||||
/>
|
||||
</td>
|
||||
{/if}
|
||||
{#each displayColumns as column}
|
||||
{#if column == TIMESTAMP_COL}
|
||||
<td title={entry.timestamp}
|
||||
|
@ -292,7 +297,6 @@
|
|||
{:else if column == VALUE_COL}
|
||||
<td class="value mark-value">
|
||||
<Editable
|
||||
{editable}
|
||||
attribute={entry.attribute}
|
||||
value={entry.value}
|
||||
on:edit={(ev) =>
|
||||
|
@ -327,6 +331,13 @@
|
|||
<td>?</td>
|
||||
{/if}
|
||||
{/each}
|
||||
<td class="attr-action">
|
||||
<IconButton
|
||||
subdued
|
||||
name="x-circle"
|
||||
on:click={() => removeEntry(entry.address)}
|
||||
/>
|
||||
</td>
|
||||
{:else}
|
||||
<tr>
|
||||
<td colspan="99">
|
||||
|
@ -337,11 +348,26 @@
|
|||
</tr>
|
||||
{/each}
|
||||
|
||||
{#if editable}
|
||||
{#each unusedAttributes as attributeAddress}
|
||||
<tr>
|
||||
{#each displayColumns as column}
|
||||
{#if column == ATTR_COL}
|
||||
<td>
|
||||
<UpObject link address={attributeAddress} />
|
||||
</td>
|
||||
{:else if column == VALUE_COL}
|
||||
<!-- <Selector type="value" bind:value={newEntryValue} /> -->
|
||||
<td class="unset">{$i18n.t("(unset)")}</td>
|
||||
{:else}
|
||||
<td></td>
|
||||
{/if}
|
||||
{/each}
|
||||
<td class="attr-action"></td>
|
||||
</tr>
|
||||
{/each}
|
||||
|
||||
{#if !attributes.length}
|
||||
<tr class="add-row">
|
||||
<td class="attr-action">
|
||||
<IconButton name="plus-circle" on:click={addEntry} />
|
||||
</td>
|
||||
{#if displayColumns.includes(ATTR_COL)}
|
||||
<td>
|
||||
<Selector
|
||||
|
@ -356,6 +382,9 @@
|
|||
<Selector type="value" bind:value={newEntryValue} />
|
||||
</td>
|
||||
{/if}
|
||||
<td class="attr-action">
|
||||
<IconButton name="plus-circle" on:click={addEntry} />
|
||||
</td>
|
||||
</tr>
|
||||
{/if}
|
||||
</table>
|
||||
|
@ -402,5 +431,10 @@
|
|||
.attribute-col {
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
.unset {
|
||||
opacity: 0.66;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
{
|
||||
name: "List",
|
||||
icon: "list-ul",
|
||||
components: (entries) => [
|
||||
components: ({ entries }) => [
|
||||
{
|
||||
component: EntryList,
|
||||
props: {
|
||||
|
@ -108,7 +108,7 @@
|
|||
{
|
||||
name: "Gallery",
|
||||
icon: "image",
|
||||
components: (entries) => [
|
||||
components: ({ entries }) => [
|
||||
{
|
||||
component: Gallery,
|
||||
props: {
|
||||
|
@ -124,7 +124,7 @@
|
|||
{
|
||||
name: "List",
|
||||
icon: "list-ul",
|
||||
components: (entries) => [
|
||||
components: ({ entries }) => [
|
||||
{
|
||||
component: EntryList,
|
||||
props: {
|
||||
|
@ -140,7 +140,7 @@
|
|||
{
|
||||
name: "Gallery",
|
||||
icon: "image",
|
||||
components: (entries) => [
|
||||
components: ({ entries }) => [
|
||||
{
|
||||
component: Gallery,
|
||||
props: {
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
}
|
||||
|
||||
$: objects = ($result?.entries || []).filter(
|
||||
(e) => e.attribute === ATTR_LABEL
|
||||
(e) => e.attribute === ATTR_LABEL,
|
||||
);
|
||||
$: sortedObjects = matchSorter(objects, debouncedQuery, {
|
||||
keys: ["value.c"],
|
||||
|
@ -51,7 +51,7 @@
|
|||
.then((labelListing) => {
|
||||
exactHits = labelListing.entries
|
||||
.filter(
|
||||
(e) => String(e.value.c).toLowerCase() === query.toLowerCase()
|
||||
(e) => String(e.value.c).toLowerCase() === query.toLowerCase(),
|
||||
)
|
||||
.map((e) => e.entity);
|
||||
});
|
||||
|
@ -68,7 +68,7 @@
|
|||
{
|
||||
name: "List",
|
||||
icon: "list-ul",
|
||||
components: (entries) => [
|
||||
components: ({ entries }) => [
|
||||
{
|
||||
component: Gallery,
|
||||
props: {
|
||||
|
@ -82,7 +82,7 @@
|
|||
{
|
||||
name: "Gallery",
|
||||
icon: "image",
|
||||
components: (entries) => [
|
||||
components: ({ entries }) => [
|
||||
{
|
||||
component: Gallery,
|
||||
props: {
|
||||
|
|
Loading…
Reference in New Issue