@yuneta/gobj-ui 6.1.0 → 6.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -631,11 +631,21 @@ else.
631
631
  `ST_LOADING`, `ST_EMPTY`, `ST_TREEDBS`, `ST_TOPICS`, `ST_DIAGRAM`,
632
632
  `ST_COLUMNS`, `ST_SAVING`.
633
633
 
634
+ **Three words decide whether a write does what it says** (`schema_write_options.js`,
635
+ and they are tested because getting one wrong costs a store repaired by hand):
636
+ a create goes through `update-node` and not `create-node`, because only that
637
+ path carries **`autolink`** — and without a link a new column belongs to no
638
+ topic. `autolink` rewrites a node's links from the fkey fields the record
639
+ carries, so it goes with a create, where the record has one, **and with nothing
640
+ else**: on a partial update it finds none, reads that as "no parents", and
641
+ detaches the node. Raising a topic's version with it on unlinked that topic
642
+ from its treedb, and the write answered success.
643
+
634
644
  The logic is pure and tested apart from the view: `schema_model.js` (the three
635
645
  lists regrouped — grouping follows the **fkey**, not a split of the qualified
636
646
  id on `.`, which works right up to the first name that carries one),
637
647
  `schema_validate.js`, `schema_descs.js`, `schema_to_c.js`, `schema_import.js`,
638
- `schema_flags.js`. Since 6.1.0.
648
+ `schema_flags.js`, `schema_write_options.js`. Since 6.1.0.
639
649
 
640
650
  ### Frontend view — `setup_frontend_view`
641
651
 
@@ -20587,6 +20587,22 @@ function build_schema_model(records) {
20587
20587
  };
20588
20588
  }
