@genesislcap/foundation-workspace 14.406.0-workspaces.7

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 (185) hide show
  1. package/api-extractor.json +5 -0
  2. package/dist/dts/index.d.ts +4 -0
  3. package/dist/dts/index.d.ts.map +1 -0
  4. package/dist/dts/tsdoc-metadata.json +11 -0
  5. package/dist/dts/workspace/filter-registry.d.ts +34 -0
  6. package/dist/dts/workspace/filter-registry.d.ts.map +1 -0
  7. package/dist/dts/workspace/grid-register/grid-register.d.ts +23 -0
  8. package/dist/dts/workspace/grid-register/grid-register.d.ts.map +1 -0
  9. package/dist/dts/workspace/grid-register/grid-register.template.d.ts +4 -0
  10. package/dist/dts/workspace/grid-register/grid-register.template.d.ts.map +1 -0
  11. package/dist/dts/workspace/grid-register/index.d.ts +2 -0
  12. package/dist/dts/workspace/grid-register/index.d.ts.map +1 -0
  13. package/dist/dts/workspace/grid-registry.d.ts +47 -0
  14. package/dist/dts/workspace/grid-registry.d.ts.map +1 -0
  15. package/dist/dts/workspace/index.d.ts +9 -0
  16. package/dist/dts/workspace/index.d.ts.map +1 -0
  17. package/dist/dts/workspace/layout-registry.d.ts +27 -0
  18. package/dist/dts/workspace/layout-registry.d.ts.map +1 -0
  19. package/dist/dts/workspace/layout-wrapper/index.d.ts +2 -0
  20. package/dist/dts/workspace/layout-wrapper/index.d.ts.map +1 -0
  21. package/dist/dts/workspace/layout-wrapper/layout-wrapper.d.ts +14 -0
  22. package/dist/dts/workspace/layout-wrapper/layout-wrapper.d.ts.map +1 -0
  23. package/dist/dts/workspace/layout-wrapper/layout-wrapper.template.d.ts +4 -0
  24. package/dist/dts/workspace/layout-wrapper/layout-wrapper.template.d.ts.map +1 -0
  25. package/dist/dts/workspace/workspace-state.d.ts +45 -0
  26. package/dist/dts/workspace/workspace-state.d.ts.map +1 -0
  27. package/dist/dts/workspace/workspace-state.types.d.ts +26 -0
  28. package/dist/dts/workspace/workspace-state.types.d.ts.map +1 -0
  29. package/dist/dts/workspace/workspace.types.d.ts +25 -0
  30. package/dist/dts/workspace/workspace.types.d.ts.map +1 -0
  31. package/dist/dts/workspace-components.d.ts +22 -0
  32. package/dist/dts/workspace-components.d.ts.map +1 -0
  33. package/dist/dts/workspace-manager/index.d.ts +2 -0
  34. package/dist/dts/workspace-manager/index.d.ts.map +1 -0
  35. package/dist/dts/workspace-manager/workspace-manager.d.ts +70 -0
  36. package/dist/dts/workspace-manager/workspace-manager.d.ts.map +1 -0
  37. package/dist/dts/workspace-manager/workspace-manager.styles.d.ts +2 -0
  38. package/dist/dts/workspace-manager/workspace-manager.styles.d.ts.map +1 -0
  39. package/dist/dts/workspace-manager/workspace-manager.template.d.ts +4 -0
  40. package/dist/dts/workspace-manager/workspace-manager.template.d.ts.map +1 -0
  41. package/dist/esm/index.js +3 -0
  42. package/dist/esm/workspace/filter-registry.js +47 -0
  43. package/dist/esm/workspace/grid-register/grid-register.js +136 -0
  44. package/dist/esm/workspace/grid-register/grid-register.template.js +4 -0
  45. package/dist/esm/workspace/grid-register/index.js +1 -0
  46. package/dist/esm/workspace/grid-registry.js +109 -0
  47. package/dist/esm/workspace/index.js +8 -0
  48. package/dist/esm/workspace/layout-registry.js +45 -0
  49. package/dist/esm/workspace/layout-wrapper/index.js +1 -0
  50. package/dist/esm/workspace/layout-wrapper/layout-wrapper.js +64 -0
  51. package/dist/esm/workspace/layout-wrapper/layout-wrapper.template.js +4 -0
  52. package/dist/esm/workspace/workspace-state.js +193 -0
  53. package/dist/esm/workspace/workspace-state.types.js +1 -0
  54. package/dist/esm/workspace/workspace.types.js +1 -0
  55. package/dist/esm/workspace-components.js +43 -0
  56. package/dist/esm/workspace-manager/index.js +1 -0
  57. package/dist/esm/workspace-manager/workspace-manager.js +436 -0
  58. package/dist/esm/workspace-manager/workspace-manager.styles.js +138 -0
  59. package/dist/esm/workspace-manager/workspace-manager.template.js +259 -0
  60. package/dist/foundation-workspace.api.json +3614 -0
  61. package/dist/foundation-workspace.d.ts +343 -0
  62. package/dist/tsconfig.tsbuildinfo +1 -0
  63. package/docs/.gitkeep +1 -0
  64. package/docs/api/foundation-workspace.defaultfilterregistry.md +17 -0
  65. package/docs/api/foundation-workspace.defaultgridregistry.md +17 -0
  66. package/docs/api/foundation-workspace.defaultlayoutregistry.md +18 -0
  67. package/docs/api/foundation-workspace.defaultworkspacestate._constructor_.md +65 -0
  68. package/docs/api/foundation-workspace.defaultworkspacestate.auth.md +14 -0
  69. package/docs/api/foundation-workspace.defaultworkspacestate.kvstorage.md +14 -0
  70. package/docs/api/foundation-workspace.defaultworkspacestate.md +115 -0
  71. package/docs/api/foundation-workspace.filterregistration.filterkey.md +14 -0
  72. package/docs/api/foundation-workspace.filterregistration.getfiltervalue.md +14 -0
  73. package/docs/api/foundation-workspace.filterregistration.md +98 -0
  74. package/docs/api/foundation-workspace.filterregistration.setfiltervalue.md +14 -0
  75. package/docs/api/foundation-workspace.filterregistry.applyfiltersvalues.md +53 -0
  76. package/docs/api/foundation-workspace.filterregistry.getallfiltersvalues.md +18 -0
  77. package/docs/api/foundation-workspace.filterregistry.md +16 -0
  78. package/docs/api/foundation-workspace.filterregistry.registerfilter.md +81 -0
  79. package/docs/api/foundation-workspace.filterregistry.unregisterfilter.md +53 -0
  80. package/docs/api/foundation-workspace.gridregister.gridkey.md +14 -0
  81. package/docs/api/foundation-workspace.gridregister.gridregistry.md +14 -0
  82. package/docs/api/foundation-workspace.gridregister.md +100 -0
  83. package/docs/api/foundation-workspace.gridregister.workspacestate.md +14 -0
  84. package/docs/api/foundation-workspace.gridregistration.columnapi.md +14 -0
  85. package/docs/api/foundation-workspace.gridregistration.gridapi.md +14 -0
  86. package/docs/api/foundation-workspace.gridregistration.gridkey.md +14 -0
  87. package/docs/api/foundation-workspace.gridregistration.md +98 -0
  88. package/docs/api/foundation-workspace.gridregistry.applyallgridssettings.md +53 -0
  89. package/docs/api/foundation-workspace.gridregistry.applygridsettings.md +72 -0
  90. package/docs/api/foundation-workspace.gridregistry.getallgridssettings.md +18 -0
  91. package/docs/api/foundation-workspace.gridregistry.getgrid.md +53 -0
  92. package/docs/api/foundation-workspace.gridregistry.md +16 -0
  93. package/docs/api/foundation-workspace.gridregistry.registergrid.md +81 -0
  94. package/docs/api/foundation-workspace.gridregistry.unregistergrid.md +53 -0
  95. package/docs/api/foundation-workspace.layoutregistry.applysavedlayouts.md +53 -0
  96. package/docs/api/foundation-workspace.layoutregistry.getlayoutsconfigs.md +18 -0
  97. package/docs/api/foundation-workspace.layoutregistry.md +16 -0
  98. package/docs/api/foundation-workspace.layoutregistry.registerlayout.md +67 -0
  99. package/docs/api/foundation-workspace.layoutregistry.unregisterlayout.md +53 -0
  100. package/docs/api/foundation-workspace.layoutwrapper.layoutkey.md +14 -0
  101. package/docs/api/foundation-workspace.layoutwrapper.layoutregistry.md +14 -0
  102. package/docs/api/foundation-workspace.layoutwrapper.md +81 -0
  103. package/docs/api/foundation-workspace.loadmode.md +16 -0
  104. package/docs/api/foundation-workspace.md +332 -0
  105. package/docs/api/foundation-workspace.savedfiltervalue.filterkey.md +14 -0
  106. package/docs/api/foundation-workspace.savedfiltervalue.md +79 -0
  107. package/docs/api/foundation-workspace.savedfiltervalue.value.md +14 -0
  108. package/docs/api/foundation-workspace.savedgridsettings.columnstate.md +14 -0
  109. package/docs/api/foundation-workspace.savedgridsettings.gridkey.md +14 -0
  110. package/docs/api/foundation-workspace.savedgridsettings.md +99 -0
  111. package/docs/api/foundation-workspace.savedgridsettings.savedat.md +14 -0
  112. package/docs/api/foundation-workspace.savedlayout.layout.md +14 -0
  113. package/docs/api/foundation-workspace.savedlayout.layoutkey.md +14 -0
  114. package/docs/api/foundation-workspace.savedlayout.md +79 -0
  115. package/docs/api/foundation-workspace.savedworkspace.description.md +14 -0
  116. package/docs/api/foundation-workspace.savedworkspace.filters.md +14 -0
  117. package/docs/api/foundation-workspace.savedworkspace.grids.md +14 -0
  118. package/docs/api/foundation-workspace.savedworkspace.layouts.md +14 -0
  119. package/docs/api/foundation-workspace.savedworkspace.md +174 -0
  120. package/docs/api/foundation-workspace.savedworkspace.name.md +14 -0
  121. package/docs/api/foundation-workspace.savedworkspace.savedat.md +14 -0
  122. package/docs/api/foundation-workspace.savedworkspace.username.md +14 -0
  123. package/docs/api/foundation-workspace.sharedworkspace.createdon.md +14 -0
  124. package/docs/api/foundation-workspace.sharedworkspace.data.md +14 -0
  125. package/docs/api/foundation-workspace.sharedworkspace.description.md +14 -0
  126. package/docs/api/foundation-workspace.sharedworkspace.id.md +14 -0
  127. package/docs/api/foundation-workspace.sharedworkspace.md +174 -0
  128. package/docs/api/foundation-workspace.sharedworkspace.modifiedon.md +14 -0
  129. package/docs/api/foundation-workspace.sharedworkspace.name.md +14 -0
  130. package/docs/api/foundation-workspace.sharedworkspace.username.md +14 -0
  131. package/docs/api/foundation-workspace.workspacecomponents.md +29 -0
  132. package/docs/api/foundation-workspace.workspacemanager.applyingworkspace.md +14 -0
  133. package/docs/api/foundation-workspace.workspacemanager.auth.md +14 -0
  134. package/docs/api/foundation-workspace.workspacemanager.canshareworkspace.md +14 -0
  135. package/docs/api/foundation-workspace.workspacemanager.connect.md +14 -0
  136. package/docs/api/foundation-workspace.workspacemanager.dialogboundary.md +14 -0
  137. package/docs/api/foundation-workspace.workspacemanager.filterregistry.md +14 -0
  138. package/docs/api/foundation-workspace.workspacemanager.gridregistry.md +14 -0
  139. package/docs/api/foundation-workspace.workspacemanager.isloading.md +14 -0
  140. package/docs/api/foundation-workspace.workspacemanager.layoutregistry.md +14 -0
  141. package/docs/api/foundation-workspace.workspacemanager.loadmodal.md +14 -0
  142. package/docs/api/foundation-workspace.workspacemanager.loadmode.md +14 -0
  143. package/docs/api/foundation-workspace.workspacemanager.md +442 -0
  144. package/docs/api/foundation-workspace.workspacemanager.savedworkspaces.md +14 -0
  145. package/docs/api/foundation-workspace.workspacemanager.savemodal.md +14 -0
  146. package/docs/api/foundation-workspace.workspacemanager.savemode.md +14 -0
  147. package/docs/api/foundation-workspace.workspacemanager.selectedworkspacetooverwrite.md +14 -0
  148. package/docs/api/foundation-workspace.workspacemanager.sharedworkspacedialogboundary.md +14 -0
  149. package/docs/api/foundation-workspace.workspacemanager.sharedworkspaces.md +14 -0
  150. package/docs/api/foundation-workspace.workspacemanager.workspacedescription.md +14 -0
  151. package/docs/api/foundation-workspace.workspacemanager.workspacename.md +14 -0
  152. package/docs/api/foundation-workspace.workspacemanager.workspacestate.md +14 -0
  153. package/docs/api/foundation-workspace.workspacemanager.workspacetoshare.md +14 -0
  154. package/docs/api/foundation-workspace.workspacestate.deleteworkspace.md +53 -0
  155. package/docs/api/foundation-workspace.workspacestate.getcurrentworkspace.md +18 -0
  156. package/docs/api/foundation-workspace.workspacestate.getsavedworkspaces.md +18 -0
  157. package/docs/api/foundation-workspace.workspacestate.loadworkspace.md +53 -0
  158. package/docs/api/foundation-workspace.workspacestate.md +16 -0
  159. package/docs/api/foundation-workspace.workspacestate.saveworkspace.md +111 -0
  160. package/docs/api/foundation-workspace.workspacestate.setcurrentworkspace.md +53 -0
  161. package/docs/api/index.md +30 -0
  162. package/docs/api-report.md.api.md +372 -0
  163. package/license.txt +46 -0
  164. package/package.json +69 -0
  165. package/src/index.ts +3 -0
  166. package/src/workspace/filter-registry.ts +80 -0
  167. package/src/workspace/grid-register/grid-register.template.ts +7 -0
  168. package/src/workspace/grid-register/grid-register.ts +142 -0
  169. package/src/workspace/grid-register/index.ts +1 -0
  170. package/src/workspace/grid-registry.ts +157 -0
  171. package/src/workspace/index.ts +8 -0
  172. package/src/workspace/layout-registry.ts +58 -0
  173. package/src/workspace/layout-wrapper/index.ts +1 -0
  174. package/src/workspace/layout-wrapper/layout-wrapper.template.ts +7 -0
  175. package/src/workspace/layout-wrapper/layout-wrapper.ts +66 -0
  176. package/src/workspace/workspace-state.ts +234 -0
  177. package/src/workspace/workspace-state.types.ts +27 -0
  178. package/src/workspace/workspace.types.ts +26 -0
  179. package/src/workspace-components.ts +51 -0
  180. package/src/workspace-manager/index.ts +1 -0
  181. package/src/workspace-manager/workspace-manager.styles.ts +139 -0
  182. package/src/workspace-manager/workspace-manager.template.ts +352 -0
  183. package/src/workspace-manager/workspace-manager.ts +420 -0
  184. package/temp/api-report.md.api.md +372 -0
  185. package/tsconfig.json +11 -0
