@yuneta/gobj-ui 5.16.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 +60 -10
- package/dist/gobj-ui.cjs.js +349 -56
- package/dist/gobj-ui.es.js +349 -56
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +38 -24
- package/src/c_yui_treedb_schema.js +348 -43
- package/src/treedb_node_label.js +73 -0
- package/src/treedb_node_label.test.js +92 -0
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -19767,11 +19767,26 @@ function register_c_yui_treedb_graph() {
|
|
|
19767
19767
|
/***********************************************************************
|
|
19768
19768
|
* c_yui_treedb_schema.js
|
|
19769
19769
|
*
|
|
19770
|
-
* Schema-graph landing
|
|
19771
|
-
*
|
|
19772
|
-
*
|
|
19773
|
-
*
|
|
19774
|
-
* 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
|
|
19775
19790
|
* topic cards, in the spirit of "every treedb is a graph".
|
|
19776
19791
|
*
|
|
19777
19792
|
* Copyright (c) 2026, ArtGins.
|
|
@@ -19781,6 +19796,27 @@ function register_c_yui_treedb_graph() {
|
|
|
19781
19796
|
* Constants
|
|
19782
19797
|
***************************************************************/
|
|
19783
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)";
|
|
19784
19820
|
/***************************************************************
|
|
19785
19821
|
* Data
|
|
19786
19822
|
***************************************************************/
|
|
@@ -19842,48 +19878,254 @@ function build_ui$2(gobj) {
|
|
|
19842
19878
|
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "$container", $container);
|
|
19843
19879
|
}
|
|
19844
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
|
+
/************************************************************
|
|
19845
20031
|
* Derive {nodes, edges} from the schema.
|
|
19846
|
-
*
|
|
19847
|
-
*
|
|
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
|
+
*
|
|
19848
20041
|
* Left-to-right dagre follows the parent -> child data flow.
|
|
19849
20042
|
************************************************************/
|
|
19850
20043
|
function schema_to_graph(gobj) {
|
|
19851
20044
|
let descs = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "descs");
|
|
19852
20045
|
let system = (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "system");
|
|
20046
|
+
let dark = yui_is_dark();
|
|
19853
20047
|
let nodes = [];
|
|
19854
|
-
let
|
|
20048
|
+
let cards = {};
|
|
19855
20049
|
if (!(0, _yuneta_gobj_js.is_object)(descs)) return {
|
|
19856
20050
|
nodes,
|
|
19857
20051
|
edges: []
|
|
19858
20052
|
};
|
|
20053
|
+
let idx = 0;
|
|
19859
20054
|
for (let topic of Object.keys(descs)) {
|
|
19860
|
-
|
|
19861
|
-
|
|
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
|
+
}
|
|
19862
20084
|
nodes.push({
|
|
19863
20085
|
id: topic,
|
|
19864
|
-
|
|
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
|
+
}
|
|
19865
20102
|
});
|
|
19866
20103
|
}
|
|
19867
20104
|
let edge_seen = {};
|
|
19868
20105
|
let edges = [];
|
|
19869
|
-
let add_edge = (source, target) => {
|
|
19870
|
-
if (!
|
|
19871
|
-
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}`;
|
|
19872
20109
|
if (edge_seen[key]) return;
|
|
19873
20110
|
edge_seen[key] = true;
|
|
19874
20111
|
edges.push({
|
|
19875
20112
|
id: key,
|
|
20113
|
+
type: "cubic",
|
|
19876
20114
|
source,
|
|
19877
|
-
target
|
|
20115
|
+
target,
|
|
20116
|
+
style: {
|
|
20117
|
+
sourcePort: source_port,
|
|
20118
|
+
targetPort: target_port
|
|
20119
|
+
}
|
|
19878
20120
|
});
|
|
19879
20121
|
};
|
|
19880
|
-
for (let topic of Object.keys(
|
|
20122
|
+
for (let topic of Object.keys(cards)) {
|
|
19881
20123
|
let desc = descs[topic];
|
|
19882
20124
|
if (!(0, _yuneta_gobj_js.is_object)(desc) || !Array.isArray(desc.cols)) continue;
|
|
19883
20125
|
for (let col of desc.cols) {
|
|
19884
|
-
if (!col) continue;
|
|
19885
|
-
if ((0, _yuneta_gobj_js.is_object)(col.hook)) for (let child of Object.keys(col.hook)) add_edge(topic, child);
|
|
19886
|
-
|
|
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);
|
|
19887
20129
|
}
|
|
19888
20130
|
}
|
|
19889
20131
|
return {
|
|
@@ -19892,26 +20134,15 @@ function schema_to_graph(gobj) {
|
|
|
19892
20134
|
};
|
|
19893
20135
|
}
|
|
19894
20136
|
/************************************************************
|
|
19895
|
-
* The theme-dependent
|
|
19896
|
-
*
|
|
20137
|
+
* The theme-dependent edge style, in ONE place: applied as
|
|
20138
|
+
* the graph is built and re-applied on a theme switch
|
|
19897
20139
|
* (ac_theme), which restyles the LIVE graph — rebuilding it
|
|
19898
20140
|
* would drop the user's zoom/pan and any dragged node.
|
|
19899
20141
|
************************************************************/
|
|
19900
|
-
function node_style(dark) {
|
|
19901
|
-
return {
|
|
19902
|
-
size: 40,
|
|
19903
|
-
fill: "#5B8FF9",
|
|
19904
|
-
labelText: (d) => d.id,
|
|
19905
|
-
labelPlacement: "bottom",
|
|
19906
|
-
labelFill: dark ? "#e6e6e6" : "#333333",
|
|
19907
|
-
labelBackground: true,
|
|
19908
|
-
labelBackgroundFill: dark ? "rgba(0,0,0,0.5)" : "rgba(255,255,255,0.7)",
|
|
19909
|
-
cursor: "pointer"
|
|
19910
|
-
};
|
|
19911
|
-
}
|
|
19912
20142
|
function edge_style(dark) {
|
|
19913
20143
|
return {
|
|
19914
|
-
stroke: dark ? "#
|
|
20144
|
+
stroke: dark ? "#7a8593" : "#9aa4b2",
|
|
20145
|
+
lineWidth: 1.2,
|
|
19915
20146
|
endArrow: true
|
|
19916
20147
|
};
|
|
19917
20148
|
}
|
|
@@ -19943,13 +20174,12 @@ function build_graph$1(gobj) {
|
|
|
19943
20174
|
container: $container,
|
|
19944
20175
|
autoResize: true,
|
|
19945
20176
|
data,
|
|
19946
|
-
node: { style: node_style(dark) },
|
|
19947
20177
|
edge: { style: edge_style(dark) },
|
|
19948
20178
|
layout: {
|
|
19949
20179
|
type: "antv-dagre",
|
|
19950
20180
|
rankdir: "LR",
|
|
19951
|
-
nodesep:
|
|
19952
|
-
ranksep:
|
|
20181
|
+
nodesep: 28,
|
|
20182
|
+
ranksep: 90
|
|
19953
20183
|
},
|
|
19954
20184
|
behaviors: [
|
|
19955
20185
|
"zoom-canvas",
|
|
@@ -20034,8 +20264,17 @@ function ac_theme$1(gobj, event, kw, src) {
|
|
|
20034
20264
|
let dark = kw && kw.theme ? kw.theme === "dark" : yui_is_dark();
|
|
20035
20265
|
try {
|
|
20036
20266
|
graph.setTheme(dark ? "dark" : "light");
|
|
20037
|
-
graph.setNode({ style: node_style(dark) });
|
|
20038
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);
|
|
20039
20278
|
graph.draw().catch((e) => {
|
|
20040
20279
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: schema graph redraw failed: ${e}`);
|
|
20041
20280
|
});
|
|
@@ -20100,6 +20339,58 @@ function register_c_yui_treedb_schema() {
|
|
|
20100
20339
|
return create_gclass$2(GCLASS_NAME$2);
|
|
20101
20340
|
}
|
|
20102
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
|
|
20103
20394
|
//#region node_modules/@babel/runtime/helpers/esm/typeof.js
|
|
20104
20395
|
function _typeof(o) {
|
|
20105
20396
|
"@babel/helpers - typeof";
|
|
@@ -47632,19 +47923,19 @@ function create_topic_node(gobj, desc, record) {
|
|
|
47632
47923
|
style.size = [116, 40];
|
|
47633
47924
|
style.dx = -58;
|
|
47634
47925
|
style.dy = -20;
|
|
47635
|
-
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);
|
|
47636
47927
|
} else if (node_treedb_type === "extended") {
|
|
47637
47928
|
node_graph_type = "html";
|
|
47638
47929
|
style.size = [144, 66];
|
|
47639
47930
|
style.dx = -72;
|
|
47640
47931
|
style.dy = -33;
|
|
47641
|
-
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);
|
|
47642
47933
|
} else {
|
|
47643
47934
|
node_graph_type = "html";
|
|
47644
47935
|
style.size = [172, 96];
|
|
47645
47936
|
style.dx = -86;
|
|
47646
47937
|
style.dy = -48;
|
|
47647
|
-
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);
|
|
47648
47939
|
}
|
|
47649
47940
|
let topic_props = priv._graph_properties[desc.topic_name];
|
|
47650
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;
|
|
@@ -47712,15 +48003,15 @@ function update_topic_node(gobj, desc, node_name, record) {
|
|
|
47712
48003
|
nodedata.data.record = record;
|
|
47713
48004
|
if (desc.node_treedb_type === "child") graph.updateNodeData([{
|
|
47714
48005
|
id: node_name,
|
|
47715
|
-
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) }
|
|
47716
48007
|
}]);
|
|
47717
48008
|
else if (desc.node_treedb_type === "extended") graph.updateNodeData([{
|
|
47718
48009
|
id: node_name,
|
|
47719
|
-
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) }
|
|
47720
48011
|
}]);
|
|
47721
48012
|
else if (desc.node_treedb_type === "hierarchical") graph.updateNodeData([{
|
|
47722
48013
|
id: node_name,
|
|
47723
|
-
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) }
|
|
47724
48015
|
}]);
|
|
47725
48016
|
} catch (e) {
|
|
47726
48017
|
(0, _yuneta_gobj_js.log_error)(e.message);
|
|
@@ -49627,7 +49918,7 @@ function show_node_popover(gobj) {
|
|
|
49627
49918
|
};
|
|
49628
49919
|
if (node_graph_type === "hierarchical") {
|
|
49629
49920
|
let record = nodeData.data.record || {};
|
|
49630
|
-
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);
|
|
49631
49922
|
}
|
|
49632
49923
|
graph.updateNodeData([{
|
|
49633
49924
|
id: node_id,
|
|
@@ -49667,7 +49958,7 @@ function show_node_popover(gobj) {
|
|
|
49667
49958
|
};
|
|
49668
49959
|
if (node_graph_type === "hierarchical") {
|
|
49669
49960
|
let record = nodeData.data.record || {};
|
|
49670
|
-
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);
|
|
49671
49962
|
}
|
|
49672
49963
|
graph.updateNodeData([{
|
|
49673
49964
|
id: node_id,
|
|
@@ -49768,15 +50059,15 @@ function refresh_html_nodes_theme(gobj, theme) {
|
|
|
49768
50059
|
let record = nd.data.record || {};
|
|
49769
50060
|
if (tt === "hierarchical") updates.push({
|
|
49770
50061
|
id: nodes[i].id,
|
|
49771
|
-
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) }
|
|
49772
50063
|
});
|
|
49773
50064
|
else if (tt === "child") updates.push({
|
|
49774
50065
|
id: nodes[i].id,
|
|
49775
|
-
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) }
|
|
49776
50067
|
});
|
|
49777
50068
|
else if (tt === "extended") updates.push({
|
|
49778
50069
|
id: nodes[i].id,
|
|
49779
|
-
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) }
|
|
49780
50071
|
});
|
|
49781
50072
|
}
|
|
49782
50073
|
if (updates.length > 0) graph.updateNodeData(updates);
|
|
@@ -49808,7 +50099,8 @@ function refresh_default_edges_theme(gobj, theme) {
|
|
|
49808
50099
|
* but lighter (1px border, no shadow, single line). The name is
|
|
49809
50100
|
* always legible (ellipsis + native title tooltip on overflow).
|
|
49810
50101
|
************************************************************/
|
|
49811
|
-
function build_chip_innerHTML(color, theme, icon,
|
|
50102
|
+
function build_chip_innerHTML(color, theme, icon, label, key) {
|
|
50103
|
+
let title = key || label;
|
|
49812
50104
|
let dark = theme === "dark";
|
|
49813
50105
|
let bg = dark ? `color-mix(in srgb, ${color} 30%, #2c3542)` : `color-mix(in srgb, ${color} 10%, ${dark ? "#1b2230" : "#ffffff"})`;
|
|
49814
50106
|
let border = dark ? `color-mix(in srgb, ${color} 85%, #ffffff)` : color;
|
|
@@ -49819,7 +50111,7 @@ function build_chip_innerHTML(color, theme, icon, id) {
|
|
|
49819
50111
|
margin-right: 6px; flex: 0 0 auto;
|
|
49820
50112
|
"/>`;
|
|
49821
50113
|
return `
|
|
49822
|
-
<div title="${(0, _yuneta_gobj_js.escapeHtml)(
|
|
50114
|
+
<div title="${(0, _yuneta_gobj_js.escapeHtml)(title)}" style="
|
|
49823
50115
|
box-sizing: border-box;
|
|
49824
50116
|
width: 100%;
|
|
49825
50117
|
height: 100%;
|
|
@@ -49836,7 +50128,7 @@ function build_chip_innerHTML(color, theme, icon, id) {
|
|
|
49836
50128
|
">${icon_html}<span style="
|
|
49837
50129
|
font-size: 12px; font-weight: 600; line-height: 1;
|
|
49838
50130
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
49839
|
-
">${(0, _yuneta_gobj_js.escapeHtml)(
|
|
50131
|
+
">${(0, _yuneta_gobj_js.escapeHtml)(label)}</span>
|
|
49840
50132
|
</div>
|
|
49841
50133
|
`;
|
|
49842
50134
|
}
|
|
@@ -49850,7 +50142,8 @@ function build_chip_innerHTML(color, theme, icon, id) {
|
|
|
49850
50142
|
* colour is kept (per-topic differentiation) but softened via
|
|
49851
50143
|
* color-mix instead of a harsh saturated fill. Theme-aware.
|
|
49852
50144
|
************************************************************/
|
|
49853
|
-
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;
|
|
49854
50147
|
let dark = theme === "dark";
|
|
49855
50148
|
let surface = dark ? "#1b2230" : "#ffffff";
|
|
49856
50149
|
let bg, border, border_style;
|
|
@@ -49880,7 +50173,7 @@ function build_node_innerHTML(color, theme, icon, id, topic_name, structural) {
|
|
|
49880
50173
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
49881
50174
|
">${(0, _yuneta_gobj_js.escapeHtml)(topic_name)}</div>`;
|
|
49882
50175
|
return `
|
|
49883
|
-
<div title="${(0, _yuneta_gobj_js.escapeHtml)(
|
|
50176
|
+
<div title="${(0, _yuneta_gobj_js.escapeHtml)(title)}" style="
|
|
49884
50177
|
box-sizing: border-box;
|
|
49885
50178
|
width: 100%;
|
|
49886
50179
|
height: 100%;
|
|
@@ -49903,7 +50196,7 @@ function build_node_innerHTML(color, theme, icon, id, topic_name, structural) {
|
|
|
49903
50196
|
max-width: 100%; overflow: hidden; text-overflow: ellipsis;
|
|
49904
50197
|
display: -webkit-box; -webkit-line-clamp: 2;
|
|
49905
50198
|
-webkit-box-orient: vertical; word-break: break-word;
|
|
49906
|
-
">${(0, _yuneta_gobj_js.escapeHtml)(
|
|
50199
|
+
">${(0, _yuneta_gobj_js.escapeHtml)(label)}</div>${sub_html}
|
|
49907
50200
|
</div>
|
|
49908
50201
|
`;
|
|
49909
50202
|
}
|
|
@@ -50124,7 +50417,7 @@ function apply_node_properties(gobj, node_id, fill, stroke, lineWidth, scope) {
|
|
|
50124
50417
|
};
|
|
50125
50418
|
if (nd.data.desc.node_treedb_type === "hierarchical") {
|
|
50126
50419
|
let record = nd.data.record || {};
|
|
50127
|
-
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);
|
|
50128
50421
|
}
|
|
50129
50422
|
updates.push({
|
|
50130
50423
|
id: nodes[i].id,
|