feat(webui): allow search / selection of entries via their attributes
ci/woodpecker/push/woodpecker Pipeline failed
Details
ci/woodpecker/push/woodpecker Pipeline failed
Details
parent
8a32b583d1
commit
bfce05600b
|
@ -9,7 +9,12 @@
|
|||
|
||||
<div class="entry">
|
||||
<div class="entity">
|
||||
<UpObject link address={entry.entity} labels={resolve ? undefined : []} />
|
||||
<UpObject
|
||||
plain
|
||||
link
|
||||
address={entry.entity}
|
||||
labels={resolve ? undefined : []}
|
||||
/>
|
||||
</div>
|
||||
<div class="attribute" title={entry.attribute}>
|
||||
{$attributeLabels[entry.attribute] || entry.attribute}
|
||||
|
@ -30,24 +35,30 @@
|
|||
<style lang="scss">
|
||||
.entry {
|
||||
border: 1px solid var(--foreground);
|
||||
background: var(--background-lighter);
|
||||
border-radius: 4px;
|
||||
padding: 0.5em;
|
||||
padding: 0.1em 0.5em 0.1em 0.25em;
|
||||
display: flex;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1em;
|
||||
|
||||
& > * {
|
||||
flex: 33%;
|
||||
min-width: 0;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
||||
.attribute {
|
||||
font-weight: bold;
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
font-weight: 300;
|
||||
&::before {
|
||||
content: "→\00a0";
|
||||
}
|
||||
&::after {
|
||||
content: "\00a0→";
|
||||
}
|
||||
}
|
||||
|
||||
:global(.value-value) {
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
export let resolve = !(labels || []).length || banner;
|
||||
export let backpath = 0;
|
||||
export let select = true;
|
||||
export let plain = false;
|
||||
|
||||
let entity: Readable<UpObject> = readable(undefined);
|
||||
let entityInfo: Readable<EntityInfo> = writable(undefined);
|
||||
|
@ -164,6 +165,7 @@
|
|||
class:left-active={address == $addresses[$index - 1]}
|
||||
class:right-active={address == $addresses[$index + 1]}
|
||||
class:selected={select && $selected.includes(address)}
|
||||
class:plain
|
||||
>
|
||||
<div
|
||||
class="address"
|
||||
|
@ -248,6 +250,12 @@
|
|||
background: linear-gradient(90deg, transparent 0%, colors.$orange 100%);
|
||||
padding: 2px 2px 2px 0;
|
||||
}
|
||||
|
||||
&.plain .address {
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.address {
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
<script lang="ts" context="module">
|
||||
import type { IValue } from "@upnd/upend/types";
|
||||
import UpEntry from "@upnd/upend";
|
||||
import UpEntryComponent from "../display/UpEntry.svelte";
|
||||
|
||||
export type SELECTOR_TYPE =
|
||||
| "Address"
|
||||
| "LabelledAddress"
|
||||
| "NewAddress"
|
||||
| "Attribute"
|
||||
| "NewAttribute"
|
||||
|
@ -16,6 +19,7 @@
|
|||
| {
|
||||
t: "Address";
|
||||
c: Address;
|
||||
entry?: UpEntry;
|
||||
labels?: string[];
|
||||
}
|
||||
| {
|
||||
|
@ -146,7 +150,7 @@
|
|||
let searchResult: UpListing | undefined = undefined;
|
||||
const updateOptions = debounce(async (query: string, doSearch: boolean) => {
|
||||
updating = true;
|
||||
let result = [];
|
||||
let result: SelectorOption[] = [];
|
||||
|
||||
if (query.length === 0 && emptyOptions !== undefined) {
|
||||
options = emptyOptions;
|
||||
|
@ -173,7 +177,7 @@
|
|||
|
||||
options = result;
|
||||
|
||||
if (types.includes("Address")) {
|
||||
if (types.includes("Address") || types.includes("LabelledAddress")) {
|
||||
if (doSearch) {
|
||||
if (emptyOptions === undefined || query.length > 0) {
|
||||
searchResult = await baseSearchOnce(query);
|
||||
|
@ -194,6 +198,7 @@
|
|||
t: "Address",
|
||||
c: addr,
|
||||
labels: addressToLabels[addr],
|
||||
entry: null,
|
||||
}),
|
||||
);
|
||||
} else if (query.length && types.includes("NewAddress")) {
|
||||
|
@ -203,23 +208,32 @@
|
|||
});
|
||||
}
|
||||
|
||||
const validOptions = (searchResult?.entries || [])
|
||||
.filter((e) => e.attribute === ATTR_LABEL)
|
||||
.filter((e) => !exactHits.includes(e.entity));
|
||||
let validOptions = (searchResult?.entries || []).filter(
|
||||
(e) => !exactHits.includes(e.entity),
|
||||
);
|
||||
// only includes LabelledAddress
|
||||
if (!types.includes("Address")) {
|
||||
validOptions = validOptions.filter((e) => e.attribute == ATTR_LABEL);
|
||||
}
|
||||
|
||||
const sortedOptions = matchSorter(validOptions, inputValue, {
|
||||
keys: ["value.c"],
|
||||
keys: ["value.c", (i) => addressToLabels[i.entity]?.join(" ")],
|
||||
});
|
||||
|
||||
result.push(
|
||||
...sortedOptions.map((e) => {
|
||||
return {
|
||||
t: "Address",
|
||||
c: e.entity,
|
||||
labels: [e.value.c],
|
||||
} as SelectorOption;
|
||||
}),
|
||||
);
|
||||
for (const entry of sortedOptions) {
|
||||
const common = {
|
||||
t: "Address" as const,
|
||||
c: entry.entity,
|
||||
};
|
||||
if (entry.attribute == ATTR_LABEL) {
|
||||
result.push({
|
||||
...common,
|
||||
labels: [entry.value.c.toString()],
|
||||
});
|
||||
} else {
|
||||
result.push({ ...common, entry });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (types.includes("Attribute")) {
|
||||
|
@ -463,13 +477,16 @@
|
|||
>
|
||||
{#if option.t === "Address"}
|
||||
{@const address = option.c}
|
||||
<UpObject
|
||||
{address}
|
||||
labels={option.labels}
|
||||
on:resolved={(ev) => onAddressResolved(address, ev)}
|
||||
/>
|
||||
{#if option.entry}
|
||||
<UpEntryComponent entry={option.entry} />
|
||||
{:else}
|
||||
<UpObject
|
||||
{address}
|
||||
labels={option.labels}
|
||||
on:resolved={(ev) => onAddressResolved(address, ev)}
|
||||
/>{/if}
|
||||
{:else if option.t === "NewAddress"}
|
||||
<div class="content">{option.c}</div>
|
||||
<div class="content new">{option.c}</div>
|
||||
<div class="type">{$i18n.t("Create object")}</div>
|
||||
{:else if option.t === "Attribute"}
|
||||
{#if option.labels.length}
|
||||
|
@ -513,14 +530,12 @@
|
|||
.options {
|
||||
position: absolute;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
margin: 2px 0 0;
|
||||
padding: 0;
|
||||
border: 1px solid var(--foreground-lighter);
|
||||
width: 100%;
|
||||
border-radius: 4px;
|
||||
margin-top: 2px;
|
||||
background: var(--background);
|
||||
font-size: smaller;
|
||||
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
|
@ -536,7 +551,7 @@
|
|||
|
||||
li {
|
||||
cursor: pointer;
|
||||
padding: 0.5em;
|
||||
padding: 0.25em;
|
||||
|
||||
transition: background-color 0.1s;
|
||||
&:hover {
|
||||
|
@ -562,5 +577,9 @@
|
|||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.content.new {
|
||||
padding: 0.25em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue