@vuu-ui/vuu-data-test 4.1.2 → 4.2.1
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/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.1
|
|
2
|
+
"version": "4.2.1",
|
|
3
3
|
"main": "./src/index.js",
|
|
4
4
|
"author": "heswell",
|
|
5
5
|
"license": "Apache-2.0",
|
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
"type-defs": "node ../../scripts/build-type-defs.mjs"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@vuu-ui/vuu-data-local": "4.1
|
|
12
|
-
"@vuu-ui/vuu-utils": "4.1
|
|
11
|
+
"@vuu-ui/vuu-data-local": "4.2.1",
|
|
12
|
+
"@vuu-ui/vuu-utils": "4.2.1"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
|
-
"@vuu-ui/vuu-protocol-types": "4.1
|
|
16
|
-
"@vuu-ui/vuu-data-types": "4.1
|
|
17
|
-
"@vuu-ui/vuu-table-types": "4.1
|
|
15
|
+
"@vuu-ui/vuu-protocol-types": "4.2.1",
|
|
16
|
+
"@vuu-ui/vuu-data-types": "4.2.1",
|
|
17
|
+
"@vuu-ui/vuu-table-types": "4.2.1"
|
|
18
18
|
},
|
|
19
19
|
"sideEffects": false,
|
|
20
20
|
"files": [
|
|
@@ -22,6 +22,7 @@ class VuuModule {
|
|
|
22
22
|
this.#sessionTableMessageColumn = sessionTableMessageColumn;
|
|
23
23
|
ModuleContainer.register(this);
|
|
24
24
|
}
|
|
25
|
+
validateEdit(_tableName, _column, _value) {}
|
|
25
26
|
getTableSchema(tableName) {
|
|
26
27
|
return this.schemas[tableName] ?? this.#sessionTableMap[tableName]?.schema;
|
|
27
28
|
}
|
|
@@ -305,14 +306,20 @@ class VuuModule {
|
|
|
305
306
|
const { column, data, key } = rpcRequest.params;
|
|
306
307
|
const sessionTable = this.#sessionTableMap[viewPortId];
|
|
307
308
|
let targetTable = sessionTable;
|
|
309
|
+
let sourceTableName = this.#sessionSourceTableMap[viewPortId];
|
|
308
310
|
if (!targetTable) {
|
|
309
311
|
const { dataSource } = this.getSubscriptionByViewport(viewPortId);
|
|
310
|
-
if (dataSource.table)
|
|
312
|
+
if (dataSource.table) {
|
|
313
|
+
sourceTableName = dataSource.table.table;
|
|
314
|
+
targetTable = this.tables[sourceTableName];
|
|
315
|
+
}
|
|
311
316
|
}
|
|
312
317
|
if (targetTable) try {
|
|
313
318
|
const sessionRow = sessionTable?.findByKey(key);
|
|
314
319
|
if (sessionRow?.[sessionTable.map.vuuAction] === "deleteRow") throw Error("editCell: cannot edit a deleted row");
|
|
315
320
|
assertUpdateIsValid(targetTable.schema, column, data);
|
|
321
|
+
const validationError = void 0 === sourceTableName ? void 0 : this.validateEdit(sourceTableName, column, data);
|
|
322
|
+
if (void 0 !== validationError) throw Error(validationError);
|
|
316
323
|
targetTable.update(key, column, data);
|
|
317
324
|
if (sessionTable && sessionTable.findByKey(key)?.[sessionTable.map.vuuAction] !== "addRow") sessionTable.update(key, "vuuAction", "editCell");
|
|
318
325
|
return {
|
|
@@ -460,6 +467,14 @@ class VuuModule {
|
|
|
460
467
|
errorMessage: `addRow: no active session table for viewport ${viewPortId}`
|
|
461
468
|
};
|
|
462
469
|
const { data, key } = rpcRequest.params;
|
|
470
|
+
const sourceTableName = this.#sessionSourceTableMap[sessionTableName];
|
|
471
|
+
if (void 0 !== sourceTableName) for (const [column, value] of Object.entries(data)){
|
|
472
|
+
const validationError = this.validateEdit(sourceTableName, column, value);
|
|
473
|
+
if (void 0 !== validationError) return {
|
|
474
|
+
type: "ERROR_RESULT",
|
|
475
|
+
errorMessage: validationError
|
|
476
|
+
};
|
|
477
|
+
}
|
|
463
478
|
const keyColumn = sessionTable.schema.key;
|
|
464
479
|
const rowKey = data[keyColumn] ?? key ?? uuid();
|
|
465
480
|
const rowData = {
|
package/src/test/TestModule.js
CHANGED
|
@@ -13,6 +13,48 @@ const generateRows = (tableSchema, count)=>{
|
|
|
13
13
|
const columnGenerator = RowGenerator(tableSchema.columns.map((c)=>c.name));
|
|
14
14
|
return new Array(count).fill(1).map((_, i)=>columnGenerator(i));
|
|
15
15
|
};
|
|
16
|
+
const CHART_VARIANT_MAX_SERIES = 50;
|
|
17
|
+
const CHART_VARIANT_PREFIXES = Array.from({
|
|
18
|
+
length: CHART_VARIANT_MAX_SERIES
|
|
19
|
+
}, (_, i)=>`series_${String(i + 1).padStart(2, "0")}`);
|
|
20
|
+
const CHART_VARIANT_SUFFIXES = [
|
|
21
|
+
"set_a",
|
|
22
|
+
"set_b",
|
|
23
|
+
"set_c"
|
|
24
|
+
];
|
|
25
|
+
const chartVariantColumns = [
|
|
26
|
+
{
|
|
27
|
+
name: "id",
|
|
28
|
+
serverDataType: "string"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "date",
|
|
32
|
+
serverDataType: "string"
|
|
33
|
+
},
|
|
34
|
+
...CHART_VARIANT_PREFIXES.flatMap((prefix)=>CHART_VARIANT_SUFFIXES.map((suffix)=>({
|
|
35
|
+
name: `${prefix}_${suffix}`,
|
|
36
|
+
serverDataType: "double"
|
|
37
|
+
})))
|
|
38
|
+
];
|
|
39
|
+
const chartVariantScale = [
|
|
40
|
+
1,
|
|
41
|
+
0.6,
|
|
42
|
+
0.3
|
|
43
|
+
];
|
|
44
|
+
const chartVariantRows = ()=>Array.from({
|
|
45
|
+
length: 25
|
|
46
|
+
}, (_, day)=>{
|
|
47
|
+
const date = new Date(Date.UTC(2026, 3, 2 + day)).toISOString().slice(0, 10);
|
|
48
|
+
const values = CHART_VARIANT_PREFIXES.flatMap((_, p)=>{
|
|
49
|
+
const base = 100 + 20 * p + Math.round(15 * Math.sin((day + 3 * p) / 4));
|
|
50
|
+
return chartVariantScale.map((scale)=>Math.round(base * scale));
|
|
51
|
+
});
|
|
52
|
+
return [
|
|
53
|
+
String(day + 1).padStart(3, "0"),
|
|
54
|
+
date,
|
|
55
|
+
...values
|
|
56
|
+
];
|
|
57
|
+
});
|
|
16
58
|
const testEditColumns = [
|
|
17
59
|
{
|
|
18
60
|
name: "id",
|
|
@@ -39,6 +81,17 @@ const testEditColumns = [
|
|
|
39
81
|
serverDataType: "long"
|
|
40
82
|
}
|
|
41
83
|
];
|
|
84
|
+
const TEST_EDIT_VALIDATION_QUANTITY_MESSAGE = "quantity must be between 1 and 1000";
|
|
85
|
+
const TEST_EDIT_VALIDATION_PRICE_MESSAGE = "price must be greater than zero";
|
|
86
|
+
const validateTestEditValidation = (column, value)=>{
|
|
87
|
+
if ("quantity" === column) {
|
|
88
|
+
const quantity = Number(value);
|
|
89
|
+
if (!Number.isInteger(quantity) || quantity < 1 || quantity > 1000) return TEST_EDIT_VALIDATION_QUANTITY_MESSAGE;
|
|
90
|
+
} else if ("price" === column) {
|
|
91
|
+
const price = Number(value);
|
|
92
|
+
if (!(price > 0)) return TEST_EDIT_VALIDATION_PRICE_MESSAGE;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
42
95
|
class TestModule extends VuuModule {
|
|
43
96
|
#schemas = {
|
|
44
97
|
TestDates: {
|
|
@@ -153,6 +206,15 @@ class TestModule extends VuuModule {
|
|
|
153
206
|
table: "ChartTable"
|
|
154
207
|
}
|
|
155
208
|
},
|
|
209
|
+
ChartVariantTable: {
|
|
210
|
+
columns: chartVariantColumns,
|
|
211
|
+
key: "id",
|
|
212
|
+
rangeLimits: DEFAULT_RANGE_LIMITS,
|
|
213
|
+
table: {
|
|
214
|
+
module: "TEST",
|
|
215
|
+
table: "ChartVariantTable"
|
|
216
|
+
}
|
|
217
|
+
},
|
|
156
218
|
MaxScrollEndTable: {
|
|
157
219
|
columns: DefaultColumnGenerator(6).map((col)=>toSchemaColumn({
|
|
158
220
|
...col,
|
|
@@ -185,6 +247,15 @@ class TestModule extends VuuModule {
|
|
|
185
247
|
module: "TEST",
|
|
186
248
|
table: "TestEdit"
|
|
187
249
|
}
|
|
250
|
+
},
|
|
251
|
+
TestEditValidation: {
|
|
252
|
+
columns: testEditColumns,
|
|
253
|
+
key: "id",
|
|
254
|
+
rangeLimits: DEFAULT_RANGE_LIMITS,
|
|
255
|
+
table: {
|
|
256
|
+
module: "TEST",
|
|
257
|
+
table: "TestEditValidation"
|
|
258
|
+
}
|
|
188
259
|
}
|
|
189
260
|
};
|
|
190
261
|
#tables = {
|
|
@@ -509,6 +580,7 @@ class TestModule extends VuuModule {
|
|
|
509
580
|
false
|
|
510
581
|
]
|
|
511
582
|
], buildDataColumnMap(this.#schemas, "ChartTable")),
|
|
583
|
+
ChartVariantTable: TableContainer.createTable(this.#schemas.ChartVariantTable, chartVariantRows(), buildDataColumnMap(this.#schemas, "ChartVariantTable")),
|
|
512
584
|
MaxScrollEndTable: TableContainer.createTable(this.#schemas.MaxScrollEndTable, generateRows(this.#schemas.MaxScrollEndTable, 1000), buildDataColumnMap(this.#schemas, "MaxScrollEndTable")),
|
|
513
585
|
TestEditEmpty: TableContainer.createTable(this.#schemas.TestEditEmpty, [], buildDataColumnMap(this.#schemas, "TestEditEmpty")),
|
|
514
586
|
TestEdit: TableContainer.createTable(this.#schemas.TestEdit, [
|
|
@@ -562,7 +634,49 @@ class TestModule extends VuuModule {
|
|
|
562
634
|
withNanoMs(Date.now(), 5),
|
|
563
635
|
1000000000000000005n
|
|
564
636
|
]
|
|
565
|
-
], buildDataColumnMap(this.#schemas, "TestEdit"))
|
|
637
|
+
], buildDataColumnMap(this.#schemas, "TestEdit")),
|
|
638
|
+
TestEditValidation: TableContainer.createTable(this.#schemas.TestEditValidation, [
|
|
639
|
+
[
|
|
640
|
+
"VAL-001",
|
|
641
|
+
"Alpha",
|
|
642
|
+
12,
|
|
643
|
+
101.25,
|
|
644
|
+
true,
|
|
645
|
+
1001
|
|
646
|
+
],
|
|
647
|
+
[
|
|
648
|
+
"VAL-002",
|
|
649
|
+
"Bravo",
|
|
650
|
+
24,
|
|
651
|
+
202.5,
|
|
652
|
+
false,
|
|
653
|
+
1002
|
|
654
|
+
],
|
|
655
|
+
[
|
|
656
|
+
"VAL-003",
|
|
657
|
+
"Charlie",
|
|
658
|
+
36,
|
|
659
|
+
303.75,
|
|
660
|
+
true,
|
|
661
|
+
1003
|
|
662
|
+
],
|
|
663
|
+
[
|
|
664
|
+
"VAL-004",
|
|
665
|
+
"Delta",
|
|
666
|
+
48,
|
|
667
|
+
405,
|
|
668
|
+
true,
|
|
669
|
+
1004
|
|
670
|
+
],
|
|
671
|
+
[
|
|
672
|
+
"VAL-005",
|
|
673
|
+
"Echo",
|
|
674
|
+
60,
|
|
675
|
+
506.25,
|
|
676
|
+
false,
|
|
677
|
+
1005
|
|
678
|
+
]
|
|
679
|
+
], buildDataColumnMap(this.#schemas, "TestEditValidation"))
|
|
566
680
|
};
|
|
567
681
|
constructor(){
|
|
568
682
|
super("TEST");
|
|
@@ -577,6 +691,9 @@ class TestModule extends VuuModule {
|
|
|
577
691
|
return this.#tables;
|
|
578
692
|
}
|
|
579
693
|
get visualLinks() {}
|
|
694
|
+
validateEdit(tableName, column, value) {
|
|
695
|
+
return "TestEditValidation" === tableName ? validateTestEditValidation(column, value) : void 0;
|
|
696
|
+
}
|
|
580
697
|
}
|
|
581
698
|
const testModule = new TestModule();
|
|
582
|
-
export { testModule };
|
|
699
|
+
export { CHART_VARIANT_MAX_SERIES, CHART_VARIANT_PREFIXES, CHART_VARIANT_SUFFIXES, TEST_EDIT_VALIDATION_PRICE_MESSAGE, TEST_EDIT_VALIDATION_QUANTITY_MESSAGE, testModule };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DataSourceBase, DataSourceConfig, DataSourceRowWithBigint, DataSourceSubscribedMessage, DataSourceVisualLinkCreatedMessage, EditSessionMode, CopyOption, SessionDataSourceOverrides, SessionType, TableSchema } from "@vuu-ui/vuu-data-types";
|
|
2
|
-
import type { VuuMenu, VuuLink, LinkDescriptorWithLabel, VuuRpcMenuResponse, VuuCreateVisualLink, VuuRemoveVisualLink, VuuRpcServiceRequest, RpcResultSuccess, RpcResultError, VuuRpcMenuRequest } from "@vuu-ui/vuu-protocol-types";
|
|
2
|
+
import type { VuuMenu, VuuRowDataItemType, VuuLink, LinkDescriptorWithLabel, VuuRpcMenuResponse, VuuCreateVisualLink, VuuRemoveVisualLink, VuuRpcServiceRequest, RpcResultSuccess, RpcResultError, VuuRpcMenuRequest } from "@vuu-ui/vuu-protocol-types";
|
|
3
3
|
import { Table } from "../../Table";
|
|
4
4
|
import { TickingArrayDataSource } from "../../TickingArrayDataSource";
|
|
5
5
|
export interface IVuuModule<T extends string = string> {
|
|
@@ -38,6 +38,12 @@ export declare abstract class VuuModule<T extends string = string> implements IV
|
|
|
38
38
|
protected abstract menuServices?: Record<T, RpcMenuService[] | undefined> | undefined;
|
|
39
39
|
protected abstract services?: Record<T, RpcService[] | undefined> | undefined;
|
|
40
40
|
protected abstract visualLinks?: Record<T, VuuLink[] | undefined>;
|
|
41
|
+
/**
|
|
42
|
+
* Server-side validation applied to every value submitted by editCell and
|
|
43
|
+
* addRow. `tableName` is the source table, also when the edit targets a
|
|
44
|
+
* session table. Return a message to reject the value, undefined to accept.
|
|
45
|
+
*/
|
|
46
|
+
protected validateEdit(_tableName: T, _column: string, _value: VuuRowDataItemType): string | undefined;
|
|
41
47
|
getTableSchema(tableName: string): Record<T, Readonly<TableSchema>>[T];
|
|
42
48
|
getTableList(): string[];
|
|
43
49
|
protected handlePostSubscribeActivities: ({ clientViewportId, tableSchema, }: DataSourceSubscribedMessage) => void;
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { type RpcMenuService, VuuModule } from "../core/module/VuuModule";
|
|
2
2
|
import { type Table } from "../Table";
|
|
3
3
|
import type { TableSchema } from "@vuu-ui/vuu-data-types";
|
|
4
|
-
|
|
4
|
+
import type { VuuRowDataItemType } from "@vuu-ui/vuu-protocol-types";
|
|
5
|
+
export type TestTableName = "TestDates" | "TwoHundredColumns" | "LinkParent" | "LinkChild" | "ChartTable" | "ChartVariantTable" | "MaxScrollEndTable" | "TestEditEmpty" | "TestEdit" | "TestEditValidation";
|
|
6
|
+
export declare const CHART_VARIANT_MAX_SERIES = 50;
|
|
7
|
+
export declare const CHART_VARIANT_PREFIXES: string[];
|
|
8
|
+
export declare const CHART_VARIANT_SUFFIXES: string[];
|
|
9
|
+
export declare const TEST_EDIT_VALIDATION_QUANTITY_MESSAGE = "quantity must be between 1 and 1000";
|
|
10
|
+
export declare const TEST_EDIT_VALIDATION_PRICE_MESSAGE = "price must be greater than zero";
|
|
5
11
|
declare class TestModule extends VuuModule<TestTableName> {
|
|
6
12
|
#private;
|
|
7
13
|
constructor();
|
|
@@ -11,6 +17,7 @@ declare class TestModule extends VuuModule<TestTableName> {
|
|
|
11
17
|
get schemas(): Record<TestTableName, TableSchema>;
|
|
12
18
|
get tables(): Record<TestTableName, Table>;
|
|
13
19
|
get visualLinks(): undefined;
|
|
20
|
+
protected validateEdit(tableName: TestTableName, column: string, value: VuuRowDataItemType): string | undefined;
|
|
14
21
|
}
|
|
15
22
|
export declare const testModule: TestModule;
|
|
16
23
|
export {};
|