Skip to content

Commit 93b90fb

Browse files
authored
Merge pull request #10197 from ester-nl/appext/922-progress-dialog-docs
Add doc and sample code for showing a progress dialog.
2 parents dd34ec8 + f25da57 commit 93b90fb

File tree

4 files changed

+161
-17
lines changed

4 files changed

+161
-17
lines changed

content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/extensibility-api/web/web-extensions-howtos/command-api.md

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,28 +29,25 @@ To register commands, use the Commands API `registerCommand`.
2929
In the sample code below, we register a command, then attach it to a menu by setting the property `commandId` to the `Menu` object.
3030

3131
```typescript
32-
import { ComponentContext, IComponent, Menu, StudioProApi, getStudioProApi } from "@mendix/extensions-api";
33-
32+
import { ComponentContext, IComponent, StudioProApi, getStudioProApi } from "@mendix/extensions-api";
3433
const extensionId = "myextension";
3534

3635
export const component: IComponent = {
3736
async loaded(componentContext: ComponentContext) {
3837
const studioPro = getStudioProApi(componentContext);
3938

40-
await this.createMenuWithCommand(studioPro);
41-
}
42-
43-
async createMenuWithCommand(studioPro: StudioProApi) {
44-
const commandId = `${extensionId}.menu-command`;
45-
const menuId = `${commandId}.menu`;
46-
47-
await studioPro.app.commands.registerCommand<void>(
48-
commandId,
49-
async () => await studioPro.ui.messageBoxes.show("info", `This menu executed a command with id '${commandId}'`)
50-
);
51-
52-
await studioPro.ui.extensionsMenu.add({ caption: "Menu with command", menuId, commandId });
39+
await createMenuWithCommand(studioPro);
5340
}
41+
};
42+
async function createMenuWithCommand(studioPro: StudioProApi) {
43+
const commandId = `${extensionId}.menu-command`;
44+
const menuId = `${commandId}.menu`;
45+
46+
await studioPro.app.commands.registerCommand(
47+
commandId,
48+
async () => await studioPro.ui.messageBoxes.show("info", `This menu executed a command with id '${commandId}'`)
49+
);
50+
await studioPro.ui.extensionsMenu.add({ caption: "Menu with command", menuId, commandId });
5451
}
5552
```
5653

content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/extensibility-api/web/web-extensions-howtos/dialog-api.md

Lines changed: 116 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ url: /apidocs-mxsdk/apidocs/web-extensibility-api-11/dialog-api/
66

77
## Introduction
88

9-
This how-to describes how to open a modal dialog in Studio Pro from an extension. This dialog will contain your web content.
9+
This how-to describes how to open a modal dialog in Studio Pro from an extension, allowing you to display web content.
10+
11+
It also describes how to show a progress dialog that follows a sequence of steps and returns a result upon completion.
1012

1113
## Prerequisites
1214

@@ -19,7 +21,7 @@ Before starting this how-to, make sure you have completed the following prerequi
1921

2022
Create a menu item to open the dialog. This is done inside the `loaded` event in the main entry point (`src/main/index.ts`). For more information, see [Create a Menu Using Web API](/apidocs-mxsdk/apidocs/web-extensibility-api-11/menu-api/).
2123

22-
In a listener event called `menuItemActivated`, the `studioPro.ui.dialogs.showModal(<dialogInfo>, <uiSpec>)` call opens a new tab where:
24+
In a listener event called `menuItemActivated`, the `studioPro.ui.dialogs.showModal(<dialogInfo>, <uiSpec>)` call opens a new dialog where:
2325

2426
* `<dialogInfo>` is an object containing the `title` of the dialog, which is shown in the title bar of your dialog in Studio Pro. It also contains the `contentSize` object, where `height` and `width` dimensions for the dialog can be provided.
2527
* `<uiSpec>` is an object containing two required properties and one optional property:
@@ -227,6 +229,118 @@ You can modify the dimensions of a dialog using the dialog API's `update` method
227229

228230
You can also modify the dialog's dimensions while it is open.
229231

