@xh/hoist 76.0.0-SNAPSHOT.1754920978016 → 76.0.0-SNAPSHOT.1755111169547
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 +6 -0
- package/admin/tabs/cluster/instances/InstancesTabModel.ts +2 -1
- package/admin/tabs/general/alertBanner/AlertBannerModel.ts +2 -2
- package/admin/tabs/userData/roles/RoleModel.ts +8 -2
- package/admin/tabs/userData/roles/editor/RoleEditorModel.ts +3 -2
- package/appcontainer/MessageModel.ts +22 -2
- package/build/types/appcontainer/MessageModel.d.ts +3 -1
- package/build/types/core/types/Interfaces.d.ts +17 -8
- package/core/types/Interfaces.ts +20 -8
- package/data/cube/row/BaseRow.ts +5 -3
- package/desktop/appcontainer/Message.ts +39 -13
- package/mobile/appcontainer/Message.ts +21 -5
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## 76.0.0-SNAPSHOT - unreleased
|
|
4
4
|
|
|
5
|
+
### 🎁 New Features
|
|
6
|
+
|
|
7
|
+
* Added new `extraConfirmText`, `extraConfirmLabel` properties to `MessageOptions`. Use this option
|
|
8
|
+
to require the specified text to be re-typed by a user when confirming a potentially destructive or disruptive action.
|
|
9
|
+
|
|
5
10
|
## 75.0.1 - 2025-08-11
|
|
6
11
|
|
|
7
12
|
### 🎁 New Features
|
|
@@ -32,6 +37,7 @@
|
|
|
32
37
|
which can be activated via the `Query.provideLeaves` property.
|
|
33
38
|
|
|
34
39
|
### 🐞 Bug Fixes
|
|
40
|
+
|
|
35
41
|
* Fixed bugs where `Store.modifyRecords`, `Store.revertRecords` and `Store.revert` were not properly
|
|
36
42
|
handling changes to `SummaryRecords`.
|
|
37
43
|
* Fixed minor `DashCanvas` issues with `allowAdd: false`, ensuring it does not block additions made
|
|
@@ -212,7 +212,8 @@ export class InstancesTabModel extends HoistModel {
|
|
|
212
212
|
private async shutdownInstanceAsync(instance: PlainObject) {
|
|
213
213
|
if (
|
|
214
214
|
!(await XH.confirm({
|
|
215
|
-
message: `Are you sure you
|
|
215
|
+
message: `Are you sure you want to immediately terminate instance ${instance.name}?`,
|
|
216
|
+
extraConfirmText: instance.name,
|
|
216
217
|
confirmProps: {
|
|
217
218
|
icon: Icon.skull(),
|
|
218
219
|
text: 'Yes, kill the instance',
|
|
@@ -135,7 +135,7 @@ export class AlertBannerModel extends HoistModel {
|
|
|
135
135
|
@action
|
|
136
136
|
removePreset(preset: PlainObject) {
|
|
137
137
|
XH.confirm({
|
|
138
|
-
message: 'Are you sure you
|
|
138
|
+
message: 'Are you sure you want to delete this preset?',
|
|
139
139
|
confirmProps: {
|
|
140
140
|
text: 'Remove',
|
|
141
141
|
intent: 'danger',
|
|
@@ -252,7 +252,7 @@ export class AlertBannerModel extends HoistModel {
|
|
|
252
252
|
const finalConfirm = await XH.confirm({
|
|
253
253
|
message: fragment(
|
|
254
254
|
p('This change will modify a live banner for all users of this application.'),
|
|
255
|
-
p('Are you sure you
|
|
255
|
+
p('Are you sure you want to do this?')
|
|
256
256
|
),
|
|
257
257
|
confirmProps: {
|
|
258
258
|
text: 'Yes, modify the banner',
|
|
@@ -8,6 +8,7 @@ import {RecategorizeDialogModel} from '@xh/hoist/admin/tabs/userData/roles/recat
|
|
|
8
8
|
import {FilterChooserModel} from '@xh/hoist/cmp/filter';
|
|
9
9
|
import {GridModel, tagsRenderer, TreeStyle} from '@xh/hoist/cmp/grid';
|
|
10
10
|
import * as Col from '@xh/hoist/cmp/grid/columns';
|
|
11
|
+
import {fragment, p} from '@xh/hoist/cmp/layout';
|
|
11
12
|
import {HoistModel, LoadSpec, managed, XH} from '@xh/hoist/core';
|
|
12
13
|
import {RecordActionSpec} from '@xh/hoist/data';
|
|
13
14
|
import {actionCol, calcActionColWidth} from '@xh/hoist/desktop/cmp/grid';
|
|
@@ -125,10 +126,15 @@ export class RoleModel extends HoistModel {
|
|
|
125
126
|
if (this.readonly) return false;
|
|
126
127
|
|
|
127
128
|
const confirm = await XH.confirm({
|
|
128
|
-
message:
|
|
129
|
+
message: fragment(
|
|
130
|
+
p(`Are you sure you want to delete the ${role.name} role?`),
|
|
131
|
+
p(`This may impact access to this application.`)
|
|
132
|
+
),
|
|
133
|
+
extraConfirmText: role.name,
|
|
129
134
|
confirmProps: {
|
|
130
|
-
text: '
|
|
135
|
+
text: 'Delete role',
|
|
131
136
|
intent: 'danger',
|
|
137
|
+
outlined: true,
|
|
132
138
|
autoFocus: false
|
|
133
139
|
}
|
|
134
140
|
});
|
|
@@ -77,13 +77,14 @@ export class RoleEditorModel extends HoistModel {
|
|
|
77
77
|
this.doCancel();
|
|
78
78
|
} else {
|
|
79
79
|
XH.confirm({
|
|
80
|
-
message: 'You have unsaved changes. Are you sure you
|
|
80
|
+
message: 'You have unsaved changes. Are you sure you want to proceed?',
|
|
81
81
|
cancelProps: {
|
|
82
82
|
text: 'Keep editing'
|
|
83
83
|
},
|
|
84
84
|
confirmProps: {
|
|
85
85
|
text: 'Discard Changes',
|
|
86
|
-
intent: 'danger'
|
|
86
|
+
intent: 'danger',
|
|
87
|
+
outlined: true
|
|
87
88
|
},
|
|
88
89
|
onConfirm: () => this.doCancel()
|
|
89
90
|
});
|
|
@@ -9,6 +9,7 @@ import {HoistModel, XH, MessageSpec, managed} from '@xh/hoist/core';
|
|
|
9
9
|
import {action, observable, makeObservable} from '@xh/hoist/mobx';
|
|
10
10
|
import {warnIf} from '@xh/hoist/utils/js';
|
|
11
11
|
import {isEmpty} from 'lodash';
|
|
12
|
+
import {ReactNode} from 'react';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Model for a single instance of a modal dialog.
|
|
@@ -26,6 +27,7 @@ export class MessageModel extends HoistModel {
|
|
|
26
27
|
messageKey;
|
|
27
28
|
className;
|
|
28
29
|
input;
|
|
30
|
+
extraConfirmLabel: ReactNode;
|
|
29
31
|
confirmProps;
|
|
30
32
|
cancelProps;
|
|
31
33
|
cancelAlign;
|
|
@@ -50,6 +52,8 @@ export class MessageModel extends HoistModel {
|
|
|
50
52
|
messageKey,
|
|
51
53
|
className,
|
|
52
54
|
input,
|
|
55
|
+
extraConfirmText,
|
|
56
|
+
extraConfirmLabel,
|
|
53
57
|
confirmProps = {},
|
|
54
58
|
cancelProps = {},
|
|
55
59
|
cancelAlign = 'right',
|
|
@@ -69,10 +73,24 @@ export class MessageModel extends HoistModel {
|
|
|
69
73
|
this.dismissable = dismissable;
|
|
70
74
|
this.cancelOnDismiss = cancelOnDismiss;
|
|
71
75
|
|
|
76
|
+
const fields = [];
|
|
77
|
+
|
|
72
78
|
if (input) {
|
|
73
79
|
this.input = input;
|
|
74
80
|
const {initialValue, rules} = input;
|
|
75
|
-
|
|
81
|
+
fields.push({name: 'value', initialValue, rules});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (extraConfirmText) {
|
|
85
|
+
this.extraConfirmLabel = extraConfirmLabel ?? `Enter '${extraConfirmText}' to confirm:`;
|
|
86
|
+
fields.push({
|
|
87
|
+
name: 'extraConfirm',
|
|
88
|
+
rules: [({value}) => (value === extraConfirmText ? null : `Confirmation required`)]
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!isEmpty(fields)) {
|
|
93
|
+
this.formModel = new FormModel({fields});
|
|
76
94
|
}
|
|
77
95
|
|
|
78
96
|
this.confirmProps = this.parseButtonProps(confirmProps, () => this.doConfirmAsync());
|
|
@@ -98,7 +116,9 @@ export class MessageModel extends HoistModel {
|
|
|
98
116
|
if (this.formModel) {
|
|
99
117
|
await this.formModel.validateAsync();
|
|
100
118
|
if (!this.formModel.isValid) return;
|
|
101
|
-
|
|
119
|
+
if (this.formModel.getField('value')) {
|
|
120
|
+
resolvedVal = this.formModel.getData().value;
|
|
121
|
+
}
|
|
102
122
|
}
|
|
103
123
|
|
|
104
124
|
this.onConfirm?.();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FormModel } from '@xh/hoist/cmp/form';
|
|
2
2
|
import { HoistModel, MessageSpec } from '@xh/hoist/core';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
3
4
|
/**
|
|
4
5
|
* Model for a single instance of a modal dialog.
|
|
5
6
|
* Not intended for direct application use.
|
|
@@ -14,6 +15,7 @@ export declare class MessageModel extends HoistModel {
|
|
|
14
15
|
messageKey: any;
|
|
15
16
|
className: any;
|
|
16
17
|
input: any;
|
|
18
|
+
extraConfirmLabel: ReactNode;
|
|
17
19
|
confirmProps: any;
|
|
18
20
|
cancelProps: any;
|
|
19
21
|
cancelAlign: any;
|
|
@@ -25,7 +27,7 @@ export declare class MessageModel extends HoistModel {
|
|
|
25
27
|
_resolver: any;
|
|
26
28
|
formModel: FormModel;
|
|
27
29
|
isOpen: boolean;
|
|
28
|
-
constructor({ title, icon, message, messageKey, className, input, confirmProps, cancelProps, cancelAlign, onConfirm, onCancel, dismissable, cancelOnDismiss }: MessageSpec);
|
|
30
|
+
constructor({ title, icon, message, messageKey, className, input, extraConfirmText, extraConfirmLabel, confirmProps, cancelProps, cancelAlign, onConfirm, onCancel, dismissable, cancelOnDismiss }: MessageSpec);
|
|
29
31
|
doConfirmAsync(): Promise<void>;
|
|
30
32
|
doCancel(): void;
|
|
31
33
|
doEscape(): void;
|
|
@@ -72,14 +72,15 @@ export interface MessageSpec {
|
|
|
72
72
|
*/
|
|
73
73
|
messageKey?: string;
|
|
74
74
|
/** Config for input to be displayed (as a prompt). */
|
|
75
|
-
input?:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
75
|
+
input?: MessageSpecInput;
|
|
76
|
+
/** If specified, user will be required to type this text when confirming. */
|
|
77
|
+
extraConfirmText?: string;
|
|
78
|
+
/**
|
|
79
|
+
* Text/label to inform the user of the text required to confirm.
|
|
80
|
+
* Only used if extraConfirmText is specified.
|
|
81
|
+
* Defaults to `Type '${extraConfirmText}' to confirm:`.
|
|
82
|
+
*/
|
|
83
|
+
extraConfirmLabel?: ReactNode;
|
|
83
84
|
/**
|
|
84
85
|
* Props for primary confirm button.
|
|
85
86
|
* Must provide either text or icon for button to be displayed, or use a preconfigured
|
|
@@ -106,6 +107,14 @@ export interface MessageSpec {
|
|
|
106
107
|
/** Flag to specify whether onCancel is executed when clicking out of or escaping a popup. */
|
|
107
108
|
cancelOnDismiss?: boolean;
|
|
108
109
|
}
|
|
110
|
+
export interface MessageSpecInput {
|
|
111
|
+
/** An element specifying a HoistInput, defaults to a platform appropriate TextInput. */
|
|
112
|
+
item?: ReactElement;
|
|
113
|
+
/** Validation constraints to apply. */
|
|
114
|
+
rules?: RuleLike[];
|
|
115
|
+
/** Initial value for the input. */
|
|
116
|
+
initialValue?: any;
|
|
117
|
+
}
|
|
109
118
|
/**
|
|
110
119
|
* Configuration object for an app-wide banner.
|
|
111
120
|
*/
|
package/core/types/Interfaces.ts
CHANGED
|
@@ -91,16 +91,17 @@ export interface MessageSpec {
|
|
|
91
91
|
messageKey?: string;
|
|
92
92
|
|
|
93
93
|
/** Config for input to be displayed (as a prompt). */
|
|
94
|
-
input?:
|
|
95
|
-
/** An element specifying a HoistInput, defaults to a platform appropriate TextInput. */
|
|
96
|
-
item?: ReactElement;
|
|
94
|
+
input?: MessageSpecInput;
|
|
97
95
|
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
/** If specified, user will be required to type this text when confirming. */
|
|
97
|
+
extraConfirmText?: string;
|
|
100
98
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Text/label to inform the user of the text required to confirm.
|
|
101
|
+
* Only used if extraConfirmText is specified.
|
|
102
|
+
* Defaults to `Type '${extraConfirmText}' to confirm:`.
|
|
103
|
+
*/
|
|
104
|
+
extraConfirmLabel?: ReactNode;
|
|
104
105
|
|
|
105
106
|
/**
|
|
106
107
|
* Props for primary confirm button.
|
|
@@ -135,6 +136,17 @@ export interface MessageSpec {
|
|
|
135
136
|
cancelOnDismiss?: boolean;
|
|
136
137
|
}
|
|
137
138
|
|
|
139
|
+
export interface MessageSpecInput {
|
|
140
|
+
/** An element specifying a HoistInput, defaults to a platform appropriate TextInput. */
|
|
141
|
+
item?: ReactElement;
|
|
142
|
+
|
|
143
|
+
/** Validation constraints to apply. */
|
|
144
|
+
rules?: RuleLike[];
|
|
145
|
+
|
|
146
|
+
/** Initial value for the input. */
|
|
147
|
+
initialValue?: any;
|
|
148
|
+
}
|
|
149
|
+
|
|
138
150
|
/**
|
|
139
151
|
* Configuration object for an app-wide banner.
|
|
140
152
|
*/
|
package/data/cube/row/BaseRow.ts
CHANGED
|
@@ -96,12 +96,14 @@ export abstract class BaseRow {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
private getChildrenDatas(): ViewRowData[] {
|
|
99
|
-
let {children, view} = this
|
|
99
|
+
let {children, view} = this,
|
|
100
|
+
{query} = view;
|
|
100
101
|
|
|
101
|
-
if (!children
|
|
102
|
+
if (!children || (children[0].isLeaf && !query.includeLeaves && !query.provideLeaves))
|
|
103
|
+
return null;
|
|
102
104
|
|
|
103
105
|
// Skip all children in a locked node
|
|
104
|
-
if (
|
|
106
|
+
if (query.lockFn?.(this as any)) {
|
|
105
107
|
this.locked = true;
|
|
106
108
|
return null;
|
|
107
109
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import {MessageModel} from '@xh/hoist/appcontainer/MessageModel';
|
|
8
8
|
import {form} from '@xh/hoist/cmp/form';
|
|
9
|
-
import {filler} from '@xh/hoist/cmp/layout';
|
|
9
|
+
import {div, filler} from '@xh/hoist/cmp/layout';
|
|
10
10
|
import {hoistCmp, uses} from '@xh/hoist/core';
|
|
11
11
|
import {button} from '@xh/hoist/desktop/cmp/button';
|
|
12
12
|
import {formField} from '@xh/hoist/desktop/cmp/form';
|
|
@@ -35,31 +35,57 @@ export const message = hoistCmp.factory({
|
|
|
35
35
|
title: model.title,
|
|
36
36
|
icon: model.icon,
|
|
37
37
|
className: classNames(className, model.className),
|
|
38
|
-
items: [dialogBody(model.message,
|
|
38
|
+
items: [dialogBody(model.message, inputsCmp()), bbar()],
|
|
39
39
|
onClose: () => model.doEscape(),
|
|
40
40
|
...props
|
|
41
41
|
});
|
|
42
42
|
}
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
const
|
|
46
|
-
const {formModel, input} = model;
|
|
45
|
+
const inputsCmp = hoistCmp.factory<MessageModel>(({model}) => {
|
|
46
|
+
const {formModel, input, extraConfirmLabel} = model;
|
|
47
47
|
if (!formModel) return null;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
|
|
49
|
+
const items = [];
|
|
50
|
+
if (formModel.getField('value')) {
|
|
51
|
+
items.push(
|
|
52
|
+
formField({
|
|
53
|
+
field: 'value',
|
|
54
|
+
label: null,
|
|
55
|
+
item: withDefault(
|
|
56
|
+
input.item,
|
|
57
|
+
textInput({
|
|
58
|
+
autoFocus: true,
|
|
59
|
+
selectOnFocus: true,
|
|
60
|
+
onKeyDown: evt => {
|
|
61
|
+
if (evt.key === 'Enter') model.doConfirmAsync();
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
)
|
|
65
|
+
})
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
if (formModel.getField('extraConfirm')) {
|
|
69
|
+
items.push(
|
|
70
|
+
formField({
|
|
71
|
+
label: extraConfirmLabel,
|
|
72
|
+
field: 'extraConfirm',
|
|
73
|
+
item: textInput({
|
|
56
74
|
autoFocus: true,
|
|
57
75
|
selectOnFocus: true,
|
|
58
76
|
onKeyDown: evt => {
|
|
59
77
|
if (evt.key === 'Enter') model.doConfirmAsync();
|
|
60
78
|
}
|
|
61
79
|
})
|
|
62
|
-
)
|
|
80
|
+
})
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
return form({
|
|
84
|
+
model: formModel,
|
|
85
|
+
fieldDefaults: {commitOnChange: true, minimal: true},
|
|
86
|
+
item: div({
|
|
87
|
+
className: 'xh-pad',
|
|
88
|
+
items
|
|
63
89
|
})
|
|
64
90
|
});
|
|
65
91
|
});
|
|
@@ -68,13 +68,29 @@ export const message = hoistCmp.factory({
|
|
|
68
68
|
});
|
|
69
69
|
|
|
70
70
|
const inputCmp = hoistCmp.factory<MessageModel>(({model}) => {
|
|
71
|
-
const {formModel, input} = model;
|
|
71
|
+
const {formModel, input, extraConfirmLabel} = model;
|
|
72
72
|
if (!formModel) return null;
|
|
73
|
+
|
|
74
|
+
const items = [];
|
|
75
|
+
if (formModel.getField('value')) {
|
|
76
|
+
items.push(
|
|
77
|
+
formField({
|
|
78
|
+
field: 'value',
|
|
79
|
+
item: withDefault(input.item, textInput())
|
|
80
|
+
})
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
if (formModel.getField('extraConfirm')) {
|
|
84
|
+
items.push(
|
|
85
|
+
formField({
|
|
86
|
+
label: extraConfirmLabel,
|
|
87
|
+
field: 'extraConfirm',
|
|
88
|
+
item: textInput()
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
}
|
|
73
92
|
return form({
|
|
74
93
|
fieldDefaults: {commitOnChange: true, minimal: true, label: null},
|
|
75
|
-
|
|
76
|
-
field: 'value',
|
|
77
|
-
item: withDefault(input.item, textInput())
|
|
78
|
-
})
|
|
94
|
+
items
|
|
79
95
|
});
|
|
80
96
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xh/hoist",
|
|
3
|
-
"version": "76.0.0-SNAPSHOT.
|
|
3
|
+
"version": "76.0.0-SNAPSHOT.1755111169547",
|
|
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",
|