@yuneta/gobj-ui 7.8.1 → 7.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gobj-ui.cjs.js +204 -5
- package/dist/gobj-ui.es.js +204 -5
- package/package.json +1 -1
- package/src/c_yui_treedb_topic_with_form.js +163 -0
- package/src/c_yui_treedb_topics.js +100 -12
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -14497,6 +14497,7 @@ var attrs_table$6 = [
|
|
|
14497
14497
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "gobj_remote_yuno", 0, null, "Remote yuno for data fetching"),
|
|
14498
14498
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "treedb_name", 0, null, "Remote TreeDB service name"),
|
|
14499
14499
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_JSON, "descs", 0, null, "Description of topics"),
|
|
14500
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_remote_paging", 0, false, "Each topic table pulls its rows a PAGE at a time (`nodes` from/limit) instead of loading the topic whole. Safe against a backend that cannot page: it answers the whole list, which the table reads as one page"),
|
|
14500
14501
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "system", 0, false, "Manage system topics (true) or user topics (false)"),
|
|
14501
14502
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "tabs_style", 0, "is-toggle is-fullwidth", "Bulma tab styling"),
|
|
14502
14503
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_cards_landing", 0, false, "Land on a grid of topic cards (list->detail): a card opens its table, with the tabs bar + a back-to-grid button. Off = tabs only (legacy)."),
|
|
@@ -15310,7 +15311,8 @@ function process_treedb_descs$1(gobj) {
|
|
|
15310
15311
|
with_delete_button: !readonly,
|
|
15311
15312
|
treedb_name,
|
|
15312
15313
|
topic_name: key,
|
|
15313
|
-
desc
|
|
15314
|
+
desc,
|
|
15315
|
+
with_remote_paging: (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "with_remote_paging")
|
|
15314
15316
|
};
|
|
15315
15317
|
let id = `${(0, _yuneta_gobj_js.gobj_name)(gobj)}?${desc.topic_name}`;
|
|
15316
15318
|
let gobj_topic_form = (0, _yuneta_gobj_js.gobj_create_service)(id, "C_YUI_TREEDB_TOPIC_WITH_FORM", kw_topic_form, gobj);
|
|
@@ -15381,6 +15383,8 @@ function register_sub_routes$1(gobj) {
|
|
|
15381
15383
|
function get_nodes$1(gobj, topic_name) {
|
|
15382
15384
|
const treedb_name = gobj.priv.treedb_name;
|
|
15383
15385
|
subscribe_treedb$1(gobj, topic_name);
|
|
15386
|
+
let gobj_topic_form = get_gobj_formtable(gobj, topic_name);
|
|
15387
|
+
if (gobj_topic_form && (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj_topic_form, "with_remote_paging")) return;
|
|
15384
15388
|
treedb_nodes$1(gobj, treedb_name, topic_name, { list_dict: true });
|
|
15385
15389
|
}
|
|
15386
15390
|
/************************************************************
|
|
@@ -15428,7 +15432,7 @@ function get_gobj_formtable(gobj, topic_name) {
|
|
|
15428
15432
|
/************************************************************
|
|
15429
15433
|
* Command to remote service
|
|
15430
15434
|
************************************************************/
|
|
15431
|
-
function treedb_nodes$1(gobj, treedb_name, topic_name, options) {
|
|
15435
|
+
function treedb_nodes$1(gobj, treedb_name, topic_name, options, page) {
|
|
15432
15436
|
let command = "nodes";
|
|
15433
15437
|
let gobj_remote_yuno = (0, _yuneta_gobj_js.gobj_read_pointer_attr)(gobj, "gobj_remote_yuno");
|
|
15434
15438
|
let kw = {
|
|
@@ -15438,8 +15442,17 @@ function treedb_nodes$1(gobj, treedb_name, topic_name, options) {
|
|
|
15438
15442
|
options: options || {}
|
|
15439
15443
|
};
|
|
15440
15444
|
kw.__md_command__ = { topic_name };
|
|
15445
|
+
if (page) {
|
|
15446
|
+
kw.from = page.from;
|
|
15447
|
+
kw.limit = page.limit;
|
|
15448
|
+
kw.__md_command__.req_id = page.req_id;
|
|
15449
|
+
}
|
|
15441
15450
|
let ret = (0, _yuneta_gobj_js.gobj_command)(gobj_remote_yuno, command, kw, gobj);
|
|
15442
|
-
if (ret)
|
|
15451
|
+
if (ret) {
|
|
15452
|
+
(0, _yuneta_gobj_js.log_error)(ret);
|
|
15453
|
+
return -1;
|
|
15454
|
+
}
|
|
15455
|
+
return 0;
|
|
15443
15456
|
}
|
|
15444
15457
|
/************************************************************
|
|
15445
15458
|
* Command to remote service
|
|
@@ -15673,7 +15686,7 @@ function ac_mt_command_answer$2(gobj, event, kw, src) {
|
|
|
15673
15686
|
yui_shell_show_error(yui_shell_of(gobj), comment, { t: i18next.t });
|
|
15674
15687
|
if (command === "update-node" || command === "create-node") {
|
|
15675
15688
|
let failed_topic = (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "topic_name", "", 0);
|
|
15676
|
-
if (failed_topic)
|
|
15689
|
+
if (failed_topic) (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_REFRESH_TOPIC", { topic_name: failed_topic }, gobj);
|
|
15677
15690
|
}
|
|
15678
15691
|
}
|
|
15679
15692
|
return 0;
|
|
@@ -15689,7 +15702,16 @@ function ac_mt_command_answer$2(gobj, event, kw, src) {
|
|
|
15689
15702
|
let topic_name = (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "topic_name", "", _yuneta_gobj_js.kw_flag_t.KW_REQUIRED);
|
|
15690
15703
|
if (result >= 0) {
|
|
15691
15704
|
let gobj_topic_form = (0, _yuneta_gobj_js.gobj_find_child)(gobj, { __gobj_name__: `${(0, _yuneta_gobj_js.gobj_name)(gobj)}?${topic_name}` });
|
|
15692
|
-
|
|
15705
|
+
let answer = nodes_answer(data);
|
|
15706
|
+
let md = (0, _yuneta_gobj_js.kw_get_dict)(gobj, kw_command, "__md_command__", {}, 0);
|
|
15707
|
+
let req_id = (0, _yuneta_gobj_js.kw_get_str)(gobj, md, "req_id", "", 0);
|
|
15708
|
+
if (req_id) (0, _yuneta_gobj_js.gobj_send_event)(gobj_topic_form, "EV_PAGE_LOADED", {
|
|
15709
|
+
req_id,
|
|
15710
|
+
rows: answer.rows,
|
|
15711
|
+
pages: answer.pages,
|
|
15712
|
+
total: answer.total
|
|
15713
|
+
}, gobj);
|
|
15714
|
+
else (0, _yuneta_gobj_js.gobj_send_event)(gobj_topic_form, "EV_LOAD_NODES", answer.rows, gobj);
|
|
15693
15715
|
}
|
|
15694
15716
|
break;
|
|
15695
15717
|
case "create-node":
|
|
@@ -15915,6 +15937,31 @@ function ac_create_record(gobj, event, kw, src) {
|
|
|
15915
15937
|
});
|
|
15916
15938
|
}
|
|
15917
15939
|
/********************************************
|
|
15940
|
+
* A topic table wants a page.
|
|
15941
|
+
*
|
|
15942
|
+
* The transport is ours, so the table asks and we fetch; the answer
|
|
15943
|
+
* finds its way back by the `req_id` we echo. A backend that cannot
|
|
15944
|
+
* page answers the whole list, which the table takes as one page —
|
|
15945
|
+
* which is the truth, and is why the table can ask without knowing
|
|
15946
|
+
* what it is talking to.
|
|
15947
|
+
********************************************/
|
|
15948
|
+
function ac_request_page(gobj, event, kw, src) {
|
|
15949
|
+
let topic_name = kw.topic_name || (0, _yuneta_gobj_js.gobj_read_attr)(src, "topic_name");
|
|
15950
|
+
if (!topic_name || !kw.req_id) {
|
|
15951
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: a page request with no topic or no id`);
|
|
15952
|
+
return -1;
|
|
15953
|
+
}
|
|
15954
|
+
if (treedb_nodes$1(gobj, (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name"), topic_name, { list_dict: true }, {
|
|
15955
|
+
from: kw.from,
|
|
15956
|
+
limit: kw.limit,
|
|
15957
|
+
req_id: kw.req_id
|
|
15958
|
+
}) < 0) (0, _yuneta_gobj_js.gobj_send_event)(src, "EV_PAGE_FAILED", {
|
|
15959
|
+
req_id: kw.req_id,
|
|
15960
|
+
error: "cannot reach the backend"
|
|
15961
|
+
}, gobj);
|
|
15962
|
+
return 0;
|
|
15963
|
+
}
|
|
15964
|
+
/********************************************
|
|
15918
15965
|
* Event from formtable: ONE field of one record, edited in place.
|
|
15919
15966
|
*
|
|
15920
15967
|
* Written as a PARTIAL update and, deliberately, with NO `autolink`.
|
|
@@ -15981,6 +16028,11 @@ function ac_delete_record(gobj, event, kw, src) {
|
|
|
15981
16028
|
* }
|
|
15982
16029
|
********************************************/
|
|
15983
16030
|
function ac_refresh_topic(gobj, event, kw, src) {
|
|
16031
|
+
let gobj_topic_form = get_gobj_formtable(gobj, kw.topic_name);
|
|
16032
|
+
if (gobj_topic_form && (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj_topic_form, "with_remote_paging")) {
|
|
16033
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj_topic_form, "EV_REPULL_PAGE", {}, gobj);
|
|
16034
|
+
return 0;
|
|
16035
|
+
}
|
|
15984
16036
|
treedb_nodes$1(gobj, (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name"), kw.topic_name, { list_dict: true });
|
|
15985
16037
|
return 0;
|
|
15986
16038
|
}
|
|
@@ -16070,6 +16122,11 @@ function create_gclass$6(gclass_name) {
|
|
|
16070
16122
|
ac_update_field,
|
|
16071
16123
|
null
|
|
16072
16124
|
],
|
|
16125
|
+
[
|
|
16126
|
+
"EV_REQUEST_PAGE",
|
|
16127
|
+
ac_request_page,
|
|
16128
|
+
null
|
|
16129
|
+
],
|
|
16073
16130
|
[
|
|
16074
16131
|
"EV_DELETE_RECORD",
|
|
16075
16132
|
ac_delete_record,
|
|
@@ -16144,6 +16201,7 @@ function create_gclass$6(gclass_name) {
|
|
|
16144
16201
|
["EV_CREATE_RECORD", 0],
|
|
16145
16202
|
["EV_UPDATE_RECORD", 0],
|
|
16146
16203
|
["EV_UPDATE_FIELD", 0],
|
|
16204
|
+
["EV_REQUEST_PAGE", 0],
|
|
16147
16205
|
["EV_DELETE_RECORD", 0],
|
|
16148
16206
|
["EV_RECORD_WRITTEN", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT | _yuneta_gobj_js.event_flag_t.EVF_NO_WARN_SUBS],
|
|
16149
16207
|
["EV_REFRESH_TOPIC", 0],
|
|
@@ -16358,6 +16416,8 @@ var attrs_table$5 = [
|
|
|
16358
16416
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_export_button", 0, true, "Button toolbar EXPORT (download as CSV what the table holds)"),
|
|
16359
16417
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_header_filters", 0, true, "Per-column filter box in the table header, on the columns a text/number match means something (not hooks, fkeys or json)"),
|
|
16360
16418
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_inline_edit", 0, true, "Edit a writable scalar cell in place while in edition mode (the record form keeps the rest)"),
|
|
16419
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_remote_paging", 0, false, "Pull the topic a PAGE at a time from the backend (`nodes` from/limit) instead of loading it whole. Needs a backend that pages"),
|
|
16420
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_INTEGER, "page_size", 0, 200, "Rows per page when with_remote_paging. Generous on purpose: a treedb that fits in one page behaves exactly as it did, paginator hidden and every filter seeing every row"),
|
|
16361
16421
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_in_row_edit_icons", 0, true, "Add a last column with internal EDIT/DELETE icon"),
|
|
16362
16422
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "editable", 0, false, "Edit state"),
|
|
16363
16423
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_checkbox", 0, true, "Auxiliary first column to select rows"),
|
|
@@ -16386,6 +16446,8 @@ var attrs_table$5 = [
|
|
|
16386
16446
|
(0, _yuneta_gobj_js.SDATA_END)()
|
|
16387
16447
|
];
|
|
16388
16448
|
var PRIVATE_DATA$5 = {
|
|
16449
|
+
_pending_pages: null,
|
|
16450
|
+
_page_seq: 0,
|
|
16389
16451
|
$container: null,
|
|
16390
16452
|
treedb_name: "",
|
|
16391
16453
|
topic_name: "",
|
|
@@ -17111,6 +17173,25 @@ function create_tabulator(gobj) {
|
|
|
17111
17173
|
let pkey = desc.pkey || "id";
|
|
17112
17174
|
let selectable = with_checkbox ? "highlight" : with_radio ? 1 : false;
|
|
17113
17175
|
let tabulator_settings = (0, _yuneta_gobj_js.json_deep_copy)((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "tabulator_settings"));
|
|
17176
|
+
if ((0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "with_remote_paging")) {
|
|
17177
|
+
let page_size = (0, _yuneta_gobj_js.gobj_read_integer_attr)(gobj, "page_size") || 200;
|
|
17178
|
+
Object.assign(tabulator_settings, {
|
|
17179
|
+
pagination: true,
|
|
17180
|
+
paginationMode: "remote",
|
|
17181
|
+
filterMode: "local",
|
|
17182
|
+
paginationSize: page_size,
|
|
17183
|
+
paginationSizeSelector: [
|
|
17184
|
+
50,
|
|
17185
|
+
100,
|
|
17186
|
+
200,
|
|
17187
|
+
500
|
|
17188
|
+
],
|
|
17189
|
+
ajaxURL: "nodes",
|
|
17190
|
+
ajaxRequestFunc: function(url, config, params) {
|
|
17191
|
+
return request_page(gobj, params.page || 1, params.size || page_size);
|
|
17192
|
+
}
|
|
17193
|
+
});
|
|
17194
|
+
}
|
|
17114
17195
|
Object.assign(tabulator_settings, {
|
|
17115
17196
|
index: pkey,
|
|
17116
17197
|
columns,
|
|
@@ -18312,6 +18393,99 @@ function ac_show_schema(gobj, event, kw, src) {
|
|
|
18312
18393
|
return 0;
|
|
18313
18394
|
}
|
|
18314
18395
|
/************************************************************
|
|
18396
|
+
* Ask the host for one page and park the promise Tabulator wants.
|
|
18397
|
+
*
|
|
18398
|
+
* The transport belongs to the HOST, so the request goes up as an event
|
|
18399
|
+
* and the answer comes back down as one; what lives here is only the
|
|
18400
|
+
* promise, keyed by a correlation id the host echoes.
|
|
18401
|
+
*
|
|
18402
|
+
* Rejected right away when there is nobody to ask: a request that can
|
|
18403
|
+
* never be answered would leave the table spinning for ever and leak
|
|
18404
|
+
* one entry per attempt. Same for the watchdog — the link can stay up
|
|
18405
|
+
* and the answer still never land.
|
|
18406
|
+
************************************************************/
|
|
18407
|
+
var PAGE_TIMEOUT_MS = 2e4;
|
|
18408
|
+
function request_page(gobj, page, size) {
|
|
18409
|
+
let priv = gobj.priv;
|
|
18410
|
+
return new Promise(function(resolve, reject) {
|
|
18411
|
+
if (!priv._pending_pages) priv._pending_pages = {};
|
|
18412
|
+
let req_id = `p${++priv._page_seq}`;
|
|
18413
|
+
let timer = window.setTimeout(function() {
|
|
18414
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_PAGE_TIMEOUT", { req_id }, gobj);
|
|
18415
|
+
}, PAGE_TIMEOUT_MS);
|
|
18416
|
+
priv._pending_pages[req_id] = {
|
|
18417
|
+
resolve,
|
|
18418
|
+
reject,
|
|
18419
|
+
timer
|
|
18420
|
+
};
|
|
18421
|
+
(0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_REQUEST_PAGE", {
|
|
18422
|
+
topic_name: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "topic_name"),
|
|
18423
|
+
req_id,
|
|
18424
|
+
from: (page - 1) * size + 1,
|
|
18425
|
+
limit: size
|
|
18426
|
+
});
|
|
18427
|
+
});
|
|
18428
|
+
}
|
|
18429
|
+
/************************************************************
|
|
18430
|
+
* Settle a parked page request, however it ended.
|
|
18431
|
+
************************************************************/
|
|
18432
|
+
function settle_page(gobj, req_id, value, error) {
|
|
18433
|
+
let priv = gobj.priv;
|
|
18434
|
+
let pend = priv._pending_pages ? priv._pending_pages[req_id] : null;
|
|
18435
|
+
if (!pend) return;
|
|
18436
|
+
delete priv._pending_pages[req_id];
|
|
18437
|
+
if (pend.timer) window.clearTimeout(pend.timer);
|
|
18438
|
+
if (error) {
|
|
18439
|
+
pend.reject(new Error(error));
|
|
18440
|
+
return;
|
|
18441
|
+
}
|
|
18442
|
+
pend.resolve(value);
|
|
18443
|
+
}
|
|
18444
|
+
/************************************************************
|
|
18445
|
+
* Pull the current page again. `replaceData()` re-runs
|
|
18446
|
+
* ajaxRequestFunc for the page the reader is on, so a refresh keeps
|
|
18447
|
+
* their position instead of throwing them back to the first page.
|
|
18448
|
+
************************************************************/
|
|
18449
|
+
function ac_repull_page(gobj, event, kw, src) {
|
|
18450
|
+
let tabulator = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "tabulator");
|
|
18451
|
+
if (!tabulator) return 0;
|
|
18452
|
+
try {
|
|
18453
|
+
tabulator.replaceData();
|
|
18454
|
+
} catch (e) {
|
|
18455
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: cannot re-pull the page: ${e}`);
|
|
18456
|
+
return -1;
|
|
18457
|
+
}
|
|
18458
|
+
return 0;
|
|
18459
|
+
}
|
|
18460
|
+
/************************************************************
|
|
18461
|
+
* The host answered a page.
|
|
18462
|
+
************************************************************/
|
|
18463
|
+
function ac_page_loaded(gobj, event, kw, src) {
|
|
18464
|
+
settle_page(gobj, kw.req_id, {
|
|
18465
|
+
data: (0, _yuneta_gobj_js.is_array)(kw.rows) ? kw.rows : [],
|
|
18466
|
+
last_page: kw.pages || 1,
|
|
18467
|
+
last_row: typeof kw.total === "number" ? kw.total : 0
|
|
18468
|
+
}, null);
|
|
18469
|
+
return 0;
|
|
18470
|
+
}
|
|
18471
|
+
/************************************************************
|
|
18472
|
+
* The host could not answer it.
|
|
18473
|
+
************************************************************/
|
|
18474
|
+
function ac_page_failed(gobj, event, kw, src) {
|
|
18475
|
+
let why = kw && kw.error || "page request failed";
|
|
18476
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${why}`);
|
|
18477
|
+
settle_page(gobj, kw.req_id, null, why);
|
|
18478
|
+
return 0;
|
|
18479
|
+
}
|
|
18480
|
+
/************************************************************
|
|
18481
|
+
* Nobody answered in time.
|
|
18482
|
+
************************************************************/
|
|
18483
|
+
function ac_page_timeout(gobj, event, kw, src) {
|
|
18484
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no answer for page request '${kw.req_id}' in ${PAGE_TIMEOUT_MS}ms`);
|
|
18485
|
+
settle_page(gobj, kw.req_id, null, "page request timed out");
|
|
18486
|
+
return 0;
|
|
18487
|
+
}
|
|
18488
|
+
/************************************************************
|
|
18315
18489
|
* Filter the loaded rows by a term matched against every non-internal
|
|
18316
18490
|
* field. `clearFilter()` with no argument drops only THIS filter: the
|
|
18317
18491
|
* per-column header filters are a separate layer and survive, so a
|
|
@@ -18559,6 +18733,26 @@ function create_gclass$5(gclass_name) {
|
|
|
18559
18733
|
ac_cell_edited,
|
|
18560
18734
|
null
|
|
18561
18735
|
],
|
|
18736
|
+
[
|
|
18737
|
+
"EV_REPULL_PAGE",
|
|
18738
|
+
ac_repull_page,
|
|
18739
|
+
null
|
|
18740
|
+
],
|
|
18741
|
+
[
|
|
18742
|
+
"EV_PAGE_LOADED",
|
|
18743
|
+
ac_page_loaded,
|
|
18744
|
+
null
|
|
18745
|
+
],
|
|
18746
|
+
[
|
|
18747
|
+
"EV_PAGE_FAILED",
|
|
18748
|
+
ac_page_failed,
|
|
18749
|
+
null
|
|
18750
|
+
],
|
|
18751
|
+
[
|
|
18752
|
+
"EV_PAGE_TIMEOUT",
|
|
18753
|
+
ac_page_timeout,
|
|
18754
|
+
null
|
|
18755
|
+
],
|
|
18562
18756
|
[
|
|
18563
18757
|
"EV_SEARCH",
|
|
18564
18758
|
ac_search,
|
|
@@ -18610,7 +18804,12 @@ function create_gclass$5(gclass_name) {
|
|
|
18610
18804
|
["EV_REFRESH", 0],
|
|
18611
18805
|
["EV_SHOW_SCHEMA", 0],
|
|
18612
18806
|
["EV_CELL_EDITED", 0],
|
|
18807
|
+
["EV_REPULL_PAGE", 0],
|
|
18808
|
+
["EV_PAGE_LOADED", 0],
|
|
18809
|
+
["EV_PAGE_FAILED", 0],
|
|
18810
|
+
["EV_PAGE_TIMEOUT", 0],
|
|
18613
18811
|
["EV_UPDATE_FIELD", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
|
|
18812
|
+
["EV_REQUEST_PAGE", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
|
|
18614
18813
|
["EV_SEARCH", 0],
|
|
18615
18814
|
["EV_OPEN_COLUMNS", 0],
|
|
18616
18815
|
["EV_TOGGLE_COLUMN", 0],
|
package/dist/gobj-ui.es.js
CHANGED
|
@@ -14492,6 +14492,7 @@ var attrs_table$6 = [
|
|
|
14492
14492
|
SDATA(data_type_t.DTP_POINTER, "gobj_remote_yuno", 0, null, "Remote yuno for data fetching"),
|
|
14493
14493
|
SDATA(data_type_t.DTP_STRING, "treedb_name", 0, null, "Remote TreeDB service name"),
|
|
14494
14494
|
SDATA(data_type_t.DTP_JSON, "descs", 0, null, "Description of topics"),
|
|
14495
|
+
SDATA(data_type_t.DTP_BOOLEAN, "with_remote_paging", 0, false, "Each topic table pulls its rows a PAGE at a time (`nodes` from/limit) instead of loading the topic whole. Safe against a backend that cannot page: it answers the whole list, which the table reads as one page"),
|
|
14495
14496
|
SDATA(data_type_t.DTP_BOOLEAN, "system", 0, false, "Manage system topics (true) or user topics (false)"),
|
|
14496
14497
|
SDATA(data_type_t.DTP_STRING, "tabs_style", 0, "is-toggle is-fullwidth", "Bulma tab styling"),
|
|
14497
14498
|
SDATA(data_type_t.DTP_BOOLEAN, "with_cards_landing", 0, false, "Land on a grid of topic cards (list->detail): a card opens its table, with the tabs bar + a back-to-grid button. Off = tabs only (legacy)."),
|
|
@@ -15305,7 +15306,8 @@ function process_treedb_descs$1(gobj) {
|
|
|
15305
15306
|
with_delete_button: !readonly,
|
|
15306
15307
|
treedb_name,
|
|
15307
15308
|
topic_name: key,
|
|
15308
|
-
desc
|
|
15309
|
+
desc,
|
|
15310
|
+
with_remote_paging: gobj_read_bool_attr(gobj, "with_remote_paging")
|
|
15309
15311
|
};
|
|
15310
15312
|
let id = `${gobj_name(gobj)}?${desc.topic_name}`;
|
|
15311
15313
|
let gobj_topic_form = gobj_create_service(id, "C_YUI_TREEDB_TOPIC_WITH_FORM", kw_topic_form, gobj);
|
|
@@ -15376,6 +15378,8 @@ function register_sub_routes$1(gobj) {
|
|
|
15376
15378
|
function get_nodes$1(gobj, topic_name) {
|
|
15377
15379
|
const treedb_name = gobj.priv.treedb_name;
|
|
15378
15380
|
subscribe_treedb$1(gobj, topic_name);
|
|
15381
|
+
let gobj_topic_form = get_gobj_formtable(gobj, topic_name);
|
|
15382
|
+
if (gobj_topic_form && gobj_read_bool_attr(gobj_topic_form, "with_remote_paging")) return;
|
|
15379
15383
|
treedb_nodes$1(gobj, treedb_name, topic_name, { list_dict: true });
|
|
15380
15384
|
}
|
|
15381
15385
|
/************************************************************
|
|
@@ -15423,7 +15427,7 @@ function get_gobj_formtable(gobj, topic_name) {
|
|
|
15423
15427
|
/************************************************************
|
|
15424
15428
|
* Command to remote service
|
|
15425
15429
|
************************************************************/
|
|
15426
|
-
function treedb_nodes$1(gobj, treedb_name, topic_name, options) {
|
|
15430
|
+
function treedb_nodes$1(gobj, treedb_name, topic_name, options, page) {
|
|
15427
15431
|
let command = "nodes";
|
|
15428
15432
|
let gobj_remote_yuno = gobj_read_pointer_attr(gobj, "gobj_remote_yuno");
|
|
15429
15433
|
let kw = {
|
|
@@ -15433,8 +15437,17 @@ function treedb_nodes$1(gobj, treedb_name, topic_name, options) {
|
|
|
15433
15437
|
options: options || {}
|
|
15434
15438
|
};
|
|
15435
15439
|
kw.__md_command__ = { topic_name };
|
|
15440
|
+
if (page) {
|
|
15441
|
+
kw.from = page.from;
|
|
15442
|
+
kw.limit = page.limit;
|
|
15443
|
+
kw.__md_command__.req_id = page.req_id;
|
|
15444
|
+
}
|
|
15436
15445
|
let ret = gobj_command(gobj_remote_yuno, command, kw, gobj);
|
|
15437
|
-
if (ret)
|
|
15446
|
+
if (ret) {
|
|
15447
|
+
log_error(ret);
|
|
15448
|
+
return -1;
|
|
15449
|
+
}
|
|
15450
|
+
return 0;
|
|
15438
15451
|
}
|
|
15439
15452
|
/************************************************************
|
|
15440
15453
|
* Command to remote service
|
|
@@ -15668,7 +15681,7 @@ function ac_mt_command_answer$2(gobj, event, kw, src) {
|
|
|
15668
15681
|
yui_shell_show_error(yui_shell_of(gobj), comment, { t });
|
|
15669
15682
|
if (command === "update-node" || command === "create-node") {
|
|
15670
15683
|
let failed_topic = kw_get_str(gobj, kw_command, "topic_name", "", 0);
|
|
15671
|
-
if (failed_topic)
|
|
15684
|
+
if (failed_topic) gobj_send_event(gobj, "EV_REFRESH_TOPIC", { topic_name: failed_topic }, gobj);
|
|
15672
15685
|
}
|
|
15673
15686
|
}
|
|
15674
15687
|
return 0;
|
|
@@ -15684,7 +15697,16 @@ function ac_mt_command_answer$2(gobj, event, kw, src) {
|
|
|
15684
15697
|
let topic_name = kw_get_str(gobj, kw_command, "topic_name", "", kw_flag_t.KW_REQUIRED);
|
|
15685
15698
|
if (result >= 0) {
|
|
15686
15699
|
let gobj_topic_form = gobj_find_child(gobj, { __gobj_name__: `${gobj_name(gobj)}?${topic_name}` });
|
|
15687
|
-
|
|
15700
|
+
let answer = nodes_answer(data);
|
|
15701
|
+
let md = kw_get_dict(gobj, kw_command, "__md_command__", {}, 0);
|
|
15702
|
+
let req_id = kw_get_str(gobj, md, "req_id", "", 0);
|
|
15703
|
+
if (req_id) gobj_send_event(gobj_topic_form, "EV_PAGE_LOADED", {
|
|
15704
|
+
req_id,
|
|
15705
|
+
rows: answer.rows,
|
|
15706
|
+
pages: answer.pages,
|
|
15707
|
+
total: answer.total
|
|
15708
|
+
}, gobj);
|
|
15709
|
+
else gobj_send_event(gobj_topic_form, "EV_LOAD_NODES", answer.rows, gobj);
|
|
15688
15710
|
}
|
|
15689
15711
|
break;
|
|
15690
15712
|
case "create-node":
|
|
@@ -15910,6 +15932,31 @@ function ac_create_record(gobj, event, kw, src) {
|
|
|
15910
15932
|
});
|
|
15911
15933
|
}
|
|
15912
15934
|
/********************************************
|
|
15935
|
+
* A topic table wants a page.
|
|
15936
|
+
*
|
|
15937
|
+
* The transport is ours, so the table asks and we fetch; the answer
|
|
15938
|
+
* finds its way back by the `req_id` we echo. A backend that cannot
|
|
15939
|
+
* page answers the whole list, which the table takes as one page —
|
|
15940
|
+
* which is the truth, and is why the table can ask without knowing
|
|
15941
|
+
* what it is talking to.
|
|
15942
|
+
********************************************/
|
|
15943
|
+
function ac_request_page(gobj, event, kw, src) {
|
|
15944
|
+
let topic_name = kw.topic_name || gobj_read_attr(src, "topic_name");
|
|
15945
|
+
if (!topic_name || !kw.req_id) {
|
|
15946
|
+
log_error(`${gobj_short_name(gobj)}: a page request with no topic or no id`);
|
|
15947
|
+
return -1;
|
|
15948
|
+
}
|
|
15949
|
+
if (treedb_nodes$1(gobj, gobj_read_str_attr(gobj, "treedb_name"), topic_name, { list_dict: true }, {
|
|
15950
|
+
from: kw.from,
|
|
15951
|
+
limit: kw.limit,
|
|
15952
|
+
req_id: kw.req_id
|
|
15953
|
+
}) < 0) gobj_send_event(src, "EV_PAGE_FAILED", {
|
|
15954
|
+
req_id: kw.req_id,
|
|
15955
|
+
error: "cannot reach the backend"
|
|
15956
|
+
}, gobj);
|
|
15957
|
+
return 0;
|
|
15958
|
+
}
|
|
15959
|
+
/********************************************
|
|
15913
15960
|
* Event from formtable: ONE field of one record, edited in place.
|
|
15914
15961
|
*
|
|
15915
15962
|
* Written as a PARTIAL update and, deliberately, with NO `autolink`.
|
|
@@ -15976,6 +16023,11 @@ function ac_delete_record(gobj, event, kw, src) {
|
|
|
15976
16023
|
* }
|
|
15977
16024
|
********************************************/
|
|
15978
16025
|
function ac_refresh_topic(gobj, event, kw, src) {
|
|
16026
|
+
let gobj_topic_form = get_gobj_formtable(gobj, kw.topic_name);
|
|
16027
|
+
if (gobj_topic_form && gobj_read_bool_attr(gobj_topic_form, "with_remote_paging")) {
|
|
16028
|
+
gobj_send_event(gobj_topic_form, "EV_REPULL_PAGE", {}, gobj);
|
|
16029
|
+
return 0;
|
|
16030
|
+
}
|
|
15979
16031
|
treedb_nodes$1(gobj, gobj_read_str_attr(gobj, "treedb_name"), kw.topic_name, { list_dict: true });
|
|
15980
16032
|
return 0;
|
|
15981
16033
|
}
|
|
@@ -16065,6 +16117,11 @@ function create_gclass$6(gclass_name) {
|
|
|
16065
16117
|
ac_update_field,
|
|
16066
16118
|
null
|
|
16067
16119
|
],
|
|
16120
|
+
[
|
|
16121
|
+
"EV_REQUEST_PAGE",
|
|
16122
|
+
ac_request_page,
|
|
16123
|
+
null
|
|
16124
|
+
],
|
|
16068
16125
|
[
|
|
16069
16126
|
"EV_DELETE_RECORD",
|
|
16070
16127
|
ac_delete_record,
|
|
@@ -16139,6 +16196,7 @@ function create_gclass$6(gclass_name) {
|
|
|
16139
16196
|
["EV_CREATE_RECORD", 0],
|
|
16140
16197
|
["EV_UPDATE_RECORD", 0],
|
|
16141
16198
|
["EV_UPDATE_FIELD", 0],
|
|
16199
|
+
["EV_REQUEST_PAGE", 0],
|
|
16142
16200
|
["EV_DELETE_RECORD", 0],
|
|
16143
16201
|
["EV_RECORD_WRITTEN", event_flag_t.EVF_OUTPUT_EVENT | event_flag_t.EVF_NO_WARN_SUBS],
|
|
16144
16202
|
["EV_REFRESH_TOPIC", 0],
|
|
@@ -16353,6 +16411,8 @@ var attrs_table$5 = [
|
|
|
16353
16411
|
SDATA(data_type_t.DTP_BOOLEAN, "with_export_button", 0, true, "Button toolbar EXPORT (download as CSV what the table holds)"),
|
|
16354
16412
|
SDATA(data_type_t.DTP_BOOLEAN, "with_header_filters", 0, true, "Per-column filter box in the table header, on the columns a text/number match means something (not hooks, fkeys or json)"),
|
|
16355
16413
|
SDATA(data_type_t.DTP_BOOLEAN, "with_inline_edit", 0, true, "Edit a writable scalar cell in place while in edition mode (the record form keeps the rest)"),
|
|
16414
|
+
SDATA(data_type_t.DTP_BOOLEAN, "with_remote_paging", 0, false, "Pull the topic a PAGE at a time from the backend (`nodes` from/limit) instead of loading it whole. Needs a backend that pages"),
|
|
16415
|
+
SDATA(data_type_t.DTP_INTEGER, "page_size", 0, 200, "Rows per page when with_remote_paging. Generous on purpose: a treedb that fits in one page behaves exactly as it did, paginator hidden and every filter seeing every row"),
|
|
16356
16416
|
SDATA(data_type_t.DTP_BOOLEAN, "with_in_row_edit_icons", 0, true, "Add a last column with internal EDIT/DELETE icon"),
|
|
16357
16417
|
SDATA(data_type_t.DTP_BOOLEAN, "editable", 0, false, "Edit state"),
|
|
16358
16418
|
SDATA(data_type_t.DTP_BOOLEAN, "with_checkbox", 0, true, "Auxiliary first column to select rows"),
|
|
@@ -16381,6 +16441,8 @@ var attrs_table$5 = [
|
|
|
16381
16441
|
SDATA_END()
|
|
16382
16442
|
];
|
|
16383
16443
|
var PRIVATE_DATA$5 = {
|
|
16444
|
+
_pending_pages: null,
|
|
16445
|
+
_page_seq: 0,
|
|
16384
16446
|
$container: null,
|
|
16385
16447
|
treedb_name: "",
|
|
16386
16448
|
topic_name: "",
|
|
@@ -17106,6 +17168,25 @@ function create_tabulator(gobj) {
|
|
|
17106
17168
|
let pkey = desc.pkey || "id";
|
|
17107
17169
|
let selectable = with_checkbox ? "highlight" : with_radio ? 1 : false;
|
|
17108
17170
|
let tabulator_settings = json_deep_copy(gobj_read_attr(gobj, "tabulator_settings"));
|
|
17171
|
+
if (gobj_read_bool_attr(gobj, "with_remote_paging")) {
|
|
17172
|
+
let page_size = gobj_read_integer_attr(gobj, "page_size") || 200;
|
|
17173
|
+
Object.assign(tabulator_settings, {
|
|
17174
|
+
pagination: true,
|
|
17175
|
+
paginationMode: "remote",
|
|
17176
|
+
filterMode: "local",
|
|
17177
|
+
paginationSize: page_size,
|
|
17178
|
+
paginationSizeSelector: [
|
|
17179
|
+
50,
|
|
17180
|
+
100,
|
|
17181
|
+
200,
|
|
17182
|
+
500
|
|
17183
|
+
],
|
|
17184
|
+
ajaxURL: "nodes",
|
|
17185
|
+
ajaxRequestFunc: function(url, config, params) {
|
|
17186
|
+
return request_page(gobj, params.page || 1, params.size || page_size);
|
|
17187
|
+
}
|
|
17188
|
+
});
|
|
17189
|
+
}
|
|
17109
17190
|
Object.assign(tabulator_settings, {
|
|
17110
17191
|
index: pkey,
|
|
17111
17192
|
columns,
|
|
@@ -18307,6 +18388,99 @@ function ac_show_schema(gobj, event, kw, src) {
|
|
|
18307
18388
|
return 0;
|
|
18308
18389
|
}
|
|
18309
18390
|
/************************************************************
|
|
18391
|
+
* Ask the host for one page and park the promise Tabulator wants.
|
|
18392
|
+
*
|
|
18393
|
+
* The transport belongs to the HOST, so the request goes up as an event
|
|
18394
|
+
* and the answer comes back down as one; what lives here is only the
|
|
18395
|
+
* promise, keyed by a correlation id the host echoes.
|
|
18396
|
+
*
|
|
18397
|
+
* Rejected right away when there is nobody to ask: a request that can
|
|
18398
|
+
* never be answered would leave the table spinning for ever and leak
|
|
18399
|
+
* one entry per attempt. Same for the watchdog — the link can stay up
|
|
18400
|
+
* and the answer still never land.
|
|
18401
|
+
************************************************************/
|
|
18402
|
+
var PAGE_TIMEOUT_MS = 2e4;
|
|
18403
|
+
function request_page(gobj, page, size) {
|
|
18404
|
+
let priv = gobj.priv;
|
|
18405
|
+
return new Promise(function(resolve, reject) {
|
|
18406
|
+
if (!priv._pending_pages) priv._pending_pages = {};
|
|
18407
|
+
let req_id = `p${++priv._page_seq}`;
|
|
18408
|
+
let timer = window.setTimeout(function() {
|
|
18409
|
+
gobj_send_event(gobj, "EV_PAGE_TIMEOUT", { req_id }, gobj);
|
|
18410
|
+
}, PAGE_TIMEOUT_MS);
|
|
18411
|
+
priv._pending_pages[req_id] = {
|
|
18412
|
+
resolve,
|
|
18413
|
+
reject,
|
|
18414
|
+
timer
|
|
18415
|
+
};
|
|
18416
|
+
gobj_publish_event(gobj, "EV_REQUEST_PAGE", {
|
|
18417
|
+
topic_name: gobj_read_str_attr(gobj, "topic_name"),
|
|
18418
|
+
req_id,
|
|
18419
|
+
from: (page - 1) * size + 1,
|
|
18420
|
+
limit: size
|
|
18421
|
+
});
|
|
18422
|
+
});
|
|
18423
|
+
}
|
|
18424
|
+
/************************************************************
|
|
18425
|
+
* Settle a parked page request, however it ended.
|
|
18426
|
+
************************************************************/
|
|
18427
|
+
function settle_page(gobj, req_id, value, error) {
|
|
18428
|
+
let priv = gobj.priv;
|
|
18429
|
+
let pend = priv._pending_pages ? priv._pending_pages[req_id] : null;
|
|
18430
|
+
if (!pend) return;
|
|
18431
|
+
delete priv._pending_pages[req_id];
|
|
18432
|
+
if (pend.timer) window.clearTimeout(pend.timer);
|
|
18433
|
+
if (error) {
|
|
18434
|
+
pend.reject(new Error(error));
|
|
18435
|
+
return;
|
|
18436
|
+
}
|
|
18437
|
+
pend.resolve(value);
|
|
18438
|
+
}
|
|
18439
|
+
/************************************************************
|
|
18440
|
+
* Pull the current page again. `replaceData()` re-runs
|
|
18441
|
+
* ajaxRequestFunc for the page the reader is on, so a refresh keeps
|
|
18442
|
+
* their position instead of throwing them back to the first page.
|
|
18443
|
+
************************************************************/
|
|
18444
|
+
function ac_repull_page(gobj, event, kw, src) {
|
|
18445
|
+
let tabulator = gobj_read_attr(gobj, "tabulator");
|
|
18446
|
+
if (!tabulator) return 0;
|
|
18447
|
+
try {
|
|
18448
|
+
tabulator.replaceData();
|
|
18449
|
+
} catch (e) {
|
|
18450
|
+
log_error(`${gobj_short_name(gobj)}: cannot re-pull the page: ${e}`);
|
|
18451
|
+
return -1;
|
|
18452
|
+
}
|
|
18453
|
+
return 0;
|
|
18454
|
+
}
|
|
18455
|
+
/************************************************************
|
|
18456
|
+
* The host answered a page.
|
|
18457
|
+
************************************************************/
|
|
18458
|
+
function ac_page_loaded(gobj, event, kw, src) {
|
|
18459
|
+
settle_page(gobj, kw.req_id, {
|
|
18460
|
+
data: is_array(kw.rows) ? kw.rows : [],
|
|
18461
|
+
last_page: kw.pages || 1,
|
|
18462
|
+
last_row: typeof kw.total === "number" ? kw.total : 0
|
|
18463
|
+
}, null);
|
|
18464
|
+
return 0;
|
|
18465
|
+
}
|
|
18466
|
+
/************************************************************
|
|
18467
|
+
* The host could not answer it.
|
|
18468
|
+
************************************************************/
|
|
18469
|
+
function ac_page_failed(gobj, event, kw, src) {
|
|
18470
|
+
let why = kw && kw.error || "page request failed";
|
|
18471
|
+
log_error(`${gobj_short_name(gobj)}: ${why}`);
|
|
18472
|
+
settle_page(gobj, kw.req_id, null, why);
|
|
18473
|
+
return 0;
|
|
18474
|
+
}
|
|
18475
|
+
/************************************************************
|
|
18476
|
+
* Nobody answered in time.
|
|
18477
|
+
************************************************************/
|
|
18478
|
+
function ac_page_timeout(gobj, event, kw, src) {
|
|
18479
|
+
log_error(`${gobj_short_name(gobj)}: no answer for page request '${kw.req_id}' in ${PAGE_TIMEOUT_MS}ms`);
|
|
18480
|
+
settle_page(gobj, kw.req_id, null, "page request timed out");
|
|
18481
|
+
return 0;
|
|
18482
|
+
}
|
|
18483
|
+
/************************************************************
|
|
18310
18484
|
* Filter the loaded rows by a term matched against every non-internal
|
|
18311
18485
|
* field. `clearFilter()` with no argument drops only THIS filter: the
|
|
18312
18486
|
* per-column header filters are a separate layer and survive, so a
|
|
@@ -18554,6 +18728,26 @@ function create_gclass$5(gclass_name) {
|
|
|
18554
18728
|
ac_cell_edited,
|
|
18555
18729
|
null
|
|
18556
18730
|
],
|
|
18731
|
+
[
|
|
18732
|
+
"EV_REPULL_PAGE",
|
|
18733
|
+
ac_repull_page,
|
|
18734
|
+
null
|
|
18735
|
+
],
|
|
18736
|
+
[
|
|
18737
|
+
"EV_PAGE_LOADED",
|
|
18738
|
+
ac_page_loaded,
|
|
18739
|
+
null
|
|
18740
|
+
],
|
|
18741
|
+
[
|
|
18742
|
+
"EV_PAGE_FAILED",
|
|
18743
|
+
ac_page_failed,
|
|
18744
|
+
null
|
|
18745
|
+
],
|
|
18746
|
+
[
|
|
18747
|
+
"EV_PAGE_TIMEOUT",
|
|
18748
|
+
ac_page_timeout,
|
|
18749
|
+
null
|
|
18750
|
+
],
|
|
18557
18751
|
[
|
|
18558
18752
|
"EV_SEARCH",
|
|
18559
18753
|
ac_search,
|
|
@@ -18605,7 +18799,12 @@ function create_gclass$5(gclass_name) {
|
|
|
18605
18799
|
["EV_REFRESH", 0],
|
|
18606
18800
|
["EV_SHOW_SCHEMA", 0],
|
|
18607
18801
|
["EV_CELL_EDITED", 0],
|
|
18802
|
+
["EV_REPULL_PAGE", 0],
|
|
18803
|
+
["EV_PAGE_LOADED", 0],
|
|
18804
|
+
["EV_PAGE_FAILED", 0],
|
|
18805
|
+
["EV_PAGE_TIMEOUT", 0],
|
|
18608
18806
|
["EV_UPDATE_FIELD", event_flag_t.EVF_OUTPUT_EVENT],
|
|
18807
|
+
["EV_REQUEST_PAGE", event_flag_t.EVF_OUTPUT_EVENT],
|
|
18609
18808
|
["EV_SEARCH", 0],
|
|
18610
18809
|
["EV_OPEN_COLUMNS", 0],
|
|
18611
18810
|
["EV_TOGGLE_COLUMN", 0],
|
package/package.json
CHANGED
|
@@ -48,6 +48,7 @@ import {
|
|
|
48
48
|
gclass_find_by_name,
|
|
49
49
|
gobj_write_attr,
|
|
50
50
|
gobj_read_bool_attr,
|
|
51
|
+
gobj_read_integer_attr,
|
|
51
52
|
gobj_read_str_attr,
|
|
52
53
|
gobj_write_bool_attr,
|
|
53
54
|
gobj_publish_event,
|
|
@@ -112,6 +113,8 @@ SDATA(data_type_t.DTP_BOOLEAN, "with_columns_button", 0, true, "Button
|
|
|
112
113
|
SDATA(data_type_t.DTP_BOOLEAN, "with_export_button", 0, true, "Button toolbar EXPORT (download as CSV what the table holds)"),
|
|
113
114
|
SDATA(data_type_t.DTP_BOOLEAN, "with_header_filters", 0, true, "Per-column filter box in the table header, on the columns a text/number match means something (not hooks, fkeys or json)"),
|
|
114
115
|
SDATA(data_type_t.DTP_BOOLEAN, "with_inline_edit", 0, true, "Edit a writable scalar cell in place while in edition mode (the record form keeps the rest)"),
|
|
116
|
+
SDATA(data_type_t.DTP_BOOLEAN, "with_remote_paging", 0, false, "Pull the topic a PAGE at a time from the backend (`nodes` from/limit) instead of loading it whole. Needs a backend that pages"),
|
|
117
|
+
SDATA(data_type_t.DTP_INTEGER, "page_size", 0, 200, "Rows per page when with_remote_paging. Generous on purpose: a treedb that fits in one page behaves exactly as it did, paginator hidden and every filter seeing every row"),
|
|
115
118
|
SDATA(data_type_t.DTP_BOOLEAN, "with_in_row_edit_icons", 0, true, "Add a last column with internal EDIT/DELETE icon"),
|
|
116
119
|
|
|
117
120
|
SDATA(data_type_t.DTP_BOOLEAN, "editable", 0, false, "Edit state"),
|
|
@@ -146,6 +149,8 @@ SDATA_END()
|
|
|
146
149
|
];
|
|
147
150
|
|
|
148
151
|
let PRIVATE_DATA = {
|
|
152
|
+
_pending_pages: null, // req_id -> {resolve, reject, timer}
|
|
153
|
+
_page_seq: 0, // correlation id of a page request
|
|
149
154
|
$container: null,
|
|
150
155
|
treedb_name: "",
|
|
151
156
|
topic_name: "",
|
|
@@ -1095,6 +1100,36 @@ function create_tabulator(gobj)
|
|
|
1095
1100
|
|
|
1096
1101
|
let tabulator_settings = json_deep_copy(gobj_read_attr(gobj, "tabulator_settings"));
|
|
1097
1102
|
|
|
1103
|
+
/* Remote paging: the TABLE pulls, instead of the host pushing the whole
|
|
1104
|
+
* topic down. The page size is generous on purpose — a treedb that fits
|
|
1105
|
+
* in one page behaves exactly as it did before, with the paginator
|
|
1106
|
+
* hidden and every filter seeing every row. Only a topic that does NOT
|
|
1107
|
+
* fit pays for paging, and for that one loading it whole was never an
|
|
1108
|
+
* option anyway.
|
|
1109
|
+
*
|
|
1110
|
+
* `filterMode: "local"` says the plain truth: the header filters and the
|
|
1111
|
+
* search box work on the page that is loaded. Same as the tranger
|
|
1112
|
+
* browser's Rows card, and for the same reason — the alternative is
|
|
1113
|
+
* pushing every filter to the backend and changing what "search" means.
|
|
1114
|
+
*/
|
|
1115
|
+
if(gobj_read_bool_attr(gobj, "with_remote_paging")) {
|
|
1116
|
+
let page_size = gobj_read_integer_attr(gobj, "page_size") || 200;
|
|
1117
|
+
Object.assign(tabulator_settings, {
|
|
1118
|
+
pagination: true,
|
|
1119
|
+
paginationMode: "remote",
|
|
1120
|
+
filterMode: "local",
|
|
1121
|
+
paginationSize: page_size,
|
|
1122
|
+
paginationSizeSelector: [50, 100, 200, 500],
|
|
1123
|
+
ajaxURL: "nodes", /* dummy: only fires the func */
|
|
1124
|
+
ajaxRequestFunc: function(url, config, params) {
|
|
1125
|
+
/* Widget plumbing, not an action: Tabulator wants a PROMISE
|
|
1126
|
+
* back — it is a data source. The action is the event this
|
|
1127
|
+
* parks on. */
|
|
1128
|
+
return request_page(gobj, params.page || 1, params.size || page_size);
|
|
1129
|
+
}
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1098
1133
|
Object.assign(tabulator_settings, {
|
|
1099
1134
|
index: pkey,
|
|
1100
1135
|
columns: columns,
|
|
@@ -2965,6 +3000,125 @@ function ac_show_schema(gobj, event, kw, src)
|
|
|
2965
3000
|
return 0;
|
|
2966
3001
|
}
|
|
2967
3002
|
|
|
3003
|
+
/************************************************************
|
|
3004
|
+
* Ask the host for one page and park the promise Tabulator wants.
|
|
3005
|
+
*
|
|
3006
|
+
* The transport belongs to the HOST, so the request goes up as an event
|
|
3007
|
+
* and the answer comes back down as one; what lives here is only the
|
|
3008
|
+
* promise, keyed by a correlation id the host echoes.
|
|
3009
|
+
*
|
|
3010
|
+
* Rejected right away when there is nobody to ask: a request that can
|
|
3011
|
+
* never be answered would leave the table spinning for ever and leak
|
|
3012
|
+
* one entry per attempt. Same for the watchdog — the link can stay up
|
|
3013
|
+
* and the answer still never land.
|
|
3014
|
+
************************************************************/
|
|
3015
|
+
const PAGE_TIMEOUT_MS = 20000;
|
|
3016
|
+
|
|
3017
|
+
function request_page(gobj, page, size)
|
|
3018
|
+
{
|
|
3019
|
+
let priv = gobj.priv;
|
|
3020
|
+
|
|
3021
|
+
return new Promise(function(resolve, reject) {
|
|
3022
|
+
if(!priv._pending_pages) {
|
|
3023
|
+
priv._pending_pages = {};
|
|
3024
|
+
}
|
|
3025
|
+
let req_id = `p${++priv._page_seq}`;
|
|
3026
|
+
|
|
3027
|
+
let timer = window.setTimeout(function() {
|
|
3028
|
+
gobj_send_event(gobj, "EV_PAGE_TIMEOUT", {req_id: req_id}, gobj);
|
|
3029
|
+
}, PAGE_TIMEOUT_MS);
|
|
3030
|
+
|
|
3031
|
+
priv._pending_pages[req_id] = {resolve: resolve, reject: reject, timer: timer};
|
|
3032
|
+
|
|
3033
|
+
gobj_publish_event(
|
|
3034
|
+
gobj,
|
|
3035
|
+
"EV_REQUEST_PAGE",
|
|
3036
|
+
{
|
|
3037
|
+
topic_name: gobj_read_str_attr(gobj, "topic_name"),
|
|
3038
|
+
req_id: req_id,
|
|
3039
|
+
from: (page - 1) * size + 1, /* `nodes` counts from 1 */
|
|
3040
|
+
limit: size
|
|
3041
|
+
}
|
|
3042
|
+
);
|
|
3043
|
+
});
|
|
3044
|
+
}
|
|
3045
|
+
|
|
3046
|
+
/************************************************************
|
|
3047
|
+
* Settle a parked page request, however it ended.
|
|
3048
|
+
************************************************************/
|
|
3049
|
+
function settle_page(gobj, req_id, value, error)
|
|
3050
|
+
{
|
|
3051
|
+
let priv = gobj.priv;
|
|
3052
|
+
let pend = priv._pending_pages? priv._pending_pages[req_id] : null;
|
|
3053
|
+
if(!pend) {
|
|
3054
|
+
return; /* already settled: a late answer after a timeout */
|
|
3055
|
+
}
|
|
3056
|
+
delete priv._pending_pages[req_id];
|
|
3057
|
+
if(pend.timer) {
|
|
3058
|
+
window.clearTimeout(pend.timer);
|
|
3059
|
+
}
|
|
3060
|
+
if(error) {
|
|
3061
|
+
pend.reject(new Error(error));
|
|
3062
|
+
return;
|
|
3063
|
+
}
|
|
3064
|
+
pend.resolve(value);
|
|
3065
|
+
}
|
|
3066
|
+
|
|
3067
|
+
/************************************************************
|
|
3068
|
+
* Pull the current page again. `replaceData()` re-runs
|
|
3069
|
+
* ajaxRequestFunc for the page the reader is on, so a refresh keeps
|
|
3070
|
+
* their position instead of throwing them back to the first page.
|
|
3071
|
+
************************************************************/
|
|
3072
|
+
function ac_repull_page(gobj, event, kw, src)
|
|
3073
|
+
{
|
|
3074
|
+
let tabulator = gobj_read_attr(gobj, "tabulator");
|
|
3075
|
+
if(!tabulator) {
|
|
3076
|
+
return 0;
|
|
3077
|
+
}
|
|
3078
|
+
try {
|
|
3079
|
+
tabulator.replaceData();
|
|
3080
|
+
} catch(e) {
|
|
3081
|
+
log_error(`${gobj_short_name(gobj)}: cannot re-pull the page: ${e}`);
|
|
3082
|
+
return -1;
|
|
3083
|
+
}
|
|
3084
|
+
return 0;
|
|
3085
|
+
}
|
|
3086
|
+
|
|
3087
|
+
/************************************************************
|
|
3088
|
+
* The host answered a page.
|
|
3089
|
+
************************************************************/
|
|
3090
|
+
function ac_page_loaded(gobj, event, kw, src)
|
|
3091
|
+
{
|
|
3092
|
+
settle_page(gobj, kw.req_id, {
|
|
3093
|
+
data: is_array(kw.rows)? kw.rows : [],
|
|
3094
|
+
last_page: kw.pages || 1,
|
|
3095
|
+
last_row: (typeof kw.total === "number")? kw.total : 0
|
|
3096
|
+
}, null);
|
|
3097
|
+
return 0;
|
|
3098
|
+
}
|
|
3099
|
+
|
|
3100
|
+
/************************************************************
|
|
3101
|
+
* The host could not answer it.
|
|
3102
|
+
************************************************************/
|
|
3103
|
+
function ac_page_failed(gobj, event, kw, src)
|
|
3104
|
+
{
|
|
3105
|
+
let why = (kw && kw.error) || "page request failed";
|
|
3106
|
+
log_error(`${gobj_short_name(gobj)}: ${why}`);
|
|
3107
|
+
settle_page(gobj, kw.req_id, null, why);
|
|
3108
|
+
return 0;
|
|
3109
|
+
}
|
|
3110
|
+
|
|
3111
|
+
/************************************************************
|
|
3112
|
+
* Nobody answered in time.
|
|
3113
|
+
************************************************************/
|
|
3114
|
+
function ac_page_timeout(gobj, event, kw, src)
|
|
3115
|
+
{
|
|
3116
|
+
log_error(`${gobj_short_name(gobj)}: no answer for page request ` +
|
|
3117
|
+
`'${kw.req_id}' in ${PAGE_TIMEOUT_MS}ms`);
|
|
3118
|
+
settle_page(gobj, kw.req_id, null, "page request timed out");
|
|
3119
|
+
return 0;
|
|
3120
|
+
}
|
|
3121
|
+
|
|
2968
3122
|
/************************************************************
|
|
2969
3123
|
* Filter the loaded rows by a term matched against every non-internal
|
|
2970
3124
|
* field. `clearFilter()` with no argument drops only THIS filter: the
|
|
@@ -3187,6 +3341,10 @@ function create_gclass(gclass_name)
|
|
|
3187
3341
|
["EV_REFRESH", ac_refresh, null],
|
|
3188
3342
|
["EV_SHOW_SCHEMA", ac_show_schema, null],
|
|
3189
3343
|
["EV_CELL_EDITED", ac_cell_edited, null],
|
|
3344
|
+
["EV_REPULL_PAGE", ac_repull_page, null],
|
|
3345
|
+
["EV_PAGE_LOADED", ac_page_loaded, null],
|
|
3346
|
+
["EV_PAGE_FAILED", ac_page_failed, null],
|
|
3347
|
+
["EV_PAGE_TIMEOUT", ac_page_timeout, null],
|
|
3190
3348
|
["EV_SEARCH", ac_search, null],
|
|
3191
3349
|
["EV_OPEN_COLUMNS", ac_open_columns, null],
|
|
3192
3350
|
["EV_TOGGLE_COLUMN", ac_toggle_column, null],
|
|
@@ -3220,7 +3378,12 @@ function create_gclass(gclass_name)
|
|
|
3220
3378
|
["EV_REFRESH", 0],
|
|
3221
3379
|
["EV_SHOW_SCHEMA", 0],
|
|
3222
3380
|
["EV_CELL_EDITED", 0],
|
|
3381
|
+
["EV_REPULL_PAGE", 0],
|
|
3382
|
+
["EV_PAGE_LOADED", 0],
|
|
3383
|
+
["EV_PAGE_FAILED", 0],
|
|
3384
|
+
["EV_PAGE_TIMEOUT", 0],
|
|
3223
3385
|
["EV_UPDATE_FIELD", event_flag_t.EVF_OUTPUT_EVENT],
|
|
3386
|
+
["EV_REQUEST_PAGE", event_flag_t.EVF_OUTPUT_EVENT],
|
|
3224
3387
|
["EV_SEARCH", 0],
|
|
3225
3388
|
["EV_OPEN_COLUMNS", 0],
|
|
3226
3389
|
["EV_TOGGLE_COLUMN", 0],
|
|
@@ -75,6 +75,7 @@ SDATA(data_type_t.DTP_POINTER, "subscriber", 0, null, "Subscriber of o
|
|
|
75
75
|
SDATA(data_type_t.DTP_POINTER, "gobj_remote_yuno", 0, null, "Remote yuno for data fetching"),
|
|
76
76
|
SDATA(data_type_t.DTP_STRING, "treedb_name", 0, null, "Remote TreeDB service name"),
|
|
77
77
|
SDATA(data_type_t.DTP_JSON, "descs", 0, null, "Description of topics"),
|
|
78
|
+
SDATA(data_type_t.DTP_BOOLEAN, "with_remote_paging", 0, false, "Each topic table pulls its rows a PAGE at a time (`nodes` from/limit) instead of loading the topic whole. Safe against a backend that cannot page: it answers the whole list, which the table reads as one page"),
|
|
78
79
|
SDATA(data_type_t.DTP_BOOLEAN, "system", 0, false, "Manage system topics (true) or user topics (false)"),
|
|
79
80
|
SDATA(data_type_t.DTP_STRING, "tabs_style", 0, "is-toggle is-fullwidth", "Bulma tab styling"),
|
|
80
81
|
SDATA(data_type_t.DTP_BOOLEAN, "with_cards_landing",0, false, "Land on a grid of topic cards (list->detail): a card opens its table, with the tabs bar + a back-to-grid button. Off = tabs only (legacy)."),
|
|
@@ -1037,7 +1038,8 @@ function process_treedb_descs(gobj)
|
|
|
1037
1038
|
|
|
1038
1039
|
treedb_name: treedb_name,
|
|
1039
1040
|
topic_name: key,
|
|
1040
|
-
desc: desc
|
|
1041
|
+
desc: desc,
|
|
1042
|
+
with_remote_paging: gobj_read_bool_attr(gobj, "with_remote_paging")
|
|
1041
1043
|
};
|
|
1042
1044
|
|
|
1043
1045
|
let id = `${gobj_name(gobj)}?${desc.topic_name}`;
|
|
@@ -1171,8 +1173,15 @@ function get_nodes(gobj, topic_name)
|
|
|
1171
1173
|
subscribe_treedb(gobj, topic_name);
|
|
1172
1174
|
|
|
1173
1175
|
/*
|
|
1174
|
-
* Get data
|
|
1176
|
+
* Get data — unless the table pulls its own pages, in which case it has
|
|
1177
|
+
* already asked (or is about to) and a second whole-topic fetch would be
|
|
1178
|
+
* the very transfer paging exists to avoid.
|
|
1175
1179
|
*/
|
|
1180
|
+
let gobj_topic_form = get_gobj_formtable(gobj, topic_name);
|
|
1181
|
+
if(gobj_topic_form && gobj_read_bool_attr(gobj_topic_form, "with_remote_paging")) {
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1176
1185
|
treedb_nodes(
|
|
1177
1186
|
gobj,
|
|
1178
1187
|
treedb_name,
|
|
@@ -1328,7 +1337,7 @@ function get_gobj_formtable(gobj, topic_name)
|
|
|
1328
1337
|
/************************************************************
|
|
1329
1338
|
* Command to remote service
|
|
1330
1339
|
************************************************************/
|
|
1331
|
-
function treedb_nodes(gobj, treedb_name, topic_name, options)
|
|
1340
|
+
function treedb_nodes(gobj, treedb_name, topic_name, options, page)
|
|
1332
1341
|
{
|
|
1333
1342
|
let command = "nodes";
|
|
1334
1343
|
|
|
@@ -1344,6 +1353,16 @@ function treedb_nodes(gobj, treedb_name, topic_name, options)
|
|
|
1344
1353
|
topic_name: topic_name,
|
|
1345
1354
|
};
|
|
1346
1355
|
|
|
1356
|
+
/* A PAGE, when the table asked for one. `from` is 1-based and a
|
|
1357
|
+
* backend that does not know these two answers the whole list, which
|
|
1358
|
+
* nodes_answer() reads as one page — so an old backend degrades to
|
|
1359
|
+
* exactly what it always did. */
|
|
1360
|
+
if(page) {
|
|
1361
|
+
kw.from = page.from;
|
|
1362
|
+
kw.limit = page.limit;
|
|
1363
|
+
kw.__md_command__.req_id = page.req_id;
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1347
1366
|
// TODO review msg_iev_write_key(kw, "__topic_name__", topic_name);
|
|
1348
1367
|
|
|
1349
1368
|
let ret = gobj_command(
|
|
@@ -1354,7 +1373,9 @@ function treedb_nodes(gobj, treedb_name, topic_name, options)
|
|
|
1354
1373
|
);
|
|
1355
1374
|
if(ret) {
|
|
1356
1375
|
log_error(ret);
|
|
1376
|
+
return -1;
|
|
1357
1377
|
}
|
|
1378
|
+
return 0;
|
|
1358
1379
|
}
|
|
1359
1380
|
|
|
1360
1381
|
/************************************************************
|
|
@@ -1749,8 +1770,8 @@ function ac_mt_command_answer(gobj, event, kw, src)
|
|
|
1749
1770
|
if(command === "update-node" || command === "create-node") {
|
|
1750
1771
|
let failed_topic = kw_get_str(gobj, kw_command, "topic_name", "", 0);
|
|
1751
1772
|
if(failed_topic) {
|
|
1752
|
-
|
|
1753
|
-
|
|
1773
|
+
gobj_send_event(gobj, "EV_REFRESH_TOPIC",
|
|
1774
|
+
{topic_name: failed_topic}, gobj);
|
|
1754
1775
|
}
|
|
1755
1776
|
}
|
|
1756
1777
|
}
|
|
@@ -1778,13 +1799,36 @@ function ac_mt_command_answer(gobj, event, kw, src)
|
|
|
1778
1799
|
* answers the plain list whatever is asked of it. Reading
|
|
1779
1800
|
* the shape rather than assuming it is what keeps the table
|
|
1780
1801
|
* from rendering an object's keys as rows the day a backend
|
|
1781
|
-
* upgrades
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1802
|
+
* upgrades — and it is what lets a paging table survive a
|
|
1803
|
+
* backend that cannot page: the whole list arrives as one
|
|
1804
|
+
* page, which is the truth. */
|
|
1805
|
+
let answer = nodes_answer(data);
|
|
1806
|
+
/* The correlation id travels in `__md_command__` of the kw
|
|
1807
|
+
* that was SENT — the same place `topic_name` rides — so it
|
|
1808
|
+
* is read back from the command stack and never sent to the
|
|
1809
|
+
* backend as a parameter it does not know. */
|
|
1810
|
+
let md = kw_get_dict(gobj, kw_command, "__md_command__", {}, 0);
|
|
1811
|
+
let req_id = kw_get_str(gobj, md, "req_id", "", 0);
|
|
1812
|
+
if(req_id) {
|
|
1813
|
+
gobj_send_event(
|
|
1814
|
+
gobj_topic_form,
|
|
1815
|
+
"EV_PAGE_LOADED",
|
|
1816
|
+
{
|
|
1817
|
+
req_id: req_id,
|
|
1818
|
+
rows: answer.rows,
|
|
1819
|
+
pages: answer.pages,
|
|
1820
|
+
total: answer.total
|
|
1821
|
+
},
|
|
1822
|
+
gobj
|
|
1823
|
+
);
|
|
1824
|
+
} else {
|
|
1825
|
+
gobj_send_event(
|
|
1826
|
+
gobj_topic_form,
|
|
1827
|
+
"EV_LOAD_NODES",
|
|
1828
|
+
answer.rows,
|
|
1829
|
+
gobj
|
|
1830
|
+
);
|
|
1831
|
+
}
|
|
1788
1832
|
}
|
|
1789
1833
|
break;
|
|
1790
1834
|
|
|
@@ -2147,6 +2191,40 @@ function ac_create_record(gobj, event, kw, src)
|
|
|
2147
2191
|
);
|
|
2148
2192
|
}
|
|
2149
2193
|
|
|
2194
|
+
/********************************************
|
|
2195
|
+
* A topic table wants a page.
|
|
2196
|
+
*
|
|
2197
|
+
* The transport is ours, so the table asks and we fetch; the answer
|
|
2198
|
+
* finds its way back by the `req_id` we echo. A backend that cannot
|
|
2199
|
+
* page answers the whole list, which the table takes as one page —
|
|
2200
|
+
* which is the truth, and is why the table can ask without knowing
|
|
2201
|
+
* what it is talking to.
|
|
2202
|
+
********************************************/
|
|
2203
|
+
function ac_request_page(gobj, event, kw, src)
|
|
2204
|
+
{
|
|
2205
|
+
let topic_name = kw.topic_name || gobj_read_attr(src, "topic_name");
|
|
2206
|
+
if(!topic_name || !kw.req_id) {
|
|
2207
|
+
log_error(`${gobj_short_name(gobj)}: a page request with no topic or no id`);
|
|
2208
|
+
return -1;
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2211
|
+
let ret = treedb_nodes(
|
|
2212
|
+
gobj,
|
|
2213
|
+
gobj_read_str_attr(gobj, "treedb_name"),
|
|
2214
|
+
topic_name,
|
|
2215
|
+
{list_dict: true},
|
|
2216
|
+
{from: kw.from, limit: kw.limit, req_id: kw.req_id}
|
|
2217
|
+
);
|
|
2218
|
+
|
|
2219
|
+
if(ret < 0) {
|
|
2220
|
+
/* The command never went out, so no answer will ever come: tell the
|
|
2221
|
+
* table now instead of leaving it spinning until its watchdog. */
|
|
2222
|
+
gobj_send_event(src, "EV_PAGE_FAILED",
|
|
2223
|
+
{req_id: kw.req_id, error: "cannot reach the backend"}, gobj);
|
|
2224
|
+
}
|
|
2225
|
+
return 0;
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2150
2228
|
/********************************************
|
|
2151
2229
|
* Event from formtable: ONE field of one record, edited in place.
|
|
2152
2230
|
*
|
|
@@ -2256,6 +2334,14 @@ function ac_delete_record(gobj, event, kw, src)
|
|
|
2256
2334
|
********************************************/
|
|
2257
2335
|
function ac_refresh_topic(gobj, event, kw, src)
|
|
2258
2336
|
{
|
|
2337
|
+
let gobj_topic_form = get_gobj_formtable(gobj, kw.topic_name);
|
|
2338
|
+
if(gobj_topic_form && gobj_read_bool_attr(gobj_topic_form, "with_remote_paging")) {
|
|
2339
|
+
/* A table that pulls refreshes by pulling: pushing a whole topic
|
|
2340
|
+
* into a paged table would replace its page with everything. */
|
|
2341
|
+
gobj_send_event(gobj_topic_form, "EV_REPULL_PAGE", {}, gobj);
|
|
2342
|
+
return 0;
|
|
2343
|
+
}
|
|
2344
|
+
|
|
2259
2345
|
let options = {
|
|
2260
2346
|
list_dict: true
|
|
2261
2347
|
};
|
|
@@ -2357,6 +2443,7 @@ function create_gclass(gclass_name)
|
|
|
2357
2443
|
["EV_CREATE_RECORD", ac_create_record, null],
|
|
2358
2444
|
["EV_UPDATE_RECORD", ac_update_record, null],
|
|
2359
2445
|
["EV_UPDATE_FIELD", ac_update_field, null],
|
|
2446
|
+
["EV_REQUEST_PAGE", ac_request_page, null],
|
|
2360
2447
|
["EV_DELETE_RECORD", ac_delete_record, null],
|
|
2361
2448
|
["EV_REFRESH_TOPIC", ac_refresh_topic, null],
|
|
2362
2449
|
["EV_OPEN_JSON", ac_open_json, null],
|
|
@@ -2384,6 +2471,7 @@ function create_gclass(gclass_name)
|
|
|
2384
2471
|
["EV_CREATE_RECORD", 0],
|
|
2385
2472
|
["EV_UPDATE_RECORD", 0],
|
|
2386
2473
|
["EV_UPDATE_FIELD", 0],
|
|
2474
|
+
["EV_REQUEST_PAGE", 0],
|
|
2387
2475
|
["EV_DELETE_RECORD", 0],
|
|
2388
2476
|
["EV_RECORD_WRITTEN", event_flag_t.EVF_OUTPUT_EVENT|
|
|
2389
2477
|
event_flag_t.EVF_NO_WARN_SUBS],
|