@yuneta/gobj-ui 7.25.14 → 7.25.16
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 +100 -4
- package/dist/gobj-ui.cjs.js +406 -94
- package/dist/gobj-ui.es.js +406 -94
- package/package.json +2 -2
- package/src/c_g6_nodes_tree.js +79 -15
- package/src/c_yui_schema_editor.js +343 -66
- 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_busy.test.js +1 -1
- 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/form_writes_in_flight.test.js +1 -1
- package/src/g6_graphs_write_owed.wiring.test.js +200 -0
- 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/host_drafts.test.js +2 -2
- package/src/schema_editor_drafts.wiring.test.js +2 -2
- package/src/schema_editor_reload.wiring.test.js +329 -49
- package/src/schema_editor_transport.wiring.test.js +2 -2
- package/src/schema_version_bump.test.js +1 -1
- package/src/shell_modals.js +31 -11
- package/src/shell_toast_once.test.js +73 -10
- package/src/table_cell_text.js +1 -1
- package/src/table_cell_text.test.js +1 -1
- package/src/treedb_graph_writes.wiring.test.js +208 -0
- package/src/treedb_topics_transport.wiring.test.js +2 -2
- package/src/yui_install.js +14 -3
- package/src/yui_install.test.js +23 -0
- package/src/yui_row_search.test.js +1 -1
- package/src/yui_table_select.test.js +1 -1
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -3038,9 +3038,8 @@ function maybe_apply_translator($node, opts) {
|
|
|
3038
3038
|
* it -- until every handle is closed or has timed out. Handed the
|
|
3039
3039
|
* first caller's handle and timer, a repeat asking `timeout: 0`
|
|
3040
3040
|
* was dismissed on the first one's timer, and closing one
|
|
3041
|
-
* caller's handle closed a toast another was still showing
|
|
3042
|
-
*
|
|
3043
|
-
* everybody.
|
|
3041
|
+
* caller's handle closed a toast another was still showing.
|
|
3042
|
+
* The operator's ✕ closes it for everybody.
|
|
3044
3043
|
***************************************************************/
|
|
3045
3044
|
function show_notification(shell, kind, message, opts) {
|
|
3046
3045
|
let $layer = notification_layer(shell);
|
|
@@ -3438,8 +3437,28 @@ function build_dialog(shell, message, buttons, opts) {
|
|
|
3438
3437
|
if ($primary) $primary.focus();
|
|
3439
3438
|
});
|
|
3440
3439
|
}
|
|
3440
|
+
/***************************************************************
|
|
3441
|
+
* The labels a confirmation shows when the caller names none.
|
|
3442
|
+
*
|
|
3443
|
+
* They are i18n KEYS, lower-case like every key: a button
|
|
3444
|
+
* translates its label with the app's t() -- its text, its title
|
|
3445
|
+
* and its aria-label. Until 7.25.16 they were "OK", "Yes", "No",
|
|
3446
|
+
* "Delete" and "Cancel", keys that no locale carries, so a dialog
|
|
3447
|
+
* that took the defaults read in English in every language.
|
|
3448
|
+
*
|
|
3449
|
+
* Written as `i18n:` entries so the validate-locales script of a
|
|
3450
|
+
* consumer finds them when it scans this module: an app that
|
|
3451
|
+
* mounts these dialogs must define the five keys.
|
|
3452
|
+
***************************************************************/
|
|
3453
|
+
var DEFAULT_LABEL = Object.freeze({
|
|
3454
|
+
ok: Object.freeze({ i18n: "ok" }),
|
|
3455
|
+
yes: Object.freeze({ i18n: "yes" }),
|
|
3456
|
+
no: Object.freeze({ i18n: "no" }),
|
|
3457
|
+
delete: Object.freeze({ i18n: "delete" }),
|
|
3458
|
+
cancel: Object.freeze({ i18n: "cancel" })
|
|
3459
|
+
});
|
|
3441
3460
|
function yui_shell_confirm_ok(shell, message, opts) {
|
|
3442
|
-
let label = opts && opts.ok_label ||
|
|
3461
|
+
let label = opts && opts.ok_label || DEFAULT_LABEL.ok.i18n;
|
|
3443
3462
|
if (!opts || !opts.type) opts = Object.assign({}, opts, { type: "success" });
|
|
3444
3463
|
return build_dialog(shell, message, [{
|
|
3445
3464
|
label,
|
|
@@ -3448,8 +3467,8 @@ function yui_shell_confirm_ok(shell, message, opts) {
|
|
|
3448
3467
|
}], opts).then(() => void 0);
|
|
3449
3468
|
}
|
|
3450
3469
|
function yui_shell_confirm_yesno(shell, message, opts) {
|
|
3451
|
-
let yes_label = opts && opts.yes_label ||
|
|
3452
|
-
let no_label = opts && opts.no_label ||
|
|
3470
|
+
let yes_label = opts && opts.yes_label || DEFAULT_LABEL.yes.i18n;
|
|
3471
|
+
let no_label = opts && opts.no_label || DEFAULT_LABEL.no.i18n;
|
|
3453
3472
|
return build_dialog(shell, message, [{
|
|
3454
3473
|
label: yes_label,
|
|
3455
3474
|
value: "yes",
|
|
@@ -3474,8 +3493,8 @@ function yui_shell_confirm_yesno(shell, message, opts) {
|
|
|
3474
3493
|
* pressed.
|
|
3475
3494
|
***************************************************************/
|
|
3476
3495
|
function yui_shell_confirm_danger(shell, message, opts) {
|
|
3477
|
-
let confirm_label = opts && opts.confirm_label ||
|
|
3478
|
-
let cancel_label = opts && opts.cancel_label ||
|
|
3496
|
+
let confirm_label = opts && opts.confirm_label || DEFAULT_LABEL.delete.i18n;
|
|
3497
|
+
let cancel_label = opts && opts.cancel_label || DEFAULT_LABEL.cancel.i18n;
|
|
3479
3498
|
if (!opts || !opts.type) opts = Object.assign({}, opts, { type: "danger" });
|
|
3480
3499
|
return build_dialog(shell, message, [{
|
|
3481
3500
|
label: confirm_label,
|
|
@@ -3487,9 +3506,9 @@ function yui_shell_confirm_danger(shell, message, opts) {
|
|
|
3487
3506
|
}], opts).then((v) => v === "confirm");
|
|
3488
3507
|
}
|
|
3489
3508
|
function yui_shell_confirm_yesnocancel(shell, message, opts) {
|
|
3490
|
-
let yes_label = opts && opts.yes_label ||
|
|
3491
|
-
let no_label = opts && opts.no_label ||
|
|
3492
|
-
let cancel_label = opts && opts.cancel_label ||
|
|
3509
|
+
let yes_label = opts && opts.yes_label || DEFAULT_LABEL.yes.i18n;
|
|
3510
|
+
let no_label = opts && opts.no_label || DEFAULT_LABEL.no.i18n;
|
|
3511
|
+
let cancel_label = opts && opts.cancel_label || DEFAULT_LABEL.cancel.i18n;
|
|
3493
3512
|
return build_dialog(shell, message, [
|
|
3494
3513
|
{
|
|
3495
3514
|
label: yes_label,
|
|
@@ -7425,7 +7444,7 @@ function json_diff_rows(doc_a, doc_b) {
|
|
|
7425
7444
|
* A Date -> the value of a `datetime-local` input, in local time,
|
|
7426
7445
|
* WITH seconds: the input is built with `step: 1`, which is what
|
|
7427
7446
|
* lets it hold them. Written as "YYYY-MM-DDTHH:mm" it lost them on
|
|
7428
|
-
* every save of any field
|
|
7447
|
+
* every save of any field.
|
|
7429
7448
|
************************************************************/
|
|
7430
7449
|
function date_to_datetime_local(value) {
|
|
7431
7450
|
if (!(value instanceof Date) || isNaN(value.getTime())) return "";
|
|
@@ -23130,8 +23149,7 @@ function yui_shell_show_route_map(shell, opts) {
|
|
|
23130
23149
|
* answers, so the host has to answer EVERY way a write ends --
|
|
23131
23150
|
* and the transport closing under a write in flight, or a
|
|
23132
23151
|
* command that never left because there was no session, are two
|
|
23133
|
-
* of them that nobody answered: the form stayed busy for ever
|
|
23134
|
-
* (N8 of the 2026-09-22 review).
|
|
23152
|
+
* of them that nobody answered: the form stayed busy for ever.
|
|
23135
23153
|
*
|
|
23136
23154
|
* A write is known by its TOPIC and its `form_write` serial,
|
|
23137
23155
|
* never by the serial alone: each topic has its own form, and
|
|
@@ -25682,8 +25700,8 @@ function ac_update_record(gobj, event, kw, src) {
|
|
|
25682
25700
|
/************************************************************
|
|
25683
25701
|
* A write sent with no session never leaves: C_IEVENT_CLI logs
|
|
25684
25702
|
* "Not in session" and answers null, as it does when the command
|
|
25685
|
-
* went -- so a form waiting for the answer waited for ever
|
|
25686
|
-
*
|
|
25703
|
+
* went -- so a form waiting for the answer waited for ever. Refused
|
|
25704
|
+
* before it is sent, aloud.
|
|
25687
25705
|
************************************************************/
|
|
25688
25706
|
function refuse_without_session(gobj, topic_name) {
|
|
25689
25707
|
if (is_connected$1(gobj)) return false;
|
|
@@ -26795,9 +26813,8 @@ function delete_impact(desc, records) {
|
|
|
26795
26813
|
* that back. So a second busy(true) while already busy must not
|
|
26796
26814
|
* run at all -- it read the buttons it had just disabled as
|
|
26797
26815
|
* "disabled on their own", and the busy(false) of a refused write
|
|
26798
|
-
* left Save and Cancel dead (
|
|
26799
|
-
*
|
|
26800
|
-
* the write). The caller owns `state` ({busy}) for the form's life.
|
|
26816
|
+
* left Save and Cancel dead (a record with a picked file went
|
|
26817
|
+
* busy for the read, then busy again for the write). The caller owns `state` ({busy}) for the form's life.
|
|
26801
26818
|
*
|
|
26802
26819
|
* Copyright (c) 2026, ArtGins.
|
|
26803
26820
|
* All Rights Reserved.
|
|
@@ -26835,7 +26852,7 @@ function set_toolbar_busy($container, state, busy) {
|
|
|
26835
26852
|
* (only its own `plaintext` formatter escapes), so a record's text
|
|
26836
26853
|
* returned as a string is parsed as markup: `a<b and c>d` showed
|
|
26837
26854
|
* as `ad`, and a field holding `<img src=x onerror=...>` ran it in
|
|
26838
|
-
* the operator's browser
|
|
26855
|
+
* the operator's browser. Record
|
|
26839
26856
|
* data goes in as a TEXT NODE, and a cell built around it as DOM,
|
|
26840
26857
|
* never as an HTML string with the data interpolated.
|
|
26841
26858
|
*
|
|
@@ -29597,7 +29614,7 @@ function ac_new_row(gobj, event, kw, src) {
|
|
|
29597
29614
|
* What crosses the confirmation is the rows' IDENTITY, never their
|
|
29598
29615
|
* position: the view applies EV_TREEDB_NODE_* of every writer while the
|
|
29599
29616
|
* dialog is open, and a position names whatever row sits there when the
|
|
29600
|
-
* person answers -- with force:true
|
|
29617
|
+
* person answers -- with force:true.
|
|
29601
29618
|
************************************************************/
|
|
29602
29619
|
function ac_delete_rows(gobj, event, kw, src) {
|
|
29603
29620
|
if (refuse_if_readonly$2(gobj, event)) return -1;
|
|
@@ -29808,8 +29825,8 @@ function ac_files_read(gobj, event, kw, src) {
|
|
|
29808
29825
|
* open and BUSY, and the serial it waits for is taken here.
|
|
29809
29826
|
*
|
|
29810
29827
|
* A refused write used to close the form all the same and throw
|
|
29811
|
-
* away what was typed, although the README said it stayed open
|
|
29812
|
-
*
|
|
29828
|
+
* away what was typed, although the README said it stayed open:
|
|
29829
|
+
* the close was posted with the
|
|
29813
29830
|
* publish, before the backend had answered anything.
|
|
29814
29831
|
************************************************************/
|
|
29815
29832
|
function wait_for_write_answer(gobj) {
|
|
@@ -30981,6 +30998,28 @@ function apply_graphs_echo(live, saved, records, rec) {
|
|
|
30981
30998
|
delete saved[rec.topic];
|
|
30982
30999
|
}
|
|
30983
31000
|
}
|
|
31001
|
+
/***************************************************************
|
|
31002
|
+
* A write of one topic's arrangement did NOT land: the backend
|
|
31003
|
+
* refused it, the transport refused it on the way out, or there
|
|
31004
|
+
* was no session to send it on.
|
|
31005
|
+
*
|
|
31006
|
+
* saved {topic_name: properties} what the backend has
|
|
31007
|
+
* topic_name the topic of the refused record
|
|
31008
|
+
*
|
|
31009
|
+
* The view records a write as saved BEFORE it leaves, because
|
|
31010
|
+
* nothing answers it when it lands. So a refused one left the view
|
|
31011
|
+
* believing the backend held an arrangement it does not, and the
|
|
31012
|
+
* next Save found nothing to write. What the backend holds for the
|
|
31013
|
+
* topic is not known any more, so it is forgotten: the next Save
|
|
31014
|
+
* writes the topic again (plan_graph_saves()).
|
|
31015
|
+
*
|
|
31016
|
+
* Returns TRUE if there was something to forget.
|
|
31017
|
+
***************************************************************/
|
|
31018
|
+
function forget_refused_graphs_write(saved, topic_name) {
|
|
31019
|
+
if (!(0, _yuneta_gobj_js.is_object)(saved) || !topic_name || !Object.prototype.hasOwnProperty.call(saved, topic_name)) return false;
|
|
31020
|
+
delete saved[topic_name];
|
|
31021
|
+
return true;
|
|
31022
|
+
}
|
|
30984
31023
|
//#endregion
|
|
30985
31024
|
//#region src/treedb_node_label.js
|
|
30986
31025
|
/***********************************************************************
|
|
@@ -59213,6 +59252,7 @@ var PRIVATE_DATA$4 = {
|
|
|
59213
59252
|
__graphs__: [],
|
|
59214
59253
|
_graph_properties: {},
|
|
59215
59254
|
_saved_graph_properties: {},
|
|
59255
|
+
_graphs_writes_owed: {},
|
|
59216
59256
|
yet_showed: false,
|
|
59217
59257
|
edit_mode: false,
|
|
59218
59258
|
operation_mode: null,
|
|
@@ -60908,6 +60948,7 @@ function save_topic_graph_properties(gobj, topic_name) {
|
|
|
60908
60948
|
if (!topic_arrangement_changed(properties, priv._saved_graph_properties[topic_name])) return;
|
|
60909
60949
|
properties.__origin__ = (0, _yuneta_gobj_js.gobj_read_str_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "node_uuid");
|
|
60910
60950
|
priv._saved_graph_properties[topic_name] = (0, _yuneta_gobj_js.json_deep_copy)(properties);
|
|
60951
|
+
delete priv._graphs_writes_owed[topic_name];
|
|
60911
60952
|
let kw_update = {
|
|
60912
60953
|
treedb_name: priv.treedb_name,
|
|
60913
60954
|
topic_name: "__graphs__",
|
|
@@ -60989,8 +61030,13 @@ function update_history_buttons(gobj) {
|
|
|
60989
61030
|
} else {
|
|
60990
61031
|
disableElements($container, ".EV_HISTORY_UNDO");
|
|
60991
61032
|
set_active_state($container, ".EV_HISTORY_UNDO", false);
|
|
60992
|
-
|
|
60993
|
-
|
|
61033
|
+
if (graphs_write_is_owed(gobj)) {
|
|
61034
|
+
enableElements($container, ".EV_SAVE_GRAPH");
|
|
61035
|
+
set_submit_state($container, ".EV_SAVE_GRAPH", true);
|
|
61036
|
+
} else {
|
|
61037
|
+
disableElements($container, ".EV_SAVE_GRAPH");
|
|
61038
|
+
set_submit_state($container, ".EV_SAVE_GRAPH", false);
|
|
61039
|
+
}
|
|
60994
61040
|
}
|
|
60995
61041
|
} else {
|
|
60996
61042
|
disableElements($container, ".EV_HISTORY_REDO");
|
|
@@ -61947,6 +61993,15 @@ function run_preview_undo(gobj, key) {
|
|
|
61947
61993
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: cannot undo the preview: ${e}`);
|
|
61948
61994
|
}
|
|
61949
61995
|
}
|
|
61996
|
+
/************************************************************
|
|
61997
|
+
* Is a `__graphs__` write owed? The host said one did not land
|
|
61998
|
+
* (EV_GRAPHS_WRITE_REFUSED), and no Save has written that topic
|
|
61999
|
+
* since. The Save button stays lit while it is: the history
|
|
62000
|
+
* knows nothing of it, so `canUndo()` alone would put it out.
|
|
62001
|
+
************************************************************/
|
|
62002
|
+
function graphs_write_is_owed(gobj) {
|
|
62003
|
+
return Object.keys(gobj.priv._graphs_writes_owed).length > 0;
|
|
62004
|
+
}
|
|
61950
62005
|
function mark_graph_dirty(gobj) {
|
|
61951
62006
|
let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
61952
62007
|
enableElements($container, ".EV_SAVE_GRAPH");
|
|
@@ -65687,6 +65742,7 @@ function ac_clear_data(gobj, event, kw, src) {
|
|
|
65687
65742
|
deselect_node(gobj);
|
|
65688
65743
|
hide_create_popover(gobj);
|
|
65689
65744
|
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "records", {});
|
|
65745
|
+
priv._graphs_writes_owed = {};
|
|
65690
65746
|
priv._nodes_total = 0;
|
|
65691
65747
|
priv._nodes_placed = 0;
|
|
65692
65748
|
priv._fold_model = null;
|
|
@@ -65779,15 +65835,36 @@ function ac_save_graph(gobj, event, kw, src) {
|
|
|
65779
65835
|
disableElements($container, ".EV_SAVE_GRAPH");
|
|
65780
65836
|
set_submit_state($container, ".EV_SAVE_GRAPH", false);
|
|
65781
65837
|
let history = graph_get_plugin(gobj, "history");
|
|
65782
|
-
if (history)
|
|
65783
|
-
history.clear();
|
|
65784
|
-
update_history_buttons(gobj);
|
|
65785
|
-
}
|
|
65838
|
+
if (history) history.clear();
|
|
65786
65839
|
save_geometry(gobj);
|
|
65840
|
+
update_history_buttons(gobj);
|
|
65787
65841
|
}
|
|
65788
65842
|
return 0;
|
|
65789
65843
|
}
|
|
65790
65844
|
/************************************************************
|
|
65845
|
+
* The host says a write of `__graphs__` did not land: the
|
|
65846
|
+
* backend refused it, the transport refused it on the way out,
|
|
65847
|
+
* or there was no session to send it on. kw: {topic}
|
|
65848
|
+
*
|
|
65849
|
+
* save_topic_graph_properties() recorded it as saved before it
|
|
65850
|
+
* left. Forgotten now, and the Save is lit again: the next Save
|
|
65851
|
+
* writes the topic again. Before, the view believed the backend
|
|
65852
|
+
* held the arrangement, and the next Save had nothing to write.
|
|
65853
|
+
************************************************************/
|
|
65854
|
+
function ac_graphs_write_refused(gobj, event, kw, src) {
|
|
65855
|
+
let priv = gobj.priv;
|
|
65856
|
+
let topic_name = kw && kw.topic;
|
|
65857
|
+
if (!topic_name) {
|
|
65858
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} names no topic`);
|
|
65859
|
+
return -1;
|
|
65860
|
+
}
|
|
65861
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: the arrangement of '${topic_name}' was not saved: the next Save writes it again`);
|
|
65862
|
+
forget_refused_graphs_write(priv._saved_graph_properties, topic_name);
|
|
65863
|
+
priv._graphs_writes_owed[topic_name] = true;
|
|
65864
|
+
if (priv.edit_mode) mark_graph_dirty(gobj);
|
|
65865
|
+
return 0;
|
|
65866
|
+
}
|
|
65867
|
+
/************************************************************
|
|
65791
65868
|
* Node created, from subscription
|
|
65792
65869
|
************************************************************/
|
|
65793
65870
|
function ac_node_created(gobj, event, kw, src) {
|
|
@@ -66855,6 +66932,11 @@ function create_gclass$4(gclass_name) {
|
|
|
66855
66932
|
ac_node_deleted,
|
|
66856
66933
|
null
|
|
66857
66934
|
],
|
|
66935
|
+
[
|
|
66936
|
+
"EV_GRAPHS_WRITE_REFUSED",
|
|
66937
|
+
ac_graphs_write_refused,
|
|
66938
|
+
null
|
|
66939
|
+
],
|
|
66858
66940
|
[
|
|
66859
66941
|
"EV_NODE_CLICK",
|
|
66860
66942
|
ac_node_click$2,
|
|
@@ -67108,6 +67190,7 @@ function create_gclass$4(gclass_name) {
|
|
|
67108
67190
|
["EV_NODE_CREATED", 0],
|
|
67109
67191
|
["EV_NODE_UPDATED", 0],
|
|
67110
67192
|
["EV_NODE_DELETED", 0],
|
|
67193
|
+
["EV_GRAPHS_WRITE_REFUSED", 0],
|
|
67111
67194
|
["EV_NODE_CLICK", 0],
|
|
67112
67195
|
["EV_EDGE_CLICK", 0],
|
|
67113
67196
|
["EV_NODE_CONTEXT_MENU", 0],
|
|
@@ -68284,7 +68367,7 @@ function treedb_update_node(gobj, treedb_name, topic_name, record, options) {
|
|
|
68284
68367
|
let priv = gobj.priv;
|
|
68285
68368
|
if (!priv.gobj_remote_yuno) {
|
|
68286
68369
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: No gobj_remote_yuno defined`);
|
|
68287
|
-
return;
|
|
68370
|
+
return -1;
|
|
68288
68371
|
}
|
|
68289
68372
|
let command = "update-node";
|
|
68290
68373
|
let kw = {
|
|
@@ -68296,7 +68379,11 @@ function treedb_update_node(gobj, treedb_name, topic_name, record, options) {
|
|
|
68296
68379
|
};
|
|
68297
68380
|
kw.__md_command__ = { topic_name };
|
|
68298
68381
|
let ret = (0, _yuneta_gobj_js.gobj_command)(priv.gobj_remote_yuno, command, kw, gobj);
|
|
68299
|
-
if (ret)
|
|
68382
|
+
if (ret) {
|
|
68383
|
+
(0, _yuneta_gobj_js.log_error)(ret);
|
|
68384
|
+
return -1;
|
|
68385
|
+
}
|
|
68386
|
+
return 0;
|
|
68300
68387
|
}
|
|
68301
68388
|
/************************************************************
|
|
68302
68389
|
* Command to remote service
|
|
@@ -68569,6 +68656,7 @@ function ac_mt_command_answer$1(gobj, event, kw, src) {
|
|
|
68569
68656
|
case "delete-node":
|
|
68570
68657
|
case "link-nodes":
|
|
68571
68658
|
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.kw_get_dict)(gobj, kw_command, "record", {}, 0));
|
|
68572
68660
|
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", {
|
|
68573
68661
|
treedb_name: (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "treedb_name", "", 0),
|
|
68574
68662
|
topic_name: (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "topic_name", "", 0),
|
|
@@ -68812,12 +68900,40 @@ function ac_create_node(gobj, event, kw, src) {
|
|
|
68812
68900
|
* Send to backend
|
|
68813
68901
|
********************************************/
|
|
68814
68902
|
function ac_update_node(gobj, event, kw, src) {
|
|
68815
|
-
let
|
|
68816
|
-
if (refuse_if_readonly$1(gobj, event)) return -1;
|
|
68817
|
-
let treedb_name = priv.treedb_name;
|
|
68903
|
+
let treedb_name = gobj.priv.treedb_name;
|
|
68818
68904
|
let topic_name = kw.topic_name;
|
|
68819
68905
|
let record = kw.record;
|
|
68820
|
-
|
|
68906
|
+
let options = kw.options || {};
|
|
68907
|
+
if (refuse_if_readonly$1(gobj, event)) {
|
|
68908
|
+
graphs_write_refused(gobj, topic_name, record);
|
|
68909
|
+
return -1;
|
|
68910
|
+
}
|
|
68911
|
+
if (topic_name === "__graphs__" && !is_connected(gobj)) {
|
|
68912
|
+
(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
|
+
return -1;
|
|
68915
|
+
}
|
|
68916
|
+
let ret = treedb_update_node(gobj, treedb_name, topic_name, record, options);
|
|
68917
|
+
if (ret < 0) graphs_write_refused(gobj, topic_name, record);
|
|
68918
|
+
return ret;
|
|
68919
|
+
}
|
|
68920
|
+
/************************************************************
|
|
68921
|
+
* A write of `__graphs__` did not land. The engine
|
|
68922
|
+
* (C_G6_NODES_TREE) took it for granted when it left -- nothing
|
|
68923
|
+
* answers it when it lands -- so it is told, and its next Save
|
|
68924
|
+
* writes the topic again. Other topics are the operator's data:
|
|
68925
|
+
* the answer's error says what happened to them.
|
|
68926
|
+
************************************************************/
|
|
68927
|
+
function graphs_write_refused(gobj, topic_name, record) {
|
|
68928
|
+
let priv = gobj.priv;
|
|
68929
|
+
if (topic_name !== "__graphs__") return;
|
|
68930
|
+
let topic = record && typeof record === "object" ? record.topic || record.id : "";
|
|
68931
|
+
if (!topic) {
|
|
68932
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: a refused __graphs__ write names no topic`);
|
|
68933
|
+
return;
|
|
68934
|
+
}
|
|
68935
|
+
if (!priv.gobj_nodes_tree) return;
|
|
68936
|
+
(0, _yuneta_gobj_js.gobj_send_event)(priv.gobj_nodes_tree, "EV_GRAPHS_WRITE_REFUSED", { topic }, gobj);
|
|
68821
68937
|
}
|
|
68822
68938
|
/********************************************
|
|
68823
68939
|
* Message from G6_nodes_tree
|
|
@@ -70473,9 +70589,8 @@ function register_c_yui_treedb_schema() {
|
|
|
70473
70589
|
* it, and that mark lived in the memory of the session only:
|
|
70474
70590
|
* a reload of the page, a reconnect or a refresh of the model
|
|
70475
70591
|
* lost the chip, the banner and the export warning while
|
|
70476
|
-
* __system__ still differed from the file in use
|
|
70477
|
-
*
|
|
70478
|
-
* C_TREEDB's `saved-schema` (`draft_changed`, by treedb) and
|
|
70592
|
+
* __system__ still differed from the file in use. The host
|
|
70593
|
+
* reads that difference from C_TREEDB's `saved-schema` (`draft_changed`, by treedb) and
|
|
70479
70594
|
* hands it here; the editor applies it to its model, in place
|
|
70480
70595
|
* of what the host said before.
|
|
70481
70596
|
*
|
|
@@ -72143,11 +72258,10 @@ function write_options(op) {
|
|
|
72143
72258
|
* AN EDIT IS A DRAFT. A write here moves no version and reaches no
|
|
72144
72259
|
* treedb: the host SAVES it (C_TREEDB's save-schema raises the
|
|
72145
72260
|
* topic_version of what changed and the schema_version, once) and
|
|
72146
|
-
* APPLIES it (apply-schema + a restart of the owning yuno).
|
|
72147
|
-
*
|
|
72148
|
-
*
|
|
72149
|
-
*
|
|
72150
|
-
* wrote and has not saved (EV_REFRESH forgets it: the view's own
|
|
72261
|
+
* APPLIES it (apply-schema + a restart of the owning yuno). If a
|
|
72262
|
+
* write here raised both versions, an edit half made would already
|
|
72263
|
+
* be the schema of the next start. The topic list marks what this
|
|
72264
|
+
* session wrote and has not saved (EV_REFRESH forgets it: the view's own
|
|
72151
72265
|
* Refresh button sends it, and a host may after a save -- the
|
|
72152
72266
|
* agent console's does not) and what the host says is not saved
|
|
72153
72267
|
* (EV_DRAFTS, replaced whole each time it is sent).
|
|
@@ -72213,6 +72327,7 @@ var HOOK_TOPICS = "topics";
|
|
|
72213
72327
|
var HOOK_COLS = "cols";
|
|
72214
72328
|
var DIAGRAM_SEG = "diagram";
|
|
72215
72329
|
var PURPOSE = "schema_editor";
|
|
72330
|
+
var DIALOGS_THAT_READ_NOTHING = ["SCHEMA_EXPORT_DIALOG", "SCHEMA_REPORT_DIALOG"];
|
|
72216
72331
|
/***************************************************************
|
|
72217
72332
|
* Attrs
|
|
72218
72333
|
***************************************************************/
|
|
@@ -72245,6 +72360,7 @@ var PRIVATE_DATA$1 = {
|
|
|
72245
72360
|
diagram_gobj: null,
|
|
72246
72361
|
dialog: null,
|
|
72247
72362
|
dialog_gen: 0,
|
|
72363
|
+
dialog_kind: "",
|
|
72248
72364
|
save_queue: null,
|
|
72249
72365
|
save_return: "",
|
|
72250
72366
|
save_wrote: false,
|
|
@@ -72254,6 +72370,8 @@ var PRIVATE_DATA$1 = {
|
|
|
72254
72370
|
dropped_round: 0,
|
|
72255
72371
|
dropped_write: 0,
|
|
72256
72372
|
reload_after_write: false,
|
|
72373
|
+
refresh_after_write: false,
|
|
72374
|
+
reopen_form: null,
|
|
72257
72375
|
pending_seg: null,
|
|
72258
72376
|
import_plan: null,
|
|
72259
72377
|
import_pane: null,
|
|
@@ -72413,9 +72531,9 @@ function refuse_if_readonly(gobj, event) {
|
|
|
72413
72531
|
* dumped by the machine trace).
|
|
72414
72532
|
*
|
|
72415
72533
|
* Refused, and said. A column form sends every field it shows, so
|
|
72416
|
-
* its Save after a reload wrote the OLD record over the newer one
|
|
72417
|
-
*
|
|
72418
|
-
*
|
|
72534
|
+
* its Save after a reload wrote the OLD record over the newer one;
|
|
72535
|
+
* a form whose column the reload removed answered "names no column"
|
|
72536
|
+
* for ever. end_load()
|
|
72419
72537
|
* closes such a dialog when the load lands; this is the same rule
|
|
72420
72538
|
* for whatever arrives anyway -- a stale screen, a confirmation
|
|
72421
72539
|
* that was up, a keyboard.
|
|
@@ -72435,8 +72553,7 @@ function built_on_a_replaced_model(gobj, event, kw) {
|
|
|
72435
72553
|
* the model shown is kept, and it may be older than the store.
|
|
72436
72554
|
* The session is up, so no reconnect will ask for it again -- it
|
|
72437
72555
|
* was owed for as long as the session lasted, and a form opened
|
|
72438
|
-
* on that model wrote every field of it over the newer record
|
|
72439
|
-
* (fifth independent review; A3 of the fourth, by another path).
|
|
72556
|
+
* on that model wrote every field of it over the newer record.
|
|
72440
72557
|
*
|
|
72441
72558
|
* So the operator's NEXT action asks it. An edit -- a form, a
|
|
72442
72559
|
* write, a confirmation, what reads the model whole (check,
|
|
@@ -72460,14 +72577,61 @@ function owes_reload(gobj) {
|
|
|
72460
72577
|
let state = (0, _yuneta_gobj_js.gobj_current_state)(gobj);
|
|
72461
72578
|
return gobj.priv.reload_on_open && transport_in_session(gobj) && state !== "ST_LOADING" && state !== "ST_SAVING";
|
|
72462
72579
|
}
|
|
72463
|
-
function reload_first(gobj, event) {
|
|
72580
|
+
function reload_first(gobj, event, reopen) {
|
|
72581
|
+
let priv = gobj.priv;
|
|
72464
72582
|
if (!owes_reload(gobj)) return false;
|
|
72465
|
-
|
|
72583
|
+
priv.reload_on_open = false;
|
|
72584
|
+
if (reopen && priv.dialog) {
|
|
72585
|
+
priv.reopen_form = Object.assign((0, _yuneta_gobj_js.json_deep_copy)(reopen), {
|
|
72586
|
+
dialog: priv.dialog,
|
|
72587
|
+
treedb_id: priv.treedb_id
|
|
72588
|
+
});
|
|
72589
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} refused, the schemas shown may be out of date: they are read again first, and the form opens again on them with its changes`);
|
|
72590
|
+
yui_shell_show_error(yui_shell_of(gobj), "the schemas shown may be out of date: they are read again, and the form opens again on them with your changes", { t: i18next.t });
|
|
72591
|
+
request_model(gobj, true);
|
|
72592
|
+
return true;
|
|
72593
|
+
}
|
|
72466
72594
|
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} refused, the schemas shown may be out of date: they are read again first`);
|
|
72467
72595
|
yui_shell_show_error(yui_shell_of(gobj), "the schemas shown may be out of date: they are read again, try again when they are in", { t: i18next.t });
|
|
72468
72596
|
request_model(gobj, true);
|
|
72469
72597
|
return true;
|
|
72470
72598
|
}
|
|
72599
|
+
/***************************************************************
|
|
72600
|
+
* The form reload_first() took down, opened again on the model
|
|
72601
|
+
* the load just made, with the operator's changes on top.
|
|
72602
|
+
*
|
|
72603
|
+
* Only where it can mean the same thing: on the treedb it was
|
|
72604
|
+
* opened on, on the screen whose Save it has, and on a record
|
|
72605
|
+
* that is still there. Otherwise it is not opened, and that is
|
|
72606
|
+
* said -- a form opened on another treedb, or on nothing, would
|
|
72607
|
+
* save somewhere the operator never meant.
|
|
72608
|
+
***************************************************************/
|
|
72609
|
+
function reopen_form(gobj, r) {
|
|
72610
|
+
let priv = gobj.priv;
|
|
72611
|
+
let state = (0, _yuneta_gobj_js.gobj_current_state)(gobj);
|
|
72612
|
+
let treedb = current_treedb(gobj);
|
|
72613
|
+
let topic = null;
|
|
72614
|
+
let col = null;
|
|
72615
|
+
let fits = false;
|
|
72616
|
+
if (treedb && r.treedb_id === priv.treedb_id) {
|
|
72617
|
+
if (r.form === "column" && state === "ST_COLUMNS") {
|
|
72618
|
+
topic = find_topic(priv.model, priv.treedb_id, r.topic);
|
|
72619
|
+
col = topic && !r.creating ? find_col(priv.model, priv.treedb_id, r.topic, r.col) : null;
|
|
72620
|
+
fits = !!topic && (r.creating || !!col);
|
|
72621
|
+
} else if (r.form === "topic" && state === "ST_TOPICS") {
|
|
72622
|
+
topic = r.creating ? null : find_topic(priv.model, priv.treedb_id, r.topic);
|
|
72623
|
+
fits = r.creating || !!topic;
|
|
72624
|
+
}
|
|
72625
|
+
}
|
|
72626
|
+
if (!fits) {
|
|
72627
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: the ${r.form} form was not opened again: what it edited is not on the schemas the reload read (${r.treedb_id} ${r.topic}${r.col ? "." + r.col : ""}, now ${state})`);
|
|
72628
|
+
yui_shell_show_error(yui_shell_of(gobj), "the schemas were read again and what the form was editing is not there any more", { t: i18next.t });
|
|
72629
|
+
return -1;
|
|
72630
|
+
}
|
|
72631
|
+
if (r.form === "column") open_column_form(gobj, topic, col, null, r.changed);
|
|
72632
|
+
else open_topic_form(gobj, treedb, topic, r.changed);
|
|
72633
|
+
return 0;
|
|
72634
|
+
}
|
|
72471
72635
|
function reload_after_move(gobj) {
|
|
72472
72636
|
if (!owes_reload(gobj)) return 0;
|
|
72473
72637
|
gobj.priv.reload_on_open = false;
|
|
@@ -72486,7 +72650,7 @@ function reload_after_move(gobj) {
|
|
|
72486
72650
|
* none of the actions of a screen, so the screen it replaces goes
|
|
72487
72651
|
* and the toolbar stops answering: left up, a click on a card, on
|
|
72488
72652
|
* Back or on the drawing answered "Event NOT DEFINED in state
|
|
72489
|
-
* ST_LOADING" and was lost
|
|
72653
|
+
* ST_LOADING" and was lost. A dialog
|
|
72490
72654
|
* left open is answered in ST_LOADING instead (ac_wait_for_the_load),
|
|
72491
72655
|
* and a load that LANDS closes it (end_load()): it was built on the
|
|
72492
72656
|
* model the load replaced, and its Save sends every field it shows.
|
|
@@ -72613,7 +72777,7 @@ function build_model(gobj) {
|
|
|
72613
72777
|
* measurement of "changed since" can be measured against.
|
|
72614
72778
|
*
|
|
72615
72779
|
* `written` is forgotten only by an EV_REFRESH (the view's own
|
|
72616
|
-
* Refresh button, or a host that sends one). Since
|
|
72780
|
+
* Refresh button, or a host that sends one). Since 7.23.196 a write moves no
|
|
72617
72781
|
* version, so `written` is the draft chip of what this session
|
|
72618
72782
|
* wrote and no longer half of a version measurement: a reload of
|
|
72619
72783
|
* the reconnect, or of a write that turned out done, forgot the
|
|
@@ -73706,6 +73870,7 @@ function close_dialog(gobj) {
|
|
|
73706
73870
|
if (!priv.dialog) return;
|
|
73707
73871
|
let dialog = priv.dialog;
|
|
73708
73872
|
priv.dialog = null;
|
|
73873
|
+
priv.dialog_kind = "";
|
|
73709
73874
|
priv.export_view = null;
|
|
73710
73875
|
try {
|
|
73711
73876
|
dialog.close();
|
|
@@ -73717,6 +73882,7 @@ function open_dialog(gobj, $content, title, logical, title_prefix) {
|
|
|
73717
73882
|
let priv = gobj.priv;
|
|
73718
73883
|
close_dialog(gobj);
|
|
73719
73884
|
priv.dialog_gen = priv.model_gen;
|
|
73885
|
+
priv.dialog_kind = logical;
|
|
73720
73886
|
priv.dialog = yui_shell_show_modal(yui_shell_of(gobj), $content, {
|
|
73721
73887
|
dialog: true,
|
|
73722
73888
|
title,
|
|
@@ -73725,6 +73891,7 @@ function open_dialog(gobj, $content, title, logical, title_prefix) {
|
|
|
73725
73891
|
t: i18next.t,
|
|
73726
73892
|
on_close: () => {
|
|
73727
73893
|
priv.dialog = null;
|
|
73894
|
+
priv.dialog_kind = "";
|
|
73728
73895
|
priv.export_view = null;
|
|
73729
73896
|
}
|
|
73730
73897
|
});
|
|
@@ -73888,6 +74055,55 @@ function read_form($root) {
|
|
|
73888
74055
|
return out;
|
|
73889
74056
|
}
|
|
73890
74057
|
/***************************************************************
|
|
74058
|
+
* A column form as its Save sends it: the fields and the flags.
|
|
74059
|
+
***************************************************************/
|
|
74060
|
+
function column_form_state($form) {
|
|
74061
|
+
let values = read_form($form);
|
|
74062
|
+
values.flag = read_flags($form);
|
|
74063
|
+
return values;
|
|
74064
|
+
}
|
|
74065
|
+
/***************************************************************
|
|
74066
|
+
* The fields the operator CHANGED: those whose value is not the
|
|
74067
|
+
* one the form was opened with.
|
|
74068
|
+
***************************************************************/
|
|
74069
|
+
function form_changes(initial, values) {
|
|
74070
|
+
let changed = {};
|
|
74071
|
+
for (let name of Object.keys(values)) if (JSON.stringify(values[name]) !== JSON.stringify(initial[name])) changed[name] = values[name];
|
|
74072
|
+
return changed;
|
|
74073
|
+
}
|
|
74074
|
+
/***************************************************************
|
|
74075
|
+
* Put changes back into a form just built (reopen_form()). The
|
|
74076
|
+
* flags are drawn again for the type the changes leave, holding
|
|
74077
|
+
* the flags they name, so none of them is hidden by the type.
|
|
74078
|
+
***************************************************************/
|
|
74079
|
+
function apply_form_changes(gobj, $form, changes) {
|
|
74080
|
+
for (let name of Object.keys(changes)) {
|
|
74081
|
+
if (name === "flag") continue;
|
|
74082
|
+
let $control = $form.querySelector(`[data-name="${name}"]`);
|
|
74083
|
+
if (!$control) {
|
|
74084
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: a change of '${name}' has no field in the form opened again: not put back`);
|
|
74085
|
+
continue;
|
|
74086
|
+
}
|
|
74087
|
+
if ($control.type === "checkbox") $control.checked = !!changes[name];
|
|
74088
|
+
else $control.value = changes[name];
|
|
74089
|
+
}
|
|
74090
|
+
let $type = $form.querySelector("[data-name=\"type\"]");
|
|
74091
|
+
if ($type && $form.querySelector(".SCHEMA_FLAGS")) {
|
|
74092
|
+
let flags = Array.isArray(changes.flag) ? changes.flag : read_flags($form);
|
|
74093
|
+
redraw_flags(gobj, $form, $type.value, flags);
|
|
74094
|
+
}
|
|
74095
|
+
}
|
|
74096
|
+
/***************************************************************
|
|
74097
|
+
* Draw the flags of a column form again, for `type`, with
|
|
74098
|
+
* `current` checked.
|
|
74099
|
+
***************************************************************/
|
|
74100
|
+
function redraw_flags(gobj, $form, type, current) {
|
|
74101
|
+
let $holder = $form.querySelector(".SCHEMA_FLAGS");
|
|
74102
|
+
let $new = (0, _yuneta_gobj_js.createElement2)(flags_field(gobj, type, current));
|
|
74103
|
+
$holder.parentNode.replaceChild($new, $holder);
|
|
74104
|
+
(0, _yuneta_gobj_js.refresh_language)($new, i18next.t);
|
|
74105
|
+
}
|
|
74106
|
+
/***************************************************************
|
|
73891
74107
|
* The flags of a column, as checkboxes that say what they do.
|
|
73892
74108
|
*
|
|
73893
74109
|
* Grouped the way they act, greyed when they are meaningless on
|
|
@@ -73961,7 +74177,7 @@ function read_flags($root) {
|
|
|
73961
74177
|
* Offering a field that silently does something else is worse
|
|
73962
74178
|
* than not offering it.
|
|
73963
74179
|
***************************************************************/
|
|
73964
|
-
function open_column_form(gobj, topic, col, prefill) {
|
|
74180
|
+
function open_column_form(gobj, topic, col, prefill, changes) {
|
|
73965
74181
|
let priv = gobj.priv;
|
|
73966
74182
|
let record = prefill || col && col.record || {};
|
|
73967
74183
|
let creating = !col;
|
|
@@ -74065,11 +74281,7 @@ function open_column_form(gobj, topic, col, prefill) {
|
|
|
74065
74281
|
]);
|
|
74066
74282
|
let $type = $form.querySelector("[data-name=\"type\"]");
|
|
74067
74283
|
$type.addEventListener("change", () => {
|
|
74068
|
-
|
|
74069
|
-
let current = read_flags($form);
|
|
74070
|
-
let $new = (0, _yuneta_gobj_js.createElement2)(flags_field(gobj, $type.value, current));
|
|
74071
|
-
$holder.parentNode.replaceChild($new, $holder);
|
|
74072
|
-
(0, _yuneta_gobj_js.refresh_language)($new, i18next.t);
|
|
74284
|
+
redraw_flags(gobj, $form, $type.value, read_flags($form));
|
|
74073
74285
|
});
|
|
74074
74286
|
$form.addEventListener("change", (evt) => {
|
|
74075
74287
|
let $box = evt.target.closest(".SCHEMA_FLAG_BOX");
|
|
@@ -74081,15 +74293,17 @@ function open_column_form(gobj, topic, col, prefill) {
|
|
|
74081
74293
|
evt.stopPropagation();
|
|
74082
74294
|
close_dialog(gobj);
|
|
74083
74295
|
});
|
|
74296
|
+
let initial = column_form_state($form);
|
|
74297
|
+
if (changes) apply_form_changes(gobj, $form, changes);
|
|
74084
74298
|
$form.querySelector(".SCHEMA_COL_FORM_SAVE").addEventListener("click", (evt) => {
|
|
74085
74299
|
evt.stopPropagation();
|
|
74086
|
-
let values =
|
|
74087
|
-
values.flag = read_flags($form);
|
|
74300
|
+
let values = column_form_state($form);
|
|
74088
74301
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_SAVE_COLUMN", {
|
|
74089
74302
|
topic: topic.name,
|
|
74090
74303
|
col: creating ? "" : col.name,
|
|
74091
74304
|
creating,
|
|
74092
74305
|
values,
|
|
74306
|
+
changed: creating ? values : form_changes(initial, values),
|
|
74093
74307
|
model_gen
|
|
74094
74308
|
}, gobj);
|
|
74095
74309
|
});
|
|
@@ -74109,7 +74323,7 @@ function stringify_field(value) {
|
|
|
74109
74323
|
* actually has: a pkey naming no column is a topic that does
|
|
74110
74324
|
* not open, and it is the first thing the validator looks for.
|
|
74111
74325
|
***************************************************************/
|
|
74112
|
-
function open_topic_form(gobj, treedb, topic) {
|
|
74326
|
+
function open_topic_form(gobj, treedb, topic, changes) {
|
|
74113
74327
|
let record = topic && topic.record || {};
|
|
74114
74328
|
let creating = !topic;
|
|
74115
74329
|
let col_names = topic ? topic.cols.map((c) => c.name) : [];
|
|
@@ -74204,12 +74418,16 @@ function open_topic_form(gobj, treedb, topic) {
|
|
|
74204
74418
|
evt.stopPropagation();
|
|
74205
74419
|
close_dialog(gobj);
|
|
74206
74420
|
});
|
|
74421
|
+
let initial = read_form($form);
|
|
74422
|
+
if (changes) apply_form_changes(gobj, $form, changes);
|
|
74207
74423
|
$form.querySelector(".SCHEMA_TOPIC_FORM_SAVE").addEventListener("click", (evt) => {
|
|
74208
74424
|
evt.stopPropagation();
|
|
74425
|
+
let values = read_form($form);
|
|
74209
74426
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_SAVE_TOPIC", {
|
|
74210
74427
|
topic: creating ? "" : topic.name,
|
|
74211
74428
|
creating,
|
|
74212
|
-
values
|
|
74429
|
+
values,
|
|
74430
|
+
changed: creating ? values : form_changes(initial, values),
|
|
74213
74431
|
model_gen
|
|
74214
74432
|
}, gobj);
|
|
74215
74433
|
});
|
|
@@ -74919,11 +75137,11 @@ function transport_in_session(gobj) {
|
|
|
74919
75137
|
* The state is part of the question, and that is only true
|
|
74920
75138
|
* because NOTHING moves the editor out of ST_LOADING or ST_SAVING
|
|
74921
75139
|
* but the end of what is in flight: a position the host sends
|
|
74922
|
-
* meanwhile waits in `pending_seg` (ac_show()).
|
|
74923
|
-
*
|
|
74924
|
-
*
|
|
74925
|
-
*
|
|
74926
|
-
*
|
|
75140
|
+
* meanwhile waits in `pending_seg` (ac_show()). If EV_SHOW moved a
|
|
75141
|
+
* RELOAD out of ST_LOADING, every answer of it would be "for a load
|
|
75142
|
+
* that is over": the records it had emptied would stay empty, and
|
|
75143
|
+
* the next write would patch them into a model with no treedb at
|
|
75144
|
+
* all.
|
|
74927
75145
|
***************************************************************/
|
|
74928
75146
|
function is_current_load(gobj, md) {
|
|
74929
75147
|
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;
|
|
@@ -74979,20 +75197,28 @@ function transport_dropped(gobj) {
|
|
|
74979
75197
|
function end_load(gobj) {
|
|
74980
75198
|
let priv = gobj.priv;
|
|
74981
75199
|
let seg = priv.pending_seg;
|
|
75200
|
+
let reopen = priv.reopen_form;
|
|
74982
75201
|
priv.pending_seg = null;
|
|
75202
|
+
priv.reopen_form = null;
|
|
74983
75203
|
if (priv.dialog && priv.dialog_gen !== priv.model_gen) {
|
|
74984
|
-
|
|
75204
|
+
if (!reopen || reopen.dialog !== priv.dialog) {
|
|
75205
|
+
reopen = null;
|
|
75206
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: a dialog was open on the schemas the load replaced: closed`);
|
|
75207
|
+
yui_shell_show_error(yui_shell_of(gobj), "the schemas were read again: open the dialog again", { t: i18next.t });
|
|
75208
|
+
}
|
|
74985
75209
|
close_dialog(gobj);
|
|
74986
|
-
|
|
74987
|
-
|
|
75210
|
+
} else reopen = null;
|
|
75211
|
+
let ret = 0;
|
|
74988
75212
|
if (priv.model) {
|
|
74989
|
-
if (seg !== null)
|
|
74990
|
-
|
|
75213
|
+
if (seg !== null) ret = apply_seg(gobj, seg);
|
|
75214
|
+
else ret = go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
|
|
75215
|
+
} else {
|
|
75216
|
+
if (seg !== null) adopt_seg(gobj, seg);
|
|
75217
|
+
(0, _yuneta_gobj_js.gobj_change_state)(gobj, "ST_IDLE");
|
|
75218
|
+
render(gobj);
|
|
74991
75219
|
}
|
|
74992
|
-
if (
|
|
74993
|
-
|
|
74994
|
-
render(gobj);
|
|
74995
|
-
return 0;
|
|
75220
|
+
if (reopen) reopen_form(gobj, reopen);
|
|
75221
|
+
return ret;
|
|
74996
75222
|
}
|
|
74997
75223
|
/***************************************************************
|
|
74998
75224
|
* The queue is done, or gave up. Either way the model is what
|
|
@@ -75017,7 +75243,11 @@ function end_writes(gobj, error) {
|
|
|
75017
75243
|
render(gobj);
|
|
75018
75244
|
publish_check(gobj);
|
|
75019
75245
|
}
|
|
75020
|
-
|
|
75246
|
+
if (priv.refresh_after_write) {
|
|
75247
|
+
priv.refresh_after_write = false;
|
|
75248
|
+
priv.reload_after_write = false;
|
|
75249
|
+
request_model(gobj, false);
|
|
75250
|
+
} else reload_if_owed(gobj);
|
|
75021
75251
|
return error ? -1 : 0;
|
|
75022
75252
|
}
|
|
75023
75253
|
/***************************************************************
|
|
@@ -75129,10 +75359,59 @@ function position_seg(gobj) {
|
|
|
75129
75359
|
* ...and the same in reverse. A tail naming a treedb or a topic
|
|
75130
75360
|
* the store does not have lands one level up rather than on an
|
|
75131
75361
|
* empty screen: a shared link outlives the schema it points at.
|
|
75362
|
+
*
|
|
75363
|
+
* Every position the HOST sends comes through here, at once
|
|
75364
|
+
* (ac_show()) or when what was in flight ends (end_load(),
|
|
75365
|
+
* end_writes()). A move to another position closes the dialog of
|
|
75366
|
+
* the screen the editor left (close_dialog_left_behind()).
|
|
75132
75367
|
***************************************************************/
|
|
75133
75368
|
function apply_seg(gobj, seg) {
|
|
75369
|
+
let before = position_seg(gobj);
|
|
75134
75370
|
let pos = seg_position(seg);
|
|
75135
|
-
|
|
75371
|
+
let ret = go(gobj, pos.treedb_id, pos.topic_name, pos.diagram, false);
|
|
75372
|
+
if (position_seg(gobj) !== before) close_dialog_left_behind(gobj);
|
|
75373
|
+
return ret;
|
|
75374
|
+
}
|
|
75375
|
+
/***************************************************************
|
|
75376
|
+
* The host moved the editor while a dialog was up. C_YUI_SHELL
|
|
75377
|
+
* keeps the overlays open on a move that changes only the subpath
|
|
75378
|
+
* (a url typed in, a link), so the dialog outlives its screen.
|
|
75379
|
+
*
|
|
75380
|
+
* A form, the import and the orphans send events that only the
|
|
75381
|
+
* screen they were opened from declares, and they name their
|
|
75382
|
+
* topic under the treedb open at the time. Left up on another
|
|
75383
|
+
* screen, their Save answered "Event NOT DEFINED" and the edit was
|
|
75384
|
+
* lost with no word. So the dialog is closed and the operator told.
|
|
75385
|
+
* The import plan goes with its dialog: it was computed for the
|
|
75386
|
+
* treedb the editor left.
|
|
75387
|
+
*
|
|
75388
|
+
* The export and the check stay: they show the texts they were
|
|
75389
|
+
* opened with, and what they send is legal in every state.
|
|
75390
|
+
***************************************************************/
|
|
75391
|
+
function close_dialog_left_behind(gobj) {
|
|
75392
|
+
let priv = gobj.priv;
|
|
75393
|
+
if (!priv.dialog || DIALOGS_THAT_READ_NOTHING.includes(priv.dialog_kind)) return;
|
|
75394
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: the host moved the view while the dialog ${priv.dialog_kind} was open: closed`);
|
|
75395
|
+
close_dialog(gobj);
|
|
75396
|
+
forget_import_plan(gobj);
|
|
75397
|
+
yui_shell_show_error(yui_shell_of(gobj), "the view moved: open the dialog again", { t: i18next.t });
|
|
75398
|
+
}
|
|
75399
|
+
/***************************************************************
|
|
75400
|
+
* A confirmation answered on another screen than the one it was
|
|
75401
|
+
* asked from. A confirmation is a shell modal, so a move sent by
|
|
75402
|
+
* the host does not close it. It names its topic and column, and
|
|
75403
|
+
* the actions look them up under the treedb open NOW: a Yes after
|
|
75404
|
+
* a move to another treedb deleted the topic or column of the same
|
|
75405
|
+
* name THERE.
|
|
75406
|
+
*
|
|
75407
|
+
* Refused, and said. A kw with no `seg` stamp is not a
|
|
75408
|
+
* confirmation's and is not asked.
|
|
75409
|
+
***************************************************************/
|
|
75410
|
+
function asked_on_another_screen(gobj, event, kw) {
|
|
75411
|
+
if (!kw || kw.seg === void 0 || kw.seg === position_seg(gobj)) return false;
|
|
75412
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} refused, it was asked on '${kw.seg}' and the view is on '${position_seg(gobj)}'`);
|
|
75413
|
+
yui_shell_show_error(yui_shell_of(gobj), "the view moved: open the dialog again", { t: i18next.t });
|
|
75414
|
+
return true;
|
|
75136
75415
|
}
|
|
75137
75416
|
function seg_position(seg) {
|
|
75138
75417
|
let parts = String(seg || "").split("/").filter((x) => x.length > 0);
|
|
@@ -75249,7 +75528,9 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
75249
75528
|
priv.save_return = "";
|
|
75250
75529
|
priv.save_wrote = false;
|
|
75251
75530
|
(0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_RECORD_WRITTEN", { treedb_name: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name") });
|
|
75252
|
-
|
|
75531
|
+
let refresh = priv.refresh_after_write;
|
|
75532
|
+
priv.refresh_after_write = false;
|
|
75533
|
+
request_model(gobj, !refresh);
|
|
75253
75534
|
return 0;
|
|
75254
75535
|
}
|
|
75255
75536
|
}
|
|
@@ -75308,8 +75589,7 @@ function late_write_done(gobj, command, topic_name, data) {
|
|
|
75308
75589
|
* The fkey is read with parse_fkey_ref(), because the store answers
|
|
75309
75590
|
* in list_dict -- `[{topic_name, id, hook_name}]` -- and not in the
|
|
75310
75591
|
* `topics^<topic id>^cols` strings this view writes. Split as a
|
|
75311
|
-
* string, every production answer marked nothing
|
|
75312
|
-
* review, probe C).
|
|
75592
|
+
* string, every production answer marked nothing.
|
|
75313
75593
|
***************************************************************/
|
|
75314
75594
|
function mark_written_record(gobj, topic_name, record) {
|
|
75315
75595
|
let priv = gobj.priv;
|
|
@@ -75366,7 +75646,7 @@ function ac_hide(gobj, event, kw, src) {
|
|
|
75366
75646
|
*
|
|
75367
75647
|
* Nothing else ends a load or a write the drop cut: their answers
|
|
75368
75648
|
* will never come, and waiting in ST_LOADING skipped the reload
|
|
75369
|
-
* itself
|
|
75649
|
+
* itself.
|
|
75370
75650
|
***************************************************************/
|
|
75371
75651
|
function ac_transport_state(gobj, event, kw, src) {
|
|
75372
75652
|
let priv = gobj.priv;
|
|
@@ -75397,6 +75677,21 @@ function ac_refresh$1(gobj, event, kw, src) {
|
|
|
75397
75677
|
return request_model(gobj, false);
|
|
75398
75678
|
}
|
|
75399
75679
|
/***************************************************************
|
|
75680
|
+
* EV_REFRESH while writes are in flight: the view's own Refresh
|
|
75681
|
+
* is busy then, so it is a host's (after a Save, say).
|
|
75682
|
+
*
|
|
75683
|
+
* Run when the writes END (end_writes()), not now. Run now, the
|
|
75684
|
+
* load replaced ST_SAVING and what was still queued was never
|
|
75685
|
+
* sent, with no word: nothing but the end of what is in flight
|
|
75686
|
+
* moves this view out of ST_LOADING or ST_SAVING.
|
|
75687
|
+
***************************************************************/
|
|
75688
|
+
function ac_refresh_after_the_writes(gobj, event, kw, src) {
|
|
75689
|
+
let priv = gobj.priv;
|
|
75690
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} while writes are in flight: the schemas are read again when the writes end`);
|
|
75691
|
+
priv.refresh_after_write = true;
|
|
75692
|
+
return 0;
|
|
75693
|
+
}
|
|
75694
|
+
/***************************************************************
|
|
75400
75695
|
* What a DIALOG sends while the model is being read again: the
|
|
75401
75696
|
* Save of a form left open when the reload started, a
|
|
75402
75697
|
* confirmation, an import. The loading screen took the rest of
|
|
@@ -75405,12 +75700,11 @@ function ac_refresh$1(gobj, event, kw, src) {
|
|
|
75405
75700
|
* a model the answers in the air are about to replace.
|
|
75406
75701
|
*
|
|
75407
75702
|
* Refused, and SAID. Undeclared, it answered "Event NOT DEFINED
|
|
75408
|
-
* in state ST_LOADING" and the edit was gone with no word
|
|
75409
|
-
* independent review).
|
|
75703
|
+
* in state ST_LOADING" and the edit was gone with no word.
|
|
75410
75704
|
*
|
|
75411
75705
|
* And NOT "try again": the same Save, once the load was in, sent
|
|
75412
75706
|
* the form built on the old model -- every field of the old record
|
|
75413
|
-
* over the newer one
|
|
75707
|
+
* over the newer one. The load that
|
|
75414
75708
|
* lands closes such a dialog (end_load()); one that fails leaves it
|
|
75415
75709
|
* up, on the model it was built on.
|
|
75416
75710
|
***************************************************************/
|
|
@@ -75424,8 +75718,7 @@ function ac_wait_for_the_load(gobj, event, kw, src) {
|
|
|
75424
75718
|
* reload landed on zero treedbs while it was up) or ST_IDLE (no
|
|
75425
75719
|
* model). A confirmation is a shell modal, not this view's dialog,
|
|
75426
75720
|
* so the load that lands does not close it, and its Yes arrives
|
|
75427
|
-
* anyway. Undeclared, it answered "Event NOT DEFINED"
|
|
75428
|
-
* independent review).
|
|
75721
|
+
* anyway. Undeclared, it answered "Event NOT DEFINED".
|
|
75429
75722
|
*
|
|
75430
75723
|
* Refused with the stamp's own words: whatever it was decided on
|
|
75431
75724
|
* is not on screen any more.
|
|
@@ -75441,13 +75734,12 @@ function ac_confirmed_on_nothing(gobj, event, kw, src) {
|
|
|
75441
75734
|
* topics hold a draft in __system__ that is not saved (C_TREEDB's
|
|
75442
75735
|
* saved-schema, `draft_changed`). The mark of a write lived in this
|
|
75443
75736
|
* session's memory only, so a reload of the page, a reconnect or a
|
|
75444
|
-
* refresh showed no draft while __system__ still differed
|
|
75445
|
-
* the 2026-09-22 review).
|
|
75737
|
+
* refresh showed no draft while __system__ still differed.
|
|
75446
75738
|
*
|
|
75447
75739
|
* REPLACES what the host said before -- the host is the truth after
|
|
75448
75740
|
* a reload, and a Save is exactly the host saying "none any more".
|
|
75449
75741
|
* It only ever added, and a topic stayed a draft after the Save that
|
|
75450
|
-
* published it
|
|
75742
|
+
* published it. What this session wrote
|
|
75451
75743
|
* stays marked: it is kept apart (see topic_is_draft()).
|
|
75452
75744
|
***************************************************************/
|
|
75453
75745
|
function ac_drafts(gobj, event, kw, src) {
|
|
@@ -75504,7 +75796,10 @@ function ac_show_orphans(gobj, event, kw, src) {
|
|
|
75504
75796
|
* to feed.
|
|
75505
75797
|
***************************************************************/
|
|
75506
75798
|
function confirm_then(gobj, message, detail, kw) {
|
|
75507
|
-
kw = Object.assign({
|
|
75799
|
+
kw = Object.assign({
|
|
75800
|
+
model_gen: gobj.priv.model_gen,
|
|
75801
|
+
seg: position_seg(gobj)
|
|
75802
|
+
}, kw);
|
|
75508
75803
|
yui_shell_confirm_danger(yui_shell_of(gobj), message, {
|
|
75509
75804
|
t: i18next.t,
|
|
75510
75805
|
detail,
|
|
@@ -75571,7 +75866,13 @@ function ac_save_column(gobj, event, kw, src) {
|
|
|
75571
75866
|
let topic = find_topic(priv.model, priv.treedb_id, kw.topic);
|
|
75572
75867
|
let col = kw.creating ? null : find_col(priv.model, priv.treedb_id, kw.topic, kw.col);
|
|
75573
75868
|
if (refuse_if_readonly(gobj, event)) return -1;
|
|
75574
|
-
if (reload_first(gobj, event
|
|
75869
|
+
if (reload_first(gobj, event, {
|
|
75870
|
+
form: "column",
|
|
75871
|
+
topic: kw.topic,
|
|
75872
|
+
col: kw.col,
|
|
75873
|
+
creating: !!kw.creating,
|
|
75874
|
+
changed: kw.changed || {}
|
|
75875
|
+
})) return -1;
|
|
75575
75876
|
if (built_on_a_replaced_model(gobj, event, kw)) return -1;
|
|
75576
75877
|
if (!topic || !kw.creating && !col) {
|
|
75577
75878
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} names no column: ${kw.topic}.${kw.col}`);
|
|
@@ -75699,7 +76000,13 @@ function ac_save_topic(gobj, event, kw, src) {
|
|
|
75699
76000
|
let treedb = current_treedb(gobj);
|
|
75700
76001
|
let topic = kw.creating ? null : find_topic(priv.model, priv.treedb_id, kw.topic);
|
|
75701
76002
|
if (refuse_if_readonly(gobj, event)) return -1;
|
|
75702
|
-
if (reload_first(gobj, event
|
|
76003
|
+
if (reload_first(gobj, event, {
|
|
76004
|
+
form: "topic",
|
|
76005
|
+
topic: kw.topic,
|
|
76006
|
+
col: "",
|
|
76007
|
+
creating: !!kw.creating,
|
|
76008
|
+
changed: kw.changed || {}
|
|
76009
|
+
})) return -1;
|
|
75703
76010
|
if (built_on_a_replaced_model(gobj, event, kw)) return -1;
|
|
75704
76011
|
if (!treedb || !kw.creating && !topic) {
|
|
75705
76012
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} names no topic: ${kw.topic}`);
|
|
@@ -75890,6 +76197,7 @@ function ac_confirmed(gobj, event, kw, src) {
|
|
|
75890
76197
|
if (refuse_if_readonly(gobj, event)) return -1;
|
|
75891
76198
|
if (reload_first(gobj, event)) return -1;
|
|
75892
76199
|
if (built_on_a_replaced_model(gobj, event, kw)) return -1;
|
|
76200
|
+
if (asked_on_another_screen(gobj, event, kw)) return -1;
|
|
75893
76201
|
if (kw.what === "import") return run_import(gobj);
|
|
75894
76202
|
if (kw.what === "topic") {
|
|
75895
76203
|
let topic = find_topic(priv.model, priv.treedb_id, kw.topic);
|
|
@@ -76161,7 +76469,11 @@ function create_gclass$1(gclass_name) {
|
|
|
76161
76469
|
null
|
|
76162
76470
|
]
|
|
76163
76471
|
])],
|
|
76164
|
-
["ST_SAVING", COMMON.
|
|
76472
|
+
["ST_SAVING", COMMON.filter((a) => a[0] !== "EV_REFRESH").concat([[
|
|
76473
|
+
"EV_REFRESH",
|
|
76474
|
+
ac_refresh_after_the_writes,
|
|
76475
|
+
null
|
|
76476
|
+
]])]
|
|
76165
76477
|
];
|
|
76166
76478
|
const event_types = [
|
|
76167
76479
|
["EV_MT_COMMAND_ANSWER", _yuneta_gobj_js.event_flag_t.EVF_PUBLIC_EVENT],
|