diff --git a/tools/upend_js/index.ts b/tools/upend_js/index.ts index 21326fb..b16b18d 100644 --- a/tools/upend_js/index.ts +++ b/tools/upend_js/index.ts @@ -14,42 +14,54 @@ import type { IEntry, ListingResult, VALUE_TYPE } from "./types"; export class UpListing { public readonly entries: UpEntry[]; + private _objects: { [key: string]: UpObject } = {}; constructor(listing: ListingResult) { - this.entries = Object.entries(listing).map((lr) => new UpEntry(...lr)); + this.entries = Object.entries(listing).map( + (lr) => new UpEntry(...lr, this) + ); } - public get objects(): UpObject[] { + public get objects() { const allEntities = new Set(this.entries.map((e) => e.entity)); - return Array.from(allEntities).map( - (entity) => new UpObject(entity, this.entries) + const result: { [key: string]: UpObject } = {}; + Array.from(allEntities).forEach( + (entity) => (result[entity] = new UpObject(entity, this)) ); + return result; + } + + public getObject(address: string) { + if (!this._objects[address]) { + this._objects[address] = new UpObject(address, this); + } + return this._objects[address]; } } export class UpObject { public readonly address; - private entries: UpEntry[]; + public listing: UpListing | undefined; - constructor(address: string, entries?: UpEntry[]) { + constructor(address: string, listing?: UpListing) { this.address = address; - this.entries = entries || []; + this.listing = listing; } - public bind(entries: UpEntry[]) { - this.entries = entries; - } - - public bindAppend(entries: UpEntry[]) { - this.entries.push(...entries); + public bind(listing: UpListing) { + this.listing = listing; } public get attributes() { - return this.entries.filter((e) => e.entity === this.address); + return (this.listing?.entries || []).filter( + (e) => e.entity === this.address + ); } public get backlinks() { - return this.entries.filter((e) => e.value.c === this.address); + return (this.listing?.entries || []).filter( + (e) => e.value.c === this.address + ); } public get attr() { @@ -70,18 +82,10 @@ export class UpObject { } public identify(): string[] { - // Get all places where this Object is "had" - const hasEntries = this.backlinks + const hasAliases = this.backlinks .filter((entry) => entry.attribute === "HAS") - .map((entry) => entry.address); - - // Out of those relations, retrieve their ALIAS attrs - const hasAliases = this.entries - .filter( - (entry) => - entry.attribute === "ALIAS" && hasEntries.includes(entry.entity) - ) - .map((entry) => String(entry.value.c)); + .map((entry) => entry.get("ALIAS")) + .filter(Boolean) as string[]; const lblValues = (this.attr["LBL"] || []).map((e) => String(e.value.c)); @@ -101,8 +105,8 @@ export class UpEntry extends UpObject implements IEntry { attribute: string; value: { t: VALUE_TYPE; c: string | number }; - constructor(address: string, entry: IEntry) { - super(address); + constructor(address: string, entry: IEntry, listing: UpListing) { + super(address, listing); this.entity = entry.entity; this.attribute = entry.attribute; diff --git a/ui/src/components/Address.svelte b/ui/src/components/Address.svelte index f9ba4b0..2b7976d 100644 --- a/ui/src/components/Address.svelte +++ b/ui/src/components/Address.svelte @@ -5,9 +5,11 @@ import Ellipsis from "./Ellipsis.svelte"; import UpLink from "./UpLink.svelte"; import { useEntity } from "../lib/entity"; + import type { UpObject } from "upend"; const dispatch = createEventDispatcher(); export let address: string; + export let labels: string[] = []; export let link = false; export let resolve = true; export let banner = false; @@ -29,7 +31,8 @@ } } - $: label = inferredIds.join(" | ") || address; + $: displayLabel = + Array.from(new Set(inferredIds.concat(labels))).join(" | ") || address; $: dispatch("resolved", inferredIds); @@ -37,17 +40,17 @@
-
+
{#if banner && isFile} - + {:else if link} - + {:else} - + {/if}
diff --git a/ui/src/components/AttributeView.svelte b/ui/src/components/AttributeView.svelte index 36f3752..a04dfec 100644 --- a/ui/src/components/AttributeView.svelte +++ b/ui/src/components/AttributeView.svelte @@ -1,16 +1,16 @@

-
+ {#if $entity} +
+ {/if}

{#if !$error}
- {#each Object.entries(typedAttributes) as [typeAddr, attributes] (typeAddr)} + {#each Object.entries(typedAttributes) as [typeAddr, entries] (typeAddr)} {/each} - {#if filteredUntypedAttributes.length > 0 || editable} + + {#if untypedAttributes.length > 0 || editable} {/if} + {#if $entity?.backlinks.length > 0} diff --git a/ui/src/components/widgets/Table.svelte b/ui/src/components/widgets/Table.svelte index 414051f..b331078 100644 --- a/ui/src/components/widgets/Table.svelte +++ b/ui/src/components/widgets/Table.svelte @@ -14,7 +14,7 @@ export let columns = "attribute, value"; export let header = true; - export let attributes: UpEntry[]; + export let entries: UpEntry[]; export let editable = false; // Display @@ -59,7 +59,7 @@ // Sorting let sortKeys: { [key: string]: string } = {}; - $: sortedAttributes = attributes + $: sortedAttributes = entries .concat() .sort((aEntry, bEntry) => { if ( @@ -77,6 +77,9 @@ return sortKeys[aEntry.value.c].localeCompare(sortKeys[bEntry.value.c]); } }) + .sort((aEntry, bEntry) => { + return String(aEntry.value.c).length - String(bEntry.value.c).length; + }) .sort((aEntry, bEntry) => { return aEntry.attribute.localeCompare(bEntry.attribute); }) @@ -186,6 +189,7 @@
{ sortKeys[entry.entity] = event.detail[0]; @@ -213,6 +217,9 @@
{ sortKeys[entry.value.c] = event.detail[0]; diff --git a/ui/src/lib/entity.ts b/ui/src/lib/entity.ts index b06e404..d59b2f8 100644 --- a/ui/src/lib/entity.ts +++ b/ui/src/lib/entity.ts @@ -16,7 +16,7 @@ export function useEntity(address: string) { const entity: Readable = derived(data, ($listing) => { if ($listing) { const listing = new UpListing($listing); - return listing.objects.find((obj) => obj.address == address); + return listing.getObject(address); } }); diff --git a/ui/src/lib/types.ts b/ui/src/lib/types.ts index 664566a..7b8aa04 100644 --- a/ui/src/lib/types.ts +++ b/ui/src/lib/types.ts @@ -1,12 +1,11 @@ -import type { SvelteComponent, SvelteComponentTyped } from "svelte"; -import List from "../components/widgets/List.svelte"; +import Table from "../components/widgets/Table.svelte"; export class UpType { address: string; name: string | null = null; attributes: string[] = []; - constructor(address: string) { + constructor(address?: string) { this.address = address; } @@ -19,6 +18,8 @@ export class UpType { } } +export const UNTYPED = new UpType("UNTYPED"); + export interface Component { component: any; // TODO props?: { [key: string]: unknown }; @@ -41,9 +42,9 @@ const TYPE_WIDGETS: { [key: string]: Widget } = { icon: "folder", components: [ { - component: List, + component: Table, props: { - attribute: "HAS", + columns: "value", }, }, ], diff --git a/ui/src/views/Home.svelte b/ui/src/views/Home.svelte index 70dc50b..397effb 100644 --- a/ui/src/views/Home.svelte +++ b/ui/src/views/Home.svelte @@ -15,8 +15,9 @@ const response = await fetch("/api/hier_roots"); const data = (await response.json()) as ListingResult; const listing = new UpListing(data); - console.log(listing.objects.map((obj) => obj.attr)); - return listing.objects.filter((obj) => Boolean(obj.attr["LBL"])); + return Object.values(listing.objects).filter((obj) => + Boolean(obj.attr["LBL"]) + ); })(); const latestFiles = (async () => { @@ -45,7 +46,7 @@
  • -

    {root.get("LBL")}

    +

    {root.identify()}

    {root.attr["HAS"]?.length || 0} children diff --git a/ui/yarn.lock b/ui/yarn.lock index 2bce790..1ae310d 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -3301,8 +3301,8 @@ __metadata: "upend@file:../tools/upend_js::locator=svelte-app%40workspace%3A.": version: 0.0.1 - resolution: "upend@file:../tools/upend_js#../tools/upend_js::hash=88b9af&locator=svelte-app%40workspace%3A." - checksum: 9076efc8b84c0c96f5d48ce092320832be93d18529af48d6ab623a3adb698401b78913ceac95439ddaaf3232a6a41ec886ad263ce2f05646ad6460d98627f8e9 + resolution: "upend@file:../tools/upend_js#../tools/upend_js::hash=28f6da&locator=svelte-app%40workspace%3A." + checksum: c0d1171522a5b5756516f5e4b1ff2eab15e9a6be7eb1689afcdecd4da89b4c26aa82293320928e8a60a9bd65de15482c5b1eae323c0205f10c17aac5524418de languageName: node linkType: hard