@vuu-ui/vuu-data-test 4.0.0-alpha.2 → 4.0.0-alpha.20

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.
Files changed (51) hide show
  1. package/README.md +8 -0
  2. package/package.json +11 -9
  3. package/src/Table.js +5 -5
  4. package/src/core/filter/PermissionFilter.js +60 -0
  5. package/src/core/filter/PermissionFilteredTable.js +59 -0
  6. package/src/core/module/ModuleContainer.js +8 -0
  7. package/src/core/module/VuuModule.js +54 -6
  8. package/src/core/table/TableContainer.js +1 -1
  9. package/src/core/user/CurrentUser.js +13 -0
  10. package/src/index.js +7 -0
  11. package/src/local-datasource-provider/LocalDatasourceProvider.js +53 -43
  12. package/src/module-admin/ModuleAdminModule.js +124 -0
  13. package/src/module-admin/index.js +3 -0
  14. package/src/module-admin/module-admin-schemas.js +107 -0
  15. package/src/module-admin/snapshot-projection.js +29 -0
  16. package/src/notifications/NotificationModule.js +93 -0
  17. package/src/notifications/NotificationsSchema.js +52 -0
  18. package/src/notifications/index.js +6 -0
  19. package/src/notifications/simulated/DismissNotificationRpcHandler.js +36 -0
  20. package/src/notifications/simulated/SimulatedNotificationsModule.js +14 -0
  21. package/src/notifications/simulated/SimulatedNotificationsProvider.js +151 -0
  22. package/src/notifications/simulated/notificationsModule.js +3 -0
  23. package/src/schemas.js +8 -2
  24. package/src/user-admin/UserAdminModule.js +567 -0
  25. package/src/user-admin/index.js +3 -0
  26. package/src/user-admin/initialSnapshot.js +461 -0
  27. package/src/user-admin/snapshot-projection.js +151 -0
  28. package/types/core/filter/PermissionFilter.d.ts +41 -0
  29. package/types/core/filter/PermissionFilteredTable.d.ts +24 -0
  30. package/types/core/module/ModuleContainer.d.ts +6 -3
  31. package/types/core/module/VuuModule.d.ts +22 -0
  32. package/types/core/table/TableContainer.d.ts +5 -5
  33. package/types/core/user/CurrentUser.d.ts +14 -0
  34. package/types/index.d.ts +7 -0
  35. package/types/local-datasource-provider/LocalDatasourceProvider.d.ts +15 -1
  36. package/types/module-admin/ModuleAdminModule.d.ts +32 -0
  37. package/types/module-admin/index.d.ts +4 -0
  38. package/types/module-admin/module-admin-schemas.d.ts +4 -0
  39. package/types/module-admin/snapshot-projection.d.ts +13 -0
  40. package/types/notifications/NotificationModule.d.ts +39 -0
  41. package/types/notifications/NotificationsSchema.d.ts +20 -0
  42. package/types/notifications/index.d.ts +6 -0
  43. package/types/notifications/simulated/DismissNotificationRpcHandler.d.ts +8 -0
  44. package/types/notifications/simulated/SimulatedNotificationsModule.d.ts +2 -0
  45. package/types/notifications/simulated/SimulatedNotificationsProvider.d.ts +21 -0
  46. package/types/notifications/simulated/notificationsModule.d.ts +5 -0
  47. package/types/schemas.d.ts +5 -3
  48. package/types/user-admin/UserAdminModule.d.ts +54 -0
  49. package/types/user-admin/index.d.ts +3 -0
  50. package/types/user-admin/initialSnapshot.d.ts +2 -0
  51. package/types/user-admin/snapshot-projection.d.ts +9 -0
package/README.md CHANGED
@@ -0,0 +1,8 @@
1
+ # `@vuu-ui/vuu-data-test`
2
+
3
+ ## Admin test module dependencies
4
+
5
+ The `USER_ADMIN` and `MODULE_DISCOVERY` test modules use the published
6
+ `@heswell/user-admin` and `@heswell/module-admin` packages. Standard
7
+ `npm install` setup is sufficient. Browser code imports only the browser-safe
8
+ `contracts` subpath for module-admin.
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.0.0-alpha.2",
2
+ "version": "4.0.0-alpha.20",
3
3
  "main": "./src/index.js",
