wip(webui): use (new) attr constants

feat/type-attributes
Tomáš Mládek 2023-06-24 16:26:14 +02:00
parent 0eec69b219
commit 641f42f785
14 changed files with 79 additions and 31 deletions

View File

@ -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";

View File

@ -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),

View File

@ -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)
)

View File

@ -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"],
});

View File

@ -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,

View File

@ -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,
});

View File

@ -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)),

View File

@ -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() {

View File

@ -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"

View File

@ -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,

View File

@ -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,

View File

@ -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))

View File

@ -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(

View File

@ -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