@xh/hoist 70.0.0-SNAPSHOT.1731083521069 → 70.0.0-SNAPSHOT.1731623470295

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 (95) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/build/types/cmp/filter/FilterChooserModel.d.ts +17 -12
  3. package/build/types/cmp/grid/GridModel.d.ts +5 -9
  4. package/build/types/cmp/grid/Types.d.ts +7 -19
  5. package/build/types/cmp/grid/columns/Column.d.ts +0 -1
  6. package/build/types/cmp/grid/impl/InitPersist.d.ts +7 -0
  7. package/build/types/cmp/grouping/GroupingChooserModel.d.ts +6 -8
  8. package/build/types/cmp/tab/TabContainerModel.d.ts +10 -4
  9. package/build/types/cmp/zoneGrid/Types.d.ts +6 -6
  10. package/build/types/cmp/zoneGrid/ZoneGridModel.d.ts +0 -2
  11. package/build/types/cmp/zoneGrid/impl/InitPersist.d.ts +7 -0
  12. package/build/types/core/HoistBase.d.ts +1 -1
  13. package/build/types/core/persist/CustomProvider.d.ts +5 -6
  14. package/build/types/core/persist/DashViewProvider.d.ts +6 -6
  15. package/build/types/core/persist/LocalStorageProvider.d.ts +4 -5
  16. package/build/types/core/persist/PersistOptions.d.ts +5 -4
  17. package/build/types/core/persist/Persistable.d.ts +14 -0
  18. package/build/types/core/persist/PersistenceProvider.d.ts +47 -34
  19. package/build/types/core/persist/PrefProvider.d.ts +5 -5
  20. package/build/types/core/persist/index.d.ts +2 -0
  21. package/build/types/core/persist/viewmanager/Types.d.ts +46 -0
  22. package/build/types/core/persist/viewmanager/ViewManagerModel.d.ts +149 -0
  23. package/build/types/core/persist/viewmanager/ViewManagerProvider.d.ts +10 -0
  24. package/build/types/core/persist/viewmanager/impl/ManageDialogModel.d.ts +30 -0
  25. package/build/types/core/persist/viewmanager/impl/SaveDialogModel.d.ts +23 -0
  26. package/build/types/core/persist/viewmanager/index.d.ts +2 -0
  27. package/build/types/desktop/cmp/button/ColAutosizeButton.d.ts +1 -1
  28. package/build/types/desktop/cmp/dash/DashConfig.d.ts +3 -1
  29. package/build/types/desktop/cmp/dash/DashModel.d.ts +1 -2
  30. package/build/types/desktop/cmp/dash/DashViewSpec.d.ts +1 -1
  31. package/build/types/desktop/cmp/dash/canvas/DashCanvasModel.d.ts +10 -2
  32. package/build/types/desktop/cmp/dash/container/DashContainerModel.d.ts +26 -10
  33. package/build/types/desktop/cmp/dash/container/impl/DashContainerUtils.d.ts +4 -2
  34. package/build/types/desktop/cmp/panel/PanelModel.d.ts +8 -4
  35. package/build/types/desktop/cmp/viewmanager/ViewManager.d.ts +22 -0
  36. package/build/types/desktop/cmp/viewmanager/cmp/ManageDialog.d.ts +6 -0
  37. package/build/types/desktop/cmp/viewmanager/cmp/SaveDialog.d.ts +2 -0
  38. package/build/types/desktop/cmp/viewmanager/index.d.ts +3 -0
  39. package/build/types/kit/blueprint/Wrappers.d.ts +1 -1
  40. package/build/types/mobile/cmp/button/ColAutosizeButton.d.ts +1 -1
  41. package/build/types/promise/Promise.d.ts +6 -5
  42. package/build/types/svc/GridAutosizeService.d.ts +2 -5
  43. package/build/types/svc/JsonBlobService.d.ts +45 -24
  44. package/cmp/filter/FilterChooserModel.ts +142 -125
  45. package/cmp/grid/Grid.ts +2 -10
  46. package/cmp/grid/GridModel.ts +18 -31
  47. package/cmp/grid/Types.ts +7 -21
  48. package/cmp/grid/columns/Column.ts +0 -1
  49. package/cmp/grid/impl/InitPersist.ts +71 -0
  50. package/cmp/grouping/GroupingChooserModel.ts +48 -57
  51. package/cmp/tab/TabContainerModel.ts +22 -36
  52. package/cmp/zoneGrid/Types.ts +6 -6
  53. package/cmp/zoneGrid/ZoneGridModel.ts +2 -7
  54. package/cmp/zoneGrid/impl/InitPersist.ts +70 -0
  55. package/core/HoistBase.ts +14 -22
  56. package/core/HoistBaseDecorators.ts +26 -28
  57. package/core/persist/CustomProvider.ts +7 -10
  58. package/core/persist/DashViewProvider.ts +8 -10
  59. package/core/persist/LocalStorageProvider.ts +9 -12
  60. package/core/persist/PersistOptions.ts +6 -4
  61. package/core/persist/Persistable.ts +23 -0
  62. package/core/persist/PersistenceProvider.ts +159 -79
  63. package/core/persist/PrefProvider.ts +9 -12
  64. package/core/persist/index.ts +2 -0
  65. package/core/persist/viewmanager/Types.ts +51 -0
  66. package/core/persist/viewmanager/ViewManagerModel.ts +515 -0
  67. package/core/persist/viewmanager/ViewManagerProvider.ts +51 -0
  68. package/core/persist/viewmanager/impl/ManageDialogModel.ts +274 -0
  69. package/core/persist/viewmanager/impl/SaveDialogModel.ts +112 -0
  70. package/core/persist/viewmanager/index.ts +2 -0
  71. package/desktop/cmp/button/ColAutosizeButton.ts +1 -1
  72. package/desktop/cmp/dash/DashConfig.ts +3 -1
  73. package/desktop/cmp/dash/DashModel.ts +1 -2
  74. package/desktop/cmp/dash/DashViewSpec.ts +1 -1
  75. package/desktop/cmp/dash/canvas/DashCanvasModel.ts +31 -30
  76. package/desktop/cmp/dash/container/DashContainerModel.ts +68 -43
  77. package/desktop/cmp/dash/container/impl/DashContainerUtils.ts +13 -4
  78. package/desktop/cmp/leftrightchooser/LeftRightChooserFilter.ts +1 -1
  79. package/desktop/cmp/panel/PanelModel.ts +33 -53
  80. package/desktop/cmp/store/impl/StoreFilterField.ts +1 -1
  81. package/desktop/cmp/viewmanager/ViewManager.scss +58 -0
  82. package/desktop/cmp/viewmanager/ViewManager.ts +274 -0
  83. package/desktop/cmp/viewmanager/cmp/ManageDialog.ts +197 -0
  84. package/desktop/cmp/viewmanager/cmp/SaveDialog.ts +89 -0
  85. package/desktop/cmp/viewmanager/index.ts +3 -0
  86. package/mobile/cmp/button/ColAutosizeButton.ts +1 -1
  87. package/package.json +1 -1
  88. package/promise/Promise.ts +6 -7
  89. package/svc/GridAutosizeService.ts +73 -36
  90. package/svc/JsonBlobService.ts +64 -31
  91. package/tsconfig.tsbuildinfo +1 -1
  92. package/build/types/cmp/grid/impl/GridPersistenceModel.d.ts +0 -41
  93. package/build/types/cmp/zoneGrid/impl/ZoneGridPersistenceModel.d.ts +0 -39
  94. package/cmp/grid/impl/GridPersistenceModel.ts +0 -174
  95. package/cmp/zoneGrid/impl/ZoneGridPersistenceModel.ts +0 -149
