diff --git a/webui/src/components/utils/Selector.svelte b/webui/src/components/utils/Selector.svelte index 37ea4c1..565cdca 100644 --- a/webui/src/components/utils/Selector.svelte +++ b/webui/src/components/utils/Selector.svelte @@ -2,7 +2,11 @@ import { debounce } from "lodash"; import { createEventDispatcher } from "svelte"; import type { IValue } from "upend/types"; - import { baseSearchOnce, getObjects } from "../../util/search"; + import { + baseSearchOnce, + createLabelled, + getObjects, + } from "../../util/search"; import UpObject from "../display/UpObject.svelte"; import IconButton from "./IconButton.svelte"; import Input from "./Input.svelte"; @@ -35,6 +39,7 @@ interface SelectorOption { attribute?: string; value?: IValue; + labelToCreate?: string; } let options: SelectorOption[] = []; @@ -82,15 +87,41 @@ }); } - options.push( - ...objects.slice(0, 25).map(([address, _]) => { - return { + let exactHits = Object.entries(addressToLabels) + .filter(([_, labels]) => + labels + .map((l) => l.toLowerCase()) + .includes(inputValue.toLowerCase()) + ) + .map(([addr, _]) => addr); + + if (exactHits.length) { + exactHits.forEach((addr) => + options.push({ value: { t: "Address", - c: address, + c: addr, }, - } as SelectorOption; - }) + }) + ); + } else { + options.push({ + labelToCreate: inputValue, + }); + } + + options.push( + ...objects + .filter(([addr, _]) => !exactHits.includes(addr)) + .slice(0, 25) + .map(([address, _]) => { + return { + value: { + t: "Address", + c: address, + }, + } as SelectorOption; + }) ); options = options; @@ -98,9 +129,18 @@ } } }, 200); - $: updateOptions(inputValue); + $: { + updateOptions(inputValue); + addressToLabels = {}; + } - function set(option: SelectorOption) { + let addressToLabels: { [key: string]: string[] } = {}; + function onAddressResolved(address: string, ev: CustomEvent) { + addressToLabels[address] = ev.detail; + updateOptions(inputValue); + } + + async function set(option: SelectorOption) { switch (type) { case "attribute": attribute = option.attribute; @@ -108,8 +148,17 @@ break; case "value": case "entity": - value = option.value; - inputValue = String(option.value.c); + if (!option.labelToCreate) { + value = option.value; + inputValue = String(option.value.c); + } else { + const addr = await createLabelled(option.labelToCreate); + value = { + t: "Address", + c: addr, + }; + inputValue = addr; + } break; } dispatch("input", value); @@ -149,11 +198,18 @@ {option.attribute} {:else if option.value} {#if option.value.t == "Address"} - + + onAddressResolved(String(option.value.c), ev)} + /> {:else}
{option.value.t}
{option.value.c}
{/if} + {:else if option.labelToCreate} +
Create object
+
{option.labelToCreate}
{/if} {/each}