@yuneta/gobj-ui 7.25.17 → 7.25.19
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 +69 -3
- package/dist/gobj-ui.cjs.js +126 -30
- package/dist/gobj-ui.es.js +126 -30
- package/package.json +2 -2
- package/src/c_g6_nodes_tree.js +23 -0
- package/src/c_yui_node.js +71 -0
- package/src/c_yui_schema_editor.js +20 -10
- package/src/c_yui_treedb_graph.js +49 -6
- package/src/c_yui_treedb_topic_with_form.js +23 -0
- package/src/c_yui_treedb_topics.js +43 -9
- package/src/c_yui_uplot.js +10 -5
- package/src/form_json_expand.wiring.test.js +121 -0
- package/src/g6_graphs_write_owed.wiring.test.js +37 -0
- package/src/node_nav_events.wiring.test.js +150 -0
- package/src/schema_editor_reload.wiring.test.js +37 -0
- package/src/treedb_graph_writes.wiring.test.js +71 -3
- package/src/treedb_topics_transport.wiring.test.js +111 -7
- package/src/uplot_add_serie.test.js +92 -0
|
@@ -29,6 +29,7 @@ const {register_c_yui_shell, yui_shell_set_connection_state} = await import("./c
|
|
|
29
29
|
const {register_c_yui_treedb_topics} = await import("./c_yui_treedb_topics.js");
|
|
30
30
|
|
|
31
31
|
const logged = [];
|
|
32
|
+
const written = []; /* the EV_RECORD_WRITTEN the host heard */
|
|
32
33
|
const answers = []; /* what the fake forms were told */
|
|
33
34
|
const loaded = []; /* the rows each fake form was loaded with */
|
|
34
35
|
const commands = []; /* what the fake transport was asked */
|
|
@@ -103,7 +104,10 @@ beforeAll(() => {
|
|
|
103
104
|
"C_TEST_VIEW_HOST",
|
|
104
105
|
[["EV_RECORD_WRITTEN", 0], ["EV_TOPIC_SELECTED", 0]],
|
|
105
106
|
[["ST_IDLE", [
|
|
106
|
-
["EV_RECORD_WRITTEN", () =>
|
|
107
|
+
["EV_RECORD_WRITTEN", (gobj, event, kw) => {
|
|
108
|
+
written.push(kw);
|
|
109
|
+
return 0;
|
|
110
|
+
}, null],
|
|
107
111
|
["EV_TOPIC_SELECTED", () => 0, null]
|
|
108
112
|
]]],
|
|
109
113
|
{}, 0, [SDATA_END()], {}, 0, 0, 0, 0
|
|
@@ -121,6 +125,7 @@ beforeAll(() => {
|
|
|
121
125
|
|
|
122
126
|
beforeEach(() => {
|
|
123
127
|
logged.length = 0;
|
|
128
|
+
written.length = 0;
|
|
124
129
|
answers.length = 0;
|
|
125
130
|
commands.length = 0;
|
|
126
131
|
loaded.length = 0;
|
|
@@ -228,16 +233,26 @@ describe("a Save in flight when the backend drops", () => {
|
|
|
228
233
|
save(topics, forms.roles, 1);
|
|
229
234
|
|
|
230
235
|
/* The answer of the users write, the way C_IEVENT_CLI delivers it:
|
|
231
|
-
* the request's frame on top of the
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
+
* the request's `__md_command__` as the frame on top of the
|
|
237
|
+
* command_stack, and nothing else of the request. */
|
|
238
|
+
const users_write = commands.find((c) => c.command === "update-node" &&
|
|
239
|
+
c.kw.topic_name === "users");
|
|
240
|
+
const ok = {result: 0, comment: "", data: [{id: "x", name: "stored"}], __md_iev__: {
|
|
241
|
+
command_stack: [{command: "update-node", kw: users_write.kw.__md_command__}]
|
|
236
242
|
}};
|
|
237
243
|
gobj_send_event(topics, "EV_MT_COMMAND_ANSWER", ok, remote);
|
|
238
244
|
expect(answers).toEqual([
|
|
239
245
|
{topic: "users", event: "EV_WRITE_DONE", form_write: 1},
|
|
240
246
|
]);
|
|
247
|
+
/* What the host is told names the treedb and carries the record
|
|
248
|
+
* the store answered: read off that frame, both arrived empty. */
|
|
249
|
+
expect(written).toEqual([{
|
|
250
|
+
treedb_name: "treedb_test",
|
|
251
|
+
topic_name: "users",
|
|
252
|
+
record: {id: "x", name: "stored"},
|
|
253
|
+
created: false,
|
|
254
|
+
command: "update-node"
|
|
255
|
+
}]);
|
|
241
256
|
|
|
242
257
|
yui_shell_set_connection_state(shell, false);
|
|
243
258
|
expect(answers).toEqual([
|
|
@@ -247,13 +262,102 @@ describe("a Save in flight when the backend drops", () => {
|
|
|
247
262
|
});
|
|
248
263
|
});
|
|
249
264
|
|
|
265
|
+
/*
|
|
266
|
+
* The success answer of a request, the way C_IEVENT_CLI delivers it: the
|
|
267
|
+
* request's `__md_command__` as the frame, and nothing else of it.
|
|
268
|
+
*/
|
|
269
|
+
function answer_ok(request, data)
|
|
270
|
+
{
|
|
271
|
+
return {result: 0, comment: "", data: data, __md_iev__: {
|
|
272
|
+
command_stack: [{command: request.command, kw: request.kw.__md_command__}]
|
|
273
|
+
}};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/*
|
|
277
|
+
* Before gobj-ui 7.25.19 a delete answered published nothing (the case
|
|
278
|
+
* was an empty `break`), and `created` compared the command with
|
|
279
|
+
* "create-node" -- which the view never sends: its +New goes out as an
|
|
280
|
+
* update-node with `create_only`, so `created` was always false.
|
|
281
|
+
*/
|
|
282
|
+
describe("EV_RECORD_WRITTEN of a create and of a delete", () => {
|
|
283
|
+
|
|
284
|
+
test("a +New answered says created: true", () => {
|
|
285
|
+
const {shell, topics, forms} = build("tc1");
|
|
286
|
+
yui_shell_set_connection_state(shell, true);
|
|
287
|
+
gobj_send_event(topics, "EV_CREATE_RECORD",
|
|
288
|
+
{record: {id: "n1"}, form_write: 1}, forms.users);
|
|
289
|
+
|
|
290
|
+
const request = commands.find((c) => c.command === "update-node");
|
|
291
|
+
expect(request.kw.options.create_only).toBe(true);
|
|
292
|
+
gobj_send_event(topics, "EV_MT_COMMAND_ANSWER",
|
|
293
|
+
answer_ok(request, [{id: "n1", name: "new"}]), remote);
|
|
294
|
+
|
|
295
|
+
expect(written).toEqual([{
|
|
296
|
+
treedb_name: "treedb_test",
|
|
297
|
+
topic_name: "users",
|
|
298
|
+
record: {id: "n1", name: "new"},
|
|
299
|
+
created: true,
|
|
300
|
+
command: "update-node"
|
|
301
|
+
}]);
|
|
302
|
+
expect(answers).toEqual([
|
|
303
|
+
{topic: "users", event: "EV_WRITE_DONE", form_write: 1},
|
|
304
|
+
]);
|
|
305
|
+
expect(errors()).toEqual([]);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test("an edit answered says created: false", () => {
|
|
309
|
+
const {shell, topics, forms} = build("tc2");
|
|
310
|
+
yui_shell_set_connection_state(shell, true);
|
|
311
|
+
save(topics, forms.users, 1);
|
|
312
|
+
const request = commands.find((c) => c.command === "update-node");
|
|
313
|
+
gobj_send_event(topics, "EV_MT_COMMAND_ANSWER",
|
|
314
|
+
answer_ok(request, [{id: "x"}]), remote);
|
|
315
|
+
expect(written.map((w) => w.created)).toEqual([false]);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
test("a delete answered is published with the node deleted", () => {
|
|
319
|
+
const {shell, topics, forms} = build("tc3");
|
|
320
|
+
yui_shell_set_connection_state(shell, true);
|
|
321
|
+
gobj_send_event(topics, "EV_DELETE_RECORD", {record: {id: "x"}}, forms.roles);
|
|
322
|
+
|
|
323
|
+
const request = commands.find((c) => c.command === "delete-node");
|
|
324
|
+
expect(request).toBeTruthy();
|
|
325
|
+
gobj_send_event(topics, "EV_MT_COMMAND_ANSWER",
|
|
326
|
+
answer_ok(request, [{id: "x", name: "gone"}]), remote);
|
|
327
|
+
|
|
328
|
+
expect(written).toEqual([{
|
|
329
|
+
treedb_name: "treedb_test",
|
|
330
|
+
topic_name: "roles",
|
|
331
|
+
record: {id: "x", name: "gone"},
|
|
332
|
+
created: false,
|
|
333
|
+
command: "delete-node"
|
|
334
|
+
}]);
|
|
335
|
+
/* A delete has no form waiting for its answer. */
|
|
336
|
+
expect(answers).toEqual([]);
|
|
337
|
+
expect(errors()).toEqual([]);
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
test("a delete refused publishes nothing", () => {
|
|
341
|
+
const {shell, topics, forms} = build("tc4");
|
|
342
|
+
yui_shell_set_connection_state(shell, true);
|
|
343
|
+
gobj_send_event(topics, "EV_DELETE_RECORD", {record: {id: "x"}}, forms.roles);
|
|
344
|
+
const request = commands.find((c) => c.command === "delete-node");
|
|
345
|
+
gobj_send_event(topics, "EV_MT_COMMAND_ANSWER", {
|
|
346
|
+
result: -1, comment: "linked", data: null, __md_iev__: {
|
|
347
|
+
command_stack: [{command: "delete-node", kw: request.kw.__md_command__}]
|
|
348
|
+
}
|
|
349
|
+
}, remote);
|
|
350
|
+
expect(written).toEqual([]);
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
|
|
250
354
|
/*
|
|
251
355
|
* The answer the routing adapter gives a write it had in flight when
|
|
252
356
|
* its session closed: a failure, settled by the adapter itself.
|
|
253
357
|
*/
|
|
254
358
|
function failed_write(topic_name, form_write)
|
|
255
359
|
{
|
|
256
|
-
const md = {topic_name: topic_name
|
|
360
|
+
const md = {topic_name: topic_name}; /* the request's __md_command__, and only it */
|
|
257
361
|
if(form_write) {
|
|
258
362
|
md.form_write = form_write;
|
|
259
363
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/***********************************************************************
|
|
2
|
+
* uplot_add_serie.test.js
|
|
3
|
+
*
|
|
4
|
+
* C_YUI_UPLOT's EV_ADD_SERIE gives a series the palette's stroke
|
|
5
|
+
* and fill only when the host gave none. It did it through
|
|
6
|
+
* kw_get_str(KW_CREATE), which reads a stroke that is a FUNCTION
|
|
7
|
+
* (uPlot takes one, and a gradient) as a value of the wrong type:
|
|
8
|
+
* since gobj-js 7.25.5, which logs that as C does, every series
|
|
9
|
+
* added with one logged an error.
|
|
10
|
+
*
|
|
11
|
+
* Copyright (c) 2026, ArtGins.
|
|
12
|
+
* All Rights Reserved.
|
|
13
|
+
***********************************************************************/
|
|
14
|
+
import {describe, test, expect, beforeAll, beforeEach, vi} from "vitest";
|
|
15
|
+
import {install_dom_double} from "../test/dom_double.js";
|
|
16
|
+
|
|
17
|
+
install_dom_double();
|
|
18
|
+
|
|
19
|
+
/* uPlot draws on a canvas the document double does not have: the
|
|
20
|
+
* chart gets a stand-in, and the test writes its own over it. */
|
|
21
|
+
vi.mock("uplot", () => ({
|
|
22
|
+
default: class {
|
|
23
|
+
constructor() {
|
|
24
|
+
this.series = [{}];
|
|
25
|
+
}
|
|
26
|
+
setSize() {}
|
|
27
|
+
addSeries() {}
|
|
28
|
+
destroy() {}
|
|
29
|
+
}
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
const {
|
|
33
|
+
gobj_start_up, gobj_create_yuno, gobj_create_pure_child, gclass_create,
|
|
34
|
+
gobj_send_event, gobj_write_attr, set_log_callback, SDATA_END,
|
|
35
|
+
} = await import("@yuneta/gobj-js");
|
|
36
|
+
const {register_c_yui_uplot} = await import("./c_yui_uplot.js");
|
|
37
|
+
|
|
38
|
+
const logged = [];
|
|
39
|
+
let yuno = null;
|
|
40
|
+
|
|
41
|
+
beforeAll(() => {
|
|
42
|
+
gobj_start_up(null, null, null, null, null, null, null);
|
|
43
|
+
set_log_callback((level, msg) => {
|
|
44
|
+
logged.push({level: String(level), msg: String(msg)});
|
|
45
|
+
});
|
|
46
|
+
gclass_create("C_TEST_UPLOT_HOST", [], [["ST_IDLE", []]], {}, 0, [SDATA_END()], {}, 0, 0, 0, 0);
|
|
47
|
+
register_c_yui_uplot();
|
|
48
|
+
yuno = gobj_create_yuno("uplot_yuno", "C_TEST_UPLOT_HOST", {});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
beforeEach(() => {
|
|
52
|
+
logged.length = 0;
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
let seq = 0;
|
|
56
|
+
|
|
57
|
+
/* The chart, with uPlot replaced by what EV_ADD_SERIE asks of it. */
|
|
58
|
+
function build()
|
|
59
|
+
{
|
|
60
|
+
const chart = gobj_create_pure_child(`chart_${++seq}`, "C_YUI_UPLOT", {}, yuno);
|
|
61
|
+
const added = [];
|
|
62
|
+
gobj_write_attr(chart, "uplot", {
|
|
63
|
+
series: [{}],
|
|
64
|
+
addSeries: (kw) => {
|
|
65
|
+
added.push(kw);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
logged.length = 0;
|
|
69
|
+
return {chart, added};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
describe("EV_ADD_SERIE", () => {
|
|
73
|
+
|
|
74
|
+
test("a series with no colours takes the palette's", () => {
|
|
75
|
+
const {chart, added} = build();
|
|
76
|
+
gobj_send_event(chart, "EV_ADD_SERIE", {id: "a", label: "A"}, chart);
|
|
77
|
+
expect(added.length).toBe(1);
|
|
78
|
+
expect(typeof added[0].stroke).toBe("string");
|
|
79
|
+
expect(added[0].stroke.length).toBeGreaterThan(0);
|
|
80
|
+
expect(logged.filter((l) => l.level === "error")).toEqual([]);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("a stroke and a fill that are functions are kept, and nothing is logged", () => {
|
|
84
|
+
const {chart, added} = build();
|
|
85
|
+
const stroke = () => "red";
|
|
86
|
+
const fill = () => "pink";
|
|
87
|
+
gobj_send_event(chart, "EV_ADD_SERIE", {id: "b", stroke, fill}, chart);
|
|
88
|
+
expect(added[0].stroke).toBe(stroke);
|
|
89
|
+
expect(added[0].fill).toBe(fill);
|
|
90
|
+
expect(logged.filter((l) => l.level === "error")).toEqual([]);
|
|
91
|
+
});
|
|
92
|
+
});
|