refactor(webui): use EntitySetEditor in Inspect & MultiGroup
ci/woodpecker/push/woodpecker Pipeline failed
Details
ci/woodpecker/push/woodpecker Pipeline failed
Details
parent
2b6a41ebe4
commit
eef2d3f5a4
|
@ -9,6 +9,7 @@
|
|||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let entities: string[];
|
||||
export let hide = false;
|
||||
|
||||
export let header = "";
|
||||
export let confirmRemoveMessage: string | null = $i18n.t(
|
||||
|
@ -37,7 +38,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<LabelBorder>
|
||||
<LabelBorder {hide}>
|
||||
<span slot="header">{header}</span>
|
||||
|
||||
{#if adding}
|
||||
|
@ -59,7 +60,11 @@
|
|||
<div class="body">
|
||||
<div class="group-list">
|
||||
{#each entities as entity}
|
||||
<div class="group">
|
||||
<div
|
||||
class="group"
|
||||
on:mouseenter={() => dispatch("highlighted", entity)}
|
||||
on:mouseleave={() => dispatch("highlighted", undefined)}
|
||||
>
|
||||
<UpObjectDisplay address={entity} link />
|
||||
<IconButton subdued name="x-circle" on:click={() => remove(entity)} />
|
||||
</div>
|
||||
|
|
|
@ -1,136 +1,42 @@
|
|||
<script lang="ts">
|
||||
import UpObjectDisplay from "./display/UpObject.svelte";
|
||||
import Selector from "./utils/Selector.svelte";
|
||||
import IconButton from "./utils/IconButton.svelte";
|
||||
import type { IValue } from "@upnd/upend/types";
|
||||
import api from "../lib/api";
|
||||
import { ATTR_IN } from "@upnd/upend/constants";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { i18n } from "../i18n";
|
||||
import type { UpObject } from "@upnd/upend";
|
||||
import type { Readable } from "svelte/store";
|
||||
import LabelBorder from "./utils/LabelBorder.svelte";
|
||||
import EntitySetEditor from "./EntitySetEditor.svelte";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let entity: Readable<UpObject>;
|
||||
|
||||
let adding = false;
|
||||
let groupSelector: Selector;
|
||||
|
||||
$: if (adding && groupSelector) groupSelector.focus();
|
||||
|
||||
$: groups = ($entity?.attr[ATTR_IN] || []).map(
|
||||
(e) => [e.value.c as string, e.address] as [string, string],
|
||||
$: groups = Object.fromEntries(
|
||||
($entity?.attr[ATTR_IN] || []).map((e) => [e.value.c as string, e.address]),
|
||||
);
|
||||
|
||||
let groupToAdd: IValue | undefined;
|
||||
async function addGroup() {
|
||||
if (!groupToAdd) {
|
||||
return;
|
||||
}
|
||||
async function addGroup(address: string) {
|
||||
await api.putEntry([
|
||||
{
|
||||
entity: $entity.address,
|
||||
attribute: ATTR_IN,
|
||||
value: {
|
||||
t: "Address",
|
||||
c: String(groupToAdd.c),
|
||||
c: address,
|
||||
},
|
||||
},
|
||||
]);
|
||||
dispatch("change");
|
||||
groupToAdd = undefined;
|
||||
}
|
||||
|
||||
async function removeGroup(groupAddress: string) {
|
||||
if (confirm($i18n.t("Are you sure you want to remove this group?"))) {
|
||||
await api.deleteEntry(groupAddress);
|
||||
dispatch("change");
|
||||
}
|
||||
async function removeGroup(address: string) {
|
||||
await api.deleteEntry(groups[address]);
|
||||
dispatch("change");
|
||||
}
|
||||
</script>
|
||||
|
||||
<LabelBorder hide={groups.length === 0}>
|
||||
<span slot="header">{$i18n.t("Groups")}</span>
|
||||
|
||||
{#if adding}
|
||||
<div class="selector">
|
||||
<Selector
|
||||
bind:this={groupSelector}
|
||||
type="value"
|
||||
valueTypes={["Address"]}
|
||||
bind:value={groupToAdd}
|
||||
on:input={addGroup}
|
||||
on:focus={(ev) => {
|
||||
if (!ev.detail) adding = false;
|
||||
}}
|
||||
placeholder={$i18n.t("Choose an entity...")}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="body">
|
||||
<div class="group-list">
|
||||
{#each groups as [groupAddress, groupEntryAddress]}
|
||||
<div
|
||||
class="group"
|
||||
on:mouseenter={() => dispatch("highlighted", groupAddress)}
|
||||
on:mouseleave={() => dispatch("highlighted", undefined)}
|
||||
>
|
||||
<UpObjectDisplay address={groupAddress} link />
|
||||
<IconButton
|
||||
subdued
|
||||
name="x-circle"
|
||||
on:click={() => removeGroup(groupEntryAddress)}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="no-groups">
|
||||
{$i18n.t("Object is not in any groups.")}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{#if !adding}
|
||||
<div class="add-button">
|
||||
<IconButton
|
||||
outline
|
||||
small
|
||||
name="folder-plus"
|
||||
on:click={() => (adding = true)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</LabelBorder>
|
||||
|
||||
<style lang="scss">
|
||||
.group-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem 0.2rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.group {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.body {
|
||||
display: flex;
|
||||
align-items: start;
|
||||
|
||||
.group-list {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.selector {
|
||||
width: 100%;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.no-groups {
|
||||
opacity: 0.66;
|
||||
}
|
||||
</style>
|
||||
<EntitySetEditor
|
||||
entities={Object.keys(groups)}
|
||||
hide={Object.keys(groups).length === 0}
|
||||
on:add={(e) => addGroup(e.detail)}
|
||||
on:remove={(e) => removeGroup(e.detail)}
|
||||
on:highlighted
|
||||
/>
|
||||
|
|
|
@ -1,21 +1,12 @@
|
|||
<script lang="ts">
|
||||
import UpObjectDisplay from "./display/UpObject.svelte";
|
||||
import Selector from "./utils/Selector.svelte";
|
||||
import IconButton from "./utils/IconButton.svelte";
|
||||
import type { IValue } from "@upnd/upend/types";
|
||||
import api from "../lib/api";
|
||||
import { ATTR_IN } from "@upnd/upend/constants";
|
||||
import { i18n } from "../i18n";
|
||||
import LabelBorder from "./utils/LabelBorder.svelte";
|
||||
import { Query, UpListing } from "@upnd/upend";
|
||||
import EntitySetEditor from "./EntitySetEditor.svelte";
|
||||
|
||||
export let entities: string[];
|
||||
|
||||
let adding = false;
|
||||
let groupSelector: Selector;
|
||||
|
||||
$: if (adding && groupSelector) groupSelector.focus();
|
||||
|
||||
let groups = [];
|
||||
let groupListing: UpListing | undefined = undefined;
|
||||
async function updateGroups() {
|
||||
|
@ -46,118 +37,37 @@
|
|||
}
|
||||
$: entities && updateGroups();
|
||||
|
||||
let groupToAdd: IValue | undefined;
|
||||
async function addGroup() {
|
||||
if (!groupToAdd) {
|
||||
return;
|
||||
}
|
||||
async function addGroup(address: string) {
|
||||
await api.putEntry(
|
||||
entities.map((entity) => ({
|
||||
entity,
|
||||
attribute: ATTR_IN,
|
||||
value: {
|
||||
t: "Address",
|
||||
c: String(groupToAdd.c),
|
||||
c: address,
|
||||
},
|
||||
})),
|
||||
);
|
||||
groupToAdd = undefined;
|
||||
await updateGroups();
|
||||
}
|
||||
|
||||
async function removeGroup(groupAddress: string) {
|
||||
if (confirm($i18n.t("Are you sure you want to remove this group?"))) {
|
||||
await Promise.all(
|
||||
entities.map((entity) =>
|
||||
api.deleteEntry(
|
||||
groupListing.objects[entity].attr[ATTR_IN].find(
|
||||
(v) => v.value.c === groupAddress,
|
||||
).address,
|
||||
),
|
||||
async function removeGroup(address: string) {
|
||||
await Promise.all(
|
||||
entities.map((entity) =>
|
||||
api.deleteEntry(
|
||||
groupListing.objects[entity].attr[ATTR_IN].find(
|
||||
(v) => v.value.c === address,
|
||||
).address,
|
||||
),
|
||||
);
|
||||
await updateGroups();
|
||||
}
|
||||
),
|
||||
);
|
||||
await updateGroups();
|
||||
}
|
||||
</script>
|
||||
|
||||
<LabelBorder>
|
||||
<span slot="header">{$i18n.t("Common groups")}</span>
|
||||
|
||||
{#if adding}
|
||||
<div class="selector">
|
||||
<Selector
|
||||
bind:this={groupSelector}
|
||||
type="value"
|
||||
valueTypes={["Address"]}
|
||||
bind:value={groupToAdd}
|
||||
on:input={addGroup}
|
||||
on:focus={(ev) => {
|
||||
if (!ev.detail) adding = false;
|
||||
}}
|
||||
placeholder={$i18n.t("Choose an entity...")}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="body">
|
||||
<div class="group-list">
|
||||
{#each groups as groupAddress}
|
||||
<div class="group">
|
||||
<UpObjectDisplay address={groupAddress} link />
|
||||
<IconButton
|
||||
subdued
|
||||
name="x-circle"
|
||||
on:click={() => removeGroup(groupAddress)}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="no-groups">
|
||||
{$i18n.t("Entities have no groups in common.")}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{#if !adding}
|
||||
<div class="add-button">
|
||||
<IconButton
|
||||
outline
|
||||
small
|
||||
name="folder-plus"
|
||||
on:click={() => (adding = true)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</LabelBorder>
|
||||
|
||||
<style lang="scss">
|
||||
.group-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem 0.2rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.group {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.body {
|
||||
display: flex;
|
||||
align-items: start;
|
||||
|
||||
.group-list {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.selector {
|
||||
width: 100%;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.no-groups {
|
||||
opacity: 0.66;
|
||||
}
|
||||
</style>
|
||||
<EntitySetEditor
|
||||
entities={groups}
|
||||
header={$i18n.t("Common groups")}
|
||||
on:add={(ev) => addGroup(ev.detail)}
|
||||
on:remove={(ev) => removeGroup(ev.detail)}
|
||||
/>
|
||||
|
|
Loading…
Reference in New Issue