4
4
  "type": "module",
5
5
  "author": "heswell",
@@ -10,15 +10,16 @@
10
10
  "type-defs": "node ../../scripts/build-type-defs.mjs"
11
11
  },
12
12
  "dependencies": {
13
- "@vuu-ui/vuu-data-editing": "4.0.0-alpha.2",
14
- "@vuu-ui/vuu-data-local": "4.0.0-alpha.2",
15
- "@vuu-ui/core": "4.0.0-alpha.2",
16
- "@vuu-ui/vuu-utils": "4.0.0-alpha.2"
13
+ "@heswell/module-admin": "1.1.0",
14
+ "@heswell/user-admin": "1.0.1",
15
+ "@vuu-ui/vuu-data-editing": "4.0.0-alpha.20",
16
+ "@vuu-ui/vuu-data-local": "4.0.0-alpha.20",
17
+ "@vuu-ui/vuu-utils": "4.0.0-alpha.20"
17
18
  },
18
19
  "devDependencies": {
19
- "@vuu-ui/vuu-protocol-types": "4.0.0-alpha.2",
20
- "@vuu-ui/vuu-data-types": "4.0.0-alpha.2",
21
- "@vuu-ui/vuu-table-types": "4.0.0-alpha.2"
20
+ "@vuu-ui/vuu-data-types": "4.0.0-alpha.20",
21
+ "@vuu-ui/vuu-protocol-types": "4.0.0-alpha.20",
22
+ "@vuu-ui/vuu-table-types": "4.0.0-alpha.20"
22
23
  },
23
24
  "sideEffects": false,
24
25
  "files": [
@@ -28,8 +29,9 @@
28
29
  ],
29
30
  "exports": {
30
31
  ".": {
32
+ "types": "./types/index.d.ts",
31
33
  "import": "./src/index.js",
32
- "types": "./types/index.d.ts"
34
+ "default": "./src/index.js"
33
35
  }
34
36
  },
35
37
  "module": "./src/index.js",
package/src/Table.js CHANGED
@@ -20,7 +20,7 @@ class Table extends EventEmitter {
20
20
  }
