2023-01-10 17:28:27 +01:00
|
|
|
<script>
|
2023-02-15 19:27:51 +01:00
|
|
|
import Grid from '$components/grid.svelte';
|
|
|
|
import Icon from '$components/icon.svelte';
|
|
|
|
import ObjectGrid from '$components/objectgrid.svelte';
|
2023-05-29 17:08:52 +02:00
|
|
|
import ObjectViewer from '$components/objectviewer.svelte';
|
2023-02-15 19:27:51 +01:00
|
|
|
import input from '$lib/actions/input';
|
2023-07-19 21:07:50 +02:00
|
|
|
import dialogs from '$lib/dialogs';
|
2023-02-19 17:26:32 +01:00
|
|
|
import { deepClone } from '$lib/objects';
|
2023-05-26 17:21:39 +02:00
|
|
|
import { startProgress } from '$lib/progress';
|
2023-02-15 19:27:51 +01:00
|
|
|
import applicationSettings from '$lib/stores/settings';
|
|
|
|
import views from '$lib/stores/views';
|
2023-07-08 13:17:30 +02:00
|
|
|
import { convertLooseJson, stringCouldBeID } from '$lib/strings';
|
2023-07-24 20:38:30 +02:00
|
|
|
import { CountItems, FindItems, RemoveItemById, UpdateFoundDocument } from '$wails/go/app/App';
|
2023-01-29 20:00:15 +01:00
|
|
|
import { EJSON } from 'bson';
|
2023-01-10 17:28:27 +01:00
|
|
|
|
|
|
|
export let collection;
|
2023-07-08 13:07:55 +02:00
|
|
|
export let visible = false;
|
2023-01-10 17:28:27 +01:00
|
|
|
|
|
|
|
const defaults = {
|
|
|
|
query: '{}',
|
2023-01-20 15:35:16 +01:00
|
|
|
sort: $applicationSettings.defaultSort || '{ "_id": 1 }',
|
2023-01-10 17:28:27 +01:00
|
|
|
fields: '{}',
|
|
|
|
skip: 0,
|
2023-01-20 15:35:16 +01:00
|
|
|
limit: $applicationSettings.defaultLimit || 15,
|
2023-01-10 17:28:27 +01:00
|
|
|
};
|
|
|
|
|
2023-01-14 20:38:39 +01:00
|
|
|
let form = { ...defaults };
|
2023-01-11 20:41:15 +01:00
|
|
|
let result = {};
|
2023-07-24 20:38:30 +02:00
|
|
|
let countResult = {};
|
2023-01-11 20:41:15 +01:00
|
|
|
let submittedForm = {};
|
2023-01-10 17:28:27 +01:00
|
|
|
let queryField;
|
2023-01-19 09:18:21 +01:00
|
|
|
let activePath = [];
|
2023-01-19 08:57:25 +01:00
|
|
|
let objectViewerData;
|
2023-05-27 17:52:51 +02:00
|
|
|
let querying = false;
|
2023-07-24 20:38:30 +02:00
|
|
|
let counting = false;
|
2023-06-02 22:33:43 +02:00
|
|
|
let objectViewerSuccessMessage = '';
|
2023-06-18 21:31:55 +02:00
|
|
|
let viewsForCollection = {};
|
2023-02-15 17:00:53 +01:00
|
|
|
|
2023-06-11 09:34:00 +02:00
|
|
|
// $: code = `db.${collection.key}.find(${form.query || '{}'}${form.fields && form.fields !== '{}' ? `, ${form.fields}` : ''}).sort(${form.sort})${form.skip ? `.skip(${form.skip})` : ''}${form.limit ? `.limit(${form.limit})` : ''};`;
|
2023-01-20 13:54:57 +01:00
|
|
|
$: lastPage = (submittedForm.limit && result?.results?.length) ? Math.max(0, Math.ceil((result.total - submittedForm.limit) / submittedForm.limit)) : 0;
|
|
|
|
$: activePage = (submittedForm.limit && submittedForm.skip && result?.results?.length) ? submittedForm.skip / submittedForm.limit : 0;
|
2023-01-10 17:28:27 +01:00
|
|
|
|
2023-06-18 21:31:55 +02:00
|
|
|
$: if ($views) {
|
|
|
|
viewsForCollection = views.forCollection(collection.hostKey, collection.dbKey, collection.key);
|
|
|
|
}
|
|
|
|
|
2023-01-20 13:54:57 +01:00
|
|
|
async function submitQuery() {
|
2023-07-08 13:07:55 +02:00
|
|
|
if (querying || !visible) {
|
2023-05-27 17:52:51 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-07-08 13:17:30 +02:00
|
|
|
if (stringCouldBeID(form.query)) {
|
|
|
|
form.query = `{ "_id": "${form.query}" }`;
|
|
|
|
}
|
|
|
|
|
2023-06-23 17:22:47 +02:00
|
|
|
querying = `Querying ${collection.key}…`;
|
2023-01-20 13:54:57 +01:00
|
|
|
activePath = [];
|
2023-06-24 16:05:33 +02:00
|
|
|
const newResult = await FindItems(collection.hostKey, collection.dbKey, collection.key, JSON.stringify({
|
|
|
|
fields: convertLooseJson(form.fields || defaults.fields),
|
|
|
|
limit: form.limit ?? defaults.limit,
|
|
|
|
query: convertLooseJson(form.query) || defaults.query,
|
|
|
|
skip: form.skip ?? defaults.skip,
|
|
|
|
sort: convertLooseJson(form.sort) || defaults.sort,
|
|
|
|
}));
|
2023-05-27 17:52:51 +02:00
|
|
|
|
2023-01-24 20:55:53 +01:00
|
|
|
if (newResult) {
|
|
|
|
newResult.results = newResult.results?.map(s => EJSON.parse(s, { relaxed: false }));
|
|
|
|
result = newResult;
|
2023-02-19 17:26:32 +01:00
|
|
|
submittedForm = deepClone(form);
|
2023-01-20 13:54:57 +01:00
|
|
|
}
|
2023-05-27 17:52:51 +02:00
|
|
|
|
2023-01-20 13:54:57 +01:00
|
|
|
resetFocus();
|
2023-05-27 17:52:51 +02:00
|
|
|
querying = false;
|
2023-01-20 13:54:57 +01:00
|
|
|
}
|
|
|
|
|
2023-07-24 20:38:30 +02:00
|
|
|
async function countItems() {
|
|
|
|
counting = true;
|
|
|
|
countResult = await CountItems(
|
|
|
|
collection.hostKey,
|
|
|
|
collection.dbKey,
|
|
|
|
collection.key,
|
|
|
|
convertLooseJson(form.query) || defaults.query
|
|
|
|
);
|
|
|
|
counting = false;
|
|
|
|
}
|
|
|
|
|
2023-01-20 13:54:57 +01:00
|
|
|
async function refresh() {
|
2023-01-20 15:35:16 +01:00
|
|
|
if ($applicationSettings.autosubmitQuery) {
|
|
|
|
await submitQuery();
|
|
|
|
}
|
2023-01-19 20:57:22 +01:00
|
|
|
}
|
|
|
|
|
2023-06-18 21:31:55 +02:00
|
|
|
async function loadQuery() {
|
|
|
|
const query = await collection.openQueryChooser();
|
|
|
|
if (query) {
|
|
|
|
form = { ...query };
|
|
|
|
submitQuery();
|
|
|
|
}
|
2023-02-15 17:00:53 +01:00
|
|
|
}
|
|
|
|
|
2023-06-18 21:31:55 +02:00
|
|
|
async function saveQuery() {
|
|
|
|
const query = await collection.openQueryChooser(form);
|
|
|
|
if (query) {
|
|
|
|
form = { ...query };
|
2023-02-15 17:00:53 +01:00
|
|
|
submitQuery();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-10 20:22:57 +01:00
|
|
|
function prev() {
|
|
|
|
form.skip -= form.limit;
|
|
|
|
if (form.skip < 0) {
|
|
|
|
form.skip = 0;
|
|
|
|
}
|
|
|
|
submitQuery();
|
|
|
|
}
|
|
|
|
|
|
|
|
function next() {
|
|
|
|
form.skip += form.limit;
|
|
|
|
submitQuery();
|
|
|
|
}
|
|
|
|
|
2023-01-20 13:54:57 +01:00
|
|
|
function first() {
|
|
|
|
form.skip = 0;
|
|
|
|
submitQuery();
|
|
|
|
}
|
|
|
|
|
|
|
|
function last() {
|
|
|
|
form.skip = lastPage * submittedForm.limit;
|
|
|
|
submitQuery();
|
|
|
|
}
|
|
|
|
|
2023-01-19 09:18:21 +01:00
|
|
|
async function removeActive() {
|
|
|
|
if (!activePath[0]) {
|
|
|
|
return;
|
|
|
|
}
|
2023-07-19 21:07:50 +02:00
|
|
|
const sure = await dialogs.confirm('Are you sure you wish to delete this item?');
|
|
|
|
if (!sure) {
|
|
|
|
return;
|
|
|
|
}
|
2023-01-19 09:18:21 +01:00
|
|
|
const ok = await RemoveItemById(collection.hostKey, collection.dbKey, collection.key, activePath[0]);
|
|
|
|
if (ok) {
|
|
|
|
await submitQuery();
|
|
|
|
}
|
2023-01-10 20:22:57 +01:00
|
|
|
}
|
|
|
|
|
2023-01-11 20:41:15 +01:00
|
|
|
function resetFocus() {
|
2023-01-10 17:28:27 +01:00
|
|
|
queryField?.focus();
|
|
|
|
queryField?.select();
|
2023-01-11 20:41:15 +01:00
|
|
|
}
|
|
|
|
|
2023-06-02 22:33:43 +02:00
|
|
|
function openJson(index) {
|
|
|
|
const item = result?.results?.[index];
|
2023-01-19 08:57:25 +01:00
|
|
|
objectViewerData = item;
|
2023-01-15 12:02:17 +01:00
|
|
|
}
|
|
|
|
|
2023-06-18 21:31:55 +02:00
|
|
|
function openViewConfig() {
|
|
|
|
views.openConfig(collection, result.results?.[0] || {});
|
|
|
|
}
|
|
|
|
|
2023-01-13 16:56:48 +01:00
|
|
|
export function performQuery(q) {
|
|
|
|
form = { ...defaults, ...q };
|
|
|
|
submitQuery();
|
|
|
|
}
|
2023-01-19 20:57:22 +01:00
|
|
|
|
2023-06-02 22:33:43 +02:00
|
|
|
async function saveDocument(event) {
|
|
|
|
const progress = startProgress('Performing update…');
|
|
|
|
const success = await UpdateFoundDocument(
|
|
|
|
collection.hostKey,
|
|
|
|
collection.dbKey,
|
|
|
|
collection.key,
|
|
|
|
EJSON.stringify({ _id: event.detail.originalData._id }),
|
2023-06-18 21:31:55 +02:00
|
|
|
convertLooseJson(event.detail.text)
|
2023-06-02 22:33:43 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
if (success) {
|
|
|
|
objectViewerSuccessMessage = 'Document has been saved!';
|
|
|
|
submitQuery();
|
|
|
|
}
|
|
|
|
|
|
|
|
progress.end();
|
|
|
|
}
|
|
|
|
|
2023-01-29 20:00:15 +01:00
|
|
|
$: collection && refresh();
|
2023-07-08 13:07:55 +02:00
|
|
|
$: visible && refresh();
|
2023-01-10 17:28:27 +01:00
|
|
|
</script>
|
|
|
|
|
2023-01-11 20:41:15 +01:00
|
|
|
<div class="find">
|
|
|
|
<form on:submit|preventDefault={submitQuery}>
|
2023-07-01 20:30:43 +02:00
|
|
|
<div class="formrow one">
|
2023-01-11 20:41:15 +01:00
|
|
|
<label class="field">
|
|
|
|
<span class="label">Query or id</span>
|
2023-06-11 09:34:00 +02:00
|
|
|
<input type="text"
|
|
|
|
class="code"
|
2023-06-25 08:16:31 +02:00
|
|
|
placeholder={defaults.query}
|
|
|
|
autocomplete="off"
|
|
|
|
spellcheck="false"
|
2023-07-08 13:17:30 +02:00
|
|
|
use:input
|
2023-06-11 09:34:00 +02:00
|
|
|
bind:this={queryField}
|
|
|
|
bind:value={form.query}
|
2023-06-25 08:16:31 +02:00
|
|
|
/>
|
2023-01-11 20:41:15 +01:00
|
|
|
</label>
|
|
|
|
|
|
|
|
<label class="field">
|
|
|
|
<span class="label">Sort</span>
|
2023-06-25 08:16:31 +02:00
|
|
|
<input
|
|
|
|
type="text"
|
|
|
|
class="code"
|
|
|
|
placeholder={defaults.sort}
|
|
|
|
autocomplete="off"
|
|
|
|
spellcheck="false"
|
|
|
|
bind:value={form.sort}
|
|
|
|
use:input={{ type: 'json' }}
|
|
|
|
/>
|
2023-01-11 20:41:15 +01:00
|
|
|
</label>
|
|
|
|
</div>
|
2023-01-10 17:28:27 +01:00
|
|
|
|
2023-07-01 20:30:43 +02:00
|
|
|
<div class="formrow two">
|
2023-01-11 20:41:15 +01:00
|
|
|
<label class="field">
|
|
|
|
<span class="label">Fields</span>
|
2023-06-25 08:16:31 +02:00
|
|
|
<input
|
|
|
|
type="text"
|
|
|
|
class="code"
|
|
|
|
placeholder={defaults.fields}
|
|
|
|
autocomplete="off"
|
|
|
|
spellcheck="false"
|
|
|
|
bind:value={form.fields}
|
|
|
|
use:input={{ type: 'json' }}
|
|
|
|
/>
|
2023-01-11 20:41:15 +01:00
|
|
|
</label>
|
2023-01-10 17:28:27 +01:00
|
|
|
|
2023-01-11 20:41:15 +01:00
|
|
|
<label class="field">
|
|
|
|
<span class="label">Skip</span>
|
2023-06-11 09:34:00 +02:00
|
|
|
<input type="number"
|
|
|
|
min="0"
|
|
|
|
bind:value={form.skip}
|
|
|
|
use:input
|
|
|
|
placeholder={defaults.skip}
|
2023-06-25 08:16:31 +02:00
|
|
|
list="skipstops"
|
|
|
|
/>
|
2023-01-11 20:41:15 +01:00
|
|
|
</label>
|
2023-01-10 17:28:27 +01:00
|
|
|
|
2023-01-11 20:41:15 +01:00
|
|
|
<label class="field">
|
|
|
|
<span class="label">Limit</span>
|
2023-06-11 09:34:00 +02:00
|
|
|
<input type="number"
|
|
|
|
min="0"
|
|
|
|
bind:value={form.limit}
|
|
|
|
use:input
|
|
|
|
placeholder={defaults.limit}
|
2023-06-25 08:16:31 +02:00
|
|
|
list="limits"
|
|
|
|
/>
|
2023-01-11 20:41:15 +01:00
|
|
|
</label>
|
2023-02-15 17:00:53 +01:00
|
|
|
</div>
|
2023-01-10 17:28:27 +01:00
|
|
|
|
2023-07-01 20:30:43 +02:00
|
|
|
<div class="formrow actions">
|
2023-06-27 17:21:54 +02:00
|
|
|
<button type="submit" class="button" title="Run query">
|
2023-02-15 17:00:53 +01:00
|
|
|
<Icon name="play" /> Run
|
|
|
|
</button>
|
2023-06-27 17:21:54 +02:00
|
|
|
<button class="button secondary" type="button" on:click={() => collection.export(form)}>
|
2023-05-29 20:22:06 +02:00
|
|
|
<Icon name="save" /> Export results…
|
|
|
|
</button>
|
|
|
|
<div class="field">
|
2023-06-27 17:21:54 +02:00
|
|
|
<button class="button secondary" type="button" on:click={loadQuery}>
|
2023-05-29 20:22:06 +02:00
|
|
|
<Icon name="upload" /> Load query…
|
|
|
|
</button>
|
2023-06-27 17:21:54 +02:00
|
|
|
<button class="button secondary" type="button" on:click={saveQuery}>
|
2023-05-29 20:22:06 +02:00
|
|
|
<Icon name="save" /> Save as…
|
|
|
|
</button>
|
|
|
|
</div>
|
2023-01-11 20:41:15 +01:00
|
|
|
</div>
|
|
|
|
</form>
|
2023-01-10 17:28:27 +01:00
|
|
|
|
2023-01-11 20:41:15 +01:00
|
|
|
<div class="result">
|
|
|
|
<div class="grid">
|
|
|
|
{#key result}
|
2023-01-29 20:00:15 +01:00
|
|
|
{#if collection.viewKey === 'list'}
|
|
|
|
<ObjectGrid
|
|
|
|
data={result.results}
|
|
|
|
hideObjectIndicators={$views[collection.viewKey]?.hideObjectIndicators}
|
2023-01-20 13:54:57 +01:00
|
|
|
bind:activePath
|
2023-06-02 22:33:43 +02:00
|
|
|
on:trigger={e => openJson(e.detail?.index)}
|
2023-06-23 17:22:47 +02:00
|
|
|
errorTitle={result.errorTitle}
|
|
|
|
errorDescription={result.errorDescription}
|
|
|
|
busy={querying}
|
2023-01-20 13:54:57 +01:00
|
|
|
/>
|
2023-01-29 20:00:15 +01:00
|
|
|
{:else}
|
|
|
|
<Grid
|
|
|
|
key="_id"
|
2023-06-25 08:16:31 +02:00
|
|
|
columns={$views[collection.viewKey]?.columns
|
|
|
|
?.filter(c => c.showInTable)
|
|
|
|
.map(c => {
|
|
|
|
return { key: c.key, title: c.key };
|
|
|
|
}) || []}
|
2023-01-29 20:00:15 +01:00
|
|
|
showHeaders={true}
|
|
|
|
items={result.results ? result.results.map(r => EJSON.deserialize(r)) : []}
|
2023-01-20 13:54:57 +01:00
|
|
|
bind:activePath
|
2023-06-02 22:33:43 +02:00
|
|
|
on:trigger={e => openJson(e.detail?.index)}
|
2023-06-23 17:22:47 +02:00
|
|
|
errorTitle={result.errorTitle}
|
|
|
|
errorDescription={result.errorDescription}
|
|
|
|
busy={querying}
|
2023-01-20 13:54:57 +01:00
|
|
|
/>
|
|
|
|
{/if}
|
2023-01-11 20:41:15 +01:00
|
|
|
{/key}
|
2023-01-10 20:10:39 +01:00
|
|
|
</div>
|
2023-01-11 20:41:15 +01:00
|
|
|
|
|
|
|
<div class="controls">
|
2023-07-24 20:38:30 +02:00
|
|
|
<div class="count">
|
|
|
|
{#if counting}
|
|
|
|
<span>Counting items…</span>
|
|
|
|
{:else if countResult?.error}
|
|
|
|
<span>{countResult.error}</span>
|
|
|
|
{:else if countResult?.total === -1}
|
|
|
|
<span>Something went wrong</span>
|
|
|
|
{:else if countResult?.total}
|
|
|
|
<!-- svelte-ignore a11y-invalid-attribute -->
|
|
|
|
<a href="" on:click|preventDefault={countItems}>Results: {countResult.total}</a>
|
|
|
|
{:else if result?.total === -1}
|
|
|
|
<!-- svelte-ignore a11y-invalid-attribute -->
|
|
|
|
<a href="" on:click|preventDefault={countItems}>Count items</a>
|
|
|
|
{:else if result?.total}
|
|
|
|
{#key result}
|
|
|
|
<span class="flash-green">Results: {result.total || 0}</span>
|
|
|
|
{/key}
|
|
|
|
{/if}
|
2023-01-11 20:41:15 +01:00
|
|
|
</div>
|
2023-07-24 20:38:30 +02:00
|
|
|
|
2023-01-11 20:41:15 +01:00
|
|
|
<div>
|
2023-01-29 20:00:15 +01:00
|
|
|
<label class="field inline">
|
|
|
|
<select bind:value={collection.viewKey}>
|
2023-06-11 09:34:00 +02:00
|
|
|
{#each Object.entries(viewsForCollection) as [ key, view ]}
|
2023-01-29 20:00:15 +01:00
|
|
|
<option value={key}>{view.name}</option>
|
|
|
|
{/each}
|
|
|
|
</select>
|
2023-06-27 17:21:54 +02:00
|
|
|
<button class="button" on:click={openViewConfig} title="Configure view">
|
2023-01-29 20:00:15 +01:00
|
|
|
<Icon name="cog" />
|
|
|
|
</button>
|
|
|
|
</label>
|
2023-06-27 17:21:54 +02:00
|
|
|
<button class="button danger" on:click={removeActive} disabled={!activePath?.length} title="Drop selected item">
|
2023-01-11 20:41:15 +01:00
|
|
|
<Icon name="-" />
|
|
|
|
</button>
|
2023-06-27 17:21:54 +02:00
|
|
|
<button class="button" on:click={first} disabled={!submittedForm.limit || (submittedForm.skip <= 0) || !result?.results || (activePage === 0)} title="First page">
|
2023-01-20 13:54:57 +01:00
|
|
|
<Icon name="chevs-l" />
|
|
|
|
</button>
|
2023-06-27 17:21:54 +02:00
|
|
|
<button class="button" on:click={prev} disabled={!submittedForm.limit || (submittedForm.skip <= 0) || !result?.results || (activePage === 0)} title="Previous {submittedForm.limit} items">
|
2023-01-11 20:41:15 +01:00
|
|
|
<Icon name="chev-l" />
|
|
|
|
</button>
|
2023-06-27 17:21:54 +02:00
|
|
|
<button class="button" on:click={next} disabled={!submittedForm.limit || ((result?.results?.length || 0) < submittedForm.limit) || !result?.results || !lastPage || (activePage >= lastPage)} title="Next {submittedForm.limit} items">
|
2023-01-11 20:41:15 +01:00
|
|
|
<Icon name="chev-r" />
|
|
|
|
</button>
|
2023-06-27 17:21:54 +02:00
|
|
|
<button class="button" on:click={last} disabled={!submittedForm.limit || ((result?.results?.length || 0) < submittedForm.limit) || !result?.results || !lastPage || (activePage >= lastPage)} title="Last page">
|
2023-01-20 13:54:57 +01:00
|
|
|
<Icon name="chevs-r" />
|
|
|
|
</button>
|
2023-01-11 20:41:15 +01:00
|
|
|
</div>
|
2023-01-10 20:10:39 +01:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2023-01-10 17:28:27 +01:00
|
|
|
|
2023-06-02 21:30:47 +02:00
|
|
|
{#if objectViewerData}
|
2023-06-02 22:33:43 +02:00
|
|
|
<ObjectViewer bind:data={objectViewerData} saveable on:save={saveDocument} bind:successMessage={objectViewerSuccessMessage} />
|
2023-06-02 21:30:47 +02:00
|
|
|
{/if}
|
2023-01-20 13:54:57 +01:00
|
|
|
|
|
|
|
<datalist id="limits">
|
|
|
|
{#each [ 1, 5, 10, 25, 50, 100, 200 ] as value}
|
|
|
|
<option {value} />
|
|
|
|
{/each}
|
|
|
|
</datalist>
|
|
|
|
|
|
|
|
{#if submittedForm?.limit}
|
|
|
|
<datalist id="skipstops">
|
|
|
|
{#each Array(lastPage).fill('').map((_, i) => i * submittedForm.limit) as value}
|
|
|
|
<option {value} />
|
|
|
|
{/each}
|
|
|
|
</datalist>
|
|
|
|
{/if}
|
2023-01-15 12:02:17 +01:00
|
|
|
|
2023-01-10 17:28:27 +01:00
|
|
|
<style>
|
2023-01-11 20:41:15 +01:00
|
|
|
.find {
|
2023-01-10 17:28:27 +01:00
|
|
|
display: grid;
|
|
|
|
gap: 0.5rem;
|
2023-02-15 17:00:53 +01:00
|
|
|
grid-template: auto 1fr / 1fr;
|
2023-01-10 17:28:27 +01:00
|
|
|
}
|
2023-01-11 20:41:15 +01:00
|
|
|
|
2023-07-01 20:30:43 +02:00
|
|
|
.formrow {
|
2023-01-10 17:28:27 +01:00
|
|
|
display: grid;
|
|
|
|
gap: 0.5rem;
|
2023-02-15 17:00:53 +01:00
|
|
|
margin-bottom: 0.5rem;
|
2023-01-11 20:41:15 +01:00
|
|
|
}
|
2023-07-01 20:30:43 +02:00
|
|
|
.formrow.one {
|
2023-01-11 20:41:15 +01:00
|
|
|
grid-template: 1fr / 3fr 2fr;
|
2023-01-10 17:28:27 +01:00
|
|
|
}
|
2023-07-01 20:30:43 +02:00
|
|
|
.formrow.two {
|
2023-02-15 17:00:53 +01:00
|
|
|
grid-template: 1fr / 5fr 1fr 1fr;
|
|
|
|
}
|
2023-07-01 20:30:43 +02:00
|
|
|
.formrow.actions {
|
2023-02-15 17:00:53 +01:00
|
|
|
margin-bottom: 0rem;
|
2023-02-21 20:26:46 +01:00
|
|
|
grid-template: 1fr / repeat(4, auto);
|
|
|
|
justify-content: start;
|
2023-01-11 20:41:15 +01:00
|
|
|
}
|
2023-01-10 20:10:39 +01:00
|
|
|
|
|
|
|
.result {
|
2023-01-11 20:41:15 +01:00
|
|
|
display: grid;
|
|
|
|
grid-template: 1fr auto / 1fr;
|
2023-01-10 20:10:39 +01:00
|
|
|
gap: 0.5rem;
|
2023-01-17 16:22:49 +01:00
|
|
|
overflow: auto;
|
|
|
|
min-height: 0;
|
|
|
|
min-width: 0;
|
2023-01-10 20:10:39 +01:00
|
|
|
}
|
2023-01-11 20:41:15 +01:00
|
|
|
.result > .grid {
|
|
|
|
overflow: auto;
|
2023-01-17 16:22:49 +01:00
|
|
|
min-height: 0;
|
|
|
|
min-width: 0;
|
|
|
|
border: 1px solid #ccc;
|
2023-01-23 13:41:43 +01:00
|
|
|
background-color: #fff;
|
2023-01-10 20:10:39 +01:00
|
|
|
}
|
|
|
|
.result > .controls {
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
|
|
|
align-items: center;
|
|
|
|
}
|
2023-07-24 20:38:30 +02:00
|
|
|
|
|
|
|
.count {
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
}
|
2023-01-10 17:28:27 +01:00
|
|
|
</style>
|