@yuneta/gobj-ui 6.1.0 → 6.1.2

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.
@@ -19818,6 +19818,7 @@ var attrs_table$3 = [
19818
19818
  SDATA(data_type_t.DTP_POINTER, "subscriber", 0, null, "Subscriber of output events"),
19819
19819
  SDATA(data_type_t.DTP_JSON, "descs", 0, null, "Treedb schema: {topic_name: desc}"),
19820
19820
  SDATA(data_type_t.DTP_STRING, "node_route", 0, "", "Hash-route template with a {topic} placeholder: a node click opens that topic (e.g. '#/topics/db/<sel>/{topic}')"),
19821
+ SDATA(data_type_t.DTP_BOOLEAN, "with_node_click", 0, false, "With no `node_route`, PUBLISH a node click as EV_NODE_CLICK instead of dropping it. Opt-in, because a subscriber has to DECLARE the event: the hosts that route by hash, and the ones that want nothing, must not have it appear underneath them"),
19821
19822
  SDATA(data_type_t.DTP_BOOLEAN, "system", 0, false, "Include system topics (__*__) too"),
19822
19823
  SDATA(data_type_t.DTP_POINTER, "$container", 0, null, "Root HTML element"),
19823
19824
  SDATA_END()
@@ -20222,19 +20223,26 @@ function destroy_graph(gobj) {
20222
20223
  * With a `node_route` the click IS a navigation and this view
20223
20224
  * makes it: that is what the route was handed down for.
20224
20225
  *
20225
- * Without one it is still an action, and it belongs to whoever
20226
- * mounted this view — the schema editor draws the same picture
20227
- * inside its own screens, where a topic opens in place and no
20228
- * hash is involved. So the click is published rather than
20229
- * dropped. A host that subscribes must DECLARE EV_NODE_CLICK in
20230
- * its own FSM, as with every event a child publishes.
20226
+ * Without one it is still an action, and it can belong to
20227
+ * whoever mounted this view — the schema editor draws the same
20228
+ * picture inside its own screens, where a topic opens in place
20229
+ * and no hash is involved. That host asks for it with
20230
+ * `with_node_click` and DECLARES EV_NODE_CLICK in its own FSM,
20231
+ * as with every event a child publishes.
20232
+ *
20233
+ * It is opt-in and not the default for exactly that reason: the
20234
+ * CHILD subscription model subscribes the host to ALL of this
20235
+ * view's events, so publishing one unasked turns a click into
20236
+ * "Event NOT DEFINED in state" in every host that never wanted
20237
+ * it — the topics view that mounts this as its schema landing,
20238
+ * and the offline demo that mounts it against a json file.
20231
20239
  ************************************************************/
20232
20240
  function ac_node_click$2(gobj, event, kw, src) {
20233
20241
  let topic = kw && kw.node_id;
20234
20242
  let route = gobj_read_str_attr(gobj, "node_route");
20235
20243
  if (!topic) return 0;
20236
20244
  if (!route) {
20237
- gobj_publish_event(gobj, "EV_NODE_CLICK", { topic });
20245
+ if (gobj_read_bool_attr(gobj, "with_node_click")) gobj_publish_event(gobj, "EV_NODE_CLICK", { topic });
20238
20246
  return 0;
20239
20247
  }
20240
20248
  let href = route.replace("{topic}", topic);
@@ -20574,6 +20582,22 @@ function build_schema_model(records) {
20574
20582
  };
20575
20583
  }
20576
20584
  /***************************************************************
20585
+ * Is there a value here at all?
20586
+ *
20587
+ * The store answers a `blob` column that was never set with an
20588
+ * EMPTY COLLECTION, not with nothing: `enum: {}`, `hook: {}`,
20589
+ * `default: {}`. Read as "a value", those turn every export into
20590
+ * a schema full of empty objects — and `'hook': {}` in a literal
20591
+ * is a hook with no mapping, which is a link the treedb builds
20592
+ * and nothing writes.
20593
+ ***************************************************************/
20594
+ function is_empty_value(value) {
20595
+ if (value === null || value === void 0 || value === "") return true;
20596
+ if (Array.isArray(value)) return value.length === 0;
20597
+ if (typeof value === "object") return Object.keys(value).length === 0;
20598
+ return false;
20599
+ }
20600
+ /***************************************************************
20577
20601
  * The fields of a column that are DECLARED as one thing and
20578
20602
  * STORED as another.
20579
20603
  *
@@ -20911,6 +20935,7 @@ var COL_STORAGE_FIELDS = [
20911
20935
  "value",
20912
20936
  "topics",
20913
20937
  "order",
20938
+ "_geometry",
20914
20939
  "__md_treedb__"
20915
20940
  ];
20916
20941
  var TOPIC_STORAGE_FIELDS = [
@@ -20919,6 +20944,7 @@ var TOPIC_STORAGE_FIELDS = [
20919
20944
  "treedbs",
20920
20945
  "cols",
20921
20946
  "order",
20947
+ "_geometry",
20922
20948
  "__md_treedb__"
20923
20949
  ];
20924
20950
  var COL_JSON_FIELDS = [
@@ -20942,13 +20968,16 @@ function col_desc(col) {
20942
20968
  let desc = {};
20943
20969
  for (let [key, value] of Object.entries(record)) {
20944
20970
  if (COL_STORAGE_FIELDS.indexOf(key) >= 0) continue;
20945
- if (value === null || value === void 0 || value === "") continue;
20946
- desc[key] = COL_JSON_FIELDS.indexOf(key) >= 0 ? as_json(value) : value;
20971
+ if (is_empty_value(value)) continue;
20972
+ let read = COL_JSON_FIELDS.indexOf(key) >= 0 ? as_json(value) : value;
20973
+ if (is_empty_value(read)) continue;
20974
+ desc[key] = read;
20947
20975
  }
20948
20976
  desc.id = col.name;
20949
20977
  desc.flag = col_flags(record);
20950
20978
  let hook = col_hook(record);
20951
- if (hook) desc.hook = hook;
20979
+ if (hook && !is_empty_value(hook)) desc.hook = hook;
20980
+ else delete desc.hook;
20952
20981
  let e = col_enum(record);
20953
20982
  if (e.length > 0) desc.enum = e;
20954
20983
  return desc;
@@ -20966,7 +20995,7 @@ function topic_descs(treedb) {
20966
20995
  let desc = {};
20967
20996
  for (let [key, value] of Object.entries(record)) {
20968
20997
  if (TOPIC_STORAGE_FIELDS.indexOf(key) >= 0) continue;
20969
- if (value === null || value === void 0 || value === "") continue;
20998
+ if (is_empty_value(value)) continue;
20970
20999
  desc[key] = value;
20971
21000
  }
20972
21001
  desc.topic_name = topic.name;
@@ -21023,6 +21052,7 @@ var COL_SKIP = [
21023
21052
  "value",
21024
21053
  "topics",
21025
21054
  "order",
21055
+ "_geometry",
21026
21056
  "__md_treedb__"
21027
21057
  ];
21028
21058
  var TOPIC_SKIP = [
@@ -21031,6 +21061,7 @@ var TOPIC_SKIP = [
21031
21061
  "treedbs",
21032
21062
  "cols",
21033
21063
  "order",
21064
+ "_geometry",
21034
21065
  "__md_treedb__"
21035
21066
  ];
21036
21067
  var JSON_FIELDS$1 = [
@@ -21084,8 +21115,10 @@ function schema_to_json(treedb) {
21084
21115
  let jn_topic = { id: topic.name };
21085
21116
  for (let [key, value] of Object.entries(record)) {
21086
21117
  if (TOPIC_SKIP.indexOf(key) >= 0) continue;
21087
- if (value === null || value === void 0 || value === "") continue;
21088
- jn_topic[key] = JSON_FIELDS$1.indexOf(key) >= 0 ? as_json(value) : value;
21118
+ if (is_empty_value(value)) continue;
21119
+ let read = JSON_FIELDS$1.indexOf(key) >= 0 ? as_json(value) : value;
21120
+ if (is_empty_value(read)) continue;
21121
+ jn_topic[key] = read;
21089
21122
  }
21090
21123
  if (jn_topic.topic_version !== void 0) jn_topic.topic_version = version(jn_topic.topic_version);
21091
21124
  let pkey2s = topic_pkey2s(record);
@@ -21098,14 +21131,17 @@ function schema_to_json(treedb) {
21098
21131
  let jn_col = {};
21099
21132
  for (let [key, value] of Object.entries(col_record)) {
21100
21133
  if (COL_SKIP.indexOf(key) >= 0) continue;
21101
- if (value === null || value === void 0 || value === "") continue;
21102
- jn_col[key] = JSON_FIELDS$1.indexOf(key) >= 0 ? as_json(value) : value;
21134
+ if (is_empty_value(value)) continue;
21135
+ let read = JSON_FIELDS$1.indexOf(key) >= 0 ? as_json(value) : value;
21136
+ if (is_empty_value(read)) continue;
21137
+ jn_col[key] = read;
21103
21138
  }
21104
21139
  let flags = col_flags(col_record);
21105
21140
  if (flags.length > 0) jn_col.flag = flags;
21106
21141
  else delete jn_col.flag;
21107
21142
  let hook = col_hook(col_record);
21108
- if (hook) jn_col.hook = hook;
21143
+ if (hook && !is_empty_value(hook)) jn_col.hook = hook;
21144
+ else delete jn_col.hook;
21109
21145
  let e = col_enum(col_record);
21110
21146
  if (e.length > 0) jn_col.enum = e;
21111
21147
  let ordered_col = {};
@@ -21290,7 +21326,7 @@ function same_value(field, a, b) {
21290
21326
  list = list.filter((f) => typeof f === "string" && f.length > 0).sort();
21291
21327
  return JSON.stringify(list);
21292
21328
  }
21293
- if (v === null || v === void 0 || v === "") return "";
21329
+ if (is_empty_value(v)) return "";
21294
21330
  if (typeof v === "object") return JSON.stringify(v);
21295
21331
  return String(v);
21296
21332
  };
@@ -21303,8 +21339,10 @@ function incoming_col_fields(col) {
21303
21339
  let out = {};
21304
21340
  for (let field of COL_FIELDS) {
21305
21341
  let value = col ? col[field] : void 0;
21306
- if (value === void 0 || value === null || value === "") continue;
21307
- out[field] = JSON_FIELDS.indexOf(field) >= 0 ? as_json(value) : value;
21342
+ if (is_empty_value(value)) continue;
21343
+ let read = JSON_FIELDS.indexOf(field) >= 0 ? as_json(value) : value;
21344
+ if (is_empty_value(read)) continue;
21345
+ out[field] = read;
21308
21346
  }
21309
21347
  if (Array.isArray(out.flag)) out.flag = out.flag.filter((f) => typeof f === "string" && f.length > 0);
21310
21348
  else if (typeof out.flag === "string" && out.flag) out.flag = [out.flag];
@@ -21317,14 +21355,17 @@ function stored_col_fields(record) {
21317
21355
  let out = {};
21318
21356
  for (let field of COL_FIELDS) {
21319
21357
  let value = record ? record[field] : void 0;
21320
- if (value === void 0 || value === null || value === "") continue;
21321
- out[field] = JSON_FIELDS.indexOf(field) >= 0 ? as_json(value) : value;
21358
+ if (is_empty_value(value)) continue;
21359
+ let read = JSON_FIELDS.indexOf(field) >= 0 ? as_json(value) : value;
21360
+ if (is_empty_value(read)) continue;
21361
+ out[field] = read;
21322
21362
  }
21323
21363
  let flags = col_flags(record);
21324
21364
  if (flags.length > 0) out.flag = flags;
21325
21365
  else delete out.flag;
21326
21366
  let hook = col_hook(record);
21327
- if (hook) out.hook = hook;
21367
+ if (hook && !is_empty_value(hook)) out.hook = hook;
21368
+ else delete out.hook;
21328
21369
  let e = col_enum(record);
21329
21370
  if (e.length > 0) out.enum = e;
21330
21371
  return out;
@@ -21949,6 +21990,61 @@ function toggle_flag(current, name, on) {
21949
21990
  return out;
21950
21991
  }
21951
21992
  //#endregion
21993
+ //#region src/schema_write_options.js
21994
+ /***********************************************************************
21995
+ * schema_write_options.js
21996
+ *
21997
+ * The OPTIONS a schema write travels with, and why each one.
21998
+ *
21999
+ * Three words decide whether a write does what it says, and all
22000
+ * three are easy to get wrong in a way that succeeds:
22001
+ *
22002
+ * `create` a node that is not there yet is written by
22003
+ * `update-node` with this, not by `create-node`. The
22004
+ * two are not the same call: only the update path
22005
+ * carries `autolink`, and without a link a new column
22006
+ * belongs to no topic.
22007
+ *
22008
+ * `autolink` turns the fkey carried IN THE RECORD into a link.
22009
+ * It rewrites the node's links from the fkey fields
22010
+ * the record has — so on a PARTIAL update, which
22011
+ * carries none, it reads that as "no parents" and
22012
+ * UNLINKS the node. Raising a topic's version with it
22013
+ * on detached that topic from its treedb, and the
22014
+ * write returned success. It goes with a create,
22015
+ * where the record carries its fkey, and with nothing
22016
+ * else.
22017
+ *
22018
+ * `force` a delete of a node something points at. A column is
22019
+ * pointed at by the topic that owns it, which is not
22020
+ * a reason to refuse.
22021
+ *
22022
+ * Pure and tested, because the cost of getting it wrong is a
22023
+ * store that has to be repaired by hand, and nothing in the
22024
+ * answer says it happened.
22025
+ *
22026
+ * Copyright (c) 2026, ArtGins.
22027
+ * All Rights Reserved.
22028
+ ***********************************************************************/
22029
+ /***************************************************************
22030
+ * write_command(op) -> the treedb command that performs it
22031
+ ***************************************************************/
22032
+ function write_command(op) {
22033
+ return op === "delete" ? "delete-node" : "update-node";
22034
+ }
22035
+ /***************************************************************
22036
+ * write_options(op) -> the options it travels with
22037
+ ***************************************************************/
22038
+ function write_options(op) {
22039
+ if (op === "delete") return { force: true };
22040
+ if (op === "create") return {
22041
+ list_dict: true,
22042
+ create: true,
22043
+ autolink: true
22044
+ };
22045
+ return { list_dict: true };
22046
+ }
22047
+ //#endregion
21952
22048
  //#region src/c_yui_schema_editor.js
21953
22049
  /***********************************************************************
21954
22050
  * c_yui_schema_editor.js
@@ -22268,10 +22364,12 @@ function remote_command(gobj, command, kw) {
22268
22364
  service: treedb_name,
22269
22365
  treedb_name
22270
22366
  }, kw || {});
22271
- full_kw.__md_command__ = Object.assign({
22367
+ full_kw.__md_command__ = {
22272
22368
  purpose: PURPOSE,
22273
- command
22274
- }, kw && kw.topic_name ? { topic_name: kw.topic_name } : {});
22369
+ topic_name: kw && kw.topic_name || "",
22370
+ record_id: kw && kw.record_id || ""
22371
+ };
22372
+ delete full_kw.record_id;
22275
22373
  let ret = gobj_command(remote, command, full_kw, gobj);
22276
22374
  if (ret) {
22277
22375
  log_error(ret);
@@ -22520,9 +22618,9 @@ function render_toolbar(gobj) {
22520
22618
  let $right = [];
22521
22619
  if (priv.treedb_id && has_model) {
22522
22620
  $right.push(toolbar_button("SCHEMA_DIAGRAM_BTN", "yi-hexagon-nodes", priv.diagram ? "topics" : "diagram", "EV_TOGGLE_DIAGRAM", false));
22523
- $right.push(toolbar_button("SCHEMA_VALIDATE_BTN", "yi-circle-check", "check", "EV_VALIDATE", false));
22524
- $right.push(toolbar_button("SCHEMA_EXPORT_BTN", "yi-file-export", "export", "EV_EXPORT", false));
22525
- if (!readonly) $right.push(toolbar_button("SCHEMA_IMPORT_BTN", "yi-file-import", "import", "EV_IMPORT", false));
22621
+ $right.push(toolbar_button("SCHEMA_VALIDATE_BTN", "yi-square-check", "check", "EV_VALIDATE", false));
22622
+ $right.push(toolbar_button("SCHEMA_EXPORT_BTN", "yi-download", "export", "EV_EXPORT", false));
22623
+ if (!readonly) $right.push(toolbar_button("SCHEMA_IMPORT_BTN", "yi-upload", "import", "EV_IMPORT", false));
22526
22624
  }
22527
22625
  if (priv.topic_name && !readonly && !priv.diagram) $right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus", "new column", "EV_ADD_COLUMN", false));
22528
22626
  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));
@@ -22725,13 +22823,16 @@ function render_topics(gobj, $body) {
22725
22823
  return;
22726
22824
  }
22727
22825
  let readonly = is_readonly(gobj);
22826
+ let twice = repeated_names(treedb.topics);
22728
22827
  let $rows = [];
22729
22828
  for (let topic of treedb.topics) {
22730
22829
  let pending = priv.written[topic.id] && String(priv.baseline[topic.id]) === String(topic.topic_version);
22830
+ let ambiguous = !!twice[topic.name];
22831
+ let address = ambiguous ? topic.id : topic.name;
22731
22832
  let $actions = [];
22732
22833
  if (!readonly) {
22733
- $actions.push(row_icon(gobj, "SCHEMA_TOPIC_EDIT", "yi-pen", "edit topic", "EV_EDIT_TOPIC", { topic: topic.name }));
22734
- $actions.push(row_icon(gobj, "SCHEMA_TOPIC_DELETE", "yi-trash", "delete topic", "EV_DELETE_TOPIC", { topic: topic.name }));
22834
+ $actions.push(row_icon(gobj, "SCHEMA_TOPIC_EDIT", "yi-pen", "edit topic", "EV_EDIT_TOPIC", { topic: address }));
22835
+ $actions.push(row_icon(gobj, "SCHEMA_TOPIC_DELETE", "yi-trash", "delete topic", "EV_DELETE_TOPIC", { topic: address }));
22735
22836
  }
22736
22837
  $rows.push([
22737
22838
  "tr",
@@ -22744,22 +22845,38 @@ function render_topics(gobj, $body) {
22744
22845
  [
22745
22846
  "td",
22746
22847
  { class: "SCHEMA_TOPIC_NAME" },
22747
- [[
22748
- "span",
22749
- { class: "has-text-weight-semibold" },
22750
- `${topic.name}`
22751
- ], topic.system_topic ? [
22752
- "span",
22753
- {
22754
- class: "SCHEMA_TOPIC_SYSTEM tag is-light ml-2",
22755
- i18n: "system"
22756
- },
22757
- t("system")
22758
- ] : [
22759
- "span",
22760
- {},
22761
- ""
22762
- ]]
22848
+ [
22849
+ [
22850
+ "span",
22851
+ { class: "has-text-weight-semibold" },
22852
+ `${topic.name}`
22853
+ ],
22854
+ topic.system_topic ? [
22855
+ "span",
22856
+ {
22857
+ class: "SCHEMA_TOPIC_SYSTEM tag is-light ml-2",
22858
+ i18n: "system"
22859
+ },
22860
+ t("system")
22861
+ ] : [
22862
+ "span",
22863
+ {},
22864
+ ""
22865
+ ],
22866
+ ambiguous ? [
22867
+ "div",
22868
+ { class: "SCHEMA_TOPIC_ID is-size-7 has-text-grey" },
22869
+ [[
22870
+ "code",
22871
+ {},
22872
+ `${topic.id}`
22873
+ ]]
22874
+ ] : [
22875
+ "span",
22876
+ {},
22877
+ ""
22878
+ ]
22879
+ ]
22763
22880
  ],
22764
22881
  [
22765
22882
  "td",
@@ -22793,12 +22910,12 @@ function render_topics(gobj, $body) {
22793
22910
  {
22794
22911
  click: (evt) => {
22795
22912
  if (evt.target.closest(".SCHEMA_TOPIC_ACTIONS")) return;
22796
- gobj_send_event(gobj, "EV_SELECT_TOPIC", { topic: topic.name }, gobj);
22913
+ gobj_send_event(gobj, "EV_SELECT_TOPIC", { topic: address }, gobj);
22797
22914
  },
22798
22915
  keydown: (evt) => {
22799
22916
  if (evt.key !== "Enter" && evt.key !== " ") return;
22800
22917
  evt.preventDefault();
22801
- gobj_send_event(gobj, "EV_SELECT_TOPIC", { topic: topic.name }, gobj);
22918
+ gobj_send_event(gobj, "EV_SELECT_TOPIC", { topic: address }, gobj);
22802
22919
  }
22803
22920
  }
22804
22921
  ]);
@@ -22887,6 +23004,26 @@ function row_icon(gobj, logical, icon, key, event, kw) {
22887
23004
  ];
22888
23005
  }
22889
23006
  /***************************************************************
23007
+ * Which names appear more than once.
23008
+ *
23009
+ * A store can hold TWO GENERATIONS of the same schema: the
23010
+ * projector never deletes, so a treedb re-keyed by a newer SDK
23011
+ * keeps its old rowid-keyed rows next to the qualified ones, and
23012
+ * both are children of the same treedb with the same name. Drawn
23013
+ * as two identical rows that behave differently, that reads as a
23014
+ * bug in the editor; drawn with what tells them apart, it reads
23015
+ * as what it is.
23016
+ ***************************************************************/
23017
+ function repeated_names(list) {
23018
+ let seen = {};
23019
+ let twice = {};
23020
+ for (let entry of list) {
23021
+ if (seen[entry.name]) twice[entry.name] = true;
23022
+ seen[entry.name] = true;
23023
+ }
23024
+ return twice;
23025
+ }
23026
+ /***************************************************************
22890
23027
  * ST_COLUMNS — the columns of one topic, in schema order.
22891
23028
  *
22892
23029
  * The order is a FIELD (`order`), so the rows are draggable and
@@ -22912,8 +23049,9 @@ function render_columns(gobj, $body) {
22912
23049
  ]);
22913
23050
  let $banner = version_banner(gobj, topic);
22914
23051
  if ($banner) $wrap.appendChild($banner);
23052
+ let twice = repeated_names(topic.cols);
22915
23053
  let $rows = [];
22916
- for (let i = 0; i < topic.cols.length; i++) $rows.push(column_row(gobj, topic, topic.cols[i], i, readonly));
23054
+ for (let i = 0; i < topic.cols.length; i++) $rows.push(column_row(gobj, topic, topic.cols[i], i, readonly, twice));
22917
23055
  let $table = createElement2([
22918
23056
  "div",
22919
23057
  {
@@ -23034,7 +23172,7 @@ function version_banner(gobj, topic) {
23034
23172
  [[
23035
23173
  "span",
23036
23174
  { class: "icon" },
23037
- [["i", { class: "yi-arrow-up" }]]
23175
+ [["i", { class: "yi-chevron-up" }]]
23038
23176
  ], [
23039
23177
  "span",
23040
23178
  { i18n: "raise" },
@@ -23055,8 +23193,10 @@ function version_banner(gobj, topic) {
23055
23193
  * Yuneta event is plain JSON, so a DOM node never travels in
23056
23194
  * one.
23057
23195
  ***************************************************************/
23058
- function column_row(gobj, topic, col, index, readonly) {
23196
+ function column_row(gobj, topic, col, index, readonly, twice) {
23059
23197
  let record = col.record || {};
23198
+ let ambiguous = !!(twice && twice[col.name]);
23199
+ let address = ambiguous ? col.id : col.name;
23060
23200
  let flags = col_flags(record);
23061
23201
  let hook = col_hook(record);
23062
23202
  let is_pkey = col.name === (topic.pkey || "id");
@@ -23068,13 +23208,13 @@ function column_row(gobj, topic, col, index, readonly) {
23068
23208
  ];
23069
23209
  });
23070
23210
  let link = "";
23071
- if (hook) link = "→ " + Object.keys(hook).join(", ");
23211
+ if (hook && !is_empty_value(hook)) link = "→ " + Object.keys(hook).join(", ");
23072
23212
  else if (flags.indexOf("fkey") >= 0) link = "↖";
23073
23213
  let $actions = [];
23074
23214
  if (!readonly) {
23075
- $actions.push(row_icon(gobj, "SCHEMA_COL_EDIT", "yi-pen", "edit column", "EV_EDIT_COLUMN", { col: col.name }));
23076
- $actions.push(row_icon(gobj, "SCHEMA_COL_DUPLICATE", "yi-copy", "duplicate column", "EV_DUPLICATE_COLUMN", { col: col.name }));
23077
- $actions.push(row_icon(gobj, "SCHEMA_COL_DELETE", "yi-trash", "delete column", "EV_DELETE_COLUMN", { col: col.name }));
23215
+ $actions.push(row_icon(gobj, "SCHEMA_COL_EDIT", "yi-pen", "edit column", "EV_EDIT_COLUMN", { col: address }));
23216
+ $actions.push(row_icon(gobj, "SCHEMA_COL_DUPLICATE", "yi-copy", "duplicate column", "EV_DUPLICATE_COLUMN", { col: address }));
23217
+ $actions.push(row_icon(gobj, "SCHEMA_COL_DELETE", "yi-trash", "delete column", "EV_DELETE_COLUMN", { col: address }));
23078
23218
  }
23079
23219
  let $row = createElement2([
23080
23220
  "tr",
@@ -23096,22 +23236,38 @@ function column_row(gobj, topic, col, index, readonly) {
23096
23236
  [
23097
23237
  "td",
23098
23238
  { class: "SCHEMA_COL_NAME" },
23099
- [[
23100
- "code",
23101
- {},
23102
- `${col.name}`
23103
- ], is_pkey ? [
23104
- "span",
23105
- {
23106
- class: "SCHEMA_COL_PKEY tag is-info is-light ml-2",
23107
- i18n: "pkey"
23108
- },
23109
- t("pkey")
23110
- ] : [
23111
- "span",
23112
- {},
23113
- ""
23114
- ]]
23239
+ [
23240
+ [
23241
+ "code",
23242
+ {},
23243
+ `${col.name}`
23244
+ ],
23245
+ ambiguous ? [
23246
+ "span",
23247
+ { class: "SCHEMA_COL_ID is-size-7 has-text-grey ml-2" },
23248
+ [[
23249
+ "code",
23250
+ {},
23251
+ `${col.id}`
23252
+ ]]
23253
+ ] : [
23254
+ "span",
23255
+ {},
23256
+ ""
23257
+ ],
23258
+ is_pkey ? [
23259
+ "span",
23260
+ {
23261
+ class: "SCHEMA_COL_PKEY tag is-info is-light ml-2",
23262
+ i18n: "pkey"
23263
+ },
23264
+ t("pkey")
23265
+ ] : [
23266
+ "span",
23267
+ {},
23268
+ ""
23269
+ ]
23270
+ ]
23115
23271
  ],
23116
23272
  [
23117
23273
  "td",
@@ -23154,7 +23310,7 @@ function column_row(gobj, topic, col, index, readonly) {
23154
23310
  if (!readonly) wire_row_drag(gobj, $row);
23155
23311
  $row.addEventListener("dblclick", (evt) => {
23156
23312
  if (readonly || evt.target.closest(".SCHEMA_COL_ACTIONS")) return;
23157
- gobj_send_event(gobj, "EV_EDIT_COLUMN", { col: col.name }, gobj);
23313
+ gobj_send_event(gobj, "EV_EDIT_COLUMN", { col: address }, gobj);
23158
23314
  });
23159
23315
  return $row;
23160
23316
  }
@@ -23254,6 +23410,7 @@ function render_diagram(gobj) {
23254
23410
  subscriber: gobj,
23255
23411
  descs,
23256
23412
  node_route: "",
23413
+ with_node_click: true,
23257
23414
  system: true
23258
23415
  }, gobj);
23259
23416
  if (!diagram) {
@@ -23491,7 +23648,8 @@ function open_column_form(gobj, topic, col, prefill) {
23491
23648
  let record = prefill || col && col.record || {};
23492
23649
  let creating = !col;
23493
23650
  let type = record.type || "string";
23494
- let hook = col_hook(record) || {};
23651
+ let hook = col_hook(record);
23652
+ if (is_empty_value(hook)) hook = {};
23495
23653
  let hook_topic = Object.keys(hook)[0] || "";
23496
23654
  let hook_col = hook_topic ? hook[hook_topic] : "";
23497
23655
  let treedb = current_treedb(gobj);
@@ -23641,7 +23799,7 @@ function open_topic_form(gobj, treedb, topic) {
23641
23799
  [
23642
23800
  field("SCHEMA_TOPIC_FORM_NAME", "value", "topic", text_input("value", creating ? "" : topic.name, t("topic name"), !creating), creating ? "" : "a topic is keyed by its whole path: renaming it is creating another one"),
23643
23801
  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"])),
23644
- 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"),
23802
+ 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"),
23645
23803
  field("SCHEMA_TOPIC_FORM_SYSTEM_FLAG", "system_flag", "system flag", text_input("system_flag", record.system_flag || "sf_string_key", "")),
23646
23804
  field("SCHEMA_TOPIC_FORM_TKEY", "tkey", "time key", text_input("tkey", record.tkey, "")),
23647
23805
  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"),
@@ -24056,7 +24214,7 @@ function open_import(gobj, treedb) {
24056
24214
  [[
24057
24215
  "span",
24058
24216
  { class: "icon" },
24059
- [["i", { class: "yi-file-import" }]]
24217
+ [["i", { class: "yi-upload" }]]
24060
24218
  ], [
24061
24219
  "span",
24062
24220
  { i18n: "import" },
@@ -24321,10 +24479,12 @@ function run_next_write(gobj) {
24321
24479
  let priv = gobj.priv;
24322
24480
  if (priv.save_queue.length === 0) return end_writes(gobj, "");
24323
24481
  let write = priv.save_queue[0];
24324
- if (remote_command(gobj, write.op === "create" ? "create-node" : write.op === "delete" ? "delete-node" : "update-node", {
24482
+ let command = write_command(write.op);
24483
+ let options = write_options(write.op);
24484
+ if (remote_command(gobj, command, {
24325
24485
  topic_name: write.topic_name,
24326
24486
  record: write.record,
24327
- options: {},
24487
+ options,
24328
24488
  record_id: write.record.id || ""
24329
24489
  }) < 0) return end_writes(gobj, t("cannot reach the treedb"));
24330
24490
  return 0;
@@ -24379,7 +24539,8 @@ function column_record(gobj, topic, col, values) {
24379
24539
  record.header = values.header || "";
24380
24540
  record.type = values.type || "string";
24381
24541
  record.flag = flags;
24382
- record.fillspace = values.fillspace === "" ? "" : Number(values.fillspace);
24542
+ if (String(values.fillspace).trim() !== "") record.fillspace = Number(values.fillspace);
24543
+ else if (!creating) record.fillspace = "";
24383
24544
  record.placeholder = values.placeholder || "";
24384
24545
  record.description = values.description || "";
24385
24546
  record.default = values.default || "";
@@ -24477,7 +24638,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
24477
24638
  let __command__ = msg_iev_get_stack(gobj, kw, "command_stack", true);
24478
24639
  let command = kw_get_str(gobj, __command__, "command", "", 0);
24479
24640
  let kw_command = kw_get_dict(gobj, __command__, "kw", {}, 0);
24480
- let md = kw_get_dict(gobj, kw_command, "__md_command__", {}, 0);
24641
+ let md = is_object(kw_command.__md_command__) ? kw_command.__md_command__ : kw_command;
24481
24642
  if (kw_get_str(gobj, md, "purpose", "", 0) !== PURPOSE) return 0;
24482
24643
  if (command === "nodes") {
24483
24644
  let topic_name = kw_get_str(gobj, md, "topic_name", "", 0);
@@ -24494,11 +24655,11 @@ function ac_mt_command_answer(gobj, event, kw, src) {
24494
24655
  build_model(gobj);
24495
24656
  return go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
24496
24657
  }
24497
- if (command === "create-node" || command === "update-node" || command === "delete-node") {
24498
- let topic_name = kw_get_str(gobj, kw_command, "topic_name", "", 0);
24658
+ if (command === "update-node" || command === "delete-node") {
24659
+ let topic_name = kw_get_str(gobj, md, "topic_name", "", 0);
24499
24660
  if (result < 0) return end_writes(gobj, comment || t("the treedb refused the write"));
24500
24661
  priv.save_wrote = true;
24501
- if (command === "delete-node") forget_record(gobj, topic_name, kw_get_str(gobj, kw_command, "record_id", "", 0));
24662
+ if (command === "delete-node") forget_record(gobj, topic_name, kw_get_str(gobj, md, "record_id", "", 0));
24502
24663
  else {
24503
24664
  let record = is_object(data) ? data : Array.isArray(data) && is_object(data[0]) ? data[0] : null;
24504
24665
  if (record) patch_record(gobj, topic_name, record);
@@ -24509,7 +24670,10 @@ function ac_mt_command_answer(gobj, event, kw, src) {
24509
24670
  return 0;
24510
24671
  }
24511
24672
  }
24512
- if (topic_name === T_TOPICS || topic_name === T_COLS) mark_written(gobj, topic_name, kw_get_dict(gobj, kw_command, "record", {}, 0));
24673
+ if (topic_name === T_TOPICS || topic_name === T_COLS) {
24674
+ let write = priv.save_queue[0];
24675
+ mark_written(gobj, topic_name, write ? write.record : null);
24676
+ }
24513
24677
  priv.save_queue.shift();
24514
24678
  return run_next_write(gobj);
24515
24679
  }
@@ -24902,7 +25066,7 @@ function ac_preview_import(gobj, event, kw, src) {
24902
25066
  writes: [],
24903
25067
  summary: {},
24904
25068
  conflicts: [{
24905
- code: "that is not JSON",
25069
+ code: "that is not json",
24906
25070
  topic: "",
24907
25071
  col: ""
24908
25072
  }]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "6.1.0",
3
+ "version": "6.1.2",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",