2021-11-11 23:37:42 +01:00
|
|
|
<script lang="ts">
|
2023-06-19 11:53:35 +02:00
|
|
|
import EntryView, { type Widget } from "./EntryView.svelte";
|
2023-06-28 14:26:34 +02:00
|
|
|
import { useEntity } from "../lib/entity";
|
2022-03-22 21:57:00 +01:00
|
|
|
import UpObject from "./display/UpObject.svelte";
|
2023-10-22 21:03:51 +02:00
|
|
|
import { createEventDispatcher } from "svelte";
|
|
|
|
import { derived, type Readable } from "svelte/store";
|
2023-10-07 11:06:45 +02:00
|
|
|
import type { UpEntry } from "@upnd/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";
|
2023-09-07 18:57:45 +02:00
|
|
|
import type { WidgetChange } from "../types/base";
|
2023-10-07 11:06:45 +02:00
|
|
|
import type { EntityInfo } from "@upnd/upend/types";
|
2022-01-30 16:40:48 +01:00
|
|
|
import IconButton from "./utils/IconButton.svelte";
|
2023-10-22 21:03:51 +02:00
|
|
|
import { Link } from "svelte-navigator";
|
2022-03-18 21:27:24 +01:00
|
|
|
import BlobViewer from "./display/BlobViewer.svelte";
|
2022-10-25 21:47:17 +02:00
|
|
|
import { i18n } from "../i18n";
|
2023-01-07 11:00:55 +01:00
|
|
|
import EntryList from "./widgets/EntryList.svelte";
|
2023-05-22 20:57:06 +02:00
|
|
|
import api from "../lib/api";
|
2023-09-07 15:40:20 +02:00
|
|
|
import EntityList from "./widgets/EntityList.svelte";
|
2023-10-22 13:56:27 +02:00
|
|
|
import {
|
|
|
|
ATTR_IN,
|
|
|
|
ATTR_LABEL,
|
|
|
|
ATTR_KEY,
|
|
|
|
ATTR_OF,
|
|
|
|
} from "@upnd/upend/constants";
|
2023-07-29 11:21:34 +02:00
|
|
|
import InspectGroups from "./InspectGroups.svelte";
|
2023-07-29 19:50:00 +02:00
|
|
|
import InspectTypeEditor from "./InspectTypeEditor.svelte";
|
2023-09-05 20:57:01 +02:00
|
|
|
import LabelBorder from "./utils/LabelBorder.svelte";
|
2023-09-09 12:09:56 +02:00
|
|
|
import { debug } from "debug";
|
|
|
|
const dbg = debug("kestrel:Inspect");
|
2023-08-02 21:11:43 +02:00
|
|
|
|
2022-02-20 18:04:47 +01:00
|
|
|
const dispatch = createEventDispatcher();
|
2021-11-11 23:37:42 +01:00
|
|
|
|
|
|
|
export let address: string;
|
2022-02-12 23:23:04 +01:00
|
|
|
export let detail: boolean;
|
2023-04-23 14:11:19 +02:00
|
|
|
let showAsEntries = false;
|
2023-05-03 16:21:03 +02:00
|
|
|
let highlightedType: string | undefined;
|
2021-11-11 23:37:42 +01:00
|
|
|
|
2022-03-25 14:11:00 +01:00
|
|
|
let blobHandled = false;
|
|
|
|
|
2023-01-07 11:00:55 +01:00
|
|
|
$: ({ entity, entityInfo, error, revalidate } = useEntity(address));
|
2021-11-11 23:37:42 +01:00
|
|
|
|
2023-06-28 14:26:34 +02:00
|
|
|
$: allTypes = derived(
|
|
|
|
entityInfo,
|
|
|
|
($entityInfo, set) => {
|
|
|
|
getAllTypes($entityInfo).then((allTypes) => {
|
|
|
|
set(allTypes);
|
|
|
|
});
|
|
|
|
},
|
2023-08-01 22:02:52 +02:00
|
|
|
{},
|
2023-06-28 14:26:34 +02:00
|
|
|
) as Readable<{
|
|
|
|
[key: string]: {
|
|
|
|
labels: string[];
|
|
|
|
attributes: string[];
|
|
|
|
};
|
|
|
|
}>;
|
|
|
|
|
|
|
|
async function getAllTypes(entityInfo: EntityInfo) {
|
|
|
|
const allTypes = {};
|
|
|
|
|
|
|
|
if (!entityInfo) {
|
|
|
|
return {};
|
|
|
|
}
|
2021-11-11 23:37:42 +01:00
|
|
|
|
2023-06-28 14:26:34 +02:00
|
|
|
const typeAddresses: string[] = [
|
|
|
|
await api.getAddress(entityInfo.t),
|
2023-07-29 12:39:23 +02:00
|
|
|
...($entity?.attr[ATTR_IN] || []).map((e) => e.value.c as string),
|
2023-06-28 14:26:34 +02:00
|
|
|
];
|
|
|
|
const typeAddressesIn = typeAddresses.map((addr) => `@${addr}`).join(" ");
|
2021-11-11 23:37:42 +01:00
|
|
|
|
2023-06-28 14:26:34 +02:00
|
|
|
const labelsQuery = await api.query(
|
2023-08-01 22:02:52 +02:00
|
|
|
`(matches (in ${typeAddressesIn}) "${ATTR_LABEL}" ?)`,
|
2023-06-28 14:26:34 +02:00
|
|
|
);
|
2023-07-30 17:02:33 +02:00
|
|
|
|
|
|
|
typeAddresses.forEach((address) => {
|
2023-07-30 17:02:52 +02:00
|
|
|
let labels = labelsQuery.getObject(address).identify();
|
2023-06-28 18:50:33 +02:00
|
|
|
|
2023-07-30 17:02:52 +02:00
|
|
|
let typeLabel: string | undefined;
|
|
|
|
if (typeLabel) {
|
|
|
|
labels.unshift(typeLabel);
|
|
|
|
}
|
2023-06-28 18:50:33 +02:00
|
|
|
|
2023-07-30 17:02:52 +02:00
|
|
|
allTypes[address] = {
|
|
|
|
labels,
|
|
|
|
attributes: [],
|
|
|
|
};
|
2023-07-30 17:02:33 +02:00
|
|
|
});
|
2021-11-11 23:37:42 +01:00
|
|
|
|
2023-06-28 14:26:34 +02:00
|
|
|
const attributes = await api.query(
|
2023-08-01 22:02:52 +02:00
|
|
|
`(matches ? "${ATTR_OF}" (in ${typeAddressesIn}))`,
|
2023-06-28 14:26:34 +02:00
|
|
|
);
|
|
|
|
await Promise.all(
|
|
|
|
typeAddresses.map(async (address) => {
|
|
|
|
allTypes[address].attributes = (
|
|
|
|
await Promise.all(
|
|
|
|
(attributes.getObject(address).attr[`~${ATTR_OF}`] || []).map(
|
|
|
|
async (e) => {
|
|
|
|
try {
|
|
|
|
const { t, c } = await api.addressToComponents(e.entity);
|
|
|
|
if (t == "Attribute") {
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
console.error(err);
|
|
|
|
return false;
|
|
|
|
}
|
2023-08-01 22:02:52 +02:00
|
|
|
},
|
|
|
|
),
|
2023-06-28 14:26:34 +02:00
|
|
|
)
|
|
|
|
).filter(Boolean);
|
2023-08-01 22:02:52 +02:00
|
|
|
}),
|
2023-06-28 14:26:34 +02:00
|
|
|
);
|
2021-11-11 23:37:42 +01:00
|
|
|
|
2023-08-27 20:45:01 +02:00
|
|
|
const result = {};
|
|
|
|
Object.keys(allTypes).forEach((addr) => {
|
|
|
|
if (allTypes[addr].attributes.length > 0) {
|
|
|
|
result[addr] = allTypes[addr];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return result;
|
2021-11-11 23:37:42 +01:00
|
|
|
}
|
|
|
|
|
2023-09-03 11:08:24 +02:00
|
|
|
let untypedProperties = [] as UpEntry[];
|
2023-07-16 20:20:56 +02:00
|
|
|
let untypedLinks = [] as UpEntry[];
|
2021-11-11 23:37:42 +01:00
|
|
|
|
|
|
|
$: {
|
2023-09-03 11:08:24 +02:00
|
|
|
untypedProperties = [];
|
2023-07-16 20:20:56 +02:00
|
|
|
untypedLinks = [];
|
2021-11-11 23:37:42 +01:00
|
|
|
|
2021-12-19 13:54:16 +01:00
|
|
|
($entity?.attributes || []).forEach((entry) => {
|
2023-06-28 14:26:34 +02:00
|
|
|
const entryTypes = Object.entries($allTypes || {}).filter(([_, t]) =>
|
2023-08-01 22:02:52 +02:00
|
|
|
t.attributes.includes(entry.attribute),
|
2021-11-11 23:37:42 +01:00
|
|
|
);
|
2023-08-27 20:45:01 +02:00
|
|
|
if (entryTypes.length === 0) {
|
2023-07-16 20:20:56 +02:00
|
|
|
if (entry.value.t === "Address") {
|
|
|
|
untypedLinks.push(entry);
|
|
|
|
} else {
|
2023-09-03 11:08:24 +02:00
|
|
|
untypedProperties.push(entry);
|
2023-07-16 20:20:56 +02:00
|
|
|
}
|
2021-11-11 23:37:42 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-09-03 11:08:24 +02:00
|
|
|
untypedProperties = untypedProperties;
|
2023-07-16 20:20:56 +02:00
|
|
|
untypedLinks = untypedLinks;
|
2021-11-11 23:37:42 +01:00
|
|
|
}
|
2022-01-21 15:57:53 +01:00
|
|
|
|
2023-09-03 11:08:24 +02:00
|
|
|
$: filteredUntypedProperties = untypedProperties.filter(
|
2022-03-20 11:21:36 +01:00
|
|
|
(entry) =>
|
2022-03-22 21:57:00 +01:00
|
|
|
![
|
2023-06-24 16:26:14 +02:00
|
|
|
ATTR_LABEL,
|
|
|
|
ATTR_IN,
|
|
|
|
ATTR_KEY,
|
2022-03-22 21:57:00 +01:00
|
|
|
"NOTE",
|
|
|
|
"LAST_VISITED",
|
|
|
|
"NUM_VISITED",
|
|
|
|
"LAST_ATTRIBUTE_WIDGET",
|
2023-08-01 22:02:52 +02:00
|
|
|
].includes(entry.attribute),
|
2022-01-21 15:57:53 +01:00
|
|
|
);
|
|
|
|
|
2023-09-03 11:08:24 +02:00
|
|
|
$: currentUntypedProperties = filteredUntypedProperties;
|
2022-01-22 20:19:26 +01:00
|
|
|
|
2023-07-16 20:20:56 +02:00
|
|
|
$: filteredUntypedLinks = untypedLinks.filter(
|
2023-08-01 22:02:52 +02:00
|
|
|
(entry) => ![ATTR_IN, ATTR_OF].includes(entry.attribute),
|
2023-07-16 20:20:56 +02:00
|
|
|
);
|
|
|
|
|
2023-09-01 19:52:49 +02:00
|
|
|
$: currentUntypedLinks = filteredUntypedLinks;
|
2023-07-16 20:20:56 +02:00
|
|
|
|
2022-01-28 22:39:08 +01:00
|
|
|
$: currentBacklinks =
|
2023-09-01 19:52:49 +02:00
|
|
|
$entity?.backlinks.filter(
|
|
|
|
(entry) => ![ATTR_IN, ATTR_OF].includes(entry.attribute),
|
|
|
|
) || [];
|
2022-01-28 22:39:08 +01:00
|
|
|
|
2023-06-24 16:26:14 +02:00
|
|
|
$: tagged = $entity?.attr[`~${ATTR_IN}`] || [];
|
2022-01-28 22:39:08 +01:00
|
|
|
|
2023-01-07 11:00:55 +01:00
|
|
|
let attributesUsed: UpEntry[] = [];
|
|
|
|
$: {
|
|
|
|
if ($entityInfo?.t === "Attribute") {
|
2023-05-22 20:57:06 +02:00
|
|
|
api
|
|
|
|
.query(`(matches ? "${$entityInfo.c}" ?)`)
|
|
|
|
.then((result) => (attributesUsed = result.entries));
|
2023-01-07 11:00:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-07 18:57:45 +02:00
|
|
|
async function onChange(ev: CustomEvent<WidgetChange>) {
|
2023-09-09 12:09:56 +02:00
|
|
|
dbg("onChange", ev.detail);
|
2022-01-22 20:19:26 +01:00
|
|
|
const change = ev.detail;
|
|
|
|
switch (change.type) {
|
|
|
|
case "create":
|
2023-05-22 20:57:06 +02:00
|
|
|
await api.putEntry({
|
2022-02-20 13:06:01 +01:00
|
|
|
entity: address,
|
|
|
|
attribute: change.attribute,
|
|
|
|
value: change.value,
|
2022-01-22 20:19:26 +01:00
|
|
|
});
|
|
|
|
break;
|
|
|
|
case "delete":
|
2023-05-22 20:57:06 +02:00
|
|
|
await api.deleteEntry(change.address);
|
2022-01-22 20:19:26 +01:00
|
|
|
break;
|
|
|
|
case "update":
|
2023-05-22 20:57:06 +02:00
|
|
|
await api.putEntityAttribute(address, change.attribute, change.value);
|
2022-01-22 20:19:26 +01:00
|
|
|
break;
|
2023-09-07 18:57:45 +02:00
|
|
|
case "entry-add":
|
|
|
|
await api.putEntry({
|
2023-09-07 21:55:16 +02:00
|
|
|
entity: change.address,
|
2023-09-07 18:57:45 +02:00
|
|
|
attribute: ATTR_IN,
|
2023-09-07 21:55:16 +02:00
|
|
|
value: { t: "Address", c: address },
|
2023-09-07 18:57:45 +02:00
|
|
|
});
|
|
|
|
break;
|
|
|
|
case "entry-delete": {
|
|
|
|
const inEntry = $entity?.attr[`~${ATTR_IN}`].find(
|
|
|
|
(e) => e.entity === change.address,
|
|
|
|
);
|
|
|
|
if (inEntry) {
|
|
|
|
await api.deleteEntry(inEntry.address);
|
|
|
|
} else {
|
|
|
|
console.warn(
|
|
|
|
"Couldn't find IN entry for entity %s?!",
|
|
|
|
change.address,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2022-01-22 20:19:26 +01:00
|
|
|
default:
|
|
|
|
console.error("Unimplemented AttributeChange", change);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
revalidate();
|
|
|
|
}
|
2022-01-30 16:30:14 +01:00
|
|
|
|
2022-02-20 18:04:47 +01:00
|
|
|
let identities = [address];
|
2023-08-02 21:11:43 +02:00
|
|
|
|
2022-02-20 18:04:47 +01:00
|
|
|
function onResolved(ev: CustomEvent<string[]>) {
|
|
|
|
identities = ev.detail;
|
|
|
|
dispatch("resolved", ev.detail);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function deleteObject() {
|
2022-10-25 21:47:17 +02:00
|
|
|
if (confirm(`${$i18n.t("Really delete")} "${identities.join(" | ")}"?`)) {
|
2023-05-22 20:57:06 +02:00
|
|
|
await api.deleteEntry(address);
|
2022-02-20 18:04:47 +01:00
|
|
|
dispatch("close");
|
|
|
|
}
|
|
|
|
}
|
2022-03-20 11:21:36 +01:00
|
|
|
|
2023-06-19 11:53:35 +02:00
|
|
|
const attributeWidgets: Widget[] = [
|
|
|
|
{
|
|
|
|
name: "List",
|
2023-06-19 12:58:42 +02:00
|
|
|
icon: "list-check",
|
2023-08-28 18:14:06 +02:00
|
|
|
components: ({ entries }) => [
|
2023-06-19 11:53:35 +02:00
|
|
|
{
|
|
|
|
component: EntryList,
|
|
|
|
props: {
|
|
|
|
entries,
|
|
|
|
columns: "attribute, value",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
2023-07-16 20:20:56 +02:00
|
|
|
];
|
|
|
|
|
|
|
|
const linkWidgets: Widget[] = [
|
|
|
|
{
|
|
|
|
name: "List",
|
|
|
|
icon: "list-check",
|
2023-08-28 18:14:06 +02:00
|
|
|
components: ({ entries, group }) => [
|
2023-07-16 20:20:56 +02:00
|
|
|
{
|
|
|
|
component: EntryList,
|
|
|
|
props: {
|
|
|
|
entries,
|
|
|
|
columns: "attribute, value",
|
2023-08-28 18:14:06 +02:00
|
|
|
attributes: $allTypes[group]?.attributes || [],
|
2023-07-16 20:20:56 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
2023-06-19 11:53:35 +02:00
|
|
|
{
|
2023-10-22 13:38:52 +02:00
|
|
|
name: "Entity List",
|
2023-06-19 12:58:42 +02:00
|
|
|
icon: "image",
|
2023-09-07 18:57:45 +02:00
|
|
|
components: ({ entries, address }) => [
|
2023-06-19 11:53:35 +02:00
|
|
|
{
|
2023-09-07 15:40:20 +02:00
|
|
|
component: EntityList,
|
2023-06-19 11:53:35 +02:00
|
|
|
props: {
|
2023-09-07 18:57:45 +02:00
|
|
|
address,
|
2023-06-19 11:53:35 +02:00
|
|
|
entities: entries
|
|
|
|
.filter((e) => e.value.t == "Address")
|
|
|
|
.map((e) => e.value.c),
|
|
|
|
thumbnails: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
const taggedWidgets: Widget[] = [
|
|
|
|
{
|
|
|
|
name: "List",
|
2023-06-19 12:58:42 +02:00
|
|
|
icon: "list-check",
|
2023-09-07 18:57:45 +02:00
|
|
|
components: ({ entries, address }) => [
|
2023-06-19 11:53:35 +02:00
|
|
|
{
|
2023-09-07 15:40:20 +02:00
|
|
|
component: EntityList,
|
2023-06-19 11:53:35 +02:00
|
|
|
props: {
|
2023-09-07 18:57:45 +02:00
|
|
|
address,
|
2023-06-19 11:53:35 +02:00
|
|
|
entities: entries.map((e) => e.entity),
|
|
|
|
thumbnails: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
{
|
2023-09-07 15:40:20 +02:00
|
|
|
name: "EntityList",
|
2023-06-19 12:58:42 +02:00
|
|
|
icon: "image",
|
2023-09-07 18:57:45 +02:00
|
|
|
components: ({ entries, address }) => [
|
2023-06-19 11:53:35 +02:00
|
|
|
{
|
2023-09-07 15:40:20 +02:00
|
|
|
component: EntityList,
|
2023-06-19 11:53:35 +02:00
|
|
|
props: {
|
2023-09-07 18:57:45 +02:00
|
|
|
address,
|
2023-06-19 11:53:35 +02:00
|
|
|
entities: entries.map((e) => e.entity),
|
|
|
|
thumbnails: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
2022-03-20 11:21:36 +01:00
|
|
|
$: entity.subscribe(async (object) => {
|
2023-01-01 16:25:40 +01:00
|
|
|
if (object && object.listing.entries.length) {
|
2023-09-09 12:09:56 +02:00
|
|
|
dbg("Updating visit stats for %o", object);
|
2023-06-19 16:45:55 +02:00
|
|
|
await api.putEntityAttribute(
|
|
|
|
object.address,
|
|
|
|
"LAST_VISITED",
|
|
|
|
{
|
|
|
|
t: "Number",
|
|
|
|
c: new Date().getTime() / 1000,
|
|
|
|
},
|
2023-08-01 22:02:52 +02:00
|
|
|
"IMPLICIT",
|
2023-06-19 16:45:55 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
await api.putEntityAttribute(
|
|
|
|
object.address,
|
|
|
|
"NUM_VISITED",
|
|
|
|
{
|
|
|
|
t: "Number",
|
|
|
|
c: (parseInt(String(object.get("NUM_VISITED"))) || 0) + 1,
|
|
|
|
},
|
2023-08-01 22:02:52 +02:00
|
|
|
"IMPLICIT",
|
2023-06-19 16:45:55 +02:00
|
|
|
);
|
2022-03-20 11:21:36 +01:00
|
|
|
}
|
|
|
|
});
|
2021-11-11 23:37:42 +01:00
|
|
|
</script>
|
|
|
|
|
2023-10-22 13:56:27 +02:00
|
|
|
<div
|
|
|
|
class="inspect"
|
|
|
|
class:detail
|
|
|
|
class:blob={blobHandled}
|
2023-10-22 21:03:51 +02:00
|
|
|
data-address-multi={($entity?.attr["~IN"]?.map((e) => e.entity) || []).join(
|
|
|
|
",",
|
|
|
|
)}
|
2023-10-22 13:56:27 +02:00
|
|
|
>
|
2022-01-28 22:39:08 +01:00
|
|
|
<header>
|
|
|
|
<h2>
|
|
|
|
{#if $entity}
|
2022-03-22 21:57:00 +01:00
|
|
|
<UpObject banner {address} on:resolved={onResolved} />
|
2022-01-28 22:39:08 +01:00
|
|
|
{:else}
|
2022-02-06 12:20:56 +01:00
|
|
|
<Spinner centered />
|
2022-01-28 22:39:08 +01:00
|
|
|
{/if}
|
|
|
|
</h2>
|
2022-02-15 23:31:17 +01:00
|
|
|
</header>
|
2023-04-23 14:11:19 +02:00
|
|
|
{#if !showAsEntries}
|
|
|
|
<div class="main-content">
|
|
|
|
<div class="detail-col">
|
2023-05-03 16:21:03 +02:00
|
|
|
<div class="blob-viewer">
|
|
|
|
<BlobViewer
|
|
|
|
{address}
|
|
|
|
{detail}
|
|
|
|
on:handled={(ev) => (blobHandled = ev.detail)}
|
|
|
|
/>
|
|
|
|
</div>
|
2023-09-01 19:52:49 +02:00
|
|
|
<NotesEditor {address} on:change={onChange} />
|
2023-05-03 16:21:03 +02:00
|
|
|
{#if !$error}
|
2023-07-29 19:50:00 +02:00
|
|
|
<InspectGroups
|
2023-07-29 19:26:00 +02:00
|
|
|
{entity}
|
2023-07-29 19:50:00 +02:00
|
|
|
on:highlighted={(ev) => (highlightedType = ev.detail)}
|
|
|
|
on:change={() => revalidate()}
|
|
|
|
/>
|
2023-09-03 11:08:24 +02:00
|
|
|
<div class="properties">
|
2023-09-01 19:52:49 +02:00
|
|
|
<InspectTypeEditor {entity} on:change={() => revalidate()} />
|
2023-08-27 20:45:01 +02:00
|
|
|
{#each Object.entries($allTypes) as [typeAddr, { labels, attributes }]}
|
2023-06-16 16:30:17 +02:00
|
|
|
<EntryView
|
2023-08-27 20:45:01 +02:00
|
|
|
entries={($entity?.attributes || []).filter((e) =>
|
|
|
|
attributes.includes(e.attribute),
|
|
|
|
)}
|
2023-07-16 20:20:56 +02:00
|
|
|
widgets={linkWidgets}
|
2023-06-16 16:30:17 +02:00
|
|
|
on:change={onChange}
|
|
|
|
highlighted={highlightedType == typeAddr}
|
2023-08-27 20:45:01 +02:00
|
|
|
title={labels.join(" | ")}
|
2023-07-30 17:02:52 +02:00
|
|
|
group={typeAddr}
|
2023-09-07 18:57:45 +02:00
|
|
|
{address}
|
2023-06-16 16:30:17 +02:00
|
|
|
/>
|
|
|
|
{/each}
|
|
|
|
|
2023-09-03 11:08:24 +02:00
|
|
|
{#if currentUntypedProperties.length > 0}
|
2023-06-16 16:30:17 +02:00
|
|
|
<EntryView
|
2023-09-03 11:08:24 +02:00
|
|
|
title={$i18n.t("Other Properties")}
|
2023-06-19 11:53:35 +02:00
|
|
|
widgets={attributeWidgets}
|
2023-09-03 11:08:24 +02:00
|
|
|
entries={currentUntypedProperties}
|
2023-06-16 16:30:17 +02:00
|
|
|
on:change={onChange}
|
2023-09-07 18:57:45 +02:00
|
|
|
{address}
|
2023-06-16 16:30:17 +02:00
|
|
|
/>
|
|
|
|
{/if}
|
2022-03-25 14:11:00 +01:00
|
|
|
|
2023-09-01 19:52:49 +02:00
|
|
|
{#if currentUntypedLinks.length > 0}
|
2023-07-16 20:20:56 +02:00
|
|
|
<EntryView
|
|
|
|
title={$i18n.t("Links")}
|
|
|
|
widgets={linkWidgets}
|
|
|
|
entries={currentUntypedLinks}
|
|
|
|
on:change={onChange}
|
2023-09-07 18:57:45 +02:00
|
|
|
{address}
|
2023-07-16 20:20:56 +02:00
|
|
|
/>
|
|
|
|
{/if}
|
|
|
|
|
2023-09-07 21:53:56 +02:00
|
|
|
<EntryView
|
|
|
|
title={`${$i18n.t("Members")}`}
|
|
|
|
widgets={taggedWidgets}
|
|
|
|
entries={tagged}
|
|
|
|
on:change={onChange}
|
|
|
|
{address}
|
|
|
|
/>
|
2023-01-07 11:00:55 +01:00
|
|
|
|
2023-07-09 19:27:20 +02:00
|
|
|
{#if currentBacklinks.length > 0}
|
2023-06-16 16:30:17 +02:00
|
|
|
<EntryView
|
2023-07-09 19:27:20 +02:00
|
|
|
title={`${$i18n.t("Referred to")} (${currentBacklinks.length})`}
|
|
|
|
entries={currentBacklinks}
|
2023-06-16 16:30:17 +02:00
|
|
|
on:change={onChange}
|
2023-09-07 18:57:45 +02:00
|
|
|
{address}
|
2023-06-16 16:30:17 +02:00
|
|
|
/>
|
|
|
|
{/if}
|
2023-04-23 14:11:19 +02:00
|
|
|
|
2023-06-16 16:30:17 +02:00
|
|
|
{#if $entityInfo?.t === "Attribute"}
|
|
|
|
<div class="buttons">
|
|
|
|
<div class="button">
|
|
|
|
<Link to="/surface?x={$entityInfo.c}">
|
|
|
|
{$i18n.t("Surface view")}
|
|
|
|
</Link>
|
2023-04-23 14:11:19 +02:00
|
|
|
</div>
|
2023-01-10 21:45:03 +01:00
|
|
|
</div>
|
2023-06-16 16:30:17 +02:00
|
|
|
|
2023-09-05 20:57:01 +02:00
|
|
|
<LabelBorder>
|
|
|
|
<span slot="header"
|
|
|
|
>{$i18n.t("Used")} ({attributesUsed.length})</span
|
|
|
|
>
|
|
|
|
<EntryList
|
|
|
|
columns="entity,value"
|
|
|
|
columnWidths={["auto", "33%"]}
|
|
|
|
entries={attributesUsed}
|
|
|
|
orderByValue
|
|
|
|
/>
|
|
|
|
</LabelBorder>
|
2023-01-07 11:00:55 +01:00
|
|
|
{/if}
|
2023-06-16 16:30:17 +02:00
|
|
|
</div>
|
2022-03-25 14:11:00 +01:00
|
|
|
{:else}
|
2023-04-23 14:11:19 +02:00
|
|
|
<div class="error">
|
|
|
|
{$error}
|
|
|
|
</div>
|
2022-02-20 18:04:47 +01:00
|
|
|
{/if}
|
2023-04-23 14:11:19 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{:else}
|
|
|
|
<div class="entries">
|
|
|
|
<h2>{$i18n.t("Attributes")}</h2>
|
2023-04-23 19:08:44 +02:00
|
|
|
<EntryList
|
|
|
|
entries={$entity.attributes}
|
2023-05-03 16:21:03 +02:00
|
|
|
columns={detail
|
|
|
|
? "timestamp, provenance, attribute, value"
|
|
|
|
: "attribute, value"}
|
2023-04-23 19:08:44 +02:00
|
|
|
/>
|
2023-04-23 14:11:19 +02:00
|
|
|
<h2>{$i18n.t("Backlinks")}</h2>
|
2023-04-23 19:08:44 +02:00
|
|
|
<EntryList
|
|
|
|
entries={$entity.backlinks}
|
2023-05-03 16:21:03 +02:00
|
|
|
columns={detail
|
|
|
|
? "timestamp, provenance, entity, attribute"
|
|
|
|
: "entity, attribute"}
|
2023-04-23 19:08:44 +02:00
|
|
|
/>
|
2022-03-25 14:11:00 +01:00
|
|
|
</div>
|
2023-04-23 14:11:19 +02:00
|
|
|
{/if}
|
2023-08-28 18:14:06 +02:00
|
|
|
<div class="footer">
|
2023-04-23 14:11:19 +02:00
|
|
|
<IconButton
|
2023-08-28 18:14:06 +02:00
|
|
|
name="detail"
|
|
|
|
title={$i18n.t("Show as entries")}
|
|
|
|
active={showAsEntries}
|
|
|
|
on:click={() => (showAsEntries = !showAsEntries)}
|
2023-04-23 14:11:19 +02:00
|
|
|
/>
|
2022-02-15 23:31:17 +01:00
|
|
|
</div>
|
2023-08-28 18:14:06 +02:00
|
|
|
<IconButton
|
|
|
|
name="trash"
|
|
|
|
outline
|
|
|
|
subdued
|
|
|
|
color="#dc322f"
|
|
|
|
on:click={deleteObject}
|
|
|
|
title={$i18n.t("Delete object")}
|
|
|
|
/>
|
2021-11-11 23:37:42 +01:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
2022-02-15 23:31:17 +01:00
|
|
|
header h2 {
|
|
|
|
margin-bottom: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.inspect,
|
|
|
|
.main-content {
|
2021-11-30 00:29:27 +01:00
|
|
|
flex: auto;
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
2022-01-28 22:39:08 +01:00
|
|
|
gap: 0.5rem;
|
2022-02-15 23:31:17 +01:00
|
|
|
min-height: 0;
|
2021-11-30 00:29:27 +01:00
|
|
|
}
|
|
|
|
|
2023-09-03 11:08:24 +02:00
|
|
|
.properties {
|
2021-11-30 00:29:27 +01:00
|
|
|
flex: auto;
|
|
|
|
height: 0; // https://stackoverflow.com/a/14964944
|
2022-03-15 17:22:14 +01:00
|
|
|
min-height: 12em;
|
2021-11-30 00:29:27 +01:00
|
|
|
overflow-y: auto;
|
|
|
|
}
|
|
|
|
|
2022-02-15 23:31:17 +01:00
|
|
|
@media screen and (max-height: 1080px) {
|
|
|
|
.main-content {
|
2022-02-17 17:34:45 +01:00
|
|
|
overflow-y: auto;
|
2022-02-15 23:31:17 +01:00
|
|
|
// min-height: 0;
|
|
|
|
}
|
|
|
|
|
2023-09-03 11:08:24 +02:00
|
|
|
.properties {
|
2022-02-15 23:31:17 +01:00
|
|
|
height: unset;
|
2022-03-19 23:15:51 +01:00
|
|
|
min-height: unset;
|
2022-02-15 23:31:17 +01:00
|
|
|
overflow-y: unset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-06 17:53:00 +02:00
|
|
|
@media screen and (min-width: 1600px) {
|
|
|
|
.inspect.detail {
|
|
|
|
.main-content {
|
|
|
|
position: relative;
|
|
|
|
flex-direction: row;
|
|
|
|
justify-content: end;
|
|
|
|
}
|
2022-03-25 14:11:00 +01:00
|
|
|
|
2023-07-06 17:53:00 +02:00
|
|
|
&.blob {
|
|
|
|
.detail-col {
|
2023-08-02 21:11:43 +02:00
|
|
|
width: 25%;
|
2023-07-06 17:53:00 +02:00
|
|
|
flex-grow: 0;
|
|
|
|
}
|
2023-08-02 21:11:43 +02:00
|
|
|
|
|
|
|
.blob-viewer {
|
|
|
|
width: 73%;
|
|
|
|
height: 100%;
|
|
|
|
position: absolute;
|
|
|
|
left: 1%;
|
|
|
|
top: 0;
|
|
|
|
}
|
2022-03-25 14:11:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-09 19:58:44 +02:00
|
|
|
.main-content .detail-col {
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
flex-grow: 1;
|
|
|
|
}
|
|
|
|
|
2023-04-23 14:11:19 +02:00
|
|
|
.entries {
|
|
|
|
flex-grow: 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
.footer {
|
2023-08-28 18:14:06 +02:00
|
|
|
margin-top: 2rem;
|
2023-04-23 14:11:19 +02:00
|
|
|
display: flex;
|
|
|
|
justify-content: end;
|
|
|
|
}
|
|
|
|
|
2023-01-10 21:45:03 +01:00
|
|
|
.buttons {
|
|
|
|
display: flex;
|
|
|
|
}
|
|
|
|
|
2021-11-11 23:37:42 +01:00
|
|
|
.error {
|
|
|
|
color: red;
|
|
|
|
}
|
|
|
|
</style>
|