20589
20589
  /***************************************************************
20590
+ * Is there a value here at all?
20591
+ *
20592
+ * The store answers a `blob` column that was never set with an
20593
+ * EMPTY COLLECTION, not with nothing: `enum: {}`, `hook: {}`,
20594
+ * `default: {}`. Read as "a value", those turn every export into
20595
+ * a schema full of empty objects — and `'hook': {}` in a literal
20596
+ * is a hook with no mapping, which is a link the treedb builds
20597
+ * and nothing writes.
20598
+ ***************************************************************/
20599
+ function is_empty_value(value) {
20600
+ if (value === null || value === void 0 || value === "") return true;
20601
+ if (Array.isArray(value)) return value.length === 0;
20602
+ if (typeof value === "object") return Object.keys(value).length === 0;
20603
+ return false;
20604
+ }
20605
+ /***************************************************************
20590
20606
  * The fields of a column that are DECLARED as one thing and
20591
20607
  * STORED as another.
20592
20608
  *
@@ -20924,6 +20940,7 @@ var COL_STORAGE_FIELDS = [
20924
20940
  "value",
20925
20941
  "topics",
20926
20942
  "order",
20943
+ "_geometry",
20927
20944
  "__md_treedb__"
20928
20945
  ];
20929
20946
  var TOPIC_STORAGE_FIELDS = [
@@ -20932,6 +20949,7 @@ var TOPIC_STORAGE_FIELDS = [
20932
20949
  "treedbs",
20933
20950
  "cols",
20934
20951
  "order",
20952
+ "_geometry",
20935
20953
  "__md_treedb__"
20936
20954
  ];
20937
20955
  var COL_JSON_FIELDS = [
@@ -20955,13 +20973,16 @@ function col_desc(col) {
20955
20973
  let desc = {};
20956
20974
  for (let [key, value] of Object.entries(record)) {
20957
20975
  if (COL_STORAGE_FIELDS.indexOf(key) >= 0) continue;
20958
- if (value === null || value === void 0 || value === "") continue;
20959
- desc[key] = COL_JSON_FIELDS.indexOf(key) >= 0 ? as_json(value) : value;
20976
+ if (is_empty_value(value)) continue;
20977
+ let read = COL_JSON_FIELDS.indexOf(key) >= 0 ? as_json(value) : value;
20978
+ if (is_empty_value(read)) continue;
20979
+ desc[key] = read;
20960
20980
  }
20961
20981
  desc.id = col.name;
20962
20982
  desc.flag = col_flags(record);
20963
20983
  let hook = col_hook(record);
20964
- if (hook) desc.hook = hook;
20984
+ if (hook && !is_empty_value(hook)) desc.hook = hook;
20985
+ else delete desc.hook;
20965
20986
  let e = col_enum(record);
20966
20987
  if (e.length > 0) desc.enum = e;
20967
20988
  return desc;
@@ -20979,7 +21000,7 @@ function topic_descs(treedb) {
20979
21000
  let desc = {};
20980
21001
  for (let [key, value] of Object.entries(record)) {
20981
21002
  if (TOPIC_STORAGE_FIELDS.indexOf(key) >= 0) continue;
20982
- if (value === null || value === void 0 || value === "") continue;
21003
+ if (is_empty_value(value)) continue;
20983
21004
  desc[key] = value;
20984
21005
  }
20985
21006
  desc.topic_name = topic.name;
@@ -21036,6 +21057,7 @@ var COL_SKIP = [
21036
21057
  "value",
21037
21058
  "topics",
21038
21059
  "order",
21060
+ "_geometry",
21039
21061
  "__md_treedb__"
21040
21062
  ];
21041
21063
  var TOPIC_SKIP = [
@@ -21044,6 +21066,7 @@ var TOPIC_SKIP = [
21044
21066
  "treedbs",
21045
21067
  "cols",
21046
21068
  "order",
21069
+ "_geometry",
21047
21070
  "__md_treedb__"
21048
21071
  ];
21049
21072
  var JSON_FIELDS$1 = [
@@ -21097,8 +21120,10 @@ function schema_to_json(treedb) {
21097
21120
  let jn_topic = { id: topic.name };
21098
21121
  for (let [key, value] of Object.entries(record)) {
21099
21122
  if (TOPIC_SKIP.indexOf(key) >= 0) continue;
21100
- if (value === null || value === void 0 || value === "") continue;
21101
- jn_topic[key] = JSON_FIELDS$1.indexOf(key) >= 0 ? as_json(value) : value;
21123
+ if (is_empty_value(value)) continue;
21124
+ let read = JSON_FIELDS$1.indexOf(key) >= 0 ? as_json(value) : value;
21125
+ if (is_empty_value(read)) continue;
21126
+ jn_topic[key] = read;
21102
21127
  }
21103
21128
  if (jn_topic.topic_version !== void 0) jn_topic.topic_version = version(jn_topic.topic_version);
21104
21129
  let pkey2s = topic_pkey2s(record);
@@ -21111,14 +21136,17 @@ function schema_to_json(treedb) {
21111
21136
  let jn_col = {};
21112
21137
  for (let [key, value] of Object.entries(col_record)) {
21113
21138
  if (COL_SKIP.indexOf(key) >= 0) continue;
21114
- if (value === null || value === void 0 || value === "") continue;
21115
- jn_col[key] = JSON_FIELDS$1.indexOf(key) >= 0 ? as_json(value) : value;
21139
+ if (is_empty_value(value)) continue;
21140
+ let read = JSON_FIELDS$1.indexOf(key) >= 0 ? as_json(value) : value;
21141
+ if (is_empty_value(read)) continue;
21142
+ jn_col[key] = read;
21116
21143
  }
21117
21144
  let flags = col_flags(col_record);
21118
21145
  if (flags.length > 0) jn_col.flag = flags;
21119
21146
  else delete jn_col.flag;
21120
21147
  let hook = col_hook(col_record);
21121
- if (hook) jn_col.hook = hook;
21148
+ if (hook && !is_empty_value(hook)) jn_col.hook = hook;
21149
+ else delete jn_col.hook;
21122
21150
  let e = col_enum(col_record);
21123
21151
  if (e.length > 0) jn_col.enum = e;
21124
21152
  let ordered_col = {};
@@ -21303,7 +21331,7 @@ function same_value(field, a, b) {
21303
21331
  list = list.filter((f) => typeof f === "string" && f.length > 0).sort();
21304
21332
  return JSON.stringify(list);
21305
21333
  }
21306
- if (v === null || v === void 0 || v === "") return "";
21334
+ if (is_empty_value(v)) return "";
21307
21335
  if (typeof v === "object") return JSON.stringify(v);
21308
21336
  return String(v);
21309
21337
  };
@@ -21316,8 +21344,10 @@ function incoming_col_fields(col) {
21316
21344
  let out = {};
21317
21345
  for (let field of COL_FIELDS) {
21318
21346
  let value = col ? col[field] : void 0;
21319
- if (value === void 0 || value === null || value === "") continue;
21320
- out[field] = JSON_FIELDS.indexOf(field) >= 0 ? as_json(value) : value;
21347
+ if (is_empty_value(value)) continue;
21348
+ let read = JSON_FIELDS.indexOf(field) >= 0 ? as_json(value) : value;
21349
+ if (is_empty_value(read)) continue;
21350
+ out[field] = read;
21321
21351
  }
21322
21352
  if (Array.isArray(out.flag)) out.flag = out.flag.filter((f) => typeof f === "string" && f.length > 0);
21323
21353
  else if (typeof out.flag === "string" && out.flag) out.flag = [out.flag];
@@ -21330,14 +21360,17 @@ function stored_col_fields(record) {
21330
21360
  let out = {};
21331
21361
  for (let field of COL_FIELDS) {
21332
21362
  let value = record ? record[field] : void 0;
21333
- if (value === void 0 || value === null || value === "") continue;
21334
- out[field] = JSON_FIELDS.indexOf(field) >= 0 ? as_json(value) : value;
21363
+ if (is_empty_value(value)) continue;
21364
+ let read = JSON_FIELDS.indexOf(field) >= 0 ? as_json(value) : value;
21365
+ if (is_empty_value(read)) continue;
21366
+ out[field] = read;
21335
21367
  }
21336
21368
  let flags = col_flags(record);
21337
21369
  if (flags.length > 0) out.flag = flags;
21338
21370
  else delete out.flag;
21339
21371
  let hook = col_hook(record);
21340
- if (hook) out.hook = hook;
21372
+ if (hook && !is_empty_value(hook)) out.hook = hook;
21373
+ else delete out.hook;
21341
21374
  let e = col_enum(record);
21342
21375
  if (e.length > 0) out.enum = e;
21343
21376
  return out;
@@ -21962,6 +21995,61 @@ function toggle_flag(current, name, on) {
21962
21995
  return out;
21963
21996
  }
21964
21997
  //#endregion
21998
+ //#region src/schema_write_options.js
21999
+ /***********************************************************************
22000
+ * schema_write_options.js
22001
+ *
22002
+ * The OPTIONS a schema write travels with, and why each one.
22003
+ *
22004
+ * Three words decide whether a write does what it says, and all
22005
+ * three are easy to get wrong in a way that succeeds:
22006
+ *
22007
+ * `create` a node that is not there yet is written by
22008
+ * `update-node` with this, not by `create-node`. The
22009
+ * two are not the same call: only the update path
22010
+ * carries `autolink`, and without a link a new column
22011
+ * belongs to no topic.
22012
+ *
22013
+ * `autolink` turns the fkey carried IN THE RECORD into a link.
22014
+ * It rewrites the node's links from the fkey fields
22015
+ * the record has — so on a PARTIAL update, which
22016
+ * carries none, it reads that as "no parents" and
22017
+ * UNLINKS the node. Raising a topic's version with it
22018
+ * on detached that topic from its treedb, and the
22019
+ * write returned success. It goes with a create,
22020
+ * where the record carries its fkey, and with nothing
22021
+ * else.
22022
+ *
22023
+ * `force` a delete of a node something points at. A column is
22024
+ * pointed at by the topic that owns it, which is not
22025
+ * a reason to refuse.
22026
+ *
22027
+ * Pure and tested, because the cost of getting it wrong is a
22028
+ * store that has to be repaired by hand, and nothing in the
22029
+ * answer says it happened.
22030
+ *
22031
+ * Copyright (c) 2026, ArtGins.
22032
+ * All Rights Reserved.
22033
+ ***********************************************************************/
22034
+ /***************************************************************
22035
+ * write_command(op) -> the treedb command that performs it
22036
+ ***************************************************************/
22037
+ function write_command(op) {
22038
+ return op === "delete" ? "delete-node" : "update-node";
22039
+ }
22040
+ /***************************************************************
22041
+ * write_options(op) -> the options it travels with
22042
+ ***************************************************************/
22043
+ function write_options(op) {
22044
+ if (op === "delete") return { force: true };
22045
+ if (op === "create") return {
22046
+ list_dict: true,
22047
+ create: true,
22048
+ autolink: true
22049
+ };
22050
+ return { list_dict: true };
22051
+ }
22052
+ //#endregion
21965
22053
  //#region src/c_yui_schema_editor.js
