+
{#if unlocked}
- Editing is unlocked for this table (this browser tab). Changes go straight into data the {t.schema} app uses, and are logged.
+ Editing is unlocked for this table (this browser tab). Changes go straight into data the {t.schema}
+ app uses, and are logged.
setUnlocked(false)}>lock again
{:else}
This table belongs to the {t.schema} app, so it is read-only by default.
- (unlockOpen = true)}>unlock editing…
+ (unlockOpen = true)}
+ >unlock editing…
{/if}
{/if}
@@ -359,14 +410,27 @@
aria-label="Search rows"
/>
@@ -374,14 +438,34 @@
{#if editable && t.canInsert}
+ row
fileInput?.click()}>import CSV
-
+
{/if}
{#if t.isList && t.access === 'open'}
-
{ colError = ''; colOpen = true; }}>+ column
+
{
+ colError = '';
+ colOpen = true;
+ }}>+ column
{/if}
-
export CSV
+
export CSV
{#if editable && t.canDelete && selectedRows.length}
-
askDelete(selectedRows)}>delete {selectedRows.length}
+
askDelete(selectedRows)}
+ >delete {selectedRows.length}
{/if}
@@ -399,11 +483,24 @@
{/if}
{#if data.queryError}
-
+
+
{#if t.primaryKey.length}
@@ -412,38 +509,73 @@
type="checkbox"
aria-label="Select all rows on this page"
checked={rows.length > 0 && selectedRows.length === rows.length}
- onchange={(e) => (selected = e.currentTarget.checked ? Object.fromEntries(rows.map((r) => [keyOf(r), true])) : {})}
+ onchange={(e) =>
+ (selected = e.currentTarget.checked
+ ? Object.fromEntries(rows.map((r) => [keyOf(r), true]))
+ : {})}
/>
{/if}
{#each cols as c (c.name)}
{@const sorted = params.get('sort') === c.name}
-
- sortBy(c)} title={c.help ?? `Sort by ${c.name}`}>
- {c.name}{#if c.pk}PK {/if}{#if sorted}{params.get('dir') === 'desc' ? ' ↓' : ' ↑'} {/if}
+
+ sortBy(c)}
+ title={c.help ?? `Sort by ${c.name}`}
+ >
+ {c.name}{#if c.pk}PK {/if}{#if sorted}{params.get('dir') === 'desc' ? ' ↓' : ' ↑'} {/if}
- {shortType(c.type)}{c.nullable ? '' : ' · req'}{c.fk ? ` → ${c.fk.table}` : ''}{c.readOnly ? ' · auto' : ''}
+ {shortType(c.type)}{c.nullable ? '' : ' · req'}{c.fk
+ ? ` → ${c.fk.table}`
+ : ''}{c.readOnly ? ' · auto' : ''}
{/each}
- {#if editable && t.canDelete} {/if}
+ {#if editable && t.canDelete} {/if}
{#each rows as row, r (keyOf(row) + r)}
-
+
{#if t.primaryKey.length}
-
+
{/if}
{#each cols as c, ci (c.name)}
{@const v = row[c.name]}
{#if editing && editing.r === r && editing.c === ci}
-
- Enter{c.kind === 'json' || c.uiType === 'longtext' ? ' + Ctrl' : ''} save · Esc cancel · Tab next
+
+
+ Enter{c.kind === 'json' || c.uiType === 'longtext' ? ' + Ctrl' : ''} save · Esc cancel
+ · Tab next
+
{:else}
(active = { r, c: ci })}
ondblclick={() => startEdit(r, ci)}
onkeydown={(e) => cellKey(e, r, ci)}
>
- {#if v === null}null
- {:else if c.fk && data.fkLabels[c.name]?.[String(v)]}{data.fkLabels[c.name][String(v)]}
+ {#if v === null}null
+ {:else if c.fk && data.fkLabels[c.name]?.[String(v)]}{data.fkLabels[c.name][String(v)]}
{:else if (c.uiType === 'url' || c.uiType === 'image') && typeof v === 'string' && /^https?:\/\//.test(v)}
- {display(c, v)}
+ {display(c, v)}
{:else}{display(c, v)}{/if}
{/if}
{/each}
{#if editable && t.canDelete}
- askDelete([row])}>✕
+ askDelete([row])}>✕
{/if}
{:else}
- no rows
+ no rows
{/each}
- navigate({ page: String(pageNo - 1) }, true)}>← prev
+ navigate({ page: String(pageNo - 1) }, true)}>← prev
page {pageNo}{pages ? ` of ${pages.toLocaleString('en-GB')}` : ''}
- = pages : rows.length < limit} onclick={() => navigate({ page: String(pageNo + 1) }, true)}>next →
+ = pages : rows.length < limit}
+ onclick={() => navigate({ page: String(pageNo + 1) }, true)}>next →
rows per page
- navigate({ limit: e.currentTarget.value })}>
+ navigate({ limit: e.currentTarget.value })}
+ >
{#each [25, 50, 100, 250, 500] as n (n)}{n} {/each}
- ↑↓←→ move · Enter edit · Space select · / search · n new row
+ ↑↓←→ move · Enter edit · Space select · / search · n new row
@@ -499,12 +669,19 @@
Unlock editing {t.schema}.{t.name}?
- This is an app table, not a list. Edits change what the {t.schema} pages show and could break them. Every change is written to the edit log. Editing stays unlocked for this table until you lock it again or close the tab.
+ This is an app table, not a list. Edits change what the {t.schema} pages show and could break
+ them. Every change is written to the edit log. Editing stays unlocked for this table until you
+ lock it again or close the tab.
cancel
- { setUnlocked(true); unlockOpen = false; }}>unlock editing
+ {
+ setUnlocked(true);
+ unlockOpen = false;
+ }}>unlock editing
@@ -512,14 +689,21 @@
- Delete {deleteTargets.length} row{deleteTargets.length === 1 ? '' : 's'}?
+ Delete {deleteTargets.length} row{deleteTargets.length === 1
+ ? ''
+ : 's'}?
- From {t.schema}.{t.name}. This can't be undone here (the old values are kept in the edit log).
+ From {t.schema}.{t.name}. This can't be undone here (the old values are kept in the edit
+ log).
cancel
- delete
+ delete
@@ -529,11 +713,17 @@
Import {importFile?.name}?
- Appends every row to {t.schema}.{t.name}. The first line must hold column names; empty cells use the column default. If any row fails, nothing is imported.
+ Appends every row to {t.schema}.{t.name}. The first line must hold column names; empty cells
+ use the column default. If any row fails, nothing is imported.
- { importFile = null; if (fileInput) fileInput.value = ''; }}>cancel
+ {
+ importFile = null;
+ if (fileInput) fileInput.value = '';
+ }}>cancel
import
@@ -548,9 +738,18 @@
{c.name}
- {shortType(c.type)}{!c.nullable && !c.hasDefault ? ' · required' : ''}{c.fk ? ` → ${c.fk.table}` : ''}
+ {shortType(c.type)}{!c.nullable && !c.hasDefault ? ' · required' : ''}{c.fk
+ ? ` → ${c.fk.table}`
+ : ''}
-
+
{/each}
add row
@@ -563,20 +762,42 @@
new column
{#if colError}{colError}
{/if}