21
21
  buildIndex() {
22
22
  for(let i = 0; i < this.#data.length; i++){
23
- const key = this.#data[i][this.#indexOfKey];
23
+ const key = String(this.#data[i][this.#indexOfKey]);
24
24
  this.#index.set(key, i);
25
25
  }
26
26
  }
@@ -41,7 +41,7 @@ class Table extends EventEmitter {
41
41
  if (-1 !== index) {
42
42
  this.#index.delete(key);
43
43
  this.#data.splice(index, 1);
44
- for(let i = index; i < this.#data.length; i++)this.#index.set(this.#data[i][this.#indexOfKey], i);
44
+ for(let i = index; i < this.#data.length; i++)this.#index.set(String(this.#data[i][this.#indexOfKey]), i);
45
45
  if (emitEvent) this.emit("delete", key);
46
46
  } else throw Error(`[Table] delete key ${key} not found`);
47
47
  }
@@ -51,7 +51,7 @@ class Table extends EventEmitter {
51
51
  row[this.#dataMap.vuuUpdatedTimestamp] = createdTime;
52
52
  row[this.#dataMap.vuuCreatedTimestamp] = createdTime;
53
53
  this.#data.push(row);
54
- const key = row[this.#indexOfKey];
54
+ const key = String(row[this.#indexOfKey]);
55
55
  this.#index.set(key, index);
56
56
  if (emitEvent) this.emit("insert", row);
57
57
  }
@@ -60,7 +60,7 @@ class Table extends EventEmitter {
60
60
  return this.#data[index];
61
61
  }
62
62
  update(key, columnName, value) {
63
- const rowIndex = this.#data.findIndex((row)=>row[this.#indexOfKey] === key);
63
+ const rowIndex = this.#data.findIndex((row)=>String(row[this.#indexOfKey]) === key);
64
64
  const colIndex = this.#dataMap[columnName];
65
65
  if (-1 !== rowIndex) {
66
66
  const row = this.#data[rowIndex];
@@ -77,7 +77,7 @@ class Table extends EventEmitter {
77
77
  }
78
78
  updateRow(row) {
79
79
  const key = row[this.#indexOfKey];
80
- const rowIndex = this.#data.findIndex((row)=>row[this.#indexOfKey] === key);
80
+ const rowIndex = this.#data.findIndex((row)=>String(row[this.#indexOfKey]) === String(key));
81
81
  if (-1 !== rowIndex) {
82
82
  const tsIndex = this.#dataMap.vuuUpdatedTimestamp;
83
83
  const lastUpdated = Date.now();
@@ -0,0 +1,60 @@
1
+ const allowAll = ()=>true;
2
+ const denyAll = ()=>false;
3
+ const AllowAllPermissionFilter = {
4
+ createPredicate: ()=>allowAll
5
+ };
6
+ const DenyAllPermissionFilter = {
7
+ createPredicate: ()=>denyAll
8
+ };
9
+ class RowPermissionFilter {
10
+ rowPredicate;
11
+ constructor(rowPredicate){
12
+ this.rowPredicate = rowPredicate;
13
+ }
14
+ createPredicate(columnMap) {
15
+ let currentRow = [];
16
+ const rowData = {
17
+ get: (columnName)=>{
18
+ const idx = columnMap[columnName];
19
+ return void 0 === idx ? void 0 : currentRow[idx];
20
+ }
21
+ };
22
+ return (row)=>{
23
+ currentRow = row;
24
+ return this.rowPredicate(rowData);
25
+ };
26
+ }
27
+ }
28
+ class ContainsPermissionFilter {
29
+ columnName;
30
+ allowedValues;
31
+ constructor(columnName, allowedValues){
32
+ this.columnName = columnName;
33
+ this.allowedValues = allowedValues;
34
+ }
35
+ createPredicate(columnMap) {
36
+ const idx = columnMap[this.columnName];
37
+ if (void 0 === idx || 0 === this.allowedValues.size) return denyAll;
38
+ const { allowedValues } = this;
39
+ return (row)=>{
40
+ const value = row[idx];
41
+ return null != value && allowedValues.has(String(value));
42
+ };
43
+ }
44
+ }
45
+ class PermissionFilterChain {
46
+ filters;
47
+ constructor(filters){
48
+ this.filters = filters;
49
+ }
50
+ createPredicate(columnMap) {
51
+ const predicates = this.filters.map((f)=>f.createPredicate(columnMap));
52
+ return (row)=>predicates.every((predicate)=>predicate(row));
53
+ }
54
+ }
55
+ function PermissionFilter(arg, allowedValues) {
56
+ if ("function" == typeof arg) return new RowPermissionFilter(arg);
57
+ if ("string" == typeof arg) return new ContainsPermissionFilter(arg, allowedValues ?? new Set());
58
+ return new PermissionFilterChain(Array.from(arg));
59
+ }
60
+ export { AllowAllPermissionFilter, DenyAllPermissionFilter, PermissionFilter };
@@ -0,0 +1,59 @@
1
+ import { Table } from "../../Table.js";
2
+ class PermissionFilteredTable extends Table {
3
+ #attached = false;
4
+ #indexOfKey;
5
+ #predicate;
6
+ #source;
7
+ constructor(source, predicate){
8
+ super(source.schema, source.data.filter(predicate), source.map);
9
+ this.#indexOfKey = source.map[source.schema.key];
10
+ this.#predicate = predicate;
11
+ this.#source = source;
12
+ this.attach();
13
+ }
14
+ get source() {
15
+ return this.#source;
16
+ }
17
+ attach() {
18
+ if (!this.#attached) {
19
+ this.#source.on("insert", this.handleSourceInsert);
20
+ this.#source.on("update", this.handleSourceUpdate);
21
+ this.#source.on("delete", this.handleSourceDelete);
22
+ this.#attached = true;
23
+ }
24
+ }
25
+ dispose() {
26
+ if (this.#attached) {
27
+ this.#source.removeListener("insert", this.handleSourceInsert);
28
+ this.#source.removeListener("update", this.handleSourceUpdate);
29
+ this.#source.removeListener("delete", this.handleSourceDelete);
30
+ this.#attached = false;
31
+ }
32
+ }
33
+ contains(key) {
34
+ return void 0 !== this.findByKey(key);
35
+ }
36
+ handleSourceInsert = (row)=>{
37
+ if (this.#predicate(row)) this.insert(row);
38
+ };
39
+ handleSourceUpdate = (row)=>{
40
+ const key = row[this.#indexOfKey];
41
+ const isMember = this.contains(key);
42
+ const isPermitted = this.#predicate(row);
43
+ if (isMember && isPermitted) this.replaceRow(row);
44
+ else if (isMember) this.delete(key);
45
+ else if (isPermitted) this.insert(row);
46
+ };
47
+ handleSourceDelete = (key)=>{
48
+ if (this.contains(key)) this.delete(key);
49
+ };
50
+ replaceRow(row) {
51
+ const key = row[this.#indexOfKey];
52
+ const rowIndex = this.data.findIndex((r)=>r[this.#indexOfKey] === key);
53
+ if (-1 !== rowIndex) {
54
+ this.data[rowIndex] = row;
55
+ this.emit("update", row);
56
+ }
57
+ }
58
+ }
59
+ export { PermissionFilteredTable };
@@ -8,6 +8,9 @@ class ModuleContainer {
8
8
  register(module) {
9
9
  this.#modules.set(module.name, module);
10
10
  }
11
+ has(name) {
12
+ return this.#modules.has(name);
13
+ }
11
14
  get(name) {
12
15
  const module = this.#modules.get(name);
13
16
  if (module) return module;
@@ -18,4 +21,9 @@ class ModuleContainer {
18
21
  }
19
22
  }
20
23
  var module_ModuleContainer = ModuleContainer.instance;
24
+ const ensureVuuModule = (module)=>{
25
+ if (!ModuleContainer.instance.has(module.name)) ModuleContainer.instance.register(module);
26
+ return module;
27
+ };
21
28
  export default module_ModuleContainer;
29
+ export { ensureVuuModule };
@@ -4,6 +4,10 @@ import { TickingArrayDataSource } from "../../TickingArrayDataSource.js";
4
4
  import { RuntimeVisualLink } from "../../RuntimeVisualLink.js";
5
5
  import ModuleContainer from "./ModuleContainer.js";
6
6
  import { sessionTableRow, sessionTableSchema } from "../../session-table-utils.js";
7
+ import { AllowAllPermissionFilter } from "../filter/PermissionFilter.js";
8
+ import { PermissionFilteredTable } from "../filter/PermissionFilteredTable.js";
9
+ import { getCurrentUser } from "../user/CurrentUser.js";
10
+ import TableContainer from "../table/TableContainer.js";
7
11
  const assertUpdateIsValid = (schema, column, _data)=>{
8
12
  const col = schema.columns.find((col)=>col.name === column);
9
13
  if (col) ;
@@ -22,6 +26,12 @@ class VuuModule {
22
26
  this.#sessionTableMessageColumn = sessionTableMessageColumn;
23
27
  ModuleContainer.register(this);
24
28
  }
29
+ get includeDefaultServices() {
30
+ return true;
31
+ }
32
+ async beforeSessionSave(_sourceTable, _sessionTable) {}
33
+ async afterSessionSave(_sourceTable, _sessionTable) {}
34
+ permissionFunctions;
25
35
  getTableSchema(tableName) {
26
36
  return this.schemas[tableName] ?? this.#sessionTableMap[tableName]?.schema;
27
37
  }
@@ -121,9 +131,17 @@ class VuuModule {
121
131
  return void 0 === linksForTable ? void 0 : this.getLinks(this.#subscriptionMap, linksForTable);
122
132
  };
123
133
  createDataSource = (tableName, viewport, config)=>{
134
+ this.beforeCreateDataSource?.(tableName);
124
135
  const columnDescriptors = this.getColumnDescriptors(tableName);
125
- const table = this.tables[tableName];
126
136
  const sessionTable = this.#sessionTableMap[tableName];
137
+ const user = getCurrentUser();
138
+ const permissionFunction = sessionTable ? void 0 : this.permissionFunctions?.[tableName];
139
+ const viewportId = permissionFunction ? viewport ?? uuid() : viewport;
140
+ const permissionFilteredTable = permissionFunction ? this.createPermissionFilteredTable(this.tables[tableName], permissionFunction, {
141
+ id: viewportId,
142
+ user
143
+ }) : void 0;
144
+ const table = permissionFilteredTable ?? this.tables[tableName];
127
145
  const vuuModule = this;
128
146
  const dataSource = new TickingArrayDataSource({
129
147
  ...config,
@@ -134,18 +152,24 @@ class VuuModule {
134
152
  menu: this.menus?.[tableName],
135
153
  rpcServices: this.getServices(tableName),
136
154
  rpcMenuServices: this.getMenuServices(tableName),
137
- viewport,
155
+ viewport: viewportId,
138
156
  visualLinkService: this.visualLinkService,
139
157
  vuuModule
140
158
  });
141
159
  dataSource.on("subscribed", this.handlePostSubscribeActivities);
142
160
  dataSource.on("unsubscribed", this.unregisterViewport);
161
+ if (permissionFilteredTable) {
162
+ dataSource.on("subscribed", ()=>permissionFilteredTable.attach());
163
+ dataSource.on("unsubscribed", ()=>permissionFilteredTable.dispose());
164
+ }
143
165
  const existingSubscriptions = this.#subscriptionMap.get(tableName);
144
166
  const subscription = {
145
167
  viewportId: dataSource.viewport,
146
168
  dataSource,
147
169
  sessionTableName: sessionTable ? tableName : void 0,
148
- sourceTableName: this.#sessionSourceTableMap[tableName]
170
+ sourceTableName: this.#sessionSourceTableMap[tableName],
171
+ table: table || sessionTable,
172
+ user
149
173
  };
150
174
  if (existingSubscriptions) existingSubscriptions.push(subscription);
151
175
  else this.#subscriptionMap.set(tableName, [
@@ -153,10 +177,16 @@ class VuuModule {
153
177
  ]);
154
178
  return dataSource;
155
179
  };
180
+ createPermissionFilteredTable(table, permissionFunction, viewport) {
181
+ const permissionFilter = permissionFunction(viewport, TableContainer);
182
+ if (permissionFilter === AllowAllPermissionFilter) return;
183
+ return new PermissionFilteredTable(table, permissionFilter.createPredicate(table.map));
184
+ }
156
185
  getServices(tableName) {
157
186
  const tableServices = this.services?.[tableName];
158
- if (Array.isArray(tableServices)) return this.#moduleServices.concat(tableServices);
159
- return this.#moduleServices;
187
+ const defaultServices = this.includeDefaultServices ? this.#moduleServices : [];
188
+ if (Array.isArray(tableServices)) return defaultServices.concat(tableServices);
189
+ return defaultServices;
160
190
  }
161
191
  getMenuServices(tableName) {
162
192
  const tableServices = this.menuServices?.[tableName];
@@ -221,7 +251,9 @@ class VuuModule {
221
251
  }
222
252
  return {
223
253
  type: "SUCCESS_RESULT",
224
- data: void 0
254
+ data: {
255
+ deletedKeys: selectedRowIds
256
+ }
225
257
  };
226
258
  }
227
259
  return {
@@ -492,6 +524,14 @@ class VuuModule {
492
524
  data: void 0
493
525
  };
494
526
  {
527
+ try {
528
+ await this.beforeSessionSave(sourceTable, sessionTable);
529
+ } catch (error) {
530
+ return {
531
+ errorMessage: error instanceof Error ? error.message : "Unable to prepare session changes",
532
+ type: "ERROR_RESULT"
533
+ };
534
+ }
495
535
  let rejectedCount = 0;
496
536
  const vuuMsgIdx = sessionTable.map[this.#sessionTableMessageColumn];
497
537
  const actionIdx = sessionTable.map.vuuAction;
@@ -526,6 +566,14 @@ class VuuModule {
526
566
  errorMessage: "stale update",
527
567
  type: "ERROR_RESULT"
528
568
  };
569
+ try {
570
+ await this.afterSessionSave(sourceTable, sessionTable);
571
+ } catch (error) {
572
+ return {
573
+ errorMessage: error instanceof Error ? error.message : "Unable to finalize session changes",
574
+ type: "ERROR_RESULT"
575
+ };
576
+ }
529
577
  return {
530
578
  type: "SUCCESS_RESULT",
531
579
  data: void 0
@@ -10,7 +10,7 @@ class TableContainer {
10
10
  return TableContainer.#instance;
11
11
  }
12
12
  #tables = new Map();
13
- createTable = (schema, data, dataMap, updateGenerator)=>{
13
+ createTable = (schema, data = [], dataMap = buildDataColumnMapFromSchema(schema), updateGenerator)=>{
14
14
  const table = new Table(schema, data, dataMap, updateGenerator);
15
15
  this.addTable(table);
16
16
  return table;
@@ -0,0 +1,13 @@
1
+ const DEFAULT_USER = {
2
+ name: "user",
3
+ authorizations: []
4
+ };
5
+ let currentUser = DEFAULT_USER;
6
+ const getCurrentUser = ()=>currentUser;
7
+ const setCurrentUser = (user)=>{
8
+ currentUser = void 0 === user ? DEFAULT_USER : "string" == typeof user ? {
9
+ name: user,
10
+ authorizations: []
11
+ } : user;
12
+ };
13
+ export { getCurrentUser, setCurrentUser };
package/src/index.js CHANGED
@@ -1,12 +1,19 @@
1
1
  export * from "./ArrayProxy.js";
2
+ export * from "./core/filter/PermissionFilter.js";
3
+ export * from "./core/filter/PermissionFilteredTable.js";
2
4
  export * from "./core/module/VuuModule.js";
5
+ export * from "./core/user/CurrentUser.js";
3
6
  export * from "./local-datasource-provider/LocalDatasourceProvider.js";
4
7
  export * from "./makeSuggestions.js";
8
+ export * from "./notifications/index.js";
5
9
  export * from "./schemas.js";
6
10
  export * from "./simul/index.js";
7
11
  export * from "./basket/index.js";
12
+ export * from "./module-admin/index.js";
13
+ export * from "./user-admin/index.js";
8
14
  export * from "./test/index.js";
9
15
  export * from "./TickingArrayDataSource.js";
10
16
  export * from "./vuu-row-generator.js";
17
+ export { ensureVuuModule } from "./core/module/ModuleContainer.js";
11
18
  export { default as tableContainer } from "./core/table/TableContainer.js";
12
19
  export { Table, buildDataColumnMap, buildDataColumnMapFromSchema } from "./Table.js";
@@ -1,50 +1,60 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { DataProvider } from "@vuu-ui/core";
3
3
  import { DataProvider as vuu_utils_DataProvider } from "@vuu-ui/vuu-utils";
4
- import ModuleContainer from "../core/module/ModuleContainer.js";
4
+ import ModuleContainer, { ensureVuuModule } from "../core/module/ModuleContainer.js";
5
5
  import TableContainer from "../core/table/TableContainer.js";
6
- const serverAPI = {
7
- getTableList: async ()=>{
8
- const tables = ModuleContainer.moduleNames.reduce((tableList, moduleName)=>{
9
- const moduleTables = ModuleContainer.get(moduleName).getTableList();
10
- moduleTables.forEach((tableName)=>{
11
- const table = TableContainer.getTable(tableName);
12
- tableList.push(table.schema.table);
13
- });
14
- return tableList;
15
- }, []);
16
- return {
17
- tables
18
- };
19
- },
20
- getTableSchema: async ({ module, table })=>ModuleContainer.get(module).getTableSchema(table),
21
- rpcCall: async ()=>{
22
- throw Error("RpcCall no longer supported on LocalDataSourceProvider ServerAPI");
6
+ const createLocalDataSourceProvider = (moduleNames)=>{
7
+ const getModule = (moduleName)=>{
8
+ if (moduleNames && !moduleNames.has(moduleName)) throw Error(`[LocalDataSourceProvider] module ${moduleName} is not available on this server`);
9
+ return ModuleContainer.get(moduleName);
10
+ };
11
+ const serverAPI = {
12
+ getTableList: async ()=>{
13
+ const tables = [];
14
+ for (const moduleName of moduleNames ?? ModuleContainer.moduleNames)for (const tableName of getModule(moduleName).getTableList())tables.push(TableContainer.getTable(tableName).schema.table);
15
+ return {
16
+ tables
17
+ };
18
+ },
19
+ getTableSchema: async ({ module, table })=>getModule(module).getTableSchema(table),
20
+ rpcCall: async ()=>{
21
+ throw Error("RpcCall no longer supported on LocalDataSourceProvider ServerAPI");
22
+ }
23
+ };
24
+ const getServerAPI = async ()=>serverAPI;
25
+ class VuuDataSource {
26
+ constructor({ aggregations, baseFilterSpec, columns, filterSpec, groupBy, session, sort, table, viewport, visualLink }){
27
+ const config = {
28
+ aggregations,
29
+ baseFilterSpec,
30
+ columns,
31
+ filterSpec,
32
+ groupBy,
33
+ session,
34
+ sort,
35
+ visualLink
36
+ };
37
+ const module = getModule(table.module);
38
+ return module.createDataSource(table.table, viewport, config);
39
+ }
23
40
  }
24
- };
25
- const getServerAPI = async ()=>serverAPI;
26
- class VuuDataSource {
27
- constructor({ aggregations, columns, filterSpec, groupBy, session, sort, table, viewport, visualLink }){
28
- const config = {
29
- aggregations,
30
- columns,
31
- filterSpec,
32
- groupBy,
33
- session,
34
- sort,
35
- visualLink
36
- };
37
- const module = ModuleContainer.get(table.module);
38
- return module.createDataSource(table.table, viewport, config);
39
- }
40
- }
41
- const LocalDataSourceProvider = ({ children })=>/*#__PURE__*/ jsx(vuu_utils_DataProvider, {
42
- VuuDataSource: VuuDataSource,
43
- getServerAPI: getServerAPI,
44
- children: /*#__PURE__*/ jsx(DataProvider, {
41
+ const DataSourceProvider = ({ children })=>/*#__PURE__*/ jsx(vuu_utils_DataProvider, {
45
42
  VuuDataSource: VuuDataSource,
46
43
  getServerAPI: getServerAPI,
47
- children: children
48
- })
49
- });
50
- export { LocalDataSourceProvider };
44
+ children: /*#__PURE__*/ jsx(DataProvider, {
45
+ VuuDataSource: VuuDataSource,
46
+ getServerAPI: getServerAPI,
47
+ children: children
48
+ })
49
+ });
50
+ return DataSourceProvider;
51
+ };
52
+ const LocalDataSourceProvider = createLocalDataSourceProvider();
53
+ const createLocalVuuServer = ({ connectionId, modules })=>{
54
+ modules.forEach(ensureVuuModule);
55
+ return {
56
+ connectionId,
57
+ DataSourceProvider: createLocalDataSourceProvider(new Set(modules.map(({ name })=>name)))
58
+ };
59
+ };
60
+ export { LocalDataSourceProvider, createLocalVuuServer };
@@ -0,0 +1,124 @@
1
+ import { DEFAULT_MODULE_DEFINITIONS, MODULE_ADMIN_RPC, MODULE_NAV_ICONS, executeModuleAdminRpc, toManagedModules } from "@heswell/module-admin/contracts";
2
+ import { VuuModule } from "../core/module/VuuModule.js";
3
+ import TableContainer from "../core/table/TableContainer.js";
4
+ import { buildDataColumnMapFromSchema } from "../Table.js";
5
+ import { MODULE_ADMIN_MODULE_NAME, MODULE_ADMIN_TABLE_SCHEMAS } from "./module-admin-schemas.js";
6
+ import { reconcileModuleAdminTables } from "./snapshot-projection.js";
7
+ const createTable = (tableName)=>{
8
+ const schema = MODULE_ADMIN_TABLE_SCHEMAS[tableName];
9
+ return TableContainer.createTable(schema, [], buildDataColumnMapFromSchema(schema));
10
+ };
11
+ const createTables = ()=>({
12
+ modulePermissions: createTable("modulePermissions"),
13
+ modules: createTable("modules")
14
+ });
15
+ const INITIAL_TIMESTAMP = 1710000000000;
16
+ const INITIAL_ACCESS_ROLES = [
17
+ {
18
+ moduleName: "moduleAdmin",
19
+ role: "module-admin-access"
20
+ },
21
+ {
22
+ moduleName: "userAdmin",
23
+ role: "user-admin-access"
24
+ },
25
+ {
26
+ moduleName: "basket-trading",
27
+ role: "basket-trading-access"
28
+ },
29
+ {
30
+ moduleName: "vuu-table-browser",
31
+ role: "vuu-table-browser-access"
32
+ }
33
+ ];
34
+ const EXAMPLE_MODULES = [
35
+ {
36
+ id: 6,
37
+ parentModuleId: 0,
38
+ name: "order-blotter",
39
+ title: "Order blotter",
40
+ description: "Monitor parent and child orders across all desks.",
41
+ version: 3,
42
+ enabled: false,
43
+ location: "/Trading/Orders",
44
+ path: "/trading/orders",
45
+ mfComponent: "OrderBlotter",
46
+ mfScope: "orderBlotter",
47
+ mfUrl: "http://localhost:5009",
48
+ navIconUrl: MODULE_NAV_ICONS.tables,
49
+ vuuConnectionId: "orders",
50
+ vuuWebsocketUrl: "wss://localhost:8095/websocket-orders",
51
+ vuuRestUrl: "https://localhost:8447/api/authn",
52
+ accessRole: "",
53
+ created: INITIAL_TIMESTAMP,
54
+ updated: INITIAL_TIMESTAMP
55
+ }
56
+ ];
57
+ const MODULE_ADMIN_INITIAL_SNAPSHOT = {
58
+ modules: [
59
+ ...toManagedModules(DEFAULT_MODULE_DEFINITIONS, INITIAL_ACCESS_ROLES, INITIAL_TIMESTAMP),
60
+ ...EXAMPLE_MODULES
61
+ ]
62
+ };
63
+ class ModuleAdminModule extends VuuModule {
64
+ now;
65
+ #modules;
66
+ #tables;
67
+ constructor(snapshot = MODULE_ADMIN_INITIAL_SNAPSHOT, now = Date.now){
68
+ super(MODULE_ADMIN_MODULE_NAME), this.now = now;
69
+ this.#modules = snapshot.modules;
70
+ this.#tables = createTables();
71
+ reconcileModuleAdminTables(snapshot, this.#tables);
72
+ }
73
+ get modules() {
74
+ return this.#modules;
75
+ }
76
+ get menus() {
77
+ return {
78
+ modulePermissions: void 0,
79
+ modules: void 0
80
+ };
81
+ }
82
+ get includeDefaultServices() {
83
+ return false;
84
+ }
85
+ get menuServices() {}
86
+ get schemas() {
87
+ return MODULE_ADMIN_TABLE_SCHEMAS;
88
+ }
89
+ service = (rpcName)=>async (request)=>{
90
+ try {
91
+ if ("RPC_REQUEST" !== request.type || request.rpcName !== rpcName) throw new Error(`Expected ${rpcName} RPC request`);
92
+ const { modules, result } = executeModuleAdminRpc(this.#modules, rpcName, request.params, this.now);
93
+ this.#modules = modules;
94
+ reconcileModuleAdminTables({
95
+ modules
96
+ }, this.#tables);
97
+ return {
98
+ data: result,
99
+ type: "SUCCESS_RESULT"
100
+ };
101
+ } catch (error) {
102
+ return {
103
+ errorMessage: error instanceof Error ? error.message : "Module admin request failed",
104
+ type: "ERROR_RESULT"
105
+ };
106
+ }
107
+ };
108
+ get services() {
109
+ const services = Object.keys(MODULE_ADMIN_RPC).map((rpcName)=>({
110
+ rpcName,
111
+ service: this.service(rpcName)
112
+ }));
113
+ return {
114
+ modulePermissions: services,
115
+ modules: services
116
+ };
117
+ }
118
+ get tables() {
119
+ return this.#tables;
120
+ }
121
+ get visualLinks() {}
122
+ }
123
+ const moduleAdminModule = new ModuleAdminModule();
124
+ export { MODULE_ADMIN_INITIAL_SNAPSHOT, ModuleAdminModule, moduleAdminModule };
@@ -0,0 +1,3 @@
1
+ export { MODULE_ADMIN_INITIAL_SNAPSHOT, ModuleAdminModule, moduleAdminModule } from "./ModuleAdminModule.js";
2
+ export { MODULE_ADMIN_MODULE_NAME, MODULE_ADMIN_TABLE_SCHEMAS } from "./module-admin-schemas.js";
3
+ export { projectModuleAdminSnapshot, reconcileModuleAdminTables } from "./snapshot-projection.js";