232+
## Showing a Progress Dialog {#process-dialog}
233+
234+
To show a progress dialog, call the method `studioPro.ui.dialogs.showProgressDialog(<title>, <steps>)`, where:
235+
236+
* `<title>` is a string that is displayed in the title bar of the dialog
237+
* `<steps>` is an array of `ProgressDialogStep`, which runs in the same order provided in the array; a `ProgressDialogStep` object contains the following properties:
238+
* `title`the title of the step, which is highlighted when the step is running
239+
* `description`the description of the step, which shows at the bottom of the dialog next to the progress bar
240+
* `action`the action the step will perform that returns `Promise<true | string>`, where `string` indicates the reason for failure if the step fails, and `true` is returned otherwise
241+
242+
A checkmark icon will be shown next to the step title once step has completed successfully. If one of the steps fails, the dialog will close and the remaining steps will not be executed.
243+
244+
The `showProgressDialog` method returns a `Promise<ProgressDialogResult>`. `ProgressDialogResult` is an object that contains the following properties:
245+
246+
* `result`a string that is either `Success`, `Failure`, or `UserCancelled`
247+
* `Success`returned when all the steps have returned true
248+
* `Failure`returned when one step has failed, causing the dialog to close
249+
* `UserCancelled`returned when the user closes the dialog themselves and interrupts the process
250+
* `failedStep` (optional) – an object of type `FailedProgressStepResult` which describes the actual step that has failed
251+
252+
The `FailedProgressStepResult` object contains the following properties:
253+
254+
* `stepTitle`the title of the step that has failed, causing the whole process to fail
255+
* `error`a string which describes the error or exception that has occurred during the step execution
256+
257+
In the example below, you create a menu to show the modal progress dialog, and run three steps. This is done inside the `loaded` event in the main entry point (`src/main/index.ts`).
258+
259+
```typescript
260+
import { ComponentContext, IComponent, ProgressDialogStep, getStudioProApi } from "@mendix/extensions-api";
261+
262+
export const component: IComponent = {
263+
async loaded(componentContext: ComponentContext) {
264+
const studioPro = getStudioProApi(componentContext);
265+
266+
const step1: ProgressDialogStep = {
267+
title: "Step 1",
268+
description: "Executing Step 1",
269+
action: async () => {
270+
// perform action
271+
return true;
272+
}
273+
};
274+
275+
const step2: ProgressDialogStep = {
276+
title: "Step 2",
277+
description: "Executing Step 2",
278+
action: async () => {
279+
// perform action
280+
return true;
281+
}
282+
};
283+
284+
const step3: ProgressDialogStep = {
285+
title: "Step 3",
286+
description: "Executing Step 3",
287+
action: async () => {
288+
// perform action
289+
return true;
290+
}
291+
};
292+
293+
// menu to call `showProgressDialog` method
294+
await studioPro.ui.extensionsMenu.add({
295+
caption: "Sample Progress Dialog",
296+
menuId: `myextension.start-progress-menu`,
297+
action: async () => {
298+
const steps = [step1, step2, step3];
299+
const progressDialogResult = await studioPro.ui.dialogs.showProgressDialog("Sample Progress Dialog", steps);
300+
301+
switch (progressDialogResult.result) {
302+
case "Success":
303+
await studioPro.ui.messageBoxes.show("info", "Process completed successfully");
304+
break;
305+
306+
case "UserCancelled":
307+
await studioPro.ui.messageBoxes.show("info", "Process was cancelled by the user");
308+
break;
309+
310+
case "Failure": {
311+
const errorMessage = `Step '${progressDialogResult.failedStep?.stepTitle}' has failed'`;
312+
const errorDetails = progressDialogResult.failedStep?.error ?? "";
313+
314+
await studioPro.ui.messageBoxes.show("error", errorMessage, errorDetails);
315+
break;
316+
}
317+
}
318+
}
319+
});
320+
}
321+
};
322+
```
323+
324+
It is recommended to always wrap your step action body in a `try/catch` block so you can be in control of the error that is returned to the user:
325+
326+
```typescript
327+
const step: ProgressDialogStep = {
328+
title: "Step X",
329+
description: "Executing Step X",
330+
action: async () => {
331+
try {
332+
// perform action
333+
return true;
334+
} catch (error: Error | unknown) {
335+
return error instanceof Error ? error.message : "An error occurred while performing Step X";
336+
}
337+
}
338+
};
339+
```
340+
341+
When running, the progress dialog will look like this:
342+
{{< figure src="/attachments/apidocs-mxsdk/apidocs/extensibility-api/web/dialogs/sample-progress-dialog.png" width="300" >}}
343+
230344
## Extensibility Feedback
231345

232346
If you would like to provide additional feedback, you can complete a small [survey](https://survey.alchemer.eu/s3/90801191/Extensibility-Feedback).

content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/extensibility-api/web/web-extensions-howtos/menu-api.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ A menu has the following properties:
2828
| `hasSeparatorBefore` <br> (default: `false`) | Adds a visual separator before the item |
2929
| `hasSeparatorAfter` <br> (default: `false`) | Adds a visual separator after the item |
3030
| `enabled` <br> (default: `true`) | Indicates that the menu item notifies the listener when clicked |
31+
| `commandId` (optional) | The id of the previously registered command, which executes when the menu is clicked |
32+
| `action` (optional) | The action that executes when the menu is clicked |
3133

3234
{{< figure src="/attachments/apidocs-mxsdk/apidocs/extensibility-api/web/menus/grouped_menus.png" width="300" >}}
3335

@@ -205,6 +207,37 @@ Instead of listening to the `menuItemActivated` event, it is possible to registe
205207

206208
For more information on how to register commands, see the [Commands API](/apidocs-mxsdk/apidocs/web-extensibility-api-11/command-api/).
207209

210+
## Setting the Action Property on the Menu
211+
212+
You can also set the `action` property on the menu directly.
213+
214+
```typescript
215+
import { IComponent, Menu, getStudioProApi } from "@mendix/extensions-api";
216+
217+
export const component: IComponent = {
218+
async loaded(componentContext) {
219+
const studioPro = getStudioProApi(componentContext);
220+
const menuApi = studioPro.ui.extensionsMenu;
221+
222+
const menuId = "my-menu-unique-id";
223+
const caption = "Menu with Action";
224+
225+
const menu: Menu = {
226+
caption: caption,
227+
menuId: menuId,
228+
action: async () => {
229+
await menuApi.update(menuId, {
230+
caption: `${caption} (Disabled)`,
231+
enabled: false
232+
});
233+
}
234+
};
235+
236+
await menuApi.add(menu);
237+
}
238+
}
239+
```
240+
208241
## Extensibility Feedback
209242

210243
If you would like to provide additional feedback, you can complete a small [survey](https://survey.alchemer.eu/s3/90801191/Extensibility-Feedback).
32.8 KB
Loading

0 commit comments

Comments
 (0)