2021-12-21 14:32:47 +01:00
|
|
|
<script lang="ts">
|
2022-01-14 22:05:17 +01:00
|
|
|
import { fetchEntry, query as queryFn } from "../lib/entity";
|
2021-12-21 14:32:47 +01:00
|
|
|
import debounce from "lodash/debounce";
|
|
|
|
import { Readable, readable } from "svelte/store";
|
2022-01-14 22:05:17 +01:00
|
|
|
import type { UpEntry, UpListing, UpObject } from "upend";
|
|
|
|
import Spinner from "../components/utils/Spinner.svelte";
|
|
|
|
import UpEntryDisplay from "../components/display/UpEntry.svelte";
|
|
|
|
import UpObjectDisplay from "../components/display/UpObject.svelte";
|
|
|
|
import UpObjectCard from "../components/display/UpObjectCard.svelte";
|
2022-01-16 19:53:40 +01:00
|
|
|
import { useNavigate } from "svelte-navigator";
|
|
|
|
import type { ListingResult } from "upend/types";
|
|
|
|
const navigate = useNavigate();
|
|
|
|
|
2021-12-21 14:32:47 +01:00
|
|
|
export let query: string;
|
|
|
|
|
|
|
|
let debouncedQuery = "";
|
|
|
|
const updateQuery = debounce((query: string) => {
|
|
|
|
debouncedQuery = query;
|
|
|
|
}, 200);
|
|
|
|
$: updateQuery(query);
|
|
|
|
|
|
|
|
let result: Readable<UpListing> = readable();
|
|
|
|
let error: Readable<unknown> = readable();
|
|
|
|
$: if (debouncedQuery.length) {
|
|
|
|
({ result, error } = queryFn(
|
|
|
|
() => `(matches ? ? (contains "${debouncedQuery}"))`
|
|
|
|
));
|
|
|
|
}
|
2022-01-14 22:05:17 +01:00
|
|
|
|
|
|
|
$: entries = ($result?.entries || []).sort((a, b) =>
|
|
|
|
a.address.localeCompare(b.address)
|
|
|
|
);
|
|
|
|
|
|
|
|
async function getObjects(entries: UpEntry[]): Promise<string[]> {
|
2022-01-16 19:29:15 +01:00
|
|
|
exactHits.length = 0;
|
2022-01-14 22:05:17 +01:00
|
|
|
const labelled = entries
|
|
|
|
.filter((e) => e.attribute == "LBL")
|
|
|
|
.map((e) => e.entity);
|
|
|
|
const aliased = entries
|
|
|
|
.filter((e) => e.attribute === "ALIAS")
|
|
|
|
.map(async (e) => {
|
|
|
|
const entry = await fetchEntry(e.entity);
|
|
|
|
return String(entry.value.c);
|
|
|
|
});
|
|
|
|
return labelled.concat(await Promise.all(aliased));
|
|
|
|
}
|
2022-01-16 19:29:15 +01:00
|
|
|
|
2022-01-14 22:05:17 +01:00
|
|
|
$: objects = getObjects($result?.entries || []);
|
2022-01-16 19:29:15 +01:00
|
|
|
let exactHits = [];
|
|
|
|
|
|
|
|
function onResolved(address: string, ids: string[]) {
|
|
|
|
console.log({ address, ids });
|
2022-01-14 22:05:17 +01:00
|
|
|
|
2022-01-16 19:29:15 +01:00
|
|
|
if (ids.some((id) => id.toLowerCase() === query.toLowerCase())) {
|
|
|
|
if (!exactHits.includes(address)) {
|
|
|
|
exactHits.push(address);
|
|
|
|
exactHits = exactHits;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-01-16 19:53:40 +01:00
|
|
|
|
|
|
|
async function create() {
|
|
|
|
const response = await fetch(`/api/obj`, {
|
|
|
|
method: "PUT",
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
body: JSON.stringify({
|
|
|
|
attribute: "LBL",
|
|
|
|
value: {
|
|
|
|
t: "Value",
|
|
|
|
c: query,
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
if (!response.ok) {
|
|
|
|
throw new Error(`Failed to create object: ${await response.text()}`);
|
|
|
|
}
|
|
|
|
const result = (await response.json()) as ListingResult;
|
|
|
|
const address = Object.values(result)[0].entity;
|
|
|
|
navigate(`/browse/${address}`);
|
|
|
|
}
|
2021-12-21 14:32:47 +01:00
|
|
|
</script>
|
|
|
|
|
|
|
|
<div>
|
2022-01-14 22:05:17 +01:00
|
|
|
{#if !$error}
|
|
|
|
{#if $result}
|
2022-01-16 18:53:18 +01:00
|
|
|
<section class="exact">
|
2022-01-14 22:05:17 +01:00
|
|
|
<h2>Exact</h2>
|
2022-01-16 19:29:15 +01:00
|
|
|
{#if exactHits.length}
|
|
|
|
<ul>
|
|
|
|
{#each exactHits as address}
|
|
|
|
<li>
|
|
|
|
<UpObjectCard {address} --width="100%" --height="100%" />
|
|
|
|
</li>
|
|
|
|
{/each}
|
|
|
|
</ul>
|
2022-01-13 19:08:36 +01:00
|
|
|
{:else}
|
2022-01-16 19:53:40 +01:00
|
|
|
<div class="create">
|
|
|
|
<p>Create new object?</p>
|
|
|
|
<button class="create-object" on:click={create}>"{query}"</button>
|
|
|
|
</div>
|
2022-01-14 22:05:17 +01:00
|
|
|
{/if}
|
|
|
|
</section>
|
2022-01-16 18:53:18 +01:00
|
|
|
|
|
|
|
<section class="objects">
|
|
|
|
{#await objects}
|
2022-01-16 19:53:40 +01:00
|
|
|
<h2>Objects</h2>
|
2022-01-14 22:05:17 +01:00
|
|
|
<Spinner />
|
2022-01-16 18:53:18 +01:00
|
|
|
{:then objects}
|
2022-01-16 19:53:40 +01:00
|
|
|
{#if objects.length}
|
|
|
|
<h2>Objects</h2>
|
|
|
|
<ul>
|
|
|
|
{#each objects as address}
|
|
|
|
<li>
|
|
|
|
<UpObjectDisplay
|
|
|
|
{address}
|
|
|
|
on:resolved={(ids) => onResolved(address, ids.detail)}
|
|
|
|
/>
|
|
|
|
</li>
|
|
|
|
{/each}
|
|
|
|
</ul>
|
|
|
|
{/if}
|
2022-01-16 18:53:18 +01:00
|
|
|
{/await}
|
|
|
|
</section>
|
|
|
|
|
2022-01-16 19:53:40 +01:00
|
|
|
<section class="raw">
|
|
|
|
{#if entries.length}
|
2022-01-14 22:05:17 +01:00
|
|
|
<h2>Raw results</h2>
|
|
|
|
<ul>
|
|
|
|
{#each entries as entry}
|
|
|
|
<li><UpEntryDisplay {entry} /></li>
|
|
|
|
{/each}
|
|
|
|
</ul>
|
2022-01-16 19:53:40 +01:00
|
|
|
{:else}
|
|
|
|
<div class="global">No results found.</div>
|
|
|
|
{/if}
|
|
|
|
</section>
|
2022-01-14 22:05:17 +01:00
|
|
|
{:else}
|
|
|
|
<div class="global">
|
|
|
|
<Spinner />
|
|
|
|
</div>
|
|
|
|
{/if}
|
|
|
|
{:else}
|
2022-01-16 19:53:40 +01:00
|
|
|
<div class="error global">
|
2022-01-14 22:05:17 +01:00
|
|
|
{$error}
|
|
|
|
</div>
|
2021-12-21 14:32:47 +01:00
|
|
|
{/if}
|
|
|
|
</div>
|
2022-01-13 19:08:36 +01:00
|
|
|
|
|
|
|
<style lang="scss">
|
|
|
|
h2 {
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
|
|
|
|
ul {
|
|
|
|
list-style: none;
|
|
|
|
margin: 0;
|
2022-01-14 22:05:17 +01:00
|
|
|
padding: 0;
|
2022-01-13 19:08:36 +01:00
|
|
|
}
|
2022-01-14 22:05:17 +01:00
|
|
|
|
2022-01-16 19:29:15 +01:00
|
|
|
.exact {
|
2022-01-16 18:53:18 +01:00
|
|
|
ul {
|
2022-01-16 19:29:15 +01:00
|
|
|
display: flex;
|
2022-01-16 18:53:18 +01:00
|
|
|
gap: 1rem;
|
2022-01-16 19:29:15 +01:00
|
|
|
justify-content: center;
|
|
|
|
flex-wrap: wrap;
|
2022-01-16 18:53:18 +01:00
|
|
|
|
|
|
|
margin: 0 1rem;
|
|
|
|
}
|
|
|
|
|
|
|
|
li {
|
|
|
|
width: 14rem;
|
|
|
|
height: 8rem;
|
|
|
|
}
|
2022-01-16 19:29:15 +01:00
|
|
|
|
|
|
|
.create {
|
|
|
|
text-align: center;
|
|
|
|
}
|
2022-01-16 19:53:40 +01:00
|
|
|
|
|
|
|
.create-object {
|
|
|
|
display: inline-block;
|
|
|
|
color: var(--foreground);
|
|
|
|
background: var(--background-lighter);
|
|
|
|
border: 1px solid var(--foreground);
|
|
|
|
border-radius: 4px;
|
|
|
|
padding: 0.2em;
|
|
|
|
font-size: 1.25em;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
2022-01-16 19:29:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
.objects {
|
|
|
|
li {
|
|
|
|
margin: 0.5em auto;
|
|
|
|
max-width: 66em;
|
|
|
|
}
|
2022-01-16 18:53:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
.raw {
|
|
|
|
li {
|
|
|
|
margin: 1em auto;
|
|
|
|
max-width: 66em;
|
|
|
|
}
|
2022-01-14 22:05:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
.global {
|
|
|
|
font-size: 48px;
|
|
|
|
position: absolute;
|
|
|
|
top: 50%;
|
|
|
|
left: 50%;
|
|
|
|
transform: translate(-50%, -50%);
|
2022-01-13 19:08:36 +01:00
|
|
|
}
|
|
|
|
</style>
|