@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.
@@ -3022,12 +3022,20 @@ function maybe_apply_translator($node, opts) {
3022
3022
  * Returns `{ close() }` so callers can dismiss programmatically.
3023
3023
  *
3024
3024
  * ONE toast per message on screen: a string message of the same
3025
- * kind as a toast still showing is not stacked under it -- that
3026
- * toast is kept, its time starts again, and its handle is
3027
- * returned. One close of a transport settles every request it
3028
- * cut, each view shows its failure, and the operator got a
3029
- * column of identical "the connection dropped". A message built
3030
- * of nodes is never merged: its text is not a key.
3025
+ * kind as a toast still showing is not stacked under it. One
3026
+ * close of a transport settles every request it cut, each view
3027
+ * shows its failure, and the operator got a column of identical
3028
+ * "the connection dropped". A message built of nodes is never
3029
+ * merged: its text is not a key.
3030
+ *
3031
+ * A repeat is still a CALLER of its own: it gets its own handle
3032
+ * and its own time, and the toast stays while any caller holds
3033
+ * it -- until every handle is closed or has timed out. Handed the
3034
+ * first caller's handle and timer, a repeat asking `timeout: 0`
3035
+ * was dismissed on the first one's timer, and closing one
3036
+ * caller's handle closed a toast another was still showing
3037
+ * (third independent review). The operator's ✕ closes it for
3038
+ * everybody.
3031
3039
  ***************************************************************/
3032
3040
  function show_notification(shell, kind, message, opts) {
3033
3041
  let $layer = notification_layer(shell);
@@ -3035,12 +3043,10 @@ function show_notification(shell, kind, message, opts) {
3035
3043
  log_warning("yui_shell_show_*: shell has no notification layer");
3036
3044
  return { close: () => {} };
3037
3045
  }
3046
+ let timeout = opts && opts.timeout != null ? opts.timeout : 5e3;
3038
3047
  let key = typeof message === "string" ? `${kind}\u0000${message}` : null;
3039
3048
  if (key !== null) {
3040
- for (let $shown of Array.from($layer.children)) if ($shown.__toast_key__ === key && $shown.__toast__) {
3041
- $shown.__toast__.restart();
3042
- return $shown.__toast__.handle;
3043
- }
3049
+ for (let $shown of Array.from($layer.children)) if ($shown.__toast_key__ === key && $shown.__toast__) return $shown.__toast__.hold(timeout);
3044
3050
  }
3045
3051
  let p_attrs = typeof message === "string" ? { i18n: message } : {};
3046
3052
  let $note = createElement2([
@@ -3051,6 +3057,8 @@ function show_notification(shell, kind, message, opts) {
3051
3057
  },
3052
3058
  [["button", {
3053
3059
  class: "TOAST_CLOSE delete",
3060
+ title: t("close"),
3061
+ "data-i18n-title": "close",
3054
3062
  "aria-label": t("close"),
3055
3063
  "data-i18n-aria-label": "close"
3056
3064
  }], [
@@ -3064,35 +3072,38 @@ function show_notification(shell, kind, message, opts) {
3064
3072
  ]);
3065
3073
  $layer.appendChild($note);
3066
3074
  maybe_apply_translator($note, opts);
3067
- let timeout_id = null;
3075
+ let holders = /* @__PURE__ */ new Set();
3068
3076
  let closed = false;
3069
- let close = function() {
3077
+ let close_toast = function() {
3070
3078
  if (closed) return;
3071
3079
  closed = true;
3072
- if (timeout_id) {
3073
- clearTimeout(timeout_id);
3074
- timeout_id = null;
3080
+ for (let holder of holders) if (holder.timeout_id) {
3081
+ clearTimeout(holder.timeout_id);
3082
+ holder.timeout_id = null;
3075
3083
  }
3084
+ holders.clear();
3076
3085
  if ($note.parentNode) $note.parentNode.removeChild($note);
3077
3086
  };
3078
- let $del = $note.querySelector(".delete");
3079
- if ($del) $del.addEventListener("click", close);
3080
- let timeout = opts && opts.timeout != null ? opts.timeout : 5e3;
3081
- let restart = function() {
3082
- if (timeout_id) {
3083
- clearTimeout(timeout_id);
3084
- timeout_id = null;
3085
- }
3086
- if (timeout > 0) timeout_id = setTimeout(close, timeout);
3087
+ let hold = function(ms) {
3088
+ let holder = { timeout_id: null };
3089
+ let release = function() {
3090
+ if (!holders.has(holder)) return;
3091
+ if (holder.timeout_id) {
3092
+ clearTimeout(holder.timeout_id);
3093
+ holder.timeout_id = null;
3094
+ }
3095
+ holders.delete(holder);
3096
+ if (holders.size === 0) close_toast();
3097
+ };
3098
+ holders.add(holder);
3099
+ if (ms > 0) holder.timeout_id = setTimeout(release, ms);
3100
+ return { close: release };
3087
3101
  };
3088
- restart();
3089
- let handle = { close };
3102
+ let $del = $note.querySelector(".delete");
3103
+ if ($del) $del.addEventListener("click", close_toast);
3090
3104
  $note.__toast_key__ = key;
3091
- $note.__toast__ = {
3092
- handle,
3093
- restart
3094
- };
3095
- return handle;
3105
+ $note.__toast__ = { hold };
3106
+ return hold(timeout);
3096
3107
  }
3097
3108
  function yui_shell_show_info(shell, message, opts) {
3098
3109
  return show_notification(shell, "info", message, opts);
@@ -3171,6 +3182,8 @@ function yui_shell_show_modal(shell, content, opts) {
3171
3182
  {
3172
3183
  class: "MODAL_CLOSE yui-dialog-x",
3173
3184
  type: "button",
3185
+ title: t("close"),
3186
+ "data-i18n-title": "close",
3174
3187
  "aria-label": t("close"),
3175
3188
  "data-i18n-aria-label": "close"
3176
3189
  },
@@ -3192,6 +3205,8 @@ function yui_shell_show_modal(shell, content, opts) {
3192
3205
  ]];
3193
3206
  if (with_close) modal_children.push(["button", {
3194
3207
  class: "MODAL_CLOSE modal-close is-large",
3208
+ title: t("close"),
3209
+ "data-i18n-title": "close",
3195
3210
  "aria-label": t("close"),
3196
3211
  "data-i18n-aria-label": "close"
3197
3212
  }]);
@@ -3346,6 +3361,8 @@ function build_dialog(shell, message, buttons, opts) {
3346
3361
  ]);
3347
3362
  $card_children.push(["button", {
3348
3363
  class: "CONFIRM_CLOSE delete yui-confirm-x",
3364
+ title: t("close"),
3365
+ "data-i18n-title": "close",
3349
3366
  "aria-label": t("close"),
3350
3367
  "data-i18n-aria-label": "close"
3351
3368
  }], [
@@ -72159,10 +72176,13 @@ var attrs_table$1 = [
72159
72176
  ];
72160
72177
  var PRIVATE_DATA$1 = {
72161
72178
  records: null,
72179
+ records_before: null,
72162
72180
  model: null,
72181
+ model_gen: 0,
72163
72182
  pending: 0,
72164
72183
  load_error: "",
72165
72184
  load_round: 0,
72185
+ load_keeps_written: false,
72166
72186
  treedb_id: "",
72167
72187
  topic_name: "",
72168
72188
  diagram: false,
@@ -72173,6 +72193,7 @@ var PRIVATE_DATA$1 = {
72173
72193
  order_undo: null,
72174
72194
  diagram_gobj: null,
72175
72195
  dialog: null,
72196
+ dialog_gen: 0,
72176
72197
  save_queue: null,
72177
72198
  save_return: "",
72178
72199
  save_wrote: false,
@@ -72333,6 +72354,29 @@ function refuse_if_readonly(gobj, event) {
72333
72354
  yui_shell_show_error(yui_shell_of(gobj), "the treedb is read-only", { t });
72334
72355
  return true;
72335
72356
  }
72357
+ /***************************************************************
72358
+ * A decision taken on a model a load has since REPLACED: the Save
72359
+ * of a form, a confirmation, an import. Each carries the
72360
+ * `model_gen` it was built on (a number, not the model: a kw is
72361
+ * dumped by the machine trace).
72362
+ *
72363
+ * Refused, and said. A column form sends every field it shows, so
72364
+ * its Save after a reload wrote the OLD record over the newer one
72365
+ * (fourth independent review, probe A3); a form whose column the
72366
+ * reload removed answered "names no column" for ever. end_load()
72367
+ * closes such a dialog when the load lands; this is the same rule
72368
+ * for whatever arrives anyway -- a stale screen, a confirmation
72369
+ * that was up, a keyboard.
72370
+ *
72371
+ * A kw with no stamp is not a dialog's and is not asked.
72372
+ ***************************************************************/
72373
+ function built_on_a_replaced_model(gobj, event, kw) {
72374
+ let priv = gobj.priv;
72375
+ if (!kw || kw.model_gen === void 0 || kw.model_gen === priv.model_gen) return false;
72376
+ log_warning(`${gobj_short_name(gobj)}: ${event} refused, it was decided on the schemas a reload replaced`);
72377
+ yui_shell_show_error(yui_shell_of(gobj), "the schemas were read again: open the dialog again", { t });
72378
+ return true;
72379
+ }
72336
72380
  /***************************
72337
72381
  * The model
72338
72382
  ***************************/
@@ -72341,10 +72385,36 @@ function refuse_if_readonly(gobj, event) {
72341
72385
  * schema set of the yuno is here: everything below — the
72342
72386
  * drawing, the validation, the export — is computed from these
72343
72387
  * and asks the backend nothing more.
72388
+ *
72389
+ * THE LOADING SCREEN IS DRAWN, not assumed. ST_LOADING declares
72390
+ * none of the actions of a screen, so the screen it replaces goes
72391
+ * and the toolbar stops answering: left up, a click on a card, on
72392
+ * Back or on the drawing answered "Event NOT DEFINED in state
72393
+ * ST_LOADING" and was lost (third independent review). A dialog
72394
+ * left open is answered in ST_LOADING instead (ac_wait_for_the_load),
72395
+ * and a load that LANDS closes it (end_load()): it was built on the
72396
+ * model the load replaced, and its Save sends every field it shows.
72397
+ * An import plan is forgotten here for the same reason: it is a list
72398
+ * of writes computed against the model going away.
72399
+ *
72400
+ * `keep_written`: a load the host did not ask for -- the reconnect,
72401
+ * a write that turned out done -- keeps what this session wrote.
72402
+ * Only the host's EV_REFRESH (a Save sends it) forgets it.
72403
+ *
72404
+ * A load that cannot leave WHOLE did not happen (out of session it
72405
+ * is not even asked): the records the model was built on are put
72406
+ * back (emptied, the next write patched them into a model with no
72407
+ * treedb), the round is spent so a request that did leave is
72408
+ * stale, and the session back asks again. A load that left and
72409
+ * FAILED keeps them the same way (`records_before`,
72410
+ * ac_mt_command_answer()).
72344
72411
  ***************************************************************/
72345
- function request_model(gobj) {
72412
+ function request_model(gobj, keep_written) {
72346
72413
  let priv = gobj.priv;
72347
72414
  if (!gobj_read_pointer_attr(gobj, "gobj_remote_yuno")) return -1;
72415
+ forget_import_plan(gobj);
72416
+ let previous = priv.records;
72417
+ priv.records_before = previous;
72348
72418
  priv.records = {
72349
72419
  treedbs: [],
72350
72420
  topics: [],
@@ -72353,22 +72423,32 @@ function request_model(gobj) {
72353
72423
  priv.load_error = "";
72354
72424
  priv.pending = 0;
72355
72425
  priv.load_round++;
72426
+ priv.load_keeps_written = !!keep_written;
72356
72427
  gobj_change_state(gobj, "ST_LOADING");
72357
- show_notice(gobj, "loading the schemas");
72358
- for (let topic_name of [
72359
- T_TREEDBS,
72360
- T_TOPICS,
72361
- T_COLS
72362
- ]) if (remote_command(gobj, "nodes", {
72363
- topic_name,
72364
- options: { list_dict: true }
72365
- }, { round: priv.load_round }) === 0) priv.pending++;
72366
- if (priv.pending === 0) {
72428
+ set_busy(gobj, false);
72429
+ render(gobj);
72430
+ let left = 0;
72431
+ if (transport_in_session(gobj)) {
72432
+ for (let topic_name of [
72433
+ T_TREEDBS,
72434
+ T_TOPICS,
72435
+ T_COLS
72436
+ ]) if (remote_command(gobj, "nodes", {
72437
+ topic_name,
72438
+ options: { list_dict: true }
72439
+ }, { round: priv.load_round }) === 0) left++;
72440
+ }
72441
+ if (left < 3) {
72442
+ priv.records = previous;
72443
+ priv.records_before = null;
72444
+ priv.load_round++;
72445
+ priv.reload_on_open = true;
72367
72446
  priv.load_error = t("cannot reach the treedb");
72368
- gobj_change_state(gobj, "ST_IDLE");
72369
- show_notice(gobj, "cannot reach the treedb");
72447
+ if (priv.model) yui_shell_show_error(yui_shell_of(gobj), "cannot reach the treedb", { t });
72448
+ end_load(gobj);
72370
72449
  return -1;
72371
72450
  }
72451
+ priv.pending = left;
72372
72452
  return 0;
72373
72453
  }
72374
72454
  /***************************************************************
@@ -72431,15 +72511,19 @@ function build_model(gobj) {
72431
72511
  * From here on, "did this session change it?" has an answer.
72432
72512
  *
72433
72513
  * Called ONLY when records arrive from the store: that is what a
72434
- * measurement of "changed since" can be measured against. Both
72435
- * halves reset together -- a baseline without its `written` is
72436
- * the same false positive from the other side, since every
72437
- * version equals a baseline just taken.
72514
+ * measurement of "changed since" can be measured against.
72515
+ *
72516
+ * `written` is forgotten only by a load the HOST asked for (its
72517
+ * EV_REFRESH, which a Save sends). Since M36 a write moves no
72518
+ * version, so `written` is the draft chip of what this session
72519
+ * wrote and no longer half of a version measurement: a reload of
72520
+ * the reconnect, or of a write that turned out done, forgot the
72521
+ * chips of writes the host had not been told about.
72438
72522
  ***************************************************************/
72439
72523
  function start_measuring(gobj) {
72440
72524
  let priv = gobj.priv;
72441
72525
  priv.baseline = {};
72442
- priv.written = {};
72526
+ if (!priv.load_keeps_written) priv.written = {};
72443
72527
  priv.host_ids = {};
72444
72528
  if (!priv.model) return;
72445
72529
  for (let treedb of priv.model.treedbs) for (let topic of treedb.topics) priv.baseline[topic.id] = topic.topic_version;
@@ -72452,9 +72536,10 @@ function start_measuring(gobj) {
72452
72536
  * until the host saves it (C_TREEDB's save-schema, which raises the
72453
72537
  * versions of what changed). Two sources say a topic is one, and
72454
72538
  * they are kept APART because they are forgotten differently:
72455
- * - `written`: what THIS session wrote since the model was loaded
72456
- * (a reload, the host's EV_REFRESH, forgets it -- the store says
72457
- * what is left);
72539
+ * - `written`: what THIS session wrote. Only a load the HOST asked
72540
+ * for forgets it (its EV_REFRESH, which a Save sends); the
72541
+ * reconnect's reload, the one owed after a write and a late
72542
+ * write's keep it (start_measuring(), request_model());
72458
72543
  * - `host_ids`: what the host said last (EV_DRAFTS), replaced WHOLE
72459
72544
  * by the next EV_DRAFTS. Folded into `written`, a topic the host
72460
72545
  * named once stayed a draft after the Save that published it.
@@ -72621,8 +72706,12 @@ function render_toolbar(gobj) {
72621
72706
  let state = gobj_current_state(gobj);
72622
72707
  let readonly = is_readonly(gobj);
72623
72708
  let has_model = !!priv.model;
72709
+ let on_a_treedb = state !== "ST_IDLE" && state !== "ST_EMPTY";
72710
+ let treedb_here = on_a_treedb && !!current_treedb(gobj);
72711
+ let topic_here = treedb_here && !!current_topic(gobj);
72712
+ let in_flight = state === "ST_SAVING" || state === "ST_LOADING";
72624
72713
  let $left = [];
72625
- if (priv.treedb_id) $left.push([
72714
+ if (priv.treedb_id && on_a_treedb) $left.push([
72626
72715
  "button",
72627
72716
  {
72628
72717
  class: "SCHEMA_BACK button",
@@ -72695,17 +72784,17 @@ function render_toolbar(gobj) {
72695
72784
  $trail
72696
72785
  ]);
72697
72786
  let $right = [];
72698
- if (priv.treedb_id && has_model) {
72787
+ if (priv.treedb_id && has_model && treedb_here) {
72699
72788
  $right.push(toolbar_button("SCHEMA_DIAGRAM_BTN", "yi-compass-drafting", priv.diagram ? "topics" : "diagram", "EV_TOGGLE_DIAGRAM", false));
72700
72789
  $right.push(toolbar_button("SCHEMA_VALIDATE_BTN", "yi-square-check", "check", "EV_VALIDATE", false));
72701
72790
  $right.push(toolbar_button("SCHEMA_EXPORT_BTN", "yi-download", "export", "EV_EXPORT", false));
72702
72791
  if (!readonly) $right.push(toolbar_button("SCHEMA_IMPORT_BTN", "yi-upload", "import", "EV_IMPORT", false));
72703
72792
  }
72704
- if (priv.topic_name && !readonly && !priv.diagram) {
72793
+ if (priv.topic_name && !readonly && !priv.diagram && topic_here) {
72705
72794
  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));
72706
72795
  $right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus", "new column", "EV_ADD_COLUMN", false));
72707
72796
  }
72708
- 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));
72797
+ 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));
72709
72798
  $right.push(toolbar_button("SCHEMA_REFRESH_BTN", "yi-arrows-rotate", "refresh", "EV_REFRESH", state === "ST_LOADING"));
72710
72799
  let $bar = createElement2([
72711
72800
  "div",
@@ -72731,7 +72820,7 @@ function render_toolbar(gobj) {
72731
72820
  ]);
72732
72821
  for (let $button of $bar.querySelectorAll("button")) {
72733
72822
  $button.__gobj__ = gobj;
72734
- if (state === "ST_SAVING") $button.disabled = true;
72823
+ if (in_flight) $button.disabled = true;
72735
72824
  }
72736
72825
  $toolbar.appendChild($bar);
72737
72826
  refresh_language($toolbar, t);
@@ -72749,16 +72838,19 @@ function render(gobj) {
72749
72838
  render_toolbar(gobj);
72750
72839
  if (state === "ST_LOADING") {
72751
72840
  show_notice(gobj, "loading the schemas");
72841
+ destroy_diagram(gobj);
72752
72842
  clear($body);
72753
72843
  return;
72754
72844
  }
72755
72845
  if (state === "ST_IDLE") {
72756
72846
  show_notice(gobj, priv.load_error ? "cannot load the schemas" : "not connected", priv.load_error);
72847
+ destroy_diagram(gobj);
72757
72848
  clear($body);
72758
72849
  return;
72759
72850
  }
72760
72851
  if (state === "ST_EMPTY") {
72761
72852
  show_notice(gobj, "this yuno stores no schema");
72853
+ destroy_diagram(gobj);
72762
72854
  clear($body);
72763
72855
  return;
72764
72856
  }
@@ -73447,12 +73539,16 @@ function render_diagram(gobj) {
73447
73539
  let priv = gobj.priv;
73448
73540
  let $body = $of(gobj, ".SCHEMA_BODY");
73449
73541
  let treedb = current_treedb(gobj);
73450
- if (!$body || !treedb) {
73542
+ if (!$body) return;
73543
+ if (!treedb) {
73544
+ destroy_diagram(gobj);
73545
+ clear($body);
73451
73546
  show_notice(gobj, "that treedb is not here any more", priv.treedb_id);
73452
73547
  return;
73453
73548
  }
73454
73549
  if (!gclass_find_by_name("C_YUI_TREEDB_SCHEMA")) {
73455
73550
  log_error(`${gobj_short_name(gobj)}: C_YUI_TREEDB_SCHEMA not registered by the app`);
73551
+ clear($body);
73456
73552
  show_notice(gobj, "the schema drawing is not available");
73457
73553
  return;
73458
73554
  }
@@ -73518,6 +73614,7 @@ function close_dialog(gobj) {
73518
73614
  function open_dialog(gobj, $content, title, logical, title_prefix) {
73519
73615
  let priv = gobj.priv;
73520
73616
  close_dialog(gobj);
73617
+ priv.dialog_gen = priv.model_gen;
73521
73618
  priv.dialog = yui_shell_show_modal(yui_shell_of(gobj), $content, {
73522
73619
  dialog: true,
73523
73620
  title,
@@ -73564,11 +73661,28 @@ function name_control($spec, label) {
73564
73661
  $spec[1]["aria-label"] = t(label);
73565
73662
  $spec[1]["data-i18n-aria-label"] = label;
73566
73663
  }
73664
+ if (!$spec[1].title) {
73665
+ $spec[1].title = t(label);
73666
+ $spec[1]["data-i18n-title"] = label;
73667
+ }
73567
73668
  return true;
73568
73669
  }
73569
73670
  for (let child of $spec[2] || []) if (name_control(child, label)) return true;
73570
73671
  return false;
73571
73672
  }
73673
+ /***************************************************************
73674
+ * The four attributes that NAME a control -- a title and an
73675
+ * aria-label, each with the key a language change re-translates
73676
+ * it by. A visible label is not a name (CLAUDE.md).
73677
+ ***************************************************************/
73678
+ function name_attrs(key, attrs) {
73679
+ return Object.assign({
73680
+ title: t(key),
73681
+ "data-i18n-title": key,
73682
+ "aria-label": t(key),
73683
+ "data-i18n-aria-label": key
73684
+ }, attrs);
73685
+ }
73572
73686
  function field(logical, name, label, $control, help) {
73573
73687
  name_control($control, label);
73574
73688
  return [
@@ -73745,7 +73859,7 @@ function read_flags($root) {
73745
73859
  * than not offering it.
73746
73860
  ***************************************************************/
73747
73861
  function open_column_form(gobj, topic, col, prefill) {
73748
- gobj.priv;
73862
+ let priv = gobj.priv;
73749
73863
  let record = prefill || col && col.record || {};
73750
73864
  let creating = !col;
73751
73865
  let type = record.type || "string";
@@ -73755,6 +73869,7 @@ function open_column_form(gobj, topic, col, prefill) {
73755
73869
  let hook_col = hook_topic ? hook[hook_topic] : "";
73756
73870
  let treedb = current_treedb(gobj);
73757
73871
  let sibling_topics = treedb ? treedb.topics.map((x) => x.name) : [];
73872
+ let model_gen = priv.model_gen;
73758
73873
  let $form = createElement2([
73759
73874
  "div",
73760
73875
  { class: "SCHEMA_COL_FORM box" },
@@ -73817,10 +73932,10 @@ function open_column_form(gobj, topic, col, prefill) {
73817
73932
  },
73818
73933
  [[
73819
73934
  "button",
73820
- {
73935
+ name_attrs("cancel", {
73821
73936
  class: "SCHEMA_COL_FORM_CANCEL button",
73822
73937
  type: "button"
73823
- },
73938
+ }),
73824
73939
  [[
73825
73940
  "span",
73826
73941
  { i18n: "cancel" },
@@ -73828,10 +73943,10 @@ function open_column_form(gobj, topic, col, prefill) {
73828
73943
  ]]
73829
73944
  ], [
73830
73945
  "button",
73831
- {
73946
+ name_attrs("save", {
73832
73947
  class: "SCHEMA_COL_FORM_SAVE button is-primary",
73833
73948
  type: "button"
73834
- },
73949
+ }),
73835
73950
  [[
73836
73951
  "span",
73837
73952
  { class: "icon" },
@@ -73871,7 +73986,8 @@ function open_column_form(gobj, topic, col, prefill) {
73871
73986
  topic: topic.name,
73872
73987
  col: creating ? "" : col.name,
73873
73988
  creating,
73874
- values
73989
+ values,
73990
+ model_gen
73875
73991
  }, gobj);
73876
73992
  });
73877
73993
  open_dialog(gobj, $form, creating ? "new column" : "edit column", "SCHEMA_COL_FORM_DIALOG", creating ? topic.name : `${topic.name}.${col.name}`);
@@ -73894,6 +74010,7 @@ function open_topic_form(gobj, treedb, topic) {
73894
74010
  let record = topic && topic.record || {};
73895
74011
  let creating = !topic;
73896
74012
  let col_names = topic ? topic.cols.map((c) => c.name) : [];
74013
+ let model_gen = gobj.priv.model_gen;
73897
74014
  let $form = createElement2([
73898
74015
  "div",
73899
74016
  { class: "SCHEMA_TOPIC_FORM box" },
@@ -73952,10 +74069,10 @@ function open_topic_form(gobj, treedb, topic) {
73952
74069
  },
73953
74070
  [[
73954
74071
  "button",
73955
- {
74072
+ name_attrs("cancel", {
73956
74073
  class: "SCHEMA_TOPIC_FORM_CANCEL button",
73957
74074
  type: "button"
73958
- },
74075
+ }),
73959
74076
  [[
73960
74077
  "span",
73961
74078
  { i18n: "cancel" },
@@ -73963,10 +74080,10 @@ function open_topic_form(gobj, treedb, topic) {
73963
74080
  ]]
73964
74081
  ], [
73965
74082
  "button",
73966
- {
74083
+ name_attrs("save", {
73967
74084
  class: "SCHEMA_TOPIC_FORM_SAVE button is-primary",
73968
74085
  type: "button"
73969
- },
74086
+ }),
73970
74087
  [[
73971
74088
  "span",
73972
74089
  { class: "icon" },
@@ -73989,7 +74106,8 @@ function open_topic_form(gobj, treedb, topic) {
73989
74106
  gobj_send_event(gobj, "EV_SAVE_TOPIC", {
73990
74107
  topic: creating ? "" : topic.name,
73991
74108
  creating,
73992
- values: read_form($form)
74109
+ values: read_form($form),
74110
+ model_gen
73993
74111
  }, gobj);
73994
74112
  });
73995
74113
  open_dialog(gobj, $form, creating ? "new topic" : "edit topic", "SCHEMA_TOPIC_FORM_DIALOG", creating ? treedb.id : `${treedb.id}.${topic.name}`);
@@ -74269,6 +74387,7 @@ function copy_text(gobj, $text) {
74269
74387
  * plan itself, so what is confirmed is what runs.
74270
74388
  ***************************************************************/
74271
74389
  function open_import(gobj, treedb) {
74390
+ let model_gen = gobj.priv.model_gen;
74272
74391
  let $content = createElement2([
74273
74392
  "div",
74274
74393
  { class: "SCHEMA_IMPORT box" },
@@ -74283,12 +74402,12 @@ function open_import(gobj, treedb) {
74283
74402
  ],
74284
74403
  [
74285
74404
  "textarea",
74286
- {
74405
+ name_attrs("schema", {
74287
74406
  class: "SCHEMA_IMPORT_TEXT textarea is-small is-family-monospace",
74288
74407
  rows: "12",
74289
74408
  spellcheck: "false",
74290
74409
  placeholder: "{\"id\": \"...\", \"schema_version\": \"1\", \"topics\": []}"
74291
- },
74410
+ }),
74292
74411
  ""
74293
74412
  ],
74294
74413
  [
@@ -74321,10 +74440,10 @@ function open_import(gobj, treedb) {
74321
74440
  [
74322
74441
  [
74323
74442
  "button",
74324
- {
74443
+ name_attrs("cancel", {
74325
74444
  class: "SCHEMA_IMPORT_CANCEL button",
74326
74445
  type: "button"
74327
- },
74446
+ }),
74328
74447
  [[
74329
74448
  "span",
74330
74449
  { i18n: "cancel" },
@@ -74333,10 +74452,10 @@ function open_import(gobj, treedb) {
74333
74452
  ],
74334
74453
  [
74335
74454
  "button",
74336
- {
74455
+ name_attrs("preview", {
74337
74456
  class: "SCHEMA_IMPORT_PREVIEW button",
74338
74457
  type: "button"
74339
- },
74458
+ }),
74340
74459
  [[
74341
74460
  "span",
74342
74461
  { class: "icon" },
@@ -74349,11 +74468,11 @@ function open_import(gobj, treedb) {
74349
74468
  ],
74350
74469
  [
74351
74470
  "button",
74352
- {
74471
+ name_attrs("import", {
74353
74472
  class: "SCHEMA_IMPORT_RUN button is-warning",
74354
74473
  type: "button",
74355
74474
  disabled: "disabled"
74356
- },
74475
+ }),
74357
74476
  [[
74358
74477
  "span",
74359
74478
  { class: "icon" },
@@ -74380,18 +74499,31 @@ function open_import(gobj, treedb) {
74380
74499
  evt.stopPropagation();
74381
74500
  gobj_send_event(gobj, "EV_PREVIEW_IMPORT", {
74382
74501
  text: $text.value,
74383
- prune: $prune.checked
74502
+ prune: $prune.checked,
74503
+ model_gen
74384
74504
  }, gobj);
74385
74505
  });
74386
74506
  $run.addEventListener("click", (evt) => {
74387
74507
  evt.stopPropagation();
74388
- gobj_send_event(gobj, "EV_APPLY_IMPORT", {}, gobj);
74508
+ gobj_send_event(gobj, "EV_APPLY_IMPORT", { model_gen }, gobj);
74389
74509
  });
74390
74510
  gobj.priv.import_pane = $plan_pane;
74391
74511
  gobj.priv.import_run = $run;
74392
74512
  open_dialog(gobj, $content, "import", "SCHEMA_IMPORT_DIALOG", treedb.id);
74393
74513
  }
74394
74514
  /***************************************************************
74515
+ * The plan is a list of writes computed against the model shown:
74516
+ * a load replaces the model, so the plan goes with it and the
74517
+ * dialog, if it stays up (a load that failed keeps the model),
74518
+ * asks for a Preview again.
74519
+ ***************************************************************/
74520
+ function forget_import_plan(gobj) {
74521
+ let priv = gobj.priv;
74522
+ priv.import_plan = null;
74523
+ clear(priv.import_pane);
74524
+ if (priv.import_run) priv.import_run.disabled = true;
74525
+ }
74526
+ /***************************************************************
74395
74527
  * The plan, drawn where the paste is: one line per write, the
74396
74528
  * deletions apart and counted, because they are what the
74397
74529
  * operator is being asked about.
@@ -74518,7 +74650,8 @@ function open_orphans(gobj) {
74518
74650
  { class: "SCHEMA_ORPHAN_ACTIONS has-text-right" },
74519
74651
  readonly ? [] : [row_icon(gobj, "SCHEMA_ORPHAN_DELETE", "yi-trash", "delete", "EV_DELETE_ORPHAN", {
74520
74652
  kind,
74521
- id: entry.id
74653
+ id: entry.id,
74654
+ model_gen: priv.model_gen
74522
74655
  })]
74523
74656
  ]
74524
74657
  ]
@@ -74690,6 +74823,10 @@ function transport_dropped(gobj) {
74690
74823
  priv.load_round++;
74691
74824
  priv.pending = 0;
74692
74825
  priv.load_error = "";
74826
+ if (priv.records_before) {
74827
+ priv.records = priv.records_before;
74828
+ priv.records_before = null;
74829
+ }
74693
74830
  return end_load(gobj);
74694
74831
  }
74695
74832
  return 0;
@@ -74700,11 +74837,22 @@ function transport_dropped(gobj) {
74700
74837
  * in flight (ac_show() kept it), or the one it had. Without a
74701
74838
  * model there is no screen to go to: the position is kept for the
74702
74839
  * next load, and the editor says why it is empty.
74840
+ *
74841
+ * A dialog built on the model this load REPLACED is closed, and the
74842
+ * operator told to open it again: it shows the old record, and its
74843
+ * Save would write every field of it over the newer one. A load
74844
+ * that failed or never left replaced nothing (`model_gen` did not
74845
+ * move), and the dialog stays with what was typed.
74703
74846
  ***************************************************************/
74704
74847
  function end_load(gobj) {
74705
74848
  let priv = gobj.priv;
74706
74849
  let seg = priv.pending_seg;
74707
74850
  priv.pending_seg = null;
74851
+ if (priv.dialog && priv.dialog_gen !== priv.model_gen) {
74852
+ log_warning(`${gobj_short_name(gobj)}: a dialog was open on the schemas the load replaced: closed`);
74853
+ close_dialog(gobj);
74854
+ yui_shell_show_error(yui_shell_of(gobj), "the schemas were read again: open the dialog again", { t });
74855
+ }
74708
74856
  if (priv.model) {
74709
74857
  if (seg !== null) return apply_seg(gobj, seg);
74710
74858
  return go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
@@ -74722,26 +74870,21 @@ function end_load(gobj) {
74722
74870
  ***************************************************************/
74723
74871
  function end_writes(gobj, error) {
74724
74872
  let priv = gobj.priv;
74873
+ let seg = priv.pending_seg;
74725
74874
  priv.save_queue = [];
74875
+ priv.pending_seg = null;
74726
74876
  gobj_change_state(gobj, priv.save_return || "ST_TREEDBS");
74727
74877
  priv.save_return = "";
74728
74878
  show_notice(gobj, "");
74729
74879
  set_busy(gobj, false);
74730
- if (priv.pending_seg !== null) {
74731
- let seg = priv.pending_seg;
74732
- priv.pending_seg = null;
74733
- if (!error) {
74734
- apply_seg(gobj, seg);
74735
- if (priv.save_wrote) gobj_publish_event(gobj, "EV_RECORD_WRITTEN", { treedb_name: gobj_read_str_attr(gobj, "treedb_name") });
74736
- priv.save_wrote = false;
74737
- return reload_if_owed(gobj);
74738
- }
74739
- }
74740
74880
  if (error) yui_shell_show_error(yui_shell_of(gobj), error, { t });
74741
74881
  if (priv.save_wrote) gobj_publish_event(gobj, "EV_RECORD_WRITTEN", { treedb_name: gobj_read_str_attr(gobj, "treedb_name") });
74742
74882
  priv.save_wrote = false;
74743
- render(gobj);
74744
- publish_check(gobj);
74883
+ if (seg !== null) apply_seg(gobj, seg);
74884
+ else {
74885
+ render(gobj);
74886
+ publish_check(gobj);
74887
+ }
74745
74888
  reload_if_owed(gobj);
74746
74889
  return error ? -1 : 0;
74747
74890
  }
@@ -74758,7 +74901,7 @@ function reload_if_owed(gobj) {
74758
74901
  priv.reload_on_open = true;
74759
74902
  return 0;
74760
74903
  }
74761
- return request_model(gobj);
74904
+ return request_model(gobj, true);
74762
74905
  }
74763
74906
  /***************************************************************
74764
74907
  * The record a column form produces.
@@ -74824,6 +74967,7 @@ function topic_record(gobj, treedb, topic, values) {
74824
74967
  ***************************************************************/
74825
74968
  function go(gobj, treedb_id, topic_name, diagram, mirror) {
74826
74969
  let priv = gobj.priv;
74970
+ priv.pending_seg = null;
74827
74971
  priv.treedb_id = treedb_id || "";
74828
74972
  priv.topic_name = topic_name || "";
74829
74973
  priv.diagram = !!diagram;
@@ -74924,10 +75068,20 @@ function ac_mt_command_answer(gobj, event, kw, src) {
74924
75068
  else if (priv.records && Array.isArray(priv.records[topic_name])) priv.records[topic_name] = Array.isArray(data) ? data : [];
74925
75069
  if (priv.pending > 0) return 0;
74926
75070
  if (priv.load_error) {
75071
+ if (priv.model) {
75072
+ log_warning(`${gobj_short_name(gobj)}: the schemas could not be read again (${priv.load_error}): the previous ones stay`);
75073
+ priv.records = priv.records_before;
75074
+ priv.records_before = null;
75075
+ priv.reload_on_open = true;
75076
+ yui_shell_show_error(yui_shell_of(gobj), "cannot read the schemas again: the previous ones stay", { t });
75077
+ return end_load(gobj);
75078
+ }
74927
75079
  priv.model = null;
74928
75080
  return end_load(gobj);
74929
75081
  }
74930
75082
  priv.order_undo = {};
75083
+ priv.records_before = null;
75084
+ priv.model_gen++;
74931
75085
  build_model(gobj);
74932
75086
  start_measuring(gobj);
74933
75087
  return end_load(gobj);
@@ -74940,7 +75094,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
74940
75094
  log_warning(`${gobj_short_name(gobj)}: '${command}' of '${topic_name}' answered for a write that is over (result ${result}): ignored`);
74941
75095
  return 0;
74942
75096
  }
74943
- return late_write_done(gobj, command, topic_name);
75097
+ return late_write_done(gobj, command, topic_name, data);
74944
75098
  }
74945
75099
  if (result < 0) return end_writes(gobj, comment || t("the treedb refused the write"));
74946
75100
  priv.save_wrote = true;
@@ -74949,9 +75103,19 @@ function ac_mt_command_answer(gobj, event, kw, src) {
74949
75103
  let record = is_object(data) ? data : Array.isArray(data) && is_object(data[0]) ? data[0] : null;
74950
75104
  if (record) patch_record(gobj, topic_name, record);
74951
75105
  else {
74952
- log_warning(`${gobj_short_name(gobj)}: '${command}' answered no record`);
75106
+ let not_sent = priv.save_queue.length - 1;
75107
+ log_warning(`${gobj_short_name(gobj)}: '${command}' answered no record` + (not_sent > 0 ? `: ${not_sent} write(s) after it were not sent` : ""));
75108
+ 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 });
75109
+ if (topic_name === T_TOPICS || topic_name === T_COLS) {
75110
+ let write = priv.save_queue[0];
75111
+ mark_written(gobj, topic_name, write ? write.record : null);
75112
+ }
75113
+ priv.reload_after_write = false;
74953
75114
  priv.save_queue = [];
74954
- request_model(gobj);
75115
+ priv.save_return = "";
75116
+ priv.save_wrote = false;
75117
+ gobj_publish_event(gobj, "EV_RECORD_WRITTEN", { treedb_name: gobj_read_str_attr(gobj, "treedb_name") });
75118
+ request_model(gobj, true);
74955
75119
  return 0;
74956
75120
  }
74957
75121
  }
@@ -74978,11 +75142,18 @@ function ac_mt_command_answer(gobj, event, kw, src) {
74978
75142
  * the view was answered once, as failed -- and echoes the node
74979
75143
  * event instead, which this view does not hear: there, Refresh is
74980
75144
  * what reads the store.
75145
+ *
75146
+ * It is a WRITE like any other for the host (EV_RECORD_WRITTEN):
75147
+ * the host was told nothing when it was given up, and it owns the
75148
+ * Save that publishes it. The reload keeps what this session wrote
75149
+ * (request_model()), and the record it answered marks its topic.
74981
75150
  ***************************************************************/
74982
- function late_write_done(gobj, command, topic_name) {
75151
+ function late_write_done(gobj, command, topic_name, data) {
74983
75152
  let priv = gobj.priv;
74984
75153
  let state = gobj_current_state(gobj);
74985
75154
  log_warning(`${gobj_short_name(gobj)}: '${command}' of '${topic_name}' was given up, and it was DONE: the model is read again`);
75155
+ mark_written_record(gobj, topic_name, is_object(data) ? data : Array.isArray(data) && is_object(data[0]) ? data[0] : null);
75156
+ gobj_publish_event(gobj, "EV_RECORD_WRITTEN", { treedb_name: gobj_read_str_attr(gobj, "treedb_name") });
74986
75157
  if (state === "ST_LOADING") return 0;
74987
75158
  if (state === "ST_SAVING") {
74988
75159
  priv.reload_after_write = true;
@@ -74992,7 +75163,29 @@ function late_write_done(gobj, command, topic_name) {
74992
75163
  priv.reload_on_open = true;
74993
75164
  return 0;
74994
75165
  }
74995
- return request_model(gobj);
75166
+ return request_model(gobj, true);
75167
+ }
75168
+ /***************************************************************
75169
+ * The topic a record written belongs to, read off the RECORD and
75170
+ * not off the screen: a write answered late may be about a topic
75171
+ * the operator has left. A column names its topic in its fkey; a
75172
+ * topic is its own id.
75173
+ *
75174
+ * The fkey is read with parse_fkey_ref(), because the store answers
75175
+ * in list_dict -- `[{topic_name, id, hook_name}]` -- and not in the
75176
+ * `topics^<topic id>^cols` strings this view writes. Split as a
75177
+ * string, every production answer marked nothing (fourth independent
75178
+ * review, probe C).
75179
+ ***************************************************************/
75180
+ function mark_written_record(gobj, topic_name, record) {
75181
+ let priv = gobj.priv;
75182
+ if (!record) return;
75183
+ if (topic_name === T_TOPICS && typeof record.id === "string" && record.id) {
75184
+ priv.written[record.id] = true;
75185
+ return;
75186
+ }
75187
+ if (topic_name !== T_COLS) return;
75188
+ for (let ref of parse_fkey_ref(record.topics)) priv.written[ref.id] = true;
74996
75189
  }
74997
75190
  /***************************************************************
74998
75191
  * Remember which topic this write belongs to, which is what
@@ -75051,7 +75244,7 @@ function ac_transport_state(gobj, event, kw, src) {
75051
75244
  }
75052
75245
  if ((!priv.model || priv.reload_on_open) && state !== "ST_LOADING" && state !== "ST_SAVING") {
75053
75246
  priv.reload_on_open = false;
75054
- return request_model(gobj);
75247
+ return request_model(gobj, true);
75055
75248
  }
75056
75249
  render_toolbar(gobj);
75057
75250
  return 0;
@@ -75066,7 +75259,30 @@ function ac_language_changed$1(gobj, event, kw, src) {
75066
75259
  return 0;
75067
75260
  }
75068
75261
  function ac_refresh$1(gobj, event, kw, src) {
75069
- return request_model(gobj);
75262
+ return request_model(gobj, false);
75263
+ }
75264
+ /***************************************************************
75265
+ * What a DIALOG sends while the model is being read again: the
75266
+ * Save of a form left open when the reload started, a
75267
+ * confirmation, an import. The loading screen took the rest of
75268
+ * the view away (request_model()); a dialog is the one thing the
75269
+ * operator can still reach, and what it asks is computed against
75270
+ * a model the answers in the air are about to replace.
75271
+ *
75272
+ * Refused, and SAID. Undeclared, it answered "Event NOT DEFINED
75273
+ * in state ST_LOADING" and the edit was gone with no word (third
75274
+ * independent review).
75275
+ *
75276
+ * And NOT "try again": the same Save, once the load was in, sent
75277
+ * the form built on the old model -- every field of the old record
75278
+ * over the newer one (fourth independent review). The load that
75279
+ * lands closes such a dialog (end_load()); one that fails leaves it
75280
+ * up, on the model it was built on.
75281
+ ***************************************************************/
75282
+ function ac_wait_for_the_load(gobj, event, kw, src) {
75283
+ log_warning(`${gobj_short_name(gobj)}: ${event} refused, the schemas are loading`);
75284
+ yui_shell_show_error(yui_shell_of(gobj), "the schemas are loading: wait for them", { t });
75285
+ return -1;
75070
75286
  }
75071
75287
  /***************************************************************
75072
75288
  * {drafts: {treedb_name: [topic names]}} -- the host says which
@@ -75131,6 +75347,7 @@ function ac_show_orphans(gobj, event, kw, src) {
75131
75347
  * to feed.
75132
75348
  ***************************************************************/
75133
75349
  function confirm_then(gobj, message, detail, kw) {
75350
+ kw = Object.assign({ model_gen: gobj.priv.model_gen }, kw);
75134
75351
  yui_shell_confirm_danger(yui_shell_of(gobj), message, {
75135
75352
  t,
75136
75353
  detail
@@ -75192,6 +75409,7 @@ function ac_save_column(gobj, event, kw, src) {
75192
75409
  let topic = find_topic(priv.model, priv.treedb_id, kw.topic);
75193
75410
  let col = kw.creating ? null : find_col(priv.model, priv.treedb_id, kw.topic, kw.col);
75194
75411
  if (refuse_if_readonly(gobj, event)) return -1;
75412
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75195
75413
  if (!topic || !kw.creating && !col) {
75196
75414
  log_error(`${gobj_short_name(gobj)}: ${event} names no column: ${kw.topic}.${kw.col}`);
75197
75415
  return -1;
@@ -75313,6 +75531,7 @@ function ac_save_topic(gobj, event, kw, src) {
75313
75531
  let treedb = current_treedb(gobj);
75314
75532
  let topic = kw.creating ? null : find_topic(priv.model, priv.treedb_id, kw.topic);
75315
75533
  if (refuse_if_readonly(gobj, event)) return -1;
75534
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75316
75535
  if (!treedb || !kw.creating && !topic) {
75317
75536
  log_error(`${gobj_short_name(gobj)}: ${event} names no topic: ${kw.topic}`);
75318
75537
  return -1;
@@ -75355,6 +75574,7 @@ function ac_delete_topic(gobj, event, kw, src) {
75355
75574
  ***************************************************************/
75356
75575
  function ac_delete_orphan(gobj, event, kw, src) {
75357
75576
  if (refuse_if_readonly(gobj, event)) return -1;
75577
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75358
75578
  if (empty_string(kw.id)) {
75359
75579
  log_error(`${gobj_short_name(gobj)}: ${event} names nothing`);
75360
75580
  return -1;
@@ -75411,6 +75631,7 @@ function ac_preview_import(gobj, event, kw, src) {
75411
75631
  let priv = gobj.priv;
75412
75632
  let treedb = current_treedb(gobj);
75413
75633
  let incoming = null;
75634
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75414
75635
  if (!treedb) {
75415
75636
  log_error(`${gobj_short_name(gobj)}: ${event} with no treedb open`);
75416
75637
  return -1;
@@ -75438,6 +75659,7 @@ function ac_preview_import(gobj, event, kw, src) {
75438
75659
  function ac_apply_import(gobj, event, kw, src) {
75439
75660
  let plan = gobj.priv.import_plan;
75440
75661
  if (refuse_if_readonly(gobj, event)) return -1;
75662
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75441
75663
  if (!plan || plan.writes.length === 0) {
75442
75664
  log_error(`${gobj_short_name(gobj)}: ${event} with no plan to run`);
75443
75665
  return -1;
@@ -75480,6 +75702,7 @@ function run_import(gobj) {
75480
75702
  function ac_confirmed(gobj, event, kw, src) {
75481
75703
  let priv = gobj.priv;
75482
75704
  if (refuse_if_readonly(gobj, event)) return -1;
75705
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75483
75706
  if (kw.what === "import") return run_import(gobj);
75484
75707
  if (kw.what === "topic") {
75485
75708
  let topic = find_topic(priv.model, priv.treedb_id, kw.topic);
@@ -75614,7 +75837,38 @@ function create_gclass$1(gclass_name) {
75614
75837
  ];
75615
75838
  const states = [
75616
75839
  ["ST_IDLE", COMMON.slice()],
75617
- ["ST_LOADING", COMMON.slice()],
75840
+ ["ST_LOADING", COMMON.concat([
75841
+ [
75842
+ "EV_SAVE_COLUMN",
75843
+ ac_wait_for_the_load,
75844
+ null
75845
+ ],
75846
+ [
75847
+ "EV_SAVE_TOPIC",
75848
+ ac_wait_for_the_load,
75849
+ null
75850
+ ],
75851
+ [
75852
+ "EV_DELETE_ORPHAN",
75853
+ ac_wait_for_the_load,
75854
+ null
75855
+ ],
75856
+ [
75857
+ "EV_PREVIEW_IMPORT",
75858
+ ac_wait_for_the_load,
75859
+ null
75860
+ ],
75861
+ [
75862
+ "EV_APPLY_IMPORT",
75863
+ ac_wait_for_the_load,
75864
+ null
75865
+ ],
75866
+ [
75867
+ "EV_CONFIRMED",
75868
+ ac_wait_for_the_load,
75869
+ null
75870
+ ]
75871
+ ])],
75618
75872
  ["ST_EMPTY", COMMON.slice()],
75619
75873
  ["ST_TREEDBS", COMMON.concat([
75620
75874
  [