upend/webui/src/lib/components/CombineColumn.svelte

165 lines
3.9 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';
import { Any } from '@upnd/upend/query';
import type { Widget } from '$lib/components/EntryView.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 requiredGroups = 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 &&
requiredGroups.length === 0 &&
excludedGroups.length === 0
) {
dispatch('close');
}
const combinedWidgets: Widget[] = [
{
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: string[] = [];
async function updateResultEntities(
includedGroups: string[],
requiredGroups: string[],
excludedGroups: string[]
) {
const included = includedGroups.length
? (
await api.query(
Query.matches(
Any,
ATTR_IN,
includedGroups.map((g) => `@${g}`)
)
)
).objects
: [];
const required = requiredGroups.length
? (
await api.query(
Query.matches(
Any,
ATTR_IN,
requiredGroups.map((g) => `@${g}`)
)
)
).objects
: [];
const excluded = excludedGroups.length
? (
await api.query(
Query.matches(
Any,
ATTR_IN,
excludedGroups.map((g) => `@${g}`)
)
)
).objects
: [];
resultEntities = (Object.keys(included).length ? Object.keys(included) : Object.keys(required))
.filter((e) => !requiredGroups.length || Object.keys(required).includes(e))
.filter((e) => !Object.keys(excluded).includes(e));
}
$: updateResultEntities(includedGroups, requiredGroups, excludedGroups);
</script>
<div class="view" data-address-multi={resultEntities}>
<h2>
<Icon plain name="intersect" />
{$i18n.t('Combine')}
</h2>
<div class="controls">
<EntitySetEditor
entities={includedGroups}
header={$i18n.t('Include') || ''}
confirmRemoveMessage={null}
on:add={(ev) => (includedGroups = [...includedGroups, ev.detail])}
on:remove={(ev) => (includedGroups = includedGroups.filter((e) => e !== ev.detail))}
/>
<EntitySetEditor
entities={requiredGroups}
header={$i18n.t('Require') || ''}
confirmRemoveMessage={null}
on:add={(ev) => (requiredGroups = [...requiredGroups, ev.detail])}
on:remove={(ev) => (requiredGroups = requiredGroups.filter((e) => e !== ev.detail))}
/>
<EntitySetEditor
entities={excludedGroups}
header={$i18n.t('Exclude') || ''}
confirmRemoveMessage={null}
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>