[ui] add group add feature, fix group display
also add entity type to selector, input eventfeat/vaults
parent
859838f124
commit
4f426bca6f
|
@ -10,6 +10,8 @@
|
|||
import Spinner from "./utils/Spinner.svelte";
|
||||
import NotesEditor from "./utils/NotesEditor.svelte";
|
||||
import type { AttributeChange } from "../types/base";
|
||||
import Selector from "./utils/Selector.svelte";
|
||||
import type { IValue } from "upend/types";
|
||||
|
||||
export let address: string;
|
||||
export let index: number | undefined;
|
||||
|
@ -99,7 +101,8 @@
|
|||
|
||||
$: groups = ($entity?.backlinks || [])
|
||||
.filter((e) => e.attribute === "HAS")
|
||||
.map((e) => e.entity);
|
||||
.map((e) => e.entity)
|
||||
.sort(); // TODO
|
||||
|
||||
async function onChange(ev: CustomEvent<AttributeChange>) {
|
||||
const change = ev.detail;
|
||||
|
@ -137,6 +140,27 @@
|
|||
}
|
||||
revalidate();
|
||||
}
|
||||
|
||||
let groupToAdd: IValue | undefined;
|
||||
async function addGroup() {
|
||||
if (!groupToAdd) {
|
||||
return;
|
||||
}
|
||||
await fetch(`/api/obj`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
entity: String(groupToAdd.c),
|
||||
attribute: "HAS",
|
||||
value: {
|
||||
t: "Address",
|
||||
c: address,
|
||||
},
|
||||
}),
|
||||
});
|
||||
revalidate();
|
||||
groupToAdd = undefined;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="inspect">
|
||||
|
@ -154,6 +178,16 @@
|
|||
{#each groups as address}
|
||||
<UpObject {address} link />
|
||||
{/each}
|
||||
{#if editable}
|
||||
<div class="selector">
|
||||
<Selector
|
||||
type="entity"
|
||||
bind:value={groupToAdd}
|
||||
on:input={addGroup}
|
||||
placeholder="Choose an entity..."
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</section>
|
||||
</header>
|
||||
|
@ -214,8 +248,16 @@
|
|||
}
|
||||
|
||||
.groups {
|
||||
display: flex;
|
||||
margin: 0.25rem 0;
|
||||
.content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem 0.5rem;
|
||||
align-items: center;
|
||||
}
|
||||
.selector {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.attributes {
|
||||
|
|
|
@ -1,15 +1,36 @@
|
|||
<script lang="ts">
|
||||
import { debounce } from "lodash";
|
||||
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import type { IValue } from "upend/types";
|
||||
import { baseSearchOnce, getObjects } from "../../util/search";
|
||||
import UpObject from "../display/UpObject.svelte";
|
||||
import IconButton from "./IconButton.svelte";
|
||||
import Input from "./Input.svelte";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let attribute: string | undefined = undefined;
|
||||
export let value: IValue | undefined = undefined;
|
||||
export let type: "attribute" | "value";
|
||||
export let type: "attribute" | "value" | "entity";
|
||||
export let placeholder = "";
|
||||
|
||||
let inputValue = "";
|
||||
if (type == "attribute") {
|
||||
inputValue = attribute || "";
|
||||
} else {
|
||||
inputValue = String(value?.c || "");
|
||||
}
|
||||
$: if (value === undefined) inputValue = undefined;
|
||||
|
||||
function onInput(ev: CustomEvent<string>) {
|
||||
if (type == "attribute") {
|
||||
attribute = ev.detail;
|
||||
} else {
|
||||
value = {
|
||||
t: "String",
|
||||
c: ev.detail,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
interface SelectorOption {
|
||||
attribute?: string;
|
||||
|
@ -36,17 +57,23 @@
|
|||
});
|
||||
break;
|
||||
}
|
||||
case "value": {
|
||||
case "value":
|
||||
case "entity": {
|
||||
const result = await baseSearchOnce(query);
|
||||
const objects = await getObjects(result.entries);
|
||||
|
||||
options = [
|
||||
{
|
||||
options = [];
|
||||
|
||||
if (type === "value") {
|
||||
options.push({
|
||||
value: {
|
||||
t: "String",
|
||||
c: query,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
options.push(
|
||||
...objects.slice(0, 25).map(([address, label]) => {
|
||||
return {
|
||||
value: {
|
||||
|
@ -54,8 +81,10 @@
|
|||
c: address,
|
||||
},
|
||||
} as SelectorOption;
|
||||
}),
|
||||
];
|
||||
})
|
||||
);
|
||||
|
||||
options = options;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -69,31 +98,15 @@
|
|||
inputValue = option.attribute;
|
||||
break;
|
||||
case "value":
|
||||
case "entity":
|
||||
value = option.value;
|
||||
inputValue = String(option.value.c);
|
||||
break;
|
||||
}
|
||||
dispatch("input", value);
|
||||
visible = false;
|
||||
}
|
||||
|
||||
let inputValue = "";
|
||||
if (type == "attribute") {
|
||||
inputValue = attribute || "";
|
||||
} else {
|
||||
inputValue = String(value?.c || "");
|
||||
}
|
||||
|
||||
function onInput(ev: CustomEvent<string>) {
|
||||
if (type == "attribute") {
|
||||
attribute = ev.detail;
|
||||
} else {
|
||||
value = {
|
||||
t: "String",
|
||||
c: ev.detail,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let inputFocused = false;
|
||||
let hover = false;
|
||||
$: visible = (inputFocused || hover) && Boolean(options.length);
|
||||
|
@ -112,6 +125,7 @@
|
|||
bind:value={inputValue}
|
||||
on:input={onInput}
|
||||
on:focusChange={(ev) => (inputFocused = ev.detail)}
|
||||
{placeholder}
|
||||
/>
|
||||
{/if}
|
||||
<ul
|
||||
|
|
Loading…
Reference in New Issue