@yuneta/gobj-ui 7.25.21 → 7.25.23
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 +9 -3
- package/dist/gobj-ui.cjs.js +72 -12
- package/dist/gobj-ui.es.js +72 -12
- package/package.json +4 -4
- package/src/c_yui_treedb_graph.js +50 -1
- package/src/c_yui_treedb_topics.js +44 -0
- package/src/treedb_json_drill.wiring.test.js +116 -0
package/README.md
CHANGED
|
@@ -597,9 +597,15 @@ Two layout facts the browser taught this component, both worth keeping:
|
|
|
597
597
|
session, or refused by the transport on its way out, never reaches the
|
|
598
598
|
backend, so no answer will ever come back for it -- the host answers it
|
|
599
599
|
itself (`C_YUI_TREEDB_TOPICS` / `C_YUI_TREEDB_GRAPH` since `7.25.21`: `i18n:
|
|
600
|
-
"no session"`, or the transport's refusal as `error`).
|
|
601
|
-
|
|
602
|
-
|
|
600
|
+
"no session"`, or the transport's refusal as `error`). So is a drill
|
|
601
|
+
already SENT when the session drops: a transport answers nothing in flight
|
|
602
|
+
on a close, so the host keeps the paths it asked and, on the disconnect
|
|
603
|
+
edge (`EV_TRANSPORT_STATE` or the shell's `EV_CONNECTION_STATE`, both
|
|
604
|
+
`{connected: false}`), answers each one `i18n: "the connection dropped"`
|
|
605
|
+
(since `7.25.22`); a failure that lands after that answer is dropped with
|
|
606
|
+
a warning, not shown twice. While a path is pending the viewer ignores
|
|
607
|
+
every click on it, so a drill left unanswered is a dead stub for the life
|
|
608
|
+
of the viewer.
|
|
603
609
|
A host that cannot read a subtree says so with the error, as
|
|
604
610
|
`C_YUI_TREEDB_TOPIC_WITH_FORM` does for its schema, cell and table viewers
|
|
605
611
|
since `7.25.19` (before, it declared nothing: *"Event NOT DEFINED"*):
|
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -11140,8 +11140,8 @@ function ac_load_data$2(gobj, event, kw, src) {
|
|
|
11140
11140
|
******************************************************/
|
|
11141
11141
|
function ac_add_serie(gobj, event, kw, src) {
|
|
11142
11142
|
let uplot$4 = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "uplot");
|
|
11143
|
-
let idx;
|
|
11144
|
-
for (
|
|
11143
|
+
let idx = 0;
|
|
11144
|
+
for (; idx < uplot$4.series.length; idx++) {
|
|
11145
11145
|
let serie = uplot$4.series[idx];
|
|
11146
11146
|
if (serie.id && serie.id === kw.id) {
|
|
11147
11147
|
(0, _yuneta_gobj_js.log_error)("Serie '" + kw.id + "' already exists");
|
|
@@ -23791,7 +23791,8 @@ var PRIVATE_DATA$6 = {
|
|
|
23791
23791
|
schema_gobj: null,
|
|
23792
23792
|
json_gobj: null,
|
|
23793
23793
|
json_win: null,
|
|
23794
|
-
json_modal: null
|
|
23794
|
+
json_modal: null,
|
|
23795
|
+
drills_in_flight: null
|
|
23795
23796
|
};
|
|
23796
23797
|
var __gclass__$6 = null;
|
|
23797
23798
|
/******************************
|
|
@@ -23804,6 +23805,7 @@ function mt_create$6(gobj) {
|
|
|
23804
23805
|
gobj.priv.form_writes = {};
|
|
23805
23806
|
gobj.priv.reread_on_session = false;
|
|
23806
23807
|
gobj.priv.conn_shell = null;
|
|
23808
|
+
gobj.priv.drills_in_flight = /* @__PURE__ */ new Set();
|
|
23807
23809
|
build_ui$6(gobj);
|
|
23808
23810
|
let subscriber = (0, _yuneta_gobj_js.gobj_read_pointer_attr)(gobj, "subscriber");
|
|
23809
23811
|
if (!subscriber) subscriber = (0, _yuneta_gobj_js.gobj_parent)(gobj);
|
|
@@ -25102,6 +25104,7 @@ function close_json_viewer$1(gobj) {
|
|
|
25102
25104
|
priv.json_gobj = null;
|
|
25103
25105
|
priv.json_win = null;
|
|
25104
25106
|
priv.json_modal = null;
|
|
25107
|
+
priv.drills_in_flight.clear();
|
|
25105
25108
|
if (win && (0, _yuneta_gobj_js.is_gobj)(win)) try {
|
|
25106
25109
|
if ((0, _yuneta_gobj_js.gobj_is_running)(win)) (0, _yuneta_gobj_js.gobj_stop)(win);
|
|
25107
25110
|
(0, _yuneta_gobj_js.gobj_destroy)(win);
|
|
@@ -25183,7 +25186,25 @@ function request_print_tranger$1(gobj, path) {
|
|
|
25183
25186
|
if (ret) {
|
|
25184
25187
|
(0, _yuneta_gobj_js.log_error)(ret);
|
|
25185
25188
|
answer_print_tranger_refused$1(gobj, path, { error: refusal_text$1(ret) });
|
|
25189
|
+
return;
|
|
25186
25190
|
}
|
|
25191
|
+
if (path) priv.drills_in_flight.add(path);
|
|
25192
|
+
}
|
|
25193
|
+
/************************************************************
|
|
25194
|
+
* The session dropped: a drill already sent will never be answered
|
|
25195
|
+
* (the transport answers nothing in flight on a close), and its stub
|
|
25196
|
+
* would show "loading" for the life of the viewer. Answered here, so a
|
|
25197
|
+
* click once the session is back asks again. Idempotent: both edges of
|
|
25198
|
+
* one drop may arrive.
|
|
25199
|
+
************************************************************/
|
|
25200
|
+
function answer_drills_in_flight$1(gobj) {
|
|
25201
|
+
let priv = gobj.priv;
|
|
25202
|
+
let paths = Array.from(priv.drills_in_flight);
|
|
25203
|
+
priv.drills_in_flight.clear();
|
|
25204
|
+
paths.forEach((path) => {
|
|
25205
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: transport closed, the drill '${path}' of the raw json is lost`);
|
|
25206
|
+
answer_print_tranger_refused$1(gobj, path, { i18n: "the connection dropped" });
|
|
25207
|
+
});
|
|
25187
25208
|
}
|
|
25188
25209
|
/***************************************************************
|
|
25189
25210
|
* The last gate before a write leaves for the yuno. The per-topic
|
|
@@ -25225,6 +25246,12 @@ function ac_mt_command_answer$2(gobj, event, kw, src) {
|
|
|
25225
25246
|
let jv = gobj.priv.json_gobj;
|
|
25226
25247
|
if (!jv || !(0, _yuneta_gobj_js.is_gobj)(jv) || (0, _yuneta_gobj_js.gobj_is_destroying)(jv)) return 0;
|
|
25227
25248
|
let path = (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "path", "", 0);
|
|
25249
|
+
if (path) {
|
|
25250
|
+
if (!gobj.priv.drills_in_flight.delete(path) && result < 0) {
|
|
25251
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: late failure of the drill '${path}' dropped, it was already answered: ${comment || ""}`);
|
|
25252
|
+
return 0;
|
|
25253
|
+
}
|
|
25254
|
+
} else gobj.priv.drills_in_flight.clear();
|
|
25228
25255
|
if (result < 0) {
|
|
25229
25256
|
if (path) (0, _yuneta_gobj_js.gobj_send_event)(jv, "EV_SUBTREE_ERROR", {
|
|
25230
25257
|
path,
|
|
@@ -25483,6 +25510,7 @@ function ac_transport_state$2(gobj, event, kw, src) {
|
|
|
25483
25510
|
refresh_toolbar_buttons(gobj, connected);
|
|
25484
25511
|
if (!connected) {
|
|
25485
25512
|
gobj.priv.reread_on_session = true;
|
|
25513
|
+
answer_drills_in_flight$1(gobj);
|
|
25486
25514
|
abandon_form_writes(gobj.priv.form_writes).forEach((w) => {
|
|
25487
25515
|
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: transport closed, the write ${w.form_write} of '${w.topic_name}' is lost`);
|
|
25488
25516
|
answer_form_write(gobj, get_gobj_formtable(gobj, w.topic_name), w.form_write, false);
|
|
@@ -25876,6 +25904,7 @@ function ac_json_closed$1(gobj, event, kw, src) {
|
|
|
25876
25904
|
priv.json_gobj = null;
|
|
25877
25905
|
priv.json_win = null;
|
|
25878
25906
|
priv.json_modal = null;
|
|
25907
|
+
priv.drills_in_flight.clear();
|
|
25879
25908
|
if (jv && (0, _yuneta_gobj_js.is_gobj)(jv)) try {
|
|
25880
25909
|
(0, _yuneta_gobj_js.gobj_stop)(jv);
|
|
25881
25910
|
(0, _yuneta_gobj_js.gobj_destroy)(jv);
|
|
@@ -32817,8 +32846,6 @@ var eventemitter3_default = (/* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJS
|
|
|
32817
32846
|
if ("undefined" !== typeof module) module.exports = EventEmitter;
|
|
32818
32847
|
})))(), 1)).default;
|
|
32819
32848
|
var ARRAY_TYPE = typeof Float32Array !== "undefined" ? Float32Array : Array;
|
|
32820
|
-
Math.PI / 180;
|
|
32821
|
-
180 / Math.PI;
|
|
32822
32849
|
//#endregion
|
|
32823
32850
|
//#region node_modules/gl-matrix/esm/mat3.js
|
|
32824
32851
|
/**
|
|
@@ -50093,12 +50120,12 @@ PERFORMANCE OF THIS SOFTWARE.
|
|
|
50093
50120
|
},
|
|
50094
50121
|
trys: [],
|
|
50095
50122
|
ops: []
|
|
50096
|
-
}, f, y, t, g
|
|
50097
|
-
return g = {
|
|
50123
|
+
}, f, y, t, g = {
|
|
50098
50124
|
next: verb(0),
|
|
50099
50125
|
"throw": verb(1),
|
|
50100
50126
|
"return": verb(2)
|
|
50101
|
-
}
|
|
50127
|
+
};
|
|
50128
|
+
return typeof Symbol === "function" && (g[Symbol.iterator] = function() {
|
|
50102
50129
|
return this;
|
|
50103
50130
|
}), g;
|
|
50104
50131
|
function verb(n) {
|
|
@@ -67468,6 +67495,7 @@ var PRIVATE_DATA$3 = {
|
|
|
67468
67495
|
json_gobj: null,
|
|
67469
67496
|
json_win: null,
|
|
67470
67497
|
json_modal: null,
|
|
67498
|
+
drills_in_flight: null,
|
|
67471
67499
|
with_treedb_tables: false,
|
|
67472
67500
|
canvas_id: null,
|
|
67473
67501
|
operation_mode: null,
|
|
@@ -67487,6 +67515,7 @@ var __gclass__$3 = null;
|
|
|
67487
67515
|
***************************************************************/
|
|
67488
67516
|
function mt_create$3(gobj) {
|
|
67489
67517
|
let priv = gobj.priv;
|
|
67518
|
+
priv.drills_in_flight = /* @__PURE__ */ new Set();
|
|
67490
67519
|
let subscriber = (0, _yuneta_gobj_js.gobj_read_pointer_attr)(gobj, "subscriber");
|
|
67491
67520
|
if (!subscriber) subscriber = (0, _yuneta_gobj_js.gobj_parent)(gobj);
|
|
67492
67521
|
(0, _yuneta_gobj_js.gobj_subscribe_event)(gobj, null, {}, subscriber);
|
|
@@ -67645,9 +67674,13 @@ function refresh_raw_json_button(gobj, connected) {
|
|
|
67645
67674
|
* "Raw JSON" button disables the moment the session drops and re-enables on
|
|
67646
67675
|
* reconnect. The library view must not subscribe to the C_IEVENT_CLI itself
|
|
67647
67676
|
* (that forwards the subscription upstream and breaks the session).
|
|
67677
|
+
* On the drop, the drills of the raw-json viewer still in flight are
|
|
67678
|
+
* answered: the transport answers nothing in flight on a close.
|
|
67648
67679
|
************************************************************/
|
|
67649
67680
|
function ac_transport_state$1(gobj, event, kw, src) {
|
|
67650
|
-
|
|
67681
|
+
let connected = !!(kw && kw.connected);
|
|
67682
|
+
refresh_raw_json_button(gobj, connected);
|
|
67683
|
+
if (!connected) answer_drills_in_flight(gobj);
|
|
67651
67684
|
return 0;
|
|
67652
67685
|
}
|
|
67653
67686
|
/************************************************************
|
|
@@ -68350,6 +68383,7 @@ function close_json_viewer(gobj) {
|
|
|
68350
68383
|
priv.json_gobj = null;
|
|
68351
68384
|
priv.json_win = null;
|
|
68352
68385
|
priv.json_modal = null;
|
|
68386
|
+
priv.drills_in_flight.clear();
|
|
68353
68387
|
if (win && (0, _yuneta_gobj_js.is_gobj)(win)) try {
|
|
68354
68388
|
if ((0, _yuneta_gobj_js.gobj_is_running)(win)) (0, _yuneta_gobj_js.gobj_stop)(win);
|
|
68355
68389
|
(0, _yuneta_gobj_js.gobj_destroy)(win);
|
|
@@ -68417,7 +68451,25 @@ function request_print_tranger(gobj, path) {
|
|
|
68417
68451
|
if (ret) {
|
|
68418
68452
|
(0, _yuneta_gobj_js.log_error)(ret);
|
|
68419
68453
|
answer_print_tranger_refused(gobj, path, { error: refusal_text(ret) });
|
|
68454
|
+
return;
|
|
68420
68455
|
}
|
|
68456
|
+
if (path) priv.drills_in_flight.add(path);
|
|
68457
|
+
}
|
|
68458
|
+
/************************************************************
|
|
68459
|
+
* The session dropped: a drill already sent will never be answered
|
|
68460
|
+
* (the transport answers nothing in flight on a close), and its stub
|
|
68461
|
+
* would show "loading" for the life of the viewer. Answered here, so a
|
|
68462
|
+
* click once the session is back asks again. Idempotent: both edges of
|
|
68463
|
+
* one drop may arrive.
|
|
68464
|
+
************************************************************/
|
|
68465
|
+
function answer_drills_in_flight(gobj) {
|
|
68466
|
+
let priv = gobj.priv;
|
|
68467
|
+
let paths = Array.from(priv.drills_in_flight);
|
|
68468
|
+
priv.drills_in_flight.clear();
|
|
68469
|
+
paths.forEach((path) => {
|
|
68470
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: transport closed, the drill '${path}' of the raw json is lost`);
|
|
68471
|
+
answer_print_tranger_refused(gobj, path, { i18n: "the connection dropped" });
|
|
68472
|
+
});
|
|
68421
68473
|
}
|
|
68422
68474
|
/************************************************************
|
|
68423
68475
|
* Populate layout dropdown from child's available layouts
|
|
@@ -68795,6 +68847,12 @@ function ac_mt_command_answer$1(gobj, event, kw, src) {
|
|
|
68795
68847
|
let jv = priv.json_gobj;
|
|
68796
68848
|
if (!jv || !(0, _yuneta_gobj_js.is_gobj)(jv) || (0, _yuneta_gobj_js.gobj_is_destroying)(jv)) return 0;
|
|
68797
68849
|
let path = (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "path", "", 0);
|
|
68850
|
+
if (path) {
|
|
68851
|
+
if (!priv.drills_in_flight.delete(path) && result < 0) {
|
|
68852
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: late failure of the drill '${path}' dropped, it was already answered: ${comment || ""}`);
|
|
68853
|
+
return 0;
|
|
68854
|
+
}
|
|
68855
|
+
} else priv.drills_in_flight.clear();
|
|
68798
68856
|
if (result < 0) {
|
|
68799
68857
|
if (path) (0, _yuneta_gobj_js.gobj_send_event)(jv, "EV_SUBTREE_ERROR", {
|
|
68800
68858
|
path,
|
|
@@ -68981,6 +69039,7 @@ function ac_json_closed(gobj, event, kw, src) {
|
|
|
68981
69039
|
priv.json_gobj = null;
|
|
68982
69040
|
priv.json_win = null;
|
|
68983
69041
|
priv.json_modal = null;
|
|
69042
|
+
priv.drills_in_flight.clear();
|
|
68984
69043
|
if (jv && (0, _yuneta_gobj_js.is_gobj)(jv)) try {
|
|
68985
69044
|
(0, _yuneta_gobj_js.gobj_stop)(jv);
|
|
68986
69045
|
(0, _yuneta_gobj_js.gobj_destroy)(jv);
|
|
@@ -69271,8 +69330,9 @@ function ac_set_operation_mode(gobj, event, kw, src) {
|
|
|
69271
69330
|
var LEGEND_GLYPH_STYLE = `font-size:${YUI_TOOLBAR_ICON_SIZE}; line-height:1; color:inherit;`;
|
|
69272
69331
|
var LEGEND_NAME_STYLE = "font-size:1rem; line-height:1.2;";
|
|
69273
69332
|
var LEGEND_COUNT_STYLE = "margin-left:.4rem; font-size:.875rem; opacity:.8;";
|
|
69274
|
-
var LEGEND_MAIN_NAME_STYLE = "
|
|
69333
|
+
var LEGEND_MAIN_NAME_STYLE = LEGEND_NAME_STYLE + " font-weight:700;";
|
|
69275
69334
|
var LEGEND_STAR_MAIN_STYLE = LEGEND_GLYPH_STYLE + " color:var(--bulma-warning-on-scheme, var(--bulma-warning, #ffdd57));";
|
|
69335
|
+
var LEGEND_FOCUSED_STYLE = "box-shadow: inset 0 0 0 2px var(--bulma-text, #2e333d);";
|
|
69276
69336
|
function refresh_legend(gobj) {
|
|
69277
69337
|
let priv = gobj.priv;
|
|
69278
69338
|
let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
@@ -69314,7 +69374,7 @@ function refresh_legend(gobj) {
|
|
|
69314
69374
|
let body_attrs = {
|
|
69315
69375
|
class: "GRAPH_LEGEND_ITEM button" + (focused ? " GRAPH_LEGEND_FOCUSED" : "") + (is_main ? " GRAPH_LEGEND_MAIN" : ""),
|
|
69316
69376
|
type: "button",
|
|
69317
|
-
style: "gap:0; flex:0 0 auto;" + (focused ? "
|
|
69377
|
+
style: "gap:0; flex:0 0 auto;" + (focused ? " " + LEGEND_FOCUSED_STYLE : ""),
|
|
69318
69378
|
title: (0, i18next.t)(body_key),
|
|
69319
69379
|
"data-i18n-title": body_key,
|
|
69320
69380
|
"aria-label": topic_name,
|
|
@@ -69346,7 +69406,7 @@ function refresh_legend(gobj) {
|
|
|
69346
69406
|
{
|
|
69347
69407
|
class: "GRAPH_LEGEND_STAR button",
|
|
69348
69408
|
type: "button",
|
|
69349
|
-
style: "padding:0 .5rem;
|
|
69409
|
+
style: "padding:0 .5rem; " + LEGEND_FOCUSED_STYLE,
|
|
69350
69410
|
title: (0, i18next.t)("main topic"),
|
|
69351
69411
|
"data-i18n-title": "main topic",
|
|
69352
69412
|
"aria-label": (0, i18next.t)("main topic"),
|
package/dist/gobj-ui.es.js
CHANGED
|
@@ -11135,8 +11135,8 @@ function ac_load_data$2(gobj, event, kw, src) {
|
|
|
11135
11135
|
******************************************************/
|
|
11136
11136
|
function ac_add_serie(gobj, event, kw, src) {
|
|
11137
11137
|
let uplot = gobj_read_attr(gobj, "uplot");
|
|
11138
|
-
let idx;
|
|
11139
|
-
for (
|
|
11138
|
+
let idx = 0;
|
|
11139
|
+
for (; idx < uplot.series.length; idx++) {
|
|
11140
11140
|
let serie = uplot.series[idx];
|
|
11141
11141
|
if (serie.id && serie.id === kw.id) {
|
|
11142
11142
|
log_error("Serie '" + kw.id + "' already exists");
|
|
@@ -23786,7 +23786,8 @@ var PRIVATE_DATA$6 = {
|
|
|
23786
23786
|
schema_gobj: null,
|
|
23787
23787
|
json_gobj: null,
|
|
23788
23788
|
json_win: null,
|
|
23789
|
-
json_modal: null
|
|
23789
|
+
json_modal: null,
|
|
23790
|
+
drills_in_flight: null
|
|
23790
23791
|
};
|
|
23791
23792
|
var __gclass__$6 = null;
|
|
23792
23793
|
/******************************
|
|
@@ -23799,6 +23800,7 @@ function mt_create$6(gobj) {
|
|
|
23799
23800
|
gobj.priv.form_writes = {};
|
|
23800
23801
|
gobj.priv.reread_on_session = false;
|
|
23801
23802
|
gobj.priv.conn_shell = null;
|
|
23803
|
+
gobj.priv.drills_in_flight = /* @__PURE__ */ new Set();
|
|
23802
23804
|
build_ui$6(gobj);
|
|
23803
23805
|
let subscriber = gobj_read_pointer_attr(gobj, "subscriber");
|
|
23804
23806
|
if (!subscriber) subscriber = gobj_parent(gobj);
|
|
@@ -25097,6 +25099,7 @@ function close_json_viewer$1(gobj) {
|
|
|
25097
25099
|
priv.json_gobj = null;
|
|
25098
25100
|
priv.json_win = null;
|
|
25099
25101
|
priv.json_modal = null;
|
|
25102
|
+
priv.drills_in_flight.clear();
|
|
25100
25103
|
if (win && is_gobj(win)) try {
|
|
25101
25104
|
if (gobj_is_running(win)) gobj_stop(win);
|
|
25102
25105
|
gobj_destroy(win);
|
|
@@ -25178,7 +25181,25 @@ function request_print_tranger$1(gobj, path) {
|
|
|
25178
25181
|
if (ret) {
|
|
25179
25182
|
log_error(ret);
|
|
25180
25183
|
answer_print_tranger_refused$1(gobj, path, { error: refusal_text$1(ret) });
|
|
25184
|
+
return;
|
|
25181
25185
|
}
|
|
25186
|
+
if (path) priv.drills_in_flight.add(path);
|
|
25187
|
+
}
|
|
25188
|
+
/************************************************************
|
|
25189
|
+
* The session dropped: a drill already sent will never be answered
|
|
25190
|
+
* (the transport answers nothing in flight on a close), and its stub
|
|
25191
|
+
* would show "loading" for the life of the viewer. Answered here, so a
|
|
25192
|
+
* click once the session is back asks again. Idempotent: both edges of
|
|
25193
|
+
* one drop may arrive.
|
|
25194
|
+
************************************************************/
|
|
25195
|
+
function answer_drills_in_flight$1(gobj) {
|
|
25196
|
+
let priv = gobj.priv;
|
|
25197
|
+
let paths = Array.from(priv.drills_in_flight);
|
|
25198
|
+
priv.drills_in_flight.clear();
|
|
25199
|
+
paths.forEach((path) => {
|
|
25200
|
+
log_warning(`${gobj_short_name(gobj)}: transport closed, the drill '${path}' of the raw json is lost`);
|
|
25201
|
+
answer_print_tranger_refused$1(gobj, path, { i18n: "the connection dropped" });
|
|
25202
|
+
});
|
|
25182
25203
|
}
|
|
25183
25204
|
/***************************************************************
|
|
25184
25205
|
* The last gate before a write leaves for the yuno. The per-topic
|
|
@@ -25220,6 +25241,12 @@ function ac_mt_command_answer$2(gobj, event, kw, src) {
|
|
|
25220
25241
|
let jv = gobj.priv.json_gobj;
|
|
25221
25242
|
if (!jv || !is_gobj(jv) || gobj_is_destroying(jv)) return 0;
|
|
25222
25243
|
let path = kw_get_str(gobj, kw_command, "path", "", 0);
|
|
25244
|
+
if (path) {
|
|
25245
|
+
if (!gobj.priv.drills_in_flight.delete(path) && result < 0) {
|
|
25246
|
+
log_warning(`${gobj_short_name(gobj)}: late failure of the drill '${path}' dropped, it was already answered: ${comment || ""}`);
|
|
25247
|
+
return 0;
|
|
25248
|
+
}
|
|
25249
|
+
} else gobj.priv.drills_in_flight.clear();
|
|
25223
25250
|
if (result < 0) {
|
|
25224
25251
|
if (path) gobj_send_event(jv, "EV_SUBTREE_ERROR", {
|
|
25225
25252
|
path,
|
|
@@ -25478,6 +25505,7 @@ function ac_transport_state$2(gobj, event, kw, src) {
|
|
|
25478
25505
|
refresh_toolbar_buttons(gobj, connected);
|
|
25479
25506
|
if (!connected) {
|
|
25480
25507
|
gobj.priv.reread_on_session = true;
|
|
25508
|
+
answer_drills_in_flight$1(gobj);
|
|
25481
25509
|
abandon_form_writes(gobj.priv.form_writes).forEach((w) => {
|
|
25482
25510
|
log_warning(`${gobj_short_name(gobj)}: transport closed, the write ${w.form_write} of '${w.topic_name}' is lost`);
|
|
25483
25511
|
answer_form_write(gobj, get_gobj_formtable(gobj, w.topic_name), w.form_write, false);
|
|
@@ -25871,6 +25899,7 @@ function ac_json_closed$1(gobj, event, kw, src) {
|
|
|
25871
25899
|
priv.json_gobj = null;
|
|
25872
25900
|
priv.json_win = null;
|
|
25873
25901
|
priv.json_modal = null;
|
|
25902
|
+
priv.drills_in_flight.clear();
|
|
25874
25903
|
if (jv && is_gobj(jv)) try {
|
|
25875
25904
|
gobj_stop(jv);
|
|
25876
25905
|
gobj_destroy(jv);
|
|
@@ -32812,8 +32841,6 @@ var eventemitter3_default = (/* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJS
|
|
|
32812
32841
|
if ("undefined" !== typeof module) module.exports = EventEmitter;
|
|
32813
32842
|
})))(), 1)).default;
|
|
32814
32843
|
var ARRAY_TYPE = typeof Float32Array !== "undefined" ? Float32Array : Array;
|
|
32815
|
-
Math.PI / 180;
|
|
32816
|
-
180 / Math.PI;
|
|
32817
32844
|
//#endregion
|
|
32818
32845
|
//#region node_modules/gl-matrix/esm/mat3.js
|
|
32819
32846
|
/**
|
|
@@ -50088,12 +50115,12 @@ PERFORMANCE OF THIS SOFTWARE.
|
|
|
50088
50115
|
},
|
|
50089
50116
|
trys: [],
|
|
50090
50117
|
ops: []
|
|
50091
|
-
}, f, y, t, g
|
|
50092
|
-
return g = {
|
|
50118
|
+
}, f, y, t, g = {
|
|
50093
50119
|
next: verb(0),
|
|
50094
50120
|
"throw": verb(1),
|
|
50095
50121
|
"return": verb(2)
|
|
50096
|
-
}
|
|
50122
|
+
};
|
|
50123
|
+
return typeof Symbol === "function" && (g[Symbol.iterator] = function() {
|
|
50097
50124
|
return this;
|
|
50098
50125
|
}), g;
|
|
50099
50126
|
function verb(n) {
|
|
@@ -67463,6 +67490,7 @@ var PRIVATE_DATA$3 = {
|
|
|
67463
67490
|
json_gobj: null,
|
|
67464
67491
|
json_win: null,
|
|
67465
67492
|
json_modal: null,
|
|
67493
|
+
drills_in_flight: null,
|
|
67466
67494
|
with_treedb_tables: false,
|
|
67467
67495
|
canvas_id: null,
|
|
67468
67496
|
operation_mode: null,
|
|
@@ -67482,6 +67510,7 @@ var __gclass__$3 = null;
|
|
|
67482
67510
|
***************************************************************/
|
|
67483
67511
|
function mt_create$3(gobj) {
|
|
67484
67512
|
let priv = gobj.priv;
|
|
67513
|
+
priv.drills_in_flight = /* @__PURE__ */ new Set();
|
|
67485
67514
|
let subscriber = gobj_read_pointer_attr(gobj, "subscriber");
|
|
67486
67515
|
if (!subscriber) subscriber = gobj_parent(gobj);
|
|
67487
67516
|
gobj_subscribe_event(gobj, null, {}, subscriber);
|
|
@@ -67640,9 +67669,13 @@ function refresh_raw_json_button(gobj, connected) {
|
|
|
67640
67669
|
* "Raw JSON" button disables the moment the session drops and re-enables on
|
|
67641
67670
|
* reconnect. The library view must not subscribe to the C_IEVENT_CLI itself
|
|
67642
67671
|
* (that forwards the subscription upstream and breaks the session).
|
|
67672
|
+
* On the drop, the drills of the raw-json viewer still in flight are
|
|
67673
|
+
* answered: the transport answers nothing in flight on a close.
|
|
67643
67674
|
************************************************************/
|
|
67644
67675
|
function ac_transport_state$1(gobj, event, kw, src) {
|
|
67645
|
-
|
|
67676
|
+
let connected = !!(kw && kw.connected);
|
|
67677
|
+
refresh_raw_json_button(gobj, connected);
|
|
67678
|
+
if (!connected) answer_drills_in_flight(gobj);
|
|
67646
67679
|
return 0;
|
|
67647
67680
|
}
|
|
67648
67681
|
/************************************************************
|
|
@@ -68345,6 +68378,7 @@ function close_json_viewer(gobj) {
|
|
|
68345
68378
|
priv.json_gobj = null;
|
|
68346
68379
|
priv.json_win = null;
|
|
68347
68380
|
priv.json_modal = null;
|
|
68381
|
+
priv.drills_in_flight.clear();
|
|
68348
68382
|
if (win && is_gobj(win)) try {
|
|
68349
68383
|
if (gobj_is_running(win)) gobj_stop(win);
|
|
68350
68384
|
gobj_destroy(win);
|
|
@@ -68412,7 +68446,25 @@ function request_print_tranger(gobj, path) {
|
|
|
68412
68446
|
if (ret) {
|
|
68413
68447
|
log_error(ret);
|
|
68414
68448
|
answer_print_tranger_refused(gobj, path, { error: refusal_text(ret) });
|
|
68449
|
+
return;
|
|
68415
68450
|
}
|
|
68451
|
+
if (path) priv.drills_in_flight.add(path);
|
|
68452
|
+
}
|
|
68453
|
+
/************************************************************
|
|
68454
|
+
* The session dropped: a drill already sent will never be answered
|
|
68455
|
+
* (the transport answers nothing in flight on a close), and its stub
|
|
68456
|
+
* would show "loading" for the life of the viewer. Answered here, so a
|
|
68457
|
+
* click once the session is back asks again. Idempotent: both edges of
|
|
68458
|
+
* one drop may arrive.
|
|
68459
|
+
************************************************************/
|
|
68460
|
+
function answer_drills_in_flight(gobj) {
|
|
68461
|
+
let priv = gobj.priv;
|
|
68462
|
+
let paths = Array.from(priv.drills_in_flight);
|
|
68463
|
+
priv.drills_in_flight.clear();
|
|
68464
|
+
paths.forEach((path) => {
|
|
68465
|
+
log_warning(`${gobj_short_name(gobj)}: transport closed, the drill '${path}' of the raw json is lost`);
|
|
68466
|
+
answer_print_tranger_refused(gobj, path, { i18n: "the connection dropped" });
|
|
68467
|
+
});
|
|
68416
68468
|
}
|
|
68417
68469
|
/************************************************************
|
|
68418
68470
|
* Populate layout dropdown from child's available layouts
|
|
@@ -68790,6 +68842,12 @@ function ac_mt_command_answer$1(gobj, event, kw, src) {
|
|
|
68790
68842
|
let jv = priv.json_gobj;
|
|
68791
68843
|
if (!jv || !is_gobj(jv) || gobj_is_destroying(jv)) return 0;
|
|
68792
68844
|
let path = kw_get_str(gobj, kw_command, "path", "", 0);
|
|
68845
|
+
if (path) {
|
|
68846
|
+
if (!priv.drills_in_flight.delete(path) && result < 0) {
|
|
68847
|
+
log_warning(`${gobj_short_name(gobj)}: late failure of the drill '${path}' dropped, it was already answered: ${comment || ""}`);
|
|
68848
|
+
return 0;
|
|
68849
|
+
}
|
|
68850
|
+
} else priv.drills_in_flight.clear();
|
|
68793
68851
|
if (result < 0) {
|
|
68794
68852
|
if (path) gobj_send_event(jv, "EV_SUBTREE_ERROR", {
|
|
68795
68853
|
path,
|
|
@@ -68976,6 +69034,7 @@ function ac_json_closed(gobj, event, kw, src) {
|
|
|
68976
69034
|
priv.json_gobj = null;
|
|
68977
69035
|
priv.json_win = null;
|
|
68978
69036
|
priv.json_modal = null;
|
|
69037
|
+
priv.drills_in_flight.clear();
|
|
68979
69038
|
if (jv && is_gobj(jv)) try {
|
|
68980
69039
|
gobj_stop(jv);
|
|
68981
69040
|
gobj_destroy(jv);
|
|
@@ -69266,8 +69325,9 @@ function ac_set_operation_mode(gobj, event, kw, src) {
|
|
|
69266
69325
|
var LEGEND_GLYPH_STYLE = `font-size:${YUI_TOOLBAR_ICON_SIZE}; line-height:1; color:inherit;`;
|
|
69267
69326
|
var LEGEND_NAME_STYLE = "font-size:1rem; line-height:1.2;";
|
|
69268
69327
|
var LEGEND_COUNT_STYLE = "margin-left:.4rem; font-size:.875rem; opacity:.8;";
|
|
69269
|
-
var LEGEND_MAIN_NAME_STYLE = "
|
|
69328
|
+
var LEGEND_MAIN_NAME_STYLE = LEGEND_NAME_STYLE + " font-weight:700;";
|
|
69270
69329
|
var LEGEND_STAR_MAIN_STYLE = LEGEND_GLYPH_STYLE + " color:var(--bulma-warning-on-scheme, var(--bulma-warning, #ffdd57));";
|
|
69330
|
+
var LEGEND_FOCUSED_STYLE = "box-shadow: inset 0 0 0 2px var(--bulma-text, #2e333d);";
|
|
69271
69331
|
function refresh_legend(gobj) {
|
|
69272
69332
|
let priv = gobj.priv;
|
|
69273
69333
|
let $container = gobj_read_attr(gobj, "$container");
|
|
@@ -69309,7 +69369,7 @@ function refresh_legend(gobj) {
|
|
|
69309
69369
|
let body_attrs = {
|
|
69310
69370
|
class: "GRAPH_LEGEND_ITEM button" + (focused ? " GRAPH_LEGEND_FOCUSED" : "") + (is_main ? " GRAPH_LEGEND_MAIN" : ""),
|
|
69311
69371
|
type: "button",
|
|
69312
|
-
style: "gap:0; flex:0 0 auto;" + (focused ? "
|
|
69372
|
+
style: "gap:0; flex:0 0 auto;" + (focused ? " " + LEGEND_FOCUSED_STYLE : ""),
|
|
69313
69373
|
title: t(body_key),
|
|
69314
69374
|
"data-i18n-title": body_key,
|
|
69315
69375
|
"aria-label": topic_name,
|
|
@@ -69341,7 +69401,7 @@ function refresh_legend(gobj) {
|
|
|
69341
69401
|
{
|
|
69342
69402
|
class: "GRAPH_LEGEND_STAR button",
|
|
69343
69403
|
type: "button",
|
|
69344
|
-
style: "padding:0 .5rem;
|
|
69404
|
+
style: "padding:0 .5rem; " + LEGEND_FOCUSED_STYLE,
|
|
69345
69405
|
title: t("main topic"),
|
|
69346
69406
|
"data-i18n-title": "main topic",
|
|
69347
69407
|
"aria-label": t("main topic"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yuneta/gobj-ui",
|
|
3
|
-
"version": "7.25.
|
|
3
|
+
"version": "7.25.23",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/gobj-ui.cjs.js",
|
|
6
6
|
"module": "dist/gobj-ui.es.js",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@rollup/plugin-terser": "^1.0.0",
|
|
32
32
|
"@vitest/coverage-v8": "^4.1.10",
|
|
33
|
-
"@yuneta/gobj-js": "^7.25.
|
|
34
|
-
"vite": "^8.
|
|
33
|
+
"@yuneta/gobj-js": "^7.25.8",
|
|
34
|
+
"vite": "^8.3.1",
|
|
35
35
|
"vitest": "^4.1.10"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"@yuneta/gobj-js": "^7.22.2",
|
|
40
40
|
"bulma": "^1.0.4",
|
|
41
41
|
"i18next": "^26.3.6",
|
|
42
|
-
"maplibre-gl": "^6.
|
|
42
|
+
"maplibre-gl": "^6.11.2",
|
|
43
43
|
"tabulator-tables": "^6.5.3",
|
|
44
44
|
"tom-select": "^2.6.2",
|
|
45
45
|
"uplot": "^1.6.32",
|
|
@@ -183,6 +183,7 @@ let PRIVATE_DATA = {
|
|
|
183
183
|
json_gobj: null, /* C_YUI_JSON viewer of the raw tranger (or null) */
|
|
184
184
|
json_win: null, /* C_YUI_WINDOW hosting it, desktop (or null) */
|
|
185
185
|
json_modal: null, /* shell modal hosting it, mobile (or null) */
|
|
186
|
+
drills_in_flight: null, /* Set of the viewer's drilled paths sent, not answered */
|
|
186
187
|
with_treedb_tables: false,
|
|
187
188
|
canvas_id: null,
|
|
188
189
|
operation_mode: null,
|
|
@@ -214,6 +215,10 @@ function mt_create(gobj)
|
|
|
214
215
|
{
|
|
215
216
|
let priv = gobj.priv;
|
|
216
217
|
|
|
218
|
+
/* The drills of the raw-json viewer sent and not yet answered:
|
|
219
|
+
* answered on the disconnect edge (answer_drills_in_flight). */
|
|
220
|
+
priv.drills_in_flight = new Set();
|
|
221
|
+
|
|
217
222
|
/*
|
|
218
223
|
* CHILD subscription model
|
|
219
224
|
*/
|
|
@@ -474,10 +479,16 @@ function refresh_raw_json_button(gobj, connected)
|
|
|
474
479
|
* "Raw JSON" button disables the moment the session drops and re-enables on
|
|
475
480
|
* reconnect. The library view must not subscribe to the C_IEVENT_CLI itself
|
|
476
481
|
* (that forwards the subscription upstream and breaks the session).
|
|
482
|
+
* On the drop, the drills of the raw-json viewer still in flight are
|
|
483
|
+
* answered: the transport answers nothing in flight on a close.
|
|
477
484
|
************************************************************/
|
|
478
485
|
function ac_transport_state(gobj, event, kw, src)
|
|
479
486
|
{
|
|
480
|
-
|
|
487
|
+
let connected = !!(kw && kw.connected);
|
|
488
|
+
refresh_raw_json_button(gobj, connected);
|
|
489
|
+
if(!connected) {
|
|
490
|
+
answer_drills_in_flight(gobj);
|
|
491
|
+
}
|
|
481
492
|
return 0;
|
|
482
493
|
}
|
|
483
494
|
|
|
@@ -1270,6 +1281,7 @@ function close_json_viewer(gobj)
|
|
|
1270
1281
|
priv.json_gobj = null;
|
|
1271
1282
|
priv.json_win = null;
|
|
1272
1283
|
priv.json_modal = null;
|
|
1284
|
+
priv.drills_in_flight.clear();
|
|
1273
1285
|
|
|
1274
1286
|
if(win && is_gobj(win)) {
|
|
1275
1287
|
try {
|
|
@@ -1381,9 +1393,32 @@ function request_print_tranger(gobj, path)
|
|
|
1381
1393
|
if(ret) {
|
|
1382
1394
|
log_error(ret);
|
|
1383
1395
|
answer_print_tranger_refused(gobj, path, {error: refusal_text(ret)});
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
if(path) {
|
|
1399
|
+
priv.drills_in_flight.add(path);
|
|
1384
1400
|
}
|
|
1385
1401
|
}
|
|
1386
1402
|
|
|
1403
|
+
/************************************************************
|
|
1404
|
+
* The session dropped: a drill already sent will never be answered
|
|
1405
|
+
* (the transport answers nothing in flight on a close), and its stub
|
|
1406
|
+
* would show "loading" for the life of the viewer. Answered here, so a
|
|
1407
|
+
* click once the session is back asks again. Idempotent: both edges of
|
|
1408
|
+
* one drop may arrive.
|
|
1409
|
+
************************************************************/
|
|
1410
|
+
function answer_drills_in_flight(gobj)
|
|
1411
|
+
{
|
|
1412
|
+
let priv = gobj.priv;
|
|
1413
|
+
let paths = Array.from(priv.drills_in_flight);
|
|
1414
|
+
priv.drills_in_flight.clear();
|
|
1415
|
+
paths.forEach((path) => {
|
|
1416
|
+
log_warning(`${gobj_short_name(gobj)}: transport closed, the drill ` +
|
|
1417
|
+
`'${path}' of the raw json is lost`);
|
|
1418
|
+
answer_print_tranger_refused(gobj, path, {i18n: "the connection dropped"});
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1387
1422
|
/************************************************************
|
|
1388
1423
|
* Populate layout dropdown from child's available layouts
|
|
1389
1424
|
************************************************************/
|
|
@@ -2100,6 +2135,19 @@ function ac_mt_command_answer(gobj, event, kw, src)
|
|
|
2100
2135
|
return 0; /* viewer closed before its answer landed: benign */
|
|
2101
2136
|
}
|
|
2102
2137
|
let path = kw_get_str(gobj, kw_command, "path", "", 0);
|
|
2138
|
+
if(path) {
|
|
2139
|
+
let in_flight = priv.drills_in_flight.delete(path);
|
|
2140
|
+
if(!in_flight && result < 0) {
|
|
2141
|
+
/* Already answered (the drop answered it, or the viewer
|
|
2142
|
+
* was refilled): a second answer would log it twice. */
|
|
2143
|
+
log_warning(`${gobj_short_name(gobj)}: late failure of the drill ` +
|
|
2144
|
+
`'${path}' dropped, it was already answered: ${comment || ""}`);
|
|
2145
|
+
return 0;
|
|
2146
|
+
}
|
|
2147
|
+
} else {
|
|
2148
|
+
/* A whole document replaces every stub the drills were for. */
|
|
2149
|
+
priv.drills_in_flight.clear();
|
|
2150
|
+
}
|
|
2103
2151
|
if(result < 0) {
|
|
2104
2152
|
if(path) {
|
|
2105
2153
|
gobj_send_event(jv, "EV_SUBTREE_ERROR",
|
|
@@ -2411,6 +2459,7 @@ function ac_json_closed(gobj, event, kw, src)
|
|
|
2411
2459
|
priv.json_gobj = null;
|
|
2412
2460
|
priv.json_win = null;
|
|
2413
2461
|
priv.json_modal = null;
|
|
2462
|
+
priv.drills_in_flight.clear();
|
|
2414
2463
|
if(jv && is_gobj(jv)) {
|
|
2415
2464
|
try {
|
|
2416
2465
|
/* STOP before destroy — the viewer was STARTED in open_json_viewer
|
|
@@ -137,6 +137,7 @@ let PRIVATE_DATA = {
|
|
|
137
137
|
json_gobj: null, /* C_YUI_JSON raw-tranger viewer (or null) */
|
|
138
138
|
json_win: null, /* C_YUI_WINDOW hosting it, desktop (or null) */
|
|
139
139
|
json_modal: null, /* shell modal hosting it, mobile (or null) */
|
|
140
|
+
drills_in_flight: null, /* Set of the viewer's drilled paths sent, not answered */
|
|
140
141
|
};
|
|
141
142
|
|
|
142
143
|
let __gclass__ = null;
|
|
@@ -166,6 +167,9 @@ function mt_create(gobj)
|
|
|
166
167
|
* (reread_open_topics), never out of session. */
|
|
167
168
|
gobj.priv.reread_on_session = false;
|
|
168
169
|
gobj.priv.conn_shell = null; /* the shell whose EV_CONNECTION_STATE we hear */
|
|
170
|
+
/* The drills of the raw-json viewer sent and not yet answered:
|
|
171
|
+
* answered on the disconnect edge (answer_drills_in_flight). */
|
|
172
|
+
gobj.priv.drills_in_flight = new Set();
|
|
169
173
|
|
|
170
174
|
build_ui(gobj);
|
|
171
175
|
|
|
@@ -1887,6 +1891,7 @@ function close_json_viewer(gobj)
|
|
|
1887
1891
|
priv.json_gobj = null;
|
|
1888
1892
|
priv.json_win = null;
|
|
1889
1893
|
priv.json_modal = null;
|
|
1894
|
+
priv.drills_in_flight.clear();
|
|
1890
1895
|
|
|
1891
1896
|
if(win && is_gobj(win)) {
|
|
1892
1897
|
try {
|
|
@@ -2011,9 +2016,32 @@ function request_print_tranger(gobj, path)
|
|
|
2011
2016
|
if(ret) {
|
|
2012
2017
|
log_error(ret);
|
|
2013
2018
|
answer_print_tranger_refused(gobj, path, {error: refusal_text(ret)});
|
|
2019
|
+
return;
|
|
2020
|
+
}
|
|
2021
|
+
if(path) {
|
|
2022
|
+
priv.drills_in_flight.add(path);
|
|
2014
2023
|
}
|
|
2015
2024
|
}
|
|
2016
2025
|
|
|
2026
|
+
/************************************************************
|
|
2027
|
+
* The session dropped: a drill already sent will never be answered
|
|
2028
|
+
* (the transport answers nothing in flight on a close), and its stub
|
|
2029
|
+
* would show "loading" for the life of the viewer. Answered here, so a
|
|
2030
|
+
* click once the session is back asks again. Idempotent: both edges of
|
|
2031
|
+
* one drop may arrive.
|
|
2032
|
+
************************************************************/
|
|
2033
|
+
function answer_drills_in_flight(gobj)
|
|
2034
|
+
{
|
|
2035
|
+
let priv = gobj.priv;
|
|
2036
|
+
let paths = Array.from(priv.drills_in_flight);
|
|
2037
|
+
priv.drills_in_flight.clear();
|
|
2038
|
+
paths.forEach((path) => {
|
|
2039
|
+
log_warning(`${gobj_short_name(gobj)}: transport closed, the drill ` +
|
|
2040
|
+
`'${path}' of the raw json is lost`);
|
|
2041
|
+
answer_print_tranger_refused(gobj, path, {i18n: "the connection dropped"});
|
|
2042
|
+
});
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2017
2045
|
|
|
2018
2046
|
|
|
2019
2047
|
|
|
@@ -2080,6 +2108,19 @@ function ac_mt_command_answer(gobj, event, kw, src)
|
|
|
2080
2108
|
return 0; /* viewer closed before its answer landed: benign */
|
|
2081
2109
|
}
|
|
2082
2110
|
let path = kw_get_str(gobj, kw_command, "path", "", 0);
|
|
2111
|
+
if(path) {
|
|
2112
|
+
let in_flight = gobj.priv.drills_in_flight.delete(path);
|
|
2113
|
+
if(!in_flight && result < 0) {
|
|
2114
|
+
/* Already answered (the drop answered it, or the viewer
|
|
2115
|
+
* was refilled): a second answer would log it twice. */
|
|
2116
|
+
log_warning(`${gobj_short_name(gobj)}: late failure of the drill ` +
|
|
2117
|
+
`'${path}' dropped, it was already answered: ${comment || ""}`);
|
|
2118
|
+
return 0;
|
|
2119
|
+
}
|
|
2120
|
+
} else {
|
|
2121
|
+
/* A whole document replaces every stub the drills were for. */
|
|
2122
|
+
gobj.priv.drills_in_flight.clear();
|
|
2123
|
+
}
|
|
2083
2124
|
if(result < 0) {
|
|
2084
2125
|
if(path) {
|
|
2085
2126
|
gobj_send_event(jv, "EV_SUBTREE_ERROR",
|
|
@@ -2552,12 +2593,14 @@ function ac_transport_state(gobj, event, kw, src)
|
|
|
2552
2593
|
* the backend: its form stayed open and busy for ever. Answered
|
|
2553
2594
|
* refused: the form stays open on what
|
|
2554
2595
|
* was typed, and the person saves again when the session is back.
|
|
2596
|
+
* The same for a drill of the raw-json viewer: its stub is answered.
|
|
2555
2597
|
*/
|
|
2556
2598
|
if(!connected) {
|
|
2557
2599
|
/* What happens in the store while the session is down reaches
|
|
2558
2600
|
* no table: its node events are published to nobody. Every open
|
|
2559
2601
|
* table is read again when the session is back. */
|
|
2560
2602
|
gobj.priv.reread_on_session = true;
|
|
2603
|
+
answer_drills_in_flight(gobj);
|
|
2561
2604
|
abandon_form_writes(gobj.priv.form_writes).forEach((w) => {
|
|
2562
2605
|
log_warning(`${gobj_short_name(gobj)}: transport closed, the write ${w.form_write} of '${w.topic_name}' is lost`);
|
|
2563
2606
|
answer_form_write(
|
|
@@ -3125,6 +3168,7 @@ function ac_json_closed(gobj, event, kw, src)
|
|
|
3125
3168
|
priv.json_gobj = null;
|
|
3126
3169
|
priv.json_win = null;
|
|
3127
3170
|
priv.json_modal = null;
|
|
3171
|
+
priv.drills_in_flight.clear();
|
|
3128
3172
|
if(jv && is_gobj(jv)) {
|
|
3129
3173
|
try {
|
|
3130
3174
|
/* STOP before destroy — the viewer was STARTED in open_json_viewer
|
|
@@ -13,6 +13,12 @@
|
|
|
13
13
|
* stayed on "loading" for the life of the viewer, and no click --
|
|
14
14
|
* not even after the reconnect -- asked again.
|
|
15
15
|
*
|
|
16
|
+
* Before gobj-ui 7.25.22 a drill already SENT when the session
|
|
17
|
+
* dropped was never answered either: the transport answers nothing
|
|
18
|
+
* in flight on a close, and neither host remembered what it had
|
|
19
|
+
* asked. Each host now keeps its drills in flight and answers them
|
|
20
|
+
* on the disconnect edge.
|
|
21
|
+
*
|
|
16
22
|
* Driven through the real hosts and the real viewer on a document
|
|
17
23
|
* double, with a fake transport whose state is the one the hosts
|
|
18
24
|
* read and which refuses on demand.
|
|
@@ -229,4 +235,114 @@ for(const gclass of ["C_YUI_TREEDB_TOPICS", "C_YUI_TREEDB_GRAPH"]) {
|
|
|
229
235
|
expect(logged.filter((l) => l.level === "error")).toEqual([]);
|
|
230
236
|
});
|
|
231
237
|
});
|
|
238
|
+
|
|
239
|
+
describe(`${gclass}: a drill in flight when the session drops is answered`, () => {
|
|
240
|
+
|
|
241
|
+
test("the drop answers the stub, and a click after the reconnect asks again", () => {
|
|
242
|
+
const {remote, host, viewer} = build(`${gclass}_d`, gclass);
|
|
243
|
+
click_stub(viewer);
|
|
244
|
+
expect(viewer.priv.pending.has("topics")).toBe(true);
|
|
245
|
+
|
|
246
|
+
/* The session drops before the answer: the transport never
|
|
247
|
+
* answers a command in flight. */
|
|
248
|
+
gobj_change_state(remote, "ST_DISCONNECTED");
|
|
249
|
+
gobj_send_event(host, "EV_TRANSPORT_STATE", {connected: false}, host);
|
|
250
|
+
|
|
251
|
+
expect(viewer.priv.pending.has("topics")).toBe(false);
|
|
252
|
+
expect(viewer.priv.errors.get("topics")).toEqual(
|
|
253
|
+
{error: "the connection dropped", is_key: true});
|
|
254
|
+
|
|
255
|
+
/* The same edge again answers nothing more. */
|
|
256
|
+
logged.length = 0;
|
|
257
|
+
gobj_send_event(host, "EV_TRANSPORT_STATE", {connected: false}, host);
|
|
258
|
+
expect(logged.filter((l) => l.level === "error")).toEqual([]);
|
|
259
|
+
|
|
260
|
+
gobj_change_state(remote, "ST_SESSION");
|
|
261
|
+
gobj_send_event(host, "EV_TRANSPORT_STATE", {connected: true}, host);
|
|
262
|
+
click_stub(viewer);
|
|
263
|
+
expect(drills()).toEqual(["topics", "topics"]);
|
|
264
|
+
expect(viewer.priv.pending.has("topics")).toBe(true);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
test("a failure that lands after the drop answered is not answered twice", () => {
|
|
268
|
+
/* gui_agent's routing adapter answers every request in flight
|
|
269
|
+
* as failed on the close, and that answer can land after the
|
|
270
|
+
* edge that already answered the stub. */
|
|
271
|
+
const {remote, host, viewer} = build(`${gclass}_h`, gclass);
|
|
272
|
+
click_stub(viewer);
|
|
273
|
+
const request = commands.find((c) => c.command === "print-tranger");
|
|
274
|
+
gobj_change_state(remote, "ST_DISCONNECTED");
|
|
275
|
+
gobj_send_event(host, "EV_TRANSPORT_STATE", {connected: false}, host);
|
|
276
|
+
|
|
277
|
+
logged.length = 0;
|
|
278
|
+
gobj_send_event(host, "EV_MT_COMMAND_ANSWER", {
|
|
279
|
+
result: -1, comment: "the connection dropped", data: null,
|
|
280
|
+
__md_iev__: {
|
|
281
|
+
command_stack: [{command: "print-tranger", kw: request.kw.__md_command__}]
|
|
282
|
+
}
|
|
283
|
+
}, remote);
|
|
284
|
+
expect(viewer.priv.errors.get("topics")).toEqual(
|
|
285
|
+
{error: "the connection dropped", is_key: true});
|
|
286
|
+
expect(logged.filter((l) => l.level === "error")).toEqual([]);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
test("a drill already answered is not answered again by a drop", () => {
|
|
290
|
+
const {remote, host, viewer} = build(`${gclass}_e`, gclass);
|
|
291
|
+
click_stub(viewer);
|
|
292
|
+
const request = commands.find((c) => c.command === "print-tranger");
|
|
293
|
+
gobj_send_event(host, "EV_MT_COMMAND_ANSWER", {
|
|
294
|
+
result: 0, comment: "", data: {a: 1, b: 2, c: 3},
|
|
295
|
+
__md_iev__: {
|
|
296
|
+
command_stack: [{command: "print-tranger", kw: request.kw.__md_command__}]
|
|
297
|
+
}
|
|
298
|
+
}, remote);
|
|
299
|
+
expect(viewer.priv.pending.has("topics")).toBe(false);
|
|
300
|
+
expect(viewer.priv.errors.has("topics")).toBe(false);
|
|
301
|
+
|
|
302
|
+
gobj_change_state(remote, "ST_DISCONNECTED");
|
|
303
|
+
gobj_send_event(host, "EV_TRANSPORT_STATE", {connected: false}, host);
|
|
304
|
+
expect(viewer.priv.errors.has("topics")).toBe(false);
|
|
305
|
+
expect(logged.filter((l) => l.level === "error")).toEqual([]);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test("a drill that failed is not answered again by a drop", () => {
|
|
309
|
+
const {remote, host, viewer} = build(`${gclass}_f`, gclass);
|
|
310
|
+
click_stub(viewer);
|
|
311
|
+
const request = commands.find((c) => c.command === "print-tranger");
|
|
312
|
+
gobj_send_event(host, "EV_MT_COMMAND_ANSWER", {
|
|
313
|
+
result: -1, comment: "no such path", data: null,
|
|
314
|
+
__md_iev__: {
|
|
315
|
+
command_stack: [{command: "print-tranger", kw: request.kw.__md_command__}]
|
|
316
|
+
}
|
|
317
|
+
}, remote);
|
|
318
|
+
expect(viewer.priv.errors.get("topics")).toEqual(
|
|
319
|
+
{error: "no such path", is_key: false});
|
|
320
|
+
|
|
321
|
+
gobj_change_state(remote, "ST_DISCONNECTED");
|
|
322
|
+
gobj_send_event(host, "EV_TRANSPORT_STATE", {connected: false}, host);
|
|
323
|
+
expect(viewer.priv.errors.get("topics")).toEqual(
|
|
324
|
+
{error: "no such path", is_key: false});
|
|
325
|
+
});
|
|
326
|
+
});
|
|
232
327
|
}
|
|
328
|
+
|
|
329
|
+
/*
|
|
330
|
+
* wattyzer and yunovatios hear the edge from the SHELL
|
|
331
|
+
* (EV_CONNECTION_STATE), not from a host that forwards the transport.
|
|
332
|
+
*/
|
|
333
|
+
describe("C_YUI_TREEDB_TOPICS: the shell's 'down' answers a drill in flight", () => {
|
|
334
|
+
test("EV_CONNECTION_STATE down answers the stub once, with its edge twin", () => {
|
|
335
|
+
const {remote, host, viewer} = build("topics_g", "C_YUI_TREEDB_TOPICS");
|
|
336
|
+
click_stub(viewer);
|
|
337
|
+
|
|
338
|
+
gobj_change_state(remote, "ST_DISCONNECTED");
|
|
339
|
+
gobj_send_event(host, "EV_CONNECTION_STATE", {connected: false}, host);
|
|
340
|
+
expect(viewer.priv.pending.has("topics")).toBe(false);
|
|
341
|
+
expect(viewer.priv.errors.get("topics")).toEqual(
|
|
342
|
+
{error: "the connection dropped", is_key: true});
|
|
343
|
+
|
|
344
|
+
const errors_after_first = logged.filter((l) => l.level === "error").length;
|
|
345
|
+
gobj_send_event(host, "EV_TRANSPORT_STATE", {connected: false}, host);
|
|
346
|
+
expect(logged.filter((l) => l.level === "error").length).toBe(errors_after_first);
|
|
347
|
+
});
|
|
348
|
+
});
|