141 lines
3.3 KiB
Svelte
141 lines
3.3 KiB
Svelte
|
<script lang="ts">
|
||
|
import { i18n } from "../i18n";
|
||
|
import EntitySetEditor from "./EntitySetEditor.svelte";
|
||
|
import EntryView from "./EntryView.svelte";
|
||
|
import Icon from "./utils/Icon.svelte";
|
||
|
import EntityList from "./widgets/EntityList.svelte";
|
||
|
import api from "../lib/api";
|
||
|
import { Query } from "@upnd/upend";
|
||
|
import { ATTR_IN } from "@upnd/upend/constants";
|
||
|
import { createEventDispatcher } from "svelte";
|
||
|
const dispatch = createEventDispatcher();
|
||
|
|
||
|
export let spec: string;
|
||
|
|
||
|
const individualSpecs = spec.split(/(?=[+-])/);
|
||
|
let includedGroups = individualSpecs
|
||
|
.filter((s) => s.startsWith("+"))
|
||
|
.map((s) => s.slice(1));
|
||
|
let excludedGroups = individualSpecs
|
||
|
.filter((s) => s.startsWith("-"))
|
||
|
.map((s) => s.slice(1));
|
||
|
|
||
|
$: if (includedGroups.length == 0 && excludedGroups.length == 0) {
|
||
|
dispatch("close");
|
||
|
}
|
||
|
|
||
|
const combinedWidgets = [
|
||
|
{
|
||
|
name: "List",
|
||
|
icon: "list-check",
|
||
|
components: ({ entities }) => [
|
||
|
{
|
||
|
component: EntityList,
|
||
|
props: {
|
||
|
entities,
|
||
|
thumbnails: false,
|
||
|
},
|
||
|
},
|
||
|
],
|
||
|
},
|
||
|
{
|
||
|
name: "EntityList",
|
||
|
icon: "image",
|
||
|
components: ({ entities }) => [
|
||
|
{
|
||
|
component: EntityList,
|
||
|
props: {
|
||
|
entities,
|
||
|
thumbnails: true,
|
||
|
},
|
||
|
},
|
||
|
],
|
||
|
},
|
||
|
];
|
||
|
|
||
|
let resultEntities = [];
|
||
|
async function updateResultEntities(
|
||
|
includedGroups: string[],
|
||
|
excludedGroups: string[],
|
||
|
) {
|
||
|
const included = includedGroups.length
|
||
|
? (
|
||
|
await api.query(
|
||
|
new Query().matches(
|
||
|
undefined,
|
||
|
ATTR_IN,
|
||
|
includedGroups.map((g) => `@${g}`),
|
||
|
),
|
||
|
)
|
||
|
).objects
|
||
|
: [];
|
||
|
const excluded = excludedGroups.length
|
||
|
? (
|
||
|
await api.query(
|
||
|
new Query().matches(
|
||
|
undefined,
|
||
|
ATTR_IN,
|
||
|
excludedGroups.map((g) => `@${g}`),
|
||
|
),
|
||
|
)
|
||
|
).objects
|
||
|
: [];
|
||
|
resultEntities = Object.keys(included).filter((e) => !(e in excluded));
|
||
|
}
|
||
|
$: updateResultEntities(includedGroups, excludedGroups);
|
||
|
</script>
|
||
|
|
||
|
<div class="view">
|
||
|
<h2>
|
||
|
<Icon plain name="intersect" />
|
||
|
{$i18n.t("Combine")}
|
||
|
</h2>
|
||
|
<div class="controls">
|
||
|
<EntitySetEditor
|
||
|
entities={includedGroups}
|
||
|
header={$i18n.t("Include")}
|
||
|
on:add={(ev) => (includedGroups = [...includedGroups, ev.detail])}
|
||
|
on:remove={(ev) =>
|
||
|
(includedGroups = includedGroups.filter((e) => e !== ev.detail))}
|
||
|
/>
|
||
|
<EntitySetEditor
|
||
|
entities={excludedGroups}
|
||
|
header={$i18n.t("Exclude")}
|
||
|
on:add={(ev) => (excludedGroups = [...excludedGroups, ev.detail])}
|
||
|
on:remove={(ev) =>
|
||
|
(excludedGroups = excludedGroups.filter((e) => e !== ev.detail))}
|
||
|
/>
|
||
|
</div>
|
||
|
<div class="entities">
|
||
|
<EntryView
|
||
|
title={$i18n.t("Matching entities")}
|
||
|
entities={resultEntities}
|
||
|
widgets={combinedWidgets}
|
||
|
/>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<style lang="scss">
|
||
|
.view {
|
||
|
display: flex;
|
||
|
flex-direction: column;
|
||
|
height: 100%;
|
||
|
}
|
||
|
|
||
|
h2 {
|
||
|
text-align: center;
|
||
|
margin: 0;
|
||
|
margin-top: -0.66em;
|
||
|
}
|
||
|
|
||
|
.controls {
|
||
|
margin-bottom: 1rem;
|
||
|
}
|
||
|
|
||
|
.entities {
|
||
|
flex-grow: 1;
|
||
|
overflow-y: auto;
|
||
|
height: 0;
|
||
|
}
|
||
|
</style>
|