21966
22054
  /***********************************************************************
21967
22055
  * c_yui_schema_editor.js
@@ -22281,10 +22369,12 @@ function remote_command(gobj, command, kw) {
22281
22369
  service: treedb_name,
22282
22370
  treedb_name
22283
22371
  }, kw || {});
22284
- full_kw.__md_command__ = Object.assign({
22372
+ full_kw.__md_command__ = {
22285
22373
  purpose: PURPOSE,
22286
- command
22287
- }, kw && kw.topic_name ? { topic_name: kw.topic_name } : {});
22374
+ topic_name: kw && kw.topic_name || "",
22375
+ record_id: kw && kw.record_id || ""
22376
+ };
22377
+ delete full_kw.record_id;
22288
22378
  let ret = (0, _yuneta_gobj_js.gobj_command)(remote, command, full_kw, gobj);
22289
22379
  if (ret) {
22290
22380
  (0, _yuneta_gobj_js.log_error)(ret);
@@ -22533,9 +22623,9 @@ function render_toolbar(gobj) {
22533
22623
  let $right = [];
22534
22624
  if (priv.treedb_id && has_model) {
22535
22625
  $right.push(toolbar_button("SCHEMA_DIAGRAM_BTN", "yi-hexagon-nodes", priv.diagram ? "topics" : "diagram", "EV_TOGGLE_DIAGRAM", false));
22536
- $right.push(toolbar_button("SCHEMA_VALIDATE_BTN", "yi-circle-check", "check", "EV_VALIDATE", false));
22537
- $right.push(toolbar_button("SCHEMA_EXPORT_BTN", "yi-file-export", "export", "EV_EXPORT", false));
22538
- if (!readonly) $right.push(toolbar_button("SCHEMA_IMPORT_BTN", "yi-file-import", "import", "EV_IMPORT", false));
22626
+ $right.push(toolbar_button("SCHEMA_VALIDATE_BTN", "yi-square-check", "check", "EV_VALIDATE", false));
22627
+ $right.push(toolbar_button("SCHEMA_EXPORT_BTN", "yi-download", "export", "EV_EXPORT", false));
22628
+ if (!readonly) $right.push(toolbar_button("SCHEMA_IMPORT_BTN", "yi-upload", "import", "EV_IMPORT", false));
22539
22629
  }
22540
22630
  if (priv.topic_name && !readonly && !priv.diagram) $right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus", "new column", "EV_ADD_COLUMN", false));
22541
22631
  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));
@@ -22738,13 +22828,16 @@ function render_topics(gobj, $body) {
22738
22828
  return;
22739
22829
  }
22740
22830
  let readonly = is_readonly(gobj);
22831
+ let twice = repeated_names(treedb.topics);
22741
22832
  let $rows = [];
22742
22833
  for (let topic of treedb.topics) {
22743
22834
  let pending = priv.written[topic.id] && String(priv.baseline[topic.id]) === String(topic.topic_version);
22835
+ let ambiguous = !!twice[topic.name];
22836
+ let address = ambiguous ? topic.id : topic.name;
22744
22837
  let $actions = [];
22745
22838
  if (!readonly) {
22746
- $actions.push(row_icon(gobj, "SCHEMA_TOPIC_EDIT", "yi-pen", "edit topic", "EV_EDIT_TOPIC", { topic: topic.name }));
22747
- $actions.push(row_icon(gobj, "SCHEMA_TOPIC_DELETE", "yi-trash", "delete topic", "EV_DELETE_TOPIC", { topic: topic.name }));
22839
+ $actions.push(row_icon(gobj, "SCHEMA_TOPIC_EDIT", "yi-pen", "edit topic", "EV_EDIT_TOPIC", { topic: address }));
22840
+ $actions.push(row_icon(gobj, "SCHEMA_TOPIC_DELETE", "yi-trash", "delete topic", "EV_DELETE_TOPIC", { topic: address }));
22748
22841
  }
22749
22842
  $rows.push([
22750
22843
  "tr",
@@ -22757,22 +22850,38 @@ function render_topics(gobj, $body) {
22757
22850
  [
22758
22851
  "td",
22759
22852
  { class: "SCHEMA_TOPIC_NAME" },
22760
- [[
22761
- "span",
22762
- { class: "has-text-weight-semibold" },
22763
- `${topic.name}`
22764
- ], topic.system_topic ? [
22765
- "span",
22766
- {
22767
- class: "SCHEMA_TOPIC_SYSTEM tag is-light ml-2",
22768
- i18n: "system"
22769
- },
22770
- (0, i18next.t)("system")
22771
- ] : [
22772
- "span",
22773
- {},
22774
- ""
22775
- ]]
22853
+ [
22854
+ [
22855
+ "span",
22856
+ { class: "has-text-weight-semibold" },
22857
+ `${topic.name}`
22858
+ ],
22859
+ topic.system_topic ? [
22860
+ "span",
22861
+ {
22862
+ class: "SCHEMA_TOPIC_SYSTEM tag is-light ml-2",
22863
+ i18n: "system"
22864
+ },
22865
+ (0, i18next.t)("system")
22866
+ ] : [
22867
+ "span",
22868
+ {},
22869
+ ""
22870
+ ],
22871
+ ambiguous ? [
22872
+ "div",
22873
+ { class: "SCHEMA_TOPIC_ID is-size-7 has-text-grey" },
22874
+ [[
22875
+ "code",
22876
+ {},
22877
+ `${topic.id}`
22878
+ ]]
22879
+ ] : [
22880
+ "span",
22881
+ {},
22882
+ ""
22883
+ ]
22884
+ ]
22776
22885
  ],
22777
22886
  [
22778
22887
  "td",
@@ -22806,12 +22915,12 @@ function render_topics(gobj, $body) {
22806
22915
  {
22807
22916
  click: (evt) => {
22808
22917
  if (evt.target.closest(".SCHEMA_TOPIC_ACTIONS")) return;
22809
- (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_SELECT_TOPIC", { topic: topic.name }, gobj);
22918
+ (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_SELECT_TOPIC", { topic: address }, gobj);
22810
22919
  },
22811
22920
  keydown: (evt) => {
22812
22921
  if (evt.key !== "Enter" && evt.key !== " ") return;
22813
22922
  evt.preventDefault();
22814
- (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_SELECT_TOPIC", { topic: topic.name }, gobj);
22923
+ (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_SELECT_TOPIC", { topic: address }, gobj);
22815
22924
  }
22816
22925
  }
22817
22926
  ]);
@@ -22900,6 +23009,26 @@ function row_icon(gobj, logical, icon, key, event, kw) {
22900
23009
  ];
22901
23010
  }
22902
23011
  /***************************************************************
23012
+ * Which names appear more than once.
23013
+ *
23014
+ * A store can hold TWO GENERATIONS of the same schema: the
23015
+ * projector never deletes, so a treedb re-keyed by a newer SDK
23016
+ * keeps its old rowid-keyed rows next to the qualified ones, and
23017
+ * both are children of the same treedb with the same name. Drawn
23018
+ * as two identical rows that behave differently, that reads as a
23019
+ * bug in the editor; drawn with what tells them apart, it reads
23020
+ * as what it is.
23021
+ ***************************************************************/
23022
+ function repeated_names(list) {
23023
+ let seen = {};
23024
+ let twice = {};
23025
+ for (let entry of list) {
23026
+ if (seen[entry.name]) twice[entry.name] = true;
23027
+ seen[entry.name] = true;
23028
+ }
23029
+ return twice;
23030
+ }
23031
+ /***************************************************************
22903
23032
  * ST_COLUMNS — the columns of one topic, in schema order.
22904
23033
  *
22905
23034
  * The order is a FIELD (`order`), so the rows are draggable and
@@ -22925,8 +23054,9 @@ function render_columns(gobj, $body) {
22925
23054
  ]);
22926
23055
  let $banner = version_banner(gobj, topic);
22927
23056
  if ($banner) $wrap.appendChild($banner);
23057
+ let twice = repeated_names(topic.cols);
22928
23058
  let $rows = [];
22929
- for (let i = 0; i < topic.cols.length; i++) $rows.push(column_row(gobj, topic, topic.cols[i], i, readonly));
23059
+ for (let i = 0; i < topic.cols.length; i++) $rows.push(column_row(gobj, topic, topic.cols[i], i, readonly, twice));
22930
23060
  let $table = (0, _yuneta_gobj_js.createElement2)([
22931
23061
  "div",
22932
23062
  {
@@ -23047,7 +23177,7 @@ function version_banner(gobj, topic) {
23047
23177
  [[
23048
23178
  "span",
23049
23179
  { class: "icon" },
23050
- [["i", { class: "yi-arrow-up" }]]
23180
+ [["i", { class: "yi-chevron-up" }]]
23051
23181
  ], [
23052
23182
  "span",
23053
23183
  { i18n: "raise" },
@@ -23068,8 +23198,10 @@ function version_banner(gobj, topic) {
23068
23198
  * Yuneta event is plain JSON, so a DOM node never travels in
23069
23199
  * one.
23070
23200
  ***************************************************************/
