@yuneta/gobj-ui 7.25.14 → 7.25.15
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 +41 -0
- package/dist/gobj-ui.cjs.js +184 -53
- package/dist/gobj-ui.es.js +184 -53
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +42 -11
- package/src/c_yui_schema_editor.js +104 -37
- package/src/c_yui_treedb_graph.js +53 -6
- package/src/c_yui_treedb_topic_with_form.js +10 -10
- package/src/c_yui_treedb_topics.js +7 -7
- package/src/form_busy.js +2 -3
- package/src/form_time_value.js +1 -1
- package/src/form_time_value.test.js +1 -1
- package/src/form_writes_in_flight.js +1 -2
- package/src/g6_nodes_tree_fsm.test.js +33 -0
- package/src/graph_save_plan.js +28 -0
- package/src/graph_save_plan.test.js +36 -2
- package/src/host_drafts.js +2 -3
- package/src/schema_editor_drafts.wiring.test.js +1 -1
- package/src/schema_editor_reload.wiring.test.js +178 -46
- package/src/schema_editor_transport.wiring.test.js +2 -2
- package/src/schema_version_bump.test.js +1 -1
- package/src/shell_modals.js +2 -3
- package/src/shell_toast_once.test.js +10 -10
- package/src/table_cell_text.js +1 -1
- package/src/treedb_graph_writes.wiring.test.js +208 -0
- package/src/treedb_topics_transport.wiring.test.js +1 -1
- package/src/yui_row_search.test.js +1 -1
- package/src/yui_table_select.test.js +1 -1
package/dist/gobj-ui.es.js
CHANGED
|
@@ -3033,9 +3033,8 @@ function maybe_apply_translator($node, opts) {
|
|
|
3033
3033
|
* it -- until every handle is closed or has timed out. Handed the
|
|
3034
3034
|
* first caller's handle and timer, a repeat asking `timeout: 0`
|
|
3035
3035
|
* was dismissed on the first one's timer, and closing one
|
|
3036
|
-
* caller's handle closed a toast another was still showing
|
|
3037
|
-
*
|
|
3038
|
-
* everybody.
|
|
3036
|
+
* caller's handle closed a toast another was still showing.
|
|
3037
|
+
* The operator's ✕ closes it for everybody.
|
|
3039
3038
|
***************************************************************/
|
|
3040
3039
|
function show_notification(shell, kind, message, opts) {
|
|
3041
3040
|
let $layer = notification_layer(shell);
|
|
@@ -7420,7 +7419,7 @@ function json_diff_rows(doc_a, doc_b) {
|
|
|
7420
7419
|
* A Date -> the value of a `datetime-local` input, in local time,
|
|
7421
7420
|
* WITH seconds: the input is built with `step: 1`, which is what
|
|
7422
7421
|
* lets it hold them. Written as "YYYY-MM-DDTHH:mm" it lost them on
|
|
7423
|
-
* every save of any field
|
|
7422
|
+
* every save of any field.
|
|
7424
7423
|
************************************************************/
|
|
7425
7424
|
function date_to_datetime_local(value) {
|
|
7426
7425
|
if (!(value instanceof Date) || isNaN(value.getTime())) return "";
|
|
@@ -23125,8 +23124,7 @@ function yui_shell_show_route_map(shell, opts) {
|
|
|
23125
23124
|
* answers, so the host has to answer EVERY way a write ends --
|
|
23126
23125
|
* and the transport closing under a write in flight, or a
|
|
23127
23126
|
* command that never left because there was no session, are two
|
|
23128
|
-
* of them that nobody answered: the form stayed busy for ever
|
|
23129
|
-
* (N8 of the 2026-09-22 review).
|
|
23127
|
+
* of them that nobody answered: the form stayed busy for ever.
|
|
23130
23128
|
*
|
|
23131
23129
|
* A write is known by its TOPIC and its `form_write` serial,
|
|
23132
23130
|
* never by the serial alone: each topic has its own form, and
|
|
@@ -25677,8 +25675,8 @@ function ac_update_record(gobj, event, kw, src) {
|
|
|
25677
25675
|
/************************************************************
|
|
25678
25676
|
* A write sent with no session never leaves: C_IEVENT_CLI logs
|
|
25679
25677
|
* "Not in session" and answers null, as it does when the command
|
|
25680
|
-
* went -- so a form waiting for the answer waited for ever
|
|
25681
|
-
*
|
|
25678
|
+
* went -- so a form waiting for the answer waited for ever. Refused
|
|
25679
|
+
* before it is sent, aloud.
|
|
25682
25680
|
************************************************************/
|
|
25683
25681
|
function refuse_without_session(gobj, topic_name) {
|
|
25684
25682
|
if (is_connected$1(gobj)) return false;
|
|
@@ -26790,9 +26788,8 @@ function delete_impact(desc, records) {
|
|
|
26790
26788
|
* that back. So a second busy(true) while already busy must not
|
|
26791
26789
|
* run at all -- it read the buttons it had just disabled as
|
|
26792
26790
|
* "disabled on their own", and the busy(false) of a refused write
|
|
26793
|
-
* left Save and Cancel dead (
|
|
26794
|
-
*
|
|
26795
|
-
* the write). The caller owns `state` ({busy}) for the form's life.
|
|
26791
|
+
* left Save and Cancel dead (a record with a picked file went
|
|
26792
|
+
* busy for the read, then busy again for the write). The caller owns `state` ({busy}) for the form's life.
|
|
26796
26793
|
*
|
|
26797
26794
|
* Copyright (c) 2026, ArtGins.
|
|
26798
26795
|
* All Rights Reserved.
|
|
@@ -26830,7 +26827,7 @@ function set_toolbar_busy($container, state, busy) {
|
|
|
26830
26827
|
* (only its own `plaintext` formatter escapes), so a record's text
|
|
26831
26828
|
* returned as a string is parsed as markup: `a<b and c>d` showed
|
|
26832
26829
|
* as `ad`, and a field holding `<img src=x onerror=...>` ran it in
|
|
26833
|
-
* the operator's browser
|
|
26830
|
+
* the operator's browser. Record
|
|
26834
26831
|
* data goes in as a TEXT NODE, and a cell built around it as DOM,
|
|
26835
26832
|
* never as an HTML string with the data interpolated.
|
|
26836
26833
|
*
|
|
@@ -29592,7 +29589,7 @@ function ac_new_row(gobj, event, kw, src) {
|
|
|
29592
29589
|
* What crosses the confirmation is the rows' IDENTITY, never their
|
|
29593
29590
|
* position: the view applies EV_TREEDB_NODE_* of every writer while the
|
|
29594
29591
|
* dialog is open, and a position names whatever row sits there when the
|
|
29595
|
-
* person answers -- with force:true
|
|
29592
|
+
* person answers -- with force:true.
|
|
29596
29593
|
************************************************************/
|
|
29597
29594
|
function ac_delete_rows(gobj, event, kw, src) {
|
|
29598
29595
|
if (refuse_if_readonly$2(gobj, event)) return -1;
|
|
@@ -29803,8 +29800,8 @@ function ac_files_read(gobj, event, kw, src) {
|
|
|
29803
29800
|
* open and BUSY, and the serial it waits for is taken here.
|
|
29804
29801
|
*
|
|
29805
29802
|
* A refused write used to close the form all the same and throw
|
|
29806
|
-
* away what was typed, although the README said it stayed open
|
|
29807
|
-
*
|
|
29803
|
+
* away what was typed, although the README said it stayed open:
|
|
29804
|
+
* the close was posted with the
|
|
29808
29805
|
* publish, before the backend had answered anything.
|
|
29809
29806
|
************************************************************/
|
|
29810
29807
|
function wait_for_write_answer(gobj) {
|
|
@@ -30976,6 +30973,28 @@ function apply_graphs_echo(live, saved, records, rec) {
|
|
|
30976
30973
|
delete saved[rec.topic];
|
|
30977
30974
|
}
|
|
30978
30975
|
}
|
|
30976
|
+
/***************************************************************
|
|
30977
|
+
* A write of one topic's arrangement did NOT land: the backend
|
|
30978
|
+
* refused it, the transport refused it on the way out, or there
|
|
30979
|
+
* was no session to send it on.
|
|
30980
|
+
*
|
|
30981
|
+
* saved {topic_name: properties} what the backend has
|
|
30982
|
+
* topic_name the topic of the refused record
|
|
30983
|
+
*
|
|
30984
|
+
* The view records a write as saved BEFORE it leaves, because
|
|
30985
|
+
* nothing answers it when it lands. So a refused one left the view
|
|
30986
|
+
* believing the backend held an arrangement it does not, and the
|
|
30987
|
+
* next Save found nothing to write. What the backend holds for the
|
|
30988
|
+
* topic is not known any more, so it is forgotten: the next Save
|
|
30989
|
+
* writes the topic again (plan_graph_saves()).
|
|
30990
|
+
*
|
|
30991
|
+
* Returns TRUE if there was something to forget.
|
|
30992
|
+
***************************************************************/
|
|
30993
|
+
function forget_refused_graphs_write(saved, topic_name) {
|
|
30994
|
+
if (!is_object(saved) || !topic_name || !Object.prototype.hasOwnProperty.call(saved, topic_name)) return false;
|
|
30995
|
+
delete saved[topic_name];
|
|
30996
|
+
return true;
|
|
30997
|
+
}
|
|
30979
30998
|
//#endregion
|
|
30980
30999
|
//#region src/treedb_node_label.js
|
|
30981
31000
|
/***********************************************************************
|
|
@@ -65783,6 +65802,28 @@ function ac_save_graph(gobj, event, kw, src) {
|
|
|
65783
65802
|
return 0;
|
|
65784
65803
|
}
|
|
65785
65804
|
/************************************************************
|
|
65805
|
+
* The host says a write of `__graphs__` did not land: the
|
|
65806
|
+
* backend refused it, the transport refused it on the way out,
|
|
65807
|
+
* or there was no session to send it on. kw: {topic}
|
|
65808
|
+
*
|
|
65809
|
+
* save_topic_graph_properties() recorded it as saved before it
|
|
65810
|
+
* left. Forgotten now, and the Save is lit again: the next Save
|
|
65811
|
+
* writes the topic again. Before, the view believed the backend
|
|
65812
|
+
* held the arrangement, and the next Save had nothing to write.
|
|
65813
|
+
************************************************************/
|
|
65814
|
+
function ac_graphs_write_refused(gobj, event, kw, src) {
|
|
65815
|
+
let priv = gobj.priv;
|
|
65816
|
+
let topic_name = kw && kw.topic;
|
|
65817
|
+
if (!topic_name) {
|
|
65818
|
+
log_error(`${gobj_short_name(gobj)}: ${event} names no topic`);
|
|
65819
|
+
return -1;
|
|
65820
|
+
}
|
|
65821
|
+
log_warning(`${gobj_short_name(gobj)}: the arrangement of '${topic_name}' was not saved: the next Save writes it again`);
|
|
65822
|
+
forget_refused_graphs_write(priv._saved_graph_properties, topic_name);
|
|
65823
|
+
if (priv.edit_mode) mark_graph_dirty(gobj);
|
|
65824
|
+
return 0;
|
|
65825
|
+
}
|
|
65826
|
+
/************************************************************
|
|
65786
65827
|
* Node created, from subscription
|
|
65787
65828
|
************************************************************/
|
|
65788
65829
|
function ac_node_created(gobj, event, kw, src) {
|
|
@@ -66850,6 +66891,11 @@ function create_gclass$4(gclass_name) {
|
|
|
66850
66891
|
ac_node_deleted,
|
|
66851
66892
|
null
|
|
66852
66893
|
],
|
|
66894
|
+
[
|
|
66895
|
+
"EV_GRAPHS_WRITE_REFUSED",
|
|
66896
|
+
ac_graphs_write_refused,
|
|
66897
|
+
null
|
|
66898
|
+
],
|
|
66853
66899
|
[
|
|
66854
66900
|
"EV_NODE_CLICK",
|
|
66855
66901
|
ac_node_click$2,
|
|
@@ -67103,6 +67149,7 @@ function create_gclass$4(gclass_name) {
|
|
|
67103
67149
|
["EV_NODE_CREATED", 0],
|
|
67104
67150
|
["EV_NODE_UPDATED", 0],
|
|
67105
67151
|
["EV_NODE_DELETED", 0],
|
|
67152
|
+
["EV_GRAPHS_WRITE_REFUSED", 0],
|
|
67106
67153
|
["EV_NODE_CLICK", 0],
|
|
67107
67154
|
["EV_EDGE_CLICK", 0],
|
|
67108
67155
|
["EV_NODE_CONTEXT_MENU", 0],
|
|
@@ -68279,7 +68326,7 @@ function treedb_update_node(gobj, treedb_name, topic_name, record, options) {
|
|
|
68279
68326
|
let priv = gobj.priv;
|
|
68280
68327
|
if (!priv.gobj_remote_yuno) {
|
|
68281
68328
|
log_error(`${gobj_short_name(gobj)}: No gobj_remote_yuno defined`);
|
|
68282
|
-
return;
|
|
68329
|
+
return -1;
|
|
68283
68330
|
}
|
|
68284
68331
|
let command = "update-node";
|
|
68285
68332
|
let kw = {
|
|
@@ -68291,7 +68338,11 @@ function treedb_update_node(gobj, treedb_name, topic_name, record, options) {
|
|
|
68291
68338
|
};
|
|
68292
68339
|
kw.__md_command__ = { topic_name };
|
|
68293
68340
|
let ret = gobj_command(priv.gobj_remote_yuno, command, kw, gobj);
|
|
68294
|
-
if (ret)
|
|
68341
|
+
if (ret) {
|
|
68342
|
+
log_error(ret);
|
|
68343
|
+
return -1;
|
|
68344
|
+
}
|
|
68345
|
+
return 0;
|
|
68295
68346
|
}
|
|
68296
68347
|
/************************************************************
|
|
68297
68348
|
* Command to remote service
|
|
@@ -68564,6 +68615,7 @@ function ac_mt_command_answer$1(gobj, event, kw, src) {
|
|
|
68564
68615
|
case "delete-node":
|
|
68565
68616
|
case "link-nodes":
|
|
68566
68617
|
case "unlink-nodes":
|
|
68618
|
+
if (result < 0 && command === "update-node") graphs_write_refused(gobj, kw_get_str(gobj, kw_command, "topic_name", "", 0), kw_get_dict(gobj, kw_command, "record", {}, 0));
|
|
68567
68619
|
if (result >= 0 && kw_get_str(gobj, kw_command, "topic_name", "", 0) !== "__graphs__") gobj_publish_event(gobj, "EV_RECORD_WRITTEN", {
|
|
68568
68620
|
treedb_name: kw_get_str(gobj, kw_command, "treedb_name", "", 0),
|
|
68569
68621
|
topic_name: kw_get_str(gobj, kw_command, "topic_name", "", 0),
|
|
@@ -68807,12 +68859,40 @@ function ac_create_node(gobj, event, kw, src) {
|
|
|
68807
68859
|
* Send to backend
|
|
68808
68860
|
********************************************/
|
|
68809
68861
|
function ac_update_node(gobj, event, kw, src) {
|
|
68810
|
-
let
|
|
68811
|
-
if (refuse_if_readonly$1(gobj, event)) return -1;
|
|
68812
|
-
let treedb_name = priv.treedb_name;
|
|
68862
|
+
let treedb_name = gobj.priv.treedb_name;
|
|
68813
68863
|
let topic_name = kw.topic_name;
|
|
68814
68864
|
let record = kw.record;
|
|
68815
|
-
|
|
68865
|
+
let options = kw.options || {};
|
|
68866
|
+
if (refuse_if_readonly$1(gobj, event)) {
|
|
68867
|
+
graphs_write_refused(gobj, topic_name, record);
|
|
68868
|
+
return -1;
|
|
68869
|
+
}
|
|
68870
|
+
if (topic_name === "__graphs__" && !is_connected(gobj)) {
|
|
68871
|
+
log_warning(`${gobj_short_name(gobj)}: no session, the arrangement was not sent`);
|
|
68872
|
+
graphs_write_refused(gobj, topic_name, record);
|
|
68873
|
+
return -1;
|
|
68874
|
+
}
|
|
68875
|
+
let ret = treedb_update_node(gobj, treedb_name, topic_name, record, options);
|
|
68876
|
+
if (ret < 0) graphs_write_refused(gobj, topic_name, record);
|
|
68877
|
+
return ret;
|
|
68878
|
+
}
|
|
68879
|
+
/************************************************************
|
|
68880
|
+
* A write of `__graphs__` did not land. The engine
|
|
68881
|
+
* (C_G6_NODES_TREE) took it for granted when it left -- nothing
|
|
68882
|
+
* answers it when it lands -- so it is told, and its next Save
|
|
68883
|
+
* writes the topic again. Other topics are the operator's data:
|
|
68884
|
+
* the answer's error says what happened to them.
|
|
68885
|
+
************************************************************/
|
|
68886
|
+
function graphs_write_refused(gobj, topic_name, record) {
|
|
68887
|
+
let priv = gobj.priv;
|
|
68888
|
+
if (topic_name !== "__graphs__") return;
|
|
68889
|
+
let topic = record && typeof record === "object" ? record.topic || record.id : "";
|
|
68890
|
+
if (!topic) {
|
|
68891
|
+
log_error(`${gobj_short_name(gobj)}: a refused __graphs__ write names no topic`);
|
|
68892
|
+
return;
|
|
68893
|
+
}
|
|
68894
|
+
if (!priv.gobj_nodes_tree) return;
|
|
68895
|
+
gobj_send_event(priv.gobj_nodes_tree, "EV_GRAPHS_WRITE_REFUSED", { topic }, gobj);
|
|
68816
68896
|
}
|
|
68817
68897
|
/********************************************
|
|
68818
68898
|
* Message from G6_nodes_tree
|
|
@@ -70468,9 +70548,8 @@ function register_c_yui_treedb_schema() {
|
|
|
70468
70548
|
* it, and that mark lived in the memory of the session only:
|
|
70469
70549
|
* a reload of the page, a reconnect or a refresh of the model
|
|
70470
70550
|
* lost the chip, the banner and the export warning while
|
|
70471
|
-
* __system__ still differed from the file in use
|
|
70472
|
-
*
|
|
70473
|
-
* C_TREEDB's `saved-schema` (`draft_changed`, by treedb) and
|
|
70551
|
+
* __system__ still differed from the file in use. The host
|
|
70552
|
+
* reads that difference from C_TREEDB's `saved-schema` (`draft_changed`, by treedb) and
|
|
70474
70553
|
* hands it here; the editor applies it to its model, in place
|
|
70475
70554
|
* of what the host said before.
|
|
70476
70555
|
*
|
|
@@ -72138,11 +72217,10 @@ function write_options(op) {
|
|
|
72138
72217
|
* AN EDIT IS A DRAFT. A write here moves no version and reaches no
|
|
72139
72218
|
* treedb: the host SAVES it (C_TREEDB's save-schema raises the
|
|
72140
72219
|
* topic_version of what changed and the schema_version, once) and
|
|
72141
|
-
* APPLIES it (apply-schema + a restart of the owning yuno).
|
|
72142
|
-
*
|
|
72143
|
-
*
|
|
72144
|
-
*
|
|
72145
|
-
* wrote and has not saved (EV_REFRESH forgets it: the view's own
|
|
72220
|
+
* APPLIES it (apply-schema + a restart of the owning yuno). If a
|
|
72221
|
+
* write here raised both versions, an edit half made would already
|
|
72222
|
+
* be the schema of the next start. The topic list marks what this
|
|
72223
|
+
* session wrote and has not saved (EV_REFRESH forgets it: the view's own
|
|
72146
72224
|
* Refresh button sends it, and a host may after a save -- the
|
|
72147
72225
|
* agent console's does not) and what the host says is not saved
|
|
72148
72226
|
* (EV_DRAFTS, replaced whole each time it is sent).
|
|
@@ -72208,6 +72286,7 @@ var HOOK_TOPICS = "topics";
|
|
|
72208
72286
|
var HOOK_COLS = "cols";
|
|
72209
72287
|
var DIAGRAM_SEG = "diagram";
|
|
72210
72288
|
var PURPOSE = "schema_editor";
|
|
72289
|
+
var DIALOGS_THAT_READ_NOTHING = ["SCHEMA_EXPORT_DIALOG", "SCHEMA_REPORT_DIALOG"];
|
|
72211
72290
|
/***************************************************************
|
|
72212
72291
|
* Attrs
|
|
72213
72292
|
***************************************************************/
|
|
@@ -72240,6 +72319,7 @@ var PRIVATE_DATA$1 = {
|
|
|
72240
72319
|
diagram_gobj: null,
|
|
72241
72320
|
dialog: null,
|
|
72242
72321
|
dialog_gen: 0,
|
|
72322
|
+
dialog_kind: "",
|
|
72243
72323
|
save_queue: null,
|
|
72244
72324
|
save_return: "",
|
|
72245
72325
|
save_wrote: false,
|
|
@@ -72408,9 +72488,9 @@ function refuse_if_readonly(gobj, event) {
|
|
|
72408
72488
|
* dumped by the machine trace).
|
|
72409
72489
|
*
|
|
72410
72490
|
* Refused, and said. A column form sends every field it shows, so
|
|
72411
|
-
* its Save after a reload wrote the OLD record over the newer one
|
|
72412
|
-
*
|
|
72413
|
-
*
|
|
72491
|
+
* its Save after a reload wrote the OLD record over the newer one;
|
|
72492
|
+
* a form whose column the reload removed answered "names no column"
|
|
72493
|
+
* for ever. end_load()
|
|
72414
72494
|
* closes such a dialog when the load lands; this is the same rule
|
|
72415
72495
|
* for whatever arrives anyway -- a stale screen, a confirmation
|
|
72416
72496
|
* that was up, a keyboard.
|
|
@@ -72430,8 +72510,7 @@ function built_on_a_replaced_model(gobj, event, kw) {
|
|
|
72430
72510
|
* the model shown is kept, and it may be older than the store.
|
|
72431
72511
|
* The session is up, so no reconnect will ask for it again -- it
|
|
72432
72512
|
* was owed for as long as the session lasted, and a form opened
|
|
72433
|
-
* on that model wrote every field of it over the newer record
|
|
72434
|
-
* (fifth independent review; A3 of the fourth, by another path).
|
|
72513
|
+
* on that model wrote every field of it over the newer record.
|
|
72435
72514
|
*
|
|
72436
72515
|
* So the operator's NEXT action asks it. An edit -- a form, a
|
|
72437
72516
|
* write, a confirmation, what reads the model whole (check,
|
|
@@ -72481,7 +72560,7 @@ function reload_after_move(gobj) {
|
|
|
72481
72560
|
* none of the actions of a screen, so the screen it replaces goes
|
|
72482
72561
|
* and the toolbar stops answering: left up, a click on a card, on
|
|
72483
72562
|
* Back or on the drawing answered "Event NOT DEFINED in state
|
|
72484
|
-
* ST_LOADING" and was lost
|
|
72563
|
+
* ST_LOADING" and was lost. A dialog
|
|
72485
72564
|
* left open is answered in ST_LOADING instead (ac_wait_for_the_load),
|
|
72486
72565
|
* and a load that LANDS closes it (end_load()): it was built on the
|
|
72487
72566
|
* model the load replaced, and its Save sends every field it shows.
|
|
@@ -73701,6 +73780,7 @@ function close_dialog(gobj) {
|
|
|
73701
73780
|
if (!priv.dialog) return;
|
|
73702
73781
|
let dialog = priv.dialog;
|
|
73703
73782
|
priv.dialog = null;
|
|
73783
|
+
priv.dialog_kind = "";
|
|
73704
73784
|
priv.export_view = null;
|
|
73705
73785
|
try {
|
|
73706
73786
|
dialog.close();
|
|
@@ -73712,6 +73792,7 @@ function open_dialog(gobj, $content, title, logical, title_prefix) {
|
|
|
73712
73792
|
let priv = gobj.priv;
|
|
73713
73793
|
close_dialog(gobj);
|
|
73714
73794
|
priv.dialog_gen = priv.model_gen;
|
|
73795
|
+
priv.dialog_kind = logical;
|
|
73715
73796
|
priv.dialog = yui_shell_show_modal(yui_shell_of(gobj), $content, {
|
|
73716
73797
|
dialog: true,
|
|
73717
73798
|
title,
|
|
@@ -73720,6 +73801,7 @@ function open_dialog(gobj, $content, title, logical, title_prefix) {
|
|
|
73720
73801
|
t,
|
|
73721
73802
|
on_close: () => {
|
|
73722
73803
|
priv.dialog = null;
|
|
73804
|
+
priv.dialog_kind = "";
|
|
73723
73805
|
priv.export_view = null;
|
|
73724
73806
|
}
|
|
73725
73807
|
});
|
|
@@ -74914,11 +74996,11 @@ function transport_in_session(gobj) {
|
|
|
74914
74996
|
* The state is part of the question, and that is only true
|
|
74915
74997
|
* because NOTHING moves the editor out of ST_LOADING or ST_SAVING
|
|
74916
74998
|
* but the end of what is in flight: a position the host sends
|
|
74917
|
-
* meanwhile waits in `pending_seg` (ac_show()).
|
|
74918
|
-
*
|
|
74919
|
-
*
|
|
74920
|
-
*
|
|
74921
|
-
*
|
|
74999
|
+
* meanwhile waits in `pending_seg` (ac_show()). If EV_SHOW moved a
|
|
75000
|
+
* RELOAD out of ST_LOADING, every answer of it would be "for a load
|
|
75001
|
+
* that is over": the records it had emptied would stay empty, and
|
|
75002
|
+
* the next write would patch them into a model with no treedb at
|
|
75003
|
+
* all.
|
|
74922
75004
|
***************************************************************/
|
|
74923
75005
|
function is_current_load(gobj, md) {
|
|
74924
75006
|
return gobj_current_state(gobj) === "ST_LOADING" && kw_get_int(gobj, md, "round", 0, 0) === gobj.priv.load_round;
|
|
@@ -75124,10 +75206,59 @@ function position_seg(gobj) {
|
|
|
75124
75206
|
* ...and the same in reverse. A tail naming a treedb or a topic
|
|
75125
75207
|
* the store does not have lands one level up rather than on an
|
|
75126
75208
|
* empty screen: a shared link outlives the schema it points at.
|
|
75209
|
+
*
|
|
75210
|
+
* Every position the HOST sends comes through here, at once
|
|
75211
|
+
* (ac_show()) or when what was in flight ends (end_load(),
|
|
75212
|
+
* end_writes()). A move to another position closes the dialog of
|
|
75213
|
+
* the screen the editor left (close_dialog_left_behind()).
|
|
75127
75214
|
***************************************************************/
|
|
75128
75215
|
function apply_seg(gobj, seg) {
|
|
75216
|
+
let before = position_seg(gobj);
|
|
75129
75217
|
let pos = seg_position(seg);
|
|
75130
|
-
|
|
75218
|
+
let ret = go(gobj, pos.treedb_id, pos.topic_name, pos.diagram, false);
|
|
75219
|
+
if (position_seg(gobj) !== before) close_dialog_left_behind(gobj);
|
|
75220
|
+
return ret;
|
|
75221
|
+
}
|
|
75222
|
+
/***************************************************************
|
|
75223
|
+
* The host moved the editor while a dialog was up. C_YUI_SHELL
|
|
75224
|
+
* keeps the overlays open on a move that changes only the subpath
|
|
75225
|
+
* (a url typed in, a link), so the dialog outlives its screen.
|
|
75226
|
+
*
|
|
75227
|
+
* A form, the import and the orphans send events that only the
|
|
75228
|
+
* screen they were opened from declares, and they name their
|
|
75229
|
+
* topic under the treedb open at the time. Left up on another
|
|
75230
|
+
* screen, their Save answered "Event NOT DEFINED" and the edit was
|
|
75231
|
+
* lost with no word. So the dialog is closed and the operator told.
|
|
75232
|
+
* The import plan goes with its dialog: it was computed for the
|
|
75233
|
+
* treedb the editor left.
|
|
75234
|
+
*
|
|
75235
|
+
* The export and the check stay: they show the texts they were
|
|
75236
|
+
* opened with, and what they send is legal in every state.
|
|
75237
|
+
***************************************************************/
|
|
75238
|
+
function close_dialog_left_behind(gobj) {
|
|
75239
|
+
let priv = gobj.priv;
|
|
75240
|
+
if (!priv.dialog || DIALOGS_THAT_READ_NOTHING.includes(priv.dialog_kind)) return;
|
|
75241
|
+
log_warning(`${gobj_short_name(gobj)}: the host moved the view while the dialog ${priv.dialog_kind} was open: closed`);
|
|
75242
|
+
close_dialog(gobj);
|
|
75243
|
+
forget_import_plan(gobj);
|
|
75244
|
+
yui_shell_show_error(yui_shell_of(gobj), "the view moved: open the dialog again", { t });
|
|
75245
|
+
}
|
|
75246
|
+
/***************************************************************
|
|
75247
|
+
* A confirmation answered on another screen than the one it was
|
|
75248
|
+
* asked from. A confirmation is a shell modal, so a move sent by
|
|
75249
|
+
* the host does not close it. It names its topic and column, and
|
|
75250
|
+
* the actions look them up under the treedb open NOW: a Yes after
|
|
75251
|
+
* a move to another treedb deleted the topic or column of the same
|
|
75252
|
+
* name THERE.
|
|
75253
|
+
*
|
|
75254
|
+
* Refused, and said. A kw with no `seg` stamp is not a
|
|
75255
|
+
* confirmation's and is not asked.
|
|
75256
|
+
***************************************************************/
|
|
75257
|
+
function asked_on_another_screen(gobj, event, kw) {
|
|
75258
|
+
if (!kw || kw.seg === void 0 || kw.seg === position_seg(gobj)) return false;
|
|
75259
|
+
log_warning(`${gobj_short_name(gobj)}: ${event} refused, it was asked on '${kw.seg}' and the view is on '${position_seg(gobj)}'`);
|
|
75260
|
+
yui_shell_show_error(yui_shell_of(gobj), "the view moved: open the dialog again", { t });
|
|
75261
|
+
return true;
|
|
75131
75262
|
}
|
|
75132
75263
|
function seg_position(seg) {
|
|
75133
75264
|
let parts = String(seg || "").split("/").filter((x) => x.length > 0);
|
|
@@ -75303,8 +75434,7 @@ function late_write_done(gobj, command, topic_name, data) {
|
|
|
75303
75434
|
* The fkey is read with parse_fkey_ref(), because the store answers
|
|
75304
75435
|
* in list_dict -- `[{topic_name, id, hook_name}]` -- and not in the
|
|
75305
75436
|
* `topics^<topic id>^cols` strings this view writes. Split as a
|
|
75306
|
-
* string, every production answer marked nothing
|
|
75307
|
-
* review, probe C).
|
|
75437
|
+
* string, every production answer marked nothing.
|
|
75308
75438
|
***************************************************************/
|
|
75309
75439
|
function mark_written_record(gobj, topic_name, record) {
|
|
75310
75440
|
let priv = gobj.priv;
|
|
@@ -75361,7 +75491,7 @@ function ac_hide(gobj, event, kw, src) {
|
|
|
75361
75491
|
*
|
|
75362
75492
|
* Nothing else ends a load or a write the drop cut: their answers
|
|
75363
75493
|
* will never come, and waiting in ST_LOADING skipped the reload
|
|
75364
|
-
* itself
|
|
75494
|
+
* itself.
|
|
75365
75495
|
***************************************************************/
|
|
75366
75496
|
function ac_transport_state(gobj, event, kw, src) {
|
|
75367
75497
|
let priv = gobj.priv;
|
|
@@ -75400,12 +75530,11 @@ function ac_refresh$1(gobj, event, kw, src) {
|
|
|
75400
75530
|
* a model the answers in the air are about to replace.
|
|
75401
75531
|
*
|
|
75402
75532
|
* Refused, and SAID. Undeclared, it answered "Event NOT DEFINED
|
|
75403
|
-
* in state ST_LOADING" and the edit was gone with no word
|
|
75404
|
-
* independent review).
|
|
75533
|
+
* in state ST_LOADING" and the edit was gone with no word.
|
|
75405
75534
|
*
|
|
75406
75535
|
* And NOT "try again": the same Save, once the load was in, sent
|
|
75407
75536
|
* the form built on the old model -- every field of the old record
|
|
75408
|
-
* over the newer one
|
|
75537
|
+
* over the newer one. The load that
|
|
75409
75538
|
* lands closes such a dialog (end_load()); one that fails leaves it
|
|
75410
75539
|
* up, on the model it was built on.
|
|
75411
75540
|
***************************************************************/
|
|
@@ -75419,8 +75548,7 @@ function ac_wait_for_the_load(gobj, event, kw, src) {
|
|
|
75419
75548
|
* reload landed on zero treedbs while it was up) or ST_IDLE (no
|
|
75420
75549
|
* model). A confirmation is a shell modal, not this view's dialog,
|
|
75421
75550
|
* so the load that lands does not close it, and its Yes arrives
|
|
75422
|
-
* anyway. Undeclared, it answered "Event NOT DEFINED"
|
|
75423
|
-
* independent review).
|
|
75551
|
+
* anyway. Undeclared, it answered "Event NOT DEFINED".
|
|
75424
75552
|
*
|
|
75425
75553
|
* Refused with the stamp's own words: whatever it was decided on
|
|
75426
75554
|
* is not on screen any more.
|
|
@@ -75436,13 +75564,12 @@ function ac_confirmed_on_nothing(gobj, event, kw, src) {
|
|
|
75436
75564
|
* topics hold a draft in __system__ that is not saved (C_TREEDB's
|
|
75437
75565
|
* saved-schema, `draft_changed`). The mark of a write lived in this
|
|
75438
75566
|
* session's memory only, so a reload of the page, a reconnect or a
|
|
75439
|
-
* refresh showed no draft while __system__ still differed
|
|
75440
|
-
* the 2026-09-22 review).
|
|
75567
|
+
* refresh showed no draft while __system__ still differed.
|
|
75441
75568
|
*
|
|
75442
75569
|
* REPLACES what the host said before -- the host is the truth after
|
|
75443
75570
|
* a reload, and a Save is exactly the host saying "none any more".
|
|
75444
75571
|
* It only ever added, and a topic stayed a draft after the Save that
|
|
75445
|
-
* published it
|
|
75572
|
+
* published it. What this session wrote
|
|
75446
75573
|
* stays marked: it is kept apart (see topic_is_draft()).
|
|
75447
75574
|
***************************************************************/
|
|
75448
75575
|
function ac_drafts(gobj, event, kw, src) {
|
|
@@ -75499,7 +75626,10 @@ function ac_show_orphans(gobj, event, kw, src) {
|
|
|
75499
75626
|
* to feed.
|
|
75500
75627
|
***************************************************************/
|
|
75501
75628
|
function confirm_then(gobj, message, detail, kw) {
|
|
75502
|
-
kw = Object.assign({
|
|
75629
|
+
kw = Object.assign({
|
|
75630
|
+
model_gen: gobj.priv.model_gen,
|
|
75631
|
+
seg: position_seg(gobj)
|
|
75632
|
+
}, kw);
|
|
75503
75633
|
yui_shell_confirm_danger(yui_shell_of(gobj), message, {
|
|
75504
75634
|
t,
|
|
75505
75635
|
detail,
|
|
@@ -75885,6 +76015,7 @@ function ac_confirmed(gobj, event, kw, src) {
|
|
|
75885
76015
|
if (refuse_if_readonly(gobj, event)) return -1;
|
|
75886
76016
|
if (reload_first(gobj, event)) return -1;
|
|
75887
76017
|
if (built_on_a_replaced_model(gobj, event, kw)) return -1;
|
|
76018
|
+
if (asked_on_another_screen(gobj, event, kw)) return -1;
|
|
75888
76019
|
if (kw.what === "import") return run_import(gobj);
|
|
75889
76020
|
if (kw.what === "topic") {
|
|
75890
76021
|
let topic = find_topic(priv.model, priv.treedb_id, kw.topic);
|
package/package.json
CHANGED
package/src/c_g6_nodes_tree.js
CHANGED
|
@@ -94,6 +94,7 @@ import {
|
|
|
94
94
|
|
|
95
95
|
import {
|
|
96
96
|
apply_graphs_echo,
|
|
97
|
+
forget_refused_graphs_write,
|
|
97
98
|
plan_graph_saves,
|
|
98
99
|
topic_arrangement_changed,
|
|
99
100
|
} from "./graph_save_plan.js";
|
|
@@ -3275,12 +3276,12 @@ function save_topic_graph_properties(gobj, topic_name)
|
|
|
3275
3276
|
* the publish and as a copy, because the object below travels by
|
|
3276
3277
|
* reference and goes on being arranged after the write.
|
|
3277
3278
|
*
|
|
3278
|
-
* Nothing answers an `EV_UPDATE_NODE` of `__graphs__`
|
|
3279
|
-
* writes that topic itself and is deliberately
|
|
3280
|
-
* (see the EV_RECORD_WRITTEN of
|
|
3281
|
-
* the write taken for granted.
|
|
3282
|
-
*
|
|
3283
|
-
* the next
|
|
3279
|
+
* Nothing answers an `EV_UPDATE_NODE` of `__graphs__` when it
|
|
3280
|
+
* lands -- the view writes that topic itself and is deliberately
|
|
3281
|
+
* not told about it (see the EV_RECORD_WRITTEN of
|
|
3282
|
+
* C_YUI_TREEDB_GRAPH) -- so this is the write taken for granted.
|
|
3283
|
+
* The host says when one does NOT land (EV_GRAPHS_WRITE_REFUSED),
|
|
3284
|
+
* and the next Save writes the topic again. */
|
|
3284
3285
|
priv._saved_graph_properties[topic_name] = json_deep_copy(properties);
|
|
3285
3286
|
|
|
3286
3287
|
let kw_update = {
|
|
@@ -10503,6 +10504,34 @@ function ac_save_graph(gobj, event, kw, src)
|
|
|
10503
10504
|
return 0;
|
|
10504
10505
|
}
|
|
10505
10506
|
|
|
10507
|
+
/************************************************************
|
|
10508
|
+
* The host says a write of `__graphs__` did not land: the
|
|
10509
|
+
* backend refused it, the transport refused it on the way out,
|
|
10510
|
+
* or there was no session to send it on. kw: {topic}
|
|
10511
|
+
*
|
|
10512
|
+
* save_topic_graph_properties() recorded it as saved before it
|
|
10513
|
+
* left. Forgotten now, and the Save is lit again: the next Save
|
|
10514
|
+
* writes the topic again. Before, the view believed the backend
|
|
10515
|
+
* held the arrangement, and the next Save had nothing to write.
|
|
10516
|
+
************************************************************/
|
|
10517
|
+
function ac_graphs_write_refused(gobj, event, kw, src)
|
|
10518
|
+
{
|
|
10519
|
+
let priv = gobj.priv;
|
|
10520
|
+
let topic_name = kw && kw.topic;
|
|
10521
|
+
|
|
10522
|
+
if(!topic_name) {
|
|
10523
|
+
log_error(`${gobj_short_name(gobj)}: ${event} names no topic`);
|
|
10524
|
+
return -1;
|
|
10525
|
+
}
|
|
10526
|
+
log_warning(`${gobj_short_name(gobj)}: the arrangement of '${topic_name}' ` +
|
|
10527
|
+
`was not saved: the next Save writes it again`);
|
|
10528
|
+
forget_refused_graphs_write(priv._saved_graph_properties, topic_name);
|
|
10529
|
+
if(priv.edit_mode) {
|
|
10530
|
+
mark_graph_dirty(gobj);
|
|
10531
|
+
}
|
|
10532
|
+
return 0;
|
|
10533
|
+
}
|
|
10534
|
+
|
|
10506
10535
|
/************************************************************
|
|
10507
10536
|
* Node created, from subscription
|
|
10508
10537
|
************************************************************/
|
|
@@ -10582,8 +10611,8 @@ function ac_node_updated(gobj, event, kw, src)
|
|
|
10582
10611
|
priv.__graphs__.push(node);
|
|
10583
10612
|
}
|
|
10584
10613
|
/* Only THIS record's topic: a rebuild of every topic took their
|
|
10585
|
-
* saved copies from the live objects
|
|
10586
|
-
*
|
|
10614
|
+
* saved copies from the live objects.
|
|
10615
|
+
* build_graph_properties() is for the load. */
|
|
10587
10616
|
apply_graphs_echo(
|
|
10588
10617
|
priv._graph_properties, priv._saved_graph_properties, priv.__graphs__, node
|
|
10589
10618
|
);
|
|
@@ -10637,7 +10666,7 @@ function ac_node_updated(gobj, event, kw, src)
|
|
|
10637
10666
|
update_local_node(gobj, topic_name, node);
|
|
10638
10667
|
/* `priv.graph`: this read an undeclared `graph`, the ReferenceError
|
|
10639
10668
|
* fell into the catch, and a card on screen kept its old record after
|
|
10640
|
-
* every UPDATED
|
|
10669
|
+
* every UPDATED. The catch is for G6,
|
|
10641
10670
|
* which throws on an id it does not hold -- a folded card. */
|
|
10642
10671
|
let on_screen = false;
|
|
10643
10672
|
try {
|
|
@@ -11778,8 +11807,8 @@ function ac_confirmed(gobj, event, kw, src)
|
|
|
11778
11807
|
}
|
|
11779
11808
|
if(missing.length) {
|
|
11780
11809
|
/* Gone while the question was open (another writer deleted
|
|
11781
|
-
* them): said, to the log and to the person
|
|
11782
|
-
*
|
|
11810
|
+
* them): said, to the log and to the person; the rest go
|
|
11811
|
+
* on. */
|
|
11783
11812
|
log_error(`${gobj_short_name(gobj)}: ${event}: cards gone while ` +
|
|
11784
11813
|
`confirming the delete, not deleted: ${missing.join(", ")}`);
|
|
11785
11814
|
yui_shell_show_error(yui_shell_of(gobj), "some records were gone before the delete", {t: t});
|
|
@@ -12022,6 +12051,7 @@ function create_gclass(gclass_name)
|
|
|
12022
12051
|
["EV_NODE_CREATED", ac_node_created, null],
|
|
12023
12052
|
["EV_NODE_UPDATED", ac_node_updated, null],
|
|
12024
12053
|
["EV_NODE_DELETED", ac_node_deleted, null],
|
|
12054
|
+
["EV_GRAPHS_WRITE_REFUSED", ac_graphs_write_refused, null],
|
|
12025
12055
|
|
|
12026
12056
|
/*--- Graph interaction events ---*/
|
|
12027
12057
|
["EV_NODE_CLICK", ac_node_click, null],
|
|
@@ -12091,6 +12121,7 @@ function create_gclass(gclass_name)
|
|
|
12091
12121
|
["EV_NODE_CREATED", 0],
|
|
12092
12122
|
["EV_NODE_UPDATED", 0],
|
|
12093
12123
|
["EV_NODE_DELETED", 0],
|
|
12124
|
+
["EV_GRAPHS_WRITE_REFUSED", 0],
|
|
12094
12125
|
|
|
12095
12126
|
/*--- Graph interaction (internal) ---*/
|
|
12096
12127
|
["EV_NODE_CLICK", 0],
|