@yuneta/gobj-ui 7.25.16 → 7.25.17
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 +47 -0
- package/dist/gobj-ui.cjs.js +52 -25
- package/dist/gobj-ui.es.js +52 -25
- package/package.json +2 -2
- package/src/c_yui_schema_editor.js +41 -18
- package/src/c_yui_treedb_graph.js +22 -6
- package/src/schema_editor_reload.wiring.test.js +161 -0
- package/src/treedb_graph_writes.wiring.test.js +8 -1
package/README.md
CHANGED
|
@@ -1824,6 +1824,20 @@ gobj_send_event(engine, "EV_GRAPHS_WRITE_REFUSED", {topic: "users"}, host); //
|
|
|
1824
1824
|
gobj_send_event(engine, "EV_SAVE_GRAPH", {}, engine); // writes users; Save dark
|
|
1825
1825
|
```
|
|
1826
1826
|
|
|
1827
|
+
**The refusal reaches the engine through the real transports** (since
|
|
1828
|
+
`7.25.17`). The answer of a command carries back only the request's
|
|
1829
|
+
`__md_command__`, as its `command_stack` frame -- `C_IEVENT_CLI` and gui_agent's
|
|
1830
|
+
`C_AGENT_TREEDB_LINK` both do, and neither echoes the request's `record`. The
|
|
1831
|
+
host read the topic from that `record`, found none, logged *"a refused
|
|
1832
|
+
__graphs__ write names no topic"* and never told the engine: the 7.25.15 fix
|
|
1833
|
+
worked only in a test whose fake transport echoed the whole request. The host
|
|
1834
|
+
now puts the topic in the echo it asks for:
|
|
1835
|
+
|
|
1836
|
+
```js
|
|
1837
|
+
kw.__md_command__ = {topic_name: "__graphs__", graph_topic: "users"};
|
|
1838
|
+
// the answer: __md_iev__.command_stack[0].kw === that echo, and nothing else
|
|
1839
|
+
```
|
|
1840
|
+
|
|
1827
1841
|
**Every saved look has a way back, in the context menu** (since `7.23.134`,
|
|
1828
1842
|
replacing `reset sizes` / `reset topic sizes`). In edition, the node, the port
|
|
1829
1843
|
and the edge menus each offer three resets — this one, its kind (`reset topic
|
|
@@ -2259,6 +2273,39 @@ else.
|
|
|
2259
2273
|
gobj_send_event(editor, "EV_REFRESH", {}, host); // logged, waits
|
|
2260
2274
|
// ... both deletes answered -> ST_LOADING -> the model is read again
|
|
2261
2275
|
```
|
|
2276
|
+
- **A write in flight takes the body out of the keyboard's reach too**
|
|
2277
|
+
(7.25.17). `ST_SAVING` keeps the screen under it and marks the body busy.
|
|
2278
|
+
The busy class only stopped the pointer (`pointer-events: none`); the
|
|
2279
|
+
shell's focus trap put the focus back on the row control that had it, and
|
|
2280
|
+
Enter or Delete there sent `EV_DELETE_COLUMN` or `EV_SELECT_TOPIC`, which
|
|
2281
|
+
`ST_SAVING` does not declare (*"Event NOT DEFINED"*). The busy body is now
|
|
2282
|
+
also `inert`. `ST_LOADING` needs nothing: its body is emptied.
|
|
2283
|
+
|
|
2284
|
+
```js
|
|
2285
|
+
// in ST_SAVING
|
|
2286
|
+
$container.querySelector(".SCHEMA_BODY").hasAttribute("inert"); // true
|
|
2287
|
+
```
|
|
2288
|
+
- **A write marks the topic of its RECORD, not the topic on screen**
|
|
2289
|
+
(7.25.17). What "its version still has to move" is asked about is the set of
|
|
2290
|
+
topics this session wrote (the draft chip, the export warning,
|
|
2291
|
+
`validate_schema()`'s `written_topics`). A column write marked the topic on
|
|
2292
|
+
screen, so an import from the topics screen (no topic on it) marked nothing,
|
|
2293
|
+
and an import that added `roles` from the screen of `users` marked `users`.
|
|
2294
|
+
The mark is read from the record the store answered (a new topic has its id
|
|
2295
|
+
only there), then from the record queued (a column names its topic in its
|
|
2296
|
+
fkey), and only then from the screen.
|
|
2297
|
+
|
|
2298
|
+
```js
|
|
2299
|
+
// import adding topic `roles`, run from db/users, every write answered
|
|
2300
|
+
editor.priv.written; // {"db.roles": true} (was {"db.users": true})
|
|
2301
|
+
```
|
|
2302
|
+
- **The reason a load failed is a key** (7.25.17). The notice's detail was
|
|
2303
|
+
the text of `t()` taken when the load failed (`cannot reach the treedb`,
|
|
2304
|
+
`cannot load the schemas`) or the backend's words, shown as plain text: it
|
|
2305
|
+
did not change language, and with no comment it repeated the notice's own
|
|
2306
|
+
title. It is now kept as a key, written with `data-i18n` (the backend's
|
|
2307
|
+
words translate to themselves when no locale has them), and left out when
|
|
2308
|
+
it is the title.
|
|
2262
2309
|
- **The loading screen is drawn** (7.25.8): the body is cleared, the drawing
|
|
2263
2310
|
destroyed and every toolbar button disabled, as in `ST_SAVING`, because
|
|
2264
2311
|
`ST_LOADING` declares none of a screen's actions. A **dialog** left open is
|
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -68378,6 +68378,7 @@ function treedb_update_node(gobj, treedb_name, topic_name, record, options) {
|
|
|
68378
68378
|
options: options || {}
|
|
68379
68379
|
};
|
|
68380
68380
|
kw.__md_command__ = { topic_name };
|
|
68381
|
+
if (topic_name === "__graphs__") kw.__md_command__.graph_topic = graph_topic_of(record);
|
|
68381
68382
|
let ret = (0, _yuneta_gobj_js.gobj_command)(priv.gobj_remote_yuno, command, kw, gobj);
|
|
68382
68383
|
if (ret) {
|
|
68383
68384
|
(0, _yuneta_gobj_js.log_error)(ret);
|
|
@@ -68656,7 +68657,7 @@ function ac_mt_command_answer$1(gobj, event, kw, src) {
|
|
|
68656
68657
|
case "delete-node":
|
|
68657
68658
|
case "link-nodes":
|
|
68658
68659
|
case "unlink-nodes":
|
|
68659
|
-
if (result < 0 && command === "update-node") graphs_write_refused(gobj, (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "topic_name", "", 0), (0, _yuneta_gobj_js.
|
|
68660
|
+
if (result < 0 && command === "update-node") graphs_write_refused(gobj, (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "topic_name", "", 0), (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "graph_topic", "", 0));
|
|
68660
68661
|
if (result >= 0 && (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "topic_name", "", 0) !== "__graphs__") (0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_RECORD_WRITTEN", {
|
|
68661
68662
|
treedb_name: (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "treedb_name", "", 0),
|
|
68662
68663
|
topic_name: (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "topic_name", "", 0),
|
|
@@ -68905,29 +68906,35 @@ function ac_update_node(gobj, event, kw, src) {
|
|
|
68905
68906
|
let record = kw.record;
|
|
68906
68907
|
let options = kw.options || {};
|
|
68907
68908
|
if (refuse_if_readonly$1(gobj, event)) {
|
|
68908
|
-
graphs_write_refused(gobj, topic_name, record);
|
|
68909
|
+
graphs_write_refused(gobj, topic_name, graph_topic_of(record));
|
|
68909
68910
|
return -1;
|
|
68910
68911
|
}
|
|
68911
68912
|
if (topic_name === "__graphs__" && !is_connected(gobj)) {
|
|
68912
68913
|
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no session, the arrangement was not sent`);
|
|
68913
|
-
graphs_write_refused(gobj, topic_name, record);
|
|
68914
|
+
graphs_write_refused(gobj, topic_name, graph_topic_of(record));
|
|
68914
68915
|
return -1;
|
|
68915
68916
|
}
|
|
68916
68917
|
let ret = treedb_update_node(gobj, treedb_name, topic_name, record, options);
|
|
68917
|
-
if (ret < 0) graphs_write_refused(gobj, topic_name, record);
|
|
68918
|
+
if (ret < 0) graphs_write_refused(gobj, topic_name, graph_topic_of(record));
|
|
68918
68919
|
return ret;
|
|
68919
68920
|
}
|
|
68920
68921
|
/************************************************************
|
|
68922
|
+
* The topic a `__graphs__` record arranges.
|
|
68923
|
+
************************************************************/
|
|
68924
|
+
function graph_topic_of(record) {
|
|
68925
|
+
if (!record || typeof record !== "object") return "";
|
|
68926
|
+
return record.topic || record.id || "";
|
|
68927
|
+
}
|
|
68928
|
+
/************************************************************
|
|
68921
68929
|
* A write of `__graphs__` did not land. The engine
|
|
68922
68930
|
* (C_G6_NODES_TREE) took it for granted when it left -- nothing
|
|
68923
68931
|
* answers it when it lands -- so it is told, and its next Save
|
|
68924
68932
|
* writes the topic again. Other topics are the operator's data:
|
|
68925
68933
|
* the answer's error says what happened to them.
|
|
68926
68934
|
************************************************************/
|
|
68927
|
-
function graphs_write_refused(gobj, topic_name,
|
|
68935
|
+
function graphs_write_refused(gobj, topic_name, topic) {
|
|
68928
68936
|
let priv = gobj.priv;
|
|
68929
68937
|
if (topic_name !== "__graphs__") return;
|
|
68930
|
-
let topic = record && typeof record === "object" ? record.topic || record.id : "";
|
|
68931
68938
|
if (!topic) {
|
|
68932
68939
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: a refused __graphs__ write names no topic`);
|
|
68933
68940
|
return;
|
|
@@ -72486,11 +72493,18 @@ function el_attrs(attrs) {
|
|
|
72486
72493
|
return attrs;
|
|
72487
72494
|
}
|
|
72488
72495
|
/***************************************************************
|
|
72489
|
-
* The body stops answering while a write is in flight.
|
|
72496
|
+
* The body stops answering while a write is in flight. For the
|
|
72497
|
+
* keyboard too: `pointer-events` stops the mouse alone, and the
|
|
72498
|
+
* shell's focus trap puts the focus back on the row control that
|
|
72499
|
+
* had it, where Enter or Delete sent an action ST_SAVING does
|
|
72500
|
+
* not declare. `inert` takes the whole body out of reach.
|
|
72490
72501
|
***************************************************************/
|
|
72491
72502
|
function set_busy(gobj, busy) {
|
|
72492
72503
|
let $body = $of(gobj, ".SCHEMA_BODY");
|
|
72493
|
-
if ($body)
|
|
72504
|
+
if ($body) {
|
|
72505
|
+
$body.classList.toggle("SCHEMA_BUSY", !!busy);
|
|
72506
|
+
$body.toggleAttribute("inert", !!busy);
|
|
72507
|
+
}
|
|
72494
72508
|
}
|
|
72495
72509
|
/***************************************************************
|
|
72496
72510
|
* Shorthands for the three panes of the frame.
|
|
@@ -72706,7 +72720,7 @@ function request_model(gobj, keep_written) {
|
|
|
72706
72720
|
priv.records_before = null;
|
|
72707
72721
|
priv.load_round++;
|
|
72708
72722
|
priv.reload_on_open = true;
|
|
72709
|
-
priv.load_error =
|
|
72723
|
+
priv.load_error = "cannot reach the treedb";
|
|
72710
72724
|
if (priv.model) yui_shell_show_error(yui_shell_of(gobj), "cannot reach the treedb", { t: i18next.t });
|
|
72711
72725
|
end_load(gobj);
|
|
72712
72726
|
return -1;
|
|
@@ -72917,10 +72931,13 @@ function show_notice(gobj, key, detail) {
|
|
|
72917
72931
|
},
|
|
72918
72932
|
(0, i18next.t)(key)
|
|
72919
72933
|
]));
|
|
72920
|
-
if (detail) $notice.appendChild((0, _yuneta_gobj_js.createElement2)([
|
|
72934
|
+
if (detail && detail !== key) $notice.appendChild((0, _yuneta_gobj_js.createElement2)([
|
|
72921
72935
|
"span",
|
|
72922
|
-
{
|
|
72923
|
-
|
|
72936
|
+
{
|
|
72937
|
+
class: "SCHEMA_NOTICE_DETAIL yui-text-quiet ml-2",
|
|
72938
|
+
i18n: `${detail}`
|
|
72939
|
+
},
|
|
72940
|
+
(0, i18next.t)(`${detail}`)
|
|
72924
72941
|
]));
|
|
72925
72942
|
}
|
|
72926
72943
|
/***************************************************************
|
|
@@ -75475,7 +75492,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
75475
75492
|
return 0;
|
|
75476
75493
|
}
|
|
75477
75494
|
priv.pending--;
|
|
75478
|
-
if (result < 0) priv.load_error = comment ||
|
|
75495
|
+
if (result < 0) priv.load_error = comment || "cannot load the schemas";
|
|
75479
75496
|
else if (priv.records && Array.isArray(priv.records[topic_name])) priv.records[topic_name] = Array.isArray(data) ? data : [];
|
|
75480
75497
|
if (priv.pending > 0) return 0;
|
|
75481
75498
|
if (priv.load_error) {
|
|
@@ -75511,9 +75528,10 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
75511
75528
|
}
|
|
75512
75529
|
if (result < 0) return end_writes(gobj, comment || (0, i18next.t)("the treedb refused the write"));
|
|
75513
75530
|
priv.save_wrote = true;
|
|
75531
|
+
let record = null;
|
|
75514
75532
|
if (command === "delete-node") forget_record(gobj, topic_name, (0, _yuneta_gobj_js.kw_get_str)(gobj, md, "record_id", "", 0));
|
|
75515
75533
|
else {
|
|
75516
|
-
|
|
75534
|
+
record = (0, _yuneta_gobj_js.is_object)(data) ? data : Array.isArray(data) && (0, _yuneta_gobj_js.is_object)(data[0]) ? data[0] : null;
|
|
75517
75535
|
if (record) patch_record(gobj, topic_name, record);
|
|
75518
75536
|
else {
|
|
75519
75537
|
let not_sent = priv.save_queue.length - 1;
|
|
@@ -75521,7 +75539,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
75521
75539
|
if (not_sent > 0) yui_shell_show_error(yui_shell_of(gobj), "the treedb did not describe a write back: the writes after it were not sent", { t: i18next.t });
|
|
75522
75540
|
if (topic_name === T_TOPICS || topic_name === T_COLS) {
|
|
75523
75541
|
let write = priv.save_queue[0];
|
|
75524
|
-
mark_written(gobj, topic_name, write ? write.record : null);
|
|
75542
|
+
mark_written(gobj, topic_name, null, write ? write.record : null);
|
|
75525
75543
|
}
|
|
75526
75544
|
priv.reload_after_write = false;
|
|
75527
75545
|
priv.save_queue = [];
|
|
@@ -75536,7 +75554,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
75536
75554
|
}
|
|
75537
75555
|
if (topic_name === T_TOPICS || topic_name === T_COLS) {
|
|
75538
75556
|
let write = priv.save_queue[0];
|
|
75539
|
-
mark_written(gobj, topic_name, write ? write.record : null);
|
|
75557
|
+
mark_written(gobj, topic_name, record, write ? write.record : null);
|
|
75540
75558
|
}
|
|
75541
75559
|
priv.save_queue.shift();
|
|
75542
75560
|
return run_next_write(gobj);
|
|
@@ -75593,25 +75611,34 @@ function late_write_done(gobj, command, topic_name, data) {
|
|
|
75593
75611
|
***************************************************************/
|
|
75594
75612
|
function mark_written_record(gobj, topic_name, record) {
|
|
75595
75613
|
let priv = gobj.priv;
|
|
75596
|
-
|
|
75614
|
+
let marked = 0;
|
|
75615
|
+
if (!record) return 0;
|
|
75597
75616
|
if (topic_name === T_TOPICS && typeof record.id === "string" && record.id) {
|
|
75598
75617
|
priv.written[record.id] = true;
|
|
75599
|
-
return;
|
|
75618
|
+
return 1;
|
|
75619
|
+
}
|
|
75620
|
+
if (topic_name !== T_COLS) return 0;
|
|
75621
|
+
for (let ref of parse_fkey_ref(record.topics)) {
|
|
75622
|
+
priv.written[ref.id] = true;
|
|
75623
|
+
marked++;
|
|
75600
75624
|
}
|
|
75601
|
-
|
|
75602
|
-
for (let ref of parse_fkey_ref(record.topics)) priv.written[ref.id] = true;
|
|
75625
|
+
return marked;
|
|
75603
75626
|
}
|
|
75604
75627
|
/***************************************************************
|
|
75605
75628
|
* Remember which topic this write belongs to, which is what
|
|
75606
75629
|
* "its version still has to move" is asked about.
|
|
75630
|
+
*
|
|
75631
|
+
* Asked of the RECORD first: the one the store answered (a new
|
|
75632
|
+
* topic has its id only there), then the one queued (a column
|
|
75633
|
+
* names its topic in its fkey). The screen is the last resort,
|
|
75634
|
+
* and a poor one: an import writes topics the operator is not
|
|
75635
|
+
* on, and from the topics screen there is no topic on it at all.
|
|
75607
75636
|
***************************************************************/
|
|
75608
|
-
function mark_written(gobj, topic_name,
|
|
75637
|
+
function mark_written(gobj, topic_name, answered, queued) {
|
|
75609
75638
|
let priv = gobj.priv;
|
|
75639
|
+
if (mark_written_record(gobj, topic_name, answered) > 0) return;
|
|
75640
|
+
if (mark_written_record(gobj, topic_name, queued) > 0) return;
|
|
75610
75641
|
let topic = current_topic(gobj);
|
|
75611
|
-
if (topic_name === T_TOPICS && record && record.id) {
|
|
75612
|
-
priv.written[record.id] = true;
|
|
75613
|
-
return;
|
|
75614
|
-
}
|
|
75615
75642
|
if (topic) priv.written[topic.id] = true;
|
|
75616
75643
|
}
|
|
75617
75644
|
/***************************************************************
|
package/dist/gobj-ui.es.js
CHANGED
|
@@ -68373,6 +68373,7 @@ function treedb_update_node(gobj, treedb_name, topic_name, record, options) {
|
|
|
68373
68373
|
options: options || {}
|
|
68374
68374
|
};
|
|
68375
68375
|
kw.__md_command__ = { topic_name };
|
|
68376
|
+
if (topic_name === "__graphs__") kw.__md_command__.graph_topic = graph_topic_of(record);
|
|
68376
68377
|
let ret = gobj_command(priv.gobj_remote_yuno, command, kw, gobj);
|
|
68377
68378
|
if (ret) {
|
|
68378
68379
|
log_error(ret);
|
|
@@ -68651,7 +68652,7 @@ function ac_mt_command_answer$1(gobj, event, kw, src) {
|
|
|
68651
68652
|
case "delete-node":
|
|
68652
68653
|
case "link-nodes":
|
|
68653
68654
|
case "unlink-nodes":
|
|
68654
|
-
if (result < 0 && command === "update-node") graphs_write_refused(gobj, kw_get_str(gobj, kw_command, "topic_name", "", 0),
|
|
68655
|
+
if (result < 0 && command === "update-node") graphs_write_refused(gobj, kw_get_str(gobj, kw_command, "topic_name", "", 0), kw_get_str(gobj, kw_command, "graph_topic", "", 0));
|
|
68655
68656
|
if (result >= 0 && kw_get_str(gobj, kw_command, "topic_name", "", 0) !== "__graphs__") gobj_publish_event(gobj, "EV_RECORD_WRITTEN", {
|
|
68656
68657
|
treedb_name: kw_get_str(gobj, kw_command, "treedb_name", "", 0),
|
|
68657
68658
|
topic_name: kw_get_str(gobj, kw_command, "topic_name", "", 0),
|
|
@@ -68900,29 +68901,35 @@ function ac_update_node(gobj, event, kw, src) {
|
|
|
68900
68901
|
let record = kw.record;
|
|
68901
68902
|
let options = kw.options || {};
|
|
68902
68903
|
if (refuse_if_readonly$1(gobj, event)) {
|
|
68903
|
-
graphs_write_refused(gobj, topic_name, record);
|
|
68904
|
+
graphs_write_refused(gobj, topic_name, graph_topic_of(record));
|
|
68904
68905
|
return -1;
|
|
68905
68906
|
}
|
|
68906
68907
|
if (topic_name === "__graphs__" && !is_connected(gobj)) {
|
|
68907
68908
|
log_warning(`${gobj_short_name(gobj)}: no session, the arrangement was not sent`);
|
|
68908
|
-
graphs_write_refused(gobj, topic_name, record);
|
|
68909
|
+
graphs_write_refused(gobj, topic_name, graph_topic_of(record));
|
|
68909
68910
|
return -1;
|
|
68910
68911
|
}
|
|
68911
68912
|
let ret = treedb_update_node(gobj, treedb_name, topic_name, record, options);
|
|
68912
|
-
if (ret < 0) graphs_write_refused(gobj, topic_name, record);
|
|
68913
|
+
if (ret < 0) graphs_write_refused(gobj, topic_name, graph_topic_of(record));
|
|
68913
68914
|
return ret;
|
|
68914
68915
|
}
|
|
68915
68916
|
/************************************************************
|
|
68917
|
+
* The topic a `__graphs__` record arranges.
|
|
68918
|
+
************************************************************/
|
|
68919
|
+
function graph_topic_of(record) {
|
|
68920
|
+
if (!record || typeof record !== "object") return "";
|
|
68921
|
+
return record.topic || record.id || "";
|
|
68922
|
+
}
|
|
68923
|
+
/************************************************************
|
|
68916
68924
|
* A write of `__graphs__` did not land. The engine
|
|
68917
68925
|
* (C_G6_NODES_TREE) took it for granted when it left -- nothing
|
|
68918
68926
|
* answers it when it lands -- so it is told, and its next Save
|
|
68919
68927
|
* writes the topic again. Other topics are the operator's data:
|
|
68920
68928
|
* the answer's error says what happened to them.
|
|
68921
68929
|
************************************************************/
|
|
68922
|
-
function graphs_write_refused(gobj, topic_name,
|
|
68930
|
+
function graphs_write_refused(gobj, topic_name, topic) {
|
|
68923
68931
|
let priv = gobj.priv;
|
|
68924
68932
|
if (topic_name !== "__graphs__") return;
|
|
68925
|
-
let topic = record && typeof record === "object" ? record.topic || record.id : "";
|
|
68926
68933
|
if (!topic) {
|
|
68927
68934
|
log_error(`${gobj_short_name(gobj)}: a refused __graphs__ write names no topic`);
|
|
68928
68935
|
return;
|
|
@@ -72481,11 +72488,18 @@ function el_attrs(attrs) {
|
|
|
72481
72488
|
return attrs;
|
|
72482
72489
|
}
|
|
72483
72490
|
/***************************************************************
|
|
72484
|
-
* The body stops answering while a write is in flight.
|
|
72491
|
+
* The body stops answering while a write is in flight. For the
|
|
72492
|
+
* keyboard too: `pointer-events` stops the mouse alone, and the
|
|
72493
|
+
* shell's focus trap puts the focus back on the row control that
|
|
72494
|
+
* had it, where Enter or Delete sent an action ST_SAVING does
|
|
72495
|
+
* not declare. `inert` takes the whole body out of reach.
|
|
72485
72496
|
***************************************************************/
|
|
72486
72497
|
function set_busy(gobj, busy) {
|
|
72487
72498
|
let $body = $of(gobj, ".SCHEMA_BODY");
|
|
72488
|
-
if ($body)
|
|
72499
|
+
if ($body) {
|
|
72500
|
+
$body.classList.toggle("SCHEMA_BUSY", !!busy);
|
|
72501
|
+
$body.toggleAttribute("inert", !!busy);
|
|
72502
|
+
}
|
|
72489
72503
|
}
|
|
72490
72504
|
/***************************************************************
|
|
72491
72505
|
* Shorthands for the three panes of the frame.
|
|
@@ -72701,7 +72715,7 @@ function request_model(gobj, keep_written) {
|
|
|
72701
72715
|
priv.records_before = null;
|
|
72702
72716
|
priv.load_round++;
|
|
72703
72717
|
priv.reload_on_open = true;
|
|
72704
|
-
priv.load_error =
|
|
72718
|
+
priv.load_error = "cannot reach the treedb";
|
|
72705
72719
|
if (priv.model) yui_shell_show_error(yui_shell_of(gobj), "cannot reach the treedb", { t });
|
|
72706
72720
|
end_load(gobj);
|
|
72707
72721
|
return -1;
|
|
@@ -72912,10 +72926,13 @@ function show_notice(gobj, key, detail) {
|
|
|
72912
72926
|
},
|
|
72913
72927
|
t(key)
|
|
72914
72928
|
]));
|
|
72915
|
-
if (detail) $notice.appendChild(createElement2([
|
|
72929
|
+
if (detail && detail !== key) $notice.appendChild(createElement2([
|
|
72916
72930
|
"span",
|
|
72917
|
-
{
|
|
72918
|
-
|
|
72931
|
+
{
|
|
72932
|
+
class: "SCHEMA_NOTICE_DETAIL yui-text-quiet ml-2",
|
|
72933
|
+
i18n: `${detail}`
|
|
72934
|
+
},
|
|
72935
|
+
t(`${detail}`)
|
|
72919
72936
|
]));
|
|
72920
72937
|
}
|
|
72921
72938
|
/***************************************************************
|
|
@@ -75470,7 +75487,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
75470
75487
|
return 0;
|
|
75471
75488
|
}
|
|
75472
75489
|
priv.pending--;
|
|
75473
|
-
if (result < 0) priv.load_error = comment ||
|
|
75490
|
+
if (result < 0) priv.load_error = comment || "cannot load the schemas";
|
|
75474
75491
|
else if (priv.records && Array.isArray(priv.records[topic_name])) priv.records[topic_name] = Array.isArray(data) ? data : [];
|
|
75475
75492
|
if (priv.pending > 0) return 0;
|
|
75476
75493
|
if (priv.load_error) {
|
|
@@ -75506,9 +75523,10 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
75506
75523
|
}
|
|
75507
75524
|
if (result < 0) return end_writes(gobj, comment || t("the treedb refused the write"));
|
|
75508
75525
|
priv.save_wrote = true;
|
|
75526
|
+
let record = null;
|
|
75509
75527
|
if (command === "delete-node") forget_record(gobj, topic_name, kw_get_str(gobj, md, "record_id", "", 0));
|
|
75510
75528
|
else {
|
|
75511
|
-
|
|
75529
|
+
record = is_object(data) ? data : Array.isArray(data) && is_object(data[0]) ? data[0] : null;
|
|
75512
75530
|
if (record) patch_record(gobj, topic_name, record);
|
|
75513
75531
|
else {
|
|
75514
75532
|
let not_sent = priv.save_queue.length - 1;
|
|
@@ -75516,7 +75534,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
75516
75534
|
if (not_sent > 0) yui_shell_show_error(yui_shell_of(gobj), "the treedb did not describe a write back: the writes after it were not sent", { t });
|
|
75517
75535
|
if (topic_name === T_TOPICS || topic_name === T_COLS) {
|
|
75518
75536
|
let write = priv.save_queue[0];
|
|
75519
|
-
mark_written(gobj, topic_name, write ? write.record : null);
|
|
75537
|
+
mark_written(gobj, topic_name, null, write ? write.record : null);
|
|
75520
75538
|
}
|
|
75521
75539
|
priv.reload_after_write = false;
|
|
75522
75540
|
priv.save_queue = [];
|
|
@@ -75531,7 +75549,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
75531
75549
|
}
|
|
75532
75550
|
if (topic_name === T_TOPICS || topic_name === T_COLS) {
|
|
75533
75551
|
let write = priv.save_queue[0];
|
|
75534
|
-
mark_written(gobj, topic_name, write ? write.record : null);
|
|
75552
|
+
mark_written(gobj, topic_name, record, write ? write.record : null);
|
|
75535
75553
|
}
|
|
75536
75554
|
priv.save_queue.shift();
|
|
75537
75555
|
return run_next_write(gobj);
|
|
@@ -75588,25 +75606,34 @@ function late_write_done(gobj, command, topic_name, data) {
|
|
|
75588
75606
|
***************************************************************/
|
|
75589
75607
|
function mark_written_record(gobj, topic_name, record) {
|
|
75590
75608
|
let priv = gobj.priv;
|
|
75591
|
-
|
|
75609
|
+
let marked = 0;
|
|
75610
|
+
if (!record) return 0;
|
|
75592
75611
|
if (topic_name === T_TOPICS && typeof record.id === "string" && record.id) {
|
|
75593
75612
|
priv.written[record.id] = true;
|
|
75594
|
-
return;
|
|
75613
|
+
return 1;
|
|
75614
|
+
}
|
|
75615
|
+
if (topic_name !== T_COLS) return 0;
|
|
75616
|
+
for (let ref of parse_fkey_ref(record.topics)) {
|
|
75617
|
+
priv.written[ref.id] = true;
|
|
75618
|
+
marked++;
|
|
75595
75619
|
}
|
|
75596
|
-
|
|
75597
|
-
for (let ref of parse_fkey_ref(record.topics)) priv.written[ref.id] = true;
|
|
75620
|
+
return marked;
|
|
75598
75621
|
}
|
|
75599
75622
|
/***************************************************************
|
|
75600
75623
|
* Remember which topic this write belongs to, which is what
|
|
75601
75624
|
* "its version still has to move" is asked about.
|
|
75625
|
+
*
|
|
75626
|
+
* Asked of the RECORD first: the one the store answered (a new
|
|
75627
|
+
* topic has its id only there), then the one queued (a column
|
|
75628
|
+
* names its topic in its fkey). The screen is the last resort,
|
|
75629
|
+
* and a poor one: an import writes topics the operator is not
|
|
75630
|
+
* on, and from the topics screen there is no topic on it at all.
|
|
75602
75631
|
***************************************************************/
|
|
75603
|
-
function mark_written(gobj, topic_name,
|
|
75632
|
+
function mark_written(gobj, topic_name, answered, queued) {
|
|
75604
75633
|
let priv = gobj.priv;
|
|
75634
|
+
if (mark_written_record(gobj, topic_name, answered) > 0) return;
|
|
75635
|
+
if (mark_written_record(gobj, topic_name, queued) > 0) return;
|
|
75605
75636
|
let topic = current_topic(gobj);
|
|
75606
|
-
if (topic_name === T_TOPICS && record && record.id) {
|
|
75607
|
-
priv.written[record.id] = true;
|
|
75608
|
-
return;
|
|
75609
|
-
}
|
|
75610
75637
|
if (topic) priv.written[topic.id] = true;
|
|
75611
75638
|
}
|
|
75612
75639
|
/***************************************************************
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yuneta/gobj-ui",
|
|
3
|
-
"version": "7.25.
|
|
3
|
+
"version": "7.25.17",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/gobj-ui.cjs.js",
|
|
6
6
|
"module": "dist/gobj-ui.es.js",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@rollup/plugin-terser": "^1.0.0",
|
|
32
32
|
"@vitest/coverage-v8": "^4.1.10",
|
|
33
|
-
"@yuneta/gobj-js": "^7.25.
|
|
33
|
+
"@yuneta/gobj-js": "^7.25.3",
|
|
34
34
|
"vite": "^8.2.1",
|
|
35
35
|
"vitest": "^4.1.10"
|
|
36
36
|
},
|
|
@@ -403,7 +403,11 @@ function el_attrs(attrs)
|
|
|
403
403
|
}
|
|
404
404
|
|
|
405
405
|
/***************************************************************
|
|
406
|
-
* The body stops answering while a write is in flight.
|
|
406
|
+
* The body stops answering while a write is in flight. For the
|
|
407
|
+
* keyboard too: `pointer-events` stops the mouse alone, and the
|
|
408
|
+
* shell's focus trap puts the focus back on the row control that
|
|
409
|
+
* had it, where Enter or Delete sent an action ST_SAVING does
|
|
410
|
+
* not declare. `inert` takes the whole body out of reach.
|
|
407
411
|
***************************************************************/
|
|
408
412
|
function set_busy(gobj, busy)
|
|
409
413
|
{
|
|
@@ -411,6 +415,7 @@ function set_busy(gobj, busy)
|
|
|
411
415
|
|
|
412
416
|
if($body) {
|
|
413
417
|
$body.classList.toggle("SCHEMA_BUSY", !!busy);
|
|
418
|
+
$body.toggleAttribute("inert", !!busy);
|
|
414
419
|
}
|
|
415
420
|
}
|
|
416
421
|
|
|
@@ -707,7 +712,7 @@ function request_model(gobj, keep_written)
|
|
|
707
712
|
priv.records_before = null;
|
|
708
713
|
priv.load_round++;
|
|
709
714
|
priv.reload_on_open = true;
|
|
710
|
-
priv.load_error =
|
|
715
|
+
priv.load_error = "cannot reach the treedb"; /* a key: the notice translates it */
|
|
711
716
|
if(priv.model) {
|
|
712
717
|
yui_shell_show_error(yui_shell_of(gobj), "cannot reach the treedb", {t: t});
|
|
713
718
|
}
|
|
@@ -993,9 +998,14 @@ function show_notice(gobj, key, detail)
|
|
|
993
998
|
$notice.appendChild(createElement2(
|
|
994
999
|
["span", {class: "SCHEMA_NOTICE_TEXT", i18n: key}, t(key)]
|
|
995
1000
|
));
|
|
996
|
-
|
|
1001
|
+
/* The detail is a KEY too (ours, or the backend's words, which
|
|
1002
|
+
* translate to themselves when no locale has them), so a change
|
|
1003
|
+
* of language changes it with the rest. One that repeats the
|
|
1004
|
+
* title says nothing. */
|
|
1005
|
+
if(detail && detail !== key) {
|
|
997
1006
|
$notice.appendChild(createElement2(
|
|
998
|
-
["span", {class: "SCHEMA_NOTICE_DETAIL yui-text-quiet ml-2"
|
|
1007
|
+
["span", {class: "SCHEMA_NOTICE_DETAIL yui-text-quiet ml-2", i18n: `${detail}`},
|
|
1008
|
+
t(`${detail}`)]
|
|
999
1009
|
));
|
|
1000
1010
|
}
|
|
1001
1011
|
}
|
|
@@ -3350,7 +3360,7 @@ function ac_mt_command_answer(gobj, event, kw, src)
|
|
|
3350
3360
|
}
|
|
3351
3361
|
priv.pending--;
|
|
3352
3362
|
if(result < 0) {
|
|
3353
|
-
priv.load_error = comment ||
|
|
3363
|
+
priv.load_error = comment || "cannot load the schemas"; /* a key */
|
|
3354
3364
|
} else if(priv.records && Array.isArray(priv.records[topic_name])) {
|
|
3355
3365
|
priv.records[topic_name] = Array.isArray(data) ? data : [];
|
|
3356
3366
|
}
|
|
@@ -3427,10 +3437,11 @@ function ac_mt_command_answer(gobj, event, kw, src)
|
|
|
3427
3437
|
return end_writes(gobj, comment || t("the treedb refused the write"));
|
|
3428
3438
|
}
|
|
3429
3439
|
priv.save_wrote = true;
|
|
3440
|
+
let record = null;
|
|
3430
3441
|
if(command === "delete-node") {
|
|
3431
3442
|
forget_record(gobj, topic_name, kw_get_str(gobj, md, "record_id", "", 0));
|
|
3432
3443
|
} else {
|
|
3433
|
-
|
|
3444
|
+
record = is_object(data) ? data
|
|
3434
3445
|
: (Array.isArray(data) && is_object(data[0]) ? data[0] : null);
|
|
3435
3446
|
if(record) {
|
|
3436
3447
|
patch_record(gobj, topic_name, record);
|
|
@@ -3453,7 +3464,7 @@ function ac_mt_command_answer(gobj, event, kw, src)
|
|
|
3453
3464
|
}
|
|
3454
3465
|
if(topic_name === T_TOPICS || topic_name === T_COLS) {
|
|
3455
3466
|
let write = priv.save_queue[0];
|
|
3456
|
-
mark_written(gobj, topic_name, write ? write.record : null);
|
|
3467
|
+
mark_written(gobj, topic_name, null, write ? write.record : null);
|
|
3457
3468
|
}
|
|
3458
3469
|
priv.reload_after_write = false;
|
|
3459
3470
|
priv.save_queue = [];
|
|
@@ -3471,11 +3482,12 @@ function ac_mt_command_answer(gobj, event, kw, src)
|
|
|
3471
3482
|
}
|
|
3472
3483
|
}
|
|
3473
3484
|
if(topic_name === T_TOPICS || topic_name === T_COLS) {
|
|
3474
|
-
/* Which record it was
|
|
3475
|
-
* adapter echoes only what it was
|
|
3476
|
-
* record is not small enough to be
|
|
3485
|
+
/* Which record it was: the one the store answered, else the
|
|
3486
|
+
* one in the QUEUE -- an adapter echoes only what it was
|
|
3487
|
+
* asked to echo, and the record is not small enough to be
|
|
3488
|
+
* worth echoing. */
|
|
3477
3489
|
let write = priv.save_queue[0];
|
|
3478
|
-
mark_written(gobj, topic_name, write ? write.record : null);
|
|
3490
|
+
mark_written(gobj, topic_name, record, write ? write.record : null);
|
|
3479
3491
|
}
|
|
3480
3492
|
priv.save_queue.shift();
|
|
3481
3493
|
return run_next_write(gobj);
|
|
@@ -3544,35 +3556,46 @@ function late_write_done(gobj, command, topic_name, data)
|
|
|
3544
3556
|
function mark_written_record(gobj, topic_name, record)
|
|
3545
3557
|
{
|
|
3546
3558
|
let priv = gobj.priv;
|
|
3559
|
+
let marked = 0;
|
|
3547
3560
|
|
|
3548
3561
|
if(!record) {
|
|
3549
|
-
return;
|
|
3562
|
+
return 0;
|
|
3550
3563
|
}
|
|
3551
3564
|
if(topic_name === T_TOPICS && typeof record.id === "string" && record.id) {
|
|
3552
3565
|
priv.written[record.id] = true;
|
|
3553
|
-
return;
|
|
3566
|
+
return 1;
|
|
3554
3567
|
}
|
|
3555
3568
|
if(topic_name !== T_COLS) {
|
|
3556
|
-
return;
|
|
3569
|
+
return 0;
|
|
3557
3570
|
}
|
|
3558
3571
|
for(let ref of parse_fkey_ref(record.topics)) {
|
|
3559
3572
|
priv.written[ref.id] = true;
|
|
3573
|
+
marked++;
|
|
3560
3574
|
}
|
|
3575
|
+
return marked;
|
|
3561
3576
|
}
|
|
3562
3577
|
|
|
3563
3578
|
/***************************************************************
|
|
3564
3579
|
* Remember which topic this write belongs to, which is what
|
|
3565
3580
|
* "its version still has to move" is asked about.
|
|
3581
|
+
*
|
|
3582
|
+
* Asked of the RECORD first: the one the store answered (a new
|
|
3583
|
+
* topic has its id only there), then the one queued (a column
|
|
3584
|
+
* names its topic in its fkey). The screen is the last resort,
|
|
3585
|
+
* and a poor one: an import writes topics the operator is not
|
|
3586
|
+
* on, and from the topics screen there is no topic on it at all.
|
|
3566
3587
|
***************************************************************/
|
|
3567
|
-
function mark_written(gobj, topic_name,
|
|
3588
|
+
function mark_written(gobj, topic_name, answered, queued)
|
|
3568
3589
|
{
|
|
3569
3590
|
let priv = gobj.priv;
|
|
3570
|
-
let topic = current_topic(gobj);
|
|
3571
3591
|
|
|
3572
|
-
if(topic_name
|
|
3573
|
-
priv.written[record.id] = true;
|
|
3592
|
+
if(mark_written_record(gobj, topic_name, answered) > 0) {
|
|
3574
3593
|
return;
|
|
3575
3594
|
}
|
|
3595
|
+
if(mark_written_record(gobj, topic_name, queued) > 0) {
|
|
3596
|
+
return;
|
|
3597
|
+
}
|
|
3598
|
+
let topic = current_topic(gobj);
|
|
3576
3599
|
if(topic) {
|
|
3577
3600
|
priv.written[topic.id] = true;
|
|
3578
3601
|
}
|
|
@@ -1520,6 +1520,12 @@ function treedb_update_node(gobj, treedb_name, topic_name, record, options)
|
|
|
1520
1520
|
kw.__md_command__ = { // Data to be returned
|
|
1521
1521
|
topic_name: topic_name,
|
|
1522
1522
|
};
|
|
1523
|
+
/* The answer carries this echo and nothing else of the request: a
|
|
1524
|
+
* refused `__graphs__` write is told to the engine by the topic it
|
|
1525
|
+
* arranges, so that topic has to travel here. */
|
|
1526
|
+
if(topic_name === "__graphs__") {
|
|
1527
|
+
kw.__md_command__.graph_topic = graph_topic_of(record);
|
|
1528
|
+
}
|
|
1523
1529
|
|
|
1524
1530
|
let ret = gobj_command(priv.gobj_remote_yuno,
|
|
1525
1531
|
command,
|
|
@@ -2118,7 +2124,7 @@ function ac_mt_command_answer(gobj, event, kw, src)
|
|
|
2118
2124
|
if(result < 0 && command === "update-node") {
|
|
2119
2125
|
graphs_write_refused(gobj,
|
|
2120
2126
|
kw_get_str(gobj, kw_command, "topic_name", "", 0),
|
|
2121
|
-
|
|
2127
|
+
kw_get_str(gobj, kw_command, "graph_topic", "", 0));
|
|
2122
2128
|
}
|
|
2123
2129
|
if(result >= 0 &&
|
|
2124
2130
|
kw_get_str(gobj, kw_command, "topic_name", "", 0) !== "__graphs__") {
|
|
@@ -2486,7 +2492,7 @@ function ac_update_node(gobj, event, kw, src)
|
|
|
2486
2492
|
let options = kw.options || {};
|
|
2487
2493
|
|
|
2488
2494
|
if(refuse_if_readonly(gobj, event)) {
|
|
2489
|
-
graphs_write_refused(gobj, topic_name, record);
|
|
2495
|
+
graphs_write_refused(gobj, topic_name, graph_topic_of(record));
|
|
2490
2496
|
return -1;
|
|
2491
2497
|
}
|
|
2492
2498
|
|
|
@@ -2496,7 +2502,7 @@ function ac_update_node(gobj, event, kw, src)
|
|
|
2496
2502
|
if(topic_name === "__graphs__" && !is_connected(gobj)) {
|
|
2497
2503
|
log_warning(`${gobj_short_name(gobj)}: no session, the arrangement ` +
|
|
2498
2504
|
`was not sent`);
|
|
2499
|
-
graphs_write_refused(gobj, topic_name, record);
|
|
2505
|
+
graphs_write_refused(gobj, topic_name, graph_topic_of(record));
|
|
2500
2506
|
return -1;
|
|
2501
2507
|
}
|
|
2502
2508
|
|
|
@@ -2508,11 +2514,22 @@ function ac_update_node(gobj, event, kw, src)
|
|
|
2508
2514
|
options
|
|
2509
2515
|
);
|
|
2510
2516
|
if(ret < 0) {
|
|
2511
|
-
graphs_write_refused(gobj, topic_name, record);
|
|
2517
|
+
graphs_write_refused(gobj, topic_name, graph_topic_of(record));
|
|
2512
2518
|
}
|
|
2513
2519
|
return ret;
|
|
2514
2520
|
}
|
|
2515
2521
|
|
|
2522
|
+
/************************************************************
|
|
2523
|
+
* The topic a `__graphs__` record arranges.
|
|
2524
|
+
************************************************************/
|
|
2525
|
+
function graph_topic_of(record)
|
|
2526
|
+
{
|
|
2527
|
+
if(!record || typeof record !== "object") {
|
|
2528
|
+
return "";
|
|
2529
|
+
}
|
|
2530
|
+
return record.topic || record.id || "";
|
|
2531
|
+
}
|
|
2532
|
+
|
|
2516
2533
|
/************************************************************
|
|
2517
2534
|
* A write of `__graphs__` did not land. The engine
|
|
2518
2535
|
* (C_G6_NODES_TREE) took it for granted when it left -- nothing
|
|
@@ -2520,14 +2537,13 @@ function ac_update_node(gobj, event, kw, src)
|
|
|
2520
2537
|
* writes the topic again. Other topics are the operator's data:
|
|
2521
2538
|
* the answer's error says what happened to them.
|
|
2522
2539
|
************************************************************/
|
|
2523
|
-
function graphs_write_refused(gobj, topic_name,
|
|
2540
|
+
function graphs_write_refused(gobj, topic_name, topic)
|
|
2524
2541
|
{
|
|
2525
2542
|
let priv = gobj.priv;
|
|
2526
2543
|
|
|
2527
2544
|
if(topic_name !== "__graphs__") {
|
|
2528
2545
|
return;
|
|
2529
2546
|
}
|
|
2530
|
-
let topic = (record && typeof record === "object") ? (record.topic || record.id) : "";
|
|
2531
2547
|
if(!topic) {
|
|
2532
2548
|
log_error(`${gobj_short_name(gobj)}: a refused __graphs__ write names no topic`);
|
|
2533
2549
|
return;
|
|
@@ -1501,3 +1501,164 @@ describe("EV_REFRESH while a write is in flight", () => {
|
|
|
1501
1501
|
expect(not_defined()).toEqual([]);
|
|
1502
1502
|
});
|
|
1503
1503
|
});
|
|
1504
|
+
|
|
1505
|
+
describe("the body while a write is in flight", () => {
|
|
1506
|
+
|
|
1507
|
+
/* pointer-events stops the mouse and nothing else: the shell's
|
|
1508
|
+
* focus trap puts the focus back on the row control that had it,
|
|
1509
|
+
* and Delete or Enter there sent an action ST_SAVING does not
|
|
1510
|
+
* declare. `inert` takes the body out of the keyboard's reach too. */
|
|
1511
|
+
test("is inert, and answers again when the write ends", () => {
|
|
1512
|
+
const {editor, remote, host} = build("r16k1", "db/users");
|
|
1513
|
+
const $body = $in(editor, ".SCHEMA_BODY");
|
|
1514
|
+
expect($body.hasAttribute("inert")).toBe(false);
|
|
1515
|
+
|
|
1516
|
+
const write = start_a_write(editor, host, "name");
|
|
1517
|
+
expect($body.hasAttribute("inert")).toBe(true);
|
|
1518
|
+
|
|
1519
|
+
answer(editor, remote, write, 0, write.kw.record);
|
|
1520
|
+
expect(gobj_current_state(editor)).toBe("ST_COLUMNS");
|
|
1521
|
+
expect($in(editor, ".SCHEMA_BODY").hasAttribute("inert")).toBe(false);
|
|
1522
|
+
expect(errors()).toEqual([]);
|
|
1523
|
+
});
|
|
1524
|
+
|
|
1525
|
+
test("a drop that ends the write gives the body back too", () => {
|
|
1526
|
+
const {editor, remote, host} = build("r16k2", "db/users");
|
|
1527
|
+
start_a_write(editor, host, "name");
|
|
1528
|
+
drop(editor, remote, host);
|
|
1529
|
+
expect($in(editor, ".SCHEMA_BODY").hasAttribute("inert")).toBe(false);
|
|
1530
|
+
});
|
|
1531
|
+
});
|
|
1532
|
+
|
|
1533
|
+
describe("the writes of an import mark the topic they write", () => {
|
|
1534
|
+
|
|
1535
|
+
/* An import that adds a topic, `roles`. */
|
|
1536
|
+
const IMPORT = JSON.stringify({id: "db", topics: [
|
|
1537
|
+
{id: "users", pkey: "id", cols: [
|
|
1538
|
+
{id: "id", type: "string", flag: ["persistent", "required"]}
|
|
1539
|
+
]},
|
|
1540
|
+
{id: "roles", pkey: "id", cols: [
|
|
1541
|
+
{id: "id", type: "string", flag: ["persistent", "required"]}
|
|
1542
|
+
]}
|
|
1543
|
+
]});
|
|
1544
|
+
|
|
1545
|
+
/* The record as the store answers it: with the id it gave a new
|
|
1546
|
+
* one, and its fkeys in list_dict. */
|
|
1547
|
+
function as_the_store_answers(write)
|
|
1548
|
+
{
|
|
1549
|
+
const record = JSON.parse(JSON.stringify(write.kw.record));
|
|
1550
|
+
const to_dict = (refs) => refs.map((ref) => {
|
|
1551
|
+
const [topic_name, id, hook_name] = ref.split("^");
|
|
1552
|
+
return {topic_name, id, hook_name};
|
|
1553
|
+
});
|
|
1554
|
+
if(write.kw.topic_name === "topics") {
|
|
1555
|
+
record.id = record.id || `db.${record.value}`;
|
|
1556
|
+
record.treedbs = to_dict(record.treedbs || []);
|
|
1557
|
+
}
|
|
1558
|
+
if(write.kw.topic_name === "cols") {
|
|
1559
|
+
record.id = record.id || `${record.topics[0].split("^")[1]}.${record.value}`;
|
|
1560
|
+
record.topics = to_dict(record.topics || []);
|
|
1561
|
+
}
|
|
1562
|
+
return record;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
function run_the_import(editor, host)
|
|
1566
|
+
{
|
|
1567
|
+
gobj_send_event(editor, "EV_IMPORT", {}, host);
|
|
1568
|
+
gobj_send_event(editor, "EV_PREVIEW_IMPORT", {prune: false, text: IMPORT,
|
|
1569
|
+
model_gen: editor.priv.model_gen}, editor);
|
|
1570
|
+
expect(editor.priv.import_plan.writes.length).toBeGreaterThan(0);
|
|
1571
|
+
gobj_send_event(editor, "EV_APPLY_IMPORT", {model_gen: editor.priv.model_gen}, editor);
|
|
1572
|
+
expect(gobj_current_state(editor)).toBe("ST_SAVING");
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
function answer_every_write(editor, remote)
|
|
1576
|
+
{
|
|
1577
|
+
for(let i = 0; i < 10; i++) {
|
|
1578
|
+
const [write] = take("update-node");
|
|
1579
|
+
if(!write) {
|
|
1580
|
+
break;
|
|
1581
|
+
}
|
|
1582
|
+
answer(editor, remote, write, 0, as_the_store_answers(write));
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
test("from another topic's screen: the topic it wrote, not the one on screen", () => {
|
|
1587
|
+
const {editor, remote, host} = build("r16m1", "db/users");
|
|
1588
|
+
run_the_import(editor, host);
|
|
1589
|
+
answer_every_write(editor, remote);
|
|
1590
|
+
expect(gobj_current_state(editor)).toBe("ST_COLUMNS");
|
|
1591
|
+
expect(editor.priv.written).toEqual({"db.roles": true});
|
|
1592
|
+
expect(errors()).toEqual([]);
|
|
1593
|
+
});
|
|
1594
|
+
|
|
1595
|
+
test("from the topics screen, where no topic is on screen", () => {
|
|
1596
|
+
const {editor, remote, host} = build("r16m2", "db");
|
|
1597
|
+
run_the_import(editor, host);
|
|
1598
|
+
answer_every_write(editor, remote);
|
|
1599
|
+
expect(gobj_current_state(editor)).toBe("ST_TOPICS");
|
|
1600
|
+
expect(editor.priv.written).toEqual({"db.roles": true});
|
|
1601
|
+
expect(errors()).toEqual([]);
|
|
1602
|
+
});
|
|
1603
|
+
|
|
1604
|
+
test("a column answered with no record: the record it queued says the topic", () => {
|
|
1605
|
+
const {editor, remote, host} = build("r16m3", "db/users");
|
|
1606
|
+
run_the_import(editor, host);
|
|
1607
|
+
const [topic] = take("update-node");
|
|
1608
|
+
expect(topic.kw.topic_name).toBe("topics");
|
|
1609
|
+
answer(editor, remote, topic, 0, as_the_store_answers(topic));
|
|
1610
|
+
const [col] = take("update-node");
|
|
1611
|
+
expect(col.kw.topic_name).toBe("cols");
|
|
1612
|
+
answer(editor, remote, col, 0, null);
|
|
1613
|
+
expect(editor.priv.written).toEqual({"db.roles": true});
|
|
1614
|
+
});
|
|
1615
|
+
});
|
|
1616
|
+
|
|
1617
|
+
describe("the reason a load failed", () => {
|
|
1618
|
+
|
|
1619
|
+
test("is a key the notice translates, not a string frozen in one language", () => {
|
|
1620
|
+
const remote = gobj_create_service("r16e1_remote", "C_TEST_REMOTE", {}, yuno);
|
|
1621
|
+
gobj_change_state(remote, "ST_SESSION");
|
|
1622
|
+
const host = gobj_create("r16e1_host", "C_TEST_EDITOR_HOST", {}, yuno);
|
|
1623
|
+
const editor = gobj_create("r16e1_editor", "C_YUI_SCHEMA_EDITOR", {
|
|
1624
|
+
gobj_remote_yuno: remote, treedb_name: "treedb_system_schema"
|
|
1625
|
+
}, host);
|
|
1626
|
+
gobj_start(editor);
|
|
1627
|
+
for(const c of take("nodes")) {
|
|
1628
|
+
answer(editor, remote, c, -1, null, "");
|
|
1629
|
+
}
|
|
1630
|
+
expect(gobj_current_state(editor)).toBe("ST_IDLE");
|
|
1631
|
+
expect(editor.priv.load_error).toBe("cannot load the schemas");
|
|
1632
|
+
/* The notice already says it: no detail repeating the title. */
|
|
1633
|
+
expect($in(editor, ".SCHEMA_NOTICE_DETAIL")).toBe(null);
|
|
1634
|
+
});
|
|
1635
|
+
|
|
1636
|
+
test("the backend's own words travel as its key", () => {
|
|
1637
|
+
const remote = gobj_create_service("r16e2_remote", "C_TEST_REMOTE", {}, yuno);
|
|
1638
|
+
gobj_change_state(remote, "ST_SESSION");
|
|
1639
|
+
const host = gobj_create("r16e2_host", "C_TEST_EDITOR_HOST", {}, yuno);
|
|
1640
|
+
const editor = gobj_create("r16e2_editor", "C_YUI_SCHEMA_EDITOR", {
|
|
1641
|
+
gobj_remote_yuno: remote, treedb_name: "treedb_system_schema"
|
|
1642
|
+
}, host);
|
|
1643
|
+
gobj_start(editor);
|
|
1644
|
+
for(const c of take("nodes")) {
|
|
1645
|
+
answer(editor, remote, c, -1, null, "treedb not found");
|
|
1646
|
+
}
|
|
1647
|
+
const $detail = $in(editor, ".SCHEMA_NOTICE_DETAIL");
|
|
1648
|
+
expect($detail.getAttribute("data-i18n")).toBe("treedb not found");
|
|
1649
|
+
});
|
|
1650
|
+
|
|
1651
|
+
test("a load that cannot leave keeps its key", () => {
|
|
1652
|
+
const remote = gobj_create_service("r16e3_remote", "C_TEST_REMOTE", {}, yuno);
|
|
1653
|
+
const host = gobj_create("r16e3_host", "C_TEST_EDITOR_HOST", {}, yuno);
|
|
1654
|
+
const editor = gobj_create("r16e3_editor", "C_YUI_SCHEMA_EDITOR", {
|
|
1655
|
+
gobj_remote_yuno: remote, treedb_name: "treedb_system_schema"
|
|
1656
|
+
}, host);
|
|
1657
|
+
gobj_start(editor);
|
|
1658
|
+
gobj_change_state(remote, "ST_DISCONNECTED");
|
|
1659
|
+
gobj_send_event(editor, "EV_REFRESH", {}, host);
|
|
1660
|
+
expect(editor.priv.load_error).toBe("cannot reach the treedb");
|
|
1661
|
+
const $detail = $in(editor, ".SCHEMA_NOTICE_DETAIL");
|
|
1662
|
+
expect($detail.getAttribute("data-i18n")).toBe("cannot reach the treedb");
|
|
1663
|
+
});
|
|
1664
|
+
});
|
|
@@ -149,13 +149,19 @@ function save_arrangement(engine, topic)
|
|
|
149
149
|
});
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
/* The answer as the real transports build it: the command frame
|
|
153
|
+
* carries ONLY the request's `__md_command__` (C_IEVENT_CLI's
|
|
154
|
+
* mt_command, gui_agent's C_AGENT_TREEDB_LINK), never the request's
|
|
155
|
+
* own kw. Echoing the whole kw here once hid that the refusal read
|
|
156
|
+
* its topic from a `record` no real answer carries. */
|
|
152
157
|
function answer(host, remote, request, result, comment)
|
|
153
158
|
{
|
|
159
|
+
const md_command = request.kw.__md_command__ || {};
|
|
154
160
|
gobj_send_event(host, "EV_MT_COMMAND_ANSWER", {
|
|
155
161
|
result: result,
|
|
156
162
|
comment: comment || "",
|
|
157
163
|
data: null,
|
|
158
|
-
__md_iev__: {command_stack: [{command: request.command, kw:
|
|
164
|
+
__md_iev__: {command_stack: [{command: request.command, kw: md_command}]}
|
|
159
165
|
}, remote);
|
|
160
166
|
}
|
|
161
167
|
|
|
@@ -172,6 +178,7 @@ describe("a __graphs__ write that does not land is said to the engine", () => {
|
|
|
172
178
|
expect(commands.length).toBe(1);
|
|
173
179
|
answer(host, remote, commands[0], -1, "not authorized");
|
|
174
180
|
expect(refused()).toEqual(["yunos"]);
|
|
181
|
+
expect(logged.filter((l) => /names no topic/.test(l.msg))).toEqual([]);
|
|
175
182
|
});
|
|
176
183
|
|
|
177
184
|
test("landed: nothing is said", () => {
|