mirror of
https://github.com/garraflavatra/rolens.git
synced 2025-07-19 14:14:05 +00:00
Loose JSON parsing. Many UI improvements.
This commit is contained in:
@ -5,6 +5,7 @@
|
||||
import MongoCollation from '$components/mongo-collation.svelte';
|
||||
import input from '$lib/actions/input';
|
||||
import { aggregationStageDocumentationURL, aggregationStages } from '$lib/mongo';
|
||||
import { jsonLooseParse, looseJsonIsValid } from '$lib/strings';
|
||||
import { Aggregate } from '$wails/go/app/App';
|
||||
import { BrowserOpenURL } from '$wails/runtime/runtime';
|
||||
import { onMount } from 'svelte';
|
||||
@ -14,15 +15,7 @@
|
||||
const options = {};
|
||||
let stages = [];
|
||||
let settingsModalOpen = false;
|
||||
$: invalid = !stages.length || stages.some(stage => {
|
||||
try {
|
||||
JSON.parse(stage.data);
|
||||
return false;
|
||||
}
|
||||
catch {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
$: invalid = !stages.length || stages.some(stage => !stage.data || !looseJsonIsValid(stage.data));
|
||||
|
||||
function addStage() {
|
||||
stages = [ ...stages, { type: '$match' } ];
|
||||
@ -38,7 +31,7 @@
|
||||
}
|
||||
|
||||
async function run() {
|
||||
const pipeline = stages.map(stage => ({ [stage.type]: JSON.parse(stage.data) }));
|
||||
const pipeline = stages.map(stage => ({ [stage.type]: jsonLooseParse(stage.data) }));
|
||||
await Aggregate(collection.hostKey, collection.dbKey, collection.key, JSON.stringify(pipeline), JSON.stringify(options));
|
||||
}
|
||||
|
||||
@ -84,11 +77,10 @@
|
||||
<Icon name="cog" /> Settings
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<Modal title="Advanced settings" bind:show={settingsModalOpen}>
|
||||
<Modal title="Advanced aggregation settings" bind:show={settingsModalOpen}>
|
||||
<div class="settinggrid">
|
||||
<label for="allowDiskUse">Allow disk use</label>
|
||||
<div class="field">
|
||||
|
@ -2,7 +2,7 @@
|
||||
import FormInput from '$components/forminput.svelte';
|
||||
import Icon from '$components/icon.svelte';
|
||||
import { inputTypes } from '$lib/mongo';
|
||||
import { resolveKeypath, setValue } from '$lib/keypaths';
|
||||
import { resolveKeypath, setValue } from '$lib/objects';
|
||||
import Hint from '$components/hint.svelte';
|
||||
|
||||
export let item = {};
|
||||
|
@ -1,9 +1,10 @@
|
||||
<script>
|
||||
import CodeExample from '$components/code-example.svelte';
|
||||
// import CodeExample from '$components/code-example.svelte';
|
||||
import Grid from '$components/grid.svelte';
|
||||
import Icon from '$components/icon.svelte';
|
||||
import ObjectGrid from '$components/objectgrid.svelte';
|
||||
import input from '$lib/actions/input';
|
||||
import { deepClone } from '$lib/objects';
|
||||
import queries from '$lib/stores/queries';
|
||||
import applicationSettings from '$lib/stores/settings';
|
||||
import views from '$lib/stores/views';
|
||||
@ -45,7 +46,7 @@
|
||||
if (newResult) {
|
||||
newResult.results = newResult.results?.map(s => EJSON.parse(s, { relaxed: false }));
|
||||
result = newResult;
|
||||
submittedForm = JSON.parse(JSON.stringify(form));
|
||||
submittedForm = deepClone(form);
|
||||
}
|
||||
resetFocus();
|
||||
}
|
||||
@ -157,12 +158,12 @@
|
||||
</div>
|
||||
|
||||
<div class="form-row three">
|
||||
<CodeExample {code} />
|
||||
<button class="btn" type="button" on:click={loadQuery} title="Load query…">
|
||||
<Icon name="upload" />
|
||||
<!-- <CodeExample {code} /> -->
|
||||
<button class="btn" type="button" on:click={loadQuery}>
|
||||
<Icon name="upload" /> Load query…
|
||||
</button>
|
||||
<button class="btn" type="button" on:click={saveQuery} title="Save query as…">
|
||||
<Icon name="save" />
|
||||
<button class="btn" type="button" on:click={saveQuery}>
|
||||
<Icon name="save" /> Save as…
|
||||
</button>
|
||||
<button type="submit" class="btn" title="Run query">
|
||||
<Icon name="play" /> Run
|
||||
@ -274,7 +275,8 @@
|
||||
}
|
||||
.form-row.three {
|
||||
margin-bottom: 0rem;
|
||||
grid-template: 1fr / 1fr repeat(3, auto);
|
||||
grid-template: 1fr / repeat(3, auto);
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
.result {
|
||||
|
@ -29,6 +29,10 @@
|
||||
collection.key = collectionKey;
|
||||
}
|
||||
|
||||
$: if (hostKey || dbKey || collectionKey) {
|
||||
tab = 'find';
|
||||
}
|
||||
|
||||
EventsOn('OpenCollectionTab', name => (tab = name || tab));
|
||||
|
||||
async function catchQuery(event) {
|
||||
|
@ -43,6 +43,16 @@
|
||||
</script>
|
||||
|
||||
<div class="indexes">
|
||||
<div class="grid">
|
||||
<ObjectGrid
|
||||
key="name"
|
||||
data={indexes}
|
||||
getRootMenu={(_, idx) => [ { label: 'Drop this index', fn: () => drop(idx.name) } ]}
|
||||
bind:activePath
|
||||
on:trigger={e => openJson(e.detail.itemKey)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button class="btn" on:click={getIndexes}>
|
||||
<Icon name="reload" /> Reload
|
||||
@ -54,16 +64,6 @@
|
||||
<Icon name="x" /> Drop selected
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<ObjectGrid
|
||||
key="name"
|
||||
data={indexes}
|
||||
getRootMenu={(_, idx) => [ { label: 'Drop this index', fn: () => drop(idx.name) } ]}
|
||||
bind:activePath
|
||||
on:trigger={e => openJson(e.detail.itemKey)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ObjectViewer bind:data={objectViewerData} />
|
||||
@ -73,7 +73,7 @@
|
||||
.indexes {
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
grid-template: auto 1fr / 1fr;
|
||||
grid-template: 1fr auto / 1fr;
|
||||
}
|
||||
|
||||
.indexes .grid {
|
||||
|
@ -7,7 +7,7 @@
|
||||
import { randomString } from '$lib/math';
|
||||
import { inputTypes } from '$lib/mongo';
|
||||
import views from '$lib/stores/views';
|
||||
import { capitalise } from '$lib/strings';
|
||||
import { capitalise, convertLooseJson, jsonLooseParse } from '$lib/strings';
|
||||
import { InsertItems } from '$wails/go/app/App';
|
||||
import { EJSON } from 'bson';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
@ -32,7 +32,7 @@
|
||||
$: {
|
||||
if (collection.viewKey === 'list') {
|
||||
try {
|
||||
newItems = EJSON.parse(json, { relaxed: false });
|
||||
newItems = EJSON.deserialize(jsonLooseParse(json), { relaxed: false });
|
||||
}
|
||||
catch { /* ok */ }
|
||||
}
|
||||
@ -46,7 +46,7 @@
|
||||
}
|
||||
|
||||
async function insert() {
|
||||
insertedIds = await InsertItems(collection.hostKey, collection.dbKey, collection.key, json);
|
||||
insertedIds = await InsertItems(collection.hostKey, collection.dbKey, collection.key, convertLooseJson(json));
|
||||
if ((collection.viewKey === 'list') && insertedIds) {
|
||||
newItems = [];
|
||||
}
|
||||
@ -95,15 +95,8 @@
|
||||
<form on:submit|preventDefault={insert}>
|
||||
<div class="items">
|
||||
{#if collection.viewKey === 'list'}
|
||||
<label class="field">
|
||||
<textarea
|
||||
cols="30"
|
||||
rows="10"
|
||||
placeholder="[]"
|
||||
class="code"
|
||||
bind:value={json}
|
||||
use:input={{ type: 'json', autofocus: true }}
|
||||
></textarea>
|
||||
<label class="field json">
|
||||
<textarea placeholder="[]" class="code" bind:value={json} use:input={{ type: 'json', autofocus: true }}></textarea>
|
||||
</label>
|
||||
{:else if viewType === 'form'}
|
||||
<div class="form">
|
||||
@ -208,4 +201,11 @@
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.field.json {
|
||||
height: 100%;
|
||||
}
|
||||
.field.json textarea {
|
||||
resize: none;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script>
|
||||
import CodeExample from '$components/code-example.svelte';
|
||||
// import CodeExample from '$components/code-example.svelte';
|
||||
import Icon from '$components/icon.svelte';
|
||||
import input from '$lib/actions/input';
|
||||
import { RemoveItems } from '$wails/go/app/App';
|
||||
@ -17,15 +17,7 @@
|
||||
</script>
|
||||
|
||||
<form on:submit|preventDefault={removeItems}>
|
||||
<div class="options">
|
||||
<CodeExample {code} />
|
||||
<label class="field">
|
||||
<span class="label">Many</span>
|
||||
<span class="checkbox">
|
||||
<input type="checkbox" bind:checked={many} />
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<!-- <CodeExample {code} /> -->
|
||||
|
||||
<label class="field">
|
||||
<textarea
|
||||
@ -38,35 +30,38 @@
|
||||
></textarea>
|
||||
</label>
|
||||
|
||||
<div class="flex">
|
||||
<div>
|
||||
{#key result}
|
||||
{#if typeof result === 'number'}
|
||||
<span class="flash-green">Removed {result} item{result === 1 ? '' : 's'}</span>
|
||||
{/if}
|
||||
{/key}
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button type="submit" class="btn danger">
|
||||
<Icon name="-" /> Remove
|
||||
</button>
|
||||
|
||||
<label class="field many">
|
||||
<span class="label">Many</span>
|
||||
<span class="checkbox">
|
||||
<input type="checkbox" bind:checked={many} />
|
||||
</span>
|
||||
</label>
|
||||
|
||||
{#key result}
|
||||
{#if typeof result === 'number'}
|
||||
<span class="flash-green">Removed {result} item{result === 1 ? '' : 's'}</span>
|
||||
{/if}
|
||||
{/key}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<style>
|
||||
form {
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
grid-template-rows: 1fr auto;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.options {
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
grid-template: 1fr / 1fr auto;
|
||||
.many {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
textarea {
|
||||
resize: none;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,12 +1,12 @@
|
||||
<script>
|
||||
import CodeExample from '$components/code-example.svelte';
|
||||
// import CodeExample from '$components/code-example.svelte';
|
||||
import ObjectGrid from '$components/objectgrid.svelte';
|
||||
|
||||
export let collection;
|
||||
</script>
|
||||
|
||||
<div class="stats">
|
||||
<CodeExample code="db.stats()" />
|
||||
<!-- <CodeExample code="db.stats()" /> -->
|
||||
|
||||
<div class="grid">
|
||||
<ObjectGrid data={collection.stats} />
|
||||
@ -17,7 +17,7 @@
|
||||
.stats {
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
grid-template: auto 1fr / 1fr;
|
||||
grid-template: auto / 1fr;
|
||||
}
|
||||
|
||||
.stats .grid {
|
||||
|
@ -1,45 +1,31 @@
|
||||
<script>
|
||||
import CodeExample from '$components/code-example.svelte';
|
||||
// import CodeExample from '$components/code-example.svelte';
|
||||
import Icon from '$components/icon.svelte';
|
||||
import input from '$lib/actions/input';
|
||||
import { atomicUpdateOperators } from '$lib/mongo';
|
||||
import { deepClone } from '$lib/objects';
|
||||
import { convertLooseJson, jsonLooseParse } from '$lib/strings';
|
||||
import { UpdateItems } from '$wails/go/app/App';
|
||||
|
||||
export let collection = {};
|
||||
|
||||
const atomicUpdateOperators = {
|
||||
'Fields': {
|
||||
$currentDate: 'Current Date',
|
||||
$inc: 'Increment',
|
||||
$min: 'Min',
|
||||
$max: 'Max',
|
||||
$mul: 'Multiply',
|
||||
$rename: 'Rename',
|
||||
$set: 'Set',
|
||||
$setOnInsert: 'Set on Insert',
|
||||
$unset: 'Unset',
|
||||
},
|
||||
'Array': {
|
||||
$addToSet: 'Add to Set',
|
||||
$pop: 'Pop',
|
||||
$pull: 'Pull',
|
||||
$push: 'Push',
|
||||
$pullAll: 'Push All',
|
||||
},
|
||||
'Modifiers': {
|
||||
$each: 'Each',
|
||||
$position: 'Position',
|
||||
$slice: 'Slice',
|
||||
$sort: 'Sort',
|
||||
},
|
||||
'Bitwise': {
|
||||
$bit: 'Bit',
|
||||
},
|
||||
};
|
||||
const allOperators = Object.values(atomicUpdateOperators).map(Object.keys).flat();
|
||||
|
||||
const form = { query: '{}', parameters: [ { type: '$set' } ] };
|
||||
let updatedCount;
|
||||
$: code = buildCode(form);
|
||||
$: invalid = !form.query || form.parameters?.some(param => {
|
||||
if (!param.value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
jsonLooseParse(param.value);
|
||||
return false;
|
||||
}
|
||||
catch {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
function buildCode(form) {
|
||||
let operation = '{ ' + form.parameters.filter(p => p.type).map(p => `${p.type}: ${p.value || '{}'}`).join(', ') + ' }';
|
||||
@ -58,7 +44,10 @@
|
||||
}
|
||||
|
||||
async function submitQuery() {
|
||||
updatedCount = await UpdateItems(collection.hostKey, collection.dbKey, collection.key, JSON.stringify(form));
|
||||
const f = deepClone(form);
|
||||
f.query = convertLooseJson(f.query);
|
||||
f.parameters = f.parameters.map(param => ({ ...param, value: convertLooseJson(param.value) }));
|
||||
updatedCount = await UpdateItems(collection.hostKey, collection.dbKey, collection.key, JSON.stringify(f));
|
||||
}
|
||||
|
||||
function removeParam(index) {
|
||||
@ -92,7 +81,7 @@
|
||||
</script>
|
||||
|
||||
<form class="update" on:submit|preventDefault={submitQuery}>
|
||||
<CodeExample language="json" {code} />
|
||||
<!-- <CodeExample language="json" {code} /> -->
|
||||
|
||||
<div class="options">
|
||||
<label class="field">
|
||||
@ -117,7 +106,7 @@
|
||||
{/if}
|
||||
{/key}
|
||||
|
||||
<button class="btn" type="submit">
|
||||
<button class="btn" type="submit" disabled={invalid}>
|
||||
<Icon name="check" /> Update
|
||||
</button>
|
||||
</div>
|
||||
@ -135,7 +124,7 @@
|
||||
{#each Object.entries(atomicUpdateOperators) as [groupName, options]}
|
||||
<optgroup label={groupName}>
|
||||
{#each Object.entries(options) as [key, label]}
|
||||
<option value={key} disabled={form.parameters.some(p => p.type === key)}>
|
||||
<option value={key} disabled={form.parameters.some(p => p.type === key) && (key !== param.type)}>
|
||||
{label}
|
||||
</option>
|
||||
{/each}
|
||||
@ -145,14 +134,13 @@
|
||||
<input type="text" class="code" bind:value={param.value} placeholder={'{}'} use:input={{ type: 'json' }} />
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
<button class="btn" disabled={form.parameters.length >= allOperators.length} on:click={() => addParameter()} type="button">
|
||||
<Icon name="+" />
|
||||
</button>
|
||||
<button class="btn" disabled={form.parameters.length < 2} on:click={() => removeParam(index)} type="button">
|
||||
<Icon name="-" />
|
||||
</button>
|
||||
</label>
|
||||
<button class="btn" disabled={form.parameters.length >= allOperators.length} on:click={() => addParameter()} type="button">
|
||||
<Icon name="+" />
|
||||
</button>
|
||||
|
||||
<button class="btn" disabled={form.parameters.length < 2} on:click={() => removeParam(index)} type="button">
|
||||
<Icon name="-" />
|
||||
</button>
|
||||
</fieldset>
|
||||
{/each}
|
||||
</fieldset>
|
||||
@ -162,7 +150,7 @@
|
||||
.update {
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
grid-template: auto auto auto 1fr / 1fr;
|
||||
grid-template: auto auto 1fr / 1fr;
|
||||
}
|
||||
|
||||
.options {
|
||||
@ -181,7 +169,7 @@
|
||||
}
|
||||
.parameter {
|
||||
display: grid;
|
||||
grid-template: 1fr / 1fr auto;
|
||||
grid-template: 1fr / 1fr auto auto;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user