1
0
mirror of https://github.com/garraflavatra/rolens.git synced 2025-04-16 15:51:03 +00:00

157 lines
4.2 KiB
Svelte

<script>
import Details from '$components/details.svelte';
import Icon from '$components/icon.svelte';
import Modal from '$components/modal.svelte';
import ObjectEditor from '$components/objecteditor.svelte';
import { aggregationStageDocumentationURL, aggregationStages } from '$lib/mongo';
import Collation from '$lib/mongo/collation.svelte';
import { jsonLooseParse, looseJsonIsValid } from '$lib/strings';
import { Aggregate } from '$wails/go/app/App';
import { BrowserOpenURL } from '$wails/runtime/runtime';
import { onMount } from 'svelte';
export let collection;
const options = {};
let stages = [];
let settingsModalOpen = false;
$: invalid = !stages.length || stages.some(stage => !stage.data || !looseJsonIsValid(stage.data));
function addStage() {
stages = [ ...stages, { type: '$match' } ];
}
function deleteStage(index) {
stages = [ ...stages.slice(0, index), ...stages.slice(index + 1) ];
}
function openStageDocs(type) {
const url = aggregationStageDocumentationURL(type);
BrowserOpenURL(url);
}
async function run() {
const pipeline = stages.map(stage => {
return { [stage.type]: jsonLooseParse(stage.data) };
});
await Aggregate(
collection.hostKey,
collection.dbKey,
collection.key,
JSON.stringify(pipeline),
JSON.stringify(options)
);
}
onMount(() => {
if (!stages.length) {
stages = [ { type: '$match' } ];
}
});
</script>
<form class="aggregate" on:submit|preventDefault={run}>
<div>
{#each stages as stage, index}
<Details title="#{index + 1}: {stage.type}" deletable={true} on:delete={() => deleteStage(index)} initiallyOpen>
<label class="field">
<span class="label">Stage type</span>
<select bind:value={stage.type}>
{#each aggregationStages as value}
<option {value}>{value}</option>
{/each}
</select>
<button class="button secondary" type="button" on:click={() => openStageDocs(stage.type)} title="Open documentation about {stage.type || 'this stage'} on mongodb.org">
<Icon name="?" />
</button>
</label>
<!-- svelte-ignore a11y-label-has-associated-control -->
<label class="field">
<ObjectEditor
bind:text={stage.data}
on:inited={e => {
e.detail.editor.dispatch({
changes: {
from: 0,
to: e.detail.editor.state.doc.length,
insert: '{\n\t\n}',
},
selection: {
anchor: 3,
},
});
}} />
</label>
</Details>
{/each}
<button class="button-small" type="button" on:click={addStage}>
<Icon name="+" /> Add stage
</button>
</div>
<div class="controls">
<div>
<button class="button" type="submit" disabled={invalid}>
<Icon name="play" /> Run pipeline
</button>
<button class="button" type="button" on:click={() => settingsModalOpen = true}>
<Icon name="cog" /> Settings
</button>
</div>
</div>
</form>
<Modal title="Advanced aggregation settings" show={settingsModalOpen} on:close={() => settingsModalOpen = false}>
<div class="settinggrid">
<label for="allowDiskUse">Allow disk use</label>
<div class="field">
<span class="checkbox">
<input type="checkbox" id="allowDiskUse" bind:checked={options.allowDiskUse} />
</span>
</div>
</div>
<Details title="Set custom collation options">
<Collation bind:collation={options.collation} />
</Details>
</Modal>
<style>
.aggregate {
display: grid;
gap: 0.5rem;
grid-template: 1fr auto / 1fr;
}
.aggregate :global(details) {
position: relative;
z-index: 2;
}
.aggregate :global(details + details::before) {
content: "";
position: absolute;
top: -0.6rem;
left: 50%;
width: 1px;
height: 0.6rem;
background-color: #888;
z-index: 1;
}
.settinggrid {
margin-bottom: 0.5rem;
}
.controls {
display: flex;
justify-content: space-between;
align-items: center;
}
.field + .field {
margin-top: 0.5rem;
}
</style>