@yuneta/gobj-ui 7.23.186 → 7.23.188
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/dist/gobj-ui.cjs.js +146 -59
- package/dist/gobj-ui.es.js +146 -59
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +52 -16
- package/src/c_yui_schema_editor.js +3 -1
- package/src/c_yui_treedb_topics.js +81 -11
- package/src/treedb_node_label.js +50 -50
- package/src/treedb_node_label.test.js +57 -46
- package/src/yui_icons.css +9 -0
|
@@ -335,12 +335,19 @@ function build_ui(gobj)
|
|
|
335
335
|
}
|
|
336
336
|
}],
|
|
337
337
|
/* Landing view toggle: cards grid <-> schema graph
|
|
338
|
-
* (topics as nodes). Shown only on the landing.
|
|
338
|
+
* (topics as nodes). Shown only on the landing.
|
|
339
|
+
*
|
|
340
|
+
* The glyph is the draughtsman's compass, not the
|
|
341
|
+
* `hexagon-nodes` of the graph: the button one place
|
|
342
|
+
* to its left opens the graph of the DATA, and the
|
|
343
|
+
* two wore the same shape with only their labels
|
|
344
|
+
* telling them apart -- which on a narrow toolbar is
|
|
345
|
+
* nothing. A schema is the PLAN of the treedb. */
|
|
339
346
|
['button', {class: 'button TREEDB_LANDING_TOGGLE is-hidden',
|
|
340
347
|
title: t('schema graph'), 'aria-label': t('schema graph'),
|
|
341
348
|
'data-i18n-title': 'schema graph',
|
|
342
349
|
'data-i18n-aria-label': 'schema graph'}, [
|
|
343
|
-
['span', {class: 'icon'}, [yui_toolbar_icon('yi-
|
|
350
|
+
['span', {class: 'icon'}, [yui_toolbar_icon('yi-compass-drafting')]],
|
|
344
351
|
['span', {i18n: 'schema'}, 'schema']
|
|
345
352
|
], {
|
|
346
353
|
click: (evt) => {
|
|
@@ -348,6 +355,24 @@ function build_ui(gobj)
|
|
|
348
355
|
gobj_send_event(gobj, "EV_TOGGLE_LANDING_VIEW", {}, gobj);
|
|
349
356
|
}
|
|
350
357
|
}],
|
|
358
|
+
/* The schema as JSON -- the `descs` the view is drawing,
|
|
359
|
+
* which is what a person writing a schema literal, or
|
|
360
|
+
* chasing a flag that did not take, actually needs to
|
|
361
|
+
* read. Landing-only, like the toggle it stands next
|
|
362
|
+
* to; the `raw json` button further right is another
|
|
363
|
+
* thing entirely (the tranger's content). */
|
|
364
|
+
['button', {class: 'button TREEDB_SCHEMA_JSON_BTN is-hidden',
|
|
365
|
+
title: t('schema json'), 'aria-label': t('schema json'),
|
|
366
|
+
'data-i18n-title': 'schema json',
|
|
367
|
+
'data-i18n-aria-label': 'schema json'}, [
|
|
368
|
+
['span', {class: 'icon'}, [yui_toolbar_icon('yi-code')]],
|
|
369
|
+
['span', {i18n: 'schema json'}, 'schema json']
|
|
370
|
+
], {
|
|
371
|
+
click: (evt) => {
|
|
372
|
+
evt.stopPropagation();
|
|
373
|
+
gobj_send_event(gobj, "EV_OPEN_SCHEMA_JSON", {}, gobj);
|
|
374
|
+
}
|
|
375
|
+
}],
|
|
351
376
|
/* The backend this view browses. The tab that hosts this
|
|
352
377
|
* view is labelled with the TREEDB name, and the same
|
|
353
378
|
* treedb name lives on more than one node — two tabs
|
|
@@ -817,6 +842,7 @@ function show_topics_landing(gobj)
|
|
|
817
842
|
let $info = $container.querySelector(".TREEDB_TOPIC_INFO");
|
|
818
843
|
let $back = $container.querySelector(".TREEDB_TOPICS_BACK");
|
|
819
844
|
let $toggle = $container.querySelector(".TREEDB_LANDING_TOGGLE");
|
|
845
|
+
let $schema_json = $container.querySelector(".TREEDB_SCHEMA_JSON_BTN");
|
|
820
846
|
if($tabs) {
|
|
821
847
|
$tabs.classList.add("is-hidden");
|
|
822
848
|
}
|
|
@@ -835,6 +861,11 @@ function show_topics_landing(gobj)
|
|
|
835
861
|
$toggle.classList.remove("is-hidden"); /* the toggle lives on the landing */
|
|
836
862
|
$toggle.classList.toggle("is-primary", schema_mode);
|
|
837
863
|
}
|
|
864
|
+
if($schema_json) {
|
|
865
|
+
/* The schema's json is worth reading when the schema is what is
|
|
866
|
+
* on screen; on the cards grid it is one more button in the way. */
|
|
867
|
+
$schema_json.classList.toggle("is-hidden", !schema_mode);
|
|
868
|
+
}
|
|
838
869
|
if(schema_mode) {
|
|
839
870
|
if($landing) {
|
|
840
871
|
$landing.classList.add("is-hidden");
|
|
@@ -946,6 +977,7 @@ function show_topic_detail(gobj)
|
|
|
946
977
|
let $info = $container.querySelector(".TREEDB_TOPIC_INFO");
|
|
947
978
|
let $back = $container.querySelector(".TREEDB_TOPICS_BACK");
|
|
948
979
|
let $toggle = $container.querySelector(".TREEDB_LANDING_TOGGLE");
|
|
980
|
+
let $schema_json = $container.querySelector(".TREEDB_SCHEMA_JSON_BTN");
|
|
949
981
|
if($landing) {
|
|
950
982
|
$landing.classList.add("is-hidden");
|
|
951
983
|
}
|
|
@@ -955,6 +987,9 @@ function show_topic_detail(gobj)
|
|
|
955
987
|
if($info) {
|
|
956
988
|
$info.classList.add("is-hidden");
|
|
957
989
|
}
|
|
990
|
+
if($schema_json) {
|
|
991
|
+
$schema_json.classList.add("is-hidden");
|
|
992
|
+
}
|
|
958
993
|
if($toggle) {
|
|
959
994
|
$toggle.classList.add("is-hidden"); /* landing-only */
|
|
960
995
|
}
|
|
@@ -1010,12 +1045,16 @@ function show_topic_info(gobj, topic)
|
|
|
1010
1045
|
let $schema = $container.querySelector(".TREEDB_TOPICS_SCHEMA");
|
|
1011
1046
|
let $back = $container.querySelector(".TREEDB_TOPICS_BACK");
|
|
1012
1047
|
let $toggle = $container.querySelector(".TREEDB_LANDING_TOGGLE");
|
|
1048
|
+
let $schema_json = $container.querySelector(".TREEDB_SCHEMA_JSON_BTN");
|
|
1013
1049
|
if($landing) {
|
|
1014
1050
|
$landing.classList.add("is-hidden");
|
|
1015
1051
|
}
|
|
1016
1052
|
if($schema) {
|
|
1017
1053
|
$schema.classList.add("is-hidden");
|
|
1018
1054
|
}
|
|
1055
|
+
if($schema_json) {
|
|
1056
|
+
$schema_json.classList.add("is-hidden");
|
|
1057
|
+
}
|
|
1019
1058
|
if($toggle) {
|
|
1020
1059
|
$toggle.classList.add("is-hidden");
|
|
1021
1060
|
}
|
|
@@ -1307,7 +1346,7 @@ function register_sub_routes(gobj)
|
|
|
1307
1346
|
let nodes = [];
|
|
1308
1347
|
if(is_object(gobj_read_attr(gobj, "landing_routes"))) {
|
|
1309
1348
|
nodes.push({route: base + "/schema", label: "schema",
|
|
1310
|
-
icon: "yi-
|
|
1349
|
+
icon: "yi-compass-drafting", gclass: "C_YUI_TREEDB_SCHEMA"});
|
|
1311
1350
|
}
|
|
1312
1351
|
if(is_object(descs)) {
|
|
1313
1352
|
for(let topic of Object.keys(descs)) {
|
|
@@ -1655,13 +1694,18 @@ function is_mobile()
|
|
|
1655
1694
|
* whole service (lazy drill). CHILD model: the viewer publishes
|
|
1656
1695
|
* EV_EXPAND_PATH to us.
|
|
1657
1696
|
************************************************************/
|
|
1658
|
-
function open_json_viewer(gobj)
|
|
1697
|
+
function open_json_viewer(gobj, opts)
|
|
1659
1698
|
{
|
|
1660
1699
|
let priv = gobj.priv;
|
|
1700
|
+
let schema = !!(opts && opts.schema);
|
|
1661
1701
|
|
|
1662
|
-
/* Already open: just re-fetch.
|
|
1702
|
+
/* Already open: just re-fetch. The schema needs no fetch -- it is
|
|
1703
|
+
* the `descs` this view already holds -- so a second click on a
|
|
1704
|
+
* viewer that is already showing it does nothing. */
|
|
1663
1705
|
if(priv.json_win || priv.json_modal) {
|
|
1664
|
-
|
|
1706
|
+
if(!schema) {
|
|
1707
|
+
request_print_tranger(gobj, "");
|
|
1708
|
+
}
|
|
1665
1709
|
return;
|
|
1666
1710
|
}
|
|
1667
1711
|
|
|
@@ -1681,7 +1725,11 @@ function open_json_viewer(gobj)
|
|
|
1681
1725
|
/* No `title`: the host titles it — the window's title bar on
|
|
1682
1726
|
* desktop, the dialog's header on mobile. The viewer's own
|
|
1683
1727
|
* title would land INSIDE that host, doubling it. */
|
|
1684
|
-
subscriber: gobj
|
|
1728
|
+
subscriber: gobj, /* publishes EV_EXPAND_PATH to us */
|
|
1729
|
+
/* The schema is here already and it is small: it goes in
|
|
1730
|
+
* whole, and no drill-down happens because nothing is
|
|
1731
|
+
* collapsed. */
|
|
1732
|
+
json_data: schema? gobj_read_attr(gobj, "descs") : null
|
|
1685
1733
|
},
|
|
1686
1734
|
gobj
|
|
1687
1735
|
);
|
|
@@ -1703,7 +1751,7 @@ function open_json_viewer(gobj)
|
|
|
1703
1751
|
dialog: true,
|
|
1704
1752
|
logical_class: "TREEDB_JSON_SHEET",
|
|
1705
1753
|
title_prefix: priv.treedb_name,
|
|
1706
|
-
title: "raw json",
|
|
1754
|
+
title: schema? "schema json" : "raw json",
|
|
1707
1755
|
t: t,
|
|
1708
1756
|
on_close: () => {
|
|
1709
1757
|
if(gobj_is_destroying(gobj)) {
|
|
@@ -1733,8 +1781,8 @@ function open_json_viewer(gobj)
|
|
|
1733
1781
|
height: 620,
|
|
1734
1782
|
logical_class: "TREEDB_JSON_WINDOW",
|
|
1735
1783
|
title_prefix: priv.treedb_name,
|
|
1736
|
-
title: "raw json",
|
|
1737
|
-
icon: "yi-eye",
|
|
1784
|
+
title: schema? "schema json" : "raw json",
|
|
1785
|
+
icon: schema? "yi-code" : "yi-eye",
|
|
1738
1786
|
body: $box,
|
|
1739
1787
|
manager: null,
|
|
1740
1788
|
on_close: () => {
|
|
@@ -1754,7 +1802,9 @@ function open_json_viewer(gobj)
|
|
|
1754
1802
|
gobj_start(priv.json_win);
|
|
1755
1803
|
}
|
|
1756
1804
|
|
|
1757
|
-
|
|
1805
|
+
if(!schema) {
|
|
1806
|
+
request_print_tranger(gobj, "");
|
|
1807
|
+
}
|
|
1758
1808
|
}
|
|
1759
1809
|
|
|
1760
1810
|
/************************************************************
|
|
@@ -2718,6 +2768,24 @@ function ac_open_json(gobj, event, kw, src)
|
|
|
2718
2768
|
return 0;
|
|
2719
2769
|
}
|
|
2720
2770
|
|
|
2771
|
+
/********************************************
|
|
2772
|
+
* The schema, as the json it is: the `descs` the schema graph is
|
|
2773
|
+
* drawing. Same viewer and same host as the tranger's raw json --
|
|
2774
|
+
* one at a time, so it closes whatever was open first.
|
|
2775
|
+
********************************************/
|
|
2776
|
+
function ac_open_schema_json(gobj, event, kw, src)
|
|
2777
|
+
{
|
|
2778
|
+
if(!is_object(gobj_read_attr(gobj, "descs"))) {
|
|
2779
|
+
/* Not reachable by hand -- the button only exists while the
|
|
2780
|
+
* schema is on screen, which needs the descs -- so this is a
|
|
2781
|
+
* broken caller, not something to tell the reader about. */
|
|
2782
|
+
log_error(`${gobj_short_name(gobj)}: schema json with no descs`);
|
|
2783
|
+
return -1;
|
|
2784
|
+
}
|
|
2785
|
+
open_json_viewer(gobj, {schema: true});
|
|
2786
|
+
return 0;
|
|
2787
|
+
}
|
|
2788
|
+
|
|
2721
2789
|
/********************************************
|
|
2722
2790
|
* Open the graph where the reader left it: its last visited
|
|
2723
2791
|
* route under the graph's base -- `<graph>/<topic>` when a topic
|
|
@@ -2823,6 +2891,7 @@ function create_gclass(gclass_name)
|
|
|
2823
2891
|
["EV_DELETE_RECORD", ac_delete_record, null],
|
|
2824
2892
|
["EV_REFRESH_TOPIC", ac_refresh_topic, null],
|
|
2825
2893
|
["EV_OPEN_JSON", ac_open_json, null],
|
|
2894
|
+
["EV_OPEN_SCHEMA_JSON", ac_open_schema_json, null],
|
|
2826
2895
|
["EV_OPEN_GRAPH", ac_open_graph, null],
|
|
2827
2896
|
["EV_EXPAND_PATH", ac_json_expand_path, null],
|
|
2828
2897
|
["EV_JSON_CLOSED", ac_json_closed, null],
|
|
@@ -2857,6 +2926,7 @@ function create_gclass(gclass_name)
|
|
|
2857
2926
|
event_flag_t.EVF_NO_WARN_SUBS],
|
|
2858
2927
|
["EV_REFRESH_TOPIC", 0],
|
|
2859
2928
|
["EV_OPEN_JSON", 0],
|
|
2929
|
+
["EV_OPEN_SCHEMA_JSON", 0],
|
|
2860
2930
|
["EV_OPEN_GRAPH", 0],
|
|
2861
2931
|
["EV_EXPAND_PATH", 0],
|
|
2862
2932
|
["EV_JSON_CLOSED", 0],
|
package/src/treedb_node_label.js
CHANGED
|
@@ -2,78 +2,78 @@
|
|
|
2
2
|
* treedb_node_label.js
|
|
3
3
|
*
|
|
4
4
|
* Pure, testable logic behind the label of a node in the treedb
|
|
5
|
-
* graph: WHAT A RECORD IS CALLED
|
|
6
|
-
*
|
|
7
|
-
* no DOM and no G6.
|
|
5
|
+
* graph: WHAT A RECORD IS CALLED. Kept out of the gclass so it can
|
|
6
|
+
* be unit-tested with no DOM and no G6.
|
|
8
7
|
*
|
|
9
8
|
* Copyright (c) 2026, ArtGins.
|
|
10
9
|
* All Rights Reserved.
|
|
11
10
|
***********************************************************************/
|
|
12
11
|
|
|
12
|
+
const SEP = " · "; /* the middle dot the shell titles use */
|
|
13
|
+
|
|
13
14
|
/************************************************************
|
|
14
|
-
* What a node is CALLED,
|
|
15
|
-
*
|
|
15
|
+
* What a node is CALLED: **its id, and the secondary keys it
|
|
16
|
+
* carries**.
|
|
16
17
|
*
|
|
17
|
-
* A
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* the graph read "181", "225", "193" while they were keyed by
|
|
26
|
-
* rowid, and reads the whole path now that they are
|
|
27
|
-
* qualified.
|
|
18
|
+
* A record is one thing and an INSTANCE of it is another: the
|
|
19
|
+
* topic keys the record by `id` and the instance by the
|
|
20
|
+
* columns it declares in `pkey2s`. A card that shows one
|
|
21
|
+
* without the other is a card that cannot be identified --
|
|
22
|
+
* and it used to show one INSTEAD of the other, so the yunos
|
|
23
|
+
* of an agent read `7.23.0-1`, `7.23.0-1`, `7.23.0-1` (the
|
|
24
|
+
* release, which they share) and never said which yuno each
|
|
25
|
+
* one was, while a `configurations` card read `1`.
|
|
28
26
|
*
|
|
29
|
-
*
|
|
27
|
+
* It came from the opposite case, and that one still works:
|
|
28
|
+
* the `topics` and `cols` of treedb_system_schema are keyed
|
|
29
|
+
* by a rowid, so the card said "181" and the name lived in
|
|
30
|
+
* the pkey2. Now it says both -- `181 · yuno_role` -- which
|
|
31
|
+
* is what the record is: that name, under that key.
|
|
30
32
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
33
|
+
* Rules:
|
|
34
|
+
* - the id always opens the label;
|
|
35
|
+
* - every pkey2 the record carries follows it, in the
|
|
36
|
+
* order the topic declares them, separated by `·`;
|
|
37
|
+
* - a pkey2 whose value is empty, absent or equal to the
|
|
38
|
+
* id adds nothing;
|
|
39
|
+
* - a desc with no `pkey2s` (an older node's schema
|
|
40
|
+
* included) gives the bare id.
|
|
34
41
|
************************************************************/
|
|
35
42
|
export function node_label(desc, record)
|
|
36
43
|
{
|
|
37
|
-
/* treedb stores every record under `id
|
|
38
|
-
* tranger2_create_topic
|
|
39
|
-
* are read from whatever column the desc names as the pkey. */
|
|
44
|
+
/* treedb stores every record under `id`: the pkey name is fixed in
|
|
45
|
+
* tranger2_create_topic, whatever the desc calls it. */
|
|
40
46
|
let id = record.id;
|
|
41
47
|
|
|
42
|
-
let
|
|
43
|
-
if(Array.isArray(desc.cols)) {
|
|
44
|
-
for(let col of desc.cols) {
|
|
45
|
-
if(col && col.id === (desc.pkey || "id")) {
|
|
46
|
-
id_col = col;
|
|
47
|
-
break;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
if(!id_col || !Array.isArray(id_col.flag)) {
|
|
52
|
-
return id;
|
|
53
|
-
}
|
|
54
|
-
if(id_col.flag.indexOf("rowid") < 0 &&
|
|
55
|
-
id_col.flag.indexOf("uuid") < 0 &&
|
|
56
|
-
id_col.flag.indexOf("qualified") < 0
|
|
57
|
-
) {
|
|
58
|
-
return id;
|
|
59
|
-
}
|
|
60
|
-
|
|
48
|
+
let pkey2s = desc? desc.pkey2s : null;
|
|
61
49
|
/* `pkey2s` is a list in the desc, but the schema literal may
|
|
62
|
-
* declare it as a bare string
|
|
63
|
-
let pkey2s = desc.pkey2s;
|
|
50
|
+
* declare it as a bare string -- take either. */
|
|
64
51
|
if(typeof pkey2s === "string") {
|
|
65
52
|
pkey2s = pkey2s? [pkey2s] : [];
|
|
66
53
|
}
|
|
67
|
-
if(!Array.isArray(pkey2s)) {
|
|
54
|
+
if(!Array.isArray(pkey2s) || pkey2s.length === 0) {
|
|
68
55
|
return id;
|
|
69
56
|
}
|
|
57
|
+
|
|
58
|
+
let parts = [];
|
|
70
59
|
for(let name of pkey2s) {
|
|
60
|
+
if(!name) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
71
63
|
let value = record[name];
|
|
72
|
-
if(typeof value === "
|
|
73
|
-
|
|
64
|
+
if(typeof value === "number") {
|
|
65
|
+
value = String(value);
|
|
66
|
+
}
|
|
67
|
+
if(typeof value !== "string" || value.length === 0) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if(value === String(id)) {
|
|
71
|
+
continue; /* the same thing twice says nothing */
|
|
74
72
|
}
|
|
73
|
+
parts.push(value);
|
|
75
74
|
}
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
if(parts.length === 0) {
|
|
76
|
+
return id;
|
|
77
|
+
}
|
|
78
|
+
return [id, ...parts].join(SEP);
|
|
78
79
|
}
|
|
79
|
-
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/***********************************************************************
|
|
2
2
|
* treedb_node_label.test.js
|
|
3
3
|
*
|
|
4
|
-
* The label of a treedb graph node:
|
|
5
|
-
* record
|
|
4
|
+
* The label of a treedb graph node: its id, and the secondary
|
|
5
|
+
* keys it carries. A record is one thing and an INSTANCE of it
|
|
6
|
+
* another, and a card that shows one without the other cannot be
|
|
7
|
+
* identified.
|
|
6
8
|
*
|
|
7
9
|
* Copyright (c) 2026, ArtGins.
|
|
8
10
|
* All Rights Reserved.
|
|
@@ -35,44 +37,67 @@ const REALMS_DESC = {
|
|
|
35
37
|
};
|
|
36
38
|
|
|
37
39
|
describe("node_label", () => {
|
|
38
|
-
|
|
40
|
+
const DOT = " \u00b7 ";
|
|
41
|
+
|
|
42
|
+
it("says the id AND the secondary key that names the record", () => {
|
|
39
43
|
expect(node_label(COLS_DESC, {id: "181", value: "yuno_role"}))
|
|
40
|
-
.toBe("yuno_role");
|
|
44
|
+
.toBe("181" + DOT + "yuno_role");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("says the id AND the instance: the case that brought it", () => {
|
|
48
|
+
/* Three yunos of one agent, all of release 7.23.0-1: the cards
|
|
49
|
+
* read `7.23.0-1` three times and never said which yuno. */
|
|
50
|
+
let yunos = {
|
|
51
|
+
topic_name: "yunos",
|
|
52
|
+
pkey: "id",
|
|
53
|
+
pkey2s: ["yuno_release"],
|
|
54
|
+
cols: [
|
|
55
|
+
{id: "id", type: "string", flag: ["persistent", "rowid"]},
|
|
56
|
+
{id: "yuno_release", type: "string", flag: ["persistent"]},
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
expect(node_label(yunos, {id: "1", yuno_release: "7.23.0-1"}))
|
|
60
|
+
.toBe("1" + DOT + "7.23.0-1");
|
|
61
|
+
expect(node_label(yunos, {id: "1600", yuno_release: "1.8.1.0-2"}))
|
|
62
|
+
.toBe("1600" + DOT + "1.8.1.0-2");
|
|
41
63
|
});
|
|
42
64
|
|
|
43
|
-
it("
|
|
65
|
+
it("gives the bare id when the topic declares no secondary key", () => {
|
|
44
66
|
expect(node_label(REALMS_DESC, {id: "artgins.utilities.all", realm_name: "all"}))
|
|
45
67
|
.toBe("artgins.utilities.all");
|
|
46
68
|
});
|
|
47
69
|
|
|
48
70
|
it("accepts a pkey2s declared as a bare string", () => {
|
|
49
71
|
let desc = {...COLS_DESC, pkey2s: "value"};
|
|
50
|
-
expect(node_label(desc, {id: "181", value: "yuno_role"}))
|
|
72
|
+
expect(node_label(desc, {id: "181", value: "yuno_role"}))
|
|
73
|
+
.toBe("181" + DOT + "yuno_role");
|
|
51
74
|
});
|
|
52
75
|
|
|
53
|
-
it("
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
76
|
+
it("does not care what the id column is flagged", () => {
|
|
77
|
+
/* rowid, uuid, qualified or nothing at all: the id is shown
|
|
78
|
+
* either way, and the flags decide nothing here any more. */
|
|
79
|
+
for(let flag of [["persistent", "uuid"], ["persistent", "qualified"], ["persistent"]]) {
|
|
80
|
+
let desc = {
|
|
81
|
+
...COLS_DESC,
|
|
82
|
+
cols: [
|
|
83
|
+
{id: "id", type: "string", flag: flag},
|
|
84
|
+
{id: "value", type: "string", flag: ["persistent", "required"]},
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
expect(node_label(desc, {id: "k", value: "named"})).toBe("k" + DOT + "named");
|
|
88
|
+
}
|
|
65
89
|
});
|
|
66
90
|
|
|
67
|
-
it("
|
|
68
|
-
let desc = {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
};
|
|
75
|
-
expect(node_label(
|
|
91
|
+
it("says every secondary key the topic declares, in its order", () => {
|
|
92
|
+
let desc = {topic_name: "x", pkey: "id", pkey2s: ["a", "b"], cols: []};
|
|
93
|
+
expect(node_label(desc, {id: "7", a: "one", b: "two"}))
|
|
94
|
+
.toBe("7" + DOT + "one" + DOT + "two");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("skips a secondary key that is empty, absent or the id again", () => {
|
|
98
|
+
expect(node_label(COLS_DESC, {id: "181", value: ""})).toBe("181");
|
|
99
|
+
expect(node_label(COLS_DESC, {id: "181"})).toBe("181");
|
|
100
|
+
expect(node_label(COLS_DESC, {id: "181", value: "181"})).toBe("181");
|
|
76
101
|
});
|
|
77
102
|
|
|
78
103
|
it("falls back to the id when the desc carries no pkey2s (older node)", () => {
|
|
@@ -80,27 +105,13 @@ describe("node_label", () => {
|
|
|
80
105
|
expect(node_label(desc, {id: "181", value: "yuno_role"})).toBe("181");
|
|
81
106
|
});
|
|
82
107
|
|
|
83
|
-
it("
|
|
84
|
-
expect(node_label(COLS_DESC, {id: "
|
|
85
|
-
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it("honours a pkey that is not called 'id'", () => {
|
|
89
|
-
let desc = {
|
|
90
|
-
topic_name: "x",
|
|
91
|
-
pkey: "key",
|
|
92
|
-
pkey2s: ["name"],
|
|
93
|
-
cols: [
|
|
94
|
-
{id: "key", type: "string", flag: ["persistent", "rowid"]},
|
|
95
|
-
{id: "name", type: "string", flag: ["persistent", "required"]},
|
|
96
|
-
/* A col called `id` that is NOT the pkey must not decide. */
|
|
97
|
-
{id: "id", type: "string", flag: ["persistent"]},
|
|
98
|
-
],
|
|
99
|
-
};
|
|
100
|
-
expect(node_label(desc, {id: "7", key: "7", name: "seven"})).toBe("seven");
|
|
108
|
+
it("takes a numeric secondary key as the text it is", () => {
|
|
109
|
+
expect(node_label(COLS_DESC, {id: "emailsender.artgins", value: 1}))
|
|
110
|
+
.toBe("emailsender.artgins" + DOT + "1");
|
|
101
111
|
});
|
|
102
112
|
|
|
103
|
-
it("survives a desc with no cols", () => {
|
|
113
|
+
it("survives a desc with no cols, and no desc at all", () => {
|
|
104
114
|
expect(node_label({topic_name: "x", pkey: "id"}, {id: "42"})).toBe("42");
|
|
115
|
+
expect(node_label(null, {id: "42"})).toBe("42");
|
|
105
116
|
});
|
|
106
117
|
});
|
package/src/yui_icons.css
CHANGED
|
@@ -176,6 +176,15 @@
|
|
|
176
176
|
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 576 512'%3E%3Cpath d='M41-24.9c-9.4-9.4-24.6-9.4-33.9 0S-2.3-.3 7 9.1l528 528c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-96.4-96.4c2.7-2.4 5.4-4.8 8-7.2 46.8-43.5 78.1-95.4 93-131.1 3.3-7.9 3.3-16.7 0-24.6-14.9-35.7-46.2-87.7-93-131.1-47.1-43.7-111.8-80.6-192.6-80.6-56.8 0-105.6 18.2-146 44.2L41-24.9zM204.5 138.7c23.5-16.8 52.4-26.7 83.5-26.7 79.5 0 144 64.5 144 144 0 31.1-9.9 59.9-26.7 83.5l-34.7-34.7c12.7-21.4 17-47.7 10.1-73.7-13.7-51.2-66.4-81.6-117.6-67.9-8.6 2.3-16.7 5.7-24 10l-34.7-34.7zM325.3 395.1c-11.9 3.2-24.4 4.9-37.3 4.9-79.5 0-144-64.5-144-144 0-12.9 1.7-25.4 4.9-37.3L69.4 139.2c-32.6 36.8-55 75.8-66.9 104.5-3.3 7.9-3.3 16.7 0 24.6 14.9 35.7 46.2 87.7 93 131.1 47.1 43.7 111.8 80.6 192.6 80.6 37.3 0 71.2-7.9 101.5-20.6l-64.2-64.2z'/%3E%3C/svg%3E");
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
/* The SCHEMA of a treedb -- its plan, as against the `hexagon-nodes`
|
|
180
|
+
* of the DATA graph. The two sat on the same glyph in the same
|
|
181
|
+
* toolbar, one button apart, and nothing but the label told them
|
|
182
|
+
* apart. */
|
|
183
|
+
.yi-compass-drafting::before {
|
|
184
|
+
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M99.3 256.1l69.4-119.9c-5.6-12.2-8.8-25.8-8.8-40.2 0-53 43-96 96-96s96 43 96 96c0 14.3-3.1 27.9-8.8 40.2l44.4 76.7c-23.1 26-53.7 45.1-88.4 53.8L256 191.9 187.9 309.5c21.5 6.8 44.3 10.5 68.1 10.5 70.7 0 133.8-32.7 174.9-84 11.1-13.8 31.2-16 45-5s16 31.2 5 45c-52.7 65.8-133.9 108-224.8 108-35.4 0-69.4-6.4-100.7-18.1L98.7 463.7C94 471.8 87 478.4 78.6 482.6L23.2 510.3c-5 2.5-10.9 2.2-15.6-.7S0 501.5 0 496l0-55.4c0-8.4 2.2-16.7 6.5-24.1l60-103.7c-12.8-11.2-24.6-23.5-35.3-36.8-11.1-13.8-8.8-33.9 5-45s33.9-8.8 45 5c5.7 7.1 11.8 13.8 18.2 20.1zM381.1 407.9c32.5-13 62.4-31 88.9-52.9l35.6 61.5c4.2 7.3 6.5 15.6 6.5 24.1l0 55.4c0 5.5-2.9 10.7-7.6 13.6s-10.6 3.2-15.6 .7l-55.4-27.7c-8.4-4.2-15.4-10.8-20.1-18.9l-32.3-55.8zM256 128a32 32 0 1 0 0-64 32 32 0 1 0 0 64z'/%3E%3C/svg%3E");
|
|
185
|
+
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M99.3 256.1l69.4-119.9c-5.6-12.2-8.8-25.8-8.8-40.2 0-53 43-96 96-96s96 43 96 96c0 14.3-3.1 27.9-8.8 40.2l44.4 76.7c-23.1 26-53.7 45.1-88.4 53.8L256 191.9 187.9 309.5c21.5 6.8 44.3 10.5 68.1 10.5 70.7 0 133.8-32.7 174.9-84 11.1-13.8 31.2-16 45-5s16 31.2 5 45c-52.7 65.8-133.9 108-224.8 108-35.4 0-69.4-6.4-100.7-18.1L98.7 463.7C94 471.8 87 478.4 78.6 482.6L23.2 510.3c-5 2.5-10.9 2.2-15.6-.7S0 501.5 0 496l0-55.4c0-8.4 2.2-16.7 6.5-24.1l60-103.7c-12.8-11.2-24.6-23.5-35.3-36.8-11.1-13.8-8.8-33.9 5-45s33.9-8.8 45 5c5.7 7.1 11.8 13.8 18.2 20.1zM381.1 407.9c32.5-13 62.4-31 88.9-52.9l35.6 61.5c4.2 7.3 6.5 15.6 6.5 24.1l0 55.4c0 5.5-2.9 10.7-7.6 13.6s-10.6 3.2-15.6 .7l-55.4-27.7c-8.4-4.2-15.4-10.8-20.1-18.9l-32.3-55.8zM256 128a32 32 0 1 0 0-64 32 32 0 1 0 0 64z'/%3E%3C/svg%3E");
|
|
186
|
+
}
|
|
187
|
+
|
|
179
188
|
.yi-hexagon-nodes::before {
|
|
180
189
|
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3E%3Cpath d='M248 106.6c18.9-9 32-28.3 32-50.6c0-30.9-25.1-56-56-56s-56 25.1-56 56c0 22.3 13.1 41.6 32 50.6l0 98.8c-2.8 1.3-5.5 2.9-8 4.7l-80.1-45.8c1.6-20.8-8.6-41.6-27.9-52.8C57.2 96 23 105.2 7.5 132S1.2 193 28 208.5c1.3 .8 2.6 1.5 4 2.1l0 90.8c-1.3 .6-2.7 1.3-4 2.1C1.2 319-8 353.2 7.5 380S57.2 416 84 400.5c19.3-11.1 29.4-32 27.8-52.8l50.5-28.9c-11.5-11.2-19.9-25.6-23.8-41.7L88 306.1c-2.6-1.8-5.2-3.3-8-4.7l0-90.8c2.8-1.3 5.5-2.9 8-4.7l80.1 45.8c-.1 1.4-.2 2.8-.2 4.3c0 22.3 13.1 41.6 32 50.6l0 98.8c-18.9 9-32 28.3-32 50.6c0 30.9 25.1 56 56 56s56-25.1 56-56c0-22.3-13.1-41.6-32-50.6l0-98.8c2.8-1.3 5.5-2.9 8-4.7l80.1 45.8c-1.6 20.8 8.6 41.6 27.8 52.8c26.8 15.5 61 6.3 76.5-20.5s6.3-61-20.5-76.5c-1.3-.8-2.7-1.5-4-2.1l0-90.8c1.4-.6 2.7-1.3 4-2.1c26.8-15.5 36-49.7 20.5-76.5S390.8 96 364 111.5c-19.3 11.1-29.4 32-27.8 52.8l-50.6 28.9c11.5 11.2 19.9 25.6 23.8 41.7L360 205.9c2.6 1.8 5.2 3.3 8 4.7l0 90.8c-2.8 1.3-5.5 2.9-8 4.6l-80.1-45.8c.1-1.4 .2-2.8 .2-4.3c0-22.3-13.1-41.6-32-50.6l0-98.8z'/%3E%3C/svg%3E");
|
|
181
190
|
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3E%3Cpath d='M248 106.6c18.9-9 32-28.3 32-50.6c0-30.9-25.1-56-56-56s-56 25.1-56 56c0 22.3 13.1 41.6 32 50.6l0 98.8c-2.8 1.3-5.5 2.9-8 4.7l-80.1-45.8c1.6-20.8-8.6-41.6-27.9-52.8C57.2 96 23 105.2 7.5 132S1.2 193 28 208.5c1.3 .8 2.6 1.5 4 2.1l0 90.8c-1.3 .6-2.7 1.3-4 2.1C1.2 319-8 353.2 7.5 380S57.2 416 84 400.5c19.3-11.1 29.4-32 27.8-52.8l50.5-28.9c-11.5-11.2-19.9-25.6-23.8-41.7L88 306.1c-2.6-1.8-5.2-3.3-8-4.7l0-90.8c2.8-1.3 5.5-2.9 8-4.7l80.1 45.8c-.1 1.4-.2 2.8-.2 4.3c0 22.3 13.1 41.6 32 50.6l0 98.8c-18.9 9-32 28.3-32 50.6c0 30.9 25.1 56 56 56s56-25.1 56-56c0-22.3-13.1-41.6-32-50.6l0-98.8c2.8-1.3 5.5-2.9 8-4.7l80.1 45.8c-1.6 20.8 8.6 41.6 27.8 52.8c26.8 15.5 61 6.3 76.5-20.5s6.3-61-20.5-76.5c-1.3-.8-2.7-1.5-4-2.1l0-90.8c1.4-.6 2.7-1.3 4-2.1c26.8-15.5 36-49.7 20.5-76.5S390.8 96 364 111.5c-19.3 11.1-29.4 32-27.8 52.8l-50.6 28.9c11.5 11.2 19.9 25.6 23.8 41.7L360 205.9c2.6 1.8 5.2 3.3 8 4.7l0 90.8c-2.8 1.3-5.5 2.9-8 4.6l-80.1-45.8c.1-1.4 .2-2.8 .2-4.3c0-22.3-13.1-41.6-32-50.6l0-98.8z'/%3E%3C/svg%3E");
|