@@ -5,12 +5,12 @@
5
5
  * Copyright © 2024 Extremely Heavy Industries Inc.
6
6
  */
7
7
 
8
+ import {GridAutosizeOptions, GridModel} from '@xh/hoist/cmp/grid';
8
9
  import {HoistService} from '@xh/hoist/core';
9
- import {isFinite, map, sum, compact, sortBy, isEmpty} from 'lodash';
10
+ import {StoreRecord} from '@xh/hoist/data';
10
11
  import {runInAction} from '@xh/hoist/mobx';
11
- import {GridModel, GridAutosizeOptions} from '@xh/hoist/cmp/grid';
12
+ import {compact, isEmpty, isFinite, map, sortBy, sum} from 'lodash';
12
13
  import {ColumnWidthCalculator} from '../cmp/grid/impl/ColumnWidthCalculator';
13
- import {StoreRecord} from '@xh/hoist/data';
14
14
 
15
15
  /**
16
16
  * Sets appropriate column widths for a grid based on its contents. Generally seeks to make columns
@@ -42,39 +42,56 @@ export class GridAutosizeService extends HoistService {
42
42
  await gridModel.whenReadyAsync();
43
43
  if (!gridModel.isReady) return;
44
44
 
45
- // 1) Check columns exist
45
+ // If not in MANAGED mode, report this change as a manual resize via updated state set on
46
+ // gridModel, as if the user had resized each column to fit. It is only in managed mode that
47
+ // we are truly deferring to autosize. Otherwise we should persist the widths we calculate.
48
+ // (The user has autosized manually to get col widths as desired - don't then forget them!)
49
+ const asManuallySized = options.mode !== 'managed';
50
+
51
+ // Check columns exist.
46
52
  colIds = colIds.filter(id => gridModel.getColumn(id));
47
53
  if (isEmpty(colIds)) return;
48
54
 
49
- // 2) Ensure order of passed colIds matches the current GridModel.columnState.
55
+ // Ensure order of passed colIds matches the current GridModel.columnState.
50
56
  // This is to prevent changing the column order when applying column state changes
51
57
  colIds = sortBy(colIds, id => gridModel.columnState.findIndex(col => col.colId === id));
52
58
 
53
- // 3) Perform computation. This is async and expensive, and may become obsolete
59
+ // Perform computation. This is async and expensive, and may become obsolete.
54
60
  const records = this.gatherRecordsToBeSized(gridModel, options),
55
61
  requiredWidths = await this.calcRequiredWidthsAsync(
56
62
  gridModel,
57
63
  colIds,
58
64
  records,
59
- options
65
+ options,
66
+ asManuallySized
60
67
  );
61
68
 
62
69
  if (!requiredWidths) {
63
- this.logDebug('Autosize aborted, grid data is obsolete.');
70
+ this.logDebug(
71
+ 'Autosize aborted, grid data has changed since autosize operation began.'
72
+ );
64
73
  return;
65
74
  }
66
75
 
67
76
  runInAction(() => {
68
- // 4) Set columns to their required widths.
77
+ // Apply calculated widths to grid.
69
78
  gridModel.applyColumnStateChanges(requiredWidths);
70
- this.logDebug(`Auto-sized columns`, `${records.length} records`, requiredWidths);
79
+ this.logDebug(
80
+ `Auto-sized ${requiredWidths.length} columns`,
81
+ `${records.length} records`
82
+ );
71
83
 
72
- // 5) Grow columns to fill any remaining space, if enabled.
84
+ // Optionally grow columns to fill any remaining space, if enabled.
73
85
  const {fillMode} = options;
74
86
  if (fillMode && fillMode !== 'none') {
75
- const fillWidths = this.calcFillWidths(gridModel, colIds, fillMode);
87
+ const fillWidths = this.calcFillWidths(
88
+ gridModel,
89
+ colIds,
90
+ fillMode,
91
+ asManuallySized
92
+ );
76
93
  gridModel.applyColumnStateChanges(fillWidths);
77
- this.logDebug('Auto-sized columns using fillMode', fillWidths);
94
+ this.logDebug(`Auto-sized ${fillWidths.length} columns using fillMode`);
78
95
  }
79
96
  });
80
97
  }
@@ -86,10 +103,11 @@ export class GridAutosizeService extends HoistService {
86
103
  gridModel: GridModel,
87
104
  colIds: string[],
88
105
  records: StoreRecord[],
89
- options: GridAutosizeOptions
90
- ): Promise<{coldId: string; width: number}[]> {
106
+ options: GridAutosizeOptions,
107
+ manuallySized: boolean
108
+ ): Promise<ColWidthSpec[]> {
91
109
  const startRecords = gridModel.store._filtered,
92
- ret = [];
110
+ ret: ColWidthSpec[] = [];
93
111
 
94
112
  for (const colId of colIds) {
95
113
  const width = await this._columnWidthCalculator.calcWidthAsync(
@@ -98,7 +116,7 @@ export class GridAutosizeService extends HoistService {
98
116
  colId,
99
117
  options
100
118
  );
101
- if (isFinite(width)) ret.push({colId, width});
119
+ if (isFinite(width)) ret.push({colId, width, manuallySized});
102
120
 
103
121
  // Bail out if GridModel has moved on to new data.
104
122
  if (startRecords !== gridModel.store._filtered) return null;
@@ -145,14 +163,13 @@ export class GridAutosizeService extends HoistService {
145
163
  return ret;
146
164
  }
147
165
 
148
- /**
149
- * Calculate the increased size of columns to fill any remaining space.
150
- */
166
+ // Calculate the increased size of columns to fill any remaining space.
151
167
  private calcFillWidths(
152
168
  gridModel: GridModel,
153
169
  colIds: string[],
154
- fillMode: string
155
- ): {colId: string; width: number}[] {
170
+ fillMode: string,
171
+ manuallySized: boolean
172
+ ): ColWidthSpec[] {
156
173
  if (gridModel.getVisibleLeafColumns().some(it => it.flex)) {
157
174
  return [];
158
175
  }
@@ -172,23 +189,27 @@ export class GridAutosizeService extends HoistService {
172
189
  }
173
190
 
174
191
  // 2) Get remaining space to be filled
175
- const fillState = this.getFillState(gridModel, colIds),
176
- remaining = available - fillState.total;
192
+ const {total, colFillSpecs} = this.getFillState(gridModel, colIds),
193
+ remaining = available - total;
177
194
  if (remaining <= 0) return [];
178
195
 
179
196
  // 3) Distribute remaining space according to fill mode
180
197
  switch (fillMode) {
181
198
  case 'all':
182
- return this.fillEvenly(fillState.columns, remaining);
199
+ return this.fillEvenly(colFillSpecs, remaining, manuallySized);
183
200
  case 'left':
184
- return this.fillSequentially(fillState.columns, remaining);
201
+ return this.fillSequentially(colFillSpecs, remaining, manuallySized);
185
202
  case 'right':
186
- return this.fillSequentially(fillState.columns.reverse(), remaining);
203
+ return this.fillSequentially(colFillSpecs.reverse(), remaining, manuallySized);
187
204
  }
188
205
  }