23071
- function column_row(gobj, topic, col, index, readonly) {
23201
+ function column_row(gobj, topic, col, index, readonly, twice) {
23072
23202
  let record = col.record || {};
23203
+ let ambiguous = !!(twice && twice[col.name]);
23204
+ let address = ambiguous ? col.id : col.name;
23073
23205
  let flags = col_flags(record);
23074
23206
  let hook = col_hook(record);
23075
23207
  let is_pkey = col.name === (topic.pkey || "id");
@@ -23081,13 +23213,13 @@ function column_row(gobj, topic, col, index, readonly) {
23081
23213
  ];
23082
23214
  });
23083
23215
  let link = "";
23084
- if (hook) link = "→ " + Object.keys(hook).join(", ");
23216
+ if (hook && !is_empty_value(hook)) link = "→ " + Object.keys(hook).join(", ");
23085
23217
  else if (flags.indexOf("fkey") >= 0) link = "↖";
23086
23218
  let $actions = [];
23087
23219
  if (!readonly) {
23088
- $actions.push(row_icon(gobj, "SCHEMA_COL_EDIT", "yi-pen", "edit column", "EV_EDIT_COLUMN", { col: col.name }));
23089
- $actions.push(row_icon(gobj, "SCHEMA_COL_DUPLICATE", "yi-copy", "duplicate column", "EV_DUPLICATE_COLUMN", { col: col.name }));
23090
- $actions.push(row_icon(gobj, "SCHEMA_COL_DELETE", "yi-trash", "delete column", "EV_DELETE_COLUMN", { col: col.name }));
23220
+ $actions.push(row_icon(gobj, "SCHEMA_COL_EDIT", "yi-pen", "edit column", "EV_EDIT_COLUMN", { col: address }));
23221
+ $actions.push(row_icon(gobj, "SCHEMA_COL_DUPLICATE", "yi-copy", "duplicate column", "EV_DUPLICATE_COLUMN", { col: address }));
23222
+ $actions.push(row_icon(gobj, "SCHEMA_COL_DELETE", "yi-trash", "delete column", "EV_DELETE_COLUMN", { col: address }));
23091
23223
  }
