@lavalogic/scoria 0.38.1 → 0.38.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Components/Table/Misc/TableConfigurationModal.svelte +41 -10
- package/dist/Components/Table/Misc/TableViewDropdown.svelte +0 -0
- package/dist/Components/Table/Types/Context/TableContext.svelte.d.ts +16 -6
- package/dist/Components/Table/Types/Context/TableContext.svelte.js +32 -20
- package/package.json +1 -1
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import { Size } from '../../../Types/Internal/Size.js';
|
|
15
15
|
import type { TabOption } from '../../../Types/Internal/TabOption.js';
|
|
16
16
|
import { Variant } from '../../../Types/Internal/Variant.js';
|
|
17
|
-
import { getContext } from 'svelte';
|
|
17
|
+
import { getContext, onMount } from 'svelte';
|
|
18
18
|
import { TableContext } from '../Types/Context/TableContext.svelte.js';
|
|
19
19
|
import type { Primitive } from '../Types/Context/TableInitOptions.js';
|
|
20
20
|
import type { DatatableView } from '../Types/Persistence/DatatableView.js';
|
|
@@ -48,6 +48,10 @@
|
|
|
48
48
|
// errors inline in its own body.
|
|
49
49
|
let errorMessage = $state<string | null>(null);
|
|
50
50
|
|
|
51
|
+
// True while the open-time fetch of saved views is in flight, so the
|
|
52
|
+
// My-tab shows "Loading…" rather than the "nothing saved yet" message.
|
|
53
|
+
let loadingViews = $state(false);
|
|
54
|
+
|
|
51
55
|
// Whether remote saved views are available at all. A table created
|
|
52
56
|
// without `datatableUuid` / `remoteLayouts` opts out of remote views;
|
|
53
57
|
// the modal then renders a graceful "unavailable" empty state and
|
|
@@ -93,6 +97,24 @@
|
|
|
93
97
|
}
|
|
94
98
|
}
|
|
95
99
|
|
|
100
|
+
// Fetch the saved views fresh every time the modal opens. The boot-time
|
|
101
|
+
// fetch can miss (it races table construction / auth readiness), so the
|
|
102
|
+
// modal cannot rely on `_viewState.savedViews` already being populated -
|
|
103
|
+
// it pulls `GET /datatable-state` itself on open. A failure surfaces in
|
|
104
|
+
// the inline error banner via `guard` rather than being swallowed.
|
|
105
|
+
onMount(() => {
|
|
106
|
+
if (!remoteAvailable) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
loadingViews = true;
|
|
110
|
+
void guard(
|
|
111
|
+
() => tableContext.refreshSavedViews(),
|
|
112
|
+
'Could not load saved layouts and filters. Please try again.'
|
|
113
|
+
).finally(() => {
|
|
114
|
+
loadingViews = false;
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
96
118
|
/** Apply a saved view to the live table. Pure local call - no await. */
|
|
97
119
|
function applyView(view: DatatableView): void {
|
|
98
120
|
errorMessage = null;
|
|
@@ -111,7 +133,14 @@
|
|
|
111
133
|
}, `Could not delete "${view.name}". Please try again.`);
|
|
112
134
|
}
|
|
113
135
|
|
|
114
|
-
/**
|
|
136
|
+
/**
|
|
137
|
+
* Save the live state of the active section as a brand-new view.
|
|
138
|
+
* `saveCurrentAsNewView` re-fetches the saved views and makes the new
|
|
139
|
+
* one active; the `My …` list and the panel dropdowns are all driven
|
|
140
|
+
* off the reactive `_viewState.savedViews(section)` so they update
|
|
141
|
+
* without a reopen. On success we also switch to the `My …` tab so
|
|
142
|
+
* the user immediately sees the view they just saved.
|
|
143
|
+
*/
|
|
115
144
|
function saveNewView(): void {
|
|
116
145
|
const trimmed = newViewName.trim();
|
|
117
146
|
if (!trimmed) {
|
|
@@ -120,6 +149,7 @@
|
|
|
120
149
|
void guard(async () => {
|
|
121
150
|
await tableContext.saveCurrentAsNewView(trimmed, section);
|
|
122
151
|
newViewName = '';
|
|
152
|
+
selectTab('mine');
|
|
123
153
|
}, `Could not save the new ${sectionNoun.toLowerCase()}. Please try again.`);
|
|
124
154
|
}
|
|
125
155
|
|
|
@@ -293,7 +323,9 @@
|
|
|
293
323
|
{/if}
|
|
294
324
|
|
|
295
325
|
{#if args.tab === 'mine'}
|
|
296
|
-
{#if
|
|
326
|
+
{#if loadingViews}
|
|
327
|
+
<p class="muted">Loading saved {sectionNounPlural.toLowerCase()}…</p>
|
|
328
|
+
{:else if myViews.length === 0}
|
|
297
329
|
<p class="muted">
|
|
298
330
|
You have not saved any {sectionNounPlural.toLowerCase()} yet. Use the "Save a new {sectionNoun}"
|
|
299
331
|
tab to create one.
|
|
@@ -450,10 +482,6 @@
|
|
|
450
482
|
}}
|
|
451
483
|
/>
|
|
452
484
|
<Button
|
|
453
|
-
type="submit"
|
|
454
|
-
variant={Variant.Primary}
|
|
455
|
-
size={Size.MediumSmall}
|
|
456
|
-
nowrap
|
|
457
485
|
disabled={!newViewName.trim()}
|
|
458
486
|
onclick={saveNewView}>Save Current</Button
|
|
459
487
|
>
|
|
@@ -537,14 +565,17 @@
|
|
|
537
565
|
color: #aa1414;
|
|
538
566
|
}
|
|
539
567
|
|
|
540
|
-
/* The body of a single top tab.
|
|
541
|
-
frame
|
|
568
|
+
/* The body of a single top tab. A `min-height` floor keeps the modal
|
|
569
|
+
frame visually stable across every section/tab combination (short
|
|
570
|
+
tabs no longer shrink the dialog); the `max-height` + `overflow-y`
|
|
571
|
+
keep taller content scrolling within that fixed frame rather than
|
|
572
|
+
growing the dialog. */
|
|
542
573
|
.tab-body {
|
|
543
574
|
display: flex;
|
|
544
575
|
flex-flow: column nowrap;
|
|
545
576
|
gap: 0.75rem;
|
|
546
577
|
padding: 1rem;
|
|
547
|
-
min-height:
|
|
578
|
+
min-height: 30vh;
|
|
548
579
|
max-height: 60vh;
|
|
549
580
|
overflow-y: auto;
|
|
550
581
|
}
|
|
Binary file
|
|
@@ -892,10 +892,18 @@ export declare class TableContext<T extends object, RowIdType extends Primitive>
|
|
|
892
892
|
* `{ kind:'filter', filter: _captureFilter() }`, plus the
|
|
893
893
|
* host-supplied `datatableUuid` and the owning user;
|
|
894
894
|
* 2. `await remoteLayouts.createView(...)`;
|
|
895
|
-
* 3.
|
|
896
|
-
*
|
|
897
|
-
*
|
|
898
|
-
*
|
|
895
|
+
* 3. `await refreshSavedViews()` so the matching kind's saved-views
|
|
896
|
+
* list is re-fetched from the backend - the new view then appears
|
|
897
|
+
* in the Table Configuration modal's My-Layouts / My-Filters list
|
|
898
|
+
* (and the panel quick-switch dropdowns) immediately, without a
|
|
899
|
+
* reopen, because both read reactively off `_viewState`;
|
|
900
|
+
* 4. set the newly-saved view as that kind's active view via
|
|
901
|
+
* `applyDatatableView`, which re-points that kind's baseline and
|
|
902
|
+
* clears that kind's dirty flag - so the quick-switch dropdown
|
|
903
|
+
* shows the new view's name straight away rather than
|
|
904
|
+
* `'Custom (unsaved)'`. The authoritative refreshed copy (matched
|
|
905
|
+
* by id) is preferred over the raw `createView` return so the
|
|
906
|
+
* baseline reflects exactly what the backend persisted.
|
|
899
907
|
*
|
|
900
908
|
* Only the named kind's state is touched. No-op (dev-logged via
|
|
901
909
|
* `devCatch`) when remote saved views are disabled (`datatableUuid` /
|
|
@@ -932,8 +940,10 @@ export declare class TableContext<T extends object, RowIdType extends Primitive>
|
|
|
932
940
|
* against the now-known body of any persisted saved-view ref.
|
|
933
941
|
*
|
|
934
942
|
* No-op when remote saved views are disabled (`datatableUuid` /
|
|
935
|
-
* `remoteLayouts` absent). An adapter rejection is
|
|
936
|
-
*
|
|
943
|
+
* `remoteLayouts` absent). An adapter rejection is propagated to the
|
|
944
|
+
* caller: the boot-time call site catches it with `devCatch`, while
|
|
945
|
+
* the Table Configuration modal routes it to its inline error banner
|
|
946
|
+
* so a failed fetch is visible rather than silently swallowed.
|
|
937
947
|
*/
|
|
938
948
|
readonly refreshSavedViews: () => Promise<void>;
|
|
939
949
|
/**
|
|
@@ -2309,10 +2309,18 @@ export class TableContext {
|
|
|
2309
2309
|
* `{ kind:'filter', filter: _captureFilter() }`, plus the
|
|
2310
2310
|
* host-supplied `datatableUuid` and the owning user;
|
|
2311
2311
|
* 2. `await remoteLayouts.createView(...)`;
|
|
2312
|
-
* 3.
|
|
2313
|
-
*
|
|
2314
|
-
*
|
|
2315
|
-
*
|
|
2312
|
+
* 3. `await refreshSavedViews()` so the matching kind's saved-views
|
|
2313
|
+
* list is re-fetched from the backend - the new view then appears
|
|
2314
|
+
* in the Table Configuration modal's My-Layouts / My-Filters list
|
|
2315
|
+
* (and the panel quick-switch dropdowns) immediately, without a
|
|
2316
|
+
* reopen, because both read reactively off `_viewState`;
|
|
2317
|
+
* 4. set the newly-saved view as that kind's active view via
|
|
2318
|
+
* `applyDatatableView`, which re-points that kind's baseline and
|
|
2319
|
+
* clears that kind's dirty flag - so the quick-switch dropdown
|
|
2320
|
+
* shows the new view's name straight away rather than
|
|
2321
|
+
* `'Custom (unsaved)'`. The authoritative refreshed copy (matched
|
|
2322
|
+
* by id) is preferred over the raw `createView` return so the
|
|
2323
|
+
* baseline reflects exactly what the backend persisted.
|
|
2316
2324
|
*
|
|
2317
2325
|
* Only the named kind's state is touched. No-op (dev-logged via
|
|
2318
2326
|
* `devCatch`) when remote saved views are disabled (`datatableUuid` /
|
|
@@ -2342,8 +2350,15 @@ export class TableContext {
|
|
|
2342
2350
|
ownerUserId,
|
|
2343
2351
|
};
|
|
2344
2352
|
const created = await adapter.createView(request);
|
|
2345
|
-
|
|
2346
|
-
|
|
2353
|
+
// Re-fetch the authoritative saved-views lists so the new view
|
|
2354
|
+
// shows up in the modal and the panel dropdowns immediately.
|
|
2355
|
+
await this.refreshSavedViews();
|
|
2356
|
+
// Prefer the refreshed copy (matched by id); fall back to the
|
|
2357
|
+
// raw create return if the refresh did not surface it.
|
|
2358
|
+
const authoritative = this._viewState.savedViews(kind).find((view) => view.id === created.id) ?? created;
|
|
2359
|
+
// Make the just-saved view active so the quick-switch dropdown
|
|
2360
|
+
// shows its name (not "Custom (unsaved)") and dirty is cleared.
|
|
2361
|
+
this.applyDatatableView(authoritative);
|
|
2347
2362
|
}
|
|
2348
2363
|
catch (e) {
|
|
2349
2364
|
devCatch(e);
|
|
@@ -2424,8 +2439,10 @@ export class TableContext {
|
|
|
2424
2439
|
* against the now-known body of any persisted saved-view ref.
|
|
2425
2440
|
*
|
|
2426
2441
|
* No-op when remote saved views are disabled (`datatableUuid` /
|
|
2427
|
-
* `remoteLayouts` absent). An adapter rejection is
|
|
2428
|
-
*
|
|
2442
|
+
* `remoteLayouts` absent). An adapter rejection is propagated to the
|
|
2443
|
+
* caller: the boot-time call site catches it with `devCatch`, while
|
|
2444
|
+
* the Table Configuration modal routes it to its inline error banner
|
|
2445
|
+
* so a failed fetch is visible rather than silently swallowed.
|
|
2429
2446
|
*/
|
|
2430
2447
|
refreshSavedViews = async () => {
|
|
2431
2448
|
const adapter = this.remoteLayouts;
|
|
@@ -2433,18 +2450,13 @@ export class TableContext {
|
|
|
2433
2450
|
if (!adapter || !datatableUuid) {
|
|
2434
2451
|
return;
|
|
2435
2452
|
}
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
this._reconcileBaselineForActiveFilterView();
|
|
2444
|
-
}
|
|
2445
|
-
catch (e) {
|
|
2446
|
-
devCatch(e);
|
|
2447
|
-
}
|
|
2453
|
+
const views = await adapter.listViews(datatableUuid);
|
|
2454
|
+
this._viewState.setSavedViews('layout', views.filter((view) => view.kind === 'layout'));
|
|
2455
|
+
this._viewState.setSavedViews('filter', views.filter((view) => view.kind === 'filter'));
|
|
2456
|
+
// A persisted saved-view ref restored at boot may have had an
|
|
2457
|
+
// unknown body until now; reconcile both baselines against it.
|
|
2458
|
+
this._reconcileBaselineForActiveView();
|
|
2459
|
+
this._reconcileBaselineForActiveFilterView();
|
|
2448
2460
|
};
|
|
2449
2461
|
/**
|
|
2450
2462
|
* Drop the persisted live-layout snapshot for this table. The next
|