189
206
 
190
207
  // Divide the remaining space evenly amongst columns, while respecting their maxWidths.
191
- private fillEvenly(columns, remaining) {
208
+ private fillEvenly(
209
+ columns: ColFillSpec[],
210
+ remaining: number,
211
+ manuallySized: boolean
212
+ ): ColWidthSpec[] {
192
213
  const ret = {};
193
214
 
194
215
  while (remaining > 0) {
@@ -215,20 +236,24 @@ export class GridAutosizeService extends HoistService {
215
236
  }
216
237
 
217
238
  return map(ret, (width, colId) => {
218
- return {width, colId};
239
+ return {width, colId, manuallySized};
219
240
  });
220
241
  }
221
242
 
222
243
  // Divide the remaining space across columns in order, while respecting their maxWidths.
223
- private fillSequentially(columns, remaining) {
224
- const ret = [];
244
+ private fillSequentially(
245
+ columns: ColFillSpec[],
246
+ remaining: number,
247
+ manuallySized: boolean
248
+ ): ColWidthSpec[] {
249
+ const ret: ColWidthSpec[] = [];
225
250
  for (const col of columns) {
226
251
  const {colId, maxWidth, width} = col,
227
252
  extraWidth = isFinite(maxWidth) ? Math.min(maxWidth - width, remaining) : remaining;
228
253
 
229
254
  if (extraWidth > 0) {
230
255
  remaining -= extraWidth;
231
- ret.push({colId, width: width + extraWidth});
256
+ ret.push({colId, width: width + extraWidth, manuallySized});
232
257
  }
233
258
 
234
259
  if (remaining <= 0) break;
@@ -236,16 +261,16 @@ export class GridAutosizeService extends HoistService {
236
261
  return ret;
237
262
  }
238
263
 
239
- private getFillState(gridModel, colIds) {
264
+ private getFillState(gridModel: GridModel, colIds: string[]) {
240
265
  return {
241
266
  total: this.getTotalColumnWidth(gridModel),
242
- columns: compact(colIds.map(colId => this.getColumnFillState(gridModel, colId)))
267
+ colFillSpecs: compact(colIds.map(colId => this.getColFillSpec(gridModel, colId)))
243
268
  };
244
269
  }
245
270
 
246
271
  // Returns an array of column state representations,
247
272
  // suitable for use by the column fill algorithms.
248
- private getColumnFillState(gridModel, colId) {
273
+ private getColFillSpec(gridModel: GridModel, colId: string): ColFillSpec {
249
274
  const column = gridModel.getColumn(colId),
250
275
  colState = gridModel.getStateForColumn(colId);
251
276
 
@@ -259,8 +284,20 @@ export class GridAutosizeService extends HoistService {
259
284
  }
260
285
 
261
286
  // Returns the total combined width of visible columns.
262
- private getTotalColumnWidth(gridModel) {
287
+ private getTotalColumnWidth(gridModel: GridModel): number {
263
288
  const widths = gridModel.columnState.filter(it => !it.hidden).map(it => it.width);
264
289
  return sum(widths);
265
290
  }
266
291
  }
292
+
293
+ interface ColWidthSpec {
294
+ colId: string;
295
+ width: number;
296
+ manuallySized: boolean;
297
+ }
298
+
299
+ interface ColFillSpec {
300
+ colId: string;
301
+ width: number;
302
+ maxWidth: number;
303
+ }
@@ -4,77 +4,110 @@
4
4
  *
5
5
  * Copyright © 2024 Extremely Heavy Industries Inc.
6
6
  */
7
- import {XH, HoistService} from '@xh/hoist/core';
7
+ import {HoistService, LoadSpec, PlainObject, XH} from '@xh/hoist/core';
8
+ import {pickBy} from 'lodash';
9
+
10
+ export interface JsonBlob {
11
+ /** Either null for private blobs or special token "*" for globally shared blobs. */
12
+ acl: string;
13
+ /** True if this blob has been archived (soft-deleted). */
14
+ archived: boolean;
15
+ /** Timestamp indicating when this blob was archived, or special value `0` if not archived. */
16
+ archivedDate: number;
17
+ dateCreated: number;
18
+ description: string;
19
+ /** @internal database ID for this blob. Favor token instead. */
20
+ id: number;
21
+ lastUpdated: number;
22
+ lastUpdatedBy: string;
23
+ /** Optional application-specific metadata. */
24
+ meta: PlainObject | unknown[];
25
+ name: string;
26
+ /** Username of the blob's creator / owner. */
27
+ owner: string;
28
+ /** Primary unique identifier for getting, updating, and archiving blobs. */
29
+ token: string;
30
+ /**
31
+ * Application defined type for this blob. Used as a discriminator when querying blobs related
32
+ * to a particular use-case within an application.
33
+ */
34
+ type: string;
35
+ /**
36
+ * Current JSON value of this blob - its contents or data. Will be undefined for blob stubs
37
+ * returned by `listAsync` if `includeValue` was false.
38
+ */
39
+ value?: any;
40
+ }
8
41
 
9
42
  /**
10
43
  * Service to read and set chunks of user-specific JSON persisted via Hoist Core's JSONBlob class.
44
+ *
45
+ * This service is intended as a general, lightweight utility for persisting small bundles of
46
+ * unstructured data that might not warrant a full-blown domain object, but which still need to be
47
+ * persisted back to the database.
11
48
  */
12
49
  export class JsonBlobService extends HoistService {
13
50
  static instance: JsonBlobService;
14
51
 
15
- async getAsync(token) {
52
+ /** Retrieve a single JSONBlob by its unique token. */
53
+ async getAsync(token: string): Promise<JsonBlob> {
16
54
  return XH.fetchJson({
17
55
  url: 'xh/getJsonBlob',
18
56
  params: {token}
19
57
  });
20
58
  }
21
59
 
22
- /**
23
- * Return the list of blobs visible to the current user.
24
- *
25
- * @param type - reference key for which type of data to list.
26
- * @param includeValue - true to include the full value string for each blob.
27
- */
28
- async listAsync({type, includeValue}: {type: string; includeValue?: boolean}) {
60
+ /** Retrieve all blobs of a particular type that are visible to the current user. */
61
+ async listAsync({
62
+ type,
63
+ includeValue,
64
+ loadSpec
65
+ }: {
66
+ type: string;
67
+ includeValue?: boolean;
68
+ loadSpec?: LoadSpec;
69
+ }) {
29
70
  return XH.fetchJson({
30
71
  url: 'xh/listJsonBlobs',
31
- params: {type, includeValue}
72
+ params: {type, includeValue},
73
+ loadSpec
32
74
  });
33
75
  }
34
76
 
35
77
  /** Persist a new JSONBlob back to the server. */
36
78
  async createAsync({
79
+ acl,
80
+ description,
37
81
  type,
38
- name,
39
- value,
40
82
  meta,
41
- description
42
- }: {
43
- type: string;
44
- name: string;
45
- description?: string;
46
- value: any;
47
- meta?: any;
48
- }) {
83
+ name,
84
+ value
85
+ }: Partial<JsonBlob>): Promise<JsonBlob> {
49
86
  return XH.fetchJson({
50
87
  url: 'xh/createJsonBlob',
51
88
  params: {
52
- data: JSON.stringify({type, name, value, meta, description})
89
+ data: JSON.stringify({type, name, acl, value, meta, description})
53
90
  }
54
91
  });
55
92
  }
56
93
 
57
- /** Modify an existing JSONBlob, as identified by its unique token. */
94
+ /** Modify mutable properties of an existing JSONBlob, as identified by its unique token. */
58
95
  async updateAsync(
59
96
  token: string,
60
- {
61
- name,
62
- value,
63
- meta,
64
- description
65
- }: {name?: string; value?: any; meta?: any; description?: string}
66
- ) {
97
+ {acl, description, meta, name, value}: Partial<JsonBlob>
98
+ ): Promise<JsonBlob> {
99
+ const update = pickBy({acl, description, meta, name, value}, (v, k) => v !== undefined);
67
100
  return XH.fetchJson({
68
101
  url: 'xh/updateJsonBlob',
69
102
  params: {
70
103
  token,
71
- update: JSON.stringify({name, value, meta, description})
104
+ update: JSON.stringify(update)
72
105
  }
73
106
  });
74
107
  }
75
108
 
76
109
  /** Archive (soft-delete) an existing JSONBlob, as identified by its unique token. */
77
- async archiveAsync(token: string) {
110
+ async archiveAsync(token: string): Promise<JsonBlob> {
78
111
  return XH.fetchJson({
79
112
  url: 'xh/archiveJsonBlob',
80
113
  params: {token}