@@ -0,0 +1,142 @@
1
+ import type { ColumnApi, GridApi } from '@ag-grid-community/core';
2
+ import { attr, customElement } from '@microsoft/fast-element';
3
+ import { GridRegistry, WorkspaceState } from '..';
4
+ import { GridRegisterTemplate as template } from './grid-register.template';
5
+
6
+ const name = 'grid-register';
7
+
8
+ /**
9
+ * Registers an AG Grid instance so workspace state can apply/load it.
10
+ * @alpha
11
+ */
12
+ @customElement({
13
+ name,
14
+ template,
15
+ })
16
+ export class GridRegister extends HTMLElement {
17
+ @attr({ attribute: 'grid-key' }) gridKey: string;
18
+
19
+ @GridRegistry gridRegistry: GridRegistry;
20
+ @WorkspaceState workspaceState: WorkspaceState;
21
+
22
+ private gridElement: HTMLElement | null = null;
23
+ private gridApi: GridApi | null = null;
24
+ private columnApi: ColumnApi | null = null;
25
+ private workspaceSettingsApplied: boolean = false;
26
+
27
+ connectedCallback(): void {
28
+ this.findAndRegisterGrid();
29
+ }
30
+
31
+ disconnectedCallback(): void {
32
+ if (this.gridKey) {
33
+ this.gridRegistry.unregisterGrid(this.gridKey);
34
+ }
35
+
36
+ this.detachFromGridApis();
37
+ }
38
+
39
+ private findAndRegisterGrid(): void {
40
+ this.gridElement = this.querySelector('rapid-grid-pro') as HTMLElement;
41
+
42
+ if (this.gridElement) {
43
+ this.gridElement.addEventListener('gridReady', this.handleGridReady as EventListener);
44
+ this.attachToGridApis();
45
+ } else {
46
+ setTimeout(() => {
47
+ this.gridElement = this.querySelector('rapid-grid-pro') as HTMLElement;
48
+
49
+ if (this.gridElement) {
50
+ this.gridElement.addEventListener('gridReady', this.handleGridReady as EventListener);
51
+ this.attachToGridApis();
52
+ } else {
53
+ console.warn(`grid-register: rapid-grid-pro element not found`);
54
+ }
55
+ }, 100);
56
+ }
57
+ }
58
+
59
+ private readonly handleGridReady = (): void => {
60
+ this.attachToGridApis();
61
+ };
62
+
63
+ private attachToGridApis(): void {
64
+ if (!this.gridElement) {
65
+ return;
66
+ }
67
+
68
+ const anyGrid: any = this.gridElement;
69
+ const gridApi = anyGrid.gridApi || null;
70
+ const columnApi = anyGrid.columnApi || null;
71
+ const persistKey = anyGrid?.getAttribute?.('persist-column-state-key') || this.gridKey;
72
+ if (!gridApi || this.gridApi === gridApi) {
73
+ return;
74
+ }
75
+
76
+ this.gridApi = gridApi;
77
+ this.columnApi = columnApi;
78
+
79
+ const effectiveGridKey = persistKey;
80
+ if (!effectiveGridKey) {
81
+ console.warn('grid-register: missing persist-column-state-key; grid state will not be saved');
82
+ } else {
83
+ this.gridRegistry.registerGrid(effectiveGridKey, gridApi, columnApi);
84
+ this.gridKey = effectiveGridKey;
85
+ }
86
+
87
+ if (!this.workspaceSettingsApplied && this.gridApi) {
88
+ this.loadWorkspaceColumnState().catch((error) => {
89
+ console.warn(`Failed to apply column state for ${this.gridKey} on gridReady:`, error);
90
+ });
91
+ }
92
+ }
93
+
94
+ private detachFromGridApis(): void {
95
+ if (this.gridElement && this.handleGridReady) {
96
+ this.gridElement.removeEventListener('gridReady', this.handleGridReady as EventListener);
97
+ }
98
+
99
+ this.gridElement = null;
100
+ this.gridApi = null;
101
+ this.columnApi = null;
102
+ }
103
+
104
+ private async loadWorkspaceSettings(options?: { applyColumns?: boolean }): Promise<void> {
105
+ if (!this.gridKey || !this.columnApi || !this.gridApi) {
106
+ return;
107
+ }
108
+
109
+ try {
110
+ const currentWorkspace = this.workspaceState.getCurrentWorkspace();
111
+ if (currentWorkspace && currentWorkspace.grids) {
112
+ const gridSetting = currentWorkspace.grids.find((g) => g.gridKey === this.gridKey);
113
+
114
+ if (gridSetting) {
115
+ const currentColumnState = this.columnApi.getColumnState() || [];
116
+ const targetColumnState = gridSetting.columnState || [];
117
+
118
+ const columnsEqual =
119
+ JSON.stringify(currentColumnState) === JSON.stringify(targetColumnState);
120
+
121
+ const applyColumns = !options || options.applyColumns !== false;
122
+ const columnsOk = !applyColumns || columnsEqual;
123
+
124
+ if (columnsOk) {
125
+ return;
126
+ }
127
+
128
+ const applied = await this.gridRegistry.applyGridSettings(gridSetting, options);
129
+ if (!applied) {
130
+ console.warn(`Failed to apply grid settings for ${this.gridKey}`);
131
+ }
132
+ }
133
+ }
134
+ } catch (error) {
135
+ console.warn(`Failed to load workspace settings for grid ${this.gridKey}:`, error);
136
+ }
137
+ }
138
+
139
+ private async loadWorkspaceColumnState(): Promise<void> {
140
+ return this.loadWorkspaceSettings({ applyColumns: true });
141
+ }
142
+ }
@@ -0,0 +1 @@
1
+ export * from './grid-register';
@@ -0,0 +1,157 @@
1
+ import type { ColumnApi, GridApi } from '@ag-grid-community/core';
2
+ import { DI } from '@microsoft/fast-foundation';
3
+ import type { SavedGridSettings } from './workspace.types';
4
+
5
+ /**
6
+ * @alpha
7
+ */
8
+ export interface GridRegistry {
9
+ registerGrid(gridKey: string, gridApi: unknown, columnApi: unknown): void;
10
+ getGrid(gridKey: string): unknown;
11
+ unregisterGrid(gridKey: string): void;
12
+ getAllGridsSettings(): SavedGridSettings[];
13
+ applyGridSettings(
14
+ gridSetting: SavedGridSettings,
15
+ options?: { applyColumns?: boolean; applyFilters?: boolean },
16
+ ): Promise<boolean>;
17
+ applyAllGridsSettings(gridsSettings: SavedGridSettings[]): Promise<void>;
18
+ }
19
+
20
+ /**
21
+ * @alpha
22
+ */
23
+ export interface GridRegistration {
24
+ gridKey: string;
25
+ gridApi: GridApi;
26
+ columnApi: ColumnApi;
27
+ }
28
+
29
+ /**
30
+ * @alpha
31
+ */
32
+ export class DefaultGridRegistry implements GridRegistry {
33
+ private grids: Map<string, GridRegistration> = new Map();
34
+ private cachedSettings: Map<string, SavedGridSettings> = new Map();
35
+
36
+ // Note: StatePersistence is not wired here to avoid a hard dependency on grid-pro.
37
+
38
+ registerGrid(gridKey: string, gridApi: unknown, columnApi: unknown): void {
39
+ this.grids.set(gridKey, {
40
+ gridKey,
41
+ gridApi: gridApi as GridApi,
42
+ columnApi: columnApi as ColumnApi,
43
+ });
44
+ }
45
+
46
+ getGrid(gridKey: string): unknown {
47
+ return this.grids.get(gridKey) || null;
48
+ }
49
+
50
+ unregisterGrid(gridKey: string): void {
51
+ const grid = this.grids.get(gridKey);
52
+ if (grid) {
53
+ const settings = this.getGridSettings(gridKey, grid);
54
+ if (settings) {
55
+ this.cachedSettings.set(gridKey, settings);
56
+ }
57
+ }
58
+ this.grids.delete(gridKey);
59
+ }
60
+
61
+ getAllGridsSettings(): SavedGridSettings[] {
62
+ Array.from(this.grids).forEach(([key, grid]) => {
63
+ const settings = this.getGridSettings(key, grid);
64
+ if (settings) {
65
+ this.cachedSettings.set(key, settings);
66
+ }
67
+ });
68
+
69
+ return Array.from(this.cachedSettings.values()).filter((s) => !!s);
70
+ }
71
+
72
+ async applyGridSettings(
73
+ gridSetting: SavedGridSettings,
74
+ options?: { applyColumns?: boolean; applyFilters?: boolean },
75
+ ): Promise<boolean> {
76
+ const gridRegistration = this.grids.get(gridSetting.gridKey);
77
+
78
+ if (!gridRegistration || !gridRegistration.columnApi || !gridRegistration.gridApi) {
79
+ return false;
80
+ }
81
+
82
+ const hasColumnState = gridSetting.columnState && gridSetting.columnState.length > 0;
83
+ const applyColumns = !options || options.applyColumns !== false;
84
+ const shouldApplyColumns = applyColumns && !!hasColumnState;
85
+
86
+ if (!shouldApplyColumns) {
87
+ // No column state to apply; treat as a no-op.
88
+ return false;
89
+ }
90
+
91
+ try {
92
+ if (shouldApplyColumns) {
93
+ gridRegistration.columnApi.applyColumnState({
94
+ state: gridSetting.columnState,
95
+ applyOrder: true,
96
+ });
97
+ }
98
+
99
+ return true;
100
+ } catch (error) {
101
+ console.warn(`Failed to apply settings for grid ${gridSetting.gridKey}:`, error);
102
+ return false;
103
+ }
104
+ }
105
+
106
+ async applyAllGridsSettings(
107
+ gridsSettings: SavedGridSettings[],
108
+ maxRetries: number = 3,
109
+ delayMs: number = 200,
110
+ ): Promise<void> {
111
+ // eslint-disable-next-line no-plusplus
112
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
113
+ const remainingSettings: SavedGridSettings[] = [];
114
+
115
+ for (const gridSetting of gridsSettings) {
116
+ // eslint-disable-next-line no-await-in-loop
117
+ const applied = await this.applyGridSettings(gridSetting);
118
+
119
+ if (!applied) {
120
+ remainingSettings.push(gridSetting);
121
+ }
122
+ }
123
+
124
+ if (remainingSettings.length === 0 || attempt >= maxRetries - 1) {
125
+ break;
126
+ }
127
+
128
+ // await new Promise((resolve) => setTimeout(resolve, delayMs));
129
+ gridsSettings = remainingSettings;
130
+ }
131
+ }
132
+
133
+ private getGridSettings(gridKey: string, grid: GridRegistration): SavedGridSettings | null {
134
+ if (grid) {
135
+ const columnState = grid.columnApi?.getColumnState();
136
+ const columnCount = columnState?.length || 0;
137
+
138
+ console.log(`Saved grid settings for ${gridKey}: ${columnCount} columns`);
139
+ return {
140
+ gridKey: grid.gridKey,
141
+ columnState: columnState || [],
142
+ savedAt: new Date().toISOString(),
143
+ };
144
+ }
145
+
146
+ console.warn(`No grid found for ${gridKey}`);
147
+ return null;
148
+ }
149
+ }
150
+
151
+ /**
152
+ * DI token for grid registry.
153
+ * @alpha
154
+ */
155
+ export const GridRegistry = DI.createInterface<GridRegistry>((x) =>
156
+ x.singleton(DefaultGridRegistry as any),
157
+ );
@@ -0,0 +1,8 @@
1
+ export * from './workspace.types';
2
+ export * from './workspace-state.types';
3
+ export * from './workspace-state';
4
+ export * from './layout-registry';
5
+ export * from './grid-registry';
6
+ export * from './filter-registry';
7
+ export * from './grid-register';
8
+ export * from './layout-wrapper';
@@ -0,0 +1,58 @@
1
+ import { DI } from '@microsoft/fast-foundation';
2
+ import type { SavedLayout } from './workspace.types';
3
+
4
+ /**
5
+ * @alpha
6
+ */
7
+ export interface LayoutRegistry {
8
+ registerLayout(layoutKey: string, layout: unknown): void;
9
+ unregisterLayout(layoutKey: string): void;
10
+ getLayoutsConfigs(): SavedLayout[];
11
+ applySavedLayouts(savedLayouts: SavedLayout[]): Promise<void>;
12
+ }
13
+
14
+ /**
15
+ * Default layout registry implementation.
16
+ * @alpha
17
+ */
18
+ export class DefaultLayoutRegistry implements LayoutRegistry {
19
+ private layouts: Map<string, any> = new Map();
20
+
21
+ registerLayout(layoutKey: string, layout: any): void {
22
+ if (!layoutKey) {
23
+ return;
24
+ }
25
+ this.layouts.set(layoutKey, layout);
26
+ }
27
+
28
+ unregisterLayout(layoutKey: string): void {
29
+ this.layouts.delete(layoutKey);
30
+ }
31
+
32
+ getLayoutsConfigs(): SavedLayout[] {
33
+ return Array.from(this.layouts).map(([key, layout]) => ({
34
+ layoutKey: key,
35
+ layout: layout.getLayout(),
36
+ }));
37
+ }
38
+
39
+ async applySavedLayouts(savedLayouts: SavedLayout[]): Promise<void> {
40
+ savedLayouts.forEach((s) => {
41
+ const layout = this.layouts.get(s.layoutKey);
42
+ if (layout) {
43
+ layout.loadLayout(s.layout as any, 'placeholder', true);
44
+ } else {
45
+ console.warn(`layout for ${s.layoutKey} not found`);
46
+ }
47
+ });
48
+ // await new Promise((resolve) => setTimeout(resolve, 300));
49
+ }
50
+ }
51
+
52
+ /**
53
+ * DI token for layout registry.
54
+ * @alpha
55
+ */
56
+ export const LayoutRegistry = DI.createInterface<LayoutRegistry>((x) =>
57
+ x.singleton(DefaultLayoutRegistry as any),
58
+ );
@@ -0,0 +1 @@
1
+ export * from './layout-wrapper';
@@ -0,0 +1,7 @@
1
+ import { html } from '@microsoft/fast-element';
2
+ import type { ViewTemplate } from '@microsoft/fast-element';
3
+ import type { LayoutWrapper } from './layout-wrapper';
4
+
5
+ export const LayoutWrapperTemplate: ViewTemplate<LayoutWrapper> = html`
6
+ <slot></slot>
7
+ `;
@@ -0,0 +1,66 @@
1
+ import { attr, customElement } from '@microsoft/fast-element';
2
+ import { LayoutRegistry } from '..';
3
+ import { LayoutWrapperTemplate as template } from './layout-wrapper.template';
4
+
5
+ const name = 'layout-register';
6
+
7
+ /**
8
+ * Registers a layout instance so workspace state can apply/load it.
9
+ * @alpha
10
+ */
11
+ @customElement({
12
+ name,
13
+ template,
14
+ })
15
+ export class LayoutWrapper extends HTMLElement {
16
+ @attr({ attribute: 'layout-key' }) layoutKey: string;
17
+
18
+ @LayoutRegistry layoutRegistry: LayoutRegistry;
19
+
20
+ private layoutElement: any | null = null;
21
+
22
+ connectedCallback(): void {
23
+ this.findAndRegisterLayout();
24
+ }
25
+
26
+ disconnectedCallback(): void {
27
+ const layoutKey =
28
+ (this.layoutElement as any)?.autoSaveKey ??
29
+ this.layoutElement?.getAttribute?.('auto-save-key') ??
30
+ this.layoutKey;
31
+
32
+ if (layoutKey) {
33
+ this.layoutRegistry.unregisterLayout(layoutKey);
34
+ }
35
+ }
36
+
37
+ private findAndRegisterLayout(): void {
38
+ let layoutElement = this.querySelector('rapid-layout') as any;
39
+
40
+ const registerLayout = (layout: any | null) => {
41
+ if (!layout) {
42
+ console.warn(`layout-register: rapid-layout element not found`);
43
+ return;
44
+ }
45
+ this.layoutElement = layout;
46
+ const layoutKeyFromLayout =
47
+ (layout as any).autoSaveKey ?? layout.getAttribute?.('auto-save-key') ?? this.layoutKey;
48
+
49
+ if (!layoutKeyFromLayout) {
50
+ console.warn('layout-register: missing layout key (auto-save-key/layout-key)');
51
+ return;
52
+ }
53
+
54
+ this.layoutRegistry.registerLayout(layoutKeyFromLayout, layout);
55
+ };
56
+
57
+ if (layoutElement) {
58
+ registerLayout(layoutElement);
59
+ } else {
60
+ setTimeout(() => {
61
+ layoutElement = this.querySelector('rapid-layout') as any;
62
+ registerLayout(layoutElement);
63
+ }, 100);
64
+ }
65
+ }
66
+ }
@@ -0,0 +1,234 @@
1
+ import {
2
+ Auth,
3
+ KVStorage,
4
+ type KVStorage as KVStorageType,
5
+ type Auth as AuthType,
6
+ } from '@genesislcap/foundation-comms';
7
+ import { DI } from '@microsoft/fast-foundation';
8
+ import type { SavedWorkspace } from './workspace-state.types';
9
+ import type { SavedFilterValue, SavedGridSettings, SavedLayout } from './workspace.types';
10
+
11
+ /**
12
+ * @alpha
13
+ */
14
+ export interface WorkspaceState {
15
+ saveWorkspace(
16
+ workspaceName: string,
17
+ layouts: SavedLayout[],
18
+ grids: SavedGridSettings[],
19
+ filters: SavedFilterValue[],
20
+ description?: string,
21
+ ): Promise<void>;
22
+ loadWorkspace(workspaceName: string): Promise<SavedWorkspace | null>;
23
+ getSavedWorkspaces(): Promise<SavedWorkspace[]>;
24
+ deleteWorkspace(workspaceName: string): Promise<void>;
25
+ getCurrentWorkspace(): SavedWorkspace | null;
26
+ setCurrentWorkspace(workspace: SavedWorkspace | null): void;
27
+ }
28
+
29
+ /**
30
+ * Default workspace persistence implementation backed by KVStorage.
31
+ *
32
+ * @alpha
33
+ */
34
+ export class DefaultWorkspaceState implements WorkspaceState {
35
+ private readonly STORAGE_PREFIX = 'workspace_';
36
+ private readonly WORKSPACES_LIST_KEY = 'workspaces_list';
37
+
38
+ private currentWorkspace: SavedWorkspace | null = null;
39
+
40
+ constructor(
41
+ @KVStorage public kvStorage: KVStorageType,
42
+ @Auth public auth: AuthType,
43
+ ) {}
44
+
45
+ private getCurrentUsername(): string {
46
+ return this.auth?.loggedUserResult?.username || 'anonymous';
47
+ }
48
+
49
+ private getWorkspaceStorageKey(workspaceName: string): string {
50
+ const username = this.getCurrentUsername();
51
+ return `${this.STORAGE_PREFIX}${username}_${workspaceName}`;
52
+ }
53
+
54
+ private getWorkspacesListKey(): string {
55
+ const username = this.getCurrentUsername();
56
+ return `${this.STORAGE_PREFIX}${username}_${this.WORKSPACES_LIST_KEY}`;
57
+ }
58
+
59
+ async saveWorkspace(
60
+ workspaceName: string,
61
+ layouts: SavedLayout[],
62
+ grids: SavedGridSettings[],
63
+ filters: SavedFilterValue[],
64
+ description?: string,
65
+ ): Promise<void> {
66
+ const storageKey = this.getWorkspaceStorageKey(workspaceName);
67
+ const username = this.getCurrentUsername();
68
+
69
+ const workspace: SavedWorkspace = {
70
+ name: workspaceName,
71
+ username,
72
+ description: description?.trim() || undefined,
73
+ layouts,
74
+ grids,
75
+ filters,
76
+ savedAt: new Date().toISOString(),
77
+ };
78
+
79
+ await this.kvStorage.put([
80
+ {
81
+ key: storageKey,
82
+ value: JSON.stringify(workspace),
83
+ },
84
+ ]);
85
+
86
+ await this.updateWorkspacesList(workspaceName);
87
+ }
88
+
89
+ async loadWorkspace(workspaceName: string): Promise<SavedWorkspace | null> {
90
+ const workspace = await this.getWorkspace(workspaceName);
91
+ this.currentWorkspace = workspace ?? null;
92
+ return this.currentWorkspace;
93
+ }
94
+
95
+ private async getWorkspace(workspaceName: string): Promise<SavedWorkspace | null> {
96
+ const storageKey = this.getWorkspaceStorageKey(workspaceName);
97
+ const existing = await this.kvStorage.get(storageKey);
98
+
99
+ if (!existing?.kv?.value) {
100
+ return null;
101
+ }
102
+
103
+ try {
104
+ const workspace =
105
+ typeof existing.kv.value === 'string' ? JSON.parse(existing.kv.value) : existing.kv.value;
106
+
107
+ const currentUsername = this.getCurrentUsername();
108
+ if (workspace.username && workspace.username !== currentUsername) {
109
+ console.warn(`Workspace ${workspaceName} does not belong to current user`);
110
+ return null;
111
+ }
112
+
113
+ if (!workspace.username) {
114
+ workspace.username = currentUsername;
115
+ }
116
+
117
+ return workspace || null;
118
+ } catch (e) {
119
+ console.warn('Failed to parse saved workspace', e);
120
+ return null;
121
+ }
122
+ }
123
+
124
+ getCurrentWorkspace(): SavedWorkspace | null {
125
+ return this.currentWorkspace;
126
+ }
127
+
128
+ setCurrentWorkspace(workspace: SavedWorkspace | null): void {
129
+ this.currentWorkspace = workspace;
130
+ }
131
+
132
+ async getSavedWorkspaces(): Promise<SavedWorkspace[]> {
133
+ const listKey = this.getWorkspaceStorageKey(this.WORKSPACES_LIST_KEY);
134
+ const existing = await this.kvStorage.get(listKey);
135
+
136
+ if (!existing?.kv?.value) {
137
+ return [];
138
+ }
139
+
140
+ try {
141
+ const workspaceNames: string[] =
142
+ typeof existing.kv.value === 'string' ? JSON.parse(existing.kv.value) : existing.kv.value;
143
+
144
+ if (!Array.isArray(workspaceNames)) {
145
+ return [];
146
+ }
147
+
148
+ const workspaces: SavedWorkspace[] = [];
149
+ const currentUsername = this.getCurrentUsername();
150
+ for (const name of workspaceNames) {
151
+ // eslint-disable-next-line no-await-in-loop
152
+ const workspace = await this.getWorkspace(name);
153
+ if (workspace && (!workspace.username || workspace.username === currentUsername)) {
154
+ workspaces.push(workspace);
155
+ }
156
+ }
157
+
158
+ return workspaces;
159
+ } catch (e) {
160
+ console.warn('Failed to parse saved workspaces list', e);
161
+ return [];
162
+ }
163
+ }
164
+
165
+ async deleteWorkspace(workspaceName: string): Promise<void> {
166
+ const storageKey = this.getWorkspaceStorageKey(workspaceName);
167
+ await this.kvStorage.delete([storageKey]);
168
+ await this.removeFromWorkspacesList(workspaceName);
169
+ }
170
+
171
+ private async updateWorkspacesList(workspaceName: string): Promise<void> {
172
+ const listKey = this.getWorkspacesListKey();
173
+ const existing = await this.kvStorage.get(listKey);
174
+
175
+ let workspaceNames: string[] = [];
176
+ if (existing?.kv?.value) {
177
+ try {
178
+ workspaceNames =
179
+ typeof existing.kv.value === 'string' ? JSON.parse(existing.kv.value) : existing.kv.value;
180
+ } catch (e) {
181
+ console.warn('Failed to parse workspaces list', e);
182
+ }
183
+ }
184
+
185
+ workspaceNames = workspaceNames.filter((name) => name !== workspaceName);
186
+ workspaceNames.push(workspaceName);
187
+
188
+ await this.kvStorage.put([
189
+ {
190
+ key: listKey,
191
+ value: JSON.stringify(workspaceNames),
192
+ },
193
+ ]);
194
+ }
195
+
196
+ private async removeFromWorkspacesList(workspaceName: string): Promise<void> {
197
+ const listKey = this.getWorkspacesListKey();
198
+ const existing = await this.kvStorage.get(listKey);
199
+
200
+ if (!existing?.kv?.value) {
201
+ return;
202
+ }
203
+
204
+ let workspaceNames: string[] = [];
205
+ try {
206
+ workspaceNames =
207
+ typeof existing.kv.value === 'string' ? JSON.parse(existing.kv.value) : existing.kv.value;
208
+ } catch (e) {
209
+ console.warn('Failed to parse workspaces list for deletion', e);
210
+ return;
211
+ }
212
+
213
+ workspaceNames = workspaceNames.filter((name) => name !== workspaceName);
214
+
215
+ if (workspaceNames.length === 0) {
216
+ await this.kvStorage.delete([listKey]);
217
+ } else {
218
+ await this.kvStorage.put([
219
+ {
220
+ key: listKey,
221
+ value: JSON.stringify(workspaceNames),
222
+ },
223
+ ]);
224
+ }
225
+ }
226
+ }
227
+
228
+ /**
229
+ * DI token for workspace state.
230
+ * @alpha
231
+ */
232
+ export const WorkspaceState = DI.createInterface<WorkspaceState>((x) =>
233
+ x.singleton(DefaultWorkspaceState),
234
+ );
@@ -0,0 +1,27 @@
1
+ import type { SavedFilterValue, SavedGridSettings, SavedLayout } from './workspace.types';
2
+
3
+ /**
4
+ * @alpha
5
+ */
6
+ export interface SavedWorkspace {
7
+ name: string;
8
+ username: string;
9
+ description?: string;
10
+ layouts: SavedLayout[];
11
+ grids: SavedGridSettings[];
12
+ filters: SavedFilterValue[];
13
+ savedAt: string;
14
+ }
15
+
16
+ /**
17
+ * @alpha
18
+ */
19
+ export interface SharedWorkspace {
20
+ id: string;
21
+ name: string;
22
+ userName: string;
23
+ description?: string;
24
+ createdOn?: string | number;
25
+ modifiedOn?: string | number;
26
+ data: string;
27
+ }