23092
23224
  let $row = (0, _yuneta_gobj_js.createElement2)([
23093
23225
  "tr",
@@ -23109,22 +23241,38 @@ function column_row(gobj, topic, col, index, readonly) {
23109
23241
  [
23110
23242
  "td",
23111
23243
  { class: "SCHEMA_COL_NAME" },
23112
- [[
23113
- "code",
23114
- {},
23115
- `${col.name}`
23116
- ], is_pkey ? [
23117
- "span",
23118
- {
23119
- class: "SCHEMA_COL_PKEY tag is-info is-light ml-2",
23120
- i18n: "pkey"
23121
- },
23122
- (0, i18next.t)("pkey")
23123
- ] : [
23124
- "span",
23125
- {},
23126
- ""
23127
- ]]
23244
+ [
23245
+ [
23246
+ "code",
23247
+ {},
23248
+ `${col.name}`
23249
+ ],
23250
+ ambiguous ? [
23251
+ "span",
23252
+ { class: "SCHEMA_COL_ID is-size-7 has-text-grey ml-2" },
23253
+ [[
23254
+ "code",
23255
+ {},
23256
+ `${col.id}`
23257
+ ]]
23258
+ ] : [
23259
+ "span",
23260
+ {},
23261
+ ""
23262
+ ],
23263
+ is_pkey ? [
23264
+ "span",
23265
+ {
23266
+ class: "SCHEMA_COL_PKEY tag is-info is-light ml-2",
23267
+ i18n: "pkey"
23268
+ },
23269
+ (0, i18next.t)("pkey")
23270
+ ] : [
23271
+ "span",
23272
+ {},
23273
+ ""
23274
+ ]
23275
+ ]
23128
23276
  ],
23129
23277
  [
23130
23278
  "td",
@@ -23167,7 +23315,7 @@ function column_row(gobj, topic, col, index, readonly) {
23167
23315
  if (!readonly) wire_row_drag(gobj, $row);
23168
23316
  $row.addEventListener("dblclick", (evt) => {
23169
23317
  if (readonly || evt.target.closest(".SCHEMA_COL_ACTIONS")) return;
23170
- (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_EDIT_COLUMN", { col: col.name }, gobj);
23318
+ (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_EDIT_COLUMN", { col: address }, gobj);
23171
23319
  });
23172
23320
  return $row;
23173
23321
  }
@@ -23504,7 +23652,8 @@ function open_column_form(gobj, topic, col, prefill) {
23504
23652
  let record = prefill || col && col.record || {};
23505
23653
  let creating = !col;
23506
23654
  let type = record.type || "string";
23507
- let hook = col_hook(record) || {};
23655
+ let hook = col_hook(record);
23656
+ if (is_empty_value(hook)) hook = {};
23508
23657
  let hook_topic = Object.keys(hook)[0] || "";
23509
23658
  let hook_col = hook_topic ? hook[hook_topic] : "";
23510
23659
  let treedb = current_treedb(gobj);
@@ -23654,7 +23803,7 @@ function open_topic_form(gobj, treedb, topic) {
23654
23803
  [
23655
23804
  field("SCHEMA_TOPIC_FORM_NAME", "value", "topic", text_input("value", creating ? "" : topic.name, (0, i18next.t)("topic name"), !creating), creating ? "" : "a topic is keyed by its whole path: renaming it is creating another one"),
23656
23805
  field("SCHEMA_TOPIC_FORM_PKEY", "pkey", "pkey", creating ? text_input("pkey", "id", "id") : select_input("pkey", record.pkey || "id", col_names.length > 0 ? col_names : [record.pkey || "id"])),
23657
- field("SCHEMA_TOPIC_FORM_PKEY2S", "pkey2s", "secondary keys", text_input("pkey2s", stringify_field(record.pkey2s), ""), "the column a record is KNOWN by when its key is composed"),
23806
+ field("SCHEMA_TOPIC_FORM_PKEY2S", "pkey2s", "secondary keys", text_input("pkey2s", stringify_field(record.pkey2s), ""), "the column a record is known by when its key is composed"),
23658
23807
  field("SCHEMA_TOPIC_FORM_SYSTEM_FLAG", "system_flag", "system flag", text_input("system_flag", record.system_flag || "sf_string_key", "")),
23659
23808
  field("SCHEMA_TOPIC_FORM_TKEY", "tkey", "time key", text_input("tkey", record.tkey, "")),
23660
23809
  field("SCHEMA_TOPIC_FORM_VERSION", "topic_version", "version", number_input("topic_version", record.topic_version === void 0 ? 1 : record.topic_version), "raising it is what publishes a change of the columns"),
@@ -24069,7 +24218,7 @@ function open_import(gobj, treedb) {
24069
24218
  [[
24070
24219
  "span",
24071
24220
  { class: "icon" },
24072
- [["i", { class: "yi-file-import" }]]
24221
+ [["i", { class: "yi-upload" }]]
24073
24222
  ], [
24074
24223
  "span",
24075
24224
  { i18n: "import" },
@@ -24334,10 +24483,12 @@ function run_next_write(gobj) {
24334
24483
  let priv = gobj.priv;
24335
24484
  if (priv.save_queue.length === 0) return end_writes(gobj, "");
24336
24485
  let write = priv.save_queue[0];
24337
- if (remote_command(gobj, write.op === "create" ? "create-node" : write.op === "delete" ? "delete-node" : "update-node", {
24486
+ let command = write_command(write.op);
24487
+ let options = write_options(write.op);
24488
+ if (remote_command(gobj, command, {
24338
24489
  topic_name: write.topic_name,
24339
24490
  record: write.record,
24340
- options: {},
24491
+ options,
24341
24492
  record_id: write.record.id || ""
24342
24493
  }) < 0) return end_writes(gobj, (0, i18next.t)("cannot reach the treedb"));
24343
24494
  return 0;
@@ -24392,7 +24543,8 @@ function column_record(gobj, topic, col, values) {
24392
24543
  record.header = values.header || "";
24393
24544
  record.type = values.type || "string";
24394
24545
  record.flag = flags;
24395
- record.fillspace = values.fillspace === "" ? "" : Number(values.fillspace);
24546
+ if (String(values.fillspace).trim() !== "") record.fillspace = Number(values.fillspace);
24547
+ else if (!creating) record.fillspace = "";
24396
24548
  record.placeholder = values.placeholder || "";
24397
24549
  record.description = values.description || "";
24398
24550
  record.default = values.default || "";
@@ -24490,7 +24642,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
24490
24642
  let __command__ = (0, _yuneta_gobj_js.msg_iev_get_stack)(gobj, kw, "command_stack", true);
24491
24643
  let command = (0, _yuneta_gobj_js.kw_get_str)(gobj, __command__, "command", "", 0);
24492
24644
  let kw_command = (0, _yuneta_gobj_js.kw_get_dict)(gobj, __command__, "kw", {}, 0);
24493
- let md = (0, _yuneta_gobj_js.kw_get_dict)(gobj, kw_command, "__md_command__", {}, 0);
24645
+ let md = (0, _yuneta_gobj_js.is_object)(kw_command.__md_command__) ? kw_command.__md_command__ : kw_command;
24494
24646
  if ((0, _yuneta_gobj_js.kw_get_str)(gobj, md, "purpose", "", 0) !== PURPOSE) return 0;
24495
24647
  if (command === "nodes") {
24496
24648
  let topic_name = (0, _yuneta_gobj_js.kw_get_str)(gobj, md, "topic_name", "", 0);
@@ -24507,11 +24659,11 @@ function ac_mt_command_answer(gobj, event, kw, src) {
24507
24659
  build_model(gobj);
24508
24660
  return go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
24509
24661
  }
24510
- if (command === "create-node" || command === "update-node" || command === "delete-node") {
24511
- let topic_name = (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "topic_name", "", 0);
24662
+ if (command === "update-node" || command === "delete-node") {
24663
+ let topic_name = (0, _yuneta_gobj_js.kw_get_str)(gobj, md, "topic_name", "", 0);
24512
24664
  if (result < 0) return end_writes(gobj, comment || (0, i18next.t)("the treedb refused the write"));
24513
24665
  priv.save_wrote = true;
24514
- if (command === "delete-node") forget_record(gobj, topic_name, (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "record_id", "", 0));
24666
+ if (command === "delete-node") forget_record(gobj, topic_name, (0, _yuneta_gobj_js.kw_get_str)(gobj, md, "record_id", "", 0));
24515
24667
  else {
24516
24668
  let record = (0, _yuneta_gobj_js.is_object)(data) ? data : Array.isArray(data) && (0, _yuneta_gobj_js.is_object)(data[0]) ? data[0] : null;
24517
24669
  if (record) patch_record(gobj, topic_name, record);
@@ -24522,7 +24674,10 @@ function ac_mt_command_answer(gobj, event, kw, src) {
24522
24674
  return 0;
24523
24675
  }
24524
24676
  }
24525
- if (topic_name === T_TOPICS || topic_name === T_COLS) mark_written(gobj, topic_name, (0, _yuneta_gobj_js.kw_get_dict)(gobj, kw_command, "record", {}, 0));
24677
+ if (topic_name === T_TOPICS || topic_name === T_COLS) {
24678
+ let write = priv.save_queue[0];
24679
+ mark_written(gobj, topic_name, write ? write.record : null);
24680
+ }
24526
24681
  priv.save_queue.shift();
24527
24682
  return run_next_write(gobj);
24528
24683
  }
@@ -24915,7 +25070,7 @@ function ac_preview_import(gobj, event, kw, src) {
24915
25070
  writes: [],
24916
25071
  summary: {},
24917
25072
  conflicts: [{
24918
- code: "that is not JSON",
25073
+ code: "that is not json",
24919
25074
  topic: "",
24920
25075
  col: ""
24921
25076
  }]