@xh/hoist 71.0.0-SNAPSHOT.1733198772915 → 71.0.0-SNAPSHOT.1733266596001

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 (75) hide show
  1. package/CHANGELOG.md +8 -2
  2. package/appcontainer/AppContainerModel.ts +2 -1
  3. package/build/types/cmp/chart/impl/copyToClipboard.d.ts +1 -2
  4. package/build/types/cmp/viewmanager/SaveAsDialogModel.d.ts +23 -0
  5. package/build/types/cmp/viewmanager/View.d.ts +28 -0
  6. package/build/types/cmp/viewmanager/ViewInfo.d.ts +30 -0
  7. package/build/types/cmp/viewmanager/ViewManagerModel.d.ts +185 -0
  8. package/build/types/cmp/viewmanager/index.d.ts +4 -0
  9. package/build/types/core/XH.d.ts +2 -1
  10. package/build/types/core/persist/PersistOptions.d.ts +3 -1
  11. package/build/types/core/persist/index.d.ts +6 -5
  12. package/build/types/core/persist/{CustomProvider.d.ts → provider/CustomProvider.d.ts} +1 -1
  13. package/build/types/core/persist/{DashViewProvider.d.ts → provider/DashViewProvider.d.ts} +2 -2
  14. package/build/types/core/persist/{LocalStorageProvider.d.ts → provider/LocalStorageProvider.d.ts} +1 -1
  15. package/build/types/core/persist/{PrefProvider.d.ts → provider/PrefProvider.d.ts} +1 -2
  16. package/build/types/core/persist/provider/SessionStorageProvider.d.ts +10 -0
  17. package/build/types/core/persist/{viewmanager → provider}/ViewManagerProvider.d.ts +3 -3
  18. package/build/types/desktop/cmp/viewmanager/ViewManager.d.ts +9 -10
  19. package/build/types/desktop/cmp/viewmanager/ViewMenu.d.ts +5 -0
  20. package/build/types/desktop/cmp/viewmanager/dialog/EditForm.d.ts +5 -0
  21. package/build/types/desktop/cmp/viewmanager/dialog/EditFormModel.d.ts +18 -0
  22. package/build/types/desktop/cmp/viewmanager/dialog/ManageDialog.d.ts +5 -0
  23. package/build/types/desktop/cmp/viewmanager/dialog/ManageDialogModel.d.ts +38 -0
  24. package/build/types/desktop/cmp/viewmanager/dialog/SaveAsDialog.d.ts +5 -0
  25. package/build/types/svc/JsonBlobService.d.ts +1 -1
  26. package/build/types/svc/index.d.ts +2 -1
  27. package/build/types/svc/storage/BaseStorageService.d.ts +21 -0
  28. package/build/types/svc/storage/LocalStorageService.d.ts +12 -0
  29. package/build/types/svc/storage/SessionStorageService.d.ts +12 -0
  30. package/cmp/chart/impl/copyToClipboard.ts +1 -2
  31. package/cmp/viewmanager/SaveAsDialogModel.ts +97 -0
  32. package/cmp/viewmanager/View.ts +56 -0
  33. package/cmp/viewmanager/ViewInfo.ts +58 -0
  34. package/cmp/viewmanager/ViewManagerModel.ts +710 -0
  35. package/cmp/viewmanager/index.ts +4 -0
  36. package/core/XH.ts +2 -0
  37. package/core/persist/PersistOptions.ts +4 -1
  38. package/core/persist/PersistenceProvider.ts +5 -0
  39. package/core/persist/index.ts +6 -5
  40. package/core/persist/{CustomProvider.ts → provider/CustomProvider.ts} +1 -1
  41. package/core/persist/{DashViewProvider.ts → provider/DashViewProvider.ts} +1 -1
  42. package/core/persist/{LocalStorageProvider.ts → provider/LocalStorageProvider.ts} +1 -1
  43. package/core/persist/{PrefProvider.ts → provider/PrefProvider.ts} +2 -2
  44. package/core/persist/provider/SessionStorageProvider.ts +35 -0
  45. package/core/persist/{viewmanager → provider}/ViewManagerProvider.ts +5 -9
  46. package/desktop/cmp/viewmanager/ViewManager.ts +47 -229
  47. package/desktop/cmp/viewmanager/ViewMenu.ts +191 -0
  48. package/desktop/cmp/viewmanager/dialog/EditForm.ts +126 -0
  49. package/desktop/cmp/viewmanager/dialog/EditFormModel.ts +125 -0
  50. package/desktop/cmp/viewmanager/dialog/ManageDialog.ts +98 -0
  51. package/desktop/cmp/viewmanager/dialog/ManageDialogModel.ts +279 -0
  52. package/desktop/cmp/viewmanager/{impl/SaveDialog.ts → dialog/SaveAsDialog.ts} +20 -12
  53. package/package.json +1 -1
  54. package/svc/JsonBlobService.ts +1 -1
  55. package/svc/index.ts +2 -1
  56. package/svc/{LocalStorageService.ts → storage/BaseStorageService.ts} +13 -23
  57. package/svc/storage/LocalStorageService.ts +23 -0
  58. package/svc/storage/SessionStorageService.ts +23 -0
  59. package/tsconfig.tsbuildinfo +1 -1
  60. package/build/types/core/persist/viewmanager/Types.d.ts +0 -48
  61. package/build/types/core/persist/viewmanager/ViewManagerModel.d.ts +0 -145
  62. package/build/types/core/persist/viewmanager/impl/BuildViewTree.d.ts +0 -8
  63. package/build/types/core/persist/viewmanager/impl/ManageDialogModel.d.ts +0 -30
  64. package/build/types/core/persist/viewmanager/impl/SaveDialogModel.d.ts +0 -23
  65. package/build/types/core/persist/viewmanager/index.d.ts +0 -2
  66. package/build/types/desktop/cmp/viewmanager/impl/ManageDialog.d.ts +0 -6
  67. package/build/types/desktop/cmp/viewmanager/impl/SaveDialog.d.ts +0 -2
  68. package/build/types/svc/LocalStorageService.d.ts +0 -24
  69. package/core/persist/viewmanager/Types.ts +0 -53
  70. package/core/persist/viewmanager/ViewManagerModel.ts +0 -481
  71. package/core/persist/viewmanager/impl/BuildViewTree.ts +0 -68
  72. package/core/persist/viewmanager/impl/ManageDialogModel.ts +0 -276
  73. package/core/persist/viewmanager/impl/SaveDialogModel.ts +0 -112
  74. package/core/persist/viewmanager/index.ts +0 -2
  75. package/desktop/cmp/viewmanager/impl/ManageDialog.ts +0 -197
