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

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 (53) hide show
  1. package/README.md +8 -0
  2. package/package.json +11 -9
  3. package/src/Table.js +5 -5
  4. package/src/TickingArrayDataSource.js +7 -2
  5. package/src/core/filter/PermissionFilter.js +60 -0
  6. package/src/core/filter/PermissionFilteredTable.js +59 -0
  7. package/src/core/module/ModuleContainer.js +8 -0
  8. package/src/core/module/VuuModule.js +57 -7
  9. package/src/core/table/TableContainer.js +1 -1
  10. package/src/core/user/CurrentUser.js +13 -0
  11. package/src/index.js +7 -0
  12. package/src/local-datasource-provider/LocalDatasourceProvider.js +64 -44
  13. package/src/module-admin/ModuleAdminModule.js +124 -0
  14. package/src/module-admin/index.js +3 -0
  15. package/src/module-admin/module-admin-schemas.js +95 -0
  16. package/src/module-admin/snapshot-projection.js +29 -0
  17. package/src/notifications/NotificationModule.js +131 -0
  18. package/src/notifications/NotificationsSchema.js +52 -0
  19. package/src/notifications/index.js +6 -0
  20. package/src/notifications/simulated/DismissNotificationRpcHandler.js +36 -0
  21. package/src/notifications/simulated/SimulatedNotificationsModule.js +18 -0
  22. package/src/notifications/simulated/SimulatedNotificationsProvider.js +151 -0
  23. package/src/notifications/simulated/notificationsModule.js +3 -0
  24. package/src/schemas.js +8 -2
  25. package/src/user-admin/UserAdminModule.js +567 -0
  26. package/src/user-admin/index.js +3 -0
  27. package/src/user-admin/initialSnapshot.js +461 -0
  28. package/src/user-admin/snapshot-projection.js +151 -0
  29. package/types/TickingArrayDataSource.d.ts +1 -1
  30. package/types/core/filter/PermissionFilter.d.ts +41 -0
  31. package/types/core/filter/PermissionFilteredTable.d.ts +24 -0
  32. package/types/core/module/ModuleContainer.d.ts +6 -3
  33. package/types/core/module/VuuModule.d.ts +22 -0
  34. package/types/core/table/TableContainer.d.ts +5 -5
  35. package/types/core/user/CurrentUser.d.ts +14 -0
  36. package/types/index.d.ts +7 -0
  37. package/types/local-datasource-provider/LocalDatasourceProvider.d.ts +18 -2
  38. package/types/module-admin/ModuleAdminModule.d.ts +32 -0
  39. package/types/module-admin/index.d.ts +4 -0
  40. package/types/module-admin/module-admin-schemas.d.ts +4 -0
  41. package/types/module-admin/snapshot-projection.d.ts +13 -0
  42. package/types/notifications/NotificationModule.d.ts +60 -0
  43. package/types/notifications/NotificationsSchema.d.ts +20 -0
  44. package/types/notifications/index.d.ts +6 -0
  45. package/types/notifications/simulated/DismissNotificationRpcHandler.d.ts +8 -0
  46. package/types/notifications/simulated/SimulatedNotificationsModule.d.ts +9 -0
  47. package/types/notifications/simulated/SimulatedNotificationsProvider.d.ts +21 -0
  48. package/types/notifications/simulated/notificationsModule.d.ts +5 -0
  49. package/types/schemas.d.ts +5 -3
  50. package/types/user-admin/UserAdminModule.d.ts +54 -0
  51. package/types/user-admin/index.d.ts +3 -0
  52. package/types/user-admin/initialSnapshot.d.ts +2 -0
  53. package/types/user-admin/snapshot-projection.d.ts +9 -0
