@yuneta/gobj-ui 7.23.42 → 7.23.43
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 +46 -7
- package/dist/gobj-ui.es.js +46 -7
- package/package.json +1 -1
- package/src/c_yui_schema_editor.js +68 -11
- package/src/schema_version_bump.test.js +92 -0
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -62151,18 +62151,57 @@ function remote_command(gobj, command, kw) {
|
|
|
62151
62151
|
return 0;
|
|
62152
62152
|
}
|
|
62153
62153
|
/***************************************************************
|
|
62154
|
-
* The three answers are in: build the schema
|
|
62155
|
-
*
|
|
62156
|
-
*
|
|
62157
|
-
*
|
|
62154
|
+
* The three answers are in: build the schema.
|
|
62155
|
+
*
|
|
62156
|
+
* IT DOES NOT TOUCH THE BASELINE, and that is the whole point.
|
|
62157
|
+
* This runs again on the patch after EVERY write, so a baseline
|
|
62158
|
+
* taken here was re-taken as the version the write had just
|
|
62159
|
+
* raised -- and "written, and its version has not moved" then
|
|
62160
|
+
* read TRUE for a topic whose version had just moved.
|
|
62161
|
+
*
|
|
62162
|
+
* The banner that says so offers a Raise button, which wrote
|
|
62163
|
+
* another version, which was measured against itself again: the
|
|
62164
|
+
* banner came back, every time, and could not be dismissed. One
|
|
62165
|
+
* operator pressed it thirty-three times on one column delete.
|
|
62166
|
+
* It is why schema versions climbed by tens with the schema
|
|
62167
|
+
* unchanged.
|
|
62168
|
+
*
|
|
62169
|
+
* See start_measuring(): the baseline belongs to the LOAD, the
|
|
62170
|
+
* same reason `order_undo` was moved out of here before it.
|
|
62158
62171
|
***************************************************************/
|
|
62159
62172
|
function build_model(gobj) {
|
|
62160
62173
|
let priv = gobj.priv;
|
|
62161
62174
|
priv.model = build_schema_model(priv.records);
|
|
62175
|
+
}
|
|
62176
|
+
/***************************************************************
|
|
62177
|
+
* From here on, "did this session change it?" has an answer.
|
|
62178
|
+
*
|
|
62179
|
+
* Called ONLY when records arrive from the store: that is what a
|
|
62180
|
+
* measurement of "changed since" can be measured against. Both
|
|
62181
|
+
* halves reset together -- a baseline without its `written` is
|
|
62182
|
+
* the same false positive from the other side, since every
|
|
62183
|
+
* version equals a baseline just taken.
|
|
62184
|
+
***************************************************************/
|
|
62185
|
+
function start_measuring(gobj) {
|
|
62186
|
+
let priv = gobj.priv;
|
|
62162
62187
|
priv.baseline = {};
|
|
62188
|
+
priv.written = {};
|
|
62189
|
+
if (!priv.model) return;
|
|
62163
62190
|
for (let treedb of priv.model.treedbs) for (let topic of treedb.topics) priv.baseline[topic.id] = topic.topic_version;
|
|
62164
62191
|
}
|
|
62165
62192
|
/***************************************************************
|
|
62193
|
+
* "This topic was written and its version did not move."
|
|
62194
|
+
*
|
|
62195
|
+
* ONE predicate, because it is asked in two places -- the topic
|
|
62196
|
+
* list draws a chip with it and the column view draws a banner --
|
|
62197
|
+
* and two copies of a rule is how they drift.
|
|
62198
|
+
***************************************************************/
|
|
62199
|
+
function needs_version_bump(written, baseline, topic) {
|
|
62200
|
+
if (!topic || !written || !baseline) return false;
|
|
62201
|
+
if (!written[topic.id]) return false;
|
|
62202
|
+
return String(baseline[topic.id]) === String(topic.topic_version);
|
|
62203
|
+
}
|
|
62204
|
+
/***************************************************************
|
|
62166
62205
|
* Say what the whole store would be refused for.
|
|
62167
62206
|
*
|
|
62168
62207
|
* Not for this view — it has a button for that — but for
|
|
@@ -62602,7 +62641,7 @@ function render_topics(gobj, $body) {
|
|
|
62602
62641
|
let twice = repeated_names(treedb.topics);
|
|
62603
62642
|
let $rows = [];
|
|
62604
62643
|
for (let topic of treedb.topics) {
|
|
62605
|
-
let pending = priv.written
|
|
62644
|
+
let pending = needs_version_bump(priv.written, priv.baseline, topic);
|
|
62606
62645
|
let ambiguous = !!twice[topic.name];
|
|
62607
62646
|
let address = ambiguous ? topic.id : topic.name;
|
|
62608
62647
|
let $actions = [];
|
|
@@ -62911,8 +62950,7 @@ function render_columns(gobj, $body) {
|
|
|
62911
62950
|
***************************************************************/
|
|
62912
62951
|
function version_banner(gobj, topic) {
|
|
62913
62952
|
let priv = gobj.priv;
|
|
62914
|
-
if (!priv.written
|
|
62915
|
-
if (String(priv.baseline[topic.id]) !== String(topic.topic_version)) return null;
|
|
62953
|
+
if (!needs_version_bump(priv.written, priv.baseline, topic)) return null;
|
|
62916
62954
|
if (is_readonly(gobj)) return null;
|
|
62917
62955
|
let $banner = (0, _yuneta_gobj_js.createElement2)([
|
|
62918
62956
|
"div",
|
|
@@ -64478,6 +64516,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
64478
64516
|
}
|
|
64479
64517
|
priv.order_undo = {};
|
|
64480
64518
|
build_model(gobj);
|
|
64519
|
+
start_measuring(gobj);
|
|
64481
64520
|
return go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
|
|
64482
64521
|
}
|
|
64483
64522
|
if (command === "update-node" || command === "delete-node") {
|
package/dist/gobj-ui.es.js
CHANGED
|
@@ -62146,18 +62146,57 @@ function remote_command(gobj, command, kw) {
|
|
|
62146
62146
|
return 0;
|
|
62147
62147
|
}
|
|
62148
62148
|
/***************************************************************
|
|
62149
|
-
* The three answers are in: build the schema
|
|
62150
|
-
*
|
|
62151
|
-
*
|
|
62152
|
-
*
|
|
62149
|
+
* The three answers are in: build the schema.
|
|
62150
|
+
*
|
|
62151
|
+
* IT DOES NOT TOUCH THE BASELINE, and that is the whole point.
|
|
62152
|
+
* This runs again on the patch after EVERY write, so a baseline
|
|
62153
|
+
* taken here was re-taken as the version the write had just
|
|
62154
|
+
* raised -- and "written, and its version has not moved" then
|
|
62155
|
+
* read TRUE for a topic whose version had just moved.
|
|
62156
|
+
*
|
|
62157
|
+
* The banner that says so offers a Raise button, which wrote
|
|
62158
|
+
* another version, which was measured against itself again: the
|
|
62159
|
+
* banner came back, every time, and could not be dismissed. One
|
|
62160
|
+
* operator pressed it thirty-three times on one column delete.
|
|
62161
|
+
* It is why schema versions climbed by tens with the schema
|
|
62162
|
+
* unchanged.
|
|
62163
|
+
*
|
|
62164
|
+
* See start_measuring(): the baseline belongs to the LOAD, the
|
|
62165
|
+
* same reason `order_undo` was moved out of here before it.
|
|
62153
62166
|
***************************************************************/
|
|
62154
62167
|
function build_model(gobj) {
|
|
62155
62168
|
let priv = gobj.priv;
|
|
62156
62169
|
priv.model = build_schema_model(priv.records);
|
|
62170
|
+
}
|
|
62171
|
+
/***************************************************************
|
|
62172
|
+
* From here on, "did this session change it?" has an answer.
|
|
62173
|
+
*
|
|
62174
|
+
* Called ONLY when records arrive from the store: that is what a
|
|
62175
|
+
* measurement of "changed since" can be measured against. Both
|
|
62176
|
+
* halves reset together -- a baseline without its `written` is
|
|
62177
|
+
* the same false positive from the other side, since every
|
|
62178
|
+
* version equals a baseline just taken.
|
|
62179
|
+
***************************************************************/
|
|
62180
|
+
function start_measuring(gobj) {
|
|
62181
|
+
let priv = gobj.priv;
|
|
62157
62182
|
priv.baseline = {};
|
|
62183
|
+
priv.written = {};
|
|
62184
|
+
if (!priv.model) return;
|
|
62158
62185
|
for (let treedb of priv.model.treedbs) for (let topic of treedb.topics) priv.baseline[topic.id] = topic.topic_version;
|
|
62159
62186
|
}
|
|
62160
62187
|
/***************************************************************
|
|
62188
|
+
* "This topic was written and its version did not move."
|
|
62189
|
+
*
|
|
62190
|
+
* ONE predicate, because it is asked in two places -- the topic
|
|
62191
|
+
* list draws a chip with it and the column view draws a banner --
|
|
62192
|
+
* and two copies of a rule is how they drift.
|
|
62193
|
+
***************************************************************/
|
|
62194
|
+
function needs_version_bump(written, baseline, topic) {
|
|
62195
|
+
if (!topic || !written || !baseline) return false;
|
|
62196
|
+
if (!written[topic.id]) return false;
|
|
62197
|
+
return String(baseline[topic.id]) === String(topic.topic_version);
|
|
62198
|
+
}
|
|
62199
|
+
/***************************************************************
|
|
62161
62200
|
* Say what the whole store would be refused for.
|
|
62162
62201
|
*
|
|
62163
62202
|
* Not for this view — it has a button for that — but for
|
|
@@ -62597,7 +62636,7 @@ function render_topics(gobj, $body) {
|
|
|
62597
62636
|
let twice = repeated_names(treedb.topics);
|
|
62598
62637
|
let $rows = [];
|
|
62599
62638
|
for (let topic of treedb.topics) {
|
|
62600
|
-
let pending = priv.written
|
|
62639
|
+
let pending = needs_version_bump(priv.written, priv.baseline, topic);
|
|
62601
62640
|
let ambiguous = !!twice[topic.name];
|
|
62602
62641
|
let address = ambiguous ? topic.id : topic.name;
|
|
62603
62642
|
let $actions = [];
|
|
@@ -62906,8 +62945,7 @@ function render_columns(gobj, $body) {
|
|
|
62906
62945
|
***************************************************************/
|
|
62907
62946
|
function version_banner(gobj, topic) {
|
|
62908
62947
|
let priv = gobj.priv;
|
|
62909
|
-
if (!priv.written
|
|
62910
|
-
if (String(priv.baseline[topic.id]) !== String(topic.topic_version)) return null;
|
|
62948
|
+
if (!needs_version_bump(priv.written, priv.baseline, topic)) return null;
|
|
62911
62949
|
if (is_readonly(gobj)) return null;
|
|
62912
62950
|
let $banner = createElement2([
|
|
62913
62951
|
"div",
|
|
@@ -64473,6 +64511,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
64473
64511
|
}
|
|
64474
64512
|
priv.order_undo = {};
|
|
64475
64513
|
build_model(gobj);
|
|
64514
|
+
start_measuring(gobj);
|
|
64476
64515
|
return go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
|
|
64477
64516
|
}
|
|
64478
64517
|
if (command === "update-node" || command === "delete-node") {
|
package/package.json
CHANGED
|
@@ -519,17 +519,50 @@ function remote_command(gobj, command, kw)
|
|
|
519
519
|
}
|
|
520
520
|
|
|
521
521
|
/***************************************************************
|
|
522
|
-
* The three answers are in: build the schema
|
|
523
|
-
*
|
|
524
|
-
*
|
|
525
|
-
*
|
|
522
|
+
* The three answers are in: build the schema.
|
|
523
|
+
*
|
|
524
|
+
* IT DOES NOT TOUCH THE BASELINE, and that is the whole point.
|
|
525
|
+
* This runs again on the patch after EVERY write, so a baseline
|
|
526
|
+
* taken here was re-taken as the version the write had just
|
|
527
|
+
* raised -- and "written, and its version has not moved" then
|
|
528
|
+
* read TRUE for a topic whose version had just moved.
|
|
529
|
+
*
|
|
530
|
+
* The banner that says so offers a Raise button, which wrote
|
|
531
|
+
* another version, which was measured against itself again: the
|
|
532
|
+
* banner came back, every time, and could not be dismissed. One
|
|
533
|
+
* operator pressed it thirty-three times on one column delete.
|
|
534
|
+
* It is why schema versions climbed by tens with the schema
|
|
535
|
+
* unchanged.
|
|
536
|
+
*
|
|
537
|
+
* See start_measuring(): the baseline belongs to the LOAD, the
|
|
538
|
+
* same reason `order_undo` was moved out of here before it.
|
|
526
539
|
***************************************************************/
|
|
527
540
|
function build_model(gobj)
|
|
528
541
|
{
|
|
529
542
|
let priv = gobj.priv;
|
|
530
543
|
|
|
531
544
|
priv.model = build_schema_model(priv.records);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/***************************************************************
|
|
548
|
+
* From here on, "did this session change it?" has an answer.
|
|
549
|
+
*
|
|
550
|
+
* Called ONLY when records arrive from the store: that is what a
|
|
551
|
+
* measurement of "changed since" can be measured against. Both
|
|
552
|
+
* halves reset together -- a baseline without its `written` is
|
|
553
|
+
* the same false positive from the other side, since every
|
|
554
|
+
* version equals a baseline just taken.
|
|
555
|
+
***************************************************************/
|
|
556
|
+
function start_measuring(gobj)
|
|
557
|
+
{
|
|
558
|
+
let priv = gobj.priv;
|
|
559
|
+
|
|
532
560
|
priv.baseline = {};
|
|
561
|
+
priv.written = {};
|
|
562
|
+
|
|
563
|
+
if(!priv.model) {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
533
566
|
for(let treedb of priv.model.treedbs) {
|
|
534
567
|
for(let topic of treedb.topics) {
|
|
535
568
|
priv.baseline[topic.id] = topic.topic_version;
|
|
@@ -537,6 +570,24 @@ function build_model(gobj)
|
|
|
537
570
|
}
|
|
538
571
|
}
|
|
539
572
|
|
|
573
|
+
/***************************************************************
|
|
574
|
+
* "This topic was written and its version did not move."
|
|
575
|
+
*
|
|
576
|
+
* ONE predicate, because it is asked in two places -- the topic
|
|
577
|
+
* list draws a chip with it and the column view draws a banner --
|
|
578
|
+
* and two copies of a rule is how they drift.
|
|
579
|
+
***************************************************************/
|
|
580
|
+
function needs_version_bump(written, baseline, topic)
|
|
581
|
+
{
|
|
582
|
+
if(!topic || !written || !baseline) {
|
|
583
|
+
return false;
|
|
584
|
+
}
|
|
585
|
+
if(!written[topic.id]) {
|
|
586
|
+
return false;
|
|
587
|
+
}
|
|
588
|
+
return String(baseline[topic.id]) === String(topic.topic_version);
|
|
589
|
+
}
|
|
590
|
+
|
|
540
591
|
/***************************************************************
|
|
541
592
|
* Say what the whole store would be refused for.
|
|
542
593
|
*
|
|
@@ -987,8 +1038,7 @@ function render_topics(gobj, $body)
|
|
|
987
1038
|
let twice = repeated_names(treedb.topics);
|
|
988
1039
|
let $rows = [];
|
|
989
1040
|
for(let topic of treedb.topics) {
|
|
990
|
-
let pending = priv.written
|
|
991
|
-
String(priv.baseline[topic.id]) === String(topic.topic_version);
|
|
1041
|
+
let pending = needs_version_bump(priv.written, priv.baseline, topic);
|
|
992
1042
|
/* Two topics of one name: the id is what tells them apart, and
|
|
993
1043
|
* it is what the url has to carry — addressing by name would
|
|
994
1044
|
* open the first one whichever row was clicked. */
|
|
@@ -1187,10 +1237,7 @@ function version_banner(gobj, topic)
|
|
|
1187
1237
|
{
|
|
1188
1238
|
let priv = gobj.priv;
|
|
1189
1239
|
|
|
1190
|
-
if(!priv.written
|
|
1191
|
-
return null;
|
|
1192
|
-
}
|
|
1193
|
-
if(String(priv.baseline[topic.id]) !== String(topic.topic_version)) {
|
|
1240
|
+
if(!needs_version_bump(priv.written, priv.baseline, topic)) {
|
|
1194
1241
|
return null;
|
|
1195
1242
|
}
|
|
1196
1243
|
if(is_readonly(gobj)) {
|
|
@@ -2558,6 +2605,11 @@ function ac_mt_command_answer(gobj, event, kw, src)
|
|
|
2558
2605
|
* write, which is exactly when the undo has to survive.) */
|
|
2559
2606
|
priv.order_undo = {};
|
|
2560
2607
|
build_model(gobj);
|
|
2608
|
+
/* Same reason as order_undo above: this is the LOAD, and the
|
|
2609
|
+
* baseline is what a later "the version did not move" is measured
|
|
2610
|
+
* against. Taken on the write patches instead, it measured every
|
|
2611
|
+
* version against itself. */
|
|
2612
|
+
start_measuring(gobj);
|
|
2561
2613
|
/* Back to where the operator was: the load may be a refresh, or
|
|
2562
2614
|
* the answer to a deep link that arrived before the model. */
|
|
2563
2615
|
return go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
|
|
@@ -3424,4 +3476,9 @@ function register_c_yui_schema_editor()
|
|
|
3424
3476
|
return create_gclass(GCLASS_NAME);
|
|
3425
3477
|
}
|
|
3426
3478
|
|
|
3427
|
-
export {
|
|
3479
|
+
export {
|
|
3480
|
+
register_c_yui_schema_editor,
|
|
3481
|
+
/* Exported for its test: the rule that decides whether a topic still
|
|
3482
|
+
* owes a version bump, which is asked in two places. */
|
|
3483
|
+
needs_version_bump
|
|
3484
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/***********************************************************************
|
|
2
|
+
* schema_version_bump.test.js
|
|
3
|
+
*
|
|
4
|
+
* "This topic was written and its version did not move."
|
|
5
|
+
*
|
|
6
|
+
* THE RULE MEASURES AGAINST A BASELINE, AND THE BASELINE MUST NOT
|
|
7
|
+
* MOVE WITH IT. It used to be re-taken inside build_model(), which
|
|
8
|
+
* runs again on the patch after EVERY write -- so it came back as
|
|
9
|
+
* the version the write had just raised, the rule read TRUE for a
|
|
10
|
+
* topic whose version HAD moved, and the banner that says so
|
|
11
|
+
* offered a Raise button that wrote another version and was
|
|
12
|
+
* measured against itself again.
|
|
13
|
+
*
|
|
14
|
+
* The banner could not be dismissed. One operator pressed it
|
|
15
|
+
* thirty-three times on a single column delete, and that is why
|
|
16
|
+
* schema versions climbed by tens with the schema unchanged.
|
|
17
|
+
*
|
|
18
|
+
* Copyright (c) 2026, ArtGins.
|
|
19
|
+
* All Rights Reserved.
|
|
20
|
+
***********************************************************************/
|
|
21
|
+
import {describe, it, expect} from "vitest";
|
|
22
|
+
import {needs_version_bump} from "./c_yui_schema_editor.js";
|
|
23
|
+
|
|
24
|
+
const TOPIC = {id: "device_groups", topic_version: 5};
|
|
25
|
+
|
|
26
|
+
describe("needs_version_bump", () => {
|
|
27
|
+
it("says nothing about a topic this session never wrote", () => {
|
|
28
|
+
expect(needs_version_bump({}, {device_groups: 5}, TOPIC)).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("asks for the bump when the version sits where it was found", () => {
|
|
32
|
+
expect(needs_version_bump({device_groups: true}, {device_groups: 5}, TOPIC))
|
|
33
|
+
.toBe(true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("STOPS asking once the version has moved past the baseline", () => {
|
|
37
|
+
/* The case the loop got wrong: the write raised it to 6 and the
|
|
38
|
+
* baseline still says 5, so there is nothing left to raise. */
|
|
39
|
+
expect(needs_version_bump(
|
|
40
|
+
{device_groups: true}, {device_groups: 5}, {id: "device_groups", topic_version: 6}
|
|
41
|
+
)).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("compares as text, so 5 and '5' are the same version", () => {
|
|
45
|
+
expect(needs_version_bump(
|
|
46
|
+
{device_groups: true}, {device_groups: "5"}, TOPIC
|
|
47
|
+
)).toBe(true);
|
|
48
|
+
expect(needs_version_bump(
|
|
49
|
+
{device_groups: true}, {device_groups: 5}, {id: "device_groups", topic_version: "5"}
|
|
50
|
+
)).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("answers false rather than throwing on a missing half", () => {
|
|
54
|
+
expect(needs_version_bump(null, {device_groups: 5}, TOPIC)).toBe(false);
|
|
55
|
+
expect(needs_version_bump({device_groups: true}, null, TOPIC)).toBe(false);
|
|
56
|
+
expect(needs_version_bump({device_groups: true}, {device_groups: 5}, null)).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("a topic with no baseline entry is not owed a bump", () => {
|
|
60
|
+
expect(needs_version_bump({device_groups: true}, {}, TOPIC)).toBe(false);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("the loop it came from", () => {
|
|
65
|
+
/*
|
|
66
|
+
* What the editor does per bump: raise the version by one. With the
|
|
67
|
+
* baseline left alone, ONE press settles it; with the baseline
|
|
68
|
+
* re-taken each time -- the old bug -- it never settles.
|
|
69
|
+
*/
|
|
70
|
+
function press_raise(state) {
|
|
71
|
+
return {written: state.written, baseline: state.baseline,
|
|
72
|
+
topic: {id: "t", topic_version: Number(state.topic.topic_version) + 1}};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
it("settles after a single press", () => {
|
|
76
|
+
let st = {written: {t: true}, baseline: {t: 5}, topic: {id: "t", topic_version: 5}};
|
|
77
|
+
expect(needs_version_bump(st.written, st.baseline, st.topic)).toBe(true);
|
|
78
|
+
st = press_raise(st);
|
|
79
|
+
expect(needs_version_bump(st.written, st.baseline, st.topic)).toBe(false);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("never settles if the baseline is re-taken with the version", () => {
|
|
83
|
+
let st = {written: {t: true}, baseline: {t: 5}, topic: {id: "t", topic_version: 5}};
|
|
84
|
+
let presses = 0;
|
|
85
|
+
while(needs_version_bump(st.written, st.baseline, st.topic) && presses < 40) {
|
|
86
|
+
st = press_raise(st);
|
|
87
|
+
st.baseline = {t: st.topic.topic_version}; /* the bug */
|
|
88
|
+
presses++;
|
|
89
|
+
}
|
|
90
|
+
expect(presses).toBe(40); /* it ran to the guard: no way out */
|
|
91
|
+
});
|
|
92
|
+
});
|