@yuneta/gobj-ui 5.15.0 → 5.17.0
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 +72 -15
- package/dist/gobj-ui.cjs.js +412 -75
- package/dist/gobj-ui.es.js +412 -75
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +38 -24
- package/src/c_yui_treedb_graph.js +99 -1
- package/src/c_yui_treedb_schema.js +348 -43
- package/src/c_yui_treedb_topic_with_form.js +16 -1
- package/src/c_yui_treedb_topics.js +2 -1
- package/src/treedb_node_label.js +73 -0
- package/src/treedb_node_label.test.js +92 -0
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -15505,7 +15505,7 @@ function request_print_tranger$1(gobj, path) {
|
|
|
15505
15505
|
* would travel, be refused by the yuno, and come back as a toast --
|
|
15506
15506
|
* after the table had already drawn the row.
|
|
15507
15507
|
***************************************************************/
|
|
15508
|
-
function refuse_if_readonly$
|
|
15508
|
+
function refuse_if_readonly$2(gobj, event) {
|
|
15509
15509
|
if (!(0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "readonly")) return false;
|
|
15510
15510
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} refused, treedb '${(0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name")}' is READ-ONLY`);
|
|
15511
15511
|
return true;
|
|
@@ -15577,7 +15577,8 @@ function ac_mt_command_answer$1(gobj, event, kw, src) {
|
|
|
15577
15577
|
treedb_name: (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "treedb_name", "", 0),
|
|
15578
15578
|
topic_name: (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "topic_name", "", 0),
|
|
15579
15579
|
record: (0, _yuneta_gobj_js.kw_get_dict)(gobj, kw_command, "record", {}, 0),
|
|
15580
|
-
created: command === "create-node"
|
|
15580
|
+
created: command === "create-node",
|
|
15581
|
+
command
|
|
15581
15582
|
});
|
|
15582
15583
|
break;
|
|
15583
15584
|
case "delete-node": break;
|
|
@@ -15782,7 +15783,7 @@ function ac_treedb_node_deleted$1(gobj, event, kw, src) {
|
|
|
15782
15783
|
* }
|
|
15783
15784
|
********************************************/
|
|
15784
15785
|
function ac_create_record(gobj, event, kw, src) {
|
|
15785
|
-
if (refuse_if_readonly$
|
|
15786
|
+
if (refuse_if_readonly$2(gobj, event)) return -1;
|
|
15786
15787
|
let treedb_name = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name");
|
|
15787
15788
|
let topic_name = (0, _yuneta_gobj_js.gobj_read_attr)(src, "topic_name");
|
|
15788
15789
|
let record = kw.record;
|
|
@@ -15800,7 +15801,7 @@ function ac_create_record(gobj, event, kw, src) {
|
|
|
15800
15801
|
* }
|
|
15801
15802
|
********************************************/
|
|
15802
15803
|
function ac_update_record(gobj, event, kw, src) {
|
|
15803
|
-
if (refuse_if_readonly$
|
|
15804
|
+
if (refuse_if_readonly$2(gobj, event)) return -1;
|
|
15804
15805
|
let treedb_name = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name");
|
|
15805
15806
|
let topic_name = (0, _yuneta_gobj_js.gobj_read_attr)(src, "topic_name");
|
|
15806
15807
|
let record = kw.record;
|
|
@@ -15817,7 +15818,7 @@ function ac_update_record(gobj, event, kw, src) {
|
|
|
15817
15818
|
* }
|
|
15818
15819
|
********************************************/
|
|
15819
15820
|
function ac_delete_record(gobj, event, kw, src) {
|
|
15820
|
-
if (refuse_if_readonly$
|
|
15821
|
+
if (refuse_if_readonly$2(gobj, event)) return -1;
|
|
15821
15822
|
let treedb_name = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name");
|
|
15822
15823
|
let topic_name = (0, _yuneta_gobj_js.gobj_read_attr)(src, "topic_name");
|
|
15823
15824
|
let record = kw.record;
|
|
@@ -17638,7 +17639,7 @@ function write_plan(gobj) {
|
|
|
17638
17639
|
* A read-only topic refuses the write EVENTS too, not only their
|
|
17639
17640
|
* buttons.
|
|
17640
17641
|
***************************************************************/
|
|
17641
|
-
function refuse_if_readonly(gobj, event) {
|
|
17642
|
+
function refuse_if_readonly$1(gobj, event) {
|
|
17642
17643
|
if (!(0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "readonly")) return false;
|
|
17643
17644
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} refused, topic '${(0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "topic_name")}' is READ-ONLY`);
|
|
17644
17645
|
return true;
|
|
@@ -17710,7 +17711,10 @@ function ac_load_node_updated(gobj, event, kw, src) {
|
|
|
17710
17711
|
return -1;
|
|
17711
17712
|
}
|
|
17712
17713
|
let tabulator = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "tabulator");
|
|
17713
|
-
if (tabulator)
|
|
17714
|
+
if (tabulator) {
|
|
17715
|
+
for (let record of data) if (tabulator.getRow(record.id)) tabulator.updateData([record]);
|
|
17716
|
+
else if (tabulator.getDataCount() > 0) (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: updated node is not in the loaded table: ${record.id}`);
|
|
17717
|
+
}
|
|
17714
17718
|
return 0;
|
|
17715
17719
|
}
|
|
17716
17720
|
/************************************************************
|
|
@@ -17735,7 +17739,7 @@ function ac_node_deleted$1(gobj, event, kw, src) {
|
|
|
17735
17739
|
* and the Op column is visible (with row's edit/delete icons)
|
|
17736
17740
|
************************************************************/
|
|
17737
17741
|
function ac_edition_mode(gobj, event, kw, src) {
|
|
17738
|
-
if (refuse_if_readonly(gobj, event)) return -1;
|
|
17742
|
+
if (refuse_if_readonly$1(gobj, event)) return -1;
|
|
17739
17743
|
let tabulator = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "tabulator");
|
|
17740
17744
|
let editable = (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "editable");
|
|
17741
17745
|
editable = !editable;
|
|
@@ -17779,7 +17783,7 @@ function ac_edition_mode(gobj, event, kw, src) {
|
|
|
17779
17783
|
* - the backend will broadcast the new record that will be added to table
|
|
17780
17784
|
************************************************************/
|
|
17781
17785
|
function ac_new_row(gobj, event, kw, src) {
|
|
17782
|
-
if (refuse_if_readonly(gobj, event)) return -1;
|
|
17786
|
+
if (refuse_if_readonly$1(gobj, event)) return -1;
|
|
17783
17787
|
let row = {};
|
|
17784
17788
|
let desc = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "desc");
|
|
17785
17789
|
for (let i = 0; i < desc.cols.length; i++) {
|
|
@@ -17809,7 +17813,7 @@ function ac_new_row(gobj, event, kw, src) {
|
|
|
17809
17813
|
* kw {index:, row:}
|
|
17810
17814
|
************************************************************/
|
|
17811
17815
|
function ac_delete_rows(gobj, event, kw, src) {
|
|
17812
|
-
if (refuse_if_readonly(gobj, event)) return -1;
|
|
17816
|
+
if (refuse_if_readonly$1(gobj, event)) return -1;
|
|
17813
17817
|
let tabulator = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "tabulator");
|
|
17814
17818
|
if ((0, _yuneta_gobj_js.json_size)(kw) === 0) {
|
|
17815
17819
|
let rows = tabulator.getSelectedData();
|
|
@@ -17873,7 +17877,7 @@ function ac_copy_rows(gobj, event, kw, src) {
|
|
|
17873
17877
|
* From internal
|
|
17874
17878
|
************************************************************/
|
|
17875
17879
|
function ac_paste_rows(gobj, event, kw, src) {
|
|
17876
|
-
if (refuse_if_readonly(gobj, event)) return -1;
|
|
17880
|
+
if (refuse_if_readonly$1(gobj, event)) return -1;
|
|
17877
17881
|
if (kw.topic_name === (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "topic_name") && kw.treedb_name === (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name")) for (let row of kw.rows) (0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_CREATE_RECORD", {
|
|
17878
17882
|
topic_name: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "topic_name"),
|
|
17879
17883
|
record: row
|
|
@@ -17886,7 +17890,7 @@ function ac_paste_rows(gobj, event, kw, src) {
|
|
|
17886
17890
|
* fkeys, times and numbers). Route by the form's mode.
|
|
17887
17891
|
************************************************************/
|
|
17888
17892
|
function ac_form_save_record(gobj, event, kw, src) {
|
|
17889
|
-
if (refuse_if_readonly(gobj, event)) return -1;
|
|
17893
|
+
if (refuse_if_readonly$1(gobj, event)) return -1;
|
|
17890
17894
|
let mode = (0, _yuneta_gobj_js.gobj_read_str_attr)(src, "form_mode");
|
|
17891
17895
|
(0, _yuneta_gobj_js.gobj_publish_event)(gobj, mode === "create" ? "EV_CREATE_RECORD" : "EV_UPDATE_RECORD", {
|
|
17892
17896
|
topic_name: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "topic_name"),
|
|
@@ -18302,6 +18306,7 @@ var attrs_table$3 = [
|
|
|
18302
18306
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "treedb_name", 0, null, "Remote service treedb name"),
|
|
18303
18307
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_DICT, "descs", 0, null, "Descriptions of topics obtained"),
|
|
18304
18308
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "system", 0, false, "Manage system topics (true) or user topics (false)"),
|
|
18309
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "readonly", 0, false, "The whole treedb is read-only: the graph drops its `edition` mode (the only one that draws write affordances) and refuses every write event. Set it when this yuno is not the MASTER of the treedb's tranger -- only the master can write, and the yuno answers 'READ-ONLY' to a write since SDK 7.13.0 (ask `treedb-info`)"),
|
|
18305
18310
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "back_route", 0, "", "Optional hash route for a '← topics' button back to the topics grid (host-supplied; empty = no button)"),
|
|
18306
18311
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "base_route", 0, "", "This view's base route (host-supplied); used to declare its per-topic focus sub-routes to the site map (ROUTING.md contributor)."),
|
|
18307
18312
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_DICT, "records", 0, "{}", "Data of topics"),
|
|
@@ -18352,6 +18357,7 @@ function mt_create$3(gobj) {
|
|
|
18352
18357
|
if (!subscriber) subscriber = (0, _yuneta_gobj_js.gobj_parent)(gobj);
|
|
18353
18358
|
(0, _yuneta_gobj_js.gobj_subscribe_event)(gobj, null, {}, subscriber);
|
|
18354
18359
|
if (!priv.treedb_name) (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_name)(gobj)} -> treedb_name not configured`);
|
|
18360
|
+
if ((0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "readonly") && priv.operation_mode === "edition") (0, _yuneta_gobj_js.gobj_write_str_attr)(gobj, "operation_mode", "reading");
|
|
18355
18361
|
let canvas_id = (0, _yuneta_gobj_js.clean_name)((0, _yuneta_gobj_js.gobj_name)(gobj)) + "-canvas";
|
|
18356
18362
|
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "canvas_id", canvas_id);
|
|
18357
18363
|
let $container_canvas = build_ui$3(gobj).querySelector(`#${priv.canvas_id}`);
|
|
@@ -18506,6 +18512,8 @@ function destroy_ui(gobj) {
|
|
|
18506
18512
|
************************************************************/
|
|
18507
18513
|
function make_toolbar(gobj) {
|
|
18508
18514
|
gobj.priv;
|
|
18515
|
+
let modes = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "operation_modes");
|
|
18516
|
+
if ((0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "readonly")) modes = modes.filter((mode) => mode !== "edition");
|
|
18509
18517
|
const $toolbar_header = yui_toolbar({}, [
|
|
18510
18518
|
[
|
|
18511
18519
|
"div",
|
|
@@ -18544,7 +18552,7 @@ function make_toolbar(gobj) {
|
|
|
18544
18552
|
[[
|
|
18545
18553
|
"select",
|
|
18546
18554
|
{ class: "GRAPH_MODE_SELECT" },
|
|
18547
|
-
|
|
18555
|
+
modes.map((item) => [
|
|
18548
18556
|
"option",
|
|
18549
18557
|
{},
|
|
18550
18558
|
item
|
|
@@ -19096,6 +19104,19 @@ function refresh_data(gobj) {
|
|
|
19096
19104
|
if (priv.gobj_nodes_tree) (0, _yuneta_gobj_js.gobj_send_event)(priv.gobj_nodes_tree, "EV_CLEAR_DATA", {}, gobj);
|
|
19097
19105
|
request_treedb_descs(gobj);
|
|
19098
19106
|
}
|
|
19107
|
+
/********************************************
|
|
19108
|
+
* The last gate before a write leaves for the yuno. The `edition`
|
|
19109
|
+
* mode is gone on a replica, so no button can raise these -- but the
|
|
19110
|
+
* G6 child also publishes them from its undo/redo history and from
|
|
19111
|
+
* saving the node geometry, and a write that got this far would
|
|
19112
|
+
* travel, be refused by the yuno, and come back as a toast with the
|
|
19113
|
+
* graph already redrawn.
|
|
19114
|
+
********************************************/
|
|
19115
|
+
function refuse_if_readonly(gobj, event) {
|
|
19116
|
+
if (!(0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "readonly")) return false;
|
|
19117
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} refused, treedb '${(0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name")}' is READ-ONLY`);
|
|
19118
|
+
return true;
|
|
19119
|
+
}
|
|
19099
19120
|
/***************************
|
|
19100
19121
|
* Actions
|
|
19101
19122
|
***************************/
|
|
@@ -19164,7 +19185,15 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
19164
19185
|
case "update-node":
|
|
19165
19186
|
case "delete-node":
|
|
19166
19187
|
case "link-nodes":
|
|
19167
|
-
case "unlink-nodes":
|
|
19188
|
+
case "unlink-nodes":
|
|
19189
|
+
if (result >= 0 && (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "topic_name", "", 0) !== "__graphs__") (0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_RECORD_WRITTEN", {
|
|
19190
|
+
treedb_name: (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "treedb_name", "", 0),
|
|
19191
|
+
topic_name: (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "topic_name", "", 0),
|
|
19192
|
+
record: (0, _yuneta_gobj_js.kw_get_dict)(gobj, kw_command, "record", {}, 0),
|
|
19193
|
+
created: command === "create-node",
|
|
19194
|
+
command
|
|
19195
|
+
});
|
|
19196
|
+
break;
|
|
19168
19197
|
default: (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)} Command unknown: ${command}`);
|
|
19169
19198
|
}
|
|
19170
19199
|
return 0;
|
|
@@ -19383,7 +19412,9 @@ function ac_edge_clicked(gobj, event, kw, src) {
|
|
|
19383
19412
|
* Send to backend
|
|
19384
19413
|
********************************************/
|
|
19385
19414
|
function ac_create_node(gobj, event, kw, src) {
|
|
19386
|
-
let
|
|
19415
|
+
let priv = gobj.priv;
|
|
19416
|
+
if (refuse_if_readonly(gobj, event)) return -1;
|
|
19417
|
+
let treedb_name = priv.treedb_name;
|
|
19387
19418
|
let topic_name = kw.topic_name;
|
|
19388
19419
|
let record = kw.record;
|
|
19389
19420
|
return treedb_create_node(gobj, treedb_name, topic_name, record, kw.options || {});
|
|
@@ -19398,7 +19429,9 @@ function ac_create_node(gobj, event, kw, src) {
|
|
|
19398
19429
|
* Send to backend
|
|
19399
19430
|
********************************************/
|
|
19400
19431
|
function ac_update_node(gobj, event, kw, src) {
|
|
19401
|
-
let
|
|
19432
|
+
let priv = gobj.priv;
|
|
19433
|
+
if (refuse_if_readonly(gobj, event)) return -1;
|
|
19434
|
+
let treedb_name = priv.treedb_name;
|
|
19402
19435
|
let topic_name = kw.topic_name;
|
|
19403
19436
|
let record = kw.record;
|
|
19404
19437
|
return treedb_update_node(gobj, treedb_name, topic_name, record, kw.options || {});
|
|
@@ -19413,7 +19446,9 @@ function ac_update_node(gobj, event, kw, src) {
|
|
|
19413
19446
|
* Send to backend
|
|
19414
19447
|
********************************************/
|
|
19415
19448
|
function ac_delete_node(gobj, event, kw, src) {
|
|
19416
|
-
let
|
|
19449
|
+
let priv = gobj.priv;
|
|
19450
|
+
if (refuse_if_readonly(gobj, event)) return -1;
|
|
19451
|
+
let treedb_name = priv.treedb_name;
|
|
19417
19452
|
let topic_name = kw.topic_name;
|
|
19418
19453
|
let record = kw.record;
|
|
19419
19454
|
return treedb_delete_node(gobj, treedb_name, topic_name, record, kw.options || {});
|
|
@@ -19428,7 +19463,9 @@ function ac_delete_node(gobj, event, kw, src) {
|
|
|
19428
19463
|
* Send to backend
|
|
19429
19464
|
********************************************/
|
|
19430
19465
|
function ac_link_nodes(gobj, event, kw, src) {
|
|
19431
|
-
let
|
|
19466
|
+
let priv = gobj.priv;
|
|
19467
|
+
if (refuse_if_readonly(gobj, event)) return -1;
|
|
19468
|
+
let treedb_name = priv.treedb_name;
|
|
19432
19469
|
let parent_ref = kw.parent_ref;
|
|
19433
19470
|
let child_ref = kw.child_ref;
|
|
19434
19471
|
return treedb_link_nodes(gobj, treedb_name, parent_ref, child_ref, kw.options || {});
|
|
@@ -19443,7 +19480,9 @@ function ac_link_nodes(gobj, event, kw, src) {
|
|
|
19443
19480
|
* Send to backend
|
|
19444
19481
|
********************************************/
|
|
19445
19482
|
function ac_unlink_nodes(gobj, event, kw, src) {
|
|
19446
|
-
let
|
|
19483
|
+
let priv = gobj.priv;
|
|
19484
|
+
if (refuse_if_readonly(gobj, event)) return -1;
|
|
19485
|
+
let treedb_name = priv.treedb_name;
|
|
19447
19486
|
let parent_ref = kw.parent_ref;
|
|
19448
19487
|
let child_ref = kw.child_ref;
|
|
19449
19488
|
return treedb_unlink_nodes(gobj, treedb_name, parent_ref, child_ref, kw.options || {});
|
|
@@ -19483,6 +19522,10 @@ function ac_set_layout$1(gobj, event, kw, src) {
|
|
|
19483
19522
|
function ac_set_operation_mode$1(gobj, event, kw, src) {
|
|
19484
19523
|
let priv = gobj.priv;
|
|
19485
19524
|
let operation_mode = kw.operation_mode;
|
|
19525
|
+
if (operation_mode === "edition" && (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "readonly")) {
|
|
19526
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: edition mode refused, treedb '${(0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name")}' is READ-ONLY`);
|
|
19527
|
+
return -1;
|
|
19528
|
+
}
|
|
19486
19529
|
(0, _yuneta_gobj_js.gobj_write_str_attr)(gobj, "operation_mode", operation_mode);
|
|
19487
19530
|
(0, _yuneta_gobj_js.gobj_save_persistent_attrs)(gobj, "operation_mode");
|
|
19488
19531
|
let $operation_mode_select = priv.$container.querySelector(".GRAPH_MODE_SELECT");
|
|
@@ -19704,6 +19747,7 @@ function create_gclass$3(gclass_name) {
|
|
|
19704
19747
|
["EV_SET_OPERATION_MODE", 0],
|
|
19705
19748
|
["EV_SET_FOCUS_TOPIC", 0],
|
|
19706
19749
|
["EV_OPERATION_MODE_CHANGED", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT | _yuneta_gobj_js.event_flag_t.EVF_NO_WARN_SUBS],
|
|
19750
|
+
["EV_RECORD_WRITTEN", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT | _yuneta_gobj_js.event_flag_t.EVF_NO_WARN_SUBS],
|
|
19707
19751
|
["EV_SHOW", 0],
|
|
19708
19752
|
["EV_HIDE", 0],
|
|
19709
19753
|
["EV_TRANSPORT_STATE", 0]
|
|
@@ -19723,11 +19767,26 @@ function register_c_yui_treedb_graph() {
|
|
|
19723
19767
|
/***********************************************************************
|
|
19724
19768
|
* c_yui_treedb_schema.js
|
|
19725
19769
|
*
|
|
19726
|
-
* Schema-graph landing
|
|
19727
|
-
*
|
|
19728
|
-
*
|
|
19729
|
-
*
|
|
19730
|
-
* the
|
|
19770
|
+
* Schema-graph landing: the treedb drawn the way its `.c` literal
|
|
19771
|
+
* draws it in ASCII (treedb_schema_*.c, treedb_system_schema.c) —
|
|
19772
|
+
* one CARD per topic listing its fields in schema order, one edge
|
|
19773
|
+
* per hook, from the row that declares the hook to the fkey row of
|
|
19774
|
+
* the child it names. Built from the schema `descs` alone: no data,
|
|
19775
|
+
* no backend calls.
|
|
19776
|
+
*
|
|
19777
|
+
* WHY THE CARD AND NOT A DOT. A topic is its fields; a schema is
|
|
19778
|
+
* read to find out what a topic holds and what links to what. A
|
|
19779
|
+
* graph of labelled dots answers neither, and the node graph next
|
|
19780
|
+
* door (C_G6_NODES_TREE) answers a different question entirely —
|
|
19781
|
+
* it draws the RECORDS, so on a treedb whose records are schemas
|
|
19782
|
+
* it draws one box per column, hundreds of them, each labelled by
|
|
19783
|
+
* a pkey that may be a rowid. This view draws the schema itself.
|
|
19784
|
+
*
|
|
19785
|
+
* The marks are the notation of the `.c` literals, so the drawing
|
|
19786
|
+
* and the source read the same — see schema_rows().
|
|
19787
|
+
*
|
|
19788
|
+
* A node click opens that topic's table (a real hash navigation
|
|
19789
|
+
* via the host-supplied `node_route`). An alternate landing to the
|
|
19731
19790
|
* topic cards, in the spirit of "every treedb is a graph".
|
|
19732
19791
|
*
|
|
19733
19792
|
* Copyright (c) 2026, ArtGins.
|
|
@@ -19737,6 +19796,27 @@ function register_c_yui_treedb_graph() {
|
|
|
19737
19796
|
* Constants
|
|
19738
19797
|
***************************************************************/
|
|
19739
19798
|
var GCLASS_NAME$2 = "C_YUI_TREEDB_SCHEMA";
|
|
19799
|
+
/************************************************************
|
|
19800
|
+
* Geometry of a card, in one place: the row height is what
|
|
19801
|
+
* turns a field's index into the vertical position of its
|
|
19802
|
+
* port, so an edge leaves the very row that declares the
|
|
19803
|
+
* hook and lands on the row that declares the fkey.
|
|
19804
|
+
************************************************************/
|
|
19805
|
+
var CARD_HEADER_H = 30;
|
|
19806
|
+
var CARD_ROW_H = 19;
|
|
19807
|
+
var CARD_PAD_V = 7;
|
|
19808
|
+
var CARD_MIN_W = 210;
|
|
19809
|
+
var CARD_MAX_W = 340;
|
|
19810
|
+
var topic_colors = [
|
|
19811
|
+
"rgb(237, 201, 73)",
|
|
19812
|
+
"rgb(118, 183, 178)",
|
|
19813
|
+
"rgb(255, 157, 167)",
|
|
19814
|
+
"rgb(175, 122, 161)",
|
|
19815
|
+
"rgb(89, 161, 79)",
|
|
19816
|
+
"rgb(186, 176, 171)",
|
|
19817
|
+
"rgb(66, 146, 198)"
|
|
19818
|
+
];
|
|
19819
|
+
var SYSTEM_TOPIC_COLOR = "rgb(148, 163, 184)";
|
|
19740
19820
|
/***************************************************************
|
|
19741
19821
|
* Data
|
|
19742
19822
|
***************************************************************/
|
|
@@ -19798,48 +19878,254 @@ function build_ui$2(gobj) {
|
|
|
19798
19878
|
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "$container", $container);
|
|
19799
19879
|
}
|
|
19800
19880
|
/************************************************************
|
|
19881
|
+
* The shape of a hook/fkey field, from the type it declares.
|
|
19882
|
+
* `dict` and `object` are the SAME thing to treedb (both build
|
|
19883
|
+
* a json object keyed by child id), and so are `list` and
|
|
19884
|
+
* `array` — see the hook/fkey switches in tr_treedb.c. A
|
|
19885
|
+
* `string` holds one reference, so it draws as one.
|
|
19886
|
+
************************************************************/
|
|
19887
|
+
function hook_mark(type) {
|
|
19888
|
+
if (type === "dict" || type === "object") return "{}";
|
|
19889
|
+
if (type === "list" || type === "array") return "[]";
|
|
19890
|
+
return "()";
|
|
19891
|
+
}
|
|
19892
|
+
/************************************************************
|
|
19893
|
+
* The fields of one topic, as the schema declares them.
|
|
19894
|
+
*
|
|
19895
|
+
* The marks are the notation of the schema `.c` literals
|
|
19896
|
+
* (treedb_schema_*.c, treedb_system_schema.c), so the
|
|
19897
|
+
* drawing and the source read the same:
|
|
19898
|
+
* {} dict hook (N unique children)
|
|
19899
|
+
* [] list hook (n not-unique children)
|
|
19900
|
+
* () 1 child
|
|
19901
|
+
* (↖) 1 fkey (1 parent)
|
|
19902
|
+
* [↖] n fkeys (n parents)
|
|
19903
|
+
* {↖} N fkeys (N parents)
|
|
19904
|
+
* * required
|
|
19905
|
+
* # the primary key
|
|
19906
|
+
*
|
|
19907
|
+
* A column can be BOTH hook and fkey, so the flags are read
|
|
19908
|
+
* here rather than through treedb_get_field_desc's single
|
|
19909
|
+
* `type`, which keeps only the last flag it saw.
|
|
19910
|
+
************************************************************/
|
|
19911
|
+
function schema_rows(desc) {
|
|
19912
|
+
let rows = [];
|
|
19913
|
+
if (!(0, _yuneta_gobj_js.is_object)(desc) || !Array.isArray(desc.cols)) return rows;
|
|
19914
|
+
for (let col of desc.cols) {
|
|
19915
|
+
if (!(0, _yuneta_gobj_js.is_object)(col) || !col.id) continue;
|
|
19916
|
+
let flags = Array.isArray(col.flag) ? col.flag : [];
|
|
19917
|
+
let is_hook = flags.indexOf("hook") >= 0;
|
|
19918
|
+
let is_fkey = flags.indexOf("fkey") >= 0;
|
|
19919
|
+
let mark = "";
|
|
19920
|
+
if (is_hook) mark = hook_mark(col.type);
|
|
19921
|
+
if (is_fkey) {
|
|
19922
|
+
let fmark = hook_mark(col.type).replace("}", "↖}").replace("]", "↖]").replace(")", "↖)");
|
|
19923
|
+
mark = mark ? mark + " " + fmark : fmark;
|
|
19924
|
+
}
|
|
19925
|
+
rows.push({
|
|
19926
|
+
name: col.id,
|
|
19927
|
+
type: col.type || "",
|
|
19928
|
+
mark,
|
|
19929
|
+
is_hook,
|
|
19930
|
+
is_fkey,
|
|
19931
|
+
is_pkey: col.id === desc.pkey,
|
|
19932
|
+
required: flags.indexOf("required") >= 0 || flags.indexOf("notnull") >= 0
|
|
19933
|
+
});
|
|
19934
|
+
}
|
|
19935
|
+
return rows;
|
|
19936
|
+
}
|
|
19937
|
+
/************************************************************
|
|
19938
|
+
* Size of the card that holds those rows. The width follows
|
|
19939
|
+
* the longest line so a long field name is not clipped into
|
|
19940
|
+
* an ellipsis — the point of the drawing is to read them.
|
|
19941
|
+
************************************************************/
|
|
19942
|
+
function card_size(rows) {
|
|
19943
|
+
let longest = 0;
|
|
19944
|
+
for (let row of rows) {
|
|
19945
|
+
let len = row.name.length + (row.mark ? row.mark.length + 2 : 0) + 2;
|
|
19946
|
+
if (len > longest) longest = len;
|
|
19947
|
+
}
|
|
19948
|
+
let w = Math.round(26 + longest * 6.6);
|
|
19949
|
+
if (w < CARD_MIN_W) w = CARD_MIN_W;
|
|
19950
|
+
if (w > CARD_MAX_W) w = CARD_MAX_W;
|
|
19951
|
+
let h = 44 + rows.length * CARD_ROW_H;
|
|
19952
|
+
return [w, h];
|
|
19953
|
+
}
|
|
19954
|
+
/************************************************************
|
|
19955
|
+
* Vertical placement of a field's port, as a fraction of the
|
|
19956
|
+
* card height: the centre of its own row.
|
|
19957
|
+
************************************************************/
|
|
19958
|
+
function row_placement(index, height) {
|
|
19959
|
+
return (37 + index * CARD_ROW_H + CARD_ROW_H / 2) / height;
|
|
19960
|
+
}
|
|
19961
|
+
/************************************************************
|
|
19962
|
+
* The card itself. Header = topic name on its topic colour;
|
|
19963
|
+
* body = one line per field, in schema order.
|
|
19964
|
+
************************************************************/
|
|
19965
|
+
function build_card_innerHTML(topic, rows, color, dark) {
|
|
19966
|
+
let surface = dark ? "#1b2230" : "#ffffff";
|
|
19967
|
+
let bg = dark ? `color-mix(in srgb, ${color} 18%, #232b38)` : `color-mix(in srgb, ${color} 6%, ${surface})`;
|
|
19968
|
+
let border = dark ? `color-mix(in srgb, ${color} 85%, #ffffff)` : color;
|
|
19969
|
+
let header_bg = dark ? `color-mix(in srgb, ${color} 45%, #2c3542)` : `color-mix(in srgb, ${color} 28%, ${surface})`;
|
|
19970
|
+
let title_color = dark ? "#e8eaed" : "#0f172a";
|
|
19971
|
+
let text_color = dark ? "#d3d8de" : "#334155";
|
|
19972
|
+
let mute_color = dark ? "#98a2b0" : "#7c8694";
|
|
19973
|
+
let rule_color = dark ? "rgba(255,255,255,0.06)" : "rgba(15,23,42,0.05)";
|
|
19974
|
+
let shadow = dark ? "0 1px 3px rgba(0,0,0,0.45), 0 1px 2px rgba(0,0,0,0.30)" : "0 1px 3px rgba(15,23,42,0.12), 0 1px 2px rgba(15,23,42,0.06)";
|
|
19975
|
+
let rows_html = "";
|
|
19976
|
+
for (let row of rows) {
|
|
19977
|
+
let lead = row.is_pkey ? "#" : row.required ? "*" : "";
|
|
19978
|
+
let name_weight = row.is_pkey || row.required ? "600" : "400";
|
|
19979
|
+
let name_color = row.is_hook || row.is_fkey ? title_color : text_color;
|
|
19980
|
+
rows_html += ` <div class="TREEDB_SCHEMA_FIELD" style="
|
|
19981
|
+
display: flex; align-items: center; gap: 6px;
|
|
19982
|
+
height: ${CARD_ROW_H}px; line-height: ${CARD_ROW_H}px;
|
|
19983
|
+
padding: 0 10px; border-top: 1px solid ${rule_color};
|
|
19984
|
+
">
|
|
19985
|
+
<span style="
|
|
19986
|
+
width: 8px; flex: 0 0 8px; text-align: center;
|
|
19987
|
+
color: ${mute_color}; font-size: 11px;
|
|
19988
|
+
">${lead}</span>
|
|
19989
|
+
<span style="
|
|
19990
|
+
flex: 1 1 auto; min-width: 0; overflow: hidden;
|
|
19991
|
+
text-overflow: ellipsis; white-space: nowrap;
|
|
19992
|
+
font-size: 12px; font-weight: ${name_weight}; color: ${name_color};
|
|
19993
|
+
">${(0, _yuneta_gobj_js.escapeHtml)(row.name)}</span>
|
|
19994
|
+
<span style="
|
|
19995
|
+
flex: 0 0 auto; font-size: 11px; color: ${mute_color};
|
|
19996
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
19997
|
+
">${(0, _yuneta_gobj_js.escapeHtml)(row.mark)}</span>
|
|
19998
|
+
</div>
|
|
19999
|
+
`;
|
|
20000
|
+
}
|
|
20001
|
+
return `
|
|
20002
|
+
<div class="TREEDB_SCHEMA_CARD" title="${(0, _yuneta_gobj_js.escapeHtml)(topic)}" style="
|
|
20003
|
+
box-sizing: border-box;
|
|
20004
|
+
width: 100%;
|
|
20005
|
+
height: 100%;
|
|
20006
|
+
background: ${bg};
|
|
20007
|
+
border: 1.5px solid ${border};
|
|
20008
|
+
border-radius: 8px;
|
|
20009
|
+
box-shadow: ${shadow};
|
|
20010
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
20011
|
+
display: flex;
|
|
20012
|
+
flex-direction: column;
|
|
20013
|
+
overflow: hidden;
|
|
20014
|
+
cursor: pointer;
|
|
20015
|
+
">
|
|
20016
|
+
<div class="TREEDB_SCHEMA_CARD_HEADER" style="
|
|
20017
|
+
height: ${CARD_HEADER_H}px; line-height: ${CARD_HEADER_H}px;
|
|
20018
|
+
flex: 0 0 ${CARD_HEADER_H}px;
|
|
20019
|
+
padding: 0 10px; background: ${header_bg}; color: ${title_color};
|
|
20020
|
+
font-size: 13px; font-weight: 700;
|
|
20021
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
20022
|
+
">${(0, _yuneta_gobj_js.escapeHtml)(topic)}</div>
|
|
20023
|
+
<div class="TREEDB_SCHEMA_CARD_BODY" style="
|
|
20024
|
+
flex: 1 1 auto; padding: ${CARD_PAD_V}px 0; overflow: hidden;
|
|
20025
|
+
">
|
|
20026
|
+
${rows_html} </div>
|
|
20027
|
+
</div>
|
|
20028
|
+
`;
|
|
20029
|
+
}
|
|
20030
|
+
/************************************************************
|
|
19801
20031
|
* Derive {nodes, edges} from the schema.
|
|
19802
|
-
*
|
|
19803
|
-
*
|
|
20032
|
+
*
|
|
20033
|
+
* Node = a topic, drawn as the card the `.c` literal draws in
|
|
20034
|
+
* ASCII: its name and its fields. Edge = a hook, from the row
|
|
20035
|
+
* that declares it to the fkey row of the child it names —
|
|
20036
|
+
* `'hook': {'users': 'departments'}` says both ends, so the
|
|
20037
|
+
* arrow can land where the `.c` drawing lands it. An fkey
|
|
20038
|
+
* whose parent declares no hook still gets its edge, or a
|
|
20039
|
+
* half-declared schema would draw as disconnected.
|
|
20040
|
+
*
|
|
19804
20041
|
* Left-to-right dagre follows the parent -> child data flow.
|
|
19805
20042
|
************************************************************/
|
|
19806
20043
|
function schema_to_graph(gobj) {
|
|
19807
20044
|
let descs = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "descs");
|
|
19808
20045
|
let system = (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "system");
|
|
20046
|
+
let dark = yui_is_dark();
|
|
19809
20047
|
let nodes = [];
|
|
19810
|
-
let
|
|
20048
|
+
let cards = {};
|
|
19811
20049
|
if (!(0, _yuneta_gobj_js.is_object)(descs)) return {
|
|
19812
20050
|
nodes,
|
|
19813
20051
|
edges: []
|
|
19814
20052
|
};
|
|
20053
|
+
let idx = 0;
|
|
19815
20054
|
for (let topic of Object.keys(descs)) {
|
|
19816
|
-
|
|
19817
|
-
|
|
20055
|
+
let is_system = topic.substring(0, 2) === "__";
|
|
20056
|
+
if (!system && is_system) continue;
|
|
20057
|
+
let rows = schema_rows(descs[topic]);
|
|
20058
|
+
let color;
|
|
20059
|
+
if (is_system) color = SYSTEM_TOPIC_COLOR;
|
|
20060
|
+
else {
|
|
20061
|
+
color = topic_colors[idx % topic_colors.length];
|
|
20062
|
+
idx++;
|
|
20063
|
+
}
|
|
20064
|
+
cards[topic] = {
|
|
20065
|
+
rows,
|
|
20066
|
+
size: card_size(rows),
|
|
20067
|
+
color
|
|
20068
|
+
};
|
|
20069
|
+
}
|
|
20070
|
+
for (let topic of Object.keys(cards)) {
|
|
20071
|
+
let card = cards[topic];
|
|
20072
|
+
let [w, h] = card.size;
|
|
20073
|
+
let ports = [];
|
|
20074
|
+
for (let i = 0; i < card.rows.length; i++) {
|
|
20075
|
+
let row = card.rows[i];
|
|
20076
|
+
if (!row.is_hook && !row.is_fkey) continue;
|
|
20077
|
+
ports.push({
|
|
20078
|
+
key: row.name,
|
|
20079
|
+
placement: [row.is_hook ? 1 : 0, row_placement(i, h)],
|
|
20080
|
+
fill: card.color,
|
|
20081
|
+
stroke: getStrokeColor(card.color)
|
|
20082
|
+
});
|
|
20083
|
+
}
|
|
19818
20084
|
nodes.push({
|
|
19819
20085
|
id: topic,
|
|
19820
|
-
|
|
20086
|
+
type: "html",
|
|
20087
|
+
style: {
|
|
20088
|
+
size: [w, h],
|
|
20089
|
+
dx: -w / 2,
|
|
20090
|
+
dy: -h / 2,
|
|
20091
|
+
innerHTML: build_card_innerHTML(topic, card.rows, card.color, dark),
|
|
20092
|
+
port: ports.length > 0,
|
|
20093
|
+
ports,
|
|
20094
|
+
portR: 3,
|
|
20095
|
+
portLineWidth: 1
|
|
20096
|
+
},
|
|
20097
|
+
data: {
|
|
20098
|
+
topic_name: topic,
|
|
20099
|
+
rows: card.rows,
|
|
20100
|
+
color: card.color
|
|
20101
|
+
}
|
|
19821
20102
|
});
|
|
19822
20103
|
}
|
|
19823
20104
|
let edge_seen = {};
|
|
19824
20105
|
let edges = [];
|
|
19825
|
-
let add_edge = (source, target) => {
|
|
19826
|
-
if (!
|
|
19827
|
-
let key = source
|
|
20106
|
+
let add_edge = (source, source_port, target, target_port) => {
|
|
20107
|
+
if (!cards[source] || !cards[target]) return;
|
|
20108
|
+
let key = `${source}|${source_port}|${target}|${target_port}`;
|
|
19828
20109
|
if (edge_seen[key]) return;
|
|
19829
20110
|
edge_seen[key] = true;
|
|
19830
20111
|
edges.push({
|
|
19831
20112
|
id: key,
|
|
20113
|
+
type: "cubic",
|
|
19832
20114
|
source,
|
|
19833
|
-
target
|
|
20115
|
+
target,
|
|
20116
|
+
style: {
|
|
20117
|
+
sourcePort: source_port,
|
|
20118
|
+
targetPort: target_port
|
|
20119
|
+
}
|
|
19834
20120
|
});
|
|
19835
20121
|
};
|
|
19836
|
-
for (let topic of Object.keys(
|
|
20122
|
+
for (let topic of Object.keys(cards)) {
|
|
19837
20123
|
let desc = descs[topic];
|
|
19838
20124
|
if (!(0, _yuneta_gobj_js.is_object)(desc) || !Array.isArray(desc.cols)) continue;
|
|
19839
20125
|
for (let col of desc.cols) {
|
|
19840
|
-
if (!col) continue;
|
|
19841
|
-
if ((0, _yuneta_gobj_js.is_object)(col.hook)) for (let child of Object.keys(col.hook)) add_edge(topic, child);
|
|
19842
|
-
|
|
20126
|
+
if (!(0, _yuneta_gobj_js.is_object)(col) || !col.id) continue;
|
|
20127
|
+
if ((0, _yuneta_gobj_js.is_object)(col.hook)) for (let child of Object.keys(col.hook)) add_edge(topic, col.id, child, col.hook[child]);
|
|
20128
|
+
if ((0, _yuneta_gobj_js.is_object)(col.fkey)) for (let parent of Object.keys(col.fkey)) add_edge(parent, col.fkey[parent], topic, col.id);
|
|
19843
20129
|
}
|
|
19844
20130
|
}
|
|
19845
20131
|
return {
|
|
@@ -19848,26 +20134,15 @@ function schema_to_graph(gobj) {
|
|
|
19848
20134
|
};
|
|
19849
20135
|
}
|
|
19850
20136
|
/************************************************************
|
|
19851
|
-
* The theme-dependent
|
|
19852
|
-
*
|
|
20137
|
+
* The theme-dependent edge style, in ONE place: applied as
|
|
20138
|
+
* the graph is built and re-applied on a theme switch
|
|
19853
20139
|
* (ac_theme), which restyles the LIVE graph — rebuilding it
|
|
19854
20140
|
* would drop the user's zoom/pan and any dragged node.
|
|
19855
20141
|
************************************************************/
|
|
19856
|
-
function node_style(dark) {
|
|
19857
|
-
return {
|
|
19858
|
-
size: 40,
|
|
19859
|
-
fill: "#5B8FF9",
|
|
19860
|
-
labelText: (d) => d.id,
|
|
19861
|
-
labelPlacement: "bottom",
|
|
19862
|
-
labelFill: dark ? "#e6e6e6" : "#333333",
|
|
19863
|
-
labelBackground: true,
|
|
19864
|
-
labelBackgroundFill: dark ? "rgba(0,0,0,0.5)" : "rgba(255,255,255,0.7)",
|
|
19865
|
-
cursor: "pointer"
|
|
19866
|
-
};
|
|
19867
|
-
}
|
|
19868
20142
|
function edge_style(dark) {
|
|
19869
20143
|
return {
|
|
19870
|
-
stroke: dark ? "#
|
|
20144
|
+
stroke: dark ? "#7a8593" : "#9aa4b2",
|
|
20145
|
+
lineWidth: 1.2,
|
|
19871
20146
|
endArrow: true
|
|
19872
20147
|
};
|
|
19873
20148
|
}
|
|
@@ -19899,13 +20174,12 @@ function build_graph$1(gobj) {
|
|
|
19899
20174
|
container: $container,
|
|
19900
20175
|
autoResize: true,
|
|
19901
20176
|
data,
|
|
19902
|
-
node: { style: node_style(dark) },
|
|
19903
20177
|
edge: { style: edge_style(dark) },
|
|
19904
20178
|
layout: {
|
|
19905
20179
|
type: "antv-dagre",
|
|
19906
20180
|
rankdir: "LR",
|
|
19907
|
-
nodesep:
|
|
19908
|
-
ranksep:
|
|
20181
|
+
nodesep: 28,
|
|
20182
|
+
ranksep: 90
|
|
19909
20183
|
},
|
|
19910
20184
|
behaviors: [
|
|
19911
20185
|
"zoom-canvas",
|
|
@@ -19990,8 +20264,17 @@ function ac_theme$1(gobj, event, kw, src) {
|
|
|
19990
20264
|
let dark = kw && kw.theme ? kw.theme === "dark" : yui_is_dark();
|
|
19991
20265
|
try {
|
|
19992
20266
|
graph.setTheme(dark ? "dark" : "light");
|
|
19993
|
-
graph.setNode({ style: node_style(dark) });
|
|
19994
20267
|
graph.setEdge({ style: edge_style(dark) });
|
|
20268
|
+
let updates = [];
|
|
20269
|
+
for (let node of graph.getNodeData()) {
|
|
20270
|
+
let data = node.data;
|
|
20271
|
+
if (!(0, _yuneta_gobj_js.is_object)(data) || !Array.isArray(data.rows)) continue;
|
|
20272
|
+
updates.push({
|
|
20273
|
+
id: node.id,
|
|
20274
|
+
style: { innerHTML: build_card_innerHTML(data.topic_name, data.rows, data.color, dark) }
|
|
20275
|
+
});
|
|
20276
|
+
}
|
|
20277
|
+
if (updates.length > 0) graph.updateNodeData(updates);
|
|
19995
20278
|
graph.draw().catch((e) => {
|
|
19996
20279
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: schema graph redraw failed: ${e}`);
|
|
19997
20280
|
});
|
|
@@ -20056,6 +20339,58 @@ function register_c_yui_treedb_schema() {
|
|
|
20056
20339
|
return create_gclass$2(GCLASS_NAME$2);
|
|
20057
20340
|
}
|
|
20058
20341
|
//#endregion
|
|
20342
|
+
//#region src/treedb_node_label.js
|
|
20343
|
+
/***********************************************************************
|
|
20344
|
+
* treedb_node_label.js
|
|
20345
|
+
*
|
|
20346
|
+
* Pure, testable logic behind the label of a node in the treedb
|
|
20347
|
+
* graph: WHAT A RECORD IS CALLED, which is not always what it is
|
|
20348
|
+
* keyed by. Kept out of the gclass so it can be unit-tested with
|
|
20349
|
+
* no DOM and no G6.
|
|
20350
|
+
*
|
|
20351
|
+
* Copyright (c) 2026, ArtGins.
|
|
20352
|
+
* All Rights Reserved.
|
|
20353
|
+
***********************************************************************/
|
|
20354
|
+
/************************************************************
|
|
20355
|
+
* What a node is CALLED, which is not always what it is
|
|
20356
|
+
* keyed by.
|
|
20357
|
+
*
|
|
20358
|
+
* A topic whose id column is flagged `rowid` or `uuid` keys
|
|
20359
|
+
* its records by a value nobody reads — that is the point of
|
|
20360
|
+
* those flags — and the name a human knows the record by
|
|
20361
|
+
* lives in the secondary key the topic declares (`pkey2s`,
|
|
20362
|
+
* carried in the desc since SDK > 7.13.0). The `topics` and
|
|
20363
|
+
* `cols` topics of treedb_system_schema are the case that
|
|
20364
|
+
* forced this: keyed by rowid, named in `value`, so every
|
|
20365
|
+
* card in the graph read "181", "225", "193".
|
|
20366
|
+
*
|
|
20367
|
+
* The pkey stays reachable: it is the card's tooltip.
|
|
20368
|
+
*
|
|
20369
|
+
* Falls back to the id whenever the schema does not say
|
|
20370
|
+
* otherwise — an older node whose desc carries no `pkey2s`
|
|
20371
|
+
* included.
|
|
20372
|
+
************************************************************/
|
|
20373
|
+
function node_label(desc, record) {
|
|
20374
|
+
let id = record.id;
|
|
20375
|
+
let id_col = null;
|
|
20376
|
+
if (Array.isArray(desc.cols)) {
|
|
20377
|
+
for (let col of desc.cols) if (col && col.id === (desc.pkey || "id")) {
|
|
20378
|
+
id_col = col;
|
|
20379
|
+
break;
|
|
20380
|
+
}
|
|
20381
|
+
}
|
|
20382
|
+
if (!id_col || !Array.isArray(id_col.flag)) return id;
|
|
20383
|
+
if (id_col.flag.indexOf("rowid") < 0 && id_col.flag.indexOf("uuid") < 0) return id;
|
|
20384
|
+
let pkey2s = desc.pkey2s;
|
|
20385
|
+
if (typeof pkey2s === "string") pkey2s = pkey2s ? [pkey2s] : [];
|
|
20386
|
+
if (!Array.isArray(pkey2s)) return id;
|
|
20387
|
+
for (let name of pkey2s) {
|
|
20388
|
+
let value = record[name];
|
|
20389
|
+
if (typeof value === "string" && value.length > 0) return value;
|
|
20390
|
+
}
|
|
20391
|
+
return id;
|
|
20392
|
+
}
|
|
20393
|
+
//#endregion
|
|
20059
20394
|
//#region node_modules/@babel/runtime/helpers/esm/typeof.js
|
|
20060
20395
|
function _typeof(o) {
|
|
20061
20396
|
"@babel/helpers - typeof";
|
|
@@ -47588,19 +47923,19 @@ function create_topic_node(gobj, desc, record) {
|
|
|
47588
47923
|
style.size = [116, 40];
|
|
47589
47924
|
style.dx = -58;
|
|
47590
47925
|
style.dy = -20;
|
|
47591
|
-
style.innerHTML = build_chip_innerHTML(desc.color, priv.theme, record.icon, record.id);
|
|
47926
|
+
style.innerHTML = build_chip_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), record.id);
|
|
47592
47927
|
} else if (node_treedb_type === "extended") {
|
|
47593
47928
|
node_graph_type = "html";
|
|
47594
47929
|
style.size = [144, 66];
|
|
47595
47930
|
style.dx = -72;
|
|
47596
47931
|
style.dy = -33;
|
|
47597
|
-
style.innerHTML = build_node_innerHTML(desc.color, priv.theme, record.icon, record
|
|
47932
|
+
style.innerHTML = build_node_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), desc.topic_name, true, record.id);
|
|
47598
47933
|
} else {
|
|
47599
47934
|
node_graph_type = "html";
|
|
47600
47935
|
style.size = [172, 96];
|
|
47601
47936
|
style.dx = -86;
|
|
47602
47937
|
style.dy = -48;
|
|
47603
|
-
style.innerHTML = build_node_innerHTML(desc.color, priv.theme, record.icon, record
|
|
47938
|
+
style.innerHTML = build_node_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), desc.topic_name, false, record.id);
|
|
47604
47939
|
}
|
|
47605
47940
|
let topic_props = priv._graph_properties[desc.topic_name];
|
|
47606
47941
|
let topic_defaults = (0, _yuneta_gobj_js.is_object)(topic_props) && (0, _yuneta_gobj_js.is_object)(topic_props.defaults) ? topic_props.defaults : null;
|
|
@@ -47668,15 +48003,15 @@ function update_topic_node(gobj, desc, node_name, record) {
|
|
|
47668
48003
|
nodedata.data.record = record;
|
|
47669
48004
|
if (desc.node_treedb_type === "child") graph.updateNodeData([{
|
|
47670
48005
|
id: node_name,
|
|
47671
|
-
style: { innerHTML: build_chip_innerHTML(desc.color, priv.theme, record.icon, record.id) }
|
|
48006
|
+
style: { innerHTML: build_chip_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), record.id) }
|
|
47672
48007
|
}]);
|
|
47673
48008
|
else if (desc.node_treedb_type === "extended") graph.updateNodeData([{
|
|
47674
48009
|
id: node_name,
|
|
47675
|
-
style: { innerHTML: build_node_innerHTML(desc.color, priv.theme, record.icon, record
|
|
48010
|
+
style: { innerHTML: build_node_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), desc.topic_name, true, record.id) }
|
|
47676
48011
|
}]);
|
|
47677
48012
|
else if (desc.node_treedb_type === "hierarchical") graph.updateNodeData([{
|
|
47678
48013
|
id: node_name,
|
|
47679
|
-
style: { innerHTML: build_node_innerHTML(desc.color, priv.theme, record.icon, record
|
|
48014
|
+
style: { innerHTML: build_node_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), desc.topic_name, false, record.id) }
|
|
47680
48015
|
}]);
|
|
47681
48016
|
} catch (e) {
|
|
47682
48017
|
(0, _yuneta_gobj_js.log_error)(e.message);
|
|
@@ -49583,7 +49918,7 @@ function show_node_popover(gobj) {
|
|
|
49583
49918
|
};
|
|
49584
49919
|
if (node_graph_type === "hierarchical") {
|
|
49585
49920
|
let record = nodeData.data.record || {};
|
|
49586
|
-
updateStyle.innerHTML = build_node_innerHTML(fill, priv.theme, record.icon,
|
|
49921
|
+
updateStyle.innerHTML = build_node_innerHTML(fill, priv.theme, record.icon, node_label(nodeData.data.desc, record), nodeData.data.desc.topic_name, false, record.id);
|
|
49587
49922
|
}
|
|
49588
49923
|
graph.updateNodeData([{
|
|
49589
49924
|
id: node_id,
|
|
@@ -49623,7 +49958,7 @@ function show_node_popover(gobj) {
|
|
|
49623
49958
|
};
|
|
49624
49959
|
if (node_graph_type === "hierarchical") {
|
|
49625
49960
|
let record = nodeData.data.record || {};
|
|
49626
|
-
restoreStyle.innerHTML = build_node_innerHTML(origFill, priv.theme, record.icon,
|
|
49961
|
+
restoreStyle.innerHTML = build_node_innerHTML(origFill, priv.theme, record.icon, node_label(nodeData.data.desc, record), nodeData.data.desc.topic_name, false, record.id);
|
|
49627
49962
|
}
|
|
49628
49963
|
graph.updateNodeData([{
|
|
49629
49964
|
id: node_id,
|
|
@@ -49724,15 +50059,15 @@ function refresh_html_nodes_theme(gobj, theme) {
|
|
|
49724
50059
|
let record = nd.data.record || {};
|
|
49725
50060
|
if (tt === "hierarchical") updates.push({
|
|
49726
50061
|
id: nodes[i].id,
|
|
49727
|
-
style: { innerHTML: build_node_innerHTML(nd.data.desc.color, theme, record.icon,
|
|
50062
|
+
style: { innerHTML: build_node_innerHTML(nd.data.desc.color, theme, record.icon, node_label(nd.data.desc, record), nd.data.desc.topic_name, false, record.id) }
|
|
49728
50063
|
});
|
|
49729
50064
|
else if (tt === "child") updates.push({
|
|
49730
50065
|
id: nodes[i].id,
|
|
49731
|
-
style: { innerHTML: build_chip_innerHTML(nd.data.desc.color, theme, record.icon, record.id) }
|
|
50066
|
+
style: { innerHTML: build_chip_innerHTML(nd.data.desc.color, theme, record.icon, node_label(nd.data.desc, record), record.id) }
|
|
49732
50067
|
});
|
|
49733
50068
|
else if (tt === "extended") updates.push({
|
|
49734
50069
|
id: nodes[i].id,
|
|
49735
|
-
style: { innerHTML: build_node_innerHTML(nd.data.desc.color, theme, record.icon,
|
|
50070
|
+
style: { innerHTML: build_node_innerHTML(nd.data.desc.color, theme, record.icon, node_label(nd.data.desc, record), nd.data.desc.topic_name, true, record.id) }
|
|
49736
50071
|
});
|
|
49737
50072
|
}
|
|
49738
50073
|
if (updates.length > 0) graph.updateNodeData(updates);
|
|
@@ -49764,7 +50099,8 @@ function refresh_default_edges_theme(gobj, theme) {
|
|
|
49764
50099
|
* but lighter (1px border, no shadow, single line). The name is
|
|
49765
50100
|
* always legible (ellipsis + native title tooltip on overflow).
|
|
49766
50101
|
************************************************************/
|
|
49767
|
-
function build_chip_innerHTML(color, theme, icon,
|
|
50102
|
+
function build_chip_innerHTML(color, theme, icon, label, key) {
|
|
50103
|
+
let title = key || label;
|
|
49768
50104
|
let dark = theme === "dark";
|
|
49769
50105
|
let bg = dark ? `color-mix(in srgb, ${color} 30%, #2c3542)` : `color-mix(in srgb, ${color} 10%, ${dark ? "#1b2230" : "#ffffff"})`;
|
|
49770
50106
|
let border = dark ? `color-mix(in srgb, ${color} 85%, #ffffff)` : color;
|
|
@@ -49775,7 +50111,7 @@ function build_chip_innerHTML(color, theme, icon, id) {
|
|
|
49775
50111
|
margin-right: 6px; flex: 0 0 auto;
|
|
49776
50112
|
"/>`;
|
|
49777
50113
|
return `
|
|
49778
|
-
<div title="${(0, _yuneta_gobj_js.escapeHtml)(
|
|
50114
|
+
<div title="${(0, _yuneta_gobj_js.escapeHtml)(title)}" style="
|
|
49779
50115
|
box-sizing: border-box;
|
|
49780
50116
|
width: 100%;
|
|
49781
50117
|
height: 100%;
|
|
@@ -49792,7 +50128,7 @@ function build_chip_innerHTML(color, theme, icon, id) {
|
|
|
49792
50128
|
">${icon_html}<span style="
|
|
49793
50129
|
font-size: 12px; font-weight: 600; line-height: 1;
|
|
49794
50130
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
49795
|
-
">${(0, _yuneta_gobj_js.escapeHtml)(
|
|
50131
|
+
">${(0, _yuneta_gobj_js.escapeHtml)(label)}</span>
|
|
49796
50132
|
</div>
|
|
49797
50133
|
`;
|
|
49798
50134
|
}
|
|
@@ -49806,7 +50142,8 @@ function build_chip_innerHTML(color, theme, icon, id) {
|
|
|
49806
50142
|
* colour is kept (per-topic differentiation) but softened via
|
|
49807
50143
|
* color-mix instead of a harsh saturated fill. Theme-aware.
|
|
49808
50144
|
************************************************************/
|
|
49809
|
-
function build_node_innerHTML(color, theme, icon,
|
|
50145
|
+
function build_node_innerHTML(color, theme, icon, label, topic_name, structural, key) {
|
|
50146
|
+
let title = key || label;
|
|
49810
50147
|
let dark = theme === "dark";
|
|
49811
50148
|
let surface = dark ? "#1b2230" : "#ffffff";
|
|
49812
50149
|
let bg, border, border_style;
|
|
@@ -49836,7 +50173,7 @@ function build_node_innerHTML(color, theme, icon, id, topic_name, structural) {
|
|
|
49836
50173
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
49837
50174
|
">${(0, _yuneta_gobj_js.escapeHtml)(topic_name)}</div>`;
|
|
49838
50175
|
return `
|
|
49839
|
-
<div title="${(0, _yuneta_gobj_js.escapeHtml)(
|
|
50176
|
+
<div title="${(0, _yuneta_gobj_js.escapeHtml)(title)}" style="
|
|
49840
50177
|
box-sizing: border-box;
|
|
49841
50178
|
width: 100%;
|
|
49842
50179
|
height: 100%;
|
|
@@ -49859,7 +50196,7 @@ function build_node_innerHTML(color, theme, icon, id, topic_name, structural) {
|
|
|
49859
50196
|
max-width: 100%; overflow: hidden; text-overflow: ellipsis;
|
|
49860
50197
|
display: -webkit-box; -webkit-line-clamp: 2;
|
|
49861
50198
|
-webkit-box-orient: vertical; word-break: break-word;
|
|
49862
|
-
">${(0, _yuneta_gobj_js.escapeHtml)(
|
|
50199
|
+
">${(0, _yuneta_gobj_js.escapeHtml)(label)}</div>${sub_html}
|
|
49863
50200
|
</div>
|
|
49864
50201
|
`;
|
|
49865
50202
|
}
|
|
@@ -50080,7 +50417,7 @@ function apply_node_properties(gobj, node_id, fill, stroke, lineWidth, scope) {
|
|
|
50080
50417
|
};
|
|
50081
50418
|
if (nd.data.desc.node_treedb_type === "hierarchical") {
|
|
50082
50419
|
let record = nd.data.record || {};
|
|
50083
|
-
updateStyle.innerHTML = build_node_innerHTML(fill, priv.theme, record.icon,
|
|
50420
|
+
updateStyle.innerHTML = build_node_innerHTML(fill, priv.theme, record.icon, node_label(nd.data.desc, record), nd.data.desc.topic_name, false, record.id);
|
|
50084
50421
|
}
|
|
50085
50422
|
updates.push({
|
|
50086
50423
|
id: nodes[i].id,
|