@yuneta/gobj-ui 7.25.7 → 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 +60 -1
- package/dist/gobj-ui.cjs.js +355 -101
- package/dist/gobj-ui.es.js +355 -101
- package/package.json +1 -1
- package/src/c_yui_schema_editor.js +384 -77
- package/src/schema_editor_reload.wiring.test.js +787 -0
- package/src/shell_modals.js +58 -33
- package/src/shell_toast_once.test.js +106 -3
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -3027,12 +3027,20 @@ function maybe_apply_translator($node, opts) {
|
|
|
3027
3027
|
* Returns `{ close() }` so callers can dismiss programmatically.
|
|
3028
3028
|
*
|
|
3029
3029
|
* ONE toast per message on screen: a string message of the same
|
|
3030
|
-
* kind as a toast still showing is not stacked under it
|
|
3031
|
-
*
|
|
3032
|
-
*
|
|
3033
|
-
*
|
|
3034
|
-
*
|
|
3035
|
-
*
|
|
3030
|
+
* kind as a toast still showing is not stacked under it. One
|
|
3031
|
+
* close of a transport settles every request it cut, each view
|
|
3032
|
+
* shows its failure, and the operator got a column of identical
|
|
3033
|
+
* "the connection dropped". A message built of nodes is never
|
|
3034
|
+
* merged: its text is not a key.
|
|
3035
|
+
*
|
|
3036
|
+
* A repeat is still a CALLER of its own: it gets its own handle
|
|
3037
|
+
* and its own time, and the toast stays while any caller holds
|
|
3038
|
+
* it -- until every handle is closed or has timed out. Handed the
|
|
3039
|
+
* first caller's handle and timer, a repeat asking `timeout: 0`
|
|
3040
|
+
* was dismissed on the first one's timer, and closing one
|
|
3041
|
+
* caller's handle closed a toast another was still showing
|
|
3042
|
+
* (third independent review). The operator's ✕ closes it for
|
|
3043
|
+
* everybody.
|
|
3036
3044
|
***************************************************************/
|
|
3037
3045
|
function show_notification(shell, kind, message, opts) {
|
|
3038
3046
|
let $layer = notification_layer(shell);
|
|
@@ -3040,12 +3048,10 @@ function show_notification(shell, kind, message, opts) {
|
|
|
3040
3048
|
(0, _yuneta_gobj_js.log_warning)("yui_shell_show_*: shell has no notification layer");
|
|
3041
3049
|
return { close: () => {} };
|
|
3042
3050
|
}
|
|
3051
|
+
let timeout = opts && opts.timeout != null ? opts.timeout : 5e3;
|
|
3043
3052
|
let key = typeof message === "string" ? `${kind}\u0000${message}` : null;
|
|
3044
3053
|
if (key !== null) {
|
|
3045
|
-
for (let $shown of Array.from($layer.children)) if ($shown.__toast_key__ === key && $shown.__toast__)
|
|
3046
|
-
$shown.__toast__.restart();
|
|
3047
|
-
return $shown.__toast__.handle;
|
|
3048
|
-
}
|
|
3054
|
+
for (let $shown of Array.from($layer.children)) if ($shown.__toast_key__ === key && $shown.__toast__) return $shown.__toast__.hold(timeout);
|
|
3049
3055
|
}
|
|
3050
3056
|
let p_attrs = typeof message === "string" ? { i18n: message } : {};
|
|
3051
3057
|
let $note = (0, _yuneta_gobj_js.createElement2)([
|
|
@@ -3056,6 +3062,8 @@ function show_notification(shell, kind, message, opts) {
|
|
|
3056
3062
|
},
|
|
3057
3063
|
[["button", {
|
|
3058
3064
|
class: "TOAST_CLOSE delete",
|
|
3065
|
+
title: (0, i18next.t)("close"),
|
|
3066
|
+
"data-i18n-title": "close",
|
|
3059
3067
|
"aria-label": (0, i18next.t)("close"),
|
|
3060
3068
|
"data-i18n-aria-label": "close"
|
|
3061
3069
|
}], [
|
|
@@ -3069,35 +3077,38 @@ function show_notification(shell, kind, message, opts) {
|
|
|
3069
3077
|
]);
|
|
3070
3078
|
$layer.appendChild($note);
|
|
3071
3079
|
maybe_apply_translator($note, opts);
|
|
3072
|
-
let
|
|
3080
|
+
let holders = /* @__PURE__ */ new Set();
|
|
3073
3081
|
let closed = false;
|
|
3074
|
-
let
|
|
3082
|
+
let close_toast = function() {
|
|
3075
3083
|
if (closed) return;
|
|
3076
3084
|
closed = true;
|
|
3077
|
-
if (timeout_id) {
|
|
3078
|
-
clearTimeout(timeout_id);
|
|
3079
|
-
timeout_id = null;
|
|
3085
|
+
for (let holder of holders) if (holder.timeout_id) {
|
|
3086
|
+
clearTimeout(holder.timeout_id);
|
|
3087
|
+
holder.timeout_id = null;
|
|
3080
3088
|
}
|
|
3089
|
+
holders.clear();
|
|
3081
3090
|
if ($note.parentNode) $note.parentNode.removeChild($note);
|
|
3082
3091
|
};
|
|
3083
|
-
let
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
+
let hold = function(ms) {
|
|
3093
|
+
let holder = { timeout_id: null };
|
|
3094
|
+
let release = function() {
|
|
3095
|
+
if (!holders.has(holder)) return;
|
|
3096
|
+
if (holder.timeout_id) {
|
|
3097
|
+
clearTimeout(holder.timeout_id);
|
|
3098
|
+
holder.timeout_id = null;
|
|
3099
|
+
}
|
|
3100
|
+
holders.delete(holder);
|
|
3101
|
+
if (holders.size === 0) close_toast();
|
|
3102
|
+
};
|
|
3103
|
+
holders.add(holder);
|
|
3104
|
+
if (ms > 0) holder.timeout_id = setTimeout(release, ms);
|
|
3105
|
+
return { close: release };
|
|
3092
3106
|
};
|
|
3093
|
-
|
|
3094
|
-
|
|
3107
|
+
let $del = $note.querySelector(".delete");
|
|
3108
|
+
if ($del) $del.addEventListener("click", close_toast);
|
|
3095
3109
|
$note.__toast_key__ = key;
|
|
3096
|
-
$note.__toast__ = {
|
|
3097
|
-
|
|
3098
|
-
restart
|
|
3099
|
-
};
|
|
3100
|
-
return handle;
|
|
3110
|
+
$note.__toast__ = { hold };
|
|
3111
|
+
return hold(timeout);
|
|
3101
3112
|
}
|
|
3102
3113
|
function yui_shell_show_info(shell, message, opts) {
|
|
3103
3114
|
return show_notification(shell, "info", message, opts);
|
|
@@ -3176,6 +3187,8 @@ function yui_shell_show_modal(shell, content, opts) {
|
|
|
3176
3187
|
{
|
|
3177
3188
|
class: "MODAL_CLOSE yui-dialog-x",
|
|
3178
3189
|
type: "button",
|
|
3190
|
+
title: (0, i18next.t)("close"),
|
|
3191
|
+
"data-i18n-title": "close",
|
|
3179
3192
|
"aria-label": (0, i18next.t)("close"),
|
|
3180
3193
|
"data-i18n-aria-label": "close"
|
|
3181
3194
|
},
|
|
@@ -3197,6 +3210,8 @@ function yui_shell_show_modal(shell, content, opts) {
|
|
|
3197
3210
|
]];
|
|
3198
3211
|
if (with_close) modal_children.push(["button", {
|
|
3199
3212
|
class: "MODAL_CLOSE modal-close is-large",
|
|
3213
|
+
title: (0, i18next.t)("close"),
|
|
3214
|
+
"data-i18n-title": "close",
|
|
3200
3215
|
"aria-label": (0, i18next.t)("close"),
|
|
3201
3216
|
"data-i18n-aria-label": "close"
|
|
3202
3217
|
}]);
|
|
@@ -3351,6 +3366,8 @@ function build_dialog(shell, message, buttons, opts) {
|
|
|
3351
3366
|
]);
|
|
3352
3367
|
$card_children.push(["button", {
|
|
3353
3368
|
class: "CONFIRM_CLOSE delete yui-confirm-x",
|
|
3369
|
+
title: (0, i18next.t)("close"),
|
|
3370
|
+
"data-i18n-title": "close",
|
|
3354
3371
|
"aria-label": (0, i18next.t)("close"),
|
|
3355
3372
|
"data-i18n-aria-label": "close"
|
|
3356
3373
|
}], [
|
|
@@ -72164,10 +72181,13 @@ var attrs_table$1 = [
|
|
|
72164
72181
|
];
|
|
72165
72182
|
var PRIVATE_DATA$1 = {
|
|
72166
72183
|
records: null,
|
|
72184
|
+
records_before: null,
|
|
72167
72185
|
model: null,
|
|
72186
|
+
model_gen: 0,
|
|
72168
72187
|
pending: 0,
|
|
72169
72188
|
load_error: "",
|
|
72170
72189
|
load_round: 0,
|
|
72190
|
+
load_keeps_written: false,
|
|
72171
72191
|
treedb_id: "",
|
|
72172
72192
|
topic_name: "",
|
|
72173
72193
|
diagram: false,
|
|
@@ -72178,6 +72198,7 @@ var PRIVATE_DATA$1 = {
|
|
|
72178
72198
|
order_undo: null,
|
|
72179
72199
|
diagram_gobj: null,
|
|
72180
72200
|
dialog: null,
|
|
72201
|
+
dialog_gen: 0,
|
|
72181
72202
|
save_queue: null,
|
|
72182
72203
|
save_return: "",
|
|
72183
72204
|
save_wrote: false,
|
|
@@ -72338,6 +72359,29 @@ function refuse_if_readonly(gobj, event) {
|
|
|
72338
72359
|
yui_shell_show_error(yui_shell_of(gobj), "the treedb is read-only", { t: i18next.t });
|
|
72339
72360
|
return true;
|
|
72340
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
|
+
}
|
|
72341
72385
|
/***************************
|
|
72342
72386
|
* The model
|
|
72343
72387
|
***************************/
|
|
@@ -72346,10 +72390,36 @@ function refuse_if_readonly(gobj, event) {
|
|
|
72346
72390
|
* schema set of the yuno is here: everything below — the
|
|
72347
72391
|
* drawing, the validation, the export — is computed from these
|
|
72348
72392
|
* and asks the backend nothing more.
|
|
72393
|
+
*
|
|
72394
|
+
* THE LOADING SCREEN IS DRAWN, not assumed. ST_LOADING declares
|
|
72395
|
+
* none of the actions of a screen, so the screen it replaces goes
|
|
72396
|
+
* and the toolbar stops answering: left up, a click on a card, on
|
|
72397
|
+
* Back or on the drawing answered "Event NOT DEFINED in state
|
|
72398
|
+
* ST_LOADING" and was lost (third independent review). A dialog
|
|
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.
|
|
72404
|
+
*
|
|
72405
|
+
* `keep_written`: a load the host did not ask for -- the reconnect,
|
|
72406
|
+
* a write that turned out done -- keeps what this session wrote.
|
|
72407
|
+
* Only the host's EV_REFRESH (a Save sends it) forgets it.
|
|
72408
|
+
*
|
|
72409
|
+
* A load that cannot leave WHOLE did not happen (out of session it
|
|
72410
|
+
* is not even asked): the records the model was built on are put
|
|
72411
|
+
* back (emptied, the next write patched them into a model with no
|
|
72412
|
+
* treedb), the round is spent so a request that did leave is
|
|
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()).
|
|
72349
72416
|
***************************************************************/
|
|
72350
|
-
function request_model(gobj) {
|
|
72417
|
+
function request_model(gobj, keep_written) {
|
|
72351
72418
|
let priv = gobj.priv;
|
|
72352
72419
|
if (!(0, _yuneta_gobj_js.gobj_read_pointer_attr)(gobj, "gobj_remote_yuno")) return -1;
|
|
72420
|
+
forget_import_plan(gobj);
|
|
72421
|
+
let previous = priv.records;
|
|
72422
|
+
priv.records_before = previous;
|
|
72353
72423
|
priv.records = {
|
|
72354
72424
|
treedbs: [],
|
|
72355
72425
|
topics: [],
|
|
@@ -72358,22 +72428,32 @@ function request_model(gobj) {
|
|
|
72358
72428
|
priv.load_error = "";
|
|
72359
72429
|
priv.pending = 0;
|
|
72360
72430
|
priv.load_round++;
|
|
72431
|
+
priv.load_keeps_written = !!keep_written;
|
|
72361
72432
|
(0, _yuneta_gobj_js.gobj_change_state)(gobj, "ST_LOADING");
|
|
72362
|
-
|
|
72363
|
-
|
|
72364
|
-
|
|
72365
|
-
|
|
72366
|
-
|
|
72367
|
-
|
|
72368
|
-
|
|
72369
|
-
|
|
72370
|
-
|
|
72371
|
-
|
|
72433
|
+
set_busy(gobj, false);
|
|
72434
|
+
render(gobj);
|
|
72435
|
+
let left = 0;
|
|
72436
|
+
if (transport_in_session(gobj)) {
|
|
72437
|
+
for (let topic_name of [
|
|
72438
|
+
T_TREEDBS,
|
|
72439
|
+
T_TOPICS,
|
|
72440
|
+
T_COLS
|
|
72441
|
+
]) if (remote_command(gobj, "nodes", {
|
|
72442
|
+
topic_name,
|
|
72443
|
+
options: { list_dict: true }
|
|
72444
|
+
}, { round: priv.load_round }) === 0) left++;
|
|
72445
|
+
}
|
|
72446
|
+
if (left < 3) {
|
|
72447
|
+
priv.records = previous;
|
|
72448
|
+
priv.records_before = null;
|
|
72449
|
+
priv.load_round++;
|
|
72450
|
+
priv.reload_on_open = true;
|
|
72372
72451
|
priv.load_error = (0, i18next.t)("cannot reach the treedb");
|
|
72373
|
-
(
|
|
72374
|
-
|
|
72452
|
+
if (priv.model) yui_shell_show_error(yui_shell_of(gobj), "cannot reach the treedb", { t: i18next.t });
|
|
72453
|
+
end_load(gobj);
|
|
72375
72454
|
return -1;
|
|
72376
72455
|
}
|
|
72456
|
+
priv.pending = left;
|
|
72377
72457
|
return 0;
|
|
72378
72458
|
}
|
|
72379
72459
|
/***************************************************************
|
|
@@ -72436,15 +72516,19 @@ function build_model(gobj) {
|
|
|
72436
72516
|
* From here on, "did this session change it?" has an answer.
|
|
72437
72517
|
*
|
|
72438
72518
|
* Called ONLY when records arrive from the store: that is what a
|
|
72439
|
-
* measurement of "changed since" can be measured against.
|
|
72440
|
-
*
|
|
72441
|
-
*
|
|
72442
|
-
*
|
|
72519
|
+
* measurement of "changed since" can be measured against.
|
|
72520
|
+
*
|
|
72521
|
+
* `written` is forgotten only by a load the HOST asked for (its
|
|
72522
|
+
* EV_REFRESH, which a Save sends). Since M36 a write moves no
|
|
72523
|
+
* version, so `written` is the draft chip of what this session
|
|
72524
|
+
* wrote and no longer half of a version measurement: a reload of
|
|
72525
|
+
* the reconnect, or of a write that turned out done, forgot the
|
|
72526
|
+
* chips of writes the host had not been told about.
|
|
72443
72527
|
***************************************************************/
|
|
72444
72528
|
function start_measuring(gobj) {
|
|
72445
72529
|
let priv = gobj.priv;
|
|
72446
72530
|
priv.baseline = {};
|
|
72447
|
-
priv.written = {};
|
|
72531
|
+
if (!priv.load_keeps_written) priv.written = {};
|
|
72448
72532
|
priv.host_ids = {};
|
|
72449
72533
|
if (!priv.model) return;
|
|
72450
72534
|
for (let treedb of priv.model.treedbs) for (let topic of treedb.topics) priv.baseline[topic.id] = topic.topic_version;
|
|
@@ -72457,9 +72541,10 @@ function start_measuring(gobj) {
|
|
|
72457
72541
|
* until the host saves it (C_TREEDB's save-schema, which raises the
|
|
72458
72542
|
* versions of what changed). Two sources say a topic is one, and
|
|
72459
72543
|
* they are kept APART because they are forgotten differently:
|
|
72460
|
-
* - `written`: what THIS session wrote
|
|
72461
|
-
*
|
|
72462
|
-
*
|
|
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());
|
|
72463
72548
|
* - `host_ids`: what the host said last (EV_DRAFTS), replaced WHOLE
|
|
72464
72549
|
* by the next EV_DRAFTS. Folded into `written`, a topic the host
|
|
72465
72550
|
* named once stayed a draft after the Save that published it.
|
|
@@ -72626,8 +72711,12 @@ function render_toolbar(gobj) {
|
|
|
72626
72711
|
let state = (0, _yuneta_gobj_js.gobj_current_state)(gobj);
|
|
72627
72712
|
let readonly = is_readonly(gobj);
|
|
72628
72713
|
let has_model = !!priv.model;
|
|
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);
|
|
72717
|
+
let in_flight = state === "ST_SAVING" || state === "ST_LOADING";
|
|
72629
72718
|
let $left = [];
|
|
72630
|
-
if (priv.treedb_id) $left.push([
|
|
72719
|
+
if (priv.treedb_id && on_a_treedb) $left.push([
|
|
72631
72720
|
"button",
|
|
72632
72721
|
{
|
|
72633
72722
|
class: "SCHEMA_BACK button",
|
|
@@ -72700,17 +72789,17 @@ function render_toolbar(gobj) {
|
|
|
72700
72789
|
$trail
|
|
72701
72790
|
]);
|
|
72702
72791
|
let $right = [];
|
|
72703
|
-
if (priv.treedb_id && has_model) {
|
|
72792
|
+
if (priv.treedb_id && has_model && treedb_here) {
|
|
72704
72793
|
$right.push(toolbar_button("SCHEMA_DIAGRAM_BTN", "yi-compass-drafting", priv.diagram ? "topics" : "diagram", "EV_TOGGLE_DIAGRAM", false));
|
|
72705
72794
|
$right.push(toolbar_button("SCHEMA_VALIDATE_BTN", "yi-square-check", "check", "EV_VALIDATE", false));
|
|
72706
72795
|
$right.push(toolbar_button("SCHEMA_EXPORT_BTN", "yi-download", "export", "EV_EXPORT", false));
|
|
72707
72796
|
if (!readonly) $right.push(toolbar_button("SCHEMA_IMPORT_BTN", "yi-upload", "import", "EV_IMPORT", false));
|
|
72708
72797
|
}
|
|
72709
|
-
if (priv.topic_name && !readonly && !priv.diagram) {
|
|
72798
|
+
if (priv.topic_name && !readonly && !priv.diagram && topic_here) {
|
|
72710
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));
|
|
72711
72800
|
$right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus", "new column", "EV_ADD_COLUMN", false));
|
|
72712
72801
|
}
|
|
72713
|
-
if (priv.treedb_id && !priv.topic_name && !readonly && !priv.diagram) $right.push(toolbar_button("SCHEMA_ADD_TOPIC_BTN", "yi-plus", "new topic", "EV_ADD_TOPIC", false));
|
|
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));
|
|
72714
72803
|
$right.push(toolbar_button("SCHEMA_REFRESH_BTN", "yi-arrows-rotate", "refresh", "EV_REFRESH", state === "ST_LOADING"));
|
|
72715
72804
|
let $bar = (0, _yuneta_gobj_js.createElement2)([
|
|
72716
72805
|
"div",
|
|
@@ -72736,7 +72825,7 @@ function render_toolbar(gobj) {
|
|
|
72736
72825
|
]);
|
|
72737
72826
|
for (let $button of $bar.querySelectorAll("button")) {
|
|
72738
72827
|
$button.__gobj__ = gobj;
|
|
72739
|
-
if (
|
|
72828
|
+
if (in_flight) $button.disabled = true;
|
|
72740
72829
|
}
|
|
72741
72830
|
$toolbar.appendChild($bar);
|
|
72742
72831
|
(0, _yuneta_gobj_js.refresh_language)($toolbar, i18next.t);
|
|
@@ -72754,16 +72843,19 @@ function render(gobj) {
|
|
|
72754
72843
|
render_toolbar(gobj);
|
|
72755
72844
|
if (state === "ST_LOADING") {
|
|
72756
72845
|
show_notice(gobj, "loading the schemas");
|
|
72846
|
+
destroy_diagram(gobj);
|
|
72757
72847
|
clear($body);
|
|
72758
72848
|
return;
|
|
72759
72849
|
}
|
|
72760
72850
|
if (state === "ST_IDLE") {
|
|
72761
72851
|
show_notice(gobj, priv.load_error ? "cannot load the schemas" : "not connected", priv.load_error);
|
|
72852
|
+
destroy_diagram(gobj);
|
|
72762
72853
|
clear($body);
|
|
72763
72854
|
return;
|
|
72764
72855
|
}
|
|
72765
72856
|
if (state === "ST_EMPTY") {
|
|
72766
72857
|
show_notice(gobj, "this yuno stores no schema");
|
|
72858
|
+
destroy_diagram(gobj);
|
|
72767
72859
|
clear($body);
|
|
72768
72860
|
return;
|
|
72769
72861
|
}
|
|
@@ -73452,12 +73544,16 @@ function render_diagram(gobj) {
|
|
|
73452
73544
|
let priv = gobj.priv;
|
|
73453
73545
|
let $body = $of(gobj, ".SCHEMA_BODY");
|
|
73454
73546
|
let treedb = current_treedb(gobj);
|
|
73455
|
-
if (!$body
|
|
73547
|
+
if (!$body) return;
|
|
73548
|
+
if (!treedb) {
|
|
73549
|
+
destroy_diagram(gobj);
|
|
73550
|
+
clear($body);
|
|
73456
73551
|
show_notice(gobj, "that treedb is not here any more", priv.treedb_id);
|
|
73457
73552
|
return;
|
|
73458
73553
|
}
|
|
73459
73554
|
if (!(0, _yuneta_gobj_js.gclass_find_by_name)("C_YUI_TREEDB_SCHEMA")) {
|
|
73460
73555
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: C_YUI_TREEDB_SCHEMA not registered by the app`);
|
|
73556
|
+
clear($body);
|
|
73461
73557
|
show_notice(gobj, "the schema drawing is not available");
|
|
73462
73558
|
return;
|
|
73463
73559
|
}
|
|
@@ -73523,6 +73619,7 @@ function close_dialog(gobj) {
|
|
|
73523
73619
|
function open_dialog(gobj, $content, title, logical, title_prefix) {
|
|
73524
73620
|
let priv = gobj.priv;
|
|
73525
73621
|
close_dialog(gobj);
|
|
73622
|
+
priv.dialog_gen = priv.model_gen;
|
|
73526
73623
|
priv.dialog = yui_shell_show_modal(yui_shell_of(gobj), $content, {
|
|
73527
73624
|
dialog: true,
|
|
73528
73625
|
title,
|
|
@@ -73569,11 +73666,28 @@ function name_control($spec, label) {
|
|
|
73569
73666
|
$spec[1]["aria-label"] = (0, i18next.t)(label);
|
|
73570
73667
|
$spec[1]["data-i18n-aria-label"] = label;
|
|
73571
73668
|
}
|
|
73669
|
+
if (!$spec[1].title) {
|
|
73670
|
+
$spec[1].title = (0, i18next.t)(label);
|
|
73671
|
+
$spec[1]["data-i18n-title"] = label;
|
|
73672
|
+
}
|
|
73572
73673
|
return true;
|
|
73573
73674
|
}
|
|
73574
73675
|
for (let child of $spec[2] || []) if (name_control(child, label)) return true;
|
|
73575
73676
|
return false;
|
|
73576
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
|
+
}
|
|
73577
73691
|
function field(logical, name, label, $control, help) {
|
|
73578
73692
|
name_control($control, label);
|
|
73579
73693
|
return [
|
|
@@ -73750,7 +73864,7 @@ function read_flags($root) {
|
|
|
73750
73864
|
* than not offering it.
|
|
73751
73865
|
***************************************************************/
|
|
73752
73866
|
function open_column_form(gobj, topic, col, prefill) {
|
|
73753
|
-
gobj.priv;
|
|
73867
|
+
let priv = gobj.priv;
|
|
73754
73868
|
let record = prefill || col && col.record || {};
|
|
73755
73869
|
let creating = !col;
|
|
73756
73870
|
let type = record.type || "string";
|
|
@@ -73760,6 +73874,7 @@ function open_column_form(gobj, topic, col, prefill) {
|
|
|
73760
73874
|
let hook_col = hook_topic ? hook[hook_topic] : "";
|
|
73761
73875
|
let treedb = current_treedb(gobj);
|
|
73762
73876
|
let sibling_topics = treedb ? treedb.topics.map((x) => x.name) : [];
|
|
73877
|
+
let model_gen = priv.model_gen;
|
|
73763
73878
|
let $form = (0, _yuneta_gobj_js.createElement2)([
|
|
73764
73879
|
"div",
|
|
73765
73880
|
{ class: "SCHEMA_COL_FORM box" },
|
|
@@ -73822,10 +73937,10 @@ function open_column_form(gobj, topic, col, prefill) {
|
|
|
73822
73937
|
},
|
|
73823
73938
|
[[
|
|
73824
73939
|
"button",
|
|
73825
|
-
{
|
|
73940
|
+
name_attrs("cancel", {
|
|
73826
73941
|
class: "SCHEMA_COL_FORM_CANCEL button",
|
|
73827
73942
|
type: "button"
|
|
73828
|
-
},
|
|
73943
|
+
}),
|
|
73829
73944
|
[[
|
|
73830
73945
|
"span",
|
|
73831
73946
|
{ i18n: "cancel" },
|
|
@@ -73833,10 +73948,10 @@ function open_column_form(gobj, topic, col, prefill) {
|
|
|
73833
73948
|
]]
|
|
73834
73949
|
], [
|
|
73835
73950
|
"button",
|
|
73836
|
-
{
|
|
73951
|
+
name_attrs("save", {
|
|
73837
73952
|
class: "SCHEMA_COL_FORM_SAVE button is-primary",
|
|
73838
73953
|
type: "button"
|
|
73839
|
-
},
|
|
73954
|
+
}),
|
|
73840
73955
|
[[
|
|
73841
73956
|
"span",
|
|
73842
73957
|
{ class: "icon" },
|
|
@@ -73876,7 +73991,8 @@ function open_column_form(gobj, topic, col, prefill) {
|
|
|
73876
73991
|
topic: topic.name,
|
|
73877
73992
|
col: creating ? "" : col.name,
|
|
73878
73993
|
creating,
|
|
73879
|
-
values
|
|
73994
|
+
values,
|
|
73995
|
+
model_gen
|
|
73880
73996
|
}, gobj);
|
|
73881
73997
|
});
|
|
73882
73998
|
open_dialog(gobj, $form, creating ? "new column" : "edit column", "SCHEMA_COL_FORM_DIALOG", creating ? topic.name : `${topic.name}.${col.name}`);
|
|
@@ -73899,6 +74015,7 @@ function open_topic_form(gobj, treedb, topic) {
|
|
|
73899
74015
|
let record = topic && topic.record || {};
|
|
73900
74016
|
let creating = !topic;
|
|
73901
74017
|
let col_names = topic ? topic.cols.map((c) => c.name) : [];
|
|
74018
|
+
let model_gen = gobj.priv.model_gen;
|
|
73902
74019
|
let $form = (0, _yuneta_gobj_js.createElement2)([
|
|
73903
74020
|
"div",
|
|
73904
74021
|
{ class: "SCHEMA_TOPIC_FORM box" },
|
|
@@ -73957,10 +74074,10 @@ function open_topic_form(gobj, treedb, topic) {
|
|
|
73957
74074
|
},
|
|
73958
74075
|
[[
|
|
73959
74076
|
"button",
|
|
73960
|
-
{
|
|
74077
|
+
name_attrs("cancel", {
|
|
73961
74078
|
class: "SCHEMA_TOPIC_FORM_CANCEL button",
|
|
73962
74079
|
type: "button"
|
|
73963
|
-
},
|
|
74080
|
+
}),
|
|
73964
74081
|
[[
|
|
73965
74082
|
"span",
|
|
73966
74083
|
{ i18n: "cancel" },
|
|
@@ -73968,10 +74085,10 @@ function open_topic_form(gobj, treedb, topic) {
|
|
|
73968
74085
|
]]
|
|
73969
74086
|
], [
|
|
73970
74087
|
"button",
|
|
73971
|
-
{
|
|
74088
|
+
name_attrs("save", {
|
|
73972
74089
|
class: "SCHEMA_TOPIC_FORM_SAVE button is-primary",
|
|
73973
74090
|
type: "button"
|
|
73974
|
-
},
|
|
74091
|
+
}),
|
|
73975
74092
|
[[
|
|
73976
74093
|
"span",
|
|
73977
74094
|
{ class: "icon" },
|
|
@@ -73994,7 +74111,8 @@ function open_topic_form(gobj, treedb, topic) {
|
|
|
73994
74111
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_SAVE_TOPIC", {
|
|
73995
74112
|
topic: creating ? "" : topic.name,
|
|
73996
74113
|
creating,
|
|
73997
|
-
values: read_form($form)
|
|
74114
|
+
values: read_form($form),
|
|
74115
|
+
model_gen
|
|
73998
74116
|
}, gobj);
|
|
73999
74117
|
});
|
|
74000
74118
|
open_dialog(gobj, $form, creating ? "new topic" : "edit topic", "SCHEMA_TOPIC_FORM_DIALOG", creating ? treedb.id : `${treedb.id}.${topic.name}`);
|
|
@@ -74274,6 +74392,7 @@ function copy_text(gobj, $text) {
|
|
|
74274
74392
|
* plan itself, so what is confirmed is what runs.
|
|
74275
74393
|
***************************************************************/
|
|
74276
74394
|
function open_import(gobj, treedb) {
|
|
74395
|
+
let model_gen = gobj.priv.model_gen;
|
|
74277
74396
|
let $content = (0, _yuneta_gobj_js.createElement2)([
|
|
74278
74397
|
"div",
|
|
74279
74398
|
{ class: "SCHEMA_IMPORT box" },
|
|
@@ -74288,12 +74407,12 @@ function open_import(gobj, treedb) {
|
|
|
74288
74407
|
],
|
|
74289
74408
|
[
|
|
74290
74409
|
"textarea",
|
|
74291
|
-
{
|
|
74410
|
+
name_attrs("schema", {
|
|
74292
74411
|
class: "SCHEMA_IMPORT_TEXT textarea is-small is-family-monospace",
|
|
74293
74412
|
rows: "12",
|
|
74294
74413
|
spellcheck: "false",
|
|
74295
74414
|
placeholder: "{\"id\": \"...\", \"schema_version\": \"1\", \"topics\": []}"
|
|
74296
|
-
},
|
|
74415
|
+
}),
|
|
74297
74416
|
""
|
|
74298
74417
|
],
|
|
74299
74418
|
[
|
|
@@ -74326,10 +74445,10 @@ function open_import(gobj, treedb) {
|
|
|
74326
74445
|
[
|
|
74327
74446
|
[
|
|
74328
74447
|
"button",
|
|
74329
|
-
{
|
|
74448
|
+
name_attrs("cancel", {
|
|
74330
74449
|
class: "SCHEMA_IMPORT_CANCEL button",
|
|
74331
74450
|
type: "button"
|
|
74332
|
-
},
|
|
74451
|
+
}),
|
|
74333
74452
|
[[
|
|
74334
74453
|
"span",
|
|
74335
74454
|
{ i18n: "cancel" },
|
|
@@ -74338,10 +74457,10 @@ function open_import(gobj, treedb) {
|
|
|
74338
74457
|
],
|
|
74339
74458
|
[
|
|
74340
74459
|
"button",
|
|
74341
|
-
{
|
|
74460
|
+
name_attrs("preview", {
|
|
74342
74461
|
class: "SCHEMA_IMPORT_PREVIEW button",
|
|
74343
74462
|
type: "button"
|
|
74344
|
-
},
|
|
74463
|
+
}),
|
|
74345
74464
|
[[
|
|
74346
74465
|
"span",
|
|
74347
74466
|
{ class: "icon" },
|
|
@@ -74354,11 +74473,11 @@ function open_import(gobj, treedb) {
|
|
|
74354
74473
|
],
|
|
74355
74474
|
[
|
|
74356
74475
|
"button",
|
|
74357
|
-
{
|
|
74476
|
+
name_attrs("import", {
|
|
74358
74477
|
class: "SCHEMA_IMPORT_RUN button is-warning",
|
|
74359
74478
|
type: "button",
|
|
74360
74479
|
disabled: "disabled"
|
|
74361
|
-
},
|
|
74480
|
+
}),
|
|
74362
74481
|
[[
|
|
74363
74482
|
"span",
|
|
74364
74483
|
{ class: "icon" },
|
|
@@ -74385,18 +74504,31 @@ function open_import(gobj, treedb) {
|
|
|
74385
74504
|
evt.stopPropagation();
|
|
74386
74505
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_PREVIEW_IMPORT", {
|
|
74387
74506
|
text: $text.value,
|
|
74388
|
-
prune: $prune.checked
|
|
74507
|
+
prune: $prune.checked,
|
|
74508
|
+
model_gen
|
|
74389
74509
|
}, gobj);
|
|
74390
74510
|
});
|
|
74391
74511
|
$run.addEventListener("click", (evt) => {
|
|
74392
74512
|
evt.stopPropagation();
|
|
74393
|
-
(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);
|
|
74394
74514
|
});
|
|
74395
74515
|
gobj.priv.import_pane = $plan_pane;
|
|
74396
74516
|
gobj.priv.import_run = $run;
|
|
74397
74517
|
open_dialog(gobj, $content, "import", "SCHEMA_IMPORT_DIALOG", treedb.id);
|
|
74398
74518
|
}
|
|
74399
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
|
+
/***************************************************************
|
|
74400
74532
|
* The plan, drawn where the paste is: one line per write, the
|
|
74401
74533
|
* deletions apart and counted, because they are what the
|
|
74402
74534
|
* operator is being asked about.
|
|
@@ -74523,7 +74655,8 @@ function open_orphans(gobj) {
|
|
|
74523
74655
|
{ class: "SCHEMA_ORPHAN_ACTIONS has-text-right" },
|
|
74524
74656
|
readonly ? [] : [row_icon(gobj, "SCHEMA_ORPHAN_DELETE", "yi-trash", "delete", "EV_DELETE_ORPHAN", {
|
|
74525
74657
|
kind,
|
|
74526
|
-
id: entry.id
|
|
74658
|
+
id: entry.id,
|
|
74659
|
+
model_gen: priv.model_gen
|
|
74527
74660
|
})]
|
|
74528
74661
|
]
|
|
74529
74662
|
]
|
|
@@ -74695,6 +74828,10 @@ function transport_dropped(gobj) {
|
|
|
74695
74828
|
priv.load_round++;
|
|
74696
74829
|
priv.pending = 0;
|
|
74697
74830
|
priv.load_error = "";
|
|
74831
|
+
if (priv.records_before) {
|
|
74832
|
+
priv.records = priv.records_before;
|
|
74833
|
+
priv.records_before = null;
|
|
74834
|
+
}
|
|
74698
74835
|
return end_load(gobj);
|
|
74699
74836
|
}
|
|
74700
74837
|
return 0;
|
|
@@ -74705,11 +74842,22 @@ function transport_dropped(gobj) {
|
|
|
74705
74842
|
* in flight (ac_show() kept it), or the one it had. Without a
|
|
74706
74843
|
* model there is no screen to go to: the position is kept for the
|
|
74707
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.
|
|
74708
74851
|
***************************************************************/
|
|
74709
74852
|
function end_load(gobj) {
|
|
74710
74853
|
let priv = gobj.priv;
|
|
74711
74854
|
let seg = priv.pending_seg;
|
|
74712
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
|
+
}
|
|
74713
74861
|
if (priv.model) {
|
|
74714
74862
|
if (seg !== null) return apply_seg(gobj, seg);
|
|
74715
74863
|
return go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
|
|
@@ -74727,26 +74875,21 @@ function end_load(gobj) {
|
|
|
74727
74875
|
***************************************************************/
|
|
74728
74876
|
function end_writes(gobj, error) {
|
|
74729
74877
|
let priv = gobj.priv;
|
|
74878
|
+
let seg = priv.pending_seg;
|
|
74730
74879
|
priv.save_queue = [];
|
|
74880
|
+
priv.pending_seg = null;
|
|
74731
74881
|
(0, _yuneta_gobj_js.gobj_change_state)(gobj, priv.save_return || "ST_TREEDBS");
|
|
74732
74882
|
priv.save_return = "";
|
|
74733
74883
|
show_notice(gobj, "");
|
|
74734
74884
|
set_busy(gobj, false);
|
|
74735
|
-
if (priv.pending_seg !== null) {
|
|
74736
|
-
let seg = priv.pending_seg;
|
|
74737
|
-
priv.pending_seg = null;
|
|
74738
|
-
if (!error) {
|
|
74739
|
-
apply_seg(gobj, seg);
|
|
74740
|
-
if (priv.save_wrote) (0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_RECORD_WRITTEN", { treedb_name: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name") });
|
|
74741
|
-
priv.save_wrote = false;
|
|
74742
|
-
return reload_if_owed(gobj);
|
|
74743
|
-
}
|
|
74744
|
-
}
|
|
74745
74885
|
if (error) yui_shell_show_error(yui_shell_of(gobj), error, { t: i18next.t });
|
|
74746
74886
|
if (priv.save_wrote) (0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_RECORD_WRITTEN", { treedb_name: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name") });
|
|
74747
74887
|
priv.save_wrote = false;
|
|
74748
|
-
|
|
74749
|
-
|
|
74888
|
+
if (seg !== null) apply_seg(gobj, seg);
|
|
74889
|
+
else {
|
|
74890
|
+
render(gobj);
|
|
74891
|
+
publish_check(gobj);
|
|
74892
|
+
}
|
|
74750
74893
|
reload_if_owed(gobj);
|
|
74751
74894
|
return error ? -1 : 0;
|
|
74752
74895
|
}
|
|
@@ -74763,7 +74906,7 @@ function reload_if_owed(gobj) {
|
|
|
74763
74906
|
priv.reload_on_open = true;
|
|
74764
74907
|
return 0;
|
|
74765
74908
|
}
|
|
74766
|
-
return request_model(gobj);
|
|
74909
|
+
return request_model(gobj, true);
|
|
74767
74910
|
}
|
|
74768
74911
|
/***************************************************************
|
|
74769
74912
|
* The record a column form produces.
|
|
@@ -74829,6 +74972,7 @@ function topic_record(gobj, treedb, topic, values) {
|
|
|
74829
74972
|
***************************************************************/
|
|
74830
74973
|
function go(gobj, treedb_id, topic_name, diagram, mirror) {
|
|
74831
74974
|
let priv = gobj.priv;
|
|
74975
|
+
priv.pending_seg = null;
|
|
74832
74976
|
priv.treedb_id = treedb_id || "";
|
|
74833
74977
|
priv.topic_name = topic_name || "";
|
|
74834
74978
|
priv.diagram = !!diagram;
|
|
@@ -74929,10 +75073,20 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
74929
75073
|
else if (priv.records && Array.isArray(priv.records[topic_name])) priv.records[topic_name] = Array.isArray(data) ? data : [];
|
|
74930
75074
|
if (priv.pending > 0) return 0;
|
|
74931
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
|
+
}
|
|
74932
75084
|
priv.model = null;
|
|
74933
75085
|
return end_load(gobj);
|
|
74934
75086
|
}
|
|
74935
75087
|
priv.order_undo = {};
|
|
75088
|
+
priv.records_before = null;
|
|
75089
|
+
priv.model_gen++;
|
|
74936
75090
|
build_model(gobj);
|
|
74937
75091
|
start_measuring(gobj);
|
|
74938
75092
|
return end_load(gobj);
|
|
@@ -74945,7 +75099,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
74945
75099
|
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: '${command}' of '${topic_name}' answered for a write that is over (result ${result}): ignored`);
|
|
74946
75100
|
return 0;
|
|
74947
75101
|
}
|
|
74948
|
-
return late_write_done(gobj, command, topic_name);
|
|
75102
|
+
return late_write_done(gobj, command, topic_name, data);
|
|
74949
75103
|
}
|
|
74950
75104
|
if (result < 0) return end_writes(gobj, comment || (0, i18next.t)("the treedb refused the write"));
|
|
74951
75105
|
priv.save_wrote = true;
|
|
@@ -74954,9 +75108,19 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
74954
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;
|
|
74955
75109
|
if (record) patch_record(gobj, topic_name, record);
|
|
74956
75110
|
else {
|
|
74957
|
-
|
|
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 });
|
|
75114
|
+
if (topic_name === T_TOPICS || topic_name === T_COLS) {
|
|
75115
|
+
let write = priv.save_queue[0];
|
|
75116
|
+
mark_written(gobj, topic_name, write ? write.record : null);
|
|
75117
|
+
}
|
|
75118
|
+
priv.reload_after_write = false;
|
|
74958
75119
|
priv.save_queue = [];
|
|
74959
|
-
|
|
75120
|
+
priv.save_return = "";
|
|
75121
|
+
priv.save_wrote = false;
|
|
75122
|
+
(0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_RECORD_WRITTEN", { treedb_name: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name") });
|
|
75123
|
+
request_model(gobj, true);
|
|
74960
75124
|
return 0;
|
|
74961
75125
|
}
|
|
74962
75126
|
}
|
|
@@ -74983,11 +75147,18 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
74983
75147
|
* the view was answered once, as failed -- and echoes the node
|
|
74984
75148
|
* event instead, which this view does not hear: there, Refresh is
|
|
74985
75149
|
* what reads the store.
|
|
75150
|
+
*
|
|
75151
|
+
* It is a WRITE like any other for the host (EV_RECORD_WRITTEN):
|
|
75152
|
+
* the host was told nothing when it was given up, and it owns the
|
|
75153
|
+
* Save that publishes it. The reload keeps what this session wrote
|
|
75154
|
+
* (request_model()), and the record it answered marks its topic.
|
|
74986
75155
|
***************************************************************/
|
|
74987
|
-
function late_write_done(gobj, command, topic_name) {
|
|
75156
|
+
function late_write_done(gobj, command, topic_name, data) {
|
|
74988
75157
|
let priv = gobj.priv;
|
|
74989
75158
|
let state = (0, _yuneta_gobj_js.gobj_current_state)(gobj);
|
|
74990
75159
|
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: '${command}' of '${topic_name}' was given up, and it was DONE: the model is read again`);
|
|
75160
|
+
mark_written_record(gobj, topic_name, (0, _yuneta_gobj_js.is_object)(data) ? data : Array.isArray(data) && (0, _yuneta_gobj_js.is_object)(data[0]) ? data[0] : null);
|
|
75161
|
+
(0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_RECORD_WRITTEN", { treedb_name: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name") });
|
|
74991
75162
|
if (state === "ST_LOADING") return 0;
|
|
74992
75163
|
if (state === "ST_SAVING") {
|
|
74993
75164
|
priv.reload_after_write = true;
|
|
@@ -74997,7 +75168,29 @@ function late_write_done(gobj, command, topic_name) {
|
|
|
74997
75168
|
priv.reload_on_open = true;
|
|
74998
75169
|
return 0;
|
|
74999
75170
|
}
|
|
75000
|
-
return request_model(gobj);
|
|
75171
|
+
return request_model(gobj, true);
|
|
75172
|
+
}
|
|
75173
|
+
/***************************************************************
|
|
75174
|
+
* The topic a record written belongs to, read off the RECORD and
|
|
75175
|
+
* not off the screen: a write answered late may be about a topic
|
|
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).
|
|
75184
|
+
***************************************************************/
|
|
75185
|
+
function mark_written_record(gobj, topic_name, record) {
|
|
75186
|
+
let priv = gobj.priv;
|
|
75187
|
+
if (!record) return;
|
|
75188
|
+
if (topic_name === T_TOPICS && typeof record.id === "string" && record.id) {
|
|
75189
|
+
priv.written[record.id] = true;
|
|
75190
|
+
return;
|
|
75191
|
+
}
|
|
75192
|
+
if (topic_name !== T_COLS) return;
|
|
75193
|
+
for (let ref of parse_fkey_ref(record.topics)) priv.written[ref.id] = true;
|
|
75001
75194
|
}
|
|
75002
75195
|
/***************************************************************
|
|
75003
75196
|
* Remember which topic this write belongs to, which is what
|
|
@@ -75056,7 +75249,7 @@ function ac_transport_state(gobj, event, kw, src) {
|
|
|
75056
75249
|
}
|
|
75057
75250
|
if ((!priv.model || priv.reload_on_open) && state !== "ST_LOADING" && state !== "ST_SAVING") {
|
|
75058
75251
|
priv.reload_on_open = false;
|
|
75059
|
-
return request_model(gobj);
|
|
75252
|
+
return request_model(gobj, true);
|
|
75060
75253
|
}
|
|
75061
75254
|
render_toolbar(gobj);
|
|
75062
75255
|
return 0;
|
|
@@ -75071,7 +75264,30 @@ function ac_language_changed$1(gobj, event, kw, src) {
|
|
|
75071
75264
|
return 0;
|
|
75072
75265
|
}
|
|
75073
75266
|
function ac_refresh$1(gobj, event, kw, src) {
|
|
75074
|
-
return request_model(gobj);
|
|
75267
|
+
return request_model(gobj, false);
|
|
75268
|
+
}
|
|
75269
|
+
/***************************************************************
|
|
75270
|
+
* What a DIALOG sends while the model is being read again: the
|
|
75271
|
+
* Save of a form left open when the reload started, a
|
|
75272
|
+
* confirmation, an import. The loading screen took the rest of
|
|
75273
|
+
* the view away (request_model()); a dialog is the one thing the
|
|
75274
|
+
* operator can still reach, and what it asks is computed against
|
|
75275
|
+
* a model the answers in the air are about to replace.
|
|
75276
|
+
*
|
|
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.
|
|
75286
|
+
***************************************************************/
|
|
75287
|
+
function ac_wait_for_the_load(gobj, event, kw, src) {
|
|
75288
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} refused, the schemas are loading`);
|
|
75289
|
+
yui_shell_show_error(yui_shell_of(gobj), "the schemas are loading: wait for them", { t: i18next.t });
|
|
75290
|
+
return -1;
|
|
75075
75291
|
}
|
|
75076
75292
|
/***************************************************************
|
|
75077
75293
|
* {drafts: {treedb_name: [topic names]}} -- the host says which
|
|
@@ -75136,6 +75352,7 @@ function ac_show_orphans(gobj, event, kw, src) {
|
|
|
75136
75352
|
* to feed.
|
|
75137
75353
|
***************************************************************/
|
|
75138
75354
|
function confirm_then(gobj, message, detail, kw) {
|
|
75355
|
+
kw = Object.assign({ model_gen: gobj.priv.model_gen }, kw);
|
|
75139
75356
|
yui_shell_confirm_danger(yui_shell_of(gobj), message, {
|
|
75140
75357
|
t: i18next.t,
|
|
75141
75358
|
detail
|
|
@@ -75197,6 +75414,7 @@ function ac_save_column(gobj, event, kw, src) {
|
|
|
75197
75414
|
let topic = find_topic(priv.model, priv.treedb_id, kw.topic);
|
|
75198
75415
|
let col = kw.creating ? null : find_col(priv.model, priv.treedb_id, kw.topic, kw.col);
|
|
75199
75416
|
if (refuse_if_readonly(gobj, event)) return -1;
|
|
75417
|
+
if (built_on_a_replaced_model(gobj, event, kw)) return -1;
|
|
75200
75418
|
if (!topic || !kw.creating && !col) {
|
|
75201
75419
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} names no column: ${kw.topic}.${kw.col}`);
|
|
75202
75420
|
return -1;
|
|
@@ -75318,6 +75536,7 @@ function ac_save_topic(gobj, event, kw, src) {
|
|
|
75318
75536
|
let treedb = current_treedb(gobj);
|
|
75319
75537
|
let topic = kw.creating ? null : find_topic(priv.model, priv.treedb_id, kw.topic);
|
|
75320
75538
|
if (refuse_if_readonly(gobj, event)) return -1;
|
|
75539
|
+
if (built_on_a_replaced_model(gobj, event, kw)) return -1;
|
|
75321
75540
|
if (!treedb || !kw.creating && !topic) {
|
|
75322
75541
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} names no topic: ${kw.topic}`);
|
|
75323
75542
|
return -1;
|
|
@@ -75360,6 +75579,7 @@ function ac_delete_topic(gobj, event, kw, src) {
|
|
|
75360
75579
|
***************************************************************/
|
|
75361
75580
|
function ac_delete_orphan(gobj, event, kw, src) {
|
|
75362
75581
|
if (refuse_if_readonly(gobj, event)) return -1;
|
|
75582
|
+
if (built_on_a_replaced_model(gobj, event, kw)) return -1;
|
|
75363
75583
|
if ((0, _yuneta_gobj_js.empty_string)(kw.id)) {
|
|
75364
75584
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} names nothing`);
|
|
75365
75585
|
return -1;
|
|
@@ -75416,6 +75636,7 @@ function ac_preview_import(gobj, event, kw, src) {
|
|
|
75416
75636
|
let priv = gobj.priv;
|
|
75417
75637
|
let treedb = current_treedb(gobj);
|
|
75418
75638
|
let incoming = null;
|
|
75639
|
+
if (built_on_a_replaced_model(gobj, event, kw)) return -1;
|
|
75419
75640
|
if (!treedb) {
|
|
75420
75641
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no treedb open`);
|
|
75421
75642
|
return -1;
|
|
@@ -75443,6 +75664,7 @@ function ac_preview_import(gobj, event, kw, src) {
|
|
|
75443
75664
|
function ac_apply_import(gobj, event, kw, src) {
|
|
75444
75665
|
let plan = gobj.priv.import_plan;
|
|
75445
75666
|
if (refuse_if_readonly(gobj, event)) return -1;
|
|
75667
|
+
if (built_on_a_replaced_model(gobj, event, kw)) return -1;
|
|
75446
75668
|
if (!plan || plan.writes.length === 0) {
|
|
75447
75669
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no plan to run`);
|
|
75448
75670
|
return -1;
|
|
@@ -75485,6 +75707,7 @@ function run_import(gobj) {
|
|
|
75485
75707
|
function ac_confirmed(gobj, event, kw, src) {
|
|
75486
75708
|
let priv = gobj.priv;
|
|
75487
75709
|
if (refuse_if_readonly(gobj, event)) return -1;
|
|
75710
|
+
if (built_on_a_replaced_model(gobj, event, kw)) return -1;
|
|
75488
75711
|
if (kw.what === "import") return run_import(gobj);
|
|
75489
75712
|
if (kw.what === "topic") {
|
|
75490
75713
|
let topic = find_topic(priv.model, priv.treedb_id, kw.topic);
|
|
@@ -75619,7 +75842,38 @@ function create_gclass$1(gclass_name) {
|
|
|
75619
75842
|
];
|
|
75620
75843
|
const states = [
|
|
75621
75844
|
["ST_IDLE", COMMON.slice()],
|
|
75622
|
-
["ST_LOADING", COMMON.
|
|
75845
|
+
["ST_LOADING", COMMON.concat([
|
|
75846
|
+
[
|
|
75847
|
+
"EV_SAVE_COLUMN",
|
|
75848
|
+
ac_wait_for_the_load,
|
|
75849
|
+
null
|
|
75850
|
+
],
|
|
75851
|
+
[
|
|
75852
|
+
"EV_SAVE_TOPIC",
|
|
75853
|
+
ac_wait_for_the_load,
|
|
75854
|
+
null
|
|
75855
|
+
],
|
|
75856
|
+
[
|
|
75857
|
+
"EV_DELETE_ORPHAN",
|
|
75858
|
+
ac_wait_for_the_load,
|
|
75859
|
+
null
|
|
75860
|
+
],
|
|
75861
|
+
[
|
|
75862
|
+
"EV_PREVIEW_IMPORT",
|
|
75863
|
+
ac_wait_for_the_load,
|
|
75864
|
+
null
|
|
75865
|
+
],
|
|
75866
|
+
[
|
|
75867
|
+
"EV_APPLY_IMPORT",
|
|
75868
|
+
ac_wait_for_the_load,
|
|
75869
|
+
null
|
|
75870
|
+
],
|
|
75871
|
+
[
|
|
75872
|
+
"EV_CONFIRMED",
|
|
75873
|
+
ac_wait_for_the_load,
|
|
75874
|
+
null
|
|
75875
|
+
]
|
|
75876
|
+
])],
|
|
75623
75877
|
["ST_EMPTY", COMMON.slice()],
|
|
75624
75878
|
["ST_TREEDBS", COMMON.concat([
|
|
75625
75879
|
[
|