@yuneta/gobj-ui 7.25.6 → 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 +53 -1
- package/dist/gobj-ui.cjs.js +330 -63
- package/dist/gobj-ui.es.js +330 -63
- package/package.json +1 -1
- package/src/c_yui_schema_editor.js +339 -66
- package/src/schema_editor_reload.wiring.test.js +473 -0
- package/src/schema_editor_transport.wiring.test.js +174 -1
- package/src/shell_modals.js +61 -12
- package/src/shell_toast_once.test.js +125 -0
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -3025,6 +3025,22 @@ function maybe_apply_translator($node, opts) {
|
|
|
3025
3025
|
* Non-blocking, auto-dismiss after `opts.timeout` ms (default
|
|
3026
3026
|
* 5000). `opts.timeout = 0` disables auto-dismiss.
|
|
3027
3027
|
* Returns `{ close() }` so callers can dismiss programmatically.
|
|
3028
|
+
*
|
|
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. 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.
|
|
3028
3044
|
***************************************************************/
|
|
3029
3045
|
function show_notification(shell, kind, message, opts) {
|
|
3030
3046
|
let $layer = notification_layer(shell);
|
|
@@ -3032,6 +3048,11 @@ function show_notification(shell, kind, message, opts) {
|
|
|
3032
3048
|
(0, _yuneta_gobj_js.log_warning)("yui_shell_show_*: shell has no notification layer");
|
|
3033
3049
|
return { close: () => {} };
|
|
3034
3050
|
}
|
|
3051
|
+
let timeout = opts && opts.timeout != null ? opts.timeout : 5e3;
|
|
3052
|
+
let key = typeof message === "string" ? `${kind}\u0000${message}` : null;
|
|
3053
|
+
if (key !== null) {
|
|
3054
|
+
for (let $shown of Array.from($layer.children)) if ($shown.__toast_key__ === key && $shown.__toast__) return $shown.__toast__.hold(timeout);
|
|
3055
|
+
}
|
|
3035
3056
|
let p_attrs = typeof message === "string" ? { i18n: message } : {};
|
|
3036
3057
|
let $note = (0, _yuneta_gobj_js.createElement2)([
|
|
3037
3058
|
"div",
|
|
@@ -3054,22 +3075,38 @@ function show_notification(shell, kind, message, opts) {
|
|
|
3054
3075
|
]);
|
|
3055
3076
|
$layer.appendChild($note);
|
|
3056
3077
|
maybe_apply_translator($note, opts);
|
|
3057
|
-
let
|
|
3078
|
+
let holders = /* @__PURE__ */ new Set();
|
|
3058
3079
|
let closed = false;
|
|
3059
|
-
let
|
|
3080
|
+
let close_toast = function() {
|
|
3060
3081
|
if (closed) return;
|
|
3061
3082
|
closed = true;
|
|
3062
|
-
if (timeout_id) {
|
|
3063
|
-
clearTimeout(timeout_id);
|
|
3064
|
-
timeout_id = null;
|
|
3083
|
+
for (let holder of holders) if (holder.timeout_id) {
|
|
3084
|
+
clearTimeout(holder.timeout_id);
|
|
3085
|
+
holder.timeout_id = null;
|
|
3065
3086
|
}
|
|
3087
|
+
holders.clear();
|
|
3066
3088
|
if ($note.parentNode) $note.parentNode.removeChild($note);
|
|
3067
3089
|
};
|
|
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 };
|
|
3104
|
+
};
|
|
3068
3105
|
let $del = $note.querySelector(".delete");
|
|
3069
|
-
if ($del) $del.addEventListener("click",
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
return
|
|
3106
|
+
if ($del) $del.addEventListener("click", close_toast);
|
|
3107
|
+
$note.__toast_key__ = key;
|
|
3108
|
+
$note.__toast__ = { hold };
|
|
3109
|
+
return hold(timeout);
|
|
3073
3110
|
}
|
|
3074
3111
|
function yui_shell_show_info(shell, message, opts) {
|
|
3075
3112
|
return show_notification(shell, "info", message, opts);
|
|
@@ -72140,6 +72177,7 @@ var PRIVATE_DATA$1 = {
|
|
|
72140
72177
|
pending: 0,
|
|
72141
72178
|
load_error: "",
|
|
72142
72179
|
load_round: 0,
|
|
72180
|
+
load_keeps_written: false,
|
|
72143
72181
|
treedb_id: "",
|
|
72144
72182
|
topic_name: "",
|
|
72145
72183
|
diagram: false,
|
|
@@ -72156,6 +72194,9 @@ var PRIVATE_DATA$1 = {
|
|
|
72156
72194
|
write_tag: 0,
|
|
72157
72195
|
connected: false,
|
|
72158
72196
|
reload_on_open: false,
|
|
72197
|
+
dropped_round: 0,
|
|
72198
|
+
dropped_write: 0,
|
|
72199
|
+
reload_after_write: false,
|
|
72159
72200
|
pending_seg: null,
|
|
72160
72201
|
import_plan: null,
|
|
72161
72202
|
import_pane: null,
|
|
@@ -72315,10 +72356,28 @@ function refuse_if_readonly(gobj, event) {
|
|
|
72315
72356
|
* schema set of the yuno is here: everything below — the
|
|
72316
72357
|
* drawing, the validation, the export — is computed from these
|
|
72317
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.
|
|
72318
72376
|
***************************************************************/
|
|
72319
|
-
function request_model(gobj) {
|
|
72377
|
+
function request_model(gobj, keep_written) {
|
|
72320
72378
|
let priv = gobj.priv;
|
|
72321
72379
|
if (!(0, _yuneta_gobj_js.gobj_read_pointer_attr)(gobj, "gobj_remote_yuno")) return -1;
|
|
72380
|
+
let previous = priv.records;
|
|
72322
72381
|
priv.records = {
|
|
72323
72382
|
treedbs: [],
|
|
72324
72383
|
topics: [],
|
|
@@ -72327,22 +72386,31 @@ function request_model(gobj) {
|
|
|
72327
72386
|
priv.load_error = "";
|
|
72328
72387
|
priv.pending = 0;
|
|
72329
72388
|
priv.load_round++;
|
|
72389
|
+
priv.load_keeps_written = !!keep_written;
|
|
72330
72390
|
(0, _yuneta_gobj_js.gobj_change_state)(gobj, "ST_LOADING");
|
|
72331
|
-
|
|
72332
|
-
|
|
72333
|
-
|
|
72334
|
-
|
|
72335
|
-
|
|
72336
|
-
|
|
72337
|
-
|
|
72338
|
-
|
|
72339
|
-
|
|
72340
|
-
|
|
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;
|
|
72341
72408
|
priv.load_error = (0, i18next.t)("cannot reach the treedb");
|
|
72342
|
-
(
|
|
72343
|
-
|
|
72409
|
+
if (priv.model) yui_shell_show_error(yui_shell_of(gobj), "cannot reach the treedb", { t: i18next.t });
|
|
72410
|
+
end_load(gobj);
|
|
72344
72411
|
return -1;
|
|
72345
72412
|
}
|
|
72413
|
+
priv.pending = left;
|
|
72346
72414
|
return 0;
|
|
72347
72415
|
}
|
|
72348
72416
|
/***************************************************************
|
|
@@ -72405,15 +72473,19 @@ function build_model(gobj) {
|
|
|
72405
72473
|
* From here on, "did this session change it?" has an answer.
|
|
72406
72474
|
*
|
|
72407
72475
|
* Called ONLY when records arrive from the store: that is what a
|
|
72408
|
-
* measurement of "changed since" can be measured against.
|
|
72409
|
-
*
|
|
72410
|
-
*
|
|
72411
|
-
*
|
|
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.
|
|
72412
72484
|
***************************************************************/
|
|
72413
72485
|
function start_measuring(gobj) {
|
|
72414
72486
|
let priv = gobj.priv;
|
|
72415
72487
|
priv.baseline = {};
|
|
72416
|
-
priv.written = {};
|
|
72488
|
+
if (!priv.load_keeps_written) priv.written = {};
|
|
72417
72489
|
priv.host_ids = {};
|
|
72418
72490
|
if (!priv.model) return;
|
|
72419
72491
|
for (let treedb of priv.model.treedbs) for (let topic of treedb.topics) priv.baseline[topic.id] = topic.topic_version;
|
|
@@ -72595,8 +72667,10 @@ function render_toolbar(gobj) {
|
|
|
72595
72667
|
let state = (0, _yuneta_gobj_js.gobj_current_state)(gobj);
|
|
72596
72668
|
let readonly = is_readonly(gobj);
|
|
72597
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";
|
|
72598
72672
|
let $left = [];
|
|
72599
|
-
if (priv.treedb_id) $left.push([
|
|
72673
|
+
if (priv.treedb_id && on_a_treedb) $left.push([
|
|
72600
72674
|
"button",
|
|
72601
72675
|
{
|
|
72602
72676
|
class: "SCHEMA_BACK button",
|
|
@@ -72669,17 +72743,17 @@ function render_toolbar(gobj) {
|
|
|
72669
72743
|
$trail
|
|
72670
72744
|
]);
|
|
72671
72745
|
let $right = [];
|
|
72672
|
-
if (priv.treedb_id && has_model) {
|
|
72746
|
+
if (priv.treedb_id && has_model && on_a_treedb) {
|
|
72673
72747
|
$right.push(toolbar_button("SCHEMA_DIAGRAM_BTN", "yi-compass-drafting", priv.diagram ? "topics" : "diagram", "EV_TOGGLE_DIAGRAM", false));
|
|
72674
72748
|
$right.push(toolbar_button("SCHEMA_VALIDATE_BTN", "yi-square-check", "check", "EV_VALIDATE", false));
|
|
72675
72749
|
$right.push(toolbar_button("SCHEMA_EXPORT_BTN", "yi-download", "export", "EV_EXPORT", false));
|
|
72676
72750
|
if (!readonly) $right.push(toolbar_button("SCHEMA_IMPORT_BTN", "yi-upload", "import", "EV_IMPORT", false));
|
|
72677
72751
|
}
|
|
72678
|
-
if (priv.topic_name && !readonly && !priv.diagram) {
|
|
72752
|
+
if (priv.topic_name && !readonly && !priv.diagram && on_a_treedb) {
|
|
72679
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));
|
|
72680
72754
|
$right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus", "new column", "EV_ADD_COLUMN", false));
|
|
72681
72755
|
}
|
|
72682
|
-
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));
|
|
72683
72757
|
$right.push(toolbar_button("SCHEMA_REFRESH_BTN", "yi-arrows-rotate", "refresh", "EV_REFRESH", state === "ST_LOADING"));
|
|
72684
72758
|
let $bar = (0, _yuneta_gobj_js.createElement2)([
|
|
72685
72759
|
"div",
|
|
@@ -72705,7 +72779,7 @@ function render_toolbar(gobj) {
|
|
|
72705
72779
|
]);
|
|
72706
72780
|
for (let $button of $bar.querySelectorAll("button")) {
|
|
72707
72781
|
$button.__gobj__ = gobj;
|
|
72708
|
-
if (
|
|
72782
|
+
if (in_flight) $button.disabled = true;
|
|
72709
72783
|
}
|
|
72710
72784
|
$toolbar.appendChild($bar);
|
|
72711
72785
|
(0, _yuneta_gobj_js.refresh_language)($toolbar, i18next.t);
|
|
@@ -72723,16 +72797,19 @@ function render(gobj) {
|
|
|
72723
72797
|
render_toolbar(gobj);
|
|
72724
72798
|
if (state === "ST_LOADING") {
|
|
72725
72799
|
show_notice(gobj, "loading the schemas");
|
|
72800
|
+
destroy_diagram(gobj);
|
|
72726
72801
|
clear($body);
|
|
72727
72802
|
return;
|
|
72728
72803
|
}
|
|
72729
72804
|
if (state === "ST_IDLE") {
|
|
72730
72805
|
show_notice(gobj, priv.load_error ? "cannot load the schemas" : "not connected", priv.load_error);
|
|
72806
|
+
destroy_diagram(gobj);
|
|
72731
72807
|
clear($body);
|
|
72732
72808
|
return;
|
|
72733
72809
|
}
|
|
72734
72810
|
if (state === "ST_EMPTY") {
|
|
72735
72811
|
show_notice(gobj, "this yuno stores no schema");
|
|
72812
|
+
destroy_diagram(gobj);
|
|
72736
72813
|
clear($body);
|
|
72737
72814
|
return;
|
|
72738
72815
|
}
|
|
@@ -73421,12 +73498,16 @@ function render_diagram(gobj) {
|
|
|
73421
73498
|
let priv = gobj.priv;
|
|
73422
73499
|
let $body = $of(gobj, ".SCHEMA_BODY");
|
|
73423
73500
|
let treedb = current_treedb(gobj);
|
|
73424
|
-
if (!$body
|
|
73501
|
+
if (!$body) return;
|
|
73502
|
+
if (!treedb) {
|
|
73503
|
+
destroy_diagram(gobj);
|
|
73504
|
+
clear($body);
|
|
73425
73505
|
show_notice(gobj, "that treedb is not here any more", priv.treedb_id);
|
|
73426
73506
|
return;
|
|
73427
73507
|
}
|
|
73428
73508
|
if (!(0, _yuneta_gobj_js.gclass_find_by_name)("C_YUI_TREEDB_SCHEMA")) {
|
|
73429
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);
|
|
73430
73511
|
show_notice(gobj, "the schema drawing is not available");
|
|
73431
73512
|
return;
|
|
73432
73513
|
}
|
|
@@ -74624,6 +74705,15 @@ function transport_in_session(gobj) {
|
|
|
74624
74705
|
* one the drop abandoned (or a deadline settled) can still come
|
|
74625
74706
|
* back: counted, it ended the next load with the old data or
|
|
74626
74707
|
* moved the next write's queue.
|
|
74708
|
+
*
|
|
74709
|
+
* The state is part of the question, and that is only true
|
|
74710
|
+
* because NOTHING moves the editor out of ST_LOADING or ST_SAVING
|
|
74711
|
+
* but the end of what is in flight: a position the host sends
|
|
74712
|
+
* meanwhile waits in `pending_seg` (ac_show()). 7.25.6 let EV_SHOW
|
|
74713
|
+
* move a RELOAD out of ST_LOADING, and every answer of it was then
|
|
74714
|
+
* "for a load that is over": the records it had emptied stayed
|
|
74715
|
+
* empty, and the next write patched them into a model with no
|
|
74716
|
+
* treedb at all.
|
|
74627
74717
|
***************************************************************/
|
|
74628
74718
|
function is_current_load(gobj, md) {
|
|
74629
74719
|
return (0, _yuneta_gobj_js.gobj_current_state)(gobj) === "ST_LOADING" && (0, _yuneta_gobj_js.kw_get_int)(gobj, md, "round", 0, 0) === gobj.priv.load_round;
|
|
@@ -74644,20 +74734,42 @@ function transport_dropped(gobj) {
|
|
|
74644
74734
|
let state = (0, _yuneta_gobj_js.gobj_current_state)(gobj);
|
|
74645
74735
|
priv.reload_on_open = true;
|
|
74646
74736
|
if (state === "ST_SAVING") {
|
|
74737
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: the transport dropped during a write: the model is read again on the reconnect`);
|
|
74738
|
+
priv.dropped_write = priv.write_tag;
|
|
74647
74739
|
priv.write_tag++;
|
|
74648
74740
|
return end_writes(gobj, "the connection dropped during the write");
|
|
74649
74741
|
}
|
|
74650
74742
|
if (state === "ST_LOADING") {
|
|
74743
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: the transport dropped during the load: the model is read again on the reconnect`);
|
|
74744
|
+
priv.dropped_round = priv.load_round;
|
|
74651
74745
|
priv.load_round++;
|
|
74652
74746
|
priv.pending = 0;
|
|
74653
74747
|
priv.load_error = "";
|
|
74654
|
-
|
|
74655
|
-
(0, _yuneta_gobj_js.gobj_change_state)(gobj, "ST_IDLE");
|
|
74656
|
-
render(gobj);
|
|
74748
|
+
return end_load(gobj);
|
|
74657
74749
|
}
|
|
74658
74750
|
return 0;
|
|
74659
74751
|
}
|
|
74660
74752
|
/***************************************************************
|
|
74753
|
+
* A load is over -- landed, failed or cut -- and the editor goes
|
|
74754
|
+
* where the operator is: the position the host sent while it was
|
|
74755
|
+
* in flight (ac_show() kept it), or the one it had. Without a
|
|
74756
|
+
* model there is no screen to go to: the position is kept for the
|
|
74757
|
+
* next load, and the editor says why it is empty.
|
|
74758
|
+
***************************************************************/
|
|
74759
|
+
function end_load(gobj) {
|
|
74760
|
+
let priv = gobj.priv;
|
|
74761
|
+
let seg = priv.pending_seg;
|
|
74762
|
+
priv.pending_seg = null;
|
|
74763
|
+
if (priv.model) {
|
|
74764
|
+
if (seg !== null) return apply_seg(gobj, seg);
|
|
74765
|
+
return go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
|
|
74766
|
+
}
|
|
74767
|
+
if (seg !== null) adopt_seg(gobj, seg);
|
|
74768
|
+
(0, _yuneta_gobj_js.gobj_change_state)(gobj, "ST_IDLE");
|
|
74769
|
+
render(gobj);
|
|
74770
|
+
return 0;
|
|
74771
|
+
}
|
|
74772
|
+
/***************************************************************
|
|
74661
74773
|
* The queue is done, or gave up. Either way the model is what
|
|
74662
74774
|
* the answers made it, so the screen is redrawn from it and the
|
|
74663
74775
|
* host is told once — the tab above owns the pending flag and
|
|
@@ -74665,29 +74777,40 @@ function transport_dropped(gobj) {
|
|
|
74665
74777
|
***************************************************************/
|
|
74666
74778
|
function end_writes(gobj, error) {
|
|
74667
74779
|
let priv = gobj.priv;
|
|
74780
|
+
let seg = priv.pending_seg;
|
|
74668
74781
|
priv.save_queue = [];
|
|
74782
|
+
priv.pending_seg = null;
|
|
74669
74783
|
(0, _yuneta_gobj_js.gobj_change_state)(gobj, priv.save_return || "ST_TREEDBS");
|
|
74670
74784
|
priv.save_return = "";
|
|
74671
74785
|
show_notice(gobj, "");
|
|
74672
74786
|
set_busy(gobj, false);
|
|
74673
|
-
if (priv.pending_seg !== null) {
|
|
74674
|
-
let seg = priv.pending_seg;
|
|
74675
|
-
priv.pending_seg = null;
|
|
74676
|
-
if (!error) {
|
|
74677
|
-
apply_seg(gobj, seg);
|
|
74678
|
-
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") });
|
|
74679
|
-
priv.save_wrote = false;
|
|
74680
|
-
return 0;
|
|
74681
|
-
}
|
|
74682
|
-
}
|
|
74683
74787
|
if (error) yui_shell_show_error(yui_shell_of(gobj), error, { t: i18next.t });
|
|
74684
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") });
|
|
74685
74789
|
priv.save_wrote = false;
|
|
74686
|
-
|
|
74687
|
-
|
|
74790
|
+
if (seg !== null) apply_seg(gobj, seg);
|
|
74791
|
+
else {
|
|
74792
|
+
render(gobj);
|
|
74793
|
+
publish_check(gobj);
|
|
74794
|
+
}
|
|
74795
|
+
reload_if_owed(gobj);
|
|
74688
74796
|
return error ? -1 : 0;
|
|
74689
74797
|
}
|
|
74690
74798
|
/***************************************************************
|
|
74799
|
+
* A write given up earlier turned out DONE while another one was
|
|
74800
|
+
* in flight (see ac_mt_command_answer()): the model is read again
|
|
74801
|
+
* now that nothing is.
|
|
74802
|
+
***************************************************************/
|
|
74803
|
+
function reload_if_owed(gobj) {
|
|
74804
|
+
let priv = gobj.priv;
|
|
74805
|
+
if (!priv.reload_after_write) return 0;
|
|
74806
|
+
priv.reload_after_write = false;
|
|
74807
|
+
if (!transport_in_session(gobj)) {
|
|
74808
|
+
priv.reload_on_open = true;
|
|
74809
|
+
return 0;
|
|
74810
|
+
}
|
|
74811
|
+
return request_model(gobj, true);
|
|
74812
|
+
}
|
|
74813
|
+
/***************************************************************
|
|
74691
74814
|
* The record a column form produces.
|
|
74692
74815
|
*
|
|
74693
74816
|
* Everything the store needs and the operator did not type is
|
|
@@ -74751,11 +74874,12 @@ function topic_record(gobj, treedb, topic, values) {
|
|
|
74751
74874
|
***************************************************************/
|
|
74752
74875
|
function go(gobj, treedb_id, topic_name, diagram, mirror) {
|
|
74753
74876
|
let priv = gobj.priv;
|
|
74877
|
+
priv.pending_seg = null;
|
|
74754
74878
|
priv.treedb_id = treedb_id || "";
|
|
74755
74879
|
priv.topic_name = topic_name || "";
|
|
74756
74880
|
priv.diagram = !!diagram;
|
|
74757
74881
|
let state = "ST_TREEDBS";
|
|
74758
|
-
if (!priv.model) state = "
|
|
74882
|
+
if (!priv.model) state = "ST_IDLE";
|
|
74759
74883
|
else if (priv.model.treedbs.length === 0) state = "ST_EMPTY";
|
|
74760
74884
|
else if (priv.treedb_id && priv.diagram) state = "ST_DIAGRAM";
|
|
74761
74885
|
else if (priv.treedb_id && priv.topic_name) state = "ST_COLUMNS";
|
|
@@ -74782,12 +74906,39 @@ function position_seg(gobj) {
|
|
|
74782
74906
|
* empty screen: a shared link outlives the schema it points at.
|
|
74783
74907
|
***************************************************************/
|
|
74784
74908
|
function apply_seg(gobj, seg) {
|
|
74909
|
+
let pos = seg_position(seg);
|
|
74910
|
+
return go(gobj, pos.treedb_id, pos.topic_name, pos.diagram, false);
|
|
74911
|
+
}
|
|
74912
|
+
function seg_position(seg) {
|
|
74785
74913
|
let parts = String(seg || "").split("/").filter((x) => x.length > 0);
|
|
74786
74914
|
let treedb_id = parts[0] || "";
|
|
74787
74915
|
let tail = parts[1] || "";
|
|
74788
|
-
if (!treedb_id) return
|
|
74789
|
-
|
|
74790
|
-
|
|
74916
|
+
if (!treedb_id) return {
|
|
74917
|
+
treedb_id: "",
|
|
74918
|
+
topic_name: "",
|
|
74919
|
+
diagram: false
|
|
74920
|
+
};
|
|
74921
|
+
if (tail === DIAGRAM_SEG) return {
|
|
74922
|
+
treedb_id,
|
|
74923
|
+
topic_name: "",
|
|
74924
|
+
diagram: true
|
|
74925
|
+
};
|
|
74926
|
+
return {
|
|
74927
|
+
treedb_id,
|
|
74928
|
+
topic_name: tail,
|
|
74929
|
+
diagram: false
|
|
74930
|
+
};
|
|
74931
|
+
}
|
|
74932
|
+
/***************************************************************
|
|
74933
|
+
* Where the operator is, taken WITHOUT a screen: there is no model
|
|
74934
|
+
* to draw it on yet, and the load that brings one goes there.
|
|
74935
|
+
***************************************************************/
|
|
74936
|
+
function adopt_seg(gobj, seg) {
|
|
74937
|
+
let priv = gobj.priv;
|
|
74938
|
+
let pos = seg_position(seg);
|
|
74939
|
+
priv.treedb_id = pos.treedb_id;
|
|
74940
|
+
priv.topic_name = pos.topic_name;
|
|
74941
|
+
priv.diagram = pos.diagram;
|
|
74791
74942
|
}
|
|
74792
74943
|
/***************************
|
|
74793
74944
|
* Actions
|
|
@@ -74815,6 +74966,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
74815
74966
|
if (command === "nodes") {
|
|
74816
74967
|
let topic_name = (0, _yuneta_gobj_js.kw_get_str)(gobj, md, "topic_name", "", 0);
|
|
74817
74968
|
if (!is_current_load(gobj, md)) {
|
|
74969
|
+
if (result < 0 && (0, _yuneta_gobj_js.kw_get_int)(gobj, md, "round", 0, 0) === priv.dropped_round) return 0;
|
|
74818
74970
|
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: 'nodes' of '${topic_name}' answered for a load that is over: ignored`);
|
|
74819
74971
|
return 0;
|
|
74820
74972
|
}
|
|
@@ -74824,20 +74976,22 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
74824
74976
|
if (priv.pending > 0) return 0;
|
|
74825
74977
|
if (priv.load_error) {
|
|
74826
74978
|
priv.model = null;
|
|
74827
|
-
|
|
74828
|
-
render(gobj);
|
|
74829
|
-
return 0;
|
|
74979
|
+
return end_load(gobj);
|
|
74830
74980
|
}
|
|
74831
74981
|
priv.order_undo = {};
|
|
74832
74982
|
build_model(gobj);
|
|
74833
74983
|
start_measuring(gobj);
|
|
74834
|
-
return
|
|
74984
|
+
return end_load(gobj);
|
|
74835
74985
|
}
|
|
74836
74986
|
if (command === "update-node" || command === "delete-node") {
|
|
74837
74987
|
let topic_name = (0, _yuneta_gobj_js.kw_get_str)(gobj, md, "topic_name", "", 0);
|
|
74838
74988
|
if (!is_current_write(gobj, md)) {
|
|
74839
|
-
(0
|
|
74840
|
-
|
|
74989
|
+
if (result < 0 && (0, _yuneta_gobj_js.kw_get_int)(gobj, md, "write", 0, 0) === priv.dropped_write) return 0;
|
|
74990
|
+
if (result < 0) {
|
|
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`);
|
|
74992
|
+
return 0;
|
|
74993
|
+
}
|
|
74994
|
+
return late_write_done(gobj, command, topic_name, data);
|
|
74841
74995
|
}
|
|
74842
74996
|
if (result < 0) return end_writes(gobj, comment || (0, i18next.t)("the treedb refused the write"));
|
|
74843
74997
|
priv.save_wrote = true;
|
|
@@ -74847,8 +75001,15 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
74847
75001
|
if (record) patch_record(gobj, topic_name, record);
|
|
74848
75002
|
else {
|
|
74849
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
|
+
}
|
|
74850
75008
|
priv.save_queue = [];
|
|
74851
|
-
|
|
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);
|
|
74852
75013
|
return 0;
|
|
74853
75014
|
}
|
|
74854
75015
|
}
|
|
@@ -74863,6 +75024,62 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
74863
75024
|
return 0;
|
|
74864
75025
|
}
|
|
74865
75026
|
/***************************************************************
|
|
75027
|
+
* A write this view gave up on (a drop, a deadline) answers that
|
|
75028
|
+
* it was DONE: the store holds a change the model does not show.
|
|
75029
|
+
* The model is read again -- now, or when what is in flight ends,
|
|
75030
|
+
* or on the reconnect. A load in flight needs nothing: it was
|
|
75031
|
+
* asked after the write, on the same transport, and reads it.
|
|
75032
|
+
*
|
|
75033
|
+
* Only when the answer reaches this view. A routing adapter that
|
|
75034
|
+
* settled the write on its own deadline (gui_agent's
|
|
75035
|
+
* C_AGENT_TREEDB_LINK) does not deliver its late answer again --
|
|
75036
|
+
* the view was answered once, as failed -- and echoes the node
|
|
75037
|
+
* event instead, which this view does not hear: there, Refresh is
|
|
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.
|
|
75044
|
+
***************************************************************/
|
|
75045
|
+
function late_write_done(gobj, command, topic_name, data) {
|
|
75046
|
+
let priv = gobj.priv;
|
|
75047
|
+
let state = (0, _yuneta_gobj_js.gobj_current_state)(gobj);
|
|
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") });
|
|
75051
|
+
if (state === "ST_LOADING") return 0;
|
|
75052
|
+
if (state === "ST_SAVING") {
|
|
75053
|
+
priv.reload_after_write = true;
|
|
75054
|
+
return 0;
|
|
75055
|
+
}
|
|
75056
|
+
if (!transport_in_session(gobj)) {
|
|
75057
|
+
priv.reload_on_open = true;
|
|
75058
|
+
return 0;
|
|
75059
|
+
}
|
|
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
|
+
}
|
|
75081
|
+
}
|
|
75082
|
+
/***************************************************************
|
|
74866
75083
|
* Remember which topic this write belongs to, which is what
|
|
74867
75084
|
* "its version still has to move" is asked about.
|
|
74868
75085
|
***************************************************************/
|
|
@@ -74882,7 +75099,8 @@ function mark_written(gobj, topic_name, record) {
|
|
|
74882
75099
|
function ac_show(gobj, event, kw, src) {
|
|
74883
75100
|
let priv = gobj.priv;
|
|
74884
75101
|
let seg = kw && kw.subpath || "";
|
|
74885
|
-
|
|
75102
|
+
let state = (0, _yuneta_gobj_js.gobj_current_state)(gobj);
|
|
75103
|
+
if (state === "ST_SAVING" || state === "ST_LOADING") {
|
|
74886
75104
|
priv.pending_seg = seg;
|
|
74887
75105
|
return 0;
|
|
74888
75106
|
}
|
|
@@ -74918,7 +75136,7 @@ function ac_transport_state(gobj, event, kw, src) {
|
|
|
74918
75136
|
}
|
|
74919
75137
|
if ((!priv.model || priv.reload_on_open) && state !== "ST_LOADING" && state !== "ST_SAVING") {
|
|
74920
75138
|
priv.reload_on_open = false;
|
|
74921
|
-
return request_model(gobj);
|
|
75139
|
+
return request_model(gobj, true);
|
|
74922
75140
|
}
|
|
74923
75141
|
render_toolbar(gobj);
|
|
74924
75142
|
return 0;
|
|
@@ -74933,7 +75151,25 @@ function ac_language_changed$1(gobj, event, kw, src) {
|
|
|
74933
75151
|
return 0;
|
|
74934
75152
|
}
|
|
74935
75153
|
function ac_refresh$1(gobj, event, kw, src) {
|
|
74936
|
-
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;
|
|
74937
75173
|
}
|
|
74938
75174
|
/***************************************************************
|
|
74939
75175
|
* {drafts: {treedb_name: [topic names]}} -- the host says which
|
|
@@ -75481,7 +75717,38 @@ function create_gclass$1(gclass_name) {
|
|
|
75481
75717
|
];
|
|
75482
75718
|
const states = [
|
|
75483
75719
|
["ST_IDLE", COMMON.slice()],
|
|
75484
|
-
["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
|
+
])],
|
|
75485
75752
|
["ST_EMPTY", COMMON.slice()],
|
|
75486
75753
|
["ST_TREEDBS", COMMON.concat([
|
|
75487
75754
|
[
|