@@ -1,276 +0,0 @@
1
- import {FormModel} from '@xh/hoist/cmp/form';
2
- import {GridAutosizeMode, GridModel} from '@xh/hoist/cmp/grid';
3
- import {fragment, p} from '@xh/hoist/cmp/layout';
4
- import {HoistModel, lookup, managed, TaskObserver, XH} from '@xh/hoist/core';
5
- import {lengthIs, required} from '@xh/hoist/data';
6
- import {Icon} from '@xh/hoist/icon';
7
- import {makeObservable} from '@xh/hoist/mobx';
8
- import {pluralize, throwIf} from '@xh/hoist/utils/js';
9
- import {ViewManagerModel} from '../ViewManagerModel';
10
-
11
- export class ManageDialogModel extends HoistModel {
12
- @lookup(() => ViewManagerModel)
13
- private viewManagerModel: ViewManagerModel;
14
-
15
- @managed gridModel: GridModel;
16
- @managed formModel: FormModel;
17
-
18
- readonly saveTask = TaskObserver.trackLast();
19
- readonly deleteTask = TaskObserver.trackLast();
20
-
21
- get selectedId(): string {
22
- return this.gridModel.selectedId as string;
23
- }
24
-
25
- get selectedIds(): string[] {
26
- return this.gridModel.selectedIds as string[];
27
- }
28
-
29
- get hasMultiSelection(): boolean {
30
- return this.selectedIds.length > 1;
31
- }
32
-
33
- get selIsShared(): boolean {
34
- return this.gridModel.selectedRecords.some(rec => rec.data.isShared);
35
- }
36
-
37
- get canDelete(): boolean {
38
- const {viewManagerModel, selIsShared, enableSharing, selectedIds} = this,
39
- {views, enableDefault} = viewManagerModel;
40
-
41
- // Can't delete shared views without manager role.
42
- if (selIsShared && !enableSharing) return false;
43
-
44
- // Can't delete all the views, unless default mode is enabled.
45
- return enableDefault || views.length - selectedIds.length > 0;
46
- }
47
-
48
- get canEdit(): boolean {
49
- return this.enableSharing || !this.selIsShared;
50
- }
51
-
52
- get enableSharing(): boolean {
53
- return this.viewManagerModel.enableSharing;
54
- }
55
-
56
- get showSaveButton(): boolean {
57
- const {formModel, viewManagerModel} = this;
58
- return formModel.isDirty && !formModel.readonly && !viewManagerModel.loadModel.isPending;
59
- }
60
-
61
- get displayName(): string {
62
- return this.viewManagerModel.displayName;
63
- }
64
-
65
- get enableFavorites(): boolean {
66
- return this.viewManagerModel.enableFavorites;
67
- }
68
-
69
- constructor() {
70
- super();
71
- makeObservable(this);
72
- }
73
-
74
- override onLinked() {
75
- super.onLinked();
76
-
77
- this.gridModel = this.createGridModel();
78
- this.formModel = this.createFormModel();
79
-
80
- this.addReaction(
81
- {
82
- track: () => this.viewManagerModel.views,
83
- run: () => this.refreshAsync()
84
- },
85
- {
86
- track: () => this.gridModel.selectedRecord,
87
- run: record => {
88
- if (record) {
89
- this.formModel.readonly = !this.canEdit;
90
- this.formModel.init(record.data);
91
- }
92
- }
93
- }
94
- );
95
- }
96
-
97
- override async doLoadAsync() {
98
- this.gridModel.loadData(this.viewManagerModel.views);
99
- await this.ensureGridHasSelection();
100
- }
101
-
102
- async saveAsync() {
103
- return this.doSaveAsync().linkTo(this.saveTask).catchDefault();
104
- }
105
-
106
- async deleteAsync() {
107
- return this.doDeleteAsync().linkTo(this.deleteTask).catchDefault();
108
- }
109
-
110
- //------------------------
111
- // Implementation
112
- //------------------------
113
- private async doSaveAsync() {
114
- const {formModel, viewManagerModel, enableSharing, selectedId, gridModel, displayName} =
115
- this,
116
- {isDirty} = formModel,
117
- {name, description, isShared} = formModel.getData(),
118
- isValid = await formModel.validateAsync(),
119
- {token, owner} = gridModel.selectedRecord.data,
120
- isOwnView = owner === XH.getUsername();
121
-
122
- if (!isValid || !selectedId || !isDirty) return;
123
-
124
- // Additional sanity-check before POSTing an update - non-admins should never be modifying global views.
125
- throwIf(
126
- isShared && !enableSharing,
127
- `Cannot save changes to shared ${displayName} - missing required permission.`
128
- );
129
-
130
- if (formModel.getField('isShared').isDirty) {
131
- const confirmMsgs = [];
132
- if (isShared) {
133
- confirmMsgs.push(
134
- `This ${displayName} will become visible to all other ${XH.appName} users.`
135
- );
136
- } else if (isOwnView) {
137
- confirmMsgs.push(
138
- `The selected ${displayName} will revert to being private to you. It will no longer be available to other users.`
139
- );
140
- } else {
141
- confirmMsgs.push(
142
- `The selected ${displayName} will revert to being private to its owner (${owner}).`,
143
- `Note that you will no longer have access to this view, meaning you will not be able to undo this change.`
144
- );
145
- }
146
-
147
- confirmMsgs.push('Are you sure you want to proceed?');
148
-
149
- const confirmed = await XH.confirm({
150
- message: fragment(confirmMsgs.map(msg => p(msg))),
151
- confirmProps: {
152
- text: 'Yes, update visibility',
153
- outlined: true,
154
- autoFocus: false,
155
- intent: 'primary'
156
- }
157
- });
158
-
159
- if (!confirmed) return;
160
- }
161
-
162
- await XH.jsonBlobService.updateAsync(token, {
163
- name,
164
- description,
165
- acl: isShared ? '*' : null
166
- });
167
-
168
- await viewManagerModel.refreshAsync();
169
- }
170
-
171
- private async doDeleteAsync() {
172
- const {viewManagerModel, gridModel, displayName, selectedIds, hasMultiSelection} = this,
173
- count = selectedIds.length;
174
- if (!count) return;
175
-
176
- const confirmStr = hasMultiSelection
177
- ? pluralize(displayName, count, true)
178
- : `"${gridModel.selectedRecord.data.name}"`,
179
- confirmed = await XH.confirm({
180
- message: `Are you sure you want to delete ${confirmStr}?`,
181
- confirmProps: {
182
- text: `Yes, delete ${pluralize(displayName, count)}`,
183
- outlined: true,
184
- autoFocus: false,
185
- intent: 'danger'
186
- }
187
- });
188
- if (!confirmed) return;
189
-
190
- for (const token of selectedIds) {
191
- viewManagerModel.removeFavorite(token);
192
- await XH.jsonBlobService.archiveAsync(token);
193
- }
194
-
195
- await viewManagerModel.refreshAsync();
196
- }
197
-
198
- private async ensureGridHasSelection() {
199
- const {gridModel, viewManagerModel} = this,
200
- {selectedToken} = viewManagerModel;
201
-
202
- if (!gridModel.hasSelection) {
203
- selectedToken
204
- ? await gridModel.selectAsync(selectedToken)
205
- : await gridModel.preSelectFirstAsync();
206
- }
207
- }
208
-
209
- private createGridModel(): GridModel {
210
- return new GridModel({
211
- emptyText: `No saved ${pluralize(this.displayName)} found...`,
212
- sortBy: 'name',
213
- groupBy: 'group',
214
- hideHeaders: true,
215
- showGroupRowCounts: false,
216
- selModel: 'multiple',
217
- contextMenu: null,
218
- sizingMode: 'standard',
219
- store: {
220
- idSpec: 'token',
221
- fields: [
222
- {name: 'token', type: 'string'},
223
- {name: 'name', type: 'string'},
224
- {name: 'description', type: 'string'},
225
- {name: 'isShared', type: 'bool'},
226
- {name: 'isFavorite', type: 'bool'},
227
- {name: 'acl', type: 'json'},
228
- {name: 'meta', type: 'json'},
229
- {name: 'dateCreated', type: 'date'},
230
- {name: 'createdBy', type: 'string'},
231
- {name: 'owner', type: 'string'},
232
- {name: 'lastUpdatedBy', type: 'string'},
233
- {name: 'lastUpdated', type: 'date'}
234
- ]
235
- },
236
- autosizeOptions: {mode: GridAutosizeMode.DISABLED},
237
- columns: [
238
- {field: 'name', flex: true},
239
- {
240
- field: 'isFavorite',
241
- omit: !this.enableFavorites,
242
- width: 40,
243
- align: 'center',
244
- headerName: Icon.favorite(),
245
- highlightOnChange: true,
246
- renderer: v => {
247
- return Icon.favorite({
248
- prefix: v ? 'fas' : 'fal',
249
- className: v ? 'xh-yellow' : 'xh-text-color-muted'
250
- });
251
- }
252
- },
253
- {field: 'group', hidden: true}
254
- ],
255
- onCellClicked: ({colDef, data: record}) => {
256
- if (colDef.colId === 'isFavorite') {
257
- this.viewManagerModel.toggleFavorite(record.id);
258
- }
259
- }
260
- });
261
- }
262
-
263
- private createFormModel(): FormModel {
264
- return new FormModel({
265
- fields: [
266
- {name: 'name', rules: [required, lengthIs({max: 255})]},
267
- {name: 'description'},
268
- {name: 'isShared', displayName: 'Shared'},
269
- {name: 'owner', readonly: true},
270
- {name: 'dateCreated', displayName: 'Created', readonly: true},
271
- {name: 'lastUpdated', displayName: 'Updated', readonly: true},
272
- {name: 'lastUpdatedBy', displayName: 'Updated By', readonly: true}
273
- ]
274
- });
275
- }
276
- }
@@ -1,112 +0,0 @@
1
- import {FormModel} from '@xh/hoist/cmp/form';
2
- import {HoistModel, managed, TaskObserver, XH} from '@xh/hoist/core';
3
- import {ViewManagerModel} from '@xh/hoist/core/persist/viewmanager';
4
- import {lengthIs, required} from '@xh/hoist/data';
5
- import {makeObservable} from '@xh/hoist/mobx';
6
- import {JsonBlob} from '@xh/hoist/svc';
7
- import {action, observable} from 'mobx';
8
- import {View} from '../Types';
9
-
10
- export class SaveDialogModel extends HoistModel {
11
- private readonly viewManagerModel: ViewManagerModel;
12
-
13
- @managed readonly formModel: FormModel;
14
- readonly saveTask = TaskObserver.trackLast();
15
-
16
- @observable viewStub: Partial<View>;
17
- @observable isOpen: boolean = false;
18
-
19
- private resolveOpen: (value: JsonBlob) => void;
20
- private invalidNames: string[] = [];
21
-
22
- get type(): string {
23
- return this.viewManagerModel.viewType;
24
- }
25
-
26
- get DisplayName(): string {
27
- return this.viewManagerModel.DisplayName;
28
- }
29
-
30
- constructor(viewManagerModel: ViewManagerModel) {
31
- super();
32
- makeObservable(this);
33
- this.viewManagerModel = viewManagerModel;
34
- this.formModel = this.createFormModel();
35
- }
36
-
37
- @action
38
- openAsync(viewStub: Partial<View>, invalidNames: string[]): Promise<JsonBlob> {
39
- this.viewStub = viewStub;
40
- this.invalidNames = invalidNames;
41
-
42
- this.formModel.init({
43
- name: viewStub.name ?? '',
44
- description: viewStub.description
45
- });
46
-
47
- this.isOpen = true;
48
-
49
- return new Promise(resolve => {
50
- this.resolveOpen = resolve;
51
- });
52
- }
53
-
54
- cancel() {
55
- this.close();
56
- this.resolveOpen(null);
57
- }
58
-
59
- async saveAsAsync() {
60
- return this.doSaveAsAsync().linkTo(this.saveTask);
61
- }
62
-
63
- //------------------------
64
- // Implementation
65
- //------------------------
66
- private createFormModel(): FormModel {
67
- return new FormModel({
68
- fields: [
69
- {
70
- name: 'name',
71
- rules: [
72
- required,
73
- lengthIs({max: 255}),
74
- ({value}) => {
75
- if (this.invalidNames.includes(value)) {
76
- return `An entry with name "${value}" already exists`;
77
- }
78
- }
79
- ]
80
- },
81
- {name: 'description'}
82
- ]
83
- });
84
- }
85
-
86
- private async doSaveAsAsync() {
87
- const {formModel, viewStub, type} = this,
88
- {name, description} = formModel.getData(),
89
- isValid = await formModel.validateAsync();
90
-
91
- if (!isValid) return;
92
-
93
- try {
94
- const newObj = await XH.jsonBlobService.createAsync({
95
- type,
96
- name,
97
- description,
98
- value: viewStub.value
99
- });
100
- this.close();
101
- this.resolveOpen(newObj);
102
- } catch (e) {
103
- XH.handleException(e);
104
- }
105
- }
106
-
107
- @action
108
- private close() {
109
- this.isOpen = false;
110
- this.formModel.init();
111
- }
112
- }
@@ -1,2 +0,0 @@
1
- export * from './ViewManagerModel';
2
- export * from './Types';
@@ -1,197 +0,0 @@
1
- import {form} from '@xh/hoist/cmp/form';
2
- import {grid} from '@xh/hoist/cmp/grid';
3
- import {div, filler, hbox, hframe, hspacer, placeholder, span, vframe} from '@xh/hoist/cmp/layout';
4
- import {storeFilterField} from '@xh/hoist/cmp/store';
5
- import {creates, hoistCmp, HoistProps, XH} from '@xh/hoist/core';
6
- import {ManageDialogModel} from '@xh/hoist/core/persist/viewmanager/impl/ManageDialogModel';
7
- import {button} from '@xh/hoist/desktop/cmp/button';
8
- import {formField} from '@xh/hoist/desktop/cmp/form';
9
- import {select, textArea, textInput} from '@xh/hoist/desktop/cmp/input';
10
- import {panel} from '@xh/hoist/desktop/cmp/panel';
11
- import {toolbar} from '@xh/hoist/desktop/cmp/toolbar';
12
- import {fmtCompactDate} from '@xh/hoist/format';
13
- import {Icon} from '@xh/hoist/icon';
14
- import {dialog} from '@xh/hoist/kit/blueprint';
15
- import {pluralize} from '@xh/hoist/utils/js';
16
- import {capitalize} from 'lodash';
17
-
18
- export interface ManageDialogProps extends HoistProps<ManageDialogModel> {
19
- onClose: () => void;
20
- }
21
-
22
- export const manageDialog = hoistCmp.factory<ManageDialogProps>({
23
- displayName: 'ManageDialog',
24
- className: 'xh-view-manager__manage-dialog',
25
- model: creates(ManageDialogModel),
26
-
27
- render({model, className, onClose}) {
28
- const {displayName, saveTask, deleteTask} = model;
29
- return dialog({
30
- title: `Manage ${capitalize(pluralize(displayName))}`,
31
- icon: Icon.gear(),
32
- className,
33
- isOpen: true,
34
- style: {width: '800px', maxWidth: '90vm', minHeight: '430px'},
35
- canOutsideClickClose: false,
36
- onClose,
37
- item: panel({
38
- item: hframe(gridPanel(), formPanel({onClose})),
39
- mask: [saveTask, deleteTask]
40
- })
41
- });
42
- }
43
- });
44
-
45
- const gridPanel = hoistCmp.factory({
46
- render() {
47
- return panel({
48
- modelConfig: {defaultSize: 350, side: 'left', collapsible: false},
49
- item: grid(),
50
- bbar: [storeFilterField()]
51
- });
52
- }
53
- });
54
-
55
- const formPanel = hoistCmp.factory<ManageDialogProps>({
56
- render({model, onClose}) {
57
- const {displayName, formModel} = model,
58
- {values} = formModel,
59
- isOwnView = values.owner === XH.getUsername();
60
-
61
- if (model.hasMultiSelection) {
62
- return multiSelectionPanel({onClose});
63
- }
64
-
65
- if (!model.selectedId)
66
- return panel({
67
- item: placeholder(Icon.gears(), `Select a ${displayName}`),
68
- bbar: bbar({onClose})
69
- });
70
-
71
- return panel({
72
- item: form({
73
- fieldDefaults: {
74
- commitOnChange: true
75
- },
76
- item: vframe({
77
- className: 'xh-view-manager__manage-dialog__form',
78
- items: [
79
- formField({
80
- field: 'name',
81
- item: textInput(),
82
- info: model.canEdit
83
- ? `Organize your ${pluralize(displayName)} into folders by including the "\\" character in their names - e.g. "My folder\\My ${displayName}".`
84
- : null
85
- }),
86
- formField({
87
- field: 'description',
88
- item: textArea({
89
- selectOnFocus: true,
90
- height: 70
91
- }),
92
- readonlyRenderer: v =>
93
- v
94
- ? v
95
- : span({
96
- item: 'None provided',
97
- className: 'xh-text-color-muted'
98
- })
99
- }),
100
- formField({
101
- field: 'isShared',
102
- label: 'Visibility',
103
- item: select({
104
- options: [
105
- {value: true, label: 'Shared with all users'},
106
- {
107
- value: false,
108
- label: `Private to ${isOwnView ? 'me' : values.owner}`
109
- }
110
- ],
111
- enableFilter: false
112
- }),
113
- omit: !model.enableSharing
114
- }),
115
- hbox({
116
- omit: !model.showSaveButton,
117
- style: {margin: '10px 20px'},
118
- items: [
119
- button({
120
- text: 'Save Changes',
121
- icon: Icon.check(),
122
- intent: 'success',
123
- minimal: false,
124
- flex: 1,
125
- onClick: () => model.saveAsync()
126
- }),
127
- hspacer(),
128
- button({
129
- icon: Icon.reset(),
130
- tooltip: 'Revert changes',
131
- minimal: false,
132
- onClick: () => formModel.reset()
133
- })
134
- ]
135
- }),
136
- filler(),
137
- div({
138
- className: 'xh-view-manager__manage-dialog__metadata',
139
- items: [
140
- `Created ${fmtCompactDate(values.dateCreated)} by ${
141
- values.owner === XH.getUsername() ? 'you' : values.owner
142
- }. `,
143
- `Updated ${fmtCompactDate(values.lastUpdated)} by ${
144
- values.lastUpdatedBy === XH.getUsername()
145
- ? 'you'
146
- : values.lastUpdatedBy
147
- }.`
148
- ]
149
- })
150
- ]
151
- })
152
- }),
153
- bbar: bbar({onClose})
154
- });
155
- }
156
- });
157
-
158
- const multiSelectionPanel = hoistCmp.factory<ManageDialogProps>({
159
- render({model, onClose}) {
160
- const {selectedIds} = model;
161
- return panel({
162
- item: vframe({
163
- alignItems: 'center',
164
- justifyContent: 'center',
165
- item: button({
166
- text: `Delete ${selectedIds.length} ${pluralize(model.displayName)}`,
167
- icon: Icon.delete(),
168
- intent: 'danger',
169
- outlined: true,
170
- disabled: !model.canDelete,
171
- onClick: () => model.deleteAsync()
172
- })
173
- }),
174
- bbar: bbar({onClose})
175
- });
176
- }
177
- });
178
-
179
- const bbar = hoistCmp.factory<ManageDialogProps>({
180
- render({model, onClose}) {
181
- return toolbar(
182
- button({
183
- text: 'Delete',
184
- icon: Icon.delete(),
185
- intent: 'danger',
186
- disabled: !model.canDelete,
187
- omit: model.hasMultiSelection,
188
- onClick: () => model.deleteAsync()
189
- }),
190
- filler(),
191
- button({
192
- text: 'Close',
193
- onClick: onClose
194
- })
195
- );
196
- }
197
- });