@yuneta/gobj-ui 7.25.8 → 7.25.10

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.
@@ -3062,6 +3062,8 @@ function show_notification(shell, kind, message, opts) {
3062
3062
  },
3063
3063
  [["button", {
3064
3064
  class: "TOAST_CLOSE delete",
3065
+ title: (0, i18next.t)("close"),
3066
+ "data-i18n-title": "close",
3065
3067
  "aria-label": (0, i18next.t)("close"),
3066
3068
  "data-i18n-aria-label": "close"
3067
3069
  }], [
@@ -3159,6 +3161,8 @@ function yui_shell_show_modal(shell, content, opts) {
3159
3161
  {
3160
3162
  class: "MODAL_BACK yui-dialog-back",
3161
3163
  type: "button",
3164
+ title: (0, i18next.t)("back"),
3165
+ "data-i18n-title": "back",
3162
3166
  "aria-label": (0, i18next.t)("back"),
3163
3167
  "data-i18n-aria-label": "back"
3164
3168
  },
@@ -3185,6 +3189,8 @@ function yui_shell_show_modal(shell, content, opts) {
3185
3189
  {
3186
3190
  class: "MODAL_CLOSE yui-dialog-x",
3187
3191
  type: "button",
3192
+ title: (0, i18next.t)("close"),
3193
+ "data-i18n-title": "close",
3188
3194
  "aria-label": (0, i18next.t)("close"),
3189
3195
  "data-i18n-aria-label": "close"
3190
3196
  },
@@ -3206,6 +3212,8 @@ function yui_shell_show_modal(shell, content, opts) {
3206
3212
  ]];
3207
3213
  if (with_close) modal_children.push(["button", {
3208
3214
  class: "MODAL_CLOSE modal-close is-large",
3215
+ title: (0, i18next.t)("close"),
3216
+ "data-i18n-title": "close",
3209
3217
  "aria-label": (0, i18next.t)("close"),
3210
3218
  "data-i18n-aria-label": "close"
3211
3219
  }]);
@@ -3335,7 +3343,13 @@ function build_dialog(shell, message, buttons, opts) {
3335
3343
  type: "button",
3336
3344
  "data-modal-button-value": b.value
3337
3345
  };
3338
- if (typeof b.label === "string") btn_attrs.i18n = b.label;
3346
+ if (typeof b.label === "string") {
3347
+ btn_attrs.i18n = b.label;
3348
+ btn_attrs.title = (0, i18next.t)(b.label);
3349
+ btn_attrs["data-i18n-title"] = b.label;
3350
+ btn_attrs["aria-label"] = (0, i18next.t)(b.label);
3351
+ btn_attrs["data-i18n-aria-label"] = b.label;
3352
+ }
3339
3353
  return [
3340
3354
  "button",
3341
3355
  btn_attrs,
@@ -3360,6 +3374,8 @@ function build_dialog(shell, message, buttons, opts) {
3360
3374
  ]);
3361
3375
  $card_children.push(["button", {
3362
3376
  class: "CONFIRM_CLOSE delete yui-confirm-x",
3377
+ title: (0, i18next.t)("close"),
3378
+ "data-i18n-title": "close",
3363
3379
  "aria-label": (0, i18next.t)("close"),
3364
3380
  "data-i18n-aria-label": "close"
3365
3381
  }], [
@@ -72094,9 +72110,10 @@ function write_options(op) {
72094
72110
  * the owner's design of M36 (2026-09-21 review) every write here
72095
72111
  * raised both versions, so an edit half made was already the
72096
72112
  * schema of the next start. The topic list marks what this session
72097
- * wrote and has not saved (the host's EV_REFRESH after a save is
72098
- * what forgets it) and what the host says is not saved (EV_DRAFTS,
72099
- * replaced whole each time it is sent).
72113
+ * wrote and has not saved (EV_REFRESH forgets it: the view's own
72114
+ * Refresh button sends it, and a host may after a save -- the
72115
+ * agent console's does not) and what the host says is not saved
72116
+ * (EV_DRAFTS, replaced whole each time it is sent).
72100
72117
  *
72101
72118
  * WHAT ELSE IS HERE, and why each is here and not somewhere else:
72102
72119
  *
@@ -72173,7 +72190,9 @@ var attrs_table$1 = [
72173
72190
  ];
72174
72191
  var PRIVATE_DATA$1 = {
72175
72192
  records: null,
72193
+ records_before: null,
72176
72194
  model: null,
72195
+ model_gen: 0,
72177
72196
  pending: 0,
72178
72197
  load_error: "",
72179
72198
  load_round: 0,
@@ -72188,6 +72207,7 @@ var PRIVATE_DATA$1 = {
72188
72207
  order_undo: null,
72189
72208
  diagram_gobj: null,
72190
72209
  dialog: null,
72210
+ dialog_gen: 0,
72191
72211
  save_queue: null,
72192
72212
  save_return: "",
72193
72213
  save_wrote: false,
@@ -72348,6 +72368,68 @@ function refuse_if_readonly(gobj, event) {
72348
72368
  yui_shell_show_error(yui_shell_of(gobj), "the treedb is read-only", { t: i18next.t });
72349
72369
  return true;
72350
72370
  }
72371
+ /***************************************************************
72372
+ * A decision taken on a model a load has since REPLACED: the Save
72373
+ * of a form, a confirmation, an import. Each carries the
72374
+ * `model_gen` it was built on (a number, not the model: a kw is
72375
+ * dumped by the machine trace).
72376
+ *
72377
+ * Refused, and said. A column form sends every field it shows, so
72378
+ * its Save after a reload wrote the OLD record over the newer one
72379
+ * (fourth independent review, probe A3); a form whose column the
72380
+ * reload removed answered "names no column" for ever. end_load()
72381
+ * closes such a dialog when the load lands; this is the same rule
72382
+ * for whatever arrives anyway -- a stale screen, a confirmation
72383
+ * that was up, a keyboard.
72384
+ *
72385
+ * A kw with no stamp is not a dialog's and is not asked.
72386
+ ***************************************************************/
72387
+ function built_on_a_replaced_model(gobj, event, kw) {
72388
+ let priv = gobj.priv;
72389
+ if (!kw || kw.model_gen === void 0 || kw.model_gen === priv.model_gen) return false;
72390
+ (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`);
72391
+ yui_shell_show_error(yui_shell_of(gobj), "the schemas were read again: open the dialog again", { t: i18next.t });
72392
+ return true;
72393
+ }
72394
+ /***************************************************************
72395
+ * The reload a load refused IN session left owed (a routing
72396
+ * adapter's deadline on a slow `nodes`, ac_mt_command_answer()):
72397
+ * the model shown is kept, and it may be older than the store.
72398
+ * The session is up, so no reconnect will ask for it again -- it
72399
+ * was owed for as long as the session lasted, and a form opened
72400
+ * on that model wrote every field of it over the newer record
72401
+ * (fifth independent review; A3 of the fourth, by another path).
72402
+ *
72403
+ * So the operator's NEXT action asks it. An edit -- a form, a
72404
+ * write, a confirmation, what reads the model whole (check,
72405
+ * export) -- is refused and said: it would be computed on what
72406
+ * the store may no longer hold, and the load that lands closes a
72407
+ * dialog built on the old model anyway (end_load()). A move is
72408
+ * not refused (reload_after_move()): it goes, and reads there.
72409
+ *
72410
+ * Not on a timer, and not at once: a load refused on a deadline
72411
+ * asked again at once is refused the same way, and one asked on a
72412
+ * clock is polling. Out of session nothing is asked; the reconnect
72413
+ * does it (ac_transport_state()). The reload keeps this session's
72414
+ * draft chips: the host did not ask for it.
72415
+ ***************************************************************/
72416
+ function owes_reload(gobj) {
72417
+ let state = (0, _yuneta_gobj_js.gobj_current_state)(gobj);
72418
+ return gobj.priv.reload_on_open && transport_in_session(gobj) && state !== "ST_LOADING" && state !== "ST_SAVING";
72419
+ }
72420
+ function reload_first(gobj, event) {
72421
+ if (!owes_reload(gobj)) return false;
72422
+ gobj.priv.reload_on_open = false;
72423
+ (0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} refused, the schemas shown may be out of date: they are read again first`);
72424
+ yui_shell_show_error(yui_shell_of(gobj), "the schemas shown may be out of date: they are read again, try again when they are in", { t: i18next.t });
72425
+ request_model(gobj, true);
72426
+ return true;
72427
+ }
72428
+ function reload_after_move(gobj) {
72429
+ if (!owes_reload(gobj)) return 0;
72430
+ gobj.priv.reload_on_open = false;
72431
+ return request_model(gobj, true);
72432
+ }
72351
72433
  /***************************
72352
72434
  * The model
72353
72435
  ***************************/
@@ -72362,22 +72444,32 @@ function refuse_if_readonly(gobj, event) {
72362
72444
  * and the toolbar stops answering: left up, a click on a card, on
72363
72445
  * Back or on the drawing answered "Event NOT DEFINED in state
72364
72446
  * ST_LOADING" and was lost (third independent review). A dialog
72365
- * left open is answered in ST_LOADING instead (ac_wait_for_the_load).
72366
- *
72367
- * `keep_written`: a load the host did not ask for -- the reconnect,
72368
- * a write that turned out done -- keeps what this session wrote.
72369
- * Only the host's EV_REFRESH (a Save sends it) forgets it.
72447
+ * left open is answered in ST_LOADING instead (ac_wait_for_the_load),
72448
+ * and a load that LANDS closes it (end_load()): it was built on the
72449
+ * model the load replaced, and its Save sends every field it shows.
72450
+ * An import plan is forgotten here for the same reason: it is a list
72451
+ * of writes computed against the model going away -- once the load
72452
+ * has LEFT (one that could not be sent replaces nothing).
72453
+ *
72454
+ * `keep_written`: a load nobody ASKED for -- the reconnect, a write
72455
+ * that turned out done, the reload a refused load owed -- keeps what
72456
+ * this session wrote. Only EV_REFRESH forgets it: the view's own
72457
+ * Refresh button, or a host that sends it (after a Save, say; the
72458
+ * agent console does not).
72370
72459
  *
72371
72460
  * A load that cannot leave WHOLE did not happen (out of session it
72372
72461
  * is not even asked): the records the model was built on are put
72373
72462
  * back (emptied, the next write patched them into a model with no
72374
72463
  * treedb), the round is spent so a request that did leave is
72375
- * stale, and the session back asks again.
72464
+ * stale, and the session back asks again. A load that left and
72465
+ * FAILED keeps them the same way (`records_before`,
72466
+ * ac_mt_command_answer()).
72376
72467
  ***************************************************************/
72377
72468
  function request_model(gobj, keep_written) {
72378
72469
  let priv = gobj.priv;
72379
72470
  if (!(0, _yuneta_gobj_js.gobj_read_pointer_attr)(gobj, "gobj_remote_yuno")) return -1;
72380
- let previous = priv.records;
72471
+ let previous = (0, _yuneta_gobj_js.gobj_current_state)(gobj) === "ST_LOADING" ? priv.records_before : priv.records;
72472
+ priv.records_before = previous;
72381
72473
  priv.records = {
72382
72474
  treedbs: [],
72383
72475
  topics: [],
@@ -72403,6 +72495,7 @@ function request_model(gobj, keep_written) {
72403
72495
  }
72404
72496
  if (left < 3) {
72405
72497
  priv.records = previous;
72498
+ priv.records_before = null;
72406
72499
  priv.load_round++;
72407
72500
  priv.reload_on_open = true;
72408
72501
  priv.load_error = (0, i18next.t)("cannot reach the treedb");
@@ -72410,6 +72503,7 @@ function request_model(gobj, keep_written) {
72410
72503
  end_load(gobj);
72411
72504
  return -1;
72412
72505
  }
72506
+ forget_import_plan(gobj);
72413
72507
  priv.pending = left;
72414
72508
  return 0;
72415
72509
  }
@@ -72475,8 +72569,8 @@ function build_model(gobj) {
72475
72569
  * Called ONLY when records arrive from the store: that is what a
72476
72570
  * measurement of "changed since" can be measured against.
72477
72571
  *
72478
- * `written` is forgotten only by a load the HOST asked for (its
72479
- * EV_REFRESH, which a Save sends). Since M36 a write moves no
72572
+ * `written` is forgotten only by an EV_REFRESH (the view's own
72573
+ * Refresh button, or a host that sends one). Since M36 a write moves no
72480
72574
  * version, so `written` is the draft chip of what this session
72481
72575
  * wrote and no longer half of a version measurement: a reload of
72482
72576
  * the reconnect, or of a write that turned out done, forgot the
@@ -72498,9 +72592,12 @@ function start_measuring(gobj) {
72498
72592
  * until the host saves it (C_TREEDB's save-schema, which raises the
72499
72593
  * versions of what changed). Two sources say a topic is one, and
72500
72594
  * they are kept APART because they are forgotten differently:
72501
- * - `written`: what THIS session wrote since the model was loaded
72502
- * (a reload, the host's EV_REFRESH, forgets it -- the store says
72503
- * what is left);
72595
+ * - `written`: what THIS session wrote. Only EV_REFRESH forgets
72596
+ * it -- the view's own Refresh button sends it (in the agent
72597
+ * console that is the only sender), and a host may after a
72598
+ * Save; the reconnect's reload, the one owed after a write, a
72599
+ * refused load's and a late write's keep it (start_measuring(),
72600
+ * request_model());
72504
72601
  * - `host_ids`: what the host said last (EV_DRAFTS), replaced WHOLE
72505
72602
  * by the next EV_DRAFTS. Folded into `written`, a topic the host
72506
72603
  * named once stayed a draft after the Save that published it.
@@ -72668,6 +72765,8 @@ function render_toolbar(gobj) {
72668
72765
  let readonly = is_readonly(gobj);
72669
72766
  let has_model = !!priv.model;
72670
72767
  let on_a_treedb = state !== "ST_IDLE" && state !== "ST_EMPTY";
72768
+ let treedb_here = on_a_treedb && !!current_treedb(gobj);
72769
+ let topic_here = treedb_here && !!current_topic(gobj);
72671
72770
  let in_flight = state === "ST_SAVING" || state === "ST_LOADING";
72672
72771
  let $left = [];
72673
72772
  if (priv.treedb_id && on_a_treedb) $left.push([
@@ -72743,17 +72842,17 @@ function render_toolbar(gobj) {
72743
72842
  $trail
72744
72843
  ]);
72745
72844
  let $right = [];
72746
- if (priv.treedb_id && has_model && on_a_treedb) {
72845
+ if (priv.treedb_id && has_model && treedb_here) {
72747
72846
  $right.push(toolbar_button("SCHEMA_DIAGRAM_BTN", "yi-compass-drafting", priv.diagram ? "topics" : "diagram", "EV_TOGGLE_DIAGRAM", false));
72748
72847
  $right.push(toolbar_button("SCHEMA_VALIDATE_BTN", "yi-square-check", "check", "EV_VALIDATE", false));
72749
72848
  $right.push(toolbar_button("SCHEMA_EXPORT_BTN", "yi-download", "export", "EV_EXPORT", false));
72750
72849
  if (!readonly) $right.push(toolbar_button("SCHEMA_IMPORT_BTN", "yi-upload", "import", "EV_IMPORT", false));
72751
72850
  }
72752
- if (priv.topic_name && !readonly && !priv.diagram && on_a_treedb) {
72851
+ if (priv.topic_name && !readonly && !priv.diagram && topic_here) {
72753
72852
  if (undo_order_writes(gobj, current_topic(gobj)).length > 0) $right.push(toolbar_button("SCHEMA_UNDO_ORDER_BTN", "yi-arrow-rotate-left", "undo the order", "EV_UNDO_ORDER", false));
72754
72853
  $right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus", "new column", "EV_ADD_COLUMN", false));
72755
72854
  }
72756
- if (priv.treedb_id && !priv.topic_name && !readonly && !priv.diagram && on_a_treedb) $right.push(toolbar_button("SCHEMA_ADD_TOPIC_BTN", "yi-plus", "new topic", "EV_ADD_TOPIC", false));
72855
+ if (priv.treedb_id && !priv.topic_name && !readonly && !priv.diagram && treedb_here) $right.push(toolbar_button("SCHEMA_ADD_TOPIC_BTN", "yi-plus", "new topic", "EV_ADD_TOPIC", false));
72757
72856
  $right.push(toolbar_button("SCHEMA_REFRESH_BTN", "yi-arrows-rotate", "refresh", "EV_REFRESH", state === "ST_LOADING"));
72758
72857
  let $bar = (0, _yuneta_gobj_js.createElement2)([
72759
72858
  "div",
@@ -73573,6 +73672,7 @@ function close_dialog(gobj) {
73573
73672
  function open_dialog(gobj, $content, title, logical, title_prefix) {
73574
73673
  let priv = gobj.priv;
73575
73674
  close_dialog(gobj);
73675
+ priv.dialog_gen = priv.model_gen;
73576
73676
  priv.dialog = yui_shell_show_modal(yui_shell_of(gobj), $content, {
73577
73677
  dialog: true,
73578
73678
  title,
@@ -73619,11 +73719,28 @@ function name_control($spec, label) {
73619
73719
  $spec[1]["aria-label"] = (0, i18next.t)(label);
73620
73720
  $spec[1]["data-i18n-aria-label"] = label;
73621
73721
  }
73722
+ if (!$spec[1].title) {
73723
+ $spec[1].title = (0, i18next.t)(label);
73724
+ $spec[1]["data-i18n-title"] = label;
73725
+ }
73622
73726
  return true;
73623
73727
  }
73624
73728
  for (let child of $spec[2] || []) if (name_control(child, label)) return true;
73625
73729
  return false;
73626
73730
  }
73731
+ /***************************************************************
73732
+ * The four attributes that NAME a control -- a title and an
73733
+ * aria-label, each with the key a language change re-translates
73734
+ * it by. A visible label is not a name (CLAUDE.md).
73735
+ ***************************************************************/
73736
+ function name_attrs(key, attrs) {
73737
+ return Object.assign({
73738
+ title: (0, i18next.t)(key),
73739
+ "data-i18n-title": key,
73740
+ "aria-label": (0, i18next.t)(key),
73741
+ "data-i18n-aria-label": key
73742
+ }, attrs);
73743
+ }
73627
73744
  function field(logical, name, label, $control, help) {
73628
73745
  name_control($control, label);
73629
73746
  return [
@@ -73800,7 +73917,7 @@ function read_flags($root) {
73800
73917
  * than not offering it.
73801
73918
  ***************************************************************/
73802
73919
  function open_column_form(gobj, topic, col, prefill) {
73803
- gobj.priv;
73920
+ let priv = gobj.priv;
73804
73921
  let record = prefill || col && col.record || {};
73805
73922
  let creating = !col;
73806
73923
  let type = record.type || "string";
@@ -73810,6 +73927,7 @@ function open_column_form(gobj, topic, col, prefill) {
73810
73927
  let hook_col = hook_topic ? hook[hook_topic] : "";
73811
73928
  let treedb = current_treedb(gobj);
73812
73929
  let sibling_topics = treedb ? treedb.topics.map((x) => x.name) : [];
73930
+ let model_gen = priv.model_gen;
73813
73931
  let $form = (0, _yuneta_gobj_js.createElement2)([
73814
73932
  "div",
73815
73933
  { class: "SCHEMA_COL_FORM box" },
@@ -73872,10 +73990,10 @@ function open_column_form(gobj, topic, col, prefill) {
73872
73990
  },
73873
73991
  [[
73874
73992
  "button",
73875
- {
73993
+ name_attrs("cancel", {
73876
73994
  class: "SCHEMA_COL_FORM_CANCEL button",
73877
73995
  type: "button"
73878
- },
73996
+ }),
73879
73997
  [[
73880
73998
  "span",
73881
73999
  { i18n: "cancel" },
@@ -73883,10 +74001,10 @@ function open_column_form(gobj, topic, col, prefill) {
73883
74001
  ]]
73884
74002
  ], [
73885
74003
  "button",
73886
- {
74004
+ name_attrs("save", {
73887
74005
  class: "SCHEMA_COL_FORM_SAVE button is-primary",
73888
74006
  type: "button"
73889
- },
74007
+ }),
73890
74008
  [[
73891
74009
  "span",
73892
74010
  { class: "icon" },
@@ -73926,7 +74044,8 @@ function open_column_form(gobj, topic, col, prefill) {
73926
74044
  topic: topic.name,
73927
74045
  col: creating ? "" : col.name,
73928
74046
  creating,
73929
- values
74047
+ values,
74048
+ model_gen
73930
74049
  }, gobj);
73931
74050
  });
73932
74051
  open_dialog(gobj, $form, creating ? "new column" : "edit column", "SCHEMA_COL_FORM_DIALOG", creating ? topic.name : `${topic.name}.${col.name}`);
@@ -73949,6 +74068,7 @@ function open_topic_form(gobj, treedb, topic) {
73949
74068
  let record = topic && topic.record || {};
73950
74069
  let creating = !topic;
73951
74070
  let col_names = topic ? topic.cols.map((c) => c.name) : [];
74071
+ let model_gen = gobj.priv.model_gen;
73952
74072
  let $form = (0, _yuneta_gobj_js.createElement2)([
73953
74073
  "div",
73954
74074
  { class: "SCHEMA_TOPIC_FORM box" },
@@ -74007,10 +74127,10 @@ function open_topic_form(gobj, treedb, topic) {
74007
74127
  },
74008
74128
  [[
74009
74129
  "button",
74010
- {
74130
+ name_attrs("cancel", {
74011
74131
  class: "SCHEMA_TOPIC_FORM_CANCEL button",
74012
74132
  type: "button"
74013
- },
74133
+ }),
74014
74134
  [[
74015
74135
  "span",
74016
74136
  { i18n: "cancel" },
@@ -74018,10 +74138,10 @@ function open_topic_form(gobj, treedb, topic) {
74018
74138
  ]]
74019
74139
  ], [
74020
74140
  "button",
74021
- {
74141
+ name_attrs("save", {
74022
74142
  class: "SCHEMA_TOPIC_FORM_SAVE button is-primary",
74023
74143
  type: "button"
74024
- },
74144
+ }),
74025
74145
  [[
74026
74146
  "span",
74027
74147
  { class: "icon" },
@@ -74044,7 +74164,8 @@ function open_topic_form(gobj, treedb, topic) {
74044
74164
  (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_SAVE_TOPIC", {
74045
74165
  topic: creating ? "" : topic.name,
74046
74166
  creating,
74047
- values: read_form($form)
74167
+ values: read_form($form),
74168
+ model_gen
74048
74169
  }, gobj);
74049
74170
  });
74050
74171
  open_dialog(gobj, $form, creating ? "new topic" : "edit topic", "SCHEMA_TOPIC_FORM_DIALOG", creating ? treedb.id : `${treedb.id}.${topic.name}`);
@@ -74185,40 +74306,40 @@ function open_export(gobj, treedb) {
74185
74306
  [
74186
74307
  [
74187
74308
  "div",
74188
- { class: "SCHEMA_EXPORT_TABS tabs is-toggle mb-2" },
74309
+ { class: "SCHEMA_EXPORT_TABS buttons has-addons mb-2" },
74189
74310
  [[
74190
- "ul",
74191
- {},
74311
+ "button",
74312
+ {
74313
+ class: "SCHEMA_EXPORT_TAB button selected_state",
74314
+ type: "button",
74315
+ "data-pane": "c",
74316
+ "aria-pressed": "true",
74317
+ title: (0, i18next.t)("schema as c source"),
74318
+ "data-i18n-title": "schema as c source",
74319
+ "aria-label": (0, i18next.t)("schema as c source"),
74320
+ "data-i18n-aria-label": "schema as c source"
74321
+ },
74192
74322
  [[
74193
- "li",
74194
- {
74195
- class: "SCHEMA_EXPORT_TAB is-active",
74196
- "data-pane": "c"
74197
- },
74198
- [[
74199
- "a",
74200
- {},
74201
- [[
74202
- "span",
74203
- {},
74204
- "C"
74205
- ]]
74206
- ]]
74207
- ], [
74208
- "li",
74209
- {
74210
- class: "SCHEMA_EXPORT_TAB",
74211
- "data-pane": "json"
74212
- },
74213
- [[
74214
- "a",
74215
- {},
74216
- [[
74217
- "span",
74218
- {},
74219
- "JSON"
74220
- ]]
74221
- ]]
74323
+ "span",
74324
+ {},
74325
+ "C"
74326
+ ]]
74327
+ ], [
74328
+ "button",
74329
+ {
74330
+ class: "SCHEMA_EXPORT_TAB button",
74331
+ type: "button",
74332
+ "data-pane": "json",
74333
+ "aria-pressed": "false",
74334
+ title: (0, i18next.t)("schema as json"),
74335
+ "data-i18n-title": "schema as json",
74336
+ "aria-label": (0, i18next.t)("schema as json"),
74337
+ "data-i18n-aria-label": "schema as json"
74338
+ },
74339
+ [[
74340
+ "span",
74341
+ {},
74342
+ "JSON"
74222
74343
  ]]
74223
74344
  ]]
74224
74345
  ],
@@ -74288,7 +74409,10 @@ function open_export(gobj, treedb) {
74288
74409
  let $text = $content.querySelector(".SCHEMA_EXPORT_TEXT");
74289
74410
  for (let $tab of $content.querySelectorAll(".SCHEMA_EXPORT_TAB")) $tab.addEventListener("click", (evt) => {
74290
74411
  evt.stopPropagation();
74291
- for (let $other of $content.querySelectorAll(".SCHEMA_EXPORT_TAB")) $other.classList.toggle("is-active", $other === $tab);
74412
+ for (let $other of $content.querySelectorAll(".SCHEMA_EXPORT_TAB")) {
74413
+ $other.classList.toggle("selected_state", $other === $tab);
74414
+ $other.setAttribute("aria-pressed", $other === $tab ? "true" : "false");
74415
+ }
74292
74416
  $text.value = $tab.dataset.pane === "c" ? c_text : json_text;
74293
74417
  });
74294
74418
  $content.querySelector(".SCHEMA_EXPORT_COPY").addEventListener("click", (evt) => {
@@ -74324,6 +74448,7 @@ function copy_text(gobj, $text) {
74324
74448
  * plan itself, so what is confirmed is what runs.
74325
74449
  ***************************************************************/
74326
74450
  function open_import(gobj, treedb) {
74451
+ let model_gen = gobj.priv.model_gen;
74327
74452
  let $content = (0, _yuneta_gobj_js.createElement2)([
74328
74453
  "div",
74329
74454
  { class: "SCHEMA_IMPORT box" },
@@ -74338,12 +74463,12 @@ function open_import(gobj, treedb) {
74338
74463
  ],
74339
74464
  [
74340
74465
  "textarea",
74341
- {
74466
+ name_attrs("schema", {
74342
74467
  class: "SCHEMA_IMPORT_TEXT textarea is-small is-family-monospace",
74343
74468
  rows: "12",
74344
74469
  spellcheck: "false",
74345
74470
  placeholder: "{\"id\": \"...\", \"schema_version\": \"1\", \"topics\": []}"
74346
- },
74471
+ }),
74347
74472
  ""
74348
74473
  ],
74349
74474
  [
@@ -74376,10 +74501,10 @@ function open_import(gobj, treedb) {
74376
74501
  [
74377
74502
  [
74378
74503
  "button",
74379
- {
74504
+ name_attrs("cancel", {
74380
74505
  class: "SCHEMA_IMPORT_CANCEL button",
74381
74506
  type: "button"
74382
- },
74507
+ }),
74383
74508
  [[
74384
74509
  "span",
74385
74510
  { i18n: "cancel" },
@@ -74388,10 +74513,10 @@ function open_import(gobj, treedb) {
74388
74513
  ],
74389
74514
  [
74390
74515
  "button",
74391
- {
74516
+ name_attrs("preview", {
74392
74517
  class: "SCHEMA_IMPORT_PREVIEW button",
74393
74518
  type: "button"
74394
- },
74519
+ }),
74395
74520
  [[
74396
74521
  "span",
74397
74522
  { class: "icon" },
@@ -74404,11 +74529,11 @@ function open_import(gobj, treedb) {
74404
74529
  ],
74405
74530
  [
74406
74531
  "button",
74407
- {
74532
+ name_attrs("import", {
74408
74533
  class: "SCHEMA_IMPORT_RUN button is-warning",
74409
74534
  type: "button",
74410
74535
  disabled: "disabled"
74411
- },
74536
+ }),
74412
74537
  [[
74413
74538
  "span",
74414
74539
  { class: "icon" },
@@ -74435,18 +74560,31 @@ function open_import(gobj, treedb) {
74435
74560
  evt.stopPropagation();
74436
74561
  (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_PREVIEW_IMPORT", {
74437
74562
  text: $text.value,
74438
- prune: $prune.checked
74563
+ prune: $prune.checked,
74564
+ model_gen
74439
74565
  }, gobj);
74440
74566
  });
74441
74567
  $run.addEventListener("click", (evt) => {
74442
74568
  evt.stopPropagation();
74443
- (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_APPLY_IMPORT", {}, gobj);
74569
+ (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_APPLY_IMPORT", { model_gen }, gobj);
74444
74570
  });
74445
74571
  gobj.priv.import_pane = $plan_pane;
74446
74572
  gobj.priv.import_run = $run;
74447
74573
  open_dialog(gobj, $content, "import", "SCHEMA_IMPORT_DIALOG", treedb.id);
74448
74574
  }
74449
74575
  /***************************************************************
74576
+ * The plan is a list of writes computed against the model shown:
74577
+ * a load replaces the model, so the plan goes with it and the
74578
+ * dialog, if it stays up (a load that failed keeps the model),
74579
+ * asks for a Preview again.
74580
+ ***************************************************************/
74581
+ function forget_import_plan(gobj) {
74582
+ let priv = gobj.priv;
74583
+ priv.import_plan = null;
74584
+ clear(priv.import_pane);
74585
+ if (priv.import_run) priv.import_run.disabled = true;
74586
+ }
74587
+ /***************************************************************
74450
74588
  * The plan, drawn where the paste is: one line per write, the
74451
74589
  * deletions apart and counted, because they are what the
74452
74590
  * operator is being asked about.
@@ -74573,7 +74711,8 @@ function open_orphans(gobj) {
74573
74711
  { class: "SCHEMA_ORPHAN_ACTIONS has-text-right" },
74574
74712
  readonly ? [] : [row_icon(gobj, "SCHEMA_ORPHAN_DELETE", "yi-trash", "delete", "EV_DELETE_ORPHAN", {
74575
74713
  kind,
74576
- id: entry.id
74714
+ id: entry.id,
74715
+ model_gen: priv.model_gen
74577
74716
  })]
74578
74717
  ]
74579
74718
  ]
@@ -74745,6 +74884,10 @@ function transport_dropped(gobj) {
74745
74884
  priv.load_round++;
74746
74885
  priv.pending = 0;
74747
74886
  priv.load_error = "";
74887
+ if (priv.records_before) {
74888
+ priv.records = priv.records_before;
74889
+ priv.records_before = null;
74890
+ }
74748
74891
  return end_load(gobj);
74749
74892
  }
74750
74893
  return 0;
@@ -74755,11 +74898,22 @@ function transport_dropped(gobj) {
74755
74898
  * in flight (ac_show() kept it), or the one it had. Without a
74756
74899
  * model there is no screen to go to: the position is kept for the
74757
74900
  * next load, and the editor says why it is empty.
74901
+ *
74902
+ * A dialog built on the model this load REPLACED is closed, and the
74903
+ * operator told to open it again: it shows the old record, and its
74904
+ * Save would write every field of it over the newer one. A load
74905
+ * that failed or never left replaced nothing (`model_gen` did not
74906
+ * move), and the dialog stays with what was typed.
74758
74907
  ***************************************************************/
74759
74908
  function end_load(gobj) {
74760
74909
  let priv = gobj.priv;
74761
74910
  let seg = priv.pending_seg;
74762
74911
  priv.pending_seg = null;
74912
+ if (priv.dialog && priv.dialog_gen !== priv.model_gen) {
74913
+ (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`);
74914
+ close_dialog(gobj);
74915
+ yui_shell_show_error(yui_shell_of(gobj), "the schemas were read again: open the dialog again", { t: i18next.t });
74916
+ }
74763
74917
  if (priv.model) {
74764
74918
  if (seg !== null) return apply_seg(gobj, seg);
74765
74919
  return go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
@@ -74975,10 +75129,20 @@ function ac_mt_command_answer(gobj, event, kw, src) {
74975
75129
  else if (priv.records && Array.isArray(priv.records[topic_name])) priv.records[topic_name] = Array.isArray(data) ? data : [];
74976
75130
  if (priv.pending > 0) return 0;
74977
75131
  if (priv.load_error) {
75132
+ if (priv.model) {
75133
+ (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`);
75134
+ priv.records = priv.records_before;
75135
+ priv.records_before = null;
75136
+ priv.reload_on_open = true;
75137
+ yui_shell_show_error(yui_shell_of(gobj), "cannot read the schemas again: the ones shown may be out of date, your next change reads them first", { t: i18next.t });
75138
+ return end_load(gobj);
75139
+ }
74978
75140
  priv.model = null;
74979
75141
  return end_load(gobj);
74980
75142
  }
74981
75143
  priv.order_undo = {};
75144
+ priv.records_before = null;
75145
+ priv.model_gen++;
74982
75146
  build_model(gobj);
74983
75147
  start_measuring(gobj);
74984
75148
  return end_load(gobj);
@@ -75000,11 +75164,14 @@ function ac_mt_command_answer(gobj, event, kw, src) {
75000
75164
  let record = (0, _yuneta_gobj_js.is_object)(data) ? data : Array.isArray(data) && (0, _yuneta_gobj_js.is_object)(data[0]) ? data[0] : null;
75001
75165
  if (record) patch_record(gobj, topic_name, record);
75002
75166
  else {
75003
- (0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: '${command}' answered no record`);
75167
+ let not_sent = priv.save_queue.length - 1;
75168
+ (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` : ""));
75169
+ if (not_sent > 0) yui_shell_show_error(yui_shell_of(gobj), "the treedb did not describe a write back: the writes after it were not sent", { t: i18next.t });
75004
75170
  if (topic_name === T_TOPICS || topic_name === T_COLS) {
75005
75171
  let write = priv.save_queue[0];
75006
75172
  mark_written(gobj, topic_name, write ? write.record : null);
75007
75173
  }
75174
+ priv.reload_after_write = false;
75008
75175
  priv.save_queue = [];
75009
75176
  priv.save_return = "";
75010
75177
  priv.save_wrote = false;
@@ -75062,8 +75229,14 @@ function late_write_done(gobj, command, topic_name, data) {
75062
75229
  /***************************************************************
75063
75230
  * The topic a record written belongs to, read off the RECORD and
75064
75231
  * not off the screen: a write answered late may be about a topic
75065
- * the operator has left. A column names its topic in its fkey
75066
- * (`topics^<topic id>^cols`); a topic is its own id.
75232
+ * the operator has left. A column names its topic in its fkey; a
75233
+ * topic is its own id.
75234
+ *
75235
+ * The fkey is read with parse_fkey_ref(), because the store answers
75236
+ * in list_dict -- `[{topic_name, id, hook_name}]` -- and not in the
75237
+ * `topics^<topic id>^cols` strings this view writes. Split as a
75238
+ * string, every production answer marked nothing (fourth independent
75239
+ * review, probe C).
75067
75240
  ***************************************************************/
75068
75241
  function mark_written_record(gobj, topic_name, record) {
75069
75242
  let priv = gobj.priv;
@@ -75073,11 +75246,7 @@ function mark_written_record(gobj, topic_name, record) {
75073
75246
  return;
75074
75247
  }
75075
75248
  if (topic_name !== T_COLS) return;
75076
- let refs = Array.isArray(record.topics) ? record.topics : typeof record.topics === "string" ? [record.topics] : [];
75077
- for (let ref of refs) {
75078
- let parts = String(ref).split("^");
75079
- if (parts.length >= 2 && parts[1]) priv.written[parts[1]] = true;
75080
- }
75249
+ for (let ref of parse_fkey_ref(record.topics)) priv.written[ref.id] = true;
75081
75250
  }
75082
75251
  /***************************************************************
75083
75252
  * Remember which topic this write belongs to, which is what
@@ -75161,14 +75330,36 @@ function ac_refresh$1(gobj, event, kw, src) {
75161
75330
  * operator can still reach, and what it asks is computed against
75162
75331
  * a model the answers in the air are about to replace.
75163
75332
  *
75164
- * Refused, and SAID -- and the dialog stays open with what was
75165
- * typed, so the same Save works once the load is in. Undeclared,
75166
- * it answered "Event NOT DEFINED in state ST_LOADING" and the
75167
- * edit was gone with no word (third independent review).
75333
+ * Refused, and SAID. Undeclared, it answered "Event NOT DEFINED
75334
+ * in state ST_LOADING" and the edit was gone with no word (third
75335
+ * independent review).
75336
+ *
75337
+ * And NOT "try again": the same Save, once the load was in, sent
75338
+ * the form built on the old model -- every field of the old record
75339
+ * over the newer one (fourth independent review). The load that
75340
+ * lands closes such a dialog (end_load()); one that fails leaves it
75341
+ * up, on the model it was built on.
75168
75342
  ***************************************************************/
75169
75343
  function ac_wait_for_the_load(gobj, event, kw, src) {
75170
75344
  (0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} refused, the schemas are loading`);
75171
- yui_shell_show_error(yui_shell_of(gobj), "the schemas are loading: try again when they are in", { t: i18next.t });
75345
+ yui_shell_show_error(yui_shell_of(gobj), "the schemas are loading: wait for them", { t: i18next.t });
75346
+ return -1;
75347
+ }
75348
+ /***************************************************************
75349
+ * A confirmation answered where no treedb is open: ST_EMPTY (a
75350
+ * reload landed on zero treedbs while it was up) or ST_IDLE (no
75351
+ * model). A confirmation is a shell modal, not this view's dialog,
75352
+ * so the load that lands does not close it, and its Yes arrives
75353
+ * anyway. Undeclared, it answered "Event NOT DEFINED" (fifth
75354
+ * independent review).
75355
+ *
75356
+ * Refused with the stamp's own words: whatever it was decided on
75357
+ * is not on screen any more.
75358
+ ***************************************************************/
75359
+ function ac_confirmed_on_nothing(gobj, event, kw, src) {
75360
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75361
+ (0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} refused, no treedb is open`);
75362
+ yui_shell_show_error(yui_shell_of(gobj), "the schemas were read again: open the dialog again", { t: i18next.t });
75172
75363
  return -1;
75173
75364
  }
75174
75365
  /***************************************************************
@@ -75196,20 +75387,23 @@ function ac_drafts(gobj, event, kw, src) {
75196
75387
  * Moving about.
75197
75388
  ***************************************************************/
75198
75389
  function ac_select_treedb(gobj, event, kw, src) {
75199
- return go(gobj, kw.treedb, "", false, true);
75390
+ go(gobj, kw.treedb, "", false, true);
75391
+ return reload_after_move(gobj);
75200
75392
  }
75201
75393
  function ac_select_topic(gobj, event, kw, src) {
75202
- return go(gobj, gobj.priv.treedb_id, kw.topic, false, true);
75394
+ go(gobj, gobj.priv.treedb_id, kw.topic, false, true);
75395
+ return reload_after_move(gobj);
75203
75396
  }
75204
75397
  function ac_back(gobj, event, kw, src) {
75205
75398
  let priv = gobj.priv;
75206
- if (priv.diagram) return go(gobj, priv.treedb_id, "", false, true);
75207
- if (priv.topic_name) return go(gobj, priv.treedb_id, "", false, true);
75208
- return go(gobj, "", "", false, true);
75399
+ if (priv.diagram || priv.topic_name) go(gobj, priv.treedb_id, "", false, true);
75400
+ else go(gobj, "", "", false, true);
75401
+ return reload_after_move(gobj);
75209
75402
  }
75210
75403
  function ac_toggle_diagram(gobj, event, kw, src) {
75211
75404
  let priv = gobj.priv;
75212
- return go(gobj, priv.treedb_id, priv.topic_name, !priv.diagram, true);
75405
+ go(gobj, priv.treedb_id, priv.topic_name, !priv.diagram, true);
75406
+ return reload_after_move(gobj);
75213
75407
  }
75214
75408
  /***************************************************************
75215
75409
  * A topic clicked in the drawing. The diagram is a CHILD here
@@ -75219,9 +75413,11 @@ function ac_toggle_diagram(gobj, event, kw, src) {
75219
75413
  function ac_node_click(gobj, event, kw, src) {
75220
75414
  let topic = kw && kw.topic;
75221
75415
  if (!topic) return 0;
75222
- return go(gobj, gobj.priv.treedb_id, topic, false, true);
75416
+ go(gobj, gobj.priv.treedb_id, topic, false, true);
75417
+ return reload_after_move(gobj);
75223
75418
  }
75224
75419
  function ac_show_orphans(gobj, event, kw, src) {
75420
+ if (reload_first(gobj, event)) return -1;
75225
75421
  open_orphans(gobj);
75226
75422
  return 0;
75227
75423
  }
@@ -75234,6 +75430,7 @@ function ac_show_orphans(gobj, event, kw, src) {
75234
75430
  * to feed.
75235
75431
  ***************************************************************/
75236
75432
  function confirm_then(gobj, message, detail, kw) {
75433
+ kw = Object.assign({ model_gen: gobj.priv.model_gen }, kw);
75237
75434
  yui_shell_confirm_danger(yui_shell_of(gobj), message, {
75238
75435
  t: i18next.t,
75239
75436
  detail
@@ -75248,6 +75445,7 @@ function confirm_then(gobj, message, detail, kw) {
75248
75445
  function ac_add_column(gobj, event, kw, src) {
75249
75446
  let topic = current_topic(gobj);
75250
75447
  if (refuse_if_readonly(gobj, event)) return -1;
75448
+ if (reload_first(gobj, event)) return -1;
75251
75449
  if (!topic) {
75252
75450
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no topic open`);
75253
75451
  return -1;
@@ -75260,6 +75458,7 @@ function ac_edit_column(gobj, event, kw, src) {
75260
75458
  let topic = current_topic(gobj);
75261
75459
  let col = topic ? find_col(priv.model, priv.treedb_id, topic.name, kw.col) : null;
75262
75460
  if (refuse_if_readonly(gobj, event)) return -1;
75461
+ if (reload_first(gobj, event)) return -1;
75263
75462
  if (!col) {
75264
75463
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} names no column: ${kw.col}`);
75265
75464
  return -1;
@@ -75277,6 +75476,7 @@ function ac_duplicate_column(gobj, event, kw, src) {
75277
75476
  let topic = current_topic(gobj);
75278
75477
  let col = topic ? find_col(priv.model, priv.treedb_id, topic.name, kw.col) : null;
75279
75478
  if (refuse_if_readonly(gobj, event)) return -1;
75479
+ if (reload_first(gobj, event)) return -1;
75280
75480
  if (!col) {
75281
75481
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} names no column: ${kw.col}`);
75282
75482
  return -1;
@@ -75295,6 +75495,8 @@ function ac_save_column(gobj, event, kw, src) {
75295
75495
  let topic = find_topic(priv.model, priv.treedb_id, kw.topic);
75296
75496
  let col = kw.creating ? null : find_col(priv.model, priv.treedb_id, kw.topic, kw.col);
75297
75497
  if (refuse_if_readonly(gobj, event)) return -1;
75498
+ if (reload_first(gobj, event)) return -1;
75499
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75298
75500
  if (!topic || !kw.creating && !col) {
75299
75501
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} names no column: ${kw.topic}.${kw.col}`);
75300
75502
  return -1;
@@ -75320,6 +75522,7 @@ function ac_delete_column(gobj, event, kw, src) {
75320
75522
  let topic = current_topic(gobj);
75321
75523
  let col = topic ? find_col(priv.model, priv.treedb_id, topic.name, kw.col) : null;
75322
75524
  if (refuse_if_readonly(gobj, event)) return -1;
75525
+ if (reload_first(gobj, event)) return -1;
75323
75526
  if (!col) {
75324
75527
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} names no column: ${kw.col}`);
75325
75528
  return -1;
@@ -75339,6 +75542,7 @@ function ac_delete_column(gobj, event, kw, src) {
75339
75542
  function ac_move_column(gobj, event, kw, src) {
75340
75543
  let topic = current_topic(gobj);
75341
75544
  if (refuse_if_readonly(gobj, event)) return -1;
75545
+ if (reload_first(gobj, event)) return -1;
75342
75546
  if (!topic) {
75343
75547
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no topic open`);
75344
75548
  return -1;
@@ -75374,6 +75578,7 @@ function ac_undo_order(gobj, event, kw, src) {
75374
75578
  let priv = gobj.priv;
75375
75579
  let topic = current_topic(gobj);
75376
75580
  if (refuse_if_readonly(gobj, event)) return -1;
75581
+ if (reload_first(gobj, event)) return -1;
75377
75582
  if (!topic) {
75378
75583
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no topic open`);
75379
75584
  return -1;
@@ -75392,6 +75597,7 @@ function ac_undo_order(gobj, event, kw, src) {
75392
75597
  function ac_add_topic(gobj, event, kw, src) {
75393
75598
  let treedb = current_treedb(gobj);
75394
75599
  if (refuse_if_readonly(gobj, event)) return -1;
75600
+ if (reload_first(gobj, event)) return -1;
75395
75601
  if (!treedb) {
75396
75602
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no treedb open`);
75397
75603
  return -1;
@@ -75404,6 +75610,7 @@ function ac_edit_topic(gobj, event, kw, src) {
75404
75610
  let treedb = current_treedb(gobj);
75405
75611
  let topic = treedb ? find_topic(priv.model, priv.treedb_id, kw.topic) : null;
75406
75612
  if (refuse_if_readonly(gobj, event)) return -1;
75613
+ if (reload_first(gobj, event)) return -1;
75407
75614
  if (!topic) {
75408
75615
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} names no topic: ${kw.topic}`);
75409
75616
  return -1;
@@ -75416,6 +75623,8 @@ function ac_save_topic(gobj, event, kw, src) {
75416
75623
  let treedb = current_treedb(gobj);
75417
75624
  let topic = kw.creating ? null : find_topic(priv.model, priv.treedb_id, kw.topic);
75418
75625
  if (refuse_if_readonly(gobj, event)) return -1;
75626
+ if (reload_first(gobj, event)) return -1;
75627
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75419
75628
  if (!treedb || !kw.creating && !topic) {
75420
75629
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} names no topic: ${kw.topic}`);
75421
75630
  return -1;
@@ -75443,6 +75652,7 @@ function ac_delete_topic(gobj, event, kw, src) {
75443
75652
  let priv = gobj.priv;
75444
75653
  let topic = find_topic(priv.model, priv.treedb_id, kw.topic);
75445
75654
  if (refuse_if_readonly(gobj, event)) return -1;
75655
+ if (reload_first(gobj, event)) return -1;
75446
75656
  if (!topic) {
75447
75657
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} names no topic: ${kw.topic}`);
75448
75658
  return -1;
@@ -75458,6 +75668,8 @@ function ac_delete_topic(gobj, event, kw, src) {
75458
75668
  ***************************************************************/
75459
75669
  function ac_delete_orphan(gobj, event, kw, src) {
75460
75670
  if (refuse_if_readonly(gobj, event)) return -1;
75671
+ if (reload_first(gobj, event)) return -1;
75672
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75461
75673
  if ((0, _yuneta_gobj_js.empty_string)(kw.id)) {
75462
75674
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} names nothing`);
75463
75675
  return -1;
@@ -75475,6 +75687,7 @@ function ac_delete_orphan(gobj, event, kw, src) {
75475
75687
  function ac_validate(gobj, event, kw, src) {
75476
75688
  let priv = gobj.priv;
75477
75689
  let treedb = current_treedb(gobj);
75690
+ if (reload_first(gobj, event)) return -1;
75478
75691
  if (!treedb) {
75479
75692
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no treedb open`);
75480
75693
  return -1;
@@ -75489,6 +75702,7 @@ function ac_validate(gobj, event, kw, src) {
75489
75702
  }
75490
75703
  function ac_export(gobj, event, kw, src) {
75491
75704
  let treedb = current_treedb(gobj);
75705
+ if (reload_first(gobj, event)) return -1;
75492
75706
  if (!treedb) {
75493
75707
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no treedb open`);
75494
75708
  return -1;
@@ -75499,6 +75713,7 @@ function ac_export(gobj, event, kw, src) {
75499
75713
  function ac_import(gobj, event, kw, src) {
75500
75714
  let treedb = current_treedb(gobj);
75501
75715
  if (refuse_if_readonly(gobj, event)) return -1;
75716
+ if (reload_first(gobj, event)) return -1;
75502
75717
  if (!treedb) {
75503
75718
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no treedb open`);
75504
75719
  return -1;
@@ -75514,6 +75729,8 @@ function ac_preview_import(gobj, event, kw, src) {
75514
75729
  let priv = gobj.priv;
75515
75730
  let treedb = current_treedb(gobj);
75516
75731
  let incoming = null;
75732
+ if (reload_first(gobj, event)) return -1;
75733
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75517
75734
  if (!treedb) {
75518
75735
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no treedb open`);
75519
75736
  return -1;
@@ -75541,6 +75758,8 @@ function ac_preview_import(gobj, event, kw, src) {
75541
75758
  function ac_apply_import(gobj, event, kw, src) {
75542
75759
  let plan = gobj.priv.import_plan;
75543
75760
  if (refuse_if_readonly(gobj, event)) return -1;
75761
+ if (reload_first(gobj, event)) return -1;
75762
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75544
75763
  if (!plan || plan.writes.length === 0) {
75545
75764
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no plan to run`);
75546
75765
  return -1;
@@ -75558,7 +75777,8 @@ function run_import(gobj) {
75558
75777
  let priv = gobj.priv;
75559
75778
  let plan = priv.import_plan;
75560
75779
  if (!plan) {
75561
- (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: the import plan is gone`);
75780
+ (0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: the import plan is gone`);
75781
+ yui_shell_show_error(yui_shell_of(gobj), "the import plan is gone: preview it again", { t: i18next.t });
75562
75782
  return -1;
75563
75783
  }
75564
75784
  close_dialog(gobj);
@@ -75583,6 +75803,8 @@ function run_import(gobj) {
75583
75803
  function ac_confirmed(gobj, event, kw, src) {
75584
75804
  let priv = gobj.priv;
75585
75805
  if (refuse_if_readonly(gobj, event)) return -1;
75806
+ if (reload_first(gobj, event)) return -1;
75807
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75586
75808
  if (kw.what === "import") return run_import(gobj);
75587
75809
  if (kw.what === "topic") {
75588
75810
  let topic = find_topic(priv.model, priv.treedb_id, kw.topic);
@@ -75716,7 +75938,11 @@ function create_gclass$1(gclass_name) {
75716
75938
  ]
75717
75939
  ];
75718
75940
  const states = [
75719
- ["ST_IDLE", COMMON.slice()],
75941
+ ["ST_IDLE", COMMON.concat([[
75942
+ "EV_CONFIRMED",
75943
+ ac_confirmed_on_nothing,
75944
+ null
75945
+ ]])],
75720
75946
  ["ST_LOADING", COMMON.concat([
75721
75947
  [
75722
75948
  "EV_SAVE_COLUMN",
@@ -75749,7 +75975,11 @@ function create_gclass$1(gclass_name) {
75749
75975
  null
75750
75976
  ]
75751
75977
  ])],
75752
- ["ST_EMPTY", COMMON.slice()],
75978
+ ["ST_EMPTY", COMMON.concat([[
75979
+ "EV_CONFIRMED",
75980
+ ac_confirmed_on_nothing,
75981
+ null
75982
+ ]])],
75753
75983
  ["ST_TREEDBS", COMMON.concat([
75754
75984
  [
75755
75985
  "EV_SELECT_TREEDB",