@yuneta/gobj-ui 7.25.7 → 7.25.8
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/README.md +32 -1
- package/dist/gobj-ui.cjs.js +204 -75
- package/dist/gobj-ui.es.js +204 -75
- package/package.json +1 -1
- package/src/c_yui_schema_editor.js +186 -50
- package/src/schema_editor_reload.wiring.test.js +473 -0
- package/src/shell_modals.js +50 -29
- package/src/shell_toast_once.test.js +64 -3
package/README.md
CHANGED
|
@@ -2177,9 +2177,24 @@ else.
|
|
|
2177
2177
|
gobj_send_event(editor, "EV_SHOW", {subpath: "db"}, host); // waits
|
|
2178
2178
|
// ... the three `nodes` answers land -> ST_TOPICS of `db`
|
|
2179
2179
|
```
|
|
2180
|
+
- **The loading screen is drawn** (7.25.8): the body is cleared, the drawing
|
|
2181
|
+
destroyed and every toolbar button disabled, as in `ST_SAVING`, because
|
|
2182
|
+
`ST_LOADING` declares none of a screen's actions. A **dialog** left open is
|
|
2183
|
+
the one thing still reachable: its Save (`EV_SAVE_COLUMN`, `EV_SAVE_TOPIC`),
|
|
2184
|
+
a confirmation (`EV_CONFIRMED`), an orphan delete or an import is refused
|
|
2185
|
+
with `the schemas are loading: try again when they are in` (an i18n key the
|
|
2186
|
+
consumer's locales carry) and the dialog stays open with what was typed, so
|
|
2187
|
+
the same Save works once the load is in. A write that ends with an error --
|
|
2188
|
+
a drop included -- still applies a position that waited, as a load does.
|
|
2189
|
+
Out of session a load is not asked at all (no *"not in session"* errors);
|
|
2190
|
+
the reconnect loads.
|
|
2180
2191
|
- A write this view gave up on (a drop, a deadline) whose answer still says it
|
|
2181
2192
|
was DONE makes the editor read the model again (at once, after the write in
|
|
2182
|
-
flight, or on the reconnect)
|
|
2193
|
+
flight, or on the reconnect), and it is a write for the host too: it
|
|
2194
|
+
publishes `EV_RECORD_WRITTEN` and marks the topic of the record answered.
|
|
2195
|
+
Only the host's `EV_REFRESH` (a Save sends it) forgets what this session
|
|
2196
|
+
wrote; the reloads the editor asks itself (the reconnect's, a late write's)
|
|
2197
|
+
keep the draft chips. Through a routing adapter that settled the
|
|
2183
2198
|
write on its OWN deadline the late answer does not reach the view -- the
|
|
2184
2199
|
adapter echoes a node event instead, which this view does not hear -- and
|
|
2185
2200
|
Refresh is what reads the store.
|
|
@@ -2614,6 +2629,22 @@ live region it is both read and announced when it changes.
|
|
|
2614
2629
|
> long time and nothing ever rendered it; the claim is gone. Implement it there
|
|
2615
2630
|
> the day a menu entry needs one.
|
|
2616
2631
|
|
|
2632
|
+
### Toasts — `yui_shell_show_info` / `_warning` / `_error`
|
|
2633
|
+
|
|
2634
|
+
`yui_shell_show_error(shell, "key", {t, timeout})` shows a non-blocking toast
|
|
2635
|
+
(5000 ms by default, `timeout: 0` = until closed) and returns `{close()}`. A
|
|
2636
|
+
string message of the same kind as a toast still on screen is not stacked
|
|
2637
|
+
under it -- there is ONE toast per message -- but each call is a caller of its
|
|
2638
|
+
own: it gets its own handle and its own time, and the toast goes when every
|
|
2639
|
+
caller has closed its handle or timed out (7.25.8). The ✕ closes it for all.
|
|
2640
|
+
|
|
2641
|
+
```js
|
|
2642
|
+
const a = yui_shell_show_error(shell, "the connection dropped", {t}); // 5 s
|
|
2643
|
+
const b = yui_shell_show_error(shell, "the connection dropped", {t, timeout: 0}); // same toast
|
|
2644
|
+
a.close(); // still shown: b holds it
|
|
2645
|
+
b.close(); // gone
|
|
2646
|
+
```
|
|
2647
|
+
|
|
2617
2648
|
### Modals — `yui_shell_show_modal` and the `before_close` veto
|
|
2618
2649
|
|
|
2619
2650
|
`yui_shell_show_modal(shell, $box, opts)` is the standard popup: pass
|
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -3027,12 +3027,20 @@ function maybe_apply_translator($node, opts) {
|
|
|
3027
3027
|
* Returns `{ close() }` so callers can dismiss programmatically.
|
|
3028
3028
|
*
|
|
3029
3029
|
* ONE toast per message on screen: a string message of the same
|
|
3030
|
-
* kind as a toast still showing is not stacked under it
|
|
3031
|
-
*
|
|
3032
|
-
*
|
|
3033
|
-
*
|
|
3034
|
-
*
|
|
3035
|
-
*
|
|
3030
|
+
* kind as a toast still showing is not stacked under it. One
|
|
3031
|
+
* close of a transport settles every request it cut, each view
|
|
3032
|
+
* shows its failure, and the operator got a column of identical
|
|
3033
|
+
* "the connection dropped". A message built of nodes is never
|
|
3034
|
+
* merged: its text is not a key.
|
|
3035
|
+
*
|
|
3036
|
+
* A repeat is still a CALLER of its own: it gets its own handle
|
|
3037
|
+
* and its own time, and the toast stays while any caller holds
|
|
3038
|
+
* it -- until every handle is closed or has timed out. Handed the
|
|
3039
|
+
* first caller's handle and timer, a repeat asking `timeout: 0`
|
|
3040
|
+
* was dismissed on the first one's timer, and closing one
|
|
3041
|
+
* caller's handle closed a toast another was still showing
|
|
3042
|
+
* (third independent review). The operator's ✕ closes it for
|
|
3043
|
+
* everybody.
|
|
3036
3044
|
***************************************************************/
|
|
3037
3045
|
function show_notification(shell, kind, message, opts) {
|
|
3038
3046
|
let $layer = notification_layer(shell);
|
|
@@ -3040,12 +3048,10 @@ function show_notification(shell, kind, message, opts) {
|
|
|
3040
3048
|
(0, _yuneta_gobj_js.log_warning)("yui_shell_show_*: shell has no notification layer");
|
|
3041
3049
|
return { close: () => {} };
|
|
3042
3050
|
}
|
|
3051
|
+
let timeout = opts && opts.timeout != null ? opts.timeout : 5e3;
|
|
3043
3052
|
let key = typeof message === "string" ? `${kind}\u0000${message}` : null;
|
|
3044
3053
|
if (key !== null) {
|
|
3045
|
-
for (let $shown of Array.from($layer.children)) if ($shown.__toast_key__ === key && $shown.__toast__)
|
|
3046
|
-
$shown.__toast__.restart();
|
|
3047
|
-
return $shown.__toast__.handle;
|
|
3048
|
-
}
|
|
3054
|
+
for (let $shown of Array.from($layer.children)) if ($shown.__toast_key__ === key && $shown.__toast__) return $shown.__toast__.hold(timeout);
|
|
3049
3055
|
}
|
|
3050
3056
|
let p_attrs = typeof message === "string" ? { i18n: message } : {};
|
|
3051
3057
|
let $note = (0, _yuneta_gobj_js.createElement2)([
|
|
@@ -3069,35 +3075,38 @@ function show_notification(shell, kind, message, opts) {
|
|
|
3069
3075
|
]);
|
|
3070
3076
|
$layer.appendChild($note);
|
|
3071
3077
|
maybe_apply_translator($note, opts);
|
|
3072
|
-
let
|
|
3078
|
+
let holders = /* @__PURE__ */ new Set();
|
|
3073
3079
|
let closed = false;
|
|
3074
|
-
let
|
|
3080
|
+
let close_toast = function() {
|
|
3075
3081
|
if (closed) return;
|
|
3076
3082
|
closed = true;
|
|
3077
|
-
if (timeout_id) {
|
|
3078
|
-
clearTimeout(timeout_id);
|
|
3079
|
-
timeout_id = null;
|
|
3083
|
+
for (let holder of holders) if (holder.timeout_id) {
|
|
3084
|
+
clearTimeout(holder.timeout_id);
|
|
3085
|
+
holder.timeout_id = null;
|
|
3080
3086
|
}
|
|
3087
|
+
holders.clear();
|
|
3081
3088
|
if ($note.parentNode) $note.parentNode.removeChild($note);
|
|
3082
3089
|
};
|
|
3083
|
-
let
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3090
|
+
let hold = function(ms) {
|
|
3091
|
+
let holder = { timeout_id: null };
|
|
3092
|
+
let release = function() {
|
|
3093
|
+
if (!holders.has(holder)) return;
|
|
3094
|
+
if (holder.timeout_id) {
|
|
3095
|
+
clearTimeout(holder.timeout_id);
|
|
3096
|
+
holder.timeout_id = null;
|
|
3097
|
+
}
|
|
3098
|
+
holders.delete(holder);
|
|
3099
|
+
if (holders.size === 0) close_toast();
|
|
3100
|
+
};
|
|
3101
|
+
holders.add(holder);
|
|
3102
|
+
if (ms > 0) holder.timeout_id = setTimeout(release, ms);
|
|
3103
|
+
return { close: release };
|
|
3092
3104
|
};
|
|
3093
|
-
|
|
3094
|
-
|
|
3105
|
+
let $del = $note.querySelector(".delete");
|
|
3106
|
+
if ($del) $del.addEventListener("click", close_toast);
|
|
3095
3107
|
$note.__toast_key__ = key;
|
|
3096
|
-
$note.__toast__ = {
|
|
3097
|
-
|
|
3098
|
-
restart
|
|
3099
|
-
};
|
|
3100
|
-
return handle;
|
|
3108
|
+
$note.__toast__ = { hold };
|
|
3109
|
+
return hold(timeout);
|
|
3101
3110
|
}
|
|
3102
3111
|
function yui_shell_show_info(shell, message, opts) {
|
|
3103
3112
|
return show_notification(shell, "info", message, opts);
|
|
@@ -72168,6 +72177,7 @@ var PRIVATE_DATA$1 = {
|
|
|
72168
72177
|
pending: 0,
|
|
72169
72178
|
load_error: "",
|
|
72170
72179
|
load_round: 0,
|
|
72180
|
+
load_keeps_written: false,
|
|
72171
72181
|
treedb_id: "",
|
|
72172
72182
|
topic_name: "",
|
|
72173
72183
|
diagram: false,
|
|
@@ -72346,10 +72356,28 @@ function refuse_if_readonly(gobj, event) {
|
|
|
72346
72356
|
* schema set of the yuno is here: everything below — the
|
|
72347
72357
|
* drawing, the validation, the export — is computed from these
|
|
72348
72358
|
* and asks the backend nothing more.
|
|
72359
|
+
*
|
|
72360
|
+
* THE LOADING SCREEN IS DRAWN, not assumed. ST_LOADING declares
|
|
72361
|
+
* none of the actions of a screen, so the screen it replaces goes
|
|
72362
|
+
* and the toolbar stops answering: left up, a click on a card, on
|
|
72363
|
+
* Back or on the drawing answered "Event NOT DEFINED in state
|
|
72364
|
+
* ST_LOADING" and was lost (third independent review). A dialog
|
|
72365
|
+
* left open is answered in ST_LOADING instead (ac_wait_for_the_load).
|
|
72366
|
+
*
|
|
72367
|
+
* `keep_written`: a load the host did not ask for -- the reconnect,
|
|
72368
|
+
* a write that turned out done -- keeps what this session wrote.
|
|
72369
|
+
* Only the host's EV_REFRESH (a Save sends it) forgets it.
|
|
72370
|
+
*
|
|
72371
|
+
* A load that cannot leave WHOLE did not happen (out of session it
|
|
72372
|
+
* is not even asked): the records the model was built on are put
|
|
72373
|
+
* back (emptied, the next write patched them into a model with no
|
|
72374
|
+
* treedb), the round is spent so a request that did leave is
|
|
72375
|
+
* stale, and the session back asks again.
|
|
72349
72376
|
***************************************************************/
|
|
72350
|
-
function request_model(gobj) {
|
|
72377
|
+
function request_model(gobj, keep_written) {
|
|
72351
72378
|
let priv = gobj.priv;
|
|
72352
72379
|
if (!(0, _yuneta_gobj_js.gobj_read_pointer_attr)(gobj, "gobj_remote_yuno")) return -1;
|
|
72380
|
+
let previous = priv.records;
|
|
72353
72381
|
priv.records = {
|
|
72354
72382
|
treedbs: [],
|
|
72355
72383
|
topics: [],
|
|
@@ -72358,22 +72386,31 @@ function request_model(gobj) {
|
|
|
72358
72386
|
priv.load_error = "";
|
|
72359
72387
|
priv.pending = 0;
|
|
72360
72388
|
priv.load_round++;
|
|
72389
|
+
priv.load_keeps_written = !!keep_written;
|
|
72361
72390
|
(0, _yuneta_gobj_js.gobj_change_state)(gobj, "ST_LOADING");
|
|
72362
|
-
|
|
72363
|
-
|
|
72364
|
-
|
|
72365
|
-
|
|
72366
|
-
|
|
72367
|
-
|
|
72368
|
-
|
|
72369
|
-
|
|
72370
|
-
|
|
72371
|
-
|
|
72391
|
+
set_busy(gobj, false);
|
|
72392
|
+
render(gobj);
|
|
72393
|
+
let left = 0;
|
|
72394
|
+
if (transport_in_session(gobj)) {
|
|
72395
|
+
for (let topic_name of [
|
|
72396
|
+
T_TREEDBS,
|
|
72397
|
+
T_TOPICS,
|
|
72398
|
+
T_COLS
|
|
72399
|
+
]) if (remote_command(gobj, "nodes", {
|
|
72400
|
+
topic_name,
|
|
72401
|
+
options: { list_dict: true }
|
|
72402
|
+
}, { round: priv.load_round }) === 0) left++;
|
|
72403
|
+
}
|
|
72404
|
+
if (left < 3) {
|
|
72405
|
+
priv.records = previous;
|
|
72406
|
+
priv.load_round++;
|
|
72407
|
+
priv.reload_on_open = true;
|
|
72372
72408
|
priv.load_error = (0, i18next.t)("cannot reach the treedb");
|
|
72373
|
-
(
|
|
72374
|
-
|
|
72409
|
+
if (priv.model) yui_shell_show_error(yui_shell_of(gobj), "cannot reach the treedb", { t: i18next.t });
|
|
72410
|
+
end_load(gobj);
|
|
72375
72411
|
return -1;
|
|
72376
72412
|
}
|
|
72413
|
+
priv.pending = left;
|
|
72377
72414
|
return 0;
|
|
72378
72415
|
}
|
|
72379
72416
|
/***************************************************************
|
|
@@ -72436,15 +72473,19 @@ function build_model(gobj) {
|
|
|
72436
72473
|
* From here on, "did this session change it?" has an answer.
|
|
72437
72474
|
*
|
|
72438
72475
|
* Called ONLY when records arrive from the store: that is what a
|
|
72439
|
-
* measurement of "changed since" can be measured against.
|
|
72440
|
-
*
|
|
72441
|
-
*
|
|
72442
|
-
*
|
|
72476
|
+
* measurement of "changed since" can be measured against.
|
|
72477
|
+
*
|
|
72478
|
+
* `written` is forgotten only by a load the HOST asked for (its
|
|
72479
|
+
* EV_REFRESH, which a Save sends). Since M36 a write moves no
|
|
72480
|
+
* version, so `written` is the draft chip of what this session
|
|
72481
|
+
* wrote and no longer half of a version measurement: a reload of
|
|
72482
|
+
* the reconnect, or of a write that turned out done, forgot the
|
|
72483
|
+
* chips of writes the host had not been told about.
|
|
72443
72484
|
***************************************************************/
|
|
72444
72485
|
function start_measuring(gobj) {
|
|
72445
72486
|
let priv = gobj.priv;
|
|
72446
72487
|
priv.baseline = {};
|
|
72447
|
-
priv.written = {};
|
|
72488
|
+
if (!priv.load_keeps_written) priv.written = {};
|
|
72448
72489
|
priv.host_ids = {};
|
|
72449
72490
|
if (!priv.model) return;
|
|
72450
72491
|
for (let treedb of priv.model.treedbs) for (let topic of treedb.topics) priv.baseline[topic.id] = topic.topic_version;
|
|
@@ -72626,8 +72667,10 @@ function render_toolbar(gobj) {
|
|
|
72626
72667
|
let state = (0, _yuneta_gobj_js.gobj_current_state)(gobj);
|
|
72627
72668
|
let readonly = is_readonly(gobj);
|
|
72628
72669
|
let has_model = !!priv.model;
|
|
72670
|
+
let on_a_treedb = state !== "ST_IDLE" && state !== "ST_EMPTY";
|
|
72671
|
+
let in_flight = state === "ST_SAVING" || state === "ST_LOADING";
|
|
72629
72672
|
let $left = [];
|
|
72630
|
-
if (priv.treedb_id) $left.push([
|
|
72673
|
+
if (priv.treedb_id && on_a_treedb) $left.push([
|
|
72631
72674
|
"button",
|
|
72632
72675
|
{
|
|
72633
72676
|
class: "SCHEMA_BACK button",
|
|
@@ -72700,17 +72743,17 @@ function render_toolbar(gobj) {
|
|
|
72700
72743
|
$trail
|
|
72701
72744
|
]);
|
|
72702
72745
|
let $right = [];
|
|
72703
|
-
if (priv.treedb_id && has_model) {
|
|
72746
|
+
if (priv.treedb_id && has_model && on_a_treedb) {
|
|
72704
72747
|
$right.push(toolbar_button("SCHEMA_DIAGRAM_BTN", "yi-compass-drafting", priv.diagram ? "topics" : "diagram", "EV_TOGGLE_DIAGRAM", false));
|
|
72705
72748
|
$right.push(toolbar_button("SCHEMA_VALIDATE_BTN", "yi-square-check", "check", "EV_VALIDATE", false));
|
|
72706
72749
|
$right.push(toolbar_button("SCHEMA_EXPORT_BTN", "yi-download", "export", "EV_EXPORT", false));
|
|
72707
72750
|
if (!readonly) $right.push(toolbar_button("SCHEMA_IMPORT_BTN", "yi-upload", "import", "EV_IMPORT", false));
|
|
72708
72751
|
}
|
|
72709
|
-
if (priv.topic_name && !readonly && !priv.diagram) {
|
|
72752
|
+
if (priv.topic_name && !readonly && !priv.diagram && on_a_treedb) {
|
|
72710
72753
|
if (undo_order_writes(gobj, current_topic(gobj)).length > 0) $right.push(toolbar_button("SCHEMA_UNDO_ORDER_BTN", "yi-arrow-rotate-left", "undo the order", "EV_UNDO_ORDER", false));
|
|
72711
72754
|
$right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus", "new column", "EV_ADD_COLUMN", false));
|
|
72712
72755
|
}
|
|
72713
|
-
if (priv.treedb_id && !priv.topic_name && !readonly && !priv.diagram) $right.push(toolbar_button("SCHEMA_ADD_TOPIC_BTN", "yi-plus", "new topic", "EV_ADD_TOPIC", false));
|
|
72756
|
+
if (priv.treedb_id && !priv.topic_name && !readonly && !priv.diagram && on_a_treedb) $right.push(toolbar_button("SCHEMA_ADD_TOPIC_BTN", "yi-plus", "new topic", "EV_ADD_TOPIC", false));
|
|
72714
72757
|
$right.push(toolbar_button("SCHEMA_REFRESH_BTN", "yi-arrows-rotate", "refresh", "EV_REFRESH", state === "ST_LOADING"));
|
|
72715
72758
|
let $bar = (0, _yuneta_gobj_js.createElement2)([
|
|
72716
72759
|
"div",
|
|
@@ -72736,7 +72779,7 @@ function render_toolbar(gobj) {
|
|
|
72736
72779
|
]);
|
|
72737
72780
|
for (let $button of $bar.querySelectorAll("button")) {
|
|
72738
72781
|
$button.__gobj__ = gobj;
|
|
72739
|
-
if (
|
|
72782
|
+
if (in_flight) $button.disabled = true;
|
|
72740
72783
|
}
|
|
72741
72784
|
$toolbar.appendChild($bar);
|
|
72742
72785
|
(0, _yuneta_gobj_js.refresh_language)($toolbar, i18next.t);
|
|
@@ -72754,16 +72797,19 @@ function render(gobj) {
|
|
|
72754
72797
|
render_toolbar(gobj);
|
|
72755
72798
|
if (state === "ST_LOADING") {
|
|
72756
72799
|
show_notice(gobj, "loading the schemas");
|
|
72800
|
+
destroy_diagram(gobj);
|
|
72757
72801
|
clear($body);
|
|
72758
72802
|
return;
|
|
72759
72803
|
}
|
|
72760
72804
|
if (state === "ST_IDLE") {
|
|
72761
72805
|
show_notice(gobj, priv.load_error ? "cannot load the schemas" : "not connected", priv.load_error);
|
|
72806
|
+
destroy_diagram(gobj);
|
|
72762
72807
|
clear($body);
|
|
72763
72808
|
return;
|
|
72764
72809
|
}
|
|
72765
72810
|
if (state === "ST_EMPTY") {
|
|
72766
72811
|
show_notice(gobj, "this yuno stores no schema");
|
|
72812
|
+
destroy_diagram(gobj);
|
|
72767
72813
|
clear($body);
|
|
72768
72814
|
return;
|
|
72769
72815
|
}
|
|
@@ -73452,12 +73498,16 @@ function render_diagram(gobj) {
|
|
|
73452
73498
|
let priv = gobj.priv;
|
|
73453
73499
|
let $body = $of(gobj, ".SCHEMA_BODY");
|
|
73454
73500
|
let treedb = current_treedb(gobj);
|
|
73455
|
-
if (!$body
|
|
73501
|
+
if (!$body) return;
|
|
73502
|
+
if (!treedb) {
|
|
73503
|
+
destroy_diagram(gobj);
|
|
73504
|
+
clear($body);
|
|
73456
73505
|
show_notice(gobj, "that treedb is not here any more", priv.treedb_id);
|
|
73457
73506
|
return;
|
|
73458
73507
|
}
|
|
73459
73508
|
if (!(0, _yuneta_gobj_js.gclass_find_by_name)("C_YUI_TREEDB_SCHEMA")) {
|
|
73460
73509
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: C_YUI_TREEDB_SCHEMA not registered by the app`);
|
|
73510
|
+
clear($body);
|
|
73461
73511
|
show_notice(gobj, "the schema drawing is not available");
|
|
73462
73512
|
return;
|
|
73463
73513
|
}
|
|
@@ -74727,26 +74777,21 @@ function end_load(gobj) {
|
|
|
74727
74777
|
***************************************************************/
|
|
74728
74778
|
function end_writes(gobj, error) {
|
|
74729
74779
|
let priv = gobj.priv;
|
|
74780
|
+
let seg = priv.pending_seg;
|
|
74730
74781
|
priv.save_queue = [];
|
|
74782
|
+
priv.pending_seg = null;
|
|
74731
74783
|
(0, _yuneta_gobj_js.gobj_change_state)(gobj, priv.save_return || "ST_TREEDBS");
|
|
74732
74784
|
priv.save_return = "";
|
|
74733
74785
|
show_notice(gobj, "");
|
|
74734
74786
|
set_busy(gobj, false);
|
|
74735
|
-
if (priv.pending_seg !== null) {
|
|
74736
|
-
let seg = priv.pending_seg;
|
|
74737
|
-
priv.pending_seg = null;
|
|
74738
|
-
if (!error) {
|
|
74739
|
-
apply_seg(gobj, seg);
|
|
74740
|
-
if (priv.save_wrote) (0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_RECORD_WRITTEN", { treedb_name: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name") });
|
|
74741
|
-
priv.save_wrote = false;
|
|
74742
|
-
return reload_if_owed(gobj);
|
|
74743
|
-
}
|
|
74744
|
-
}
|
|
74745
74787
|
if (error) yui_shell_show_error(yui_shell_of(gobj), error, { t: i18next.t });
|
|
74746
74788
|
if (priv.save_wrote) (0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_RECORD_WRITTEN", { treedb_name: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name") });
|
|
74747
74789
|
priv.save_wrote = false;
|
|
74748
|
-
|
|
74749
|
-
|
|
74790
|
+
if (seg !== null) apply_seg(gobj, seg);
|
|
74791
|
+
else {
|
|
74792
|
+
render(gobj);
|
|
74793
|
+
publish_check(gobj);
|
|
74794
|
+
}
|
|
74750
74795
|
reload_if_owed(gobj);
|
|
74751
74796
|
return error ? -1 : 0;
|
|
74752
74797
|
}
|
|
@@ -74763,7 +74808,7 @@ function reload_if_owed(gobj) {
|
|
|
74763
74808
|
priv.reload_on_open = true;
|
|
74764
74809
|
return 0;
|
|
74765
74810
|
}
|
|
74766
|
-
return request_model(gobj);
|
|
74811
|
+
return request_model(gobj, true);
|
|
74767
74812
|
}
|
|
74768
74813
|
/***************************************************************
|
|
74769
74814
|
* The record a column form produces.
|
|
@@ -74829,6 +74874,7 @@ function topic_record(gobj, treedb, topic, values) {
|
|
|
74829
74874
|
***************************************************************/
|
|
74830
74875
|
function go(gobj, treedb_id, topic_name, diagram, mirror) {
|
|
74831
74876
|
let priv = gobj.priv;
|
|
74877
|
+
priv.pending_seg = null;
|
|
74832
74878
|
priv.treedb_id = treedb_id || "";
|
|
74833
74879
|
priv.topic_name = topic_name || "";
|
|
74834
74880
|
priv.diagram = !!diagram;
|
|
@@ -74945,7 +74991,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
74945
74991
|
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: '${command}' of '${topic_name}' answered for a write that is over (result ${result}): ignored`);
|
|
74946
74992
|
return 0;
|
|
74947
74993
|
}
|
|
74948
|
-
return late_write_done(gobj, command, topic_name);
|
|
74994
|
+
return late_write_done(gobj, command, topic_name, data);
|
|
74949
74995
|
}
|
|
74950
74996
|
if (result < 0) return end_writes(gobj, comment || (0, i18next.t)("the treedb refused the write"));
|
|
74951
74997
|
priv.save_wrote = true;
|
|
@@ -74955,8 +75001,15 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
74955
75001
|
if (record) patch_record(gobj, topic_name, record);
|
|
74956
75002
|
else {
|
|
74957
75003
|
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: '${command}' answered no record`);
|
|
75004
|
+
if (topic_name === T_TOPICS || topic_name === T_COLS) {
|
|
75005
|
+
let write = priv.save_queue[0];
|
|
75006
|
+
mark_written(gobj, topic_name, write ? write.record : null);
|
|
75007
|
+
}
|
|
74958
75008
|
priv.save_queue = [];
|
|
74959
|
-
|
|
75009
|
+
priv.save_return = "";
|
|
75010
|
+
priv.save_wrote = false;
|
|
75011
|
+
(0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_RECORD_WRITTEN", { treedb_name: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name") });
|
|
75012
|
+
request_model(gobj, true);
|
|
74960
75013
|
return 0;
|
|
74961
75014
|
}
|
|
74962
75015
|
}
|
|
@@ -74983,11 +75036,18 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
74983
75036
|
* the view was answered once, as failed -- and echoes the node
|
|
74984
75037
|
* event instead, which this view does not hear: there, Refresh is
|
|
74985
75038
|
* what reads the store.
|
|
75039
|
+
*
|
|
75040
|
+
* It is a WRITE like any other for the host (EV_RECORD_WRITTEN):
|
|
75041
|
+
* the host was told nothing when it was given up, and it owns the
|
|
75042
|
+
* Save that publishes it. The reload keeps what this session wrote
|
|
75043
|
+
* (request_model()), and the record it answered marks its topic.
|
|
74986
75044
|
***************************************************************/
|
|
74987
|
-
function late_write_done(gobj, command, topic_name) {
|
|
75045
|
+
function late_write_done(gobj, command, topic_name, data) {
|
|
74988
75046
|
let priv = gobj.priv;
|
|
74989
75047
|
let state = (0, _yuneta_gobj_js.gobj_current_state)(gobj);
|
|
74990
75048
|
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: '${command}' of '${topic_name}' was given up, and it was DONE: the model is read again`);
|
|
75049
|
+
mark_written_record(gobj, topic_name, (0, _yuneta_gobj_js.is_object)(data) ? data : Array.isArray(data) && (0, _yuneta_gobj_js.is_object)(data[0]) ? data[0] : null);
|
|
75050
|
+
(0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_RECORD_WRITTEN", { treedb_name: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name") });
|
|
74991
75051
|
if (state === "ST_LOADING") return 0;
|
|
74992
75052
|
if (state === "ST_SAVING") {
|
|
74993
75053
|
priv.reload_after_write = true;
|
|
@@ -74997,7 +75057,27 @@ function late_write_done(gobj, command, topic_name) {
|
|
|
74997
75057
|
priv.reload_on_open = true;
|
|
74998
75058
|
return 0;
|
|
74999
75059
|
}
|
|
75000
|
-
return request_model(gobj);
|
|
75060
|
+
return request_model(gobj, true);
|
|
75061
|
+
}
|
|
75062
|
+
/***************************************************************
|
|
75063
|
+
* The topic a record written belongs to, read off the RECORD and
|
|
75064
|
+
* not off the screen: a write answered late may be about a topic
|
|
75065
|
+
* the operator has left. A column names its topic in its fkey
|
|
75066
|
+
* (`topics^<topic id>^cols`); a topic is its own id.
|
|
75067
|
+
***************************************************************/
|
|
75068
|
+
function mark_written_record(gobj, topic_name, record) {
|
|
75069
|
+
let priv = gobj.priv;
|
|
75070
|
+
if (!record) return;
|
|
75071
|
+
if (topic_name === T_TOPICS && typeof record.id === "string" && record.id) {
|
|
75072
|
+
priv.written[record.id] = true;
|
|
75073
|
+
return;
|
|
75074
|
+
}
|
|
75075
|
+
if (topic_name !== T_COLS) return;
|
|
75076
|
+
let refs = Array.isArray(record.topics) ? record.topics : typeof record.topics === "string" ? [record.topics] : [];
|
|
75077
|
+
for (let ref of refs) {
|
|
75078
|
+
let parts = String(ref).split("^");
|
|
75079
|
+
if (parts.length >= 2 && parts[1]) priv.written[parts[1]] = true;
|
|
75080
|
+
}
|
|
75001
75081
|
}
|
|
75002
75082
|
/***************************************************************
|
|
75003
75083
|
* Remember which topic this write belongs to, which is what
|
|
@@ -75056,7 +75136,7 @@ function ac_transport_state(gobj, event, kw, src) {
|
|
|
75056
75136
|
}
|
|
75057
75137
|
if ((!priv.model || priv.reload_on_open) && state !== "ST_LOADING" && state !== "ST_SAVING") {
|
|
75058
75138
|
priv.reload_on_open = false;
|
|
75059
|
-
return request_model(gobj);
|
|
75139
|
+
return request_model(gobj, true);
|
|
75060
75140
|
}
|
|
75061
75141
|
render_toolbar(gobj);
|
|
75062
75142
|
return 0;
|
|
@@ -75071,7 +75151,25 @@ function ac_language_changed$1(gobj, event, kw, src) {
|
|
|
75071
75151
|
return 0;
|
|
75072
75152
|
}
|
|
75073
75153
|
function ac_refresh$1(gobj, event, kw, src) {
|
|
75074
|
-
return request_model(gobj);
|
|
75154
|
+
return request_model(gobj, false);
|
|
75155
|
+
}
|
|
75156
|
+
/***************************************************************
|
|
75157
|
+
* What a DIALOG sends while the model is being read again: the
|
|
75158
|
+
* Save of a form left open when the reload started, a
|
|
75159
|
+
* confirmation, an import. The loading screen took the rest of
|
|
75160
|
+
* the view away (request_model()); a dialog is the one thing the
|
|
75161
|
+
* operator can still reach, and what it asks is computed against
|
|
75162
|
+
* a model the answers in the air are about to replace.
|
|
75163
|
+
*
|
|
75164
|
+
* Refused, and SAID -- and the dialog stays open with what was
|
|
75165
|
+
* typed, so the same Save works once the load is in. Undeclared,
|
|
75166
|
+
* it answered "Event NOT DEFINED in state ST_LOADING" and the
|
|
75167
|
+
* edit was gone with no word (third independent review).
|
|
75168
|
+
***************************************************************/
|
|
75169
|
+
function ac_wait_for_the_load(gobj, event, kw, src) {
|
|
75170
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} refused, the schemas are loading`);
|
|
75171
|
+
yui_shell_show_error(yui_shell_of(gobj), "the schemas are loading: try again when they are in", { t: i18next.t });
|
|
75172
|
+
return -1;
|
|
75075
75173
|
}
|
|
75076
75174
|
/***************************************************************
|
|
75077
75175
|
* {drafts: {treedb_name: [topic names]}} -- the host says which
|
|
@@ -75619,7 +75717,38 @@ function create_gclass$1(gclass_name) {
|
|
|
75619
75717
|
];
|
|
75620
75718
|
const states = [
|
|
75621
75719
|
["ST_IDLE", COMMON.slice()],
|
|
75622
|
-
["ST_LOADING", COMMON.
|
|
75720
|
+
["ST_LOADING", COMMON.concat([
|
|
75721
|
+
[
|
|
75722
|
+
"EV_SAVE_COLUMN",
|
|
75723
|
+
ac_wait_for_the_load,
|
|
75724
|
+
null
|
|
75725
|
+
],
|
|
75726
|
+
[
|
|
75727
|
+
"EV_SAVE_TOPIC",
|
|
75728
|
+
ac_wait_for_the_load,
|
|
75729
|
+
null
|
|
75730
|
+
],
|
|
75731
|
+
[
|
|
75732
|
+
"EV_DELETE_ORPHAN",
|
|
75733
|
+
ac_wait_for_the_load,
|
|
75734
|
+
null
|
|
75735
|
+
],
|
|
75736
|
+
[
|
|
75737
|
+
"EV_PREVIEW_IMPORT",
|
|
75738
|
+
ac_wait_for_the_load,
|
|
75739
|
+
null
|
|
75740
|
+
],
|
|
75741
|
+
[
|
|
75742
|
+
"EV_APPLY_IMPORT",
|
|
75743
|
+
ac_wait_for_the_load,
|
|
75744
|
+
null
|
|
75745
|
+
],
|
|
75746
|
+
[
|
|
75747
|
+
"EV_CONFIRMED",
|
|
75748
|
+
ac_wait_for_the_load,
|
|
75749
|
+
null
|
|
75750
|
+
]
|
|
75751
|
+
])],
|
|
75623
75752
|
["ST_EMPTY", COMMON.slice()],
|
|
75624
75753
|
["ST_TREEDBS", COMMON.concat([
|
|
75625
75754
|
[
|