@yuneta/gobj-ui 7.25.8 → 7.25.9
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 +34 -6
- package/dist/gobj-ui.cjs.js +168 -43
- package/dist/gobj-ui.es.js +168 -43
- package/package.json +1 -1
- package/src/c_yui_schema_editor.js +217 -46
- package/src/schema_editor_reload.wiring.test.js +321 -7
- package/src/shell_modals.js +8 -4
- package/src/shell_toast_once.test.js +42 -0
package/README.md
CHANGED
|
@@ -2182,12 +2182,40 @@ else.
|
|
|
2182
2182
|
`ST_LOADING` declares none of a screen's actions. A **dialog** left open is
|
|
2183
2183
|
the one thing still reachable: its Save (`EV_SAVE_COLUMN`, `EV_SAVE_TOPIC`),
|
|
2184
2184
|
a confirmation (`EV_CONFIRMED`), an orphan delete or an import is refused
|
|
2185
|
-
with `the schemas are loading:
|
|
2186
|
-
consumer's locales carry)
|
|
2187
|
-
|
|
2188
|
-
a
|
|
2189
|
-
|
|
2190
|
-
|
|
2185
|
+
with `the schemas are loading: wait for them` (7.25.9; an i18n key the
|
|
2186
|
+
consumer's locales carry). A write that ends with an error -- a drop
|
|
2187
|
+
included -- still applies a position that waited, as a load does. Out of
|
|
2188
|
+
session a load is not asked at all (no *"not in session"* errors); the
|
|
2189
|
+
reconnect loads.
|
|
2190
|
+
- **A dialog is built on ONE model, and a load that replaces it closes it**
|
|
2191
|
+
(7.25.9). Every load that lands bumps `model_gen`; a dialog records the one
|
|
2192
|
+
it was opened on, and its Save, its import Preview/Run, an orphan delete and
|
|
2193
|
+
a confirmation carry it in their kw. When a load lands under a dialog of an
|
|
2194
|
+
older model, the dialog is closed and the operator told
|
|
2195
|
+
`the schemas were read again: open the dialog again`; anything stamped with
|
|
2196
|
+
a replaced model that arrives anyway is refused with the same words. A
|
|
2197
|
+
column form sends every field it shows, so its Save after a reload wrote
|
|
2198
|
+
the OLD record over the newer one -- 7.25.8 told the operator to "try
|
|
2199
|
+
again", which did exactly that. The import plan is forgotten when a load
|
|
2200
|
+
starts. A load that failed or never left replaced nothing, and the dialog
|
|
2201
|
+
stays with what was typed.
|
|
2202
|
+
|
|
2203
|
+
```js
|
|
2204
|
+
gobj_send_event(editor, "EV_EDIT_COLUMN", {col: "id"}, host); // form, model_gen N
|
|
2205
|
+
gobj_send_event(editor, "EV_REFRESH", {}, host); // Save -> "wait for them"
|
|
2206
|
+
// ... the load lands (model_gen N+1): the form closes, the operator reopens it
|
|
2207
|
+
```
|
|
2208
|
+
- **A load refused IN session keeps the model it was replacing** (7.25.9): a
|
|
2209
|
+
routing adapter's deadline on a slow `nodes` answers -1 while the session
|
|
2210
|
+
is up. The records are put back, the screen and any open dialog stay, the
|
|
2211
|
+
operator is told `cannot read the schemas again: the previous ones stay`,
|
|
2212
|
+
and the reload is owed. Only a first load, with no model before it, ends
|
|
2213
|
+
on the empty screen. A write answered with no record reloads the model and
|
|
2214
|
+
says what it did not send after it
|
|
2215
|
+
(`the treedb did not describe a write back: the writes after it were not sent`).
|
|
2216
|
+
- The toolbar offers Diagram, Check, Export, Import, New topic and New column
|
|
2217
|
+
only when the treedb (or topic) the position names is IN the model; after a
|
|
2218
|
+
reload that no longer has it, Back and Refresh remain.
|
|
2191
2219
|
- A write this view gave up on (a drop, a deadline) whose answer still says it
|
|
2192
2220
|
was DONE makes the editor read the model again (at once, after the write in
|
|
2193
2221
|
flight, or on the reconnect), and it is a write for the host too: it
|
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -3062,6 +3062,8 @@ function show_notification(shell, kind, message, opts) {
|
|
|
3062
3062
|
},
|
|
3063
3063
|
[["button", {
|
|
3064
3064
|
class: "TOAST_CLOSE delete",
|
|
3065
|
+
title: (0, i18next.t)("close"),
|
|
3066
|
+
"data-i18n-title": "close",
|
|
3065
3067
|
"aria-label": (0, i18next.t)("close"),
|
|
3066
3068
|
"data-i18n-aria-label": "close"
|
|
3067
3069
|
}], [
|
|
@@ -3185,6 +3187,8 @@ function yui_shell_show_modal(shell, content, opts) {
|
|
|
3185
3187
|
{
|
|
3186
3188
|
class: "MODAL_CLOSE yui-dialog-x",
|
|
3187
3189
|
type: "button",
|
|
3190
|
+
title: (0, i18next.t)("close"),
|
|
3191
|
+
"data-i18n-title": "close",
|
|
3188
3192
|
"aria-label": (0, i18next.t)("close"),
|
|
3189
3193
|
"data-i18n-aria-label": "close"
|
|
3190
3194
|
},
|
|
@@ -3206,6 +3210,8 @@ function yui_shell_show_modal(shell, content, opts) {
|
|
|
3206
3210
|
]];
|
|
3207
3211
|
if (with_close) modal_children.push(["button", {
|
|
3208
3212
|
class: "MODAL_CLOSE modal-close is-large",
|
|
3213
|
+
title: (0, i18next.t)("close"),
|
|
3214
|
+
"data-i18n-title": "close",
|
|
3209
3215
|
"aria-label": (0, i18next.t)("close"),
|
|
3210
3216
|
"data-i18n-aria-label": "close"
|
|
3211
3217
|
}]);
|
|
@@ -3360,6 +3366,8 @@ function build_dialog(shell, message, buttons, opts) {
|
|
|
3360
3366
|
]);
|
|
3361
3367
|
$card_children.push(["button", {
|
|
3362
3368
|
class: "CONFIRM_CLOSE delete yui-confirm-x",
|
|
3369
|
+
title: (0, i18next.t)("close"),
|
|
3370
|
+
"data-i18n-title": "close",
|
|
3363
3371
|
"aria-label": (0, i18next.t)("close"),
|
|
3364
3372
|
"data-i18n-aria-label": "close"
|
|
3365
3373
|
}], [
|
|
@@ -72173,7 +72181,9 @@ var attrs_table$1 = [
|
|
|
72173
72181
|
];
|
|
72174
72182
|
var PRIVATE_DATA$1 = {
|
|
72175
72183
|
records: null,
|
|
72184
|
+
records_before: null,
|
|
72176
72185
|
model: null,
|
|
72186
|
+
model_gen: 0,
|
|
72177
72187
|
pending: 0,
|
|
72178
72188
|
load_error: "",
|
|
72179
72189
|
load_round: 0,
|
|
@@ -72188,6 +72198,7 @@ var PRIVATE_DATA$1 = {
|
|
|
72188
72198
|
order_undo: null,
|
|
72189
72199
|
diagram_gobj: null,
|
|
72190
72200
|
dialog: null,
|
|
72201
|
+
dialog_gen: 0,
|
|
72191
72202
|
save_queue: null,
|
|
72192
72203
|
save_return: "",
|
|
72193
72204
|
save_wrote: false,
|
|
@@ -72348,6 +72359,29 @@ function refuse_if_readonly(gobj, event) {
|
|
|
72348
72359
|
yui_shell_show_error(yui_shell_of(gobj), "the treedb is read-only", { t: i18next.t });
|
|
72349
72360
|
return true;
|
|
72350
72361
|
}
|
|
72362
|
+
/***************************************************************
|
|
72363
|
+
* A decision taken on a model a load has since REPLACED: the Save
|
|
72364
|
+
* of a form, a confirmation, an import. Each carries the
|
|
72365
|
+
* `model_gen` it was built on (a number, not the model: a kw is
|
|
72366
|
+
* dumped by the machine trace).
|
|
72367
|
+
*
|
|
72368
|
+
* Refused, and said. A column form sends every field it shows, so
|
|
72369
|
+
* its Save after a reload wrote the OLD record over the newer one
|
|
72370
|
+
* (fourth independent review, probe A3); a form whose column the
|
|
72371
|
+
* reload removed answered "names no column" for ever. end_load()
|
|
72372
|
+
* closes such a dialog when the load lands; this is the same rule
|
|
72373
|
+
* for whatever arrives anyway -- a stale screen, a confirmation
|
|
72374
|
+
* that was up, a keyboard.
|
|
72375
|
+
*
|
|
72376
|
+
* A kw with no stamp is not a dialog's and is not asked.
|
|
72377
|
+
***************************************************************/
|
|
72378
|
+
function built_on_a_replaced_model(gobj, event, kw) {
|
|
72379
|
+
let priv = gobj.priv;
|
|
72380
|
+
if (!kw || kw.model_gen === void 0 || kw.model_gen === priv.model_gen) return false;
|
|
72381
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} refused, it was decided on the schemas a reload replaced`);
|
|
72382
|
+
yui_shell_show_error(yui_shell_of(gobj), "the schemas were read again: open the dialog again", { t: i18next.t });
|
|
72383
|
+
return true;
|
|
72384
|
+
}
|
|
72351
72385
|
/***************************
|
|
72352
72386
|
* The model
|
|
72353
72387
|
***************************/
|
|
@@ -72362,7 +72396,11 @@ function refuse_if_readonly(gobj, event) {
|
|
|
72362
72396
|
* and the toolbar stops answering: left up, a click on a card, on
|
|
72363
72397
|
* Back or on the drawing answered "Event NOT DEFINED in state
|
|
72364
72398
|
* ST_LOADING" and was lost (third independent review). A dialog
|
|
72365
|
-
* left open is answered in ST_LOADING instead (ac_wait_for_the_load)
|
|
72399
|
+
* left open is answered in ST_LOADING instead (ac_wait_for_the_load),
|
|
72400
|
+
* and a load that LANDS closes it (end_load()): it was built on the
|
|
72401
|
+
* model the load replaced, and its Save sends every field it shows.
|
|
72402
|
+
* An import plan is forgotten here for the same reason: it is a list
|
|
72403
|
+
* of writes computed against the model going away.
|
|
72366
72404
|
*
|
|
72367
72405
|
* `keep_written`: a load the host did not ask for -- the reconnect,
|
|
72368
72406
|
* a write that turned out done -- keeps what this session wrote.
|
|
@@ -72372,12 +72410,16 @@ function refuse_if_readonly(gobj, event) {
|
|
|
72372
72410
|
* is not even asked): the records the model was built on are put
|
|
72373
72411
|
* back (emptied, the next write patched them into a model with no
|
|
72374
72412
|
* treedb), the round is spent so a request that did leave is
|
|
72375
|
-
* stale, and the session back asks again.
|
|
72413
|
+
* stale, and the session back asks again. A load that left and
|
|
72414
|
+
* FAILED keeps them the same way (`records_before`,
|
|
72415
|
+
* ac_mt_command_answer()).
|
|
72376
72416
|
***************************************************************/
|
|
72377
72417
|
function request_model(gobj, keep_written) {
|
|
72378
72418
|
let priv = gobj.priv;
|
|
72379
72419
|
if (!(0, _yuneta_gobj_js.gobj_read_pointer_attr)(gobj, "gobj_remote_yuno")) return -1;
|
|
72420
|
+
forget_import_plan(gobj);
|
|
72380
72421
|
let previous = priv.records;
|
|
72422
|
+
priv.records_before = previous;
|
|
72381
72423
|
priv.records = {
|
|
72382
72424
|
treedbs: [],
|
|
72383
72425
|
topics: [],
|
|
@@ -72403,6 +72445,7 @@ function request_model(gobj, keep_written) {
|
|
|
72403
72445
|
}
|
|
72404
72446
|
if (left < 3) {
|
|
72405
72447
|
priv.records = previous;
|
|
72448
|
+
priv.records_before = null;
|
|
72406
72449
|
priv.load_round++;
|
|
72407
72450
|
priv.reload_on_open = true;
|
|
72408
72451
|
priv.load_error = (0, i18next.t)("cannot reach the treedb");
|
|
@@ -72498,9 +72541,10 @@ function start_measuring(gobj) {
|
|
|
72498
72541
|
* until the host saves it (C_TREEDB's save-schema, which raises the
|
|
72499
72542
|
* versions of what changed). Two sources say a topic is one, and
|
|
72500
72543
|
* they are kept APART because they are forgotten differently:
|
|
72501
|
-
* - `written`: what THIS session wrote
|
|
72502
|
-
*
|
|
72503
|
-
*
|
|
72544
|
+
* - `written`: what THIS session wrote. Only a load the HOST asked
|
|
72545
|
+
* for forgets it (its EV_REFRESH, which a Save sends); the
|
|
72546
|
+
* reconnect's reload, the one owed after a write and a late
|
|
72547
|
+
* write's keep it (start_measuring(), request_model());
|
|
72504
72548
|
* - `host_ids`: what the host said last (EV_DRAFTS), replaced WHOLE
|
|
72505
72549
|
* by the next EV_DRAFTS. Folded into `written`, a topic the host
|
|
72506
72550
|
* named once stayed a draft after the Save that published it.
|
|
@@ -72668,6 +72712,8 @@ function render_toolbar(gobj) {
|
|
|
72668
72712
|
let readonly = is_readonly(gobj);
|
|
72669
72713
|
let has_model = !!priv.model;
|
|
72670
72714
|
let on_a_treedb = state !== "ST_IDLE" && state !== "ST_EMPTY";
|
|
72715
|
+
let treedb_here = on_a_treedb && !!current_treedb(gobj);
|
|
72716
|
+
let topic_here = treedb_here && !!current_topic(gobj);
|
|
72671
72717
|
let in_flight = state === "ST_SAVING" || state === "ST_LOADING";
|
|
72672
72718
|
let $left = [];
|
|
72673
72719
|
if (priv.treedb_id && on_a_treedb) $left.push([
|
|
@@ -72743,17 +72789,17 @@ function render_toolbar(gobj) {
|
|
|
72743
72789
|
$trail
|
|
72744
72790
|
]);
|
|
72745
72791
|
let $right = [];
|
|
72746
|
-
if (priv.treedb_id && has_model &&
|
|
72792
|
+
if (priv.treedb_id && has_model && treedb_here) {
|
|
72747
72793
|
$right.push(toolbar_button("SCHEMA_DIAGRAM_BTN", "yi-compass-drafting", priv.diagram ? "topics" : "diagram", "EV_TOGGLE_DIAGRAM", false));
|
|
72748
72794
|
$right.push(toolbar_button("SCHEMA_VALIDATE_BTN", "yi-square-check", "check", "EV_VALIDATE", false));
|
|
72749
72795
|
$right.push(toolbar_button("SCHEMA_EXPORT_BTN", "yi-download", "export", "EV_EXPORT", false));
|
|
72750
72796
|
if (!readonly) $right.push(toolbar_button("SCHEMA_IMPORT_BTN", "yi-upload", "import", "EV_IMPORT", false));
|
|
72751
72797
|
}
|
|
72752
|
-
if (priv.topic_name && !readonly && !priv.diagram &&
|
|
72798
|
+
if (priv.topic_name && !readonly && !priv.diagram && topic_here) {
|
|
72753
72799
|
if (undo_order_writes(gobj, current_topic(gobj)).length > 0) $right.push(toolbar_button("SCHEMA_UNDO_ORDER_BTN", "yi-arrow-rotate-left", "undo the order", "EV_UNDO_ORDER", false));
|
|
72754
72800
|
$right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus", "new column", "EV_ADD_COLUMN", false));
|
|
72755
72801
|
}
|
|
72756
|
-
if (priv.treedb_id && !priv.topic_name && !readonly && !priv.diagram &&
|
|
72802
|
+
if (priv.treedb_id && !priv.topic_name && !readonly && !priv.diagram && treedb_here) $right.push(toolbar_button("SCHEMA_ADD_TOPIC_BTN", "yi-plus", "new topic", "EV_ADD_TOPIC", false));
|
|
72757
72803
|
$right.push(toolbar_button("SCHEMA_REFRESH_BTN", "yi-arrows-rotate", "refresh", "EV_REFRESH", state === "ST_LOADING"));
|
|
72758
72804
|
let $bar = (0, _yuneta_gobj_js.createElement2)([
|
|
72759
72805
|
"div",
|
|
@@ -73573,6 +73619,7 @@ function close_dialog(gobj) {
|
|
|
73573
73619
|
function open_dialog(gobj, $content, title, logical, title_prefix) {
|
|
73574
73620
|
let priv = gobj.priv;
|
|
73575
73621
|
close_dialog(gobj);
|
|
73622
|
+
priv.dialog_gen = priv.model_gen;
|
|
73576
73623
|
priv.dialog = yui_shell_show_modal(yui_shell_of(gobj), $content, {
|
|
73577
73624
|
dialog: true,
|
|
73578
73625
|
title,
|
|
@@ -73619,11 +73666,28 @@ function name_control($spec, label) {
|
|
|
73619
73666
|
$spec[1]["aria-label"] = (0, i18next.t)(label);
|
|
73620
73667
|
$spec[1]["data-i18n-aria-label"] = label;
|
|
73621
73668
|
}
|
|
73669
|
+
if (!$spec[1].title) {
|
|
73670
|
+
$spec[1].title = (0, i18next.t)(label);
|
|
73671
|
+
$spec[1]["data-i18n-title"] = label;
|
|
73672
|
+
}
|
|
73622
73673
|
return true;
|
|
73623
73674
|
}
|
|
73624
73675
|
for (let child of $spec[2] || []) if (name_control(child, label)) return true;
|
|
73625
73676
|
return false;
|
|
73626
73677
|
}
|
|
73678
|
+
/***************************************************************
|
|
73679
|
+
* The four attributes that NAME a control -- a title and an
|
|
73680
|
+
* aria-label, each with the key a language change re-translates
|
|
73681
|
+
* it by. A visible label is not a name (CLAUDE.md).
|
|
73682
|
+
***************************************************************/
|
|
73683
|
+
function name_attrs(key, attrs) {
|
|
73684
|
+
return Object.assign({
|
|
73685
|
+
title: (0, i18next.t)(key),
|
|
73686
|
+
"data-i18n-title": key,
|
|
73687
|
+
"aria-label": (0, i18next.t)(key),
|
|
73688
|
+
"data-i18n-aria-label": key
|
|
73689
|
+
}, attrs);
|
|
73690
|
+
}
|
|
73627
73691
|
function field(logical, name, label, $control, help) {
|
|
73628
73692
|
name_control($control, label);
|
|
73629
73693
|
return [
|
|
@@ -73800,7 +73864,7 @@ function read_flags($root) {
|
|
|
73800
73864
|
* than not offering it.
|
|
73801
73865
|
***************************************************************/
|
|
73802
73866
|
function open_column_form(gobj, topic, col, prefill) {
|
|
73803
|
-
gobj.priv;
|
|
73867
|
+
let priv = gobj.priv;
|
|
73804
73868
|
let record = prefill || col && col.record || {};
|
|
73805
73869
|
let creating = !col;
|
|
73806
73870
|
let type = record.type || "string";
|
|
@@ -73810,6 +73874,7 @@ function open_column_form(gobj, topic, col, prefill) {
|
|
|
73810
73874
|
let hook_col = hook_topic ? hook[hook_topic] : "";
|
|
73811
73875
|
let treedb = current_treedb(gobj);
|
|
73812
73876
|
let sibling_topics = treedb ? treedb.topics.map((x) => x.name) : [];
|
|
73877
|
+
let model_gen = priv.model_gen;
|
|
73813
73878
|
let $form = (0, _yuneta_gobj_js.createElement2)([
|
|
73814
73879
|
"div",
|
|
73815
73880
|
{ class: "SCHEMA_COL_FORM box" },
|
|
@@ -73872,10 +73937,10 @@ function open_column_form(gobj, topic, col, prefill) {
|
|
|
73872
73937
|
},
|
|
73873
73938
|
[[
|
|
73874
73939
|
"button",
|
|
73875
|
-
{
|
|
73940
|
+
name_attrs("cancel", {
|
|
73876
73941
|
class: "SCHEMA_COL_FORM_CANCEL button",
|
|
73877
73942
|
type: "button"
|
|
73878
|
-
},
|
|
73943
|
+
}),
|
|
73879
73944
|
[[
|
|
73880
73945
|
"span",
|
|
73881
73946
|
{ i18n: "cancel" },
|
|
@@ -73883,10 +73948,10 @@ function open_column_form(gobj, topic, col, prefill) {
|
|
|
73883
73948
|
]]
|
|
73884
73949
|
], [
|
|
73885
73950
|
"button",
|
|
73886
|
-
{
|
|
73951
|
+
name_attrs("save", {
|
|
73887
73952
|
class: "SCHEMA_COL_FORM_SAVE button is-primary",
|
|
73888
73953
|
type: "button"
|
|
73889
|
-
},
|
|
73954
|
+
}),
|
|
73890
73955
|
[[
|
|
73891
73956
|
"span",
|
|
73892
73957
|
{ class: "icon" },
|
|
@@ -73926,7 +73991,8 @@ function open_column_form(gobj, topic, col, prefill) {
|
|
|
73926
73991
|
topic: topic.name,
|
|
73927
73992
|
col: creating ? "" : col.name,
|
|
73928
73993
|
creating,
|
|
73929
|
-
values
|
|
73994
|
+
values,
|
|
73995
|
+
model_gen
|
|
73930
73996
|
}, gobj);
|
|
73931
73997
|
});
|
|
73932
73998
|
open_dialog(gobj, $form, creating ? "new column" : "edit column", "SCHEMA_COL_FORM_DIALOG", creating ? topic.name : `${topic.name}.${col.name}`);
|
|
@@ -73949,6 +74015,7 @@ function open_topic_form(gobj, treedb, topic) {
|
|
|
73949
74015
|
let record = topic && topic.record || {};
|
|
73950
74016
|
let creating = !topic;
|
|
73951
74017
|
let col_names = topic ? topic.cols.map((c) => c.name) : [];
|
|
74018
|
+
let model_gen = gobj.priv.model_gen;
|
|
73952
74019
|
let $form = (0, _yuneta_gobj_js.createElement2)([
|
|
73953
74020
|
"div",
|
|
73954
74021
|
{ class: "SCHEMA_TOPIC_FORM box" },
|
|
@@ -74007,10 +74074,10 @@ function open_topic_form(gobj, treedb, topic) {
|
|
|
74007
74074
|
},
|
|
74008
74075
|
[[
|
|
74009
74076
|
"button",
|
|
74010
|
-
{
|
|
74077
|
+
name_attrs("cancel", {
|
|
74011
74078
|
class: "SCHEMA_TOPIC_FORM_CANCEL button",
|
|
74012
74079
|
type: "button"
|
|
74013
|
-
},
|
|
74080
|
+
}),
|
|
74014
74081
|
[[
|
|
74015
74082
|
"span",
|
|
74016
74083
|
{ i18n: "cancel" },
|
|
@@ -74018,10 +74085,10 @@ function open_topic_form(gobj, treedb, topic) {
|
|
|
74018
74085
|
]]
|
|
74019
74086
|
], [
|
|
74020
74087
|
"button",
|
|
74021
|
-
{
|
|
74088
|
+
name_attrs("save", {
|
|
74022
74089
|
class: "SCHEMA_TOPIC_FORM_SAVE button is-primary",
|
|
74023
74090
|
type: "button"
|
|
74024
|
-
},
|
|
74091
|
+
}),
|
|
74025
74092
|
[[
|
|
74026
74093
|
"span",
|
|
74027
74094
|
{ class: "icon" },
|
|
@@ -74044,7 +74111,8 @@ function open_topic_form(gobj, treedb, topic) {
|
|
|
74044
74111
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_SAVE_TOPIC", {
|
|
74045
74112
|
topic: creating ? "" : topic.name,
|
|
74046
74113
|
creating,
|
|
74047
|
-
values: read_form($form)
|
|
74114
|
+
values: read_form($form),
|
|
74115
|
+
model_gen
|
|
74048
74116
|
}, gobj);
|
|
74049
74117
|
});
|
|
74050
74118
|
open_dialog(gobj, $form, creating ? "new topic" : "edit topic", "SCHEMA_TOPIC_FORM_DIALOG", creating ? treedb.id : `${treedb.id}.${topic.name}`);
|
|
@@ -74324,6 +74392,7 @@ function copy_text(gobj, $text) {
|
|
|
74324
74392
|
* plan itself, so what is confirmed is what runs.
|
|
74325
74393
|
***************************************************************/
|
|
74326
74394
|
function open_import(gobj, treedb) {
|
|
74395
|
+
let model_gen = gobj.priv.model_gen;
|
|
74327
74396
|
let $content = (0, _yuneta_gobj_js.createElement2)([
|
|
74328
74397
|
"div",
|
|
74329
74398
|
{ class: "SCHEMA_IMPORT box" },
|
|
@@ -74338,12 +74407,12 @@ function open_import(gobj, treedb) {
|
|
|
74338
74407
|
],
|
|
74339
74408
|
[
|
|
74340
74409
|
"textarea",
|
|
74341
|
-
{
|
|
74410
|
+
name_attrs("schema", {
|
|
74342
74411
|
class: "SCHEMA_IMPORT_TEXT textarea is-small is-family-monospace",
|
|
74343
74412
|
rows: "12",
|
|
74344
74413
|
spellcheck: "false",
|
|
74345
74414
|
placeholder: "{\"id\": \"...\", \"schema_version\": \"1\", \"topics\": []}"
|
|
74346
|
-
},
|
|
74415
|
+
}),
|
|
74347
74416
|
""
|
|
74348
74417
|
],
|
|
74349
74418
|
[
|
|
@@ -74376,10 +74445,10 @@ function open_import(gobj, treedb) {
|
|
|
74376
74445
|
[
|
|
74377
74446
|
[
|
|
74378
74447
|
"button",
|
|
74379
|
-
{
|
|
74448
|
+
name_attrs("cancel", {
|
|
74380
74449
|
class: "SCHEMA_IMPORT_CANCEL button",
|
|
74381
74450
|
type: "button"
|
|
74382
|
-
},
|
|
74451
|
+
}),
|
|
74383
74452
|
[[
|
|
74384
74453
|
"span",
|
|
74385
74454
|
{ i18n: "cancel" },
|
|
@@ -74388,10 +74457,10 @@ function open_import(gobj, treedb) {
|
|
|
74388
74457
|
],
|
|
74389
74458
|
[
|
|
74390
74459
|
"button",
|
|
74391
|
-
{
|
|
74460
|
+
name_attrs("preview", {
|
|
74392
74461
|
class: "SCHEMA_IMPORT_PREVIEW button",
|
|
74393
74462
|
type: "button"
|
|
74394
|
-
},
|
|
74463
|
+
}),
|
|
74395
74464
|
[[
|
|
74396
74465
|
"span",
|
|
74397
74466
|
{ class: "icon" },
|
|
@@ -74404,11 +74473,11 @@ function open_import(gobj, treedb) {
|
|
|
74404
74473
|
],
|
|
74405
74474
|
[
|
|
74406
74475
|
"button",
|
|
74407
|
-
{
|
|
74476
|
+
name_attrs("import", {
|
|
74408
74477
|
class: "SCHEMA_IMPORT_RUN button is-warning",
|
|
74409
74478
|
type: "button",
|
|
74410
74479
|
disabled: "disabled"
|
|
74411
|
-
},
|
|
74480
|
+
}),
|
|
74412
74481
|
[[
|
|
74413
74482
|
"span",
|
|
74414
74483
|
{ class: "icon" },
|
|
@@ -74435,18 +74504,31 @@ function open_import(gobj, treedb) {
|
|
|
74435
74504
|
evt.stopPropagation();
|
|
74436
74505
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_PREVIEW_IMPORT", {
|
|
74437
74506
|
text: $text.value,
|
|
74438
|
-
prune: $prune.checked
|
|
74507
|
+
prune: $prune.checked,
|
|
74508
|
+
model_gen
|
|
74439
74509
|
}, gobj);
|
|
74440
74510
|
});
|
|
74441
74511
|
$run.addEventListener("click", (evt) => {
|
|
74442
74512
|
evt.stopPropagation();
|
|
74443
|
-
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_APPLY_IMPORT", {}, gobj);
|
|
74513
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_APPLY_IMPORT", { model_gen }, gobj);
|
|
74444
74514
|
});
|
|
74445
74515
|
gobj.priv.import_pane = $plan_pane;
|
|
74446
74516
|
gobj.priv.import_run = $run;
|
|
74447
74517
|
open_dialog(gobj, $content, "import", "SCHEMA_IMPORT_DIALOG", treedb.id);
|
|
74448
74518
|
}
|
|
74449
74519
|
/***************************************************************
|
|
74520
|
+
* The plan is a list of writes computed against the model shown:
|
|
74521
|
+
* a load replaces the model, so the plan goes with it and the
|
|
74522
|
+
* dialog, if it stays up (a load that failed keeps the model),
|
|
74523
|
+
* asks for a Preview again.
|
|
74524
|
+
***************************************************************/
|
|
74525
|
+
function forget_import_plan(gobj) {
|
|
74526
|
+
let priv = gobj.priv;
|
|
74527
|
+
priv.import_plan = null;
|
|
74528
|
+
clear(priv.import_pane);
|
|
74529
|
+
if (priv.import_run) priv.import_run.disabled = true;
|
|
74530
|
+
}
|
|
74531
|
+
/***************************************************************
|
|
74450
74532
|
* The plan, drawn where the paste is: one line per write, the
|
|
74451
74533
|
* deletions apart and counted, because they are what the
|
|
74452
74534
|
* operator is being asked about.
|
|
@@ -74573,7 +74655,8 @@ function open_orphans(gobj) {
|
|
|
74573
74655
|
{ class: "SCHEMA_ORPHAN_ACTIONS has-text-right" },
|
|
74574
74656
|
readonly ? [] : [row_icon(gobj, "SCHEMA_ORPHAN_DELETE", "yi-trash", "delete", "EV_DELETE_ORPHAN", {
|
|
74575
74657
|
kind,
|
|
74576
|
-
id: entry.id
|
|
74658
|
+
id: entry.id,
|
|
74659
|
+
model_gen: priv.model_gen
|
|
74577
74660
|
})]
|
|
74578
74661
|
]
|
|
74579
74662
|
]
|
|
@@ -74745,6 +74828,10 @@ function transport_dropped(gobj) {
|
|
|
74745
74828
|
priv.load_round++;
|
|
74746
74829
|
priv.pending = 0;
|
|
74747
74830
|
priv.load_error = "";
|
|
74831
|
+
if (priv.records_before) {
|
|
74832
|
+
priv.records = priv.records_before;
|
|
74833
|
+
priv.records_before = null;
|
|
74834
|
+
}
|
|
74748
74835
|
return end_load(gobj);
|
|
74749
74836
|
}
|
|
74750
74837
|
return 0;
|
|
@@ -74755,11 +74842,22 @@ function transport_dropped(gobj) {
|
|
|
74755
74842
|
* in flight (ac_show() kept it), or the one it had. Without a
|
|
74756
74843
|
* model there is no screen to go to: the position is kept for the
|
|
74757
74844
|
* next load, and the editor says why it is empty.
|
|
74845
|
+
*
|
|
74846
|
+
* A dialog built on the model this load REPLACED is closed, and the
|
|
74847
|
+
* operator told to open it again: it shows the old record, and its
|
|
74848
|
+
* Save would write every field of it over the newer one. A load
|
|
74849
|
+
* that failed or never left replaced nothing (`model_gen` did not
|
|
74850
|
+
* move), and the dialog stays with what was typed.
|
|
74758
74851
|
***************************************************************/
|
|
74759
74852
|
function end_load(gobj) {
|
|
74760
74853
|
let priv = gobj.priv;
|
|
74761
74854
|
let seg = priv.pending_seg;
|
|
74762
74855
|
priv.pending_seg = null;
|
|
74856
|
+
if (priv.dialog && priv.dialog_gen !== priv.model_gen) {
|
|
74857
|
+
(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`);
|
|
74858
|
+
close_dialog(gobj);
|
|
74859
|
+
yui_shell_show_error(yui_shell_of(gobj), "the schemas were read again: open the dialog again", { t: i18next.t });
|
|
74860
|
+
}
|
|
74763
74861
|
if (priv.model) {
|
|
74764
74862
|
if (seg !== null) return apply_seg(gobj, seg);
|
|
74765
74863
|
return go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
|
|
@@ -74975,10 +75073,20 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
74975
75073
|
else if (priv.records && Array.isArray(priv.records[topic_name])) priv.records[topic_name] = Array.isArray(data) ? data : [];
|
|
74976
75074
|
if (priv.pending > 0) return 0;
|
|
74977
75075
|
if (priv.load_error) {
|
|
75076
|
+
if (priv.model) {
|
|
75077
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: the schemas could not be read again (${priv.load_error}): the previous ones stay`);
|
|
75078
|
+
priv.records = priv.records_before;
|
|
75079
|
+
priv.records_before = null;
|
|
75080
|
+
priv.reload_on_open = true;
|
|
75081
|
+
yui_shell_show_error(yui_shell_of(gobj), "cannot read the schemas again: the previous ones stay", { t: i18next.t });
|
|
75082
|
+
return end_load(gobj);
|
|
75083
|
+
}
|
|
74978
75084
|
priv.model = null;
|
|
74979
75085
|
return end_load(gobj);
|
|
74980
75086
|
}
|
|
74981
75087
|
priv.order_undo = {};
|
|
75088
|
+
priv.records_before = null;
|
|
75089
|
+
priv.model_gen++;
|
|
74982
75090
|
build_model(gobj);
|
|
74983
75091
|
start_measuring(gobj);
|
|
74984
75092
|
return end_load(gobj);
|
|
@@ -75000,11 +75108,14 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
75000
75108
|
let record = (0, _yuneta_gobj_js.is_object)(data) ? data : Array.isArray(data) && (0, _yuneta_gobj_js.is_object)(data[0]) ? data[0] : null;
|
|
75001
75109
|
if (record) patch_record(gobj, topic_name, record);
|
|
75002
75110
|
else {
|
|
75003
|
-
|
|
75111
|
+
let not_sent = priv.save_queue.length - 1;
|
|
75112
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: '${command}' answered no record` + (not_sent > 0 ? `: ${not_sent} write(s) after it were not sent` : ""));
|
|
75113
|
+
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 });
|
|
75004
75114
|
if (topic_name === T_TOPICS || topic_name === T_COLS) {
|
|
75005
75115
|
let write = priv.save_queue[0];
|
|
75006
75116
|
mark_written(gobj, topic_name, write ? write.record : null);
|
|
75007
75117
|
}
|
|
75118
|
+
priv.reload_after_write = false;
|
|
75008
75119
|
priv.save_queue = [];
|
|
75009
75120
|
priv.save_return = "";
|
|
75010
75121
|
priv.save_wrote = false;
|
|
@@ -75062,8 +75173,14 @@ function late_write_done(gobj, command, topic_name, data) {
|
|
|
75062
75173
|
/***************************************************************
|
|
75063
75174
|
* The topic a record written belongs to, read off the RECORD and
|
|
75064
75175
|
* not off the screen: a write answered late may be about a topic
|
|
75065
|
-
* the operator has left. A column names its topic in its fkey
|
|
75066
|
-
*
|
|
75176
|
+
* the operator has left. A column names its topic in its fkey; a
|
|
75177
|
+
* topic is its own id.
|
|
75178
|
+
*
|
|
75179
|
+
* The fkey is read with parse_fkey_ref(), because the store answers
|
|
75180
|
+
* in list_dict -- `[{topic_name, id, hook_name}]` -- and not in the
|
|
75181
|
+
* `topics^<topic id>^cols` strings this view writes. Split as a
|
|
75182
|
+
* string, every production answer marked nothing (fourth independent
|
|
75183
|
+
* review, probe C).
|
|
75067
75184
|
***************************************************************/
|
|
75068
75185
|
function mark_written_record(gobj, topic_name, record) {
|
|
75069
75186
|
let priv = gobj.priv;
|
|
@@ -75073,11 +75190,7 @@ function mark_written_record(gobj, topic_name, record) {
|
|
|
75073
75190
|
return;
|
|
75074
75191
|
}
|
|
75075
75192
|
if (topic_name !== T_COLS) return;
|
|
75076
|
-
let
|
|
75077
|
-
for (let ref of refs) {
|
|
75078
|
-
let parts = String(ref).split("^");
|
|
75079
|
-
if (parts.length >= 2 && parts[1]) priv.written[parts[1]] = true;
|
|
75080
|
-
}
|
|
75193
|
+
for (let ref of parse_fkey_ref(record.topics)) priv.written[ref.id] = true;
|
|
75081
75194
|
}
|
|
75082
75195
|
/***************************************************************
|
|
75083
75196
|
* Remember which topic this write belongs to, which is what
|
|
@@ -75161,14 +75274,19 @@ function ac_refresh$1(gobj, event, kw, src) {
|
|
|
75161
75274
|
* operator can still reach, and what it asks is computed against
|
|
75162
75275
|
* a model the answers in the air are about to replace.
|
|
75163
75276
|
*
|
|
75164
|
-
* Refused, and SAID
|
|
75165
|
-
*
|
|
75166
|
-
*
|
|
75167
|
-
*
|
|
75277
|
+
* Refused, and SAID. Undeclared, it answered "Event NOT DEFINED
|
|
75278
|
+
* in state ST_LOADING" and the edit was gone with no word (third
|
|
75279
|
+
* independent review).
|
|
75280
|
+
*
|
|
75281
|
+
* And NOT "try again": the same Save, once the load was in, sent
|
|
75282
|
+
* the form built on the old model -- every field of the old record
|
|
75283
|
+
* over the newer one (fourth independent review). The load that
|
|
75284
|
+
* lands closes such a dialog (end_load()); one that fails leaves it
|
|
75285
|
+
* up, on the model it was built on.
|
|
75168
75286
|
***************************************************************/
|
|
75169
75287
|
function ac_wait_for_the_load(gobj, event, kw, src) {
|
|
75170
75288
|
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} refused, the schemas are loading`);
|
|
75171
|
-
yui_shell_show_error(yui_shell_of(gobj), "the schemas are loading:
|
|
75289
|
+
yui_shell_show_error(yui_shell_of(gobj), "the schemas are loading: wait for them", { t: i18next.t });
|
|
75172
75290
|
return -1;
|
|
75173
75291
|
}
|
|
75174
75292
|
/***************************************************************
|
|
@@ -75234,6 +75352,7 @@ function ac_show_orphans(gobj, event, kw, src) {
|
|
|
75234
75352
|
* to feed.
|
|
75235
75353
|
***************************************************************/
|
|
75236
75354
|
function confirm_then(gobj, message, detail, kw) {
|
|
75355
|
+
kw = Object.assign({ model_gen: gobj.priv.model_gen }, kw);
|
|
75237
75356
|
yui_shell_confirm_danger(yui_shell_of(gobj), message, {
|
|
75238
75357
|
t: i18next.t,
|
|
75239
75358
|
detail
|
|
@@ -75295,6 +75414,7 @@ function ac_save_column(gobj, event, kw, src) {
|
|
|
75295
75414
|
let topic = find_topic(priv.model, priv.treedb_id, kw.topic);
|
|
75296
75415
|
let col = kw.creating ? null : find_col(priv.model, priv.treedb_id, kw.topic, kw.col);
|
|
75297
75416
|
if (refuse_if_readonly(gobj, event)) return -1;
|
|
75417
|
+
if (built_on_a_replaced_model(gobj, event, kw)) return -1;
|
|
75298
75418
|
if (!topic || !kw.creating && !col) {
|
|
75299
75419
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} names no column: ${kw.topic}.${kw.col}`);
|
|
75300
75420
|
return -1;
|
|
@@ -75416,6 +75536,7 @@ function ac_save_topic(gobj, event, kw, src) {
|
|
|
75416
75536
|
let treedb = current_treedb(gobj);
|
|
75417
75537
|
let topic = kw.creating ? null : find_topic(priv.model, priv.treedb_id, kw.topic);
|
|
75418
75538
|
if (refuse_if_readonly(gobj, event)) return -1;
|
|
75539
|
+
if (built_on_a_replaced_model(gobj, event, kw)) return -1;
|
|
75419
75540
|
if (!treedb || !kw.creating && !topic) {
|
|
75420
75541
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} names no topic: ${kw.topic}`);
|
|
75421
75542
|
return -1;
|
|
@@ -75458,6 +75579,7 @@ function ac_delete_topic(gobj, event, kw, src) {
|
|
|
75458
75579
|
***************************************************************/
|
|
75459
75580
|
function ac_delete_orphan(gobj, event, kw, src) {
|
|
75460
75581
|
if (refuse_if_readonly(gobj, event)) return -1;
|
|
75582
|
+
if (built_on_a_replaced_model(gobj, event, kw)) return -1;
|
|
75461
75583
|
if ((0, _yuneta_gobj_js.empty_string)(kw.id)) {
|
|
75462
75584
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} names nothing`);
|
|
75463
75585
|
return -1;
|
|
@@ -75514,6 +75636,7 @@ function ac_preview_import(gobj, event, kw, src) {
|
|
|
75514
75636
|
let priv = gobj.priv;
|
|
75515
75637
|
let treedb = current_treedb(gobj);
|
|
75516
75638
|
let incoming = null;
|
|
75639
|
+
if (built_on_a_replaced_model(gobj, event, kw)) return -1;
|
|
75517
75640
|
if (!treedb) {
|
|
75518
75641
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no treedb open`);
|
|
75519
75642
|
return -1;
|
|
@@ -75541,6 +75664,7 @@ function ac_preview_import(gobj, event, kw, src) {
|
|
|
75541
75664
|
function ac_apply_import(gobj, event, kw, src) {
|
|
75542
75665
|
let plan = gobj.priv.import_plan;
|
|
75543
75666
|
if (refuse_if_readonly(gobj, event)) return -1;
|
|
75667
|
+
if (built_on_a_replaced_model(gobj, event, kw)) return -1;
|
|
75544
75668
|
if (!plan || plan.writes.length === 0) {
|
|
75545
75669
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no plan to run`);
|
|
75546
75670
|
return -1;
|
|
@@ -75583,6 +75707,7 @@ function run_import(gobj) {
|
|
|
75583
75707
|
function ac_confirmed(gobj, event, kw, src) {
|
|
75584
75708
|
let priv = gobj.priv;
|
|
75585
75709
|
if (refuse_if_readonly(gobj, event)) return -1;
|
|
75710
|
+
if (built_on_a_replaced_model(gobj, event, kw)) return -1;
|
|
75586
75711
|
if (kw.what === "import") return run_import(gobj);
|
|
75587
75712
|
if (kw.what === "topic") {
|
|
75588
75713
|
let topic = find_topic(priv.model, priv.treedb_id, kw.topic);
|