@@ -0,0 +1,461 @@
1
+ const USER_ADMIN_INITIAL_SNAPSHOT = {
2
+ clients: [
3
+ {
4
+ clientId: "vuu-portal",
5
+ description: "VUU portal",
6
+ enabled: true,
7
+ id: "client-portal",
8
+ name: "VUU Portal"
9
+ },
10
+ {
11
+ clientId: "vuu-user-admin",
12
+ description: "User administration",
13
+ enabled: true,
14
+ id: "client-user-admin",
15
+ name: "User Admin"
16
+ },
17
+ {
18
+ clientId: "vuu-basket-trading",
19
+ description: "Basket trading",
20
+ enabled: true,
21
+ id: "client-basket-trading",
22
+ name: "Basket Trading"
23
+ },
24
+ {
25
+ clientId: "vuu-module-admin",
26
+ description: "Module administration",
27
+ enabled: true,
28
+ id: "client-module-admin",
29
+ name: "Module Admin"
30
+ },
31
+ {
32
+ clientId: "vuu-feature-filter-table",
33
+ description: "Instrument tables",
34
+ enabled: true,
35
+ id: "client-feature-filter-table",
36
+ name: "Instruments"
37
+ }
38
+ ],
39
+ clientRoles: [
40
+ {
41
+ client: {
42
+ clientId: "vuu-portal",
43
+ id: "client-portal",
44
+ name: "VUU Portal"
45
+ },
46
+ role: {
47
+ clientRole: true,
48
+ containerId: "client-portal",
49
+ id: "role-user-admin-access",
50
+ name: "user-admin-access",
51
+ roleDisplayName: "access"
52
+ }
53
+ },
54
+ {
55
+ client: {
56
+ clientId: "vuu-portal",
57
+ id: "client-portal",
58
+ name: "VUU Portal"
59
+ },
60
+ role: {
61
+ clientRole: true,
62
+ containerId: "client-portal",
63
+ id: "role-feature-filter-table-access",
64
+ name: "feature-filter-table-access",
65
+ roleDisplayName: "access"
66
+ }
67
+ },
68
+ {
69
+ client: {
70
+ clientId: "vuu-portal",
71
+ id: "client-portal",
72
+ name: "VUU Portal"
73
+ },
74
+ role: {
75
+ clientRole: true,
76
+ containerId: "client-portal",
77
+ id: "role-module-admin-access",
78
+ name: "module-admin-access",
79
+ roleDisplayName: "access"
80
+ }
81
+ },
82
+ {
83
+ client: {
84
+ clientId: "vuu-portal",
85
+ id: "client-portal",
86
+ name: "VUU Portal"
87
+ },
88
+ role: {
89
+ clientRole: true,
90
+ containerId: "client-portal",
91
+ id: "role-basket-trading-access",
92
+ name: "basket-trading-access",
93
+ roleDisplayName: "access"
94
+ }
95
+ },
96
+ {
97
+ client: {
98
+ clientId: "vuu-user-admin",
99
+ id: "client-user-admin",
100
+ name: "User Admin"
101
+ },
102
+ role: {
103
+ clientRole: true,
104
+ containerId: "client-user-admin",
105
+ id: "role-user-admin-admin",
106
+ name: "user-admin-admin",
107
+ roleDisplayName: "admin"
108
+ }
109
+ },
110
+ {
111
+ client: {
112
+ clientId: "vuu-module-admin",
113
+ id: "client-module-admin",
114
+ name: "Module Admin"
115
+ },
116
+ role: {
117
+ clientRole: true,
118
+ containerId: "client-module-admin",
119
+ id: "role-module-admin-admin",
120
+ name: "module-admin-admin",
121
+ roleDisplayName: "admin"
122
+ }
123
+ },
124
+ {
125
+ client: {
126
+ clientId: "vuu-basket-trading",
127
+ id: "client-basket-trading",
128
+ name: "Basket Trading"
129
+ },
130
+ role: {
131
+ clientRole: true,
132
+ containerId: "client-basket-trading",
133
+ id: "role-basket-trading-trade",
134
+ name: "basket-trading-trade",
135
+ roleDisplayName: "trade"
136
+ }
137
+ }
138
+ ],
139
+ groupRoles: [
140
+ {
141
+ client: {
142
+ clientId: "vuu-portal",
143
+ id: "client-portal",
144
+ name: "VUU Portal"
145
+ },
146
+ group: {
147
+ id: "group-user-admin-read",
148
+ name: "user-admin-read",
149
+ groupDisplayName: "read",
150
+ moduleAccessDefaultRoles: [
151
+ "user-admin-access"
152
+ ],
153
+ path: "/vuu/user-admin-read"
154
+ },
155
+ role: {
156
+ id: "role-user-admin-access",
157
+ name: "user-admin-access",
158
+ roleDisplayName: "access"
159
+ }
160
+ },
161
+ {
162
+ client: {
163
+ clientId: "vuu-portal",
164
+ id: "client-portal",
165
+ name: "VUU Portal"
166
+ },
167
+ group: {
168
+ id: "group-feature-filter-table-read",
169
+ name: "feature-filter-table-read",
170
+ groupDisplayName: "read",
171
+ moduleAccessDefaultRoles: [
172
+ "feature-filter-table-access"
173
+ ],
174
+ path: "/vuu/feature-filter-table-read"
175
+ },
176
+ role: {
177
+ id: "role-feature-filter-table-access",
178
+ name: "feature-filter-table-access",
179
+ roleDisplayName: "access"
180
+ }
181
+ },
182
+ {
183
+ client: {
184
+ clientId: "vuu-portal",
185
+ id: "client-portal",
186
+ name: "VUU Portal"
187
+ },
188
+ group: {
189
+ id: "group-module-admin-read",
190
+ name: "module-admin-read",
191
+ groupDisplayName: "read",
192
+ moduleAccessDefaultRoles: [
193
+ "module-admin-access"
194
+ ],
195
+ path: "/vuu/module-admin-read"
196
+ },
197
+ role: {
198
+ id: "role-module-admin-access",
199
+ name: "module-admin-access",
200
+ roleDisplayName: "access"
201
+ }
202
+ },
203
+ {
204
+ client: {
205
+ clientId: "vuu-portal",
206
+ id: "client-portal",
207
+ name: "VUU Portal"
208
+ },
209
+ group: {
210
+ id: "group-basket-trading-read",
211
+ name: "basket-trading-read",
212
+ groupDisplayName: "read",
213
+ moduleAccessDefaultRoles: [
214
+ "basket-trading-access"
215
+ ],
216
+ path: "/vuu/basket-trading-read"
217
+ },
218
+ role: {
219
+ id: "role-basket-trading-access",
220
+ name: "basket-trading-access",
221
+ roleDisplayName: "access"
222
+ }
223
+ },
224
+ {
225
+ client: {
226
+ clientId: "vuu-portal",
227
+ id: "client-portal",
228
+ name: "VUU Portal"
229
+ },
230
+ group: {
231
+ id: "group-user-admin-admin",
232
+ name: "user-admin-admin",
233
+ groupDisplayName: "admin",
234
+ path: "/vuu/user-admin-admin"
235
+ },
236
+ role: {
237
+ id: "role-user-admin-access",
238
+ name: "user-admin-access",
239
+ roleDisplayName: "access"
240
+ }
241
+ },
242
+ {
243
+ client: {
244
+ clientId: "vuu-user-admin",
245
+ id: "client-user-admin",
246
+ name: "User Admin"
247
+ },
248
+ group: {
249
+ id: "group-user-admin-admin",
250
+ name: "user-admin-admin",
251
+ groupDisplayName: "admin",
252
+ path: "/vuu/user-admin-admin"
253
+ },
254
+ role: {
255
+ id: "role-user-admin-admin",
256
+ name: "user-admin-admin",
257
+ roleDisplayName: "admin"
258
+ }
259
+ },
260
+ {
261
+ client: {
262
+ clientId: "vuu-portal",
263
+ id: "client-portal",
264
+ name: "VUU Portal"
265
+ },
266
+ group: {
267
+ id: "group-module-admin-admin",
268
+ name: "module-admin-admin",
269
+ groupDisplayName: "admin",
270
+ path: "/vuu/module-admin-admin"
271
+ },
272
+ role: {
273
+ id: "role-module-admin-access",
274
+ name: "module-admin-access",
275
+ roleDisplayName: "access"
276
+ }
277
+ },
278
+ {
279
+ client: {
280
+ clientId: "vuu-module-admin",
281
+ id: "client-module-admin",
282
+ name: "Module Admin"
283
+ },
284
+ group: {
285
+ id: "group-module-admin-admin",
286
+ name: "module-admin-admin",
287
+ groupDisplayName: "admin",
288
+ path: "/vuu/module-admin-admin"
289
+ },
290
+ role: {
291
+ id: "role-module-admin-admin",
292
+ name: "module-admin-admin",
293
+ roleDisplayName: "admin"
294
+ }
295
+ },
296
+ {
297
+ client: {
298
+ clientId: "vuu-portal",
299
+ id: "client-portal",
300
+ name: "VUU Portal"
301
+ },
302
+ group: {
303
+ id: "group-basket-trading-trade",
304
+ name: "basket-trading-trade",
305
+ groupDisplayName: "trade",
306
+ path: "/vuu/basket-trading-trade"
307
+ },
308
+ role: {
309
+ id: "role-basket-trading-access",
310
+ name: "basket-trading-access",
311
+ roleDisplayName: "access"
312
+ }
313
+ },
314
+ {
315
+ client: {
316
+ clientId: "vuu-basket-trading",
317
+ id: "client-basket-trading",
318
+ name: "Basket Trading"
319
+ },
320
+ group: {
321
+ id: "group-basket-trading-trade",
322
+ name: "basket-trading-trade",
323
+ groupDisplayName: "trade",
324
+ path: "/vuu/basket-trading-trade"
325
+ },
326
+ role: {
327
+ id: "role-basket-trading-trade",
328
+ name: "basket-trading-trade",
329
+ roleDisplayName: "trade"
330
+ }
331
+ }
332
+ ],
333
+ groups: [
334
+ {
335
+ id: "group-user-admin-read",
336
+ name: "user-admin-read",
337
+ groupDisplayName: "read",
338
+ moduleAccessDefaultRoles: [
339
+ "user-admin-access"
340
+ ],
341
+ path: "/vuu/user-admin-read"
342
+ },
343
+ {
344
+ id: "group-module-admin-read",
345
+ name: "module-admin-read",
346
+ groupDisplayName: "read",
347
+ moduleAccessDefaultRoles: [
348
+ "module-admin-access"
349
+ ],
350
+ path: "/vuu/module-admin-read"
351
+ },
352
+ {
353
+ id: "group-basket-trading-read",
354
+ name: "basket-trading-read",
355
+ groupDisplayName: "read",
356
+ moduleAccessDefaultRoles: [
357
+ "basket-trading-access"
358
+ ],
359
+ path: "/vuu/basket-trading-read"
360
+ },
361
+ {
362
+ id: "group-feature-filter-table-read",
363
+ name: "feature-filter-table-read",
364
+ groupDisplayName: "read",
365
+ moduleAccessDefaultRoles: [
366
+ "feature-filter-table-access"
367
+ ],
368
+ path: "/vuu/feature-filter-table-read"
369
+ },
370
+ {
371
+ id: "group-user-admin-admin",
372
+ name: "user-admin-admin",
373
+ groupDisplayName: "admin",
374
+ path: "/vuu/user-admin-admin"
375
+ },
376
+ {
377
+ id: "group-module-admin-admin",
378
+ name: "module-admin-admin",
379
+ groupDisplayName: "admin",
380
+ path: "/vuu/module-admin-admin"
381
+ },
382
+ {
383
+ id: "group-basket-trading-trade",
384
+ name: "basket-trading-trade",
385
+ groupDisplayName: "trade",
386
+ path: "/vuu/basket-trading-trade"
387
+ }
388
+ ],
389
+ timestamp: 1710000000000,
390
+ userGroups: [
391
+ {
392
+ group: {
393
+ id: "group-user-admin-read",
394
+ name: "user-admin-read",
395
+ groupDisplayName: "read",
396
+ moduleAccessDefaultRoles: [
397
+ "user-admin-access"
398
+ ],
399
+ path: "/vuu/user-admin-read"
400
+ },
401
+ user: {
402
+ email: "alice@example.com",
403
+ id: "user-alice",
404
+ username: "alice"
405
+ }
406
+ },
407
+ {
408
+ group: {
409
+ id: "group-module-admin-read",
410
+ name: "module-admin-read",
411
+ groupDisplayName: "read",
412
+ moduleAccessDefaultRoles: [
413
+ "module-admin-access"
414
+ ],
415
+ path: "/vuu/module-admin-read"
416
+ },
417
+ user: {
418
+ email: "bob@example.com",
419
+ id: "user-bob",
420
+ username: "bob"
421
+ }
422
+ },
423
+ {
424
+ group: {
425
+ id: "group-basket-trading-read",
426
+ name: "basket-trading-read",
427
+ groupDisplayName: "read",
428
+ moduleAccessDefaultRoles: [
429
+ "basket-trading-access"
430
+ ],
431
+ path: "/vuu/basket-trading-read"
432
+ },
433
+ user: {
434
+ email: "alice@example.com",
435
+ id: "user-alice",
436
+ username: "alice"
437
+ }
438
+ }
439
+ ],
440
+ users: [
441
+ {
442
+ email: "alice@example.com",
443
+ emailVerified: true,
444
+ enabled: true,
445
+ firstName: "Alice",
446
+ id: "user-alice",
447
+ lastName: "Admin",
448
+ username: "alice"
449
+ },
450
+ {
451
+ email: "bob@example.com",
452
+ emailVerified: true,
453
+ enabled: true,
454
+ firstName: "Bob",
455
+ id: "user-bob",
456
+ lastName: "Builder",
457
+ username: "bob"
458
+ }
459
+ ]
460
+ };
461
+ export { USER_ADMIN_INITIAL_SNAPSHOT };
@@ -0,0 +1,151 @@
1
+ const rowsEqual = (left, right)=>left.length === right.length && left.every((value, index)=>value === right[index]);
2
+ const membershipId = (userId, groupId)=>`${userId}:${groupId}`;
3
+ const assignmentId = (groupId, roleId)=>`${groupId}:${roleId}`;
4
+ const resolveDisplayName = (name, configuredDisplayName)=>configuredDisplayName ?? name.split("-").at(-1) ?? name;
5
+ const groupDisplayName = ({ groupDisplayName: configuredDisplayName, name })=>resolveDisplayName(name, configuredDisplayName);
6
+ const roleDisplayName = ({ roleDisplayName: configuredDisplayName, name })=>resolveDisplayName(name, configuredDisplayName);
7
+ const systemValues = (timestamp)=>({
8
+ vuuCreatedTimestamp: timestamp,
9
+ vuuMsg: "",
10
+ vuuUpdatedTimestamp: timestamp
11
+ });
12
+ const toRow = (table, values)=>table.schema.columns.map(({ name })=>values[name] ?? "");
13
+ const userRoleIds = (snapshot, userId)=>{
14
+ const groupIds = new Set(snapshot.userGroups.filter(({ user })=>user.id === userId).map(({ group })=>group.id));
15
+ return new Set(snapshot.groupRoles.filter(({ group })=>groupIds.has(group.id)).map(({ role })=>role.id));
16
+ };
17
+ const moduleAccessRoles = (snapshot, userId)=>Array.from(new Set(snapshot.groupRoles.filter(({ group, role })=>snapshot.userGroups.some(({ user, group: userGroup })=>user.id === userId && userGroup.id === group.id) && role.name.endsWith("-access")).map(({ role })=>role.name))).sort();
18
+ const projectUserAdminSnapshot = (snapshot, tables)=>{
19
+ const system = systemValues(snapshot.timestamp);
20
+ const membershipRows = snapshot.userGroups.map(({ user, group })=>({
21
+ group,
22
+ membership_id: membershipId(user.id, group.id),
23
+ user
24
+ }));
25
+ const assignmentRows = snapshot.groupRoles.map(({ client, group, role })=>({
26
+ assignment_id: assignmentId(group.id, role.id),
27
+ client,
28
+ group,
29
+ role
30
+ }));
31
+ return {
32
+ users: snapshot.users.map((user)=>{
33
+ const accessRoles = moduleAccessRoles(snapshot, user.id);
34
+ return toRow(tables.users, {
35
+ ...system,
36
+ email: user.email ?? "",
37
+ email_verified: user.emailVerified ?? false,
38
+ enabled: user.enabled ?? true,
39
+ first_name: user.firstName ?? "",
40
+ group_count: snapshot.userGroups.filter(({ user: member })=>member.id === user.id).length,
41
+ last_login: 0,
42
+ last_name: user.lastName ?? "",
43
+ module_access: accessRoles.join(","),
44
+ module_access_count: accessRoles.length,
45
+ password_update_required: user.requiredActions?.includes("UPDATE_PASSWORD") ?? false,
46
+ role_count: userRoleIds(snapshot, user.id).size,
47
+ user_id: user.id,
48
+ username: user.username
49
+ });
50
+ }),
51
+ groups: snapshot.groups.map((group)=>toRow(tables.groups, {
52
+ ...system,
53
+ group_display_name: groupDisplayName(group),
54
+ group_id: group.id,
55
+ group_path: group.path ?? `/${group.name}`,
56
+ parent_group_id: group.parentId ?? "",
57
+ role_count: snapshot.groupRoles.filter(({ group: assignmentGroup })=>assignmentGroup.id === group.id).length,
58
+ user_count: snapshot.userGroups.filter(({ group: memberGroup })=>memberGroup.id === group.id).length
59
+ })),
60
+ clients: snapshot.clients.map((client)=>toRow(tables.clients, {
61
+ ...system,
62
+ client_id: client.id,
63
+ client_identifier: client.clientId,
64
+ client_name: client.name ?? "",
65
+ description: client.description ?? "",
66
+ enabled: client.enabled ?? true
67
+ })),
68
+ roles: snapshot.clientRoles.map(({ client, role })=>toRow(tables.roles, {
69
+ ...system,
70
+ client_id: role.containerId ?? client.id,
71
+ client_identifier: client.clientId,
72
+ client_name: client.name ?? "",
73
+ description: role.description ?? "",
74
+ group_count: snapshot.groupRoles.filter(({ role: groupRole })=>groupRole.id === role.id).length,
75
+ role_id: role.id,
76
+ role_display_name: roleDisplayName(role),
77
+ role_name: role.name,
78
+ user_count: new Set(snapshot.userGroups.filter(({ group })=>snapshot.groupRoles.some(({ group: roleGroup, role: groupRole })=>group.id === roleGroup.id && groupRole.id === role.id)).map(({ user })=>user.id)).size
79
+ })),
80
+ user_groups: membershipRows.map(({ group, membership_id, user })=>toRow(tables.user_groups, {
81
+ ...system,
82
+ group_display_name: groupDisplayName(group),
83
+ group_id: group.id,
84
+ group_name: group.name,
85
+ group_path: group.path ?? `/${group.name}`,
86
+ membership_id,
87
+ user_id: user.id,
88
+ username: user.username
89
+ })),
90
+ group_roles: assignmentRows.map(({ assignment_id, client, group, role })=>toRow(tables.group_roles, {
91
+ ...system,
92
+ assignment_id,
93
+ client_id: client?.id ?? "",
94
+ client_identifier: client?.clientId ?? "",
95
+ client_name: client?.name ?? "",
96
+ group_id: group.id,
97
+ group_display_name: groupDisplayName(group),
98
+ group_name: group.name,
99
+ role_id: role.id,
100
+ role_display_name: roleDisplayName(role),
101
+ role_name: role.name
102
+ })),
103
+ user_group_roles: membershipRows.flatMap(({ group, membership_id, user })=>assignmentRows.filter(({ group: assignmentGroup })=>assignmentGroup.id === group.id).map(({ assignment_id, client, role })=>toRow(tables.user_group_roles, {
104
+ ...system,
105
+ assignment_id,
106
+ client_id: client?.id ?? "",
107
+ client_identifier: client?.clientId ?? "",
108
+ client_name: client?.name ?? "",
109
+ email: user.email ?? "",
110
+ email_verified: user.emailVerified ?? false,
111
+ enabled: user.enabled ?? true,
112
+ first_name: user.firstName ?? "",
113
+ group_id: group.id,
114
+ group_display_name: groupDisplayName(group),
115
+ group_name: group.name,
116
+ group_path: group.path ?? `/${group.name}`,
117
+ id: `${membership_id}:${assignment_id}`,
118
+ last_login: 0,
119
+ last_name: user.lastName ?? "",
120
+ membership_id,
121
+ password_update_required: user.requiredActions?.includes("UPDATE_PASSWORD") ?? false,
122
+ role_id: role.id,
123
+ role_display_name: roleDisplayName(role),
124
+ role_name: role.name,
125
+ user_id: user.id,
126
+ username: user.username
127
+ })))
128
+ };
129
+ };
130
+ const reconcileUserAdminTables = (snapshot, tables)=>{
131
+ const projected = projectUserAdminSnapshot(snapshot, tables);
132
+ for (const tableName of Object.keys(tables)){
133
+ const table = tables[tableName];
134
+ const desiredRows = projected[tableName];
135
+ const keyIndex = table.map[table.schema.key];
136
+ const desiredKeys = new Set(desiredRows.map((row)=>String(row[keyIndex])));
137
+ for (const existingRow of [
138
+ ...table.data
139
+ ]){
140
+ const key = String(existingRow[keyIndex]);
141
+ if (!desiredKeys.has(key)) table.delete(key);
142
+ }
143
+ for (const row of desiredRows){
144
+ const key = String(row[keyIndex]);
145
+ const existingRow = table.findByKey(key);
146
+ if (void 0 === existingRow) table.insert(row);
147
+ else if (!rowsEqual(existingRow, row)) table.updateRow(row);
148
+ }
149
+ }
150
+ };
151
+ export { projectUserAdminSnapshot, reconcileUserAdminTables, resolveDisplayName };
@@ -33,7 +33,7 @@ export declare class TickingArrayDataSource extends ArrayDataSource {
33
33
  undoRowChange: (key: string) => Promise<RpcResultSuccess | RpcResultError>;
34
34
  set columns(columns: string[]);
35
35
  get columns(): string[];
36
- endEditSession(saveChanges?: boolean): Promise<void>;
36
+ endEditSession(saveChanges?: boolean, force?: boolean): Promise<void>;
37
37
  rpcRequest(rpcRequest: Omit<VuuRpcServiceRequest, "context">): Promise<RpcResultSuccess | RpcResultError>;
38
38
  menuRpcCall(rpcRequest: Omit<VuuRpcMenuRequest, "vpId">): Promise<VuuRpcMenuResponse>;
39
39
  getTypeaheadSuggestions(column: string, pattern?: string): Promise<string[]>;
@@ -0,0 +1,41 @@
1
+ import type { VuuRowDataItemType } from "@vuu-ui/vuu-protocol-types";
2
+ import type { VuuModuleUser } from "../user/CurrentUser";
3
+ import type { ColumnMap } from "@vuu-ui/vuu-utils";
4
+ import type tableContainer from "../table/TableContainer";
5
+ export type TableRow = Array<bigint | VuuRowDataItemType>;
6
+ export type RowPredicate = (row: TableRow) => boolean;
7
+ /**
8
+ * Read access to a single row, by column name.
9
+ */
10
+ export interface RowData {
11
+ get: (columnName: string) => bigint | VuuRowDataItemType | undefined;
12
+ }
13
+ /**
14
+ * Restricts the rows of a table visible through a viewport, typically
15
+ * based on the user that owns the viewport. Permission filters are applied
16
+ * in addition to any client filter.
17
+ */
18
+ export interface PermissionFilter {
19
+ /**
20
+ * Bind this permission filter to the column layout of a table, returning a
21
+ * predicate that can be evaluated against raw table rows.
22
+ */
23
+ createPredicate: (columnMap: ColumnMap) => RowPredicate;
24
+ }
25
+ /**
26
+ * The subset of viewport state available to a PermissionFunction.
27
+ */
28
+ export interface PermissionViewport {
29
+ id: string;
30
+ user: VuuModuleUser;
31
+ }
32
+ export type TableContainer = typeof tableContainer;
33
+ /**
34
+ * Creates the PermissionFilter for a viewport. Configured per table on a VuuModule.
35
+ */
36
+ export type PermissionFunction = (viewport: PermissionViewport, tableContainer: TableContainer) => PermissionFilter;
37
+ export declare const AllowAllPermissionFilter: PermissionFilter;
38
+ export declare const DenyAllPermissionFilter: PermissionFilter;
39
+ export declare function PermissionFilter(rowPredicate: (row: RowData) => boolean): PermissionFilter;
40
+ export declare function PermissionFilter(columnName: string, allowedValues: Set<string>): PermissionFilter;
41
+ export declare function PermissionFilter(filters: Iterable<PermissionFilter>): PermissionFilter;
@@ -0,0 +1,24 @@
1
+ import { Table } from "../../Table";
2
+ import type { RowPredicate } from "./PermissionFilter";
3
+ /**
4
+ * A per-viewport view of a source table, containing only those rows that
5
+ * satisfy a permission predicate. Changes to the source table are mirrored,
6
+ * an update that moves a row into or out of the permitted set is emitted as
7
+ * an insert or delete.
8
+ */
9
+ export declare class PermissionFilteredTable extends Table {
10
+ #private;
11
+ constructor(source: Table, predicate: RowPredicate);
12
+ get source(): Table;
13
+ /**
14
+ * Start mirroring changes from the source table. Invoked on construction,
15
+ * only needs to be called again following dispose.
16
+ */
17
+ attach(): void;
18
+ dispose(): void;
19
+ private contains;
20
+ private handleSourceInsert;
21
+ private handleSourceUpdate;
22
+ private handleSourceDelete;
23
+ private replaceRow;
24
+ }