@yuneta/gobj-ui 7.25.8 → 7.25.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3057,6 +3057,8 @@ function show_notification(shell, kind, message, opts) {
3057
3057
  },
3058
3058
  [["button", {
3059
3059
  class: "TOAST_CLOSE delete",
3060
+ title: t("close"),
3061
+ "data-i18n-title": "close",
3060
3062
  "aria-label": t("close"),
3061
3063
  "data-i18n-aria-label": "close"
3062
3064
  }], [
@@ -3180,6 +3182,8 @@ function yui_shell_show_modal(shell, content, opts) {
3180
3182
  {
3181
3183
  class: "MODAL_CLOSE yui-dialog-x",
3182
3184
  type: "button",
3185
+ title: t("close"),
3186
+ "data-i18n-title": "close",
3183
3187
  "aria-label": t("close"),
3184
3188
  "data-i18n-aria-label": "close"
3185
3189
  },
@@ -3201,6 +3205,8 @@ function yui_shell_show_modal(shell, content, opts) {
3201
3205
  ]];
3202
3206
  if (with_close) modal_children.push(["button", {
3203
3207
  class: "MODAL_CLOSE modal-close is-large",
3208
+ title: t("close"),
3209
+ "data-i18n-title": "close",
3204
3210
  "aria-label": t("close"),
3205
3211
  "data-i18n-aria-label": "close"
3206
3212
  }]);
@@ -3355,6 +3361,8 @@ function build_dialog(shell, message, buttons, opts) {
3355
3361
  ]);
3356
3362
  $card_children.push(["button", {
3357
3363
  class: "CONFIRM_CLOSE delete yui-confirm-x",
3364
+ title: t("close"),
3365
+ "data-i18n-title": "close",
3358
3366
  "aria-label": t("close"),
3359
3367
  "data-i18n-aria-label": "close"
3360
3368
  }], [
@@ -72168,7 +72176,9 @@ var attrs_table$1 = [
72168
72176
  ];
72169
72177
  var PRIVATE_DATA$1 = {
72170
72178
  records: null,
72179
+ records_before: null,
72171
72180
  model: null,
72181
+ model_gen: 0,
72172
72182
  pending: 0,
72173
72183
  load_error: "",
72174
72184
  load_round: 0,
@@ -72183,6 +72193,7 @@ var PRIVATE_DATA$1 = {
72183
72193
  order_undo: null,
72184
72194
  diagram_gobj: null,
72185
72195
  dialog: null,
72196
+ dialog_gen: 0,
72186
72197
  save_queue: null,
72187
72198
  save_return: "",
72188
72199
  save_wrote: false,
@@ -72343,6 +72354,29 @@ function refuse_if_readonly(gobj, event) {
72343
72354
  yui_shell_show_error(yui_shell_of(gobj), "the treedb is read-only", { t });
72344
72355
  return true;
72345
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
+ }
72346
72380
  /***************************
72347
72381
  * The model
72348
72382
  ***************************/
@@ -72357,7 +72391,11 @@ function refuse_if_readonly(gobj, event) {
72357
72391
  * and the toolbar stops answering: left up, a click on a card, on
72358
72392
  * Back or on the drawing answered "Event NOT DEFINED in state
72359
72393
  * ST_LOADING" and was lost (third independent review). A dialog
72360
- * left open is answered in ST_LOADING instead (ac_wait_for_the_load).
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.
72361
72399
  *
72362
72400
  * `keep_written`: a load the host did not ask for -- the reconnect,
72363
72401
  * a write that turned out done -- keeps what this session wrote.
@@ -72367,12 +72405,16 @@ function refuse_if_readonly(gobj, event) {
72367
72405
  * is not even asked): the records the model was built on are put
72368
72406
  * back (emptied, the next write patched them into a model with no
72369
72407
  * treedb), the round is spent so a request that did leave is
72370
- * stale, and the session back asks again.
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()).
72371
72411
  ***************************************************************/
72372
72412
  function request_model(gobj, keep_written) {
72373
72413
  let priv = gobj.priv;
72374
72414
  if (!gobj_read_pointer_attr(gobj, "gobj_remote_yuno")) return -1;
72415
+ forget_import_plan(gobj);
72375
72416
  let previous = priv.records;
72417
+ priv.records_before = previous;
72376
72418
  priv.records = {
72377
72419
  treedbs: [],
72378
72420
  topics: [],
@@ -72398,6 +72440,7 @@ function request_model(gobj, keep_written) {
72398
72440
  }
72399
72441
  if (left < 3) {
72400
72442
  priv.records = previous;
72443
+ priv.records_before = null;
72401
72444
  priv.load_round++;
72402
72445
  priv.reload_on_open = true;
72403
72446
  priv.load_error = t("cannot reach the treedb");
@@ -72493,9 +72536,10 @@ function start_measuring(gobj) {
72493
72536
  * until the host saves it (C_TREEDB's save-schema, which raises the
72494
72537
  * versions of what changed). Two sources say a topic is one, and
72495
72538
  * they are kept APART because they are forgotten differently:
72496
- * - `written`: what THIS session wrote since the model was loaded
72497
- * (a reload, the host's EV_REFRESH, forgets it -- the store says
72498
- * 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());
72499
72543
  * - `host_ids`: what the host said last (EV_DRAFTS), replaced WHOLE
72500
72544
  * by the next EV_DRAFTS. Folded into `written`, a topic the host
72501
72545
  * named once stayed a draft after the Save that published it.
@@ -72663,6 +72707,8 @@ function render_toolbar(gobj) {
72663
72707
  let readonly = is_readonly(gobj);
72664
72708
  let has_model = !!priv.model;
72665
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);
72666
72712
  let in_flight = state === "ST_SAVING" || state === "ST_LOADING";
72667
72713
  let $left = [];
72668
72714
  if (priv.treedb_id && on_a_treedb) $left.push([
@@ -72738,17 +72784,17 @@ function render_toolbar(gobj) {
72738
72784
  $trail
72739
72785
  ]);
72740
72786
  let $right = [];
72741
- if (priv.treedb_id && has_model && on_a_treedb) {
72787
+ if (priv.treedb_id && has_model && treedb_here) {
72742
72788
  $right.push(toolbar_button("SCHEMA_DIAGRAM_BTN", "yi-compass-drafting", priv.diagram ? "topics" : "diagram", "EV_TOGGLE_DIAGRAM", false));
72743
72789
  $right.push(toolbar_button("SCHEMA_VALIDATE_BTN", "yi-square-check", "check", "EV_VALIDATE", false));
72744
72790
  $right.push(toolbar_button("SCHEMA_EXPORT_BTN", "yi-download", "export", "EV_EXPORT", false));
72745
72791
  if (!readonly) $right.push(toolbar_button("SCHEMA_IMPORT_BTN", "yi-upload", "import", "EV_IMPORT", false));
72746
72792
  }
72747
- if (priv.topic_name && !readonly && !priv.diagram && on_a_treedb) {
72793
+ if (priv.topic_name && !readonly && !priv.diagram && topic_here) {
72748
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));
72749
72795
  $right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus", "new column", "EV_ADD_COLUMN", false));
72750
72796
  }
72751
- 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));
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));
72752
72798
  $right.push(toolbar_button("SCHEMA_REFRESH_BTN", "yi-arrows-rotate", "refresh", "EV_REFRESH", state === "ST_LOADING"));
72753
72799
  let $bar = createElement2([
72754
72800
  "div",
@@ -73568,6 +73614,7 @@ function close_dialog(gobj) {
73568
73614
  function open_dialog(gobj, $content, title, logical, title_prefix) {
73569
73615
  let priv = gobj.priv;
73570
73616
  close_dialog(gobj);
73617
+ priv.dialog_gen = priv.model_gen;
73571
73618
  priv.dialog = yui_shell_show_modal(yui_shell_of(gobj), $content, {
73572
73619
  dialog: true,
73573
73620
  title,
@@ -73614,11 +73661,28 @@ function name_control($spec, label) {
73614
73661
  $spec[1]["aria-label"] = t(label);
73615
73662
  $spec[1]["data-i18n-aria-label"] = label;
73616
73663
  }
73664
+ if (!$spec[1].title) {
73665
+ $spec[1].title = t(label);
73666
+ $spec[1]["data-i18n-title"] = label;
73667
+ }
73617
73668
  return true;
73618
73669
  }
73619
73670
  for (let child of $spec[2] || []) if (name_control(child, label)) return true;
73620
73671
  return false;
73621
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
+ }
73622
73686
  function field(logical, name, label, $control, help) {
73623
73687
  name_control($control, label);
73624
73688
  return [
@@ -73795,7 +73859,7 @@ function read_flags($root) {
73795
73859
  * than not offering it.
73796
73860
  ***************************************************************/
73797
73861
  function open_column_form(gobj, topic, col, prefill) {
73798
- gobj.priv;
73862
+ let priv = gobj.priv;
73799
73863
  let record = prefill || col && col.record || {};
73800
73864
  let creating = !col;
73801
73865
  let type = record.type || "string";
@@ -73805,6 +73869,7 @@ function open_column_form(gobj, topic, col, prefill) {
73805
73869
  let hook_col = hook_topic ? hook[hook_topic] : "";
73806
73870
  let treedb = current_treedb(gobj);
73807
73871
  let sibling_topics = treedb ? treedb.topics.map((x) => x.name) : [];
73872
+ let model_gen = priv.model_gen;
73808
73873
  let $form = createElement2([
73809
73874
  "div",
73810
73875
  { class: "SCHEMA_COL_FORM box" },
@@ -73867,10 +73932,10 @@ function open_column_form(gobj, topic, col, prefill) {
73867
73932
  },
73868
73933
  [[
73869
73934
  "button",
73870
- {
73935
+ name_attrs("cancel", {
73871
73936
  class: "SCHEMA_COL_FORM_CANCEL button",
73872
73937
  type: "button"
73873
- },
73938
+ }),
73874
73939
  [[
73875
73940
  "span",
73876
73941
  { i18n: "cancel" },
@@ -73878,10 +73943,10 @@ function open_column_form(gobj, topic, col, prefill) {
73878
73943
  ]]
73879
73944
  ], [
73880
73945
  "button",
73881
- {
73946
+ name_attrs("save", {
73882
73947
  class: "SCHEMA_COL_FORM_SAVE button is-primary",
73883
73948
  type: "button"
73884
- },
73949
+ }),
73885
73950
  [[
73886
73951
  "span",
73887
73952
  { class: "icon" },
@@ -73921,7 +73986,8 @@ function open_column_form(gobj, topic, col, prefill) {
73921
73986
  topic: topic.name,
73922
73987
  col: creating ? "" : col.name,
73923
73988
  creating,
73924
- values
73989
+ values,
73990
+ model_gen
73925
73991
  }, gobj);
73926
73992
  });
73927
73993
  open_dialog(gobj, $form, creating ? "new column" : "edit column", "SCHEMA_COL_FORM_DIALOG", creating ? topic.name : `${topic.name}.${col.name}`);
@@ -73944,6 +74010,7 @@ function open_topic_form(gobj, treedb, topic) {
73944
74010
  let record = topic && topic.record || {};
73945
74011
  let creating = !topic;
73946
74012
  let col_names = topic ? topic.cols.map((c) => c.name) : [];
74013
+ let model_gen = gobj.priv.model_gen;
73947
74014
  let $form = createElement2([
73948
74015
  "div",
73949
74016
  { class: "SCHEMA_TOPIC_FORM box" },
@@ -74002,10 +74069,10 @@ function open_topic_form(gobj, treedb, topic) {
74002
74069
  },
74003
74070
  [[
74004
74071
  "button",
74005
- {
74072
+ name_attrs("cancel", {
74006
74073
  class: "SCHEMA_TOPIC_FORM_CANCEL button",
74007
74074
  type: "button"
74008
- },
74075
+ }),
74009
74076
  [[
74010
74077
  "span",
74011
74078
  { i18n: "cancel" },
@@ -74013,10 +74080,10 @@ function open_topic_form(gobj, treedb, topic) {
74013
74080
  ]]
74014
74081
  ], [
74015
74082
  "button",
74016
- {
74083
+ name_attrs("save", {
74017
74084
  class: "SCHEMA_TOPIC_FORM_SAVE button is-primary",
74018
74085
  type: "button"
74019
- },
74086
+ }),
74020
74087
  [[
74021
74088
  "span",
74022
74089
  { class: "icon" },
@@ -74039,7 +74106,8 @@ function open_topic_form(gobj, treedb, topic) {
74039
74106
  gobj_send_event(gobj, "EV_SAVE_TOPIC", {
74040
74107
  topic: creating ? "" : topic.name,
74041
74108
  creating,
74042
- values: read_form($form)
74109
+ values: read_form($form),
74110
+ model_gen
74043
74111
  }, gobj);
74044
74112
  });
74045
74113
  open_dialog(gobj, $form, creating ? "new topic" : "edit topic", "SCHEMA_TOPIC_FORM_DIALOG", creating ? treedb.id : `${treedb.id}.${topic.name}`);
@@ -74319,6 +74387,7 @@ function copy_text(gobj, $text) {
74319
74387
  * plan itself, so what is confirmed is what runs.
74320
74388
  ***************************************************************/
74321
74389
  function open_import(gobj, treedb) {
74390
+ let model_gen = gobj.priv.model_gen;
74322
74391
  let $content = createElement2([
74323
74392
  "div",
74324
74393
  { class: "SCHEMA_IMPORT box" },
@@ -74333,12 +74402,12 @@ function open_import(gobj, treedb) {
74333
74402
  ],
74334
74403
  [
74335
74404
  "textarea",
74336
- {
74405
+ name_attrs("schema", {
74337
74406
  class: "SCHEMA_IMPORT_TEXT textarea is-small is-family-monospace",
74338
74407
  rows: "12",
74339
74408
  spellcheck: "false",
74340
74409
  placeholder: "{\"id\": \"...\", \"schema_version\": \"1\", \"topics\": []}"
74341
- },
74410
+ }),
74342
74411
  ""
74343
74412
  ],
74344
74413
  [
@@ -74371,10 +74440,10 @@ function open_import(gobj, treedb) {
74371
74440
  [
74372
74441
  [
74373
74442
  "button",
74374
- {
74443
+ name_attrs("cancel", {
74375
74444
  class: "SCHEMA_IMPORT_CANCEL button",
74376
74445
  type: "button"
74377
- },
74446
+ }),
74378
74447
  [[
74379
74448
  "span",
74380
74449
  { i18n: "cancel" },
@@ -74383,10 +74452,10 @@ function open_import(gobj, treedb) {
74383
74452
  ],
74384
74453
  [
74385
74454
  "button",
74386
- {
74455
+ name_attrs("preview", {
74387
74456
  class: "SCHEMA_IMPORT_PREVIEW button",
74388
74457
  type: "button"
74389
- },
74458
+ }),
74390
74459
  [[
74391
74460
  "span",
74392
74461
  { class: "icon" },
@@ -74399,11 +74468,11 @@ function open_import(gobj, treedb) {
74399
74468
  ],
74400
74469
  [
74401
74470
  "button",
74402
- {
74471
+ name_attrs("import", {
74403
74472
  class: "SCHEMA_IMPORT_RUN button is-warning",
74404
74473
  type: "button",
74405
74474
  disabled: "disabled"
74406
- },
74475
+ }),
74407
74476
  [[
74408
74477
  "span",
74409
74478
  { class: "icon" },
@@ -74430,18 +74499,31 @@ function open_import(gobj, treedb) {
74430
74499
  evt.stopPropagation();
74431
74500
  gobj_send_event(gobj, "EV_PREVIEW_IMPORT", {
74432
74501
  text: $text.value,
74433
- prune: $prune.checked
74502
+ prune: $prune.checked,
74503
+ model_gen
74434
74504
  }, gobj);
74435
74505
  });
74436
74506
  $run.addEventListener("click", (evt) => {
74437
74507
  evt.stopPropagation();
74438
- gobj_send_event(gobj, "EV_APPLY_IMPORT", {}, gobj);
74508
+ gobj_send_event(gobj, "EV_APPLY_IMPORT", { model_gen }, gobj);
74439
74509
  });
74440
74510
  gobj.priv.import_pane = $plan_pane;
74441
74511
  gobj.priv.import_run = $run;
74442
74512
  open_dialog(gobj, $content, "import", "SCHEMA_IMPORT_DIALOG", treedb.id);
74443
74513
  }
74444
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
+ /***************************************************************
74445
74527
  * The plan, drawn where the paste is: one line per write, the
74446
74528
  * deletions apart and counted, because they are what the
74447
74529
  * operator is being asked about.
@@ -74568,7 +74650,8 @@ function open_orphans(gobj) {
74568
74650
  { class: "SCHEMA_ORPHAN_ACTIONS has-text-right" },
74569
74651
  readonly ? [] : [row_icon(gobj, "SCHEMA_ORPHAN_DELETE", "yi-trash", "delete", "EV_DELETE_ORPHAN", {
74570
74652
  kind,
74571
- id: entry.id
74653
+ id: entry.id,
74654
+ model_gen: priv.model_gen
74572
74655
  })]
74573
74656
  ]
74574
74657
  ]
@@ -74740,6 +74823,10 @@ function transport_dropped(gobj) {
74740
74823
  priv.load_round++;
74741
74824
  priv.pending = 0;
74742
74825
  priv.load_error = "";
74826
+ if (priv.records_before) {
74827
+ priv.records = priv.records_before;
74828
+ priv.records_before = null;
74829
+ }
74743
74830
  return end_load(gobj);
74744
74831
  }
74745
74832
  return 0;
@@ -74750,11 +74837,22 @@ function transport_dropped(gobj) {
74750
74837
  * in flight (ac_show() kept it), or the one it had. Without a
74751
74838
  * model there is no screen to go to: the position is kept for the
74752
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.
74753
74846
  ***************************************************************/
74754
74847
  function end_load(gobj) {
74755
74848
  let priv = gobj.priv;
74756
74849
  let seg = priv.pending_seg;
74757
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
+ }
74758
74856
  if (priv.model) {
74759
74857
  if (seg !== null) return apply_seg(gobj, seg);
74760
74858
  return go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
@@ -74970,10 +75068,20 @@ function ac_mt_command_answer(gobj, event, kw, src) {
74970
75068
  else if (priv.records && Array.isArray(priv.records[topic_name])) priv.records[topic_name] = Array.isArray(data) ? data : [];
74971
75069
  if (priv.pending > 0) return 0;
74972
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
+ }
74973
75079
  priv.model = null;
74974
75080
  return end_load(gobj);
74975
75081
  }
74976
75082
  priv.order_undo = {};
75083
+ priv.records_before = null;
75084
+ priv.model_gen++;
74977
75085
  build_model(gobj);
74978
75086
  start_measuring(gobj);
74979
75087
  return end_load(gobj);
@@ -74995,11 +75103,14 @@ function ac_mt_command_answer(gobj, event, kw, src) {
74995
75103
  let record = is_object(data) ? data : Array.isArray(data) && is_object(data[0]) ? data[0] : null;
74996
75104
  if (record) patch_record(gobj, topic_name, record);
74997
75105
  else {
74998
- 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 });
74999
75109
  if (topic_name === T_TOPICS || topic_name === T_COLS) {
75000
75110
  let write = priv.save_queue[0];
75001
75111
  mark_written(gobj, topic_name, write ? write.record : null);
75002
75112
  }
75113
+ priv.reload_after_write = false;
75003
75114
  priv.save_queue = [];
75004
75115
  priv.save_return = "";
75005
75116
  priv.save_wrote = false;
@@ -75057,8 +75168,14 @@ function late_write_done(gobj, command, topic_name, data) {
75057
75168
  /***************************************************************
75058
75169
  * The topic a record written belongs to, read off the RECORD and
75059
75170
  * not off the screen: a write answered late may be about a topic
75060
- * the operator has left. A column names its topic in its fkey
75061
- * (`topics^<topic id>^cols`); a topic is its own id.
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).
75062
75179
  ***************************************************************/
75063
75180
  function mark_written_record(gobj, topic_name, record) {
75064
75181
  let priv = gobj.priv;
@@ -75068,11 +75185,7 @@ function mark_written_record(gobj, topic_name, record) {
75068
75185
  return;
75069
75186
  }
75070
75187
  if (topic_name !== T_COLS) return;
75071
- let refs = Array.isArray(record.topics) ? record.topics : typeof record.topics === "string" ? [record.topics] : [];
75072
- for (let ref of refs) {
75073
- let parts = String(ref).split("^");
75074
- if (parts.length >= 2 && parts[1]) priv.written[parts[1]] = true;
75075
- }
75188
+ for (let ref of parse_fkey_ref(record.topics)) priv.written[ref.id] = true;
75076
75189
  }
75077
75190
  /***************************************************************
75078
75191
  * Remember which topic this write belongs to, which is what
@@ -75156,14 +75269,19 @@ function ac_refresh$1(gobj, event, kw, src) {
75156
75269
  * operator can still reach, and what it asks is computed against
75157
75270
  * a model the answers in the air are about to replace.
75158
75271
  *
75159
- * Refused, and SAID -- and the dialog stays open with what was
75160
- * typed, so the same Save works once the load is in. Undeclared,
75161
- * it answered "Event NOT DEFINED in state ST_LOADING" and the
75162
- * edit was gone with no word (third independent review).
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.
75163
75281
  ***************************************************************/
75164
75282
  function ac_wait_for_the_load(gobj, event, kw, src) {
75165
75283
  log_warning(`${gobj_short_name(gobj)}: ${event} refused, the schemas are loading`);
75166
- yui_shell_show_error(yui_shell_of(gobj), "the schemas are loading: try again when they are in", { t });
75284
+ yui_shell_show_error(yui_shell_of(gobj), "the schemas are loading: wait for them", { t });
75167
75285
  return -1;
75168
75286
  }
75169
75287
  /***************************************************************
@@ -75229,6 +75347,7 @@ function ac_show_orphans(gobj, event, kw, src) {
75229
75347
  * to feed.
75230
75348
  ***************************************************************/
75231
75349
  function confirm_then(gobj, message, detail, kw) {
75350
+ kw = Object.assign({ model_gen: gobj.priv.model_gen }, kw);
75232
75351
  yui_shell_confirm_danger(yui_shell_of(gobj), message, {
75233
75352
  t,
75234
75353
  detail
@@ -75290,6 +75409,7 @@ function ac_save_column(gobj, event, kw, src) {
75290
75409
  let topic = find_topic(priv.model, priv.treedb_id, kw.topic);
75291
75410
  let col = kw.creating ? null : find_col(priv.model, priv.treedb_id, kw.topic, kw.col);
75292
75411
  if (refuse_if_readonly(gobj, event)) return -1;
75412
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75293
75413
  if (!topic || !kw.creating && !col) {
75294
75414
  log_error(`${gobj_short_name(gobj)}: ${event} names no column: ${kw.topic}.${kw.col}`);
75295
75415
  return -1;
@@ -75411,6 +75531,7 @@ function ac_save_topic(gobj, event, kw, src) {
75411
75531
  let treedb = current_treedb(gobj);
75412
75532
  let topic = kw.creating ? null : find_topic(priv.model, priv.treedb_id, kw.topic);
75413
75533
  if (refuse_if_readonly(gobj, event)) return -1;
75534
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75414
75535
  if (!treedb || !kw.creating && !topic) {
75415
75536
  log_error(`${gobj_short_name(gobj)}: ${event} names no topic: ${kw.topic}`);
75416
75537
  return -1;
@@ -75453,6 +75574,7 @@ function ac_delete_topic(gobj, event, kw, src) {
75453
75574
  ***************************************************************/
75454
75575
  function ac_delete_orphan(gobj, event, kw, src) {
75455
75576
  if (refuse_if_readonly(gobj, event)) return -1;
75577
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75456
75578
  if (empty_string(kw.id)) {
75457
75579
  log_error(`${gobj_short_name(gobj)}: ${event} names nothing`);
75458
75580
  return -1;
@@ -75509,6 +75631,7 @@ function ac_preview_import(gobj, event, kw, src) {
75509
75631
  let priv = gobj.priv;
75510
75632
  let treedb = current_treedb(gobj);
75511
75633
  let incoming = null;
75634
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75512
75635
  if (!treedb) {
75513
75636
  log_error(`${gobj_short_name(gobj)}: ${event} with no treedb open`);
75514
75637
  return -1;
@@ -75536,6 +75659,7 @@ function ac_preview_import(gobj, event, kw, src) {
75536
75659
  function ac_apply_import(gobj, event, kw, src) {
75537
75660
  let plan = gobj.priv.import_plan;
75538
75661
  if (refuse_if_readonly(gobj, event)) return -1;
75662
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75539
75663
  if (!plan || plan.writes.length === 0) {
75540
75664
  log_error(`${gobj_short_name(gobj)}: ${event} with no plan to run`);
75541
75665
  return -1;
@@ -75578,6 +75702,7 @@ function run_import(gobj) {
75578
75702
  function ac_confirmed(gobj, event, kw, src) {
75579
75703
  let priv = gobj.priv;
75580
75704
  if (refuse_if_readonly(gobj, event)) return -1;
75705
+ if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75581
75706
  if (kw.what === "import") return run_import(gobj);
75582
75707
  if (kw.what === "topic") {
75583
75708
  let topic = find_topic(priv.model, priv.treedb_id, kw.topic);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.25.8",
3
+ "version": "7.25.9",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",