@yuneta/gobj-ui 7.23.41 → 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 +50 -10
- package/dist/gobj-ui.es.js +50 -10
- package/package.json +1 -1
- package/src/c_yui_schema_editor.js +68 -11
- package/src/c_yui_treedb_topic_with_form.js +25 -3
- package/src/schema_version_bump.test.js +92 -0
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -23218,14 +23218,14 @@ function build_ui$5(gobj) {
|
|
|
23218
23218
|
"div",
|
|
23219
23219
|
{
|
|
23220
23220
|
class: "C_YUI_TREEDB_TOPIC_WITH_FORM",
|
|
23221
|
-
style: "height:100%;"
|
|
23221
|
+
style: "height:100%; min-height:0; display:flex; flex-direction:column;"
|
|
23222
23222
|
},
|
|
23223
23223
|
[["div", {
|
|
23224
23224
|
class: "TREEDB_TABLE_TOOLBAR toolbar_tabulator_table m-1",
|
|
23225
|
-
style: "display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap;"
|
|
23225
|
+
style: "flex:none; display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap;"
|
|
23226
23226
|
}], ["div", {
|
|
23227
23227
|
id: `${table_id}`,
|
|
23228
|
-
style: "margin-top:0px !important;"
|
|
23228
|
+
style: "margin-top:0px !important; flex:1 1 auto; min-height:0;"
|
|
23229
23229
|
}]]
|
|
23230
23230
|
]);
|
|
23231
23231
|
if ((0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "with_checkbox") && (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "with_selection_bar")) {
|
|
@@ -23235,6 +23235,7 @@ function build_ui$5(gobj) {
|
|
|
23235
23235
|
on_clear: () => (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_CLEAR_SELECTION", {}, gobj)
|
|
23236
23236
|
});
|
|
23237
23237
|
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "selection_bar", bar);
|
|
23238
|
+
bar.$el.style.flex = "none";
|
|
23238
23239
|
$container.insertBefore(bar.$el, $container.querySelector(`#${table_id}`));
|
|
23239
23240
|
}
|
|
23240
23241
|
let $toolbar_slot = $container.querySelector(".toolbar_tabulator_table");
|
|
@@ -62150,18 +62151,57 @@ function remote_command(gobj, command, kw) {
|
|
|
62150
62151
|
return 0;
|
|
62151
62152
|
}
|
|
62152
62153
|
/***************************************************************
|
|
62153
|
-
* The three answers are in: build the schema
|
|
62154
|
-
*
|
|
62155
|
-
*
|
|
62156
|
-
*
|
|
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.
|
|
62157
62171
|
***************************************************************/
|
|
62158
62172
|
function build_model(gobj) {
|
|
62159
62173
|
let priv = gobj.priv;
|
|
62160
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;
|
|
62161
62187
|
priv.baseline = {};
|
|
62188
|
+
priv.written = {};
|
|
62189
|
+
if (!priv.model) return;
|
|
62162
62190
|
for (let treedb of priv.model.treedbs) for (let topic of treedb.topics) priv.baseline[topic.id] = topic.topic_version;
|
|
62163
62191
|
}
|
|
62164
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
|
+
/***************************************************************
|
|
62165
62205
|
* Say what the whole store would be refused for.
|
|
62166
62206
|
*
|
|
62167
62207
|
* Not for this view — it has a button for that — but for
|
|
@@ -62601,7 +62641,7 @@ function render_topics(gobj, $body) {
|
|
|
62601
62641
|
let twice = repeated_names(treedb.topics);
|
|
62602
62642
|
let $rows = [];
|
|
62603
62643
|
for (let topic of treedb.topics) {
|
|
62604
|
-
let pending = priv.written
|
|
62644
|
+
let pending = needs_version_bump(priv.written, priv.baseline, topic);
|
|
62605
62645
|
let ambiguous = !!twice[topic.name];
|
|
62606
62646
|
let address = ambiguous ? topic.id : topic.name;
|
|
62607
62647
|
let $actions = [];
|
|
@@ -62910,8 +62950,7 @@ function render_columns(gobj, $body) {
|
|
|
62910
62950
|
***************************************************************/
|
|
62911
62951
|
function version_banner(gobj, topic) {
|
|
62912
62952
|
let priv = gobj.priv;
|
|
62913
|
-
if (!priv.written
|
|
62914
|
-
if (String(priv.baseline[topic.id]) !== String(topic.topic_version)) return null;
|
|
62953
|
+
if (!needs_version_bump(priv.written, priv.baseline, topic)) return null;
|
|
62915
62954
|
if (is_readonly(gobj)) return null;
|
|
62916
62955
|
let $banner = (0, _yuneta_gobj_js.createElement2)([
|
|
62917
62956
|
"div",
|
|
@@ -64477,6 +64516,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
64477
64516
|
}
|
|
64478
64517
|
priv.order_undo = {};
|
|
64479
64518
|
build_model(gobj);
|
|
64519
|
+
start_measuring(gobj);
|
|
64480
64520
|
return go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
|
|
64481
64521
|
}
|
|
64482
64522
|
if (command === "update-node" || command === "delete-node") {
|
package/dist/gobj-ui.es.js
CHANGED
|
@@ -23213,14 +23213,14 @@ function build_ui$5(gobj) {
|
|
|
23213
23213
|
"div",
|
|
23214
23214
|
{
|
|
23215
23215
|
class: "C_YUI_TREEDB_TOPIC_WITH_FORM",
|
|
23216
|
-
style: "height:100%;"
|
|
23216
|
+
style: "height:100%; min-height:0; display:flex; flex-direction:column;"
|
|
23217
23217
|
},
|
|
23218
23218
|
[["div", {
|
|
23219
23219
|
class: "TREEDB_TABLE_TOOLBAR toolbar_tabulator_table m-1",
|
|
23220
|
-
style: "display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap;"
|
|
23220
|
+
style: "flex:none; display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap;"
|
|
23221
23221
|
}], ["div", {
|
|
23222
23222
|
id: `${table_id}`,
|
|
23223
|
-
style: "margin-top:0px !important;"
|
|
23223
|
+
style: "margin-top:0px !important; flex:1 1 auto; min-height:0;"
|
|
23224
23224
|
}]]
|
|
23225
23225
|
]);
|
|
23226
23226
|
if (gobj_read_bool_attr(gobj, "with_checkbox") && gobj_read_bool_attr(gobj, "with_selection_bar")) {
|
|
@@ -23230,6 +23230,7 @@ function build_ui$5(gobj) {
|
|
|
23230
23230
|
on_clear: () => gobj_send_event(gobj, "EV_CLEAR_SELECTION", {}, gobj)
|
|
23231
23231
|
});
|
|
23232
23232
|
gobj_write_attr(gobj, "selection_bar", bar);
|
|
23233
|
+
bar.$el.style.flex = "none";
|
|
23233
23234
|
$container.insertBefore(bar.$el, $container.querySelector(`#${table_id}`));
|
|
23234
23235
|
}
|
|
23235
23236
|
let $toolbar_slot = $container.querySelector(".toolbar_tabulator_table");
|
|
@@ -62145,18 +62146,57 @@ function remote_command(gobj, command, kw) {
|
|
|
62145
62146
|
return 0;
|
|
62146
62147
|
}
|
|
62147
62148
|
/***************************************************************
|
|
62148
|
-
* The three answers are in: build the schema
|
|
62149
|
-
*
|
|
62150
|
-
*
|
|
62151
|
-
*
|
|
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.
|
|
62152
62166
|
***************************************************************/
|
|
62153
62167
|
function build_model(gobj) {
|
|
62154
62168
|
let priv = gobj.priv;
|
|
62155
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;
|
|
62156
62182
|
priv.baseline = {};
|
|
62183
|
+
priv.written = {};
|
|
62184
|
+
if (!priv.model) return;
|
|
62157
62185
|
for (let treedb of priv.model.treedbs) for (let topic of treedb.topics) priv.baseline[topic.id] = topic.topic_version;
|
|
62158
62186
|
}
|
|
62159
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
|
+
/***************************************************************
|
|
62160
62200
|
* Say what the whole store would be refused for.
|
|
62161
62201
|
*
|
|
62162
62202
|
* Not for this view — it has a button for that — but for
|
|
@@ -62596,7 +62636,7 @@ function render_topics(gobj, $body) {
|
|
|
62596
62636
|
let twice = repeated_names(treedb.topics);
|
|
62597
62637
|
let $rows = [];
|
|
62598
62638
|
for (let topic of treedb.topics) {
|
|
62599
|
-
let pending = priv.written
|
|
62639
|
+
let pending = needs_version_bump(priv.written, priv.baseline, topic);
|
|
62600
62640
|
let ambiguous = !!twice[topic.name];
|
|
62601
62641
|
let address = ambiguous ? topic.id : topic.name;
|
|
62602
62642
|
let $actions = [];
|
|
@@ -62905,8 +62945,7 @@ function render_columns(gobj, $body) {
|
|
|
62905
62945
|
***************************************************************/
|
|
62906
62946
|
function version_banner(gobj, topic) {
|
|
62907
62947
|
let priv = gobj.priv;
|
|
62908
|
-
if (!priv.written
|
|
62909
|
-
if (String(priv.baseline[topic.id]) !== String(topic.topic_version)) return null;
|
|
62948
|
+
if (!needs_version_bump(priv.written, priv.baseline, topic)) return null;
|
|
62910
62949
|
if (is_readonly(gobj)) return null;
|
|
62911
62950
|
let $banner = createElement2([
|
|
62912
62951
|
"div",
|
|
@@ -64472,6 +64511,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
64472
64511
|
}
|
|
64473
64512
|
priv.order_undo = {};
|
|
64474
64513
|
build_model(gobj);
|
|
64514
|
+
start_measuring(gobj);
|
|
64475
64515
|
return go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
|
|
64476
64516
|
}
|
|
64477
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
|
+
};
|
|
@@ -759,13 +759,33 @@ function build_ui(gobj)
|
|
|
759
759
|
* Layout Schema
|
|
760
760
|
*----------------------------------------------*/
|
|
761
761
|
let table_id = gobj_read_str_attr(gobj, "table_id");
|
|
762
|
+
/*
|
|
763
|
+
* A FLEX COLUMN, and that is the whole point of this block.
|
|
764
|
+
*
|
|
765
|
+
* It used to be a plain `height:100%` box with the toolbar and the
|
|
766
|
+
* table stacked inside it. The toolbar took its natural height and the
|
|
767
|
+
* table asked for `maxHeight: 100%` -- 100% of the CONTAINER, not of
|
|
768
|
+
* what the toolbar left -- so the box overflowed by exactly the height
|
|
769
|
+
* of the toolbar. The parent scrolls (`overflow:auto`), so the page
|
|
770
|
+
* ended up with TWO scrolls, and what fell off the bottom was the
|
|
771
|
+
* table's own footer: the row count and the paginator. Scrolling the
|
|
772
|
+
* outer one to reach them pushed the toolbar out of sight instead.
|
|
773
|
+
*
|
|
774
|
+
* As a column with the chrome at `flex:none` and the table at
|
|
775
|
+
* `flex:1 1 auto; min-height:0`, the table is sized to the space that
|
|
776
|
+
* is actually left, its footer stays put, and the only thing that
|
|
777
|
+
* scrolls is the rows -- which is the one scroll a table should have.
|
|
778
|
+
*/
|
|
762
779
|
let $container = createElement2(
|
|
763
|
-
['div', {class: 'C_YUI_TREEDB_TOPIC_WITH_FORM',
|
|
764
|
-
|
|
780
|
+
['div', {class: 'C_YUI_TREEDB_TOPIC_WITH_FORM',
|
|
781
|
+
style: 'height:100%; min-height:0; display:flex; flex-direction:column;'}, [
|
|
782
|
+
['div', {class: 'TREEDB_TABLE_TOOLBAR toolbar_tabulator_table m-1',
|
|
783
|
+
style: 'flex:none; display:flex; justify-content:space-between; ' +
|
|
784
|
+
'align-items:center; flex-wrap:wrap;'}],
|
|
765
785
|
['div',
|
|
766
786
|
{
|
|
767
787
|
id: `${table_id}`,
|
|
768
|
-
style: 'margin-top:0px !important;',
|
|
788
|
+
style: 'margin-top:0px !important; flex:1 1 auto; min-height:0;',
|
|
769
789
|
}
|
|
770
790
|
]
|
|
771
791
|
]]
|
|
@@ -782,6 +802,8 @@ function build_ui(gobj)
|
|
|
782
802
|
on_clear: () => gobj_send_event(gobj, "EV_CLEAR_SELECTION", {}, gobj)
|
|
783
803
|
});
|
|
784
804
|
gobj_write_attr(gobj, "selection_bar", bar);
|
|
805
|
+
/* Chrome too: it must not take height from the rows. */
|
|
806
|
+
bar.$el.style.flex = "none";
|
|
785
807
|
$container.insertBefore(bar.$el, $container.querySelector(`#${table_id}`));
|
|
786
808
|
}
|
|
787
809
|
|
|
@@ -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
|
+
});
|