@cloudtower/eagle 490.0.5 → 490.0.6
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/README.md +34 -0
- package/dist/cjs/core/Cascader/cascader.widget.js +12 -12
- package/dist/cjs/core/SearchInput/SearchInput.hook.js +124 -0
- package/dist/cjs/core/SearchInput/SearchInput.js +253 -0
- package/dist/cjs/core/SearchInput/SearchInput.style.js +13 -0
- package/dist/cjs/core/index.js +6 -6
- package/dist/cjs/index.js +172 -172
- package/dist/cjs/legacy-antd.js +89 -89
- package/dist/cjs/stats1.html +1 -1
- package/dist/components.css +3304 -3281
- package/dist/esm/core/Cascader/cascader.widget.js +1 -1
- package/dist/esm/core/SearchInput/SearchInput.hook.js +117 -0
- package/dist/esm/core/SearchInput/SearchInput.js +247 -0
- package/dist/esm/core/SearchInput/SearchInput.style.js +7 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/legacy-antd.js +1 -1
- package/dist/esm/stats1.html +1 -1
- package/dist/linaria.merged.scss +4417 -4388
- package/dist/src/core/Cascader/cascader.type.d.ts +1 -1
- package/dist/src/core/ImmersiveDialog/type.d.ts +127 -19
- package/dist/src/core/MediumDialog/MediumDialog.type.d.ts +49 -1
- package/dist/src/core/SearchInput/SearchInput.d.ts +2 -0
- package/dist/src/core/SearchInput/SearchInput.hook.d.ts +9 -0
- package/dist/src/core/SearchInput/SearchInput.style.d.ts +5 -0
- package/dist/src/core/SearchInput/{searchInput.type.d.ts → SearchInput.type.d.ts} +18 -2
- package/dist/src/core/SearchInput/__test__/SearchInput.hook.test.d.ts +1 -0
- package/dist/src/core/SearchInput/index.d.ts +2 -4
- package/dist/src/core/SmallDialog/SmallDialog.type.d.ts +150 -21
- package/dist/src/core/TableForm/types.d.ts +216 -68
- package/dist/src/core/WizardDialog/type.d.ts +147 -13
- package/dist/src/core/index.d.ts +0 -1
- package/dist/src/coreX/Dialogs/DeleteDialog/DeleteDialog.type.d.ts +100 -9
- package/dist/src/coreX/Dialogs/RejectDialog/RejectDialog.type.d.ts +126 -19
- package/dist/stories/docs/core/ImmersiveDialog.stories.d.ts +76 -8
- package/dist/stories/docs/core/MediumDialog.stories.d.ts +42 -8
- package/dist/stories/docs/core/SearchInput.stories.d.ts +6 -1
- package/dist/stories/docs/core/SmallDialog.stories.d.ts +86 -7
- package/dist/stories/docs/core/TableForm.stories.d.ts +40 -26
- package/dist/stories/docs/core/WizardDialog.stories.d.ts +65 -6
- package/dist/stories/docs/coreX/Dialogs/DeleteDialog.stories.d.ts +20 -19
- package/dist/stories/docs/coreX/Dialogs/RejectDialog.stories.d.ts +24 -23
- package/dist/style.css +3304 -3281
- package/docs/core/ImmersiveDialog/guide.md +298 -0
- package/docs/core/LegacyModal/migrate-guide.md +422 -0
- package/docs/core/MediumDialog/guide.md +263 -0
- package/docs/core/SmallDialog/guide.md +224 -0
- package/docs/core/TableForm/guide.md +195 -0
- package/docs/core/WizardDialog/guide.md +322 -0
- package/docs/coreX/DeleteDialog/guide.md +161 -0
- package/docs/coreX/RejectDialog/guide.md +185 -0
- package/docs/llms.txt +169 -0
- package/package.json +6 -5
- package/dist/cjs/core/SearchInput/index.js +0 -164
- package/dist/esm/core/SearchInput/index.js +0 -157
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
# WizardDialog
|
|
2
|
+
|
|
3
|
+
## 简介
|
|
4
|
+
|
|
5
|
+
WizardDialog 是基于 ImmersiveDialog 的多步骤向导对话框组件,自动管理步骤导航、步骤指示器和按钮文案切换。非最后一步时确定按钮显示"下一步"并触发 `onNextStep`;最后一步显示"确定"并触发 `onOk`。左侧内置垂直步骤条(Steps),底部自动展示"上一步"按钮(第一步时隐藏)。
|
|
6
|
+
|
|
7
|
+
## 何时使用
|
|
8
|
+
|
|
9
|
+
- 多步骤表单(如"创建虚拟机"需要依次填写基本信息、网络配置、存储配置)
|
|
10
|
+
- 分步操作流程(需要引导用户按顺序完成一系列操作)
|
|
11
|
+
- 需要在步骤之间做校验、阻止用户跳到下一步的场景
|
|
12
|
+
|
|
13
|
+
不要使用:
|
|
14
|
+
|
|
15
|
+
- 简单确认操作 --> 请用 `SmallDialog`
|
|
16
|
+
- 不需要步骤的全屏操作 --> 请用 `ImmersiveDialog`
|
|
17
|
+
- 包含表单但无需分步 --> 请用 `MediumDialog`
|
|
18
|
+
|
|
19
|
+
## 基础用法
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import React from "react";
|
|
23
|
+
import { WizardDialog, Button } from "@cloudtower/eagle";
|
|
24
|
+
import { usePushModal, usePopModal } from "@cloudtower/eagle";
|
|
25
|
+
|
|
26
|
+
const CreateVmDialog: React.FC = () => {
|
|
27
|
+
const popModal = usePopModal();
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<WizardDialog
|
|
31
|
+
title="创建虚拟机"
|
|
32
|
+
steps={[
|
|
33
|
+
{
|
|
34
|
+
title: "基本信息",
|
|
35
|
+
children: <div>填写虚拟机名称、描述等基本信息</div>,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
title: "网络配置",
|
|
39
|
+
children: <div>选择网络、配置 IP 地址</div>,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
title: "存储配置",
|
|
43
|
+
children: <div>选择存储策略、配置磁盘</div>,
|
|
44
|
+
},
|
|
45
|
+
]}
|
|
46
|
+
onOk={(e) => {
|
|
47
|
+
console.log("提交创建");
|
|
48
|
+
popModal();
|
|
49
|
+
}}
|
|
50
|
+
>
|
|
51
|
+
</WizardDialog>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// 使用方式
|
|
56
|
+
const App = () => {
|
|
57
|
+
const pushModal = usePushModal();
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<Button
|
|
61
|
+
type="primary"
|
|
62
|
+
onClick={() =>
|
|
63
|
+
pushModal({
|
|
64
|
+
component: () => <CreateVmDialog />,
|
|
65
|
+
props: { name: "CreateVmDialog" },
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
>
|
|
69
|
+
创建虚拟机
|
|
70
|
+
</Button>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 常见模式
|
|
76
|
+
|
|
77
|
+
### 模式一:基础向导
|
|
78
|
+
|
|
79
|
+
最简单的多步骤向导,步骤之间自由导航,最后一步提交。
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import React from "react";
|
|
83
|
+
import { WizardDialog, Button } from "@cloudtower/eagle";
|
|
84
|
+
import { usePushModal, usePopModal } from "@cloudtower/eagle";
|
|
85
|
+
|
|
86
|
+
const BasicWizardDialog: React.FC = () => {
|
|
87
|
+
const popModal = usePopModal();
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<WizardDialog
|
|
91
|
+
title="初始化集群"
|
|
92
|
+
steps={[
|
|
93
|
+
{
|
|
94
|
+
title: "选择节点",
|
|
95
|
+
children: <div>从列表中选择要加入集群的节点</div>,
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
title: "网络设置",
|
|
99
|
+
children: <div>配置集群网络参数</div>,
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
title: "确认信息",
|
|
103
|
+
children: <div>确认集群配置信息无误后提交</div>,
|
|
104
|
+
},
|
|
105
|
+
]}
|
|
106
|
+
onOk={(e) => {
|
|
107
|
+
console.log("提交集群初始化");
|
|
108
|
+
popModal();
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
</WizardDialog>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const App = () => {
|
|
116
|
+
const pushModal = usePushModal();
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<Button
|
|
120
|
+
type="primary"
|
|
121
|
+
onClick={() =>
|
|
122
|
+
pushModal({
|
|
123
|
+
component: () => <BasicWizardDialog />,
|
|
124
|
+
props: { name: "BasicWizardDialog" },
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
>
|
|
128
|
+
初始化集群
|
|
129
|
+
</Button>
|
|
130
|
+
);
|
|
131
|
+
};
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 模式二:带校验的向导(onNextStep 阻止导航)
|
|
135
|
+
|
|
136
|
+
这是 WizardDialog 最核心的模式。通过 `onNextStep` 回调返回 `false` 来阻止用户在校验未通过时跳到下一步。注意:组件内部使用严格等于 `=== false` 判断,因此只有显式返回 `false` 才会阻止导航,返回 `undefined`(即不返回值)不会阻止。
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
import React, { useState } from "react";
|
|
140
|
+
import { WizardDialog, Button } from "@cloudtower/eagle";
|
|
141
|
+
import { usePushModal, usePopModal } from "@cloudtower/eagle";
|
|
142
|
+
|
|
143
|
+
const ValidatedWizardDialog: React.FC = () => {
|
|
144
|
+
const popModal = usePopModal();
|
|
145
|
+
const [vmName, setVmName] = useState("");
|
|
146
|
+
const [network, setNetwork] = useState("");
|
|
147
|
+
const [error, setError] = useState<string>();
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<WizardDialog
|
|
151
|
+
title="创建虚拟机"
|
|
152
|
+
error={error}
|
|
153
|
+
steps={[
|
|
154
|
+
{
|
|
155
|
+
title: "基本信息",
|
|
156
|
+
children: (
|
|
157
|
+
<div>
|
|
158
|
+
<label>虚拟机名称</label>
|
|
159
|
+
<input
|
|
160
|
+
value={vmName}
|
|
161
|
+
onChange={(e) => {
|
|
162
|
+
setVmName(e.target.value);
|
|
163
|
+
setError(undefined);
|
|
164
|
+
}}
|
|
165
|
+
placeholder="请输入虚拟机名称"
|
|
166
|
+
/>
|
|
167
|
+
</div>
|
|
168
|
+
),
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
title: "网络配置",
|
|
172
|
+
children: (
|
|
173
|
+
<div>
|
|
174
|
+
<label>网络</label>
|
|
175
|
+
<input
|
|
176
|
+
value={network}
|
|
177
|
+
onChange={(e) => {
|
|
178
|
+
setNetwork(e.target.value);
|
|
179
|
+
setError(undefined);
|
|
180
|
+
}}
|
|
181
|
+
placeholder="请选择网络"
|
|
182
|
+
/>
|
|
183
|
+
</div>
|
|
184
|
+
),
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
title: "确认",
|
|
188
|
+
children: (
|
|
189
|
+
<div>
|
|
190
|
+
<p>虚拟机名称:{vmName}</p>
|
|
191
|
+
<p>网络:{network}</p>
|
|
192
|
+
</div>
|
|
193
|
+
),
|
|
194
|
+
},
|
|
195
|
+
]}
|
|
196
|
+
onNextStep={(nextStep) => {
|
|
197
|
+
// nextStep 是即将跳转到的步骤索引
|
|
198
|
+
if (nextStep === 1 && !vmName.trim()) {
|
|
199
|
+
setError("请输入虚拟机名称");
|
|
200
|
+
return false; // 阻止导航
|
|
201
|
+
}
|
|
202
|
+
if (nextStep === 2 && !network.trim()) {
|
|
203
|
+
setError("请选择网络");
|
|
204
|
+
return false; // 阻止导航
|
|
205
|
+
}
|
|
206
|
+
setError(undefined);
|
|
207
|
+
// 不返回值(即返回 undefined),允许导航
|
|
208
|
+
}}
|
|
209
|
+
onOk={(e) => {
|
|
210
|
+
console.log("提交创建", { vmName, network });
|
|
211
|
+
popModal();
|
|
212
|
+
}}
|
|
213
|
+
>
|
|
214
|
+
</WizardDialog>
|
|
215
|
+
);
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const App = () => {
|
|
219
|
+
const pushModal = usePushModal();
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
<Button
|
|
223
|
+
type="primary"
|
|
224
|
+
onClick={() =>
|
|
225
|
+
pushModal({
|
|
226
|
+
component: () => <ValidatedWizardDialog />,
|
|
227
|
+
props: { name: "ValidatedWizardDialog" },
|
|
228
|
+
})
|
|
229
|
+
}
|
|
230
|
+
>
|
|
231
|
+
创建虚拟机
|
|
232
|
+
</Button>
|
|
233
|
+
);
|
|
234
|
+
};
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### 模式三:受控模式向导
|
|
238
|
+
|
|
239
|
+
通过外部 state 控制当前步骤,配合 `onStepChange` 同步状态。适用于需要在父组件中根据步骤变化执行额外逻辑的场景。
|
|
240
|
+
|
|
241
|
+
```tsx
|
|
242
|
+
import React, { useState } from "react";
|
|
243
|
+
import { WizardDialog, Button } from "@cloudtower/eagle";
|
|
244
|
+
import { usePushModal, usePopModal } from "@cloudtower/eagle";
|
|
245
|
+
|
|
246
|
+
const ControlledWizardDialog: React.FC = () => {
|
|
247
|
+
const popModal = usePopModal();
|
|
248
|
+
const [currentStep, setCurrentStep] = useState(0);
|
|
249
|
+
|
|
250
|
+
return (
|
|
251
|
+
<WizardDialog
|
|
252
|
+
title="部署应用"
|
|
253
|
+
step={currentStep}
|
|
254
|
+
onStepChange={(step) => {
|
|
255
|
+
console.log("步骤变化:", step);
|
|
256
|
+
setCurrentStep(step);
|
|
257
|
+
}}
|
|
258
|
+
onPrevStep={(step) => {
|
|
259
|
+
console.log("返回上一步:", step);
|
|
260
|
+
}}
|
|
261
|
+
onNextStep={(step) => {
|
|
262
|
+
console.log("进入下一步:", step);
|
|
263
|
+
}}
|
|
264
|
+
steps={[
|
|
265
|
+
{
|
|
266
|
+
title: "选择镜像",
|
|
267
|
+
children: <div>当前步骤:{currentStep + 1} / 3</div>,
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
title: "配置资源",
|
|
271
|
+
children: <div>当前步骤:{currentStep + 1} / 3</div>,
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
title: "确认部署",
|
|
275
|
+
children: <div>当前步骤:{currentStep + 1} / 3</div>,
|
|
276
|
+
},
|
|
277
|
+
]}
|
|
278
|
+
onOk={(e) => {
|
|
279
|
+
console.log("确认部署");
|
|
280
|
+
popModal();
|
|
281
|
+
}}
|
|
282
|
+
>
|
|
283
|
+
</WizardDialog>
|
|
284
|
+
);
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const App = () => {
|
|
288
|
+
const pushModal = usePushModal();
|
|
289
|
+
|
|
290
|
+
return (
|
|
291
|
+
<Button
|
|
292
|
+
type="primary"
|
|
293
|
+
onClick={() =>
|
|
294
|
+
pushModal({
|
|
295
|
+
component: () => <ControlledWizardDialog />,
|
|
296
|
+
props: { name: "ControlledWizardDialog" },
|
|
297
|
+
})
|
|
298
|
+
}
|
|
299
|
+
>
|
|
300
|
+
部署应用
|
|
301
|
+
</Button>
|
|
302
|
+
);
|
|
303
|
+
};
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## 关键说明
|
|
307
|
+
|
|
308
|
+
- **按钮文案自动切换**:非最后一步时,确认按钮文案自动显示为 `nextText`(默认"下一步");最后一步时显示为 `okText`(默认"确认")。
|
|
309
|
+
- **onNextStep 校验机制**:`onNextStep` 返回值严格等于 `false`(`=== false`)时阻止导航到下一步。返回 `undefined`、`null`、`true` 或其他值均不会阻止。这是该组件最核心的交互模式。
|
|
310
|
+
- **onOk 仅在最后一步触发**:非最后一步点击确认按钮时触发的是 `onNextStep`,不会触发 `onOk`。
|
|
311
|
+
- **onOk 签名**:`onOk` 的签名为 `(e: React.MouseEvent) => void`,与 ImmersiveDialog 一致。需要使用 `usePopModal()` 获取 `popModal` 函数手动关闭弹窗。
|
|
312
|
+
- **步骤内容保留**:默认情况下所有步骤内容均保留在 DOM 中(通过 `display: none` 隐藏),表单状态不会丢失。如需销毁非当前步骤的内容,可设置 `destroyOtherStep={true}`。
|
|
313
|
+
- **"上一步"按钮**:当步骤索引大于 0 时,底部左侧自动展示"上一步"按钮(带左箭头图标)。第一步时不显示。
|
|
314
|
+
- **footerLeftAction 被占用**:WizardDialog 内部使用 `footerLeftAction` 渲染"上一步"按钮,因此外部传入的 `footerLeftAction` 会被覆盖。
|
|
315
|
+
|
|
316
|
+
## 相关组件
|
|
317
|
+
|
|
318
|
+
- `ImmersiveDialog` -- 全屏沉浸式对话框,WizardDialog 的基础组件,适用于不需要步骤的全屏操作
|
|
319
|
+
- `SmallDialog` -- 轻量级对话框(492px),适用于简单确认和信息提示
|
|
320
|
+
- `MediumDialog` -- 中等尺寸对话框(720px),适用于包含表单输入的场景
|
|
321
|
+
- `DeleteDialog` -- 删除确认对话框,封装了删除场景的标准样式和交互(位于 `@cloudtower/eagle` 的 coreX 模块)
|
|
322
|
+
- `Steps` -- 步骤条组件,WizardDialog 内部使用的步骤指示器
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# DeleteDialog
|
|
2
|
+
|
|
3
|
+
## 简介
|
|
4
|
+
|
|
5
|
+
DeleteDialog 是一个预设了删除确认样式的对话框组件,基于 SmallDialog 封装。确认按钮默认使用危险(红色)样式以突出操作风险,支持异步删除(confirmLoading)和 footer 错误信息展示。固定宽度 492px。
|
|
6
|
+
|
|
7
|
+
## 何时使用
|
|
8
|
+
|
|
9
|
+
- 删除单个或多个资源前需要用户二次确认
|
|
10
|
+
- 需要展示删除操作的风险提示(主描述 + 辅助说明)
|
|
11
|
+
- 异步删除操作需要 loading 状态和错误反馈
|
|
12
|
+
|
|
13
|
+
不要使用:
|
|
14
|
+
|
|
15
|
+
- 操作被拒绝/不可执行的反馈 --> 请用 `RejectDialog`
|
|
16
|
+
- 包含表单输入的删除确认 --> 请用 `MediumDialog`
|
|
17
|
+
- 非删除类的简单确认 --> 请用 `SmallDialog`
|
|
18
|
+
|
|
19
|
+
## 基础用法
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import React from "react";
|
|
23
|
+
import {
|
|
24
|
+
DeleteDialog,
|
|
25
|
+
Button,
|
|
26
|
+
KitStoreProvider,
|
|
27
|
+
ModalStack,
|
|
28
|
+
} from "@cloudtower/eagle";
|
|
29
|
+
import { usePushModal } from "@cloudtower/eagle";
|
|
30
|
+
|
|
31
|
+
const App = () => {
|
|
32
|
+
const pushModal = usePushModal();
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<Button
|
|
36
|
+
type="primary"
|
|
37
|
+
danger
|
|
38
|
+
onClick={() =>
|
|
39
|
+
pushModal({
|
|
40
|
+
component: () => (
|
|
41
|
+
<DeleteDialog
|
|
42
|
+
title="删除虚拟机"
|
|
43
|
+
description="确定要删除虚拟机 vm-prod-01 吗?"
|
|
44
|
+
secondaryDesc="删除后数据将无法恢复。"
|
|
45
|
+
onOk={(popModal) => {
|
|
46
|
+
console.log("confirmed delete");
|
|
47
|
+
popModal();
|
|
48
|
+
}}
|
|
49
|
+
/>
|
|
50
|
+
),
|
|
51
|
+
props: {},
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
>
|
|
55
|
+
删除虚拟机
|
|
56
|
+
</Button>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## 常见模式
|
|
62
|
+
|
|
63
|
+
### 模式一:异步删除 + 错误处理
|
|
64
|
+
|
|
65
|
+
适用于删除操作需要调用 API 的场景。通过 `confirmLoading` 控制按钮加载状态,`error` 展示操作失败信息。
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
import React, { useState } from "react";
|
|
69
|
+
import { DeleteDialog, Button } from "@cloudtower/eagle";
|
|
70
|
+
import { usePushModal } from "@cloudtower/eagle";
|
|
71
|
+
|
|
72
|
+
const AsyncDeleteDialog = () => {
|
|
73
|
+
const [loading, setLoading] = useState(false);
|
|
74
|
+
const [error, setError] = useState<string>();
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<DeleteDialog
|
|
78
|
+
title="删除集群"
|
|
79
|
+
description="确定要删除集群 cluster-01 吗?"
|
|
80
|
+
secondaryDesc="删除过程中请耐心等待。"
|
|
81
|
+
confirmLoading={loading}
|
|
82
|
+
error={error}
|
|
83
|
+
onOk={async (popModal) => {
|
|
84
|
+
setLoading(true);
|
|
85
|
+
setError(undefined);
|
|
86
|
+
try {
|
|
87
|
+
await deleteCluster("cluster-01");
|
|
88
|
+
popModal();
|
|
89
|
+
} catch {
|
|
90
|
+
setError("删除失败,请重试");
|
|
91
|
+
} finally {
|
|
92
|
+
setLoading(false);
|
|
93
|
+
}
|
|
94
|
+
}}
|
|
95
|
+
/>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// 使用方式
|
|
100
|
+
const App = () => {
|
|
101
|
+
const pushModal = usePushModal();
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<Button
|
|
105
|
+
type="primary"
|
|
106
|
+
danger
|
|
107
|
+
onClick={() =>
|
|
108
|
+
pushModal({ component: () => <AsyncDeleteDialog />, props: {} })
|
|
109
|
+
}
|
|
110
|
+
>
|
|
111
|
+
删除集群
|
|
112
|
+
</Button>
|
|
113
|
+
);
|
|
114
|
+
};
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 模式二:自定义按钮文案
|
|
118
|
+
|
|
119
|
+
适用于需要更明确的按钮文案来引导用户决策的场景。
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
import React from "react";
|
|
123
|
+
import { DeleteDialog, Button } from "@cloudtower/eagle";
|
|
124
|
+
import { usePushModal } from "@cloudtower/eagle";
|
|
125
|
+
|
|
126
|
+
const App = () => {
|
|
127
|
+
const pushModal = usePushModal();
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<Button
|
|
131
|
+
type="primary"
|
|
132
|
+
danger
|
|
133
|
+
onClick={() =>
|
|
134
|
+
pushModal({
|
|
135
|
+
component: () => (
|
|
136
|
+
<DeleteDialog
|
|
137
|
+
title="删除数据盘"
|
|
138
|
+
description="该数据盘中可能包含重要数据,删除后将无法恢复。"
|
|
139
|
+
cancelText="暂不删除"
|
|
140
|
+
okText="确认删除"
|
|
141
|
+
onOk={(popModal) => {
|
|
142
|
+
console.log("confirmed delete disk");
|
|
143
|
+
popModal();
|
|
144
|
+
}}
|
|
145
|
+
/>
|
|
146
|
+
),
|
|
147
|
+
props: {},
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
>
|
|
151
|
+
删除数据盘
|
|
152
|
+
</Button>
|
|
153
|
+
);
|
|
154
|
+
};
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## 相关组件
|
|
158
|
+
|
|
159
|
+
- `SmallDialog`: 底层对话框组件(492px),DeleteDialog 基于其封装
|
|
160
|
+
- `RejectDialog`: 操作拒绝反馈对话框,用于告知用户操作无法执行的原因
|
|
161
|
+
- `MediumDialog`: 中型对话框(720px),适用于包含表单的删除确认
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# RejectDialog
|
|
2
|
+
|
|
3
|
+
## 简介
|
|
4
|
+
|
|
5
|
+
RejectDialog 是操作拒绝反馈对话框,基于 SmallDialog 封装。用于告知用户某个操作无法执行及其原因,通过 `type` 属性(RejectDialogType 枚举)支持四种模式:Single(单个对象拒绝)、All(批量全部拒绝)、Part(批量部分拒绝)、Custom(自定义内容)。仅 Part 模式显示确认按钮(允许用户继续操作未被拒绝的部分)。
|
|
6
|
+
|
|
7
|
+
## 何时使用
|
|
8
|
+
|
|
9
|
+
- 单个资源操作被拒绝,需要展示拒绝原因(Single 模式)
|
|
10
|
+
- 批量操作中全部资源都不可操作,需要逐一列出原因(All 模式)
|
|
11
|
+
- 批量操作中部分资源不可操作,用户可选择跳过并继续(Part 模式)
|
|
12
|
+
- 标准模式无法满足的特殊拒绝反馈(Custom 模式)
|
|
13
|
+
|
|
14
|
+
不要使用:
|
|
15
|
+
|
|
16
|
+
- 删除确认场景 --> 请用 `DeleteDialog`
|
|
17
|
+
- 通用确认/提示场景 --> 请用 `SmallDialog`
|
|
18
|
+
- 包含表单的操作反馈 --> 请用 `MediumDialog`
|
|
19
|
+
|
|
20
|
+
## 基础用法
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import React from "react";
|
|
24
|
+
import {
|
|
25
|
+
RejectDialog,
|
|
26
|
+
RejectDialogType,
|
|
27
|
+
Button,
|
|
28
|
+
KitStoreProvider,
|
|
29
|
+
ModalStack,
|
|
30
|
+
} from "@cloudtower/eagle";
|
|
31
|
+
import { usePushModal } from "@cloudtower/eagle";
|
|
32
|
+
|
|
33
|
+
const App = () => {
|
|
34
|
+
const pushModal = usePushModal();
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<Button
|
|
38
|
+
onClick={() =>
|
|
39
|
+
pushModal({
|
|
40
|
+
component: () => (
|
|
41
|
+
<RejectDialog
|
|
42
|
+
type={RejectDialogType.Single}
|
|
43
|
+
title="无法删除虚拟机"
|
|
44
|
+
content="虚拟机正在运行中,请先关机再执行删除操作"
|
|
45
|
+
description="请解决以上问题后重试"
|
|
46
|
+
/>
|
|
47
|
+
),
|
|
48
|
+
props: {},
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
>
|
|
52
|
+
删除虚拟机
|
|
53
|
+
</Button>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## 常见模式
|
|
59
|
+
|
|
60
|
+
### 模式一:单个对象拒绝 - 多条原因
|
|
61
|
+
|
|
62
|
+
适用于单个资源有多个拒绝原因需要列出的场景。支持有序列表(ordered)、无序列表(unordered)和资源列表(resource)三种列表样式。
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
import React from "react";
|
|
66
|
+
import { RejectDialog, RejectDialogType, Button } from "@cloudtower/eagle";
|
|
67
|
+
import { usePushModal } from "@cloudtower/eagle";
|
|
68
|
+
|
|
69
|
+
const App = () => {
|
|
70
|
+
const pushModal = usePushModal();
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<Button
|
|
74
|
+
onClick={() =>
|
|
75
|
+
pushModal({
|
|
76
|
+
component: () => (
|
|
77
|
+
<RejectDialog
|
|
78
|
+
type={RejectDialogType.Single}
|
|
79
|
+
title="无法删除虚拟机"
|
|
80
|
+
content={[
|
|
81
|
+
"虚拟机当前状态为运行中,需要先关机",
|
|
82
|
+
"存在未完成的数据备份任务",
|
|
83
|
+
"该虚拟机已被安全策略锁定",
|
|
84
|
+
]}
|
|
85
|
+
listType="ordered"
|
|
86
|
+
description="请解决以上问题后重试"
|
|
87
|
+
/>
|
|
88
|
+
),
|
|
89
|
+
props: {},
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
>
|
|
93
|
+
删除虚拟机
|
|
94
|
+
</Button>
|
|
95
|
+
);
|
|
96
|
+
};
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 模式二:批量全部拒绝
|
|
100
|
+
|
|
101
|
+
适用于批量操作中所有资源均被拒绝的场景。content 使用 `{ [对象名]: [原因列表] }` 格式。
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
import React from "react";
|
|
105
|
+
import { RejectDialog, RejectDialogType, Button } from "@cloudtower/eagle";
|
|
106
|
+
import { usePushModal } from "@cloudtower/eagle";
|
|
107
|
+
|
|
108
|
+
const App = () => {
|
|
109
|
+
const pushModal = usePushModal();
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<Button
|
|
113
|
+
onClick={() =>
|
|
114
|
+
pushModal({
|
|
115
|
+
component: () => (
|
|
116
|
+
<RejectDialog
|
|
117
|
+
type={RejectDialogType.All}
|
|
118
|
+
title="无法删除选中的虚拟机"
|
|
119
|
+
content={{
|
|
120
|
+
"vm-master-01": ["作为集群主节点,需要先迁移控制平面"],
|
|
121
|
+
"vm-db-01": ["当前为主数据库节点", "有活跃的数据库连接"],
|
|
122
|
+
}}
|
|
123
|
+
description="以下虚拟机无法执行删除操作"
|
|
124
|
+
secondaryDesc="建议在业务低峰期执行删除操作"
|
|
125
|
+
/>
|
|
126
|
+
),
|
|
127
|
+
props: {},
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
>
|
|
131
|
+
批量删除虚拟机
|
|
132
|
+
</Button>
|
|
133
|
+
);
|
|
134
|
+
};
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 模式三:批量部分拒绝
|
|
138
|
+
|
|
139
|
+
适用于批量操作中部分资源可继续操作的场景。Part 模式会显示确认按钮(默认 danger 样式),通过 `okButtonProps={{ danger: false }}` 可改为非危险样式。
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
import React from "react";
|
|
143
|
+
import { RejectDialog, RejectDialogType, Button } from "@cloudtower/eagle";
|
|
144
|
+
import { usePushModal } from "@cloudtower/eagle";
|
|
145
|
+
|
|
146
|
+
const App = () => {
|
|
147
|
+
const pushModal = usePushModal();
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<Button
|
|
151
|
+
onClick={() =>
|
|
152
|
+
pushModal({
|
|
153
|
+
component: () => (
|
|
154
|
+
<RejectDialog
|
|
155
|
+
type={RejectDialogType.Part}
|
|
156
|
+
title="升级虚拟机工具"
|
|
157
|
+
description="选中的 3 个虚拟机中,有 1 个可以升级。"
|
|
158
|
+
content={{
|
|
159
|
+
vm1: ["无需升级"],
|
|
160
|
+
vm2: ["未安装虚拟机工具"],
|
|
161
|
+
}}
|
|
162
|
+
partialDescription="2 个虚拟机无法升级,继续操作将跳过这些虚拟机。"
|
|
163
|
+
okText="部分升级"
|
|
164
|
+
okButtonProps={{ danger: false }}
|
|
165
|
+
onOk={(popModal) => {
|
|
166
|
+
console.log("执行部分升级");
|
|
167
|
+
popModal();
|
|
168
|
+
}}
|
|
169
|
+
/>
|
|
170
|
+
),
|
|
171
|
+
props: {},
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
>
|
|
175
|
+
批量升级虚拟机工具
|
|
176
|
+
</Button>
|
|
177
|
+
);
|
|
178
|
+
};
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## 相关组件
|
|
182
|
+
|
|
183
|
+
- `SmallDialog`: 底层对话框组件(492px),RejectDialog 基于其封装
|
|
184
|
+
- `DeleteDialog`: 删除确认对话框,用于需要用户确认的删除操作
|
|
185
|
+
- `MediumDialog`: 中型对话框(720px),适用于包含表单的复杂反馈场景
|