From 641f42f785cb364ccb2a3a686f827421e5748f88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Ml=C3=A1dek?= Date: Sat, 24 Jun 2023 16:26:14 +0200 Subject: [PATCH] wip(webui): use (new) attr constants --- tools/upend_js/constants.ts | 31 +++++++++++++++++++ webui/src/components/Inspect.svelte | 15 ++++----- .../src/components/display/BlobPreview.svelte | 5 +-- .../display/blobs/AudioViewer.svelte | 5 +-- .../display/blobs/ImageViewer.svelte | 13 ++++---- webui/src/components/utils/Selector.svelte | 5 +-- webui/src/components/widgets/EntryList.svelte | 7 +++-- webui/src/components/widgets/Gallery.svelte | 5 ++- webui/src/i18n/en.json | 2 +- webui/src/util/mediatypes.ts | 3 +- webui/src/util/search.ts | 3 +- webui/src/views/Home.svelte | 5 +-- webui/src/views/Search.svelte | 7 +++-- webui/yarn.lock | 4 +-- 14 files changed, 79 insertions(+), 31 deletions(-) create mode 100644 tools/upend_js/constants.ts diff --git a/tools/upend_js/constants.ts b/tools/upend_js/constants.ts new file mode 100644 index 0000000..612f17f --- /dev/null +++ b/tools/upend_js/constants.ts @@ -0,0 +1,31 @@ +/** + * Attribute denoting (hierarchical) relation, in the "upwards" direction. For example, a file `IN` a group, an image `IN` photos, etc. + */ +export const ATTR_IN = "IN"; + +/** + * Attribute denoting that an entry belongs to the set relating to a given (hierarchical) relation. + * For example, a data blob may have a label entry, and to qualify that label within the context of belonging to a given hierarchical group, that label entry and the hierarchical entry will be linked with `BY`. + */ +export const ATTR_BY = "BY"; + +/** + * Attribute denoting that an attribute belongs to a given "tagging" entity. If an entity belongs to (`IN`) a "tagging" entity, it is expected to have attributes that are `OF` that entity. + */ +export const ATTR_OF = "OF"; + +/** + * Attribute denoting a human readable label. + */ +export const ATTR_LABEL = "LBL"; + +/** + * Attribute denoting the date & time an entity was noted in the database. + * (TODO: This info can be trivially derived from existing entry timestamps, while at the same time the "Introduction problem" is still open.) + */ +export const ATTR_ADDED = "ADDED"; + +/** + * Attribute for cross-vault unambiguous referencing of non-hashable (e.g. UUID) entities. + */ +export const ATTR_KEY = "KEY"; diff --git a/webui/src/components/Inspect.svelte b/webui/src/components/Inspect.svelte index 266936e..ff87c93 100644 --- a/webui/src/components/Inspect.svelte +++ b/webui/src/components/Inspect.svelte @@ -19,6 +19,7 @@ import EntryList from "./widgets/EntryList.svelte"; import api from "../lib/api"; import Gallery from "./widgets/Gallery.svelte"; + import { ATTR_IN, ATTR_LABEL, ATTR_KEY } from "upend/constants"; const dispatch = createEventDispatcher(); const params = useParams(); @@ -76,9 +77,9 @@ $: filteredUntypedAttributes = untypedAttributes.filter( (entry) => ![ - "LBL", - "OF", - "KEY", + ATTR_LABEL, + ATTR_IN, + ATTR_KEY, "NOTE", "LAST_VISITED", "NUM_VISITED", @@ -94,14 +95,14 @@ (editable ? $entity?.backlinks : $entity?.backlinks.filter( - (entry) => !["OF"].includes(entry.attribute) + (entry) => ![ATTR_IN].includes(entry.attribute) )) || []; - $: groups = ($entity?.attr["OF"] || []).map((e) => [ + $: groups = ($entity?.attr[ATTR_IN] || []).map((e) => [ e.value.c as string, e.address, ]); - $: tagged = $entity?.attr["~OF"] || []; + $: tagged = $entity?.attr[`~${ATTR_IN}`] || []; let attributesUsed: UpEntry[] = []; $: { @@ -149,7 +150,7 @@ await api.putEntry([ { entity: address, - attribute: "OF", + attribute: ATTR_IN, value: { t: "Address", c: String(groupToAdd.c), diff --git a/webui/src/components/display/BlobPreview.svelte b/webui/src/components/display/BlobPreview.svelte index d7cbaa5..ff89f34 100644 --- a/webui/src/components/display/BlobPreview.svelte +++ b/webui/src/components/display/BlobPreview.svelte @@ -10,6 +10,7 @@ import { getTypes } from "../../util/mediatypes"; import { formatDuration } from "../../util/fragments/time"; import { concurrentImage } from "../imageQueue"; + import { ATTR_IN } from "upend/constants"; const dispatch = createEventDispatcher(); export let address: string; @@ -38,14 +39,14 @@ let failedChildren: string[] = []; let loadedChildren: string[] = []; $: groupChildren = $entity?.backlinks - .filter((e) => e.attribute === "OF") + .filter((e) => e.attribute === ATTR_IN) .map((e) => String(e.entity)) .filter( (addr) => !failedChildren .slice( 0, - $entity?.backlinks.filter((e) => e.attribute === "OF").length - 4 + $entity?.backlinks.filter((e) => e.attribute === ATTR_IN).length - 4 ) .includes(addr) ) diff --git a/webui/src/components/display/blobs/AudioViewer.svelte b/webui/src/components/display/blobs/AudioViewer.svelte index 5a95ee6..1fa7602 100644 --- a/webui/src/components/display/blobs/AudioViewer.svelte +++ b/webui/src/components/display/blobs/AudioViewer.svelte @@ -11,6 +11,7 @@ import UpObject from "../../display/UpObject.svelte"; import Spinner from "../../utils/Spinner.svelte"; import { i18n } from "../../../i18n"; + import { ATTR_LABEL } from "upend/constants"; export let address: string; export let detail: boolean; @@ -51,7 +52,7 @@ color: annotation.get("COLOR") || DEFAULT_ANNOTATION_COLOR, attributes: { "upend-address": annotation.address, - label: annotation.get("LBL"), + label: annotation.get(ATTR_LABEL), }, data: (annotation.attr["NOTE"] || [])[0]?.value, ...fragment, @@ -92,7 +93,7 @@ } as any); // incorrect types, `update()` does take `attributes` } - await api.putEntityAttribute(entity, "LBL", { + await api.putEntityAttribute(entity, ATTR_LABEL, { t: "String", c: region.attributes["label"], }); diff --git a/webui/src/components/display/blobs/ImageViewer.svelte b/webui/src/components/display/blobs/ImageViewer.svelte index d0cf019..a02d811 100644 --- a/webui/src/components/display/blobs/ImageViewer.svelte +++ b/webui/src/components/display/blobs/ImageViewer.svelte @@ -6,6 +6,7 @@ import IconButton from "../../utils/IconButton.svelte"; import Spinner from "../../utils/Spinner.svelte"; import UpObject from "../UpObject.svelte"; + import { ATTR_LABEL } from "upend/constants"; export let address: string; export let editable: boolean; @@ -58,7 +59,7 @@ if (annotation.get("W3C_FRAGMENT_SELECTOR")) { anno.addAnnotation({ type: "Annotation", - body: annotation.attr["LBL"].map((e) => { + body: annotation.attr[ATTR_LABEL].map((e) => { return { type: "TextualBody", value: String(e.value.c), @@ -134,7 +135,7 @@ ...annotation.body.map((body) => { return { entity: uuid, - attribute: "LBL", + attribute: ATTR_LABEL, value: { t: "String", c: body.value, @@ -146,9 +147,9 @@ anno.on("updateAnnotation", async (annotation) => { const annotationObject = await api.fetchEntity(annotation.id); await Promise.all( - annotationObject.attr["LBL"] - .concat(annotationObject.attr["W3C_FRAGMENT_SELECTOR"]) - .map(async (e) => api.deleteEntry(e.address)) + annotationObject.attr[ATTR_LABEL].concat( + annotationObject.attr["W3C_FRAGMENT_SELECTOR"] + ).map(async (e) => api.deleteEntry(e.address)) ); await api.putEntry([ { @@ -162,7 +163,7 @@ ...annotation.body.map((body) => { return { entity: annotation.id, - attribute: "LBL", + attribute: ATTR_LABEL, value: { t: "String", c: body.value, diff --git a/webui/src/components/utils/Selector.svelte b/webui/src/components/utils/Selector.svelte index ac616fa..2afc502 100644 --- a/webui/src/components/utils/Selector.svelte +++ b/webui/src/components/utils/Selector.svelte @@ -10,6 +10,7 @@ const dispatch = createEventDispatcher(); import { matchSorter } from "match-sorter"; import api from "../../lib/api"; + import { ATTR_LABEL } from "upend/constants"; const MAX_OPTIONS = 25; @@ -150,7 +151,7 @@ } const validOptions = searchResult.entries - .filter((e) => e.attribute === "LBL") + .filter((e) => e.attribute === ATTR_LABEL) .filter((e) => !exactHits.includes(e.entity)); const sortedOptions = matchSorter(validOptions, inputValue, { @@ -197,7 +198,7 @@ entity: { t: "Attribute", c: option.attribute.name }, }); // Second, label it. - await api.putEntityAttribute(address, "LBL", { + await api.putEntityAttribute(address, ATTR_LABEL, { t: "String", c: option.labelToCreate, }); diff --git a/webui/src/components/widgets/EntryList.svelte b/webui/src/components/widgets/EntryList.svelte index 342afb4..d7444c1 100644 --- a/webui/src/components/widgets/EntryList.svelte +++ b/webui/src/components/widgets/EntryList.svelte @@ -17,6 +17,7 @@ import { formatDuration } from "../../util/fragments/time"; import { i18n } from "../../i18n"; import UpLink from "../display/UpLink.svelte"; + import { ATTR_ADDED, ATTR_LABEL } from "upend/constants"; const dispatch = createEventDispatcher(); export let columns: string | undefined = undefined; @@ -87,7 +88,9 @@ const addressesString = addresses.map((addr) => `@${addr}`).join(" "); - labelListing = query(`(matches (in ${addressesString}) "LBL" ? )`).result; + labelListing = query( + `(matches (in ${addressesString}) "${ATTR_LABEL}" ? )` + ).result; } // Sorting @@ -159,7 +162,7 @@ switch (attribute) { case "FILE_SIZE": return filesize(parseInt(String(value), 10), { base: 2 }); - case "ADDED": + case ATTR_ADDED: case "LAST_VISITED": return formatRelative( fromUnixTime(parseInt(String(value), 10)), diff --git a/webui/src/components/widgets/Gallery.svelte b/webui/src/components/widgets/Gallery.svelte index 4414d4e..42683d7 100644 --- a/webui/src/components/widgets/Gallery.svelte +++ b/webui/src/components/widgets/Gallery.svelte @@ -5,6 +5,7 @@ import { query } from "../../lib/entity"; import UpObject from "../display/UpObject.svelte"; import UpObjectCard from "../display/UpObjectCard.svelte"; + import { ATTR_LABEL } from "upend/constants"; export let entities: Address[]; export let thumbnails = true; @@ -49,7 +50,9 @@ const addressesString = addresses.map((addr) => `@${addr}`).join(" "); - labelListing = query(`(matches (in ${addressesString}) "LBL" ? )`).result; + labelListing = query( + `(matches (in ${addressesString}) "${ATTR_LABEL}" ? )` + ).result; } function sortEntities() { diff --git a/webui/src/i18n/en.json b/webui/src/i18n/en.json index 910268b..0715079 100644 --- a/webui/src/i18n/en.json +++ b/webui/src/i18n/en.json @@ -5,7 +5,7 @@ "ADDED": "Added at", "LAST_VISITED": "Last visited at", "NUM_VISITED": "Times visited", - "LBL": "Label", + "ATTR_LABEL": "Label", "IS": "Type", "TYPE": "Type ID", "MEDIA_DURATION": "Duration" diff --git a/webui/src/util/mediatypes.ts b/webui/src/util/mediatypes.ts index 7352bb5..350c52a 100644 --- a/webui/src/util/mediatypes.ts +++ b/webui/src/util/mediatypes.ts @@ -1,5 +1,6 @@ import type { EntityInfo } from "upend/types"; import type { UpObject } from "upend"; +import { ATTR_IN } from "upend/constants"; export function getTypes(entity: UpObject, entityInfo: EntityInfo) { const mimeType = String(entity?.get("FILE_MIME")); @@ -22,7 +23,7 @@ export function getTypes(entity: UpObject, entityInfo: EntityInfo) { const web = entityInfo?.t == "Url"; const fragment = Boolean(entity?.get("ANNOTATES")); - const group = entity?.backlinks.some((e) => e.attribute == "OF"); + const group = entity?.backlinks.some((e) => e.attribute == ATTR_IN); return { mimeType, diff --git a/webui/src/util/search.ts b/webui/src/util/search.ts index 4b86b9f..23b1f91 100644 --- a/webui/src/util/search.ts +++ b/webui/src/util/search.ts @@ -1,6 +1,7 @@ import type { PutInput } from "upend/types"; import { query as queryFn } from "../lib/entity"; import api from "../lib/api"; +import { ATTR_LABEL } from "upend/constants"; export function baseSearch(query: string) { return queryFn( @@ -26,7 +27,7 @@ export async function createLabelled(label: string) { } else { // TODO - don't create invariants, create UUIDs instead, maybe with keys? body = { - attribute: "LBL", + attribute: ATTR_LABEL, value: { t: "String", c: label, diff --git a/webui/src/views/Home.svelte b/webui/src/views/Home.svelte index a0f849d..318ad6e 100644 --- a/webui/src/views/Home.svelte +++ b/webui/src/views/Home.svelte @@ -12,12 +12,13 @@ import { vaultInfo } from "../util/info"; import { updateTitle } from "../util/title"; import { i18n } from "../i18n"; + import { ATTR_ADDED, ATTR_LABEL } from "upend/constants"; const roots = (async () => { const data = await api.fetchRoots(); const listing = new UpListing(data); return Object.values(listing.objects) - .filter((obj) => Boolean(obj.attr["LBL"])) + .filter((obj) => Boolean(obj.attr[ATTR_LABEL])) .map((obj) => [obj.address, obj.identify().join(" | ")]) .sort(([_, i1], [__, i2]) => i1.localeCompare(i2)); })(); @@ -34,7 +35,7 @@ .sort((a, b) => (b.value.c as number) - (a.value.c as number)) .slice(0, 25); - const { result: latestQuery } = query(`(matches ? "ADDED" ?)`); + const { result: latestQuery } = query(`(matches ? "${ATTR_ADDED}" ?)`); $: latest = ($latestQuery?.entries || []) .filter((e) => e.value.t == "Number") .sort((a, b) => (b.value.c as number) - (a.value.c as number)) diff --git a/webui/src/views/Search.svelte b/webui/src/views/Search.svelte index 1e260d5..232f422 100644 --- a/webui/src/views/Search.svelte +++ b/webui/src/views/Search.svelte @@ -13,6 +13,7 @@ import api from "../lib/api"; import Gallery from "../components/widgets/Gallery.svelte"; import { matchSorter } from "match-sorter"; + import { ATTR_LABEL } from "upend/constants"; const navigate = useNavigate(); export let query: string; @@ -35,7 +36,9 @@ exactHits = []; } - $: objects = ($result?.entries || []).filter((e) => e.attribute === "LBL"); + $: objects = ($result?.entries || []).filter( + (e) => e.attribute === ATTR_LABEL + ); $: sortedObjects = matchSorter(objects, debouncedQuery, { keys: ["value.c"], }); @@ -44,7 +47,7 @@ $: { const addressesString = objects.map((e) => `@${e.entity}`).join(" "); api - .query(`(matches (in ${addressesString}) "LBL" ? )`) + .query(`(matches (in ${addressesString}) "${ATTR_LABEL}" ? )`) .then((labelListing) => { exactHits = labelListing.entries .filter( diff --git a/webui/yarn.lock b/webui/yarn.lock index da6e591..17d189c 100644 --- a/webui/yarn.lock +++ b/webui/yarn.lock @@ -12585,11 +12585,11 @@ __metadata: "upend@file:../tools/upend_js::locator=upend-kestrel%40workspace%3A.": version: 0.0.1 - resolution: "upend@file:../tools/upend_js#../tools/upend_js::hash=88616b&locator=upend-kestrel%40workspace%3A." + resolution: "upend@file:../tools/upend_js#../tools/upend_js::hash=cda57f&locator=upend-kestrel%40workspace%3A." dependencies: debug: ^4.3.4 lru-cache: ^7.0.0 - checksum: c73ce133f42c9669f15b5d38b2d552722d9df56ec1daa61d31b41d8a0ec6c9064a9424c6e5589d53edeebfc75c447464f10110539b8237c19bf9597987bd6d06 + checksum: 551abb5f6c2d07e1350993d27ca835fea005172ad66889e41fa5a9793ad414788ecfce2c966f526d3347d08e1731f1945c695e95aae15dd334ca17b1bc1fd195 languageName: node linkType: hard