upend/ui/src/components/Inspect.svelte

160 lines
3.7 KiB
Svelte
Raw Normal View History

2021-11-11 23:37:42 +01:00
<script lang="ts">
import AttributeView from "./AttributeView.svelte";
import { query, useEntity } from "../lib/entity";
import Address from "./Address.svelte";
import { UpType } from "../lib/types";
import type { IEntry } from "upend/types";
export let address: string;
export let editable = false;
const { error, revalidate, attributes, backlinks } = useEntity(address);
$: allTypeAddresses = $attributes
.map(([_, attr]) => attr)
.filter((attr) => attr.attribute == "IS")
.map((attr) => attr.value.c);
$: allTypeEntries = query(
() =>
`(matches (in ${allTypeAddresses
.map((addr) => `"${addr}"`)
.join(" ")}) ? ?)`
).result;
let allTypes: { [key: string]: UpType } = {};
$: {
allTypes = {};
$allTypeEntries.forEach(([_, entry]) => {
if (allTypes[entry.entity] === undefined) {
allTypes[entry.entity] = new UpType(entry.entity);
}
switch (entry.attribute) {
case "TYPE":
allTypes[entry.entity].name = entry.value.c;
break;
case "TYPE_HAS":
case "TYPE_REQUIRES":
case "TYPE_ID":
allTypes[entry.entity].attributes.push(entry.value.c);
break;
}
});
allTypes = allTypes;
}
let typedAttributes = {} as { [key: string]: [string, IEntry][] };
let untypedAttributes = [] as [string, IEntry][];
$: {
typedAttributes = {};
untypedAttributes = [];
$attributes.forEach(([entryAddr, entry]) => {
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] = [];
}
typedAttributes[addr].push([entryAddr, entry]);
});
} else {
untypedAttributes.push([entryAddr, entry]);
}
});
typedAttributes = typedAttributes;
untypedAttributes = untypedAttributes;
}
$: filteredUntypedAttributes = untypedAttributes.filter(
([_, entry]) =>
entry.attribute !== "IS" ||
!Object.keys(typedAttributes).includes(entry.value.c)
);
</script>
<div class="inspect">
<h2>
<Address
{address}
isFile={$backlinks.some(([_, e]) => e.attribute === "FILE_IS")}
/>
</h2>
<blob-preview :address="address" />
{#if !$error}
<div>
{#each Object.entries(typedAttributes) as [typeAddr, attributes] (typeAddr)}
<AttributeView
{editable}
{address}
type={allTypes[typeAddr]}
{attributes}
on:edit={revalidate}
/>
{/each}
{#if filteredUntypedAttributes.length > 0 || editable}
<AttributeView
title="Other attributes"
{editable}
{address}
attributes={untypedAttributes}
on:change={revalidate}
/>
{/if}
{#if $backlinks.length > 0}
<AttributeView
title={`Referred to (${$backlinks.length})`}
{address}
attributes={$backlinks}
reverse
/>
{/if}
</div>
{:else}
<div class="error">
{JSON.stringify($error)}
</div>
{/if}
</div>
<style scoped lang="scss">
.hr {
position: relative;
margin: 2rem 0 1rem 0;
hr {
border: none;
border-top: 4px double var(--foreground);
height: 1rem;
}
.hr-label {
position: absolute;
top: -1ex;
left: 50%;
transform: translateX(-50%);
font-weight: bold;
font-size: 18px;
color: var(--foreground);
background: var(--background);
padding: 0 4px;
sl-icon {
margin-bottom: -4px;
}
}
}
.error {
color: red;
}
</style>