diff --git a/frontend/src/actions.js b/frontend/src/actions.js
index 3a9ba0c..ac3da8c 100644
--- a/frontend/src/actions.js
+++ b/frontend/src/actions.js
@@ -1,4 +1,4 @@
-import { int32, int64, isInt, uint64 } from './utils';
+import { canBeObjectId, int32, int64, isInt, uint64 } from './utils';
export function input(node, { autofocus, type, onValid, onInvalid, mandatory } = {
autofocus: false,
@@ -47,6 +47,9 @@ export function input(node, { autofocus, type, onValid, onInvalid, mandatory } =
}
return false;
+ case 'objectid':
+ return !canBeObjectId(node.value) && 'Invalid string representation of an ObjectId';
+
case 'double':
case 'decimal':
default:
diff --git a/frontend/src/components/clock.svelte b/frontend/src/components/clock.svelte
new file mode 100644
index 0000000..6ae78fd
--- /dev/null
+++ b/frontend/src/components/clock.svelte
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+ {#each [ 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55 ] as minute}
+
+
+ {#each [ 1, 2, 3, 4 ] as offset}
+
+ {/each}
+ {/each}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/components/datepicker.svelte b/frontend/src/components/datepicker.svelte
new file mode 100644
index 0000000..98d30a4
--- /dev/null
+++ b/frontend/src/components/datepicker.svelte
@@ -0,0 +1,201 @@
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/components/forminput.svelte b/frontend/src/components/forminput.svelte
new file mode 100644
index 0000000..2203217
--- /dev/null
+++ b/frontend/src/components/forminput.svelte
@@ -0,0 +1,136 @@
+
+
+
+
+{#if type === 'date'}
+
+{/if}
+
+
diff --git a/frontend/src/components/grid-items.svelte b/frontend/src/components/grid-items.svelte
index 6786d7b..d0ac33f 100644
--- a/frontend/src/components/grid-items.svelte
+++ b/frontend/src/components/grid-items.svelte
@@ -2,7 +2,8 @@
import { contextMenu } from '../stores';
import { createEventDispatcher } from 'svelte';
import Icon from './icon.svelte';
- import { resolveKeypath } from '../utils';
+ import { resolveKeypath, setValue } from '../utils';
+ import FormInput from './forminput.svelte';
export let items = [];
export let columns = [];
@@ -14,18 +15,34 @@
export let striped = true;
export let hideObjectIndicators = false;
export let hideChildrenToggles = false;
+ export let canSelect = true;
+ export let canRemoveItems = false;
+ export let inputsValid = false;
const dispatch = createEventDispatcher();
+ const keypathProxies = {};
+ const validity = {};
let childrenOpen = {};
let _items = [];
$: refresh(hideObjectIndicators, items);
+ $: inputsValid = Object.values(validity).every(v => !!v);
function refresh(hideObjectIndicators, items) {
_items = objectToArray(items).map(item => {
item.children = objectToArray(item.children);
return item;
});
+
+ for (let index = 0; index < _items.length; index++) {
+ keypathProxies[index] = new Proxy(_items, {
+ get: (_items, key) => resolveKeypath(_items[index], key),
+ set: (_items, key, value) => {
+ setValue(_items[index], key, value);
+ return true;
+ },
+ });
+ }
}
function objectToArray(obj) {
@@ -41,6 +58,10 @@
}
function select(itemKey) {
+ if (!canSelect) {
+ return false;
+ }
+
if (activeKey !== itemKey) {
activeKey = itemKey;
if (level === 0) {
@@ -75,6 +96,11 @@
contextMenu.show(evt, item.menu);
}
+ function removeItem(index) {
+ items.splice(index, 1);
+ items = items;
+ }
+
function formatValue(value) {
if (Array.isArray(value)) {
return hideObjectIndicators ? '' : '[...]';
@@ -98,12 +124,13 @@
}
-{#each _items as item}
+{#each _items as item, index}
select(item[key])}
on:dblclick={() => doubleClick(item[key])}
on:contextmenu|preventDefault={evt => showContextMenu(evt, item)}
- class:selected={!activePath[level + 1] && activePath.every(k => path.includes(k) || k === item[key]) && (activePath[level] === item[key])}
+ class:selectable={canSelect}
+ class:selected={canSelect && !activePath[level + 1] && activePath.every(k => path.includes(k) || k === item[key]) && (activePath[level] === item[key])}
class:striped
>
{#if !hideChildrenToggles}
@@ -127,21 +154,35 @@
{#each columns as column, columnIndex}
- {@const value = column.key?.includes('.') ? resolveKeypath(item, column.key) : item[column.key]}
-
-
- {formatValue(value)}
-
+
+ {#if column.inputType}
+
+ {:else}
+
+ {formatValue(keypathProxies[index][column.key])}
+
+ {/if}
{/each}
+
+ {#if canRemoveItems}
+
+ removeItem(index)}>
+
+
+
+ {/if}
{#if item.children && childrenOpen[item[key]]}
+ import { createEventDispatcher } from 'svelte';
import GridItems from './grid-items.svelte';
- // import Icon from './icon.svelte';
+ import Icon from './icon.svelte';
export let columns = [];
export let items = [];
- // export let actions = [];
export let key = 'id';
export let activePath = [];
export let striped = true;
export let showHeaders = false;
export let hideObjectIndicators = false;
export let hideChildrenToggles = false;
+ export let canAddRows = false;
+ export let canSelect = true;
+ export let canRemoveItems = false;
+ export let inputsValid = false;
+ // export let actions = [];
+
+ const dispatch = createEventDispatcher();
+
+ function addRow() {
+ dispatch('addRow');
+ }
@@ -38,6 +49,10 @@
{#each columns as column}
{column.title || ''}
{/each}
+
+ {#if canRemoveItems}
+
+ {/if}
{/if}
@@ -48,13 +63,24 @@
{columns}
{key}
{striped}
+ {canSelect}
+ {canRemoveItems}
{hideObjectIndicators}
{hideChildrenToggles}
bind:activePath
+ bind:inputsValid
on:select
on:trigger
/>
+
+ {#if canAddRows}
+
+
+
+
+
+ {/if}
@@ -86,8 +112,10 @@
th {
font-weight: 600;
text-align: left;
- }
- th {
padding: 2px;
}
+
+ /* tfoot button {
+ margin-top: 0.5rem;
+ } */
diff --git a/frontend/src/components/icon.svelte b/frontend/src/components/icon.svelte
index 100c8ea..88c8ea0 100644
--- a/frontend/src/components/icon.svelte
+++ b/frontend/src/components/icon.svelte
@@ -73,5 +73,11 @@
{:else if name === 'target'}
+ {:else if name === 'trash'}
+
+ {:else if name === 'anchor'}
+
+ {:else if name === 'o'}
+
{/if}
diff --git a/frontend/src/components/objectgrid.svelte b/frontend/src/components/objectgrid.svelte
index 136636b..f171e15 100644
--- a/frontend/src/components/objectgrid.svelte
+++ b/frontend/src/components/objectgrid.svelte
@@ -1,5 +1,6 @@
{#if displayOnly}
{#if items.length}
{#if draggable && isArray}
- dragstart(e, kp, data)} draggable="true" class="bracket" on:click={clicked} tabindex="0">{openBracket}
+ onDragstart(e, kp, data)} draggable="true" class="bracket" on:click={onClick} tabindex="0">{openBracket}
{:else}
- {openBracket}
+ {openBracket}
{/if}
(readonly ? displayOnly = true : displayOnly = false)} >
{#each items as i, idx}
{#if !isArray}
{#if draggable}
- dragstart(e, kp ? kp + '.' + i : i, data[i])} draggable="true" class="key">{i}:
+ onDragstart(e, kp ? kp + '.' + i : i, data[i])} draggable="true" class="key">{i}:
{:else}
{i}:
{/if}
@@ -107,7 +110,7 @@
{:else}
{#if draggable}
- dragstart(e, kp ? kp + '.' + i : i, data[i])} draggable="true" class="val {getType(data[i])}">{format(data[i])} {#if idx < items.length - 1}, {/if}
+ onDragstart(e, kp ? kp + '.' + i : i, data[i])} draggable="true" class="val {getType(data[i])}">{format(data[i])} {#if idx < items.length - 1}, {/if}
{:else}
{format(data[i])} {#if idx < items.length - 1}, {/if}
{/if}
@@ -115,16 +118,14 @@
{/each}
- {closeBracket} {#if !last},
- {/if}
+ {closeBracket} {#if !last}, {/if}
- {openBracket}{collapsedSymbol}{closeBracket} {#if !last && collapsed}, {/if}
+ {openBracket}{collapsedSymbol}{closeBracket} {#if !last && collapsed}, {/if}
{:else}
{@html isArray ? '[]' : '{}'}
{/if}
{:else}
-
+
{/if}
diff --git a/frontend/src/organisms/connection/collection/components/form.svelte b/frontend/src/organisms/connection/collection/components/form.svelte
index 73cb13a..5e20194 100644
--- a/frontend/src/organisms/connection/collection/components/form.svelte
+++ b/frontend/src/organisms/connection/collection/components/form.svelte
@@ -1,7 +1,7 @@
{#if item && view}
- {#each view?.columns?.filter(c => c.inputType !== 'none') || [] as column}
+ {#each view?.columns?.filter(c => inputTypes.includes(c.inputType)) || [] as column}
@@ -49,9 +46,6 @@
- reset(column.key)} disabled={keypathProxy[column.key] === undefined}>
-
-
{/each}
@@ -75,12 +69,6 @@
height: 13px;
}
- .input {
- display: grid;
- grid-template: 1fr / 1fr auto;
- gap: 0.5rem;
- }
-
.tag {
display: inline-block;
background-color: rgba(140, 140, 140, 0.1);
diff --git a/frontend/src/organisms/connection/collection/components/forminput.svelte b/frontend/src/organisms/connection/collection/components/forminput.svelte
deleted file mode 100644
index 92ce207..0000000
--- a/frontend/src/organisms/connection/collection/components/forminput.svelte
+++ /dev/null
@@ -1,73 +0,0 @@
-
-
-
- {#if type === 'string'}
-
- {:else if numericTypes.includes(type)}
-
- {:else if type === 'bool'}
-
- Unset
- Yes / true
- No / false
-
- {:else if type === 'date'}
- {@const isNotDate = !isDate(value)}
-
-
- {/if}
-
-
-
diff --git a/frontend/src/organisms/connection/collection/components/viewconfig.svelte b/frontend/src/organisms/connection/collection/components/viewconfig.svelte
index 62a68c9..0406dad 100644
--- a/frontend/src/organisms/connection/collection/components/viewconfig.svelte
+++ b/frontend/src/organisms/connection/collection/components/viewconfig.svelte
@@ -151,7 +151,7 @@
Hidden in form
String
- ObjectID
+ ObjectId
Integer (32-bit, signed)
diff --git a/frontend/src/organisms/connection/collection/insert.svelte b/frontend/src/organisms/connection/collection/insert.svelte
index a97a871..3914932 100644
--- a/frontend/src/organisms/connection/collection/insert.svelte
+++ b/frontend/src/organisms/connection/collection/insert.svelte
@@ -6,6 +6,8 @@
import Icon from '../../../components/icon.svelte';
import Form from './components/form.svelte';
import ObjectViewer from '../../../components/objectviewer.svelte';
+ import Grid from '../../../components/grid.svelte';
+ import { inputTypes, randomString } from '../../../utils';
export let collection;
@@ -50,6 +52,10 @@
objectViewerData = [ ...newItems ];
}
}
+
+ function addRow() {
+ newItems = [ ...newItems, {} ];
+ }