@xh/hoist 78.0.0-SNAPSHOT.1762216163824 → 78.0.0-SNAPSHOT.1762310926429

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.
package/CHANGELOG.md CHANGED
@@ -33,6 +33,11 @@
33
33
  * Fixed `AgGridModel.getExpandState()` not returning a full representation of expanded groups -
34
34
  an issue that primarily affected linked tree map visualizations.
35
35
 
36
+ ### ⚙️ Technical
37
+
38
+ * Support Grails 7 service name conventions in admin client (backward compatible)
39
+
40
+
36
41
  ## 76.2.0 - 2025-10-22
37
42
 
38
43
  ### ⚙️ Technical
@@ -152,7 +152,13 @@ export class ServiceModel extends BaseInstanceModel {
152
152
  }
153
153
 
154
154
  private processRawData(r: PlainObject) {
155
- const provider = r.name && r.name.startsWith('hoistCore') ? 'Hoist' : 'App';
155
+ // For Grails <=6, plugin is prefix in name.
156
+ // For Grails >7, we provide class to determine provider
157
+ // TODO: simplify when Hoist v34+ required.
158
+ const provider =
159
+ r.name.startsWith('hoistCore') || r.className?.startsWith('io.xh.hoist')
160
+ ? 'Hoist'
161
+ : 'App';
156
162
  const displayName = lowerFirst(r.name.replace('hoistCore', ''));
157
163
  return {provider, displayName, ...r};
158
164
  }
@@ -7,7 +7,7 @@
7
7
  import {exportFilenameWithDate} from '@xh/hoist/admin/AdminUtils';
8
8
  import {AppModel} from '@xh/hoist/admin/AppModel';
9
9
  import * as Col from '@xh/hoist/admin/columns';
10
- import {hbox, hspacer} from '@xh/hoist/cmp/layout';
10
+ import {br, fragment, hbox, hspacer} from '@xh/hoist/cmp/layout';
11
11
  import {HoistModel, LoadSpec, managed, XH} from '@xh/hoist/core';
12
12
  import {FieldSpec} from '@xh/hoist/data';
13
13
  import {defaultReadonlyRenderer} from '@xh/hoist/desktop/cmp/form';
@@ -17,14 +17,14 @@ import {
17
17
  cloneAction,
18
18
  deleteAction,
19
19
  editAction,
20
- RestGridModel,
21
- RestStore
20
+ RestGridModel
22
21
  } from '@xh/hoist/desktop/cmp/rest';
22
+ import {Icon} from '@xh/hoist/icon';
23
23
  import {action, makeObservable, observable} from '@xh/hoist/mobx';
24
+ import {pluralize} from '@xh/hoist/utils/js';
24
25
  import {isNil, truncate} from 'lodash';
25
26
  import {DifferModel} from '../../../differ/DifferModel';
26
27
  import {RegroupDialogModel} from '../../../regroup/RegroupDialogModel';
27
- import {Icon} from '@xh/hoist/icon';
28
28
 
