2021-11-11 23:37:42 +01:00
|
|
|
<script lang="ts">
|
|
|
|
import AttributeView from "./AttributeView.svelte";
|
|
|
|
import { query, useEntity } from "../lib/entity";
|
2021-12-21 20:02:47 +01:00
|
|
|
import UpObject from "./display/UpObject.svelte";
|
2021-11-11 23:37:42 +01:00
|
|
|
import { UpType } from "../lib/types";
|
2021-12-21 20:02:47 +01:00
|
|
|
import BlobPreview from "./display/BlobPreview.svelte";
|
2021-12-02 23:27:09 +01:00
|
|
|
import { setContext } from "svelte";
|
|
|
|
import { writable } from "svelte/store";
|
2021-12-19 13:54:16 +01:00
|
|
|
import type { UpEntry } from "upend";
|
2022-01-21 15:57:53 +01:00
|
|
|
import Spinner from "./utils/Spinner.svelte";
|
2022-01-22 20:19:26 +01:00
|
|
|
import NotesEditor from "./utils/NotesEditor.svelte";
|
|
|
|
import type { AttributeChange } from "../types/base";
|
2021-11-11 23:37:42 +01:00
|
|
|
|
|
|
|
export let address: string;
|
2021-12-02 23:27:09 +01:00
|
|
|
export let index: number | undefined;
|
2021-11-11 23:37:42 +01:00
|
|
|
export let editable = false;
|
|
|
|
|
2021-12-02 23:27:09 +01:00
|
|
|
let indexStore = writable(index);
|
|
|
|
$: $indexStore = index;
|
|
|
|
|
|
|
|
setContext("browse", { index: indexStore });
|
|
|
|
|
2021-12-19 13:54:16 +01:00
|
|
|
$: ({ entity, error, revalidate } = useEntity(address));
|
2021-11-11 23:37:42 +01:00
|
|
|
|
2021-12-19 13:54:16 +01:00
|
|
|
$: allTypeAddresses = ($entity?.attr["IS"] || []).map((attr) => attr.value.c);
|
2021-11-11 23:37:42 +01:00
|
|
|
|
|
|
|
$: allTypeEntries = query(
|
|
|
|
() =>
|
|
|
|
`(matches (in ${allTypeAddresses
|
|
|
|
.map((addr) => `"${addr}"`)
|
|
|
|
.join(" ")}) ? ?)`
|
|
|
|
).result;
|
|
|
|
|
|
|
|
let allTypes: { [key: string]: UpType } = {};
|
|
|
|
$: {
|
|
|
|
allTypes = {};
|
2021-12-19 13:54:16 +01:00
|
|
|
($allTypeEntries?.entries || []).forEach((entry) => {
|
2021-11-11 23:37:42 +01:00
|
|
|
if (allTypes[entry.entity] === undefined) {
|
|
|
|
allTypes[entry.entity] = new UpType(entry.entity);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (entry.attribute) {
|
|
|
|
case "TYPE":
|
2021-12-19 13:54:16 +01:00
|
|
|
allTypes[entry.entity].name = String(entry.value.c);
|
2021-11-11 23:37:42 +01:00
|
|
|
break;
|
|
|
|
case "TYPE_HAS":
|
2021-12-19 13:54:16 +01:00
|
|
|
allTypes[entry.entity].attributes.push(String(entry.value.c));
|
2021-11-11 23:37:42 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
allTypes = allTypes;
|
|
|
|
}
|
|
|
|
|
2021-12-19 13:54:16 +01:00
|
|
|
let typedAttributes = {} as { [key: string]: UpEntry[] };
|
|
|
|
let untypedAttributes = [] as UpEntry[];
|
2021-11-11 23:37:42 +01:00
|
|
|
|
|
|
|
$: {
|
|
|
|
typedAttributes = {};
|
|
|
|
untypedAttributes = [];
|
|
|
|
|
2021-12-19 13:54:16 +01:00
|
|
|
($entity?.attributes || []).forEach((entry) => {
|
2021-11-11 23:37:42 +01:00
|
|
|
const entryTypes = Object.entries(allTypes).filter(([_, t]) =>
|
|
|
|
t.attributes.includes(entry.attribute)
|
|
|
|
);
|
|
|
|
if (entryTypes.length > 0) {
|
|
|
|
entryTypes.forEach(([addr, _]) => {
|
|
|
|
if (typedAttributes[addr] == undefined) {
|
|
|
|
typedAttributes[addr] = [];
|
|
|
|
}
|
2021-12-19 13:54:16 +01:00
|
|
|
typedAttributes[addr].push(entry);
|
2021-11-11 23:37:42 +01:00
|
|
|
});
|
|
|
|
} else {
|
2021-12-19 13:54:16 +01:00
|
|
|
untypedAttributes.push(entry);
|
2021-11-11 23:37:42 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
typedAttributes = typedAttributes;
|
2022-01-21 15:57:53 +01:00
|
|
|
untypedAttributes = untypedAttributes;
|
2021-11-11 23:37:42 +01:00
|
|
|
}
|
2022-01-21 15:57:53 +01:00
|
|
|
|
|
|
|
$: filteredUntypedAttributes = untypedAttributes.filter(
|
2022-01-23 11:31:58 +01:00
|
|
|
(entry) => !["IS", "LBL", "NOTE"].includes(entry.attribute)
|
2022-01-21 15:57:53 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$: currentUntypedAttributes = editable
|
|
|
|
? untypedAttributes
|
|
|
|
: filteredUntypedAttributes;
|
2022-01-22 20:19:26 +01:00
|
|
|
|
|
|
|
async function onChange(ev: CustomEvent<AttributeChange>) {
|
|
|
|
const change = ev.detail;
|
|
|
|
switch (change.type) {
|
|
|
|
case "create":
|
|
|
|
await fetch(`/api/obj`, {
|
|
|
|
method: "PUT",
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
body: JSON.stringify({
|
|
|
|
entity: address,
|
|
|
|
attribute: change.attribute,
|
|
|
|
value: change.value,
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
case "delete":
|
|
|
|
await fetch(`/api/obj/${change.address}`, { method: "DELETE" });
|
|
|
|
break;
|
|
|
|
case "update":
|
|
|
|
// TODO
|
|
|
|
await fetch(`/api/obj/${change.address}`, { method: "DELETE" });
|
|
|
|
await fetch(`/api/obj`, {
|
|
|
|
method: "PUT",
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
body: JSON.stringify({
|
|
|
|
entity: address,
|
|
|
|
attribute: change.attribute,
|
|
|
|
value: change.value,
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
console.error("Unimplemented AttributeChange", change);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
revalidate();
|
|
|
|
}
|
2021-11-11 23:37:42 +01:00
|
|
|
</script>
|
|
|
|
|
|
|
|
<div class="inspect">
|
|
|
|
<h2>
|
2021-12-19 19:20:09 +01:00
|
|
|
{#if $entity}
|
2021-12-21 18:47:54 +01:00
|
|
|
<UpObject banner {address} />
|
2021-12-20 13:41:06 +01:00
|
|
|
{:else}
|
2021-12-30 19:28:43 +01:00
|
|
|
<Spinner />
|
2021-12-19 19:20:09 +01:00
|
|
|
{/if}
|
2021-11-11 23:37:42 +01:00
|
|
|
</h2>
|
2021-11-30 23:26:40 +01:00
|
|
|
<BlobPreview {address} />
|
2022-01-22 20:19:26 +01:00
|
|
|
<NotesEditor {address} {editable} on:change={onChange} />
|
2021-11-11 23:37:42 +01:00
|
|
|
{#if !$error}
|
2021-12-20 13:41:06 +01:00
|
|
|
{#if Boolean($allTypeEntries)}
|
|
|
|
<div class="attributes">
|
|
|
|
{#each Object.entries(typedAttributes) as [typeAddr, entries] (typeAddr)}
|
|
|
|
<AttributeView
|
|
|
|
{entries}
|
|
|
|
type={allTypes[typeAddr]}
|
|
|
|
{editable}
|
2022-01-22 20:19:26 +01:00
|
|
|
on:change={onChange}
|
2021-12-20 13:41:06 +01:00
|
|
|
/>
|
|
|
|
{/each}
|
|
|
|
|
2022-01-21 15:57:53 +01:00
|
|
|
{#if currentUntypedAttributes.length > 0 || editable}
|
2021-12-20 13:41:06 +01:00
|
|
|
<AttributeView
|
|
|
|
title="Other attributes"
|
|
|
|
{editable}
|
2022-01-21 15:57:53 +01:00
|
|
|
entries={currentUntypedAttributes}
|
2022-01-22 20:19:26 +01:00
|
|
|
on:change={onChange}
|
2021-12-20 13:41:06 +01:00
|
|
|
/>
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
{#if $entity?.backlinks.length > 0}
|
|
|
|
<AttributeView
|
|
|
|
title={`Referred to (${$entity.backlinks.length})`}
|
|
|
|
entries={$entity.backlinks}
|
|
|
|
reverse
|
2022-01-22 20:19:26 +01:00
|
|
|
on:change={onChange}
|
2021-12-20 13:41:06 +01:00
|
|
|
/>
|
|
|
|
{/if}
|
|
|
|
</div>
|
|
|
|
{:else}
|
2021-12-30 19:28:43 +01:00
|
|
|
<Spinner />
|
2021-12-20 13:41:06 +01:00
|
|
|
{/if}
|
2021-11-11 23:37:42 +01:00
|
|
|
{:else}
|
|
|
|
<div class="error">
|
|
|
|
{JSON.stringify($error)}
|
|
|
|
</div>
|
|
|
|
{/if}
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
2021-11-30 00:29:27 +01:00
|
|
|
.inspect {
|
|
|
|
flex: auto;
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
2022-01-22 20:19:26 +01:00
|
|
|
gap: 1rem;
|
|
|
|
|
|
|
|
h2 {
|
|
|
|
margin-bottom: 0;
|
|
|
|
}
|
2021-11-30 00:29:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
.attributes {
|
|
|
|
flex: auto;
|
|
|
|
height: 0; // https://stackoverflow.com/a/14964944
|
|
|
|
overflow-y: auto;
|
|
|
|
}
|
|
|
|
|
2021-11-11 23:37:42 +01:00
|
|
|
.error {
|
|
|
|
color: red;
|
|
|
|
}
|
|
|
|
</style>
|