29
29
  export class ConfigPanelModel extends HoistModel {
30
30
  override persistWith = {localStorageKey: 'xhAdminConfigState'};
@@ -43,18 +43,27 @@ export class ConfigPanelModel extends HoistModel {
43
43
  super();
44
44
  makeObservable(this);
45
45
 
46
- const required = true,
46
+ const {regroupAction} = this.regroupDialogModel,
47
+ required = true,
47
48
  enableCreate = true,
48
49
  hidden = true;
49
50
 
50
51
  this.gridModel = new RestGridModel({
51
- readonly: AppModel.readonly,
52
- persistWith: this.persistWith,
52
+ // Core config
53
+ autosizeOptions: {mode: 'managed', includeCollapsedChildren: true},
53
54
  colChooserModel: true,
54
55
  enableExport: true,
55
56
  exportOptions: {filename: exportFilenameWithDate('configs')},
57
+ filterFields: ['name', 'value', 'groupName', 'note'],
58
+ groupBy: 'groupName',
59
+ persistWith: this.persistWith,
60
+ prepareCloneFn: ({clone}) => (clone.name = `${clone.name}_CLONE`),
61
+ readonly: AppModel.readonly,
56
62
  selModel: 'multiple',
57
- store: new RestStore({
63
+ sortBy: 'name',
64
+ unit: 'config',
65
+ // Store + fields
66
+ store: {
58
67
  url: 'rest/configAdmin',
59
68
  reloadLookupsOnLoad: true,
60
69
  fieldDefaults: {enableXssProtection: false},
@@ -83,25 +92,8 @@ export class ConfigPanelModel extends HoistModel {
83
92
  editable: false
84
93
  }
85
94
  ]
86
- }),
87
- actionWarning: {
88
- del: records =>
89
- `Are you sure you want to delete ${records.length} config(s)? Deleting configs can break running apps.`
90
95
  },
91
- toolbarActions: [addAction, editAction, cloneAction, deleteAction],
92
- menuActions: [
93
- addAction,
94
- editAction,
95
- cloneAction,
96
- deleteAction,
97
- '-',
98
- this.regroupDialogModel.regroupAction
99
- ],
100
- prepareCloneFn: ({clone}) => (clone.name = `${clone.name}_CLONE`),
101
- unit: 'config',
102
- filterFields: ['name', 'value', 'groupName', 'note'],
103
- sortBy: 'name',
104
- groupBy: 'groupName',
96
+ // Cols + editors
105
97
  columns: [
106
98
  {...Col.groupName, hidden},
107
99
  {...Col.name},
@@ -138,7 +130,19 @@ export class ConfigPanelModel extends HoistModel {
138
130
  {field: 'clientVisible'},
139
131
  {field: 'lastUpdated'},
140
132
  {field: 'lastUpdatedBy'}
141
- ]
133
+ ],
134
+ // Actions
135
+ actionWarning: {
136
+ del: records =>
137
+ fragment(
138
+ `Are you sure you want to delete ${pluralize('selected config', records.length, true)}?`,
139
+ br(),
140
+ br(),
141
+ `Deleting configs can break running apps.`
142
+ )
143
+ },
144
+ menuActions: [addAction, editAction, cloneAction, deleteAction, '-', regroupAction],
145
+ toolbarActions: [addAction, editAction, cloneAction, deleteAction]
142
146
  });
143
147
  }
144
148
 
@@ -25,12 +25,19 @@ export class UserPreferenceModel extends HoistModel {
25
25
  hidden = true;
26
26
 
27
27
  this.gridModel = new RestGridModel({
28
- readonly: AppModel.readonly,
29
- persistWith: {localStorageKey: 'xhAdminUserPreferenceState'},
28
+ // Core config
29
+ autosizeOptions: {mode: 'managed', includeCollapsedChildren: true},
30
30
  colChooserModel: true,
31
31
  enableExport: true,
32
32
  exportOptions: {filename: exportFilenameWithDate('user-prefs')},
33
+ filterFields: ['name', 'username'],
34
+ groupBy: 'groupName',
35
+ persistWith: {localStorageKey: 'xhAdminUserPreferenceState'},
36
+ readonly: AppModel.readonly,
33
37
  selModel: 'multiple',
38
+ sortBy: 'name',
39
+ unit: 'user preference',
40
+ // Store + fields
34
41
  store: {
35
42
  url: 'rest/userPreferenceAdmin',
36
43
  reloadLookupsOnLoad: true,
@@ -55,10 +62,7 @@ export class UserPreferenceModel extends HoistModel {
55
62
  {...(Col.lastUpdatedBy.field as FieldSpec), editable: false}
56
63
  ]
57
64
  },
58
- sortBy: 'name',
59
- groupBy: 'groupName',
60
- unit: 'user preference',
61
- filterFields: ['name', 'username'],
65
+ // Cols + editors
62
66
  columns: [
63
67
  {...Col.name},
64
68
  {...Col.type},
@@ -7,11 +7,13 @@
7
7
  import {exportFilenameWithDate} from '@xh/hoist/admin/AdminUtils';
8
8
  import {AppModel} from '@xh/hoist/admin/AppModel';
9
9
  import * as Col from '@xh/hoist/admin/columns';
10
+ import {br, fragment} from '@xh/hoist/cmp/layout';
10
11
  import {HoistModel, LoadSpec, managed, XH} from '@xh/hoist/core';
11
12
  import {FieldSpec} from '@xh/hoist/data';
12
13
  import {textArea} from '@xh/hoist/desktop/cmp/input';
13
14
  import {addAction, deleteAction, editAction, RestGridModel} from '@xh/hoist/desktop/cmp/rest';
14
15
  import {action, makeObservable, observable} from '@xh/hoist/mobx';
16
+ import {pluralize} from '@xh/hoist/utils/js';
15
17
  import {DifferModel} from '../../../../differ/DifferModel';
16
18
  import {RegroupDialogModel} from '../../../../regroup/RegroupDialogModel';
17
19
 
@@ -32,18 +34,26 @@ export class PrefEditorModel extends HoistModel {
32
34
  super();
33
35
  makeObservable(this);
34
36
 
35
- const required = true,
37
+ const {regroupAction} = this.regroupDialogModel,
38
+ required = true,
36
39
  enableCreate = true,
37
40
  hidden = true;
38
41
 
39
42
  this.gridModel = new RestGridModel({
40
- readonly: AppModel.readonly,
41
- persistWith: this.persistWith,
43
+ // Core config
44
+ autosizeOptions: {mode: 'managed', includeCollapsedChildren: true},
42
45
  colChooserModel: true,
43
46
  enableExport: true,
44
47
  exportOptions: {filename: exportFilenameWithDate('prefs')},
48
+ filterFields: ['name', 'groupName'],
49
+ groupBy: 'groupName',
50
+ persistWith: this.persistWith,
51
+ readonly: AppModel.readonly,
45
52
  selModel: 'multiple',
46
53
  showRefreshButton: true,
54
+ sortBy: 'name',
55
+ unit: 'preference',
56
+ // Store + fields
47
57
  store: {
48
58
  url: 'rest/preferenceAdmin',
49
59
  reloadLookupsOnLoad: true,
@@ -68,21 +78,7 @@ export class PrefEditorModel extends HoistModel {
68
78
  {...(Col.lastUpdatedBy.field as FieldSpec), editable: false}
69
79
  ]
70
80
  },
71
- sortBy: 'name',
72
- groupBy: 'groupName',
73
- unit: 'preference',
74
- filterFields: ['name', 'groupName'],
75
- actionWarning: {
76
- del: records =>
77
- `Are you sure you want to delete ${records.length} preference(s)? Deleting preferences can break running apps.`
78
- },
79
- menuActions: [
80
- addAction,
81
- editAction,
82
- deleteAction,
83
- '-',
84
- this.regroupDialogModel.regroupAction
85
- ],
81
+ // Cols + Editors
86
82
  columns: [
87
83
  {...Col.name},
88
84
  {...Col.type},
@@ -100,7 +96,18 @@ export class PrefEditorModel extends HoistModel {
100
96
  {field: 'notes', formField: {item: textArea({height: 100})}},
101
97
  {field: 'lastUpdated'},
102
98
  {field: 'lastUpdatedBy'}
103
- ]
99
+ ],
100
+ // Actions
101
+ actionWarning: {
102
+ del: records =>
103
+ fragment(
104
+ `Are you sure you want to delete ${pluralize('selected preference', records.length, true)}?`,
105
+ br(),
106
+ br(),
107
+ `Deleting preference definitions can break running apps.`
108
+ )
109
+ },
110
+ menuActions: [addAction, editAction, deleteAction, '-', regroupAction]
104
111
  });
105
112
  }
106
113
 
@@ -1,10 +1,11 @@
1
- import { RowDoubleClickedEvent } from '@xh/hoist/kit/ag-grid';
2
1
  import { BaseFieldConfig } from '@xh/hoist/cmp/form';
3
2
  import { GridConfig, GridModel } from '@xh/hoist/cmp/grid';
4
3
  import { ElementSpec, HoistModel, PlainObject } from '@xh/hoist/core';
5
4
  import '@xh/hoist/desktop/register';
6
5
  import { RecordAction, RecordActionSpec, StoreRecord } from '@xh/hoist/data';
6
+ import { RowDoubleClickedEvent } from '@xh/hoist/kit/ag-grid';
7
7
  import { ExportOptions } from '@xh/hoist/svc';
8
+ import { ReactNode } from 'react';
8
9
  import { FormFieldProps } from '../form';
9
10
  import { RestStore, RestStoreConfig } from './data/RestStore';
10
11
  import { RestFormModel } from './impl/RestFormModel';
@@ -22,9 +23,9 @@ export interface RestGridConfig extends GridConfig {
22
23
  showRefreshButton?: boolean;
23
24
  /** Warning to display before actions on a selection of records. */
24
25
  actionWarning?: {
25
- add?: string | ((recs: StoreRecord[]) => string);
26
- del?: string | ((recs: StoreRecord[]) => string);
27
- edit?: string | ((recs: StoreRecord[]) => string);
26
+ add?: ReactNode | ((recs: StoreRecord[]) => ReactNode);
27
+ del?: ReactNode | ((recs: StoreRecord[]) => ReactNode);
28
+ edit?: ReactNode | ((recs: StoreRecord[]) => ReactNode);
28
29
  };
29
30
  /** Name that describes records in this grid. */
30
31
  unit?: string;
@@ -16,9 +16,9 @@ export declare class RestFormModel extends HoistModel {
16
16
  dialogRef: import("react").RefObject<HTMLElement>;
17
17
  get unit(): string;
18
18
  get actionWarning(): {
19
- add?: string | ((recs: import("@xh/hoist/data").StoreRecord[]) => string);
20
- del?: string | ((recs: import("@xh/hoist/data").StoreRecord[]) => string);
21
- edit?: string | ((recs: import("@xh/hoist/data").StoreRecord[]) => string);
19
+ add?: import("react").ReactNode | ((recs: import("@xh/hoist/data").StoreRecord[]) => import("react").ReactNode);
20
+ del?: import("react").ReactNode | ((recs: import("@xh/hoist/data").StoreRecord[]) => import("react").ReactNode);
21
+ edit?: import("react").ReactNode | ((recs: import("@xh/hoist/data").StoreRecord[]) => import("react").ReactNode);
22
22
  };
23
23
  get actions(): (import("@xh/hoist/data").RecordActionSpec | import("@xh/hoist/data").RecordAction)[];
24
24
  get editors(): RestGridEditor[];
@@ -5,15 +5,16 @@
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
7
 
8
- import {RowDoubleClickedEvent} from '@xh/hoist/kit/ag-grid';
9
8
  import {BaseFieldConfig} from '@xh/hoist/cmp/form';
10
9
  import {GridConfig, GridModel} from '@xh/hoist/cmp/grid';
11
10
  import {ElementSpec, HoistModel, managed, PlainObject, XH} from '@xh/hoist/core';
12
11
  import '@xh/hoist/desktop/register';
13
12
  import {RecordAction, RecordActionSpec, StoreRecord} from '@xh/hoist/data';
13
+ import {RowDoubleClickedEvent} from '@xh/hoist/kit/ag-grid';
14
14
  import {ExportOptions} from '@xh/hoist/svc';
15
15
  import {pluralize, throwIf, withDefault} from '@xh/hoist/utils/js';
16
16
  import {isFunction} from 'lodash';
17
+ import {ReactNode} from 'react';
17
18
  import {FormFieldProps} from '../form';
18
19
  import {addAction, deleteAction, editAction, viewAction} from './Actions';
19
20
  import {RestStore, RestStoreConfig} from './data/RestStore';
@@ -39,9 +40,9 @@ export interface RestGridConfig extends GridConfig {
39
40
 
40
41
  /** Warning to display before actions on a selection of records. */
41
42
  actionWarning?: {
42
- add?: string | ((recs: StoreRecord[]) => string);
43
- del?: string | ((recs: StoreRecord[]) => string);
44
- edit?: string | ((recs: StoreRecord[]) => string);
43
+ add?: ReactNode | ((recs: StoreRecord[]) => ReactNode);
44
+ del?: ReactNode | ((recs: StoreRecord[]) => ReactNode);
45
+ edit?: ReactNode | ((recs: StoreRecord[]) => ReactNode);
45
46
  };
46
47
 
47
48
  /** Name that describes records in this grid. */
@@ -109,11 +110,7 @@ export class RestGridModel extends HoistModel {
109
110
  add: null,
110
111
  edit: null,
111
112
  del: recs =>
112
- recs.length > 1
113
- ? `Are you sure you want to delete the selected ${recs.length} ${pluralize(
114
- this.unit
115
- )}?`
116
- : `Are you sure you want to delete the selected ${this.unit}?`
113
+ `Are you sure you want to delete ${pluralize(`selected ${this.unit}`, recs.length, true)}?`
117
114
  };
118
115
 
119
116
  @managed gridModel: GridModel = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xh/hoist",
3
- "version": "78.0.0-SNAPSHOT.1762216163824",
3
+ "version": "78.0.0-SNAPSHOT.1762310926429",
4
4
  "description": "Hoist add-on for building and deploying React Applications.",
5
5
  "repository": "github:xh/hoist-react",
6
6
  "homepage": "https://xh.io",