Skip to content

Commit 3b3832e

Browse files
committed
UI and dynamic input form optimalizations
1 parent 7e1c661 commit 3b3832e

21 files changed

+324
-249
lines changed

README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ My colleague [MrAutomate33](https://github.com/mrautomate33) and I have been lon
1717
<br />
1818
This SPFx (SharePoint Framework) command set expands on the existing 'trigger a flow' menu button in SharePoint, and allows you to configure one or more HTTP request triggered flows and serve the user with a choice on which flow to execute when selecting one or more items by injecting a menu lint and context button upon loading the page. A sppkg for both SharePoint document libaries and custom lists are available.
1919

20-
**[<img src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fwww.iconsdb.com%2Ficons%2Fpreview%2Froyal-blue%2Fdata-transfer-download-xxl.png&f=1&nofb=1" alt="Download .sppkg file" style="width:15px;margin-right:10px;"/><u>Download the .sppkg file for custom lists here!</u>](https://github.com/cupo365/enhanced-power-automate-command-set/releases/tag/v1.4.0)**
20+
**[<img src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fwww.iconsdb.com%2Ficons%2Fpreview%2Froyal-blue%2Fdata-transfer-download-xxl.png&f=1&nofb=1" alt="Download .sppkg file" style="width:15px;margin-right:10px;"/><u>Download the .sppkg file for custom lists here!</u>](https://github.com/cupo365/enhanced-power-automate-command-set/releases/tag/v1.5.0)**
2121

22-
**[<img src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fwww.iconsdb.com%2Ficons%2Fpreview%2Froyal-blue%2Fdata-transfer-download-xxl.png&f=1&nofb=1" alt="Download .sppkg file" style="width:15px;margin-right:10px;"/><u>Download the .sppkg file for document libraries here!</u>](https://github.com/cupo365/enhanced-power-automate-command-set/releases/tag/v1.4.0)**
22+
**[<img src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fwww.iconsdb.com%2Ficons%2Fpreview%2Froyal-blue%2Fdata-transfer-download-xxl.png&f=1&nofb=1" alt="Download .sppkg file" style="width:15px;margin-right:10px;"/><u>Download the .sppkg file for document libraries here!</u>](https://github.com/cupo365/enhanced-power-automate-command-set/releases/tag/v1.5.0)**
2323

2424
## Compatibility
2525

@@ -33,7 +33,7 @@ This SPFx (SharePoint Framework) command set expands on the existing 'trigger a
3333

3434
![Compatible with SharePoint document libraries](https://img.shields.io/badge/Document%20libraries-Compatible-green.svg) ![Compatible with SharePoint custom lists](https://img.shields.io/badge/Custom%20lists-Compatible-green.svg)
3535

36-
![Compatible with Microsoft Edge](https://img.shields.io/badge/MS%20Edge-Compatible-green.svg) ![Compatible with Google Chrome](https://img.shields.io/badge/Google%20Chrome-Compatible-green.svg) ![Compatible with Mozilla Firefox](https://img.shields.io/badge/Mozilla%20Firefox-Compatible-green.svg)
36+
![Compatible with Microsoft Edge](https://img.shields.io/badge/MS%20Edge-Compatible-green.svg) ![Compatible with Google Chrome](https://img.shields.io/badge/Google%20Chrome-Compatible-green.svg) ![Compatible with Mozilla Firefox](https://img.shields.io/badge/Mozilla%20Firefox-Compatible-green.svg) ![Responsive UI](https://img.shields.io/badge/Mobile-Compatible-green.svg)
3737

3838
## Applies to
3939

@@ -73,6 +73,7 @@ This SPFx (SharePoint Framework) command set expands on the existing 'trigger a
7373
| [1.2.0](https://github.com/cupo365/enhanced-power-automate-command-set/releases/tag/v1.2.1) | August 1, 2022 | Customizable list and folder whitelisting and content type and file extension blacklisting |
7474
| [1.3.0](https://github.com/cupo365/enhanced-power-automate-command-set/releases/tag/v1.3.0) | October 2, 2022 | Dynamic user input form |
7575
| [1.4.0](https://github.com/cupo365/enhanced-power-automate-command-set/releases/tag/v1.4.0) | October 4, 2022 | Support lookup as user input |
76+
| [1.5.0](https://github.com/cupo365/enhanced-power-automate-command-set/releases/tag/v1.5.0) | October 5, 2022 | UI and dynamic input form optimalizations |
7677

7778
## Supported languages
7879
- English
@@ -110,7 +111,11 @@ If the command set is installed on the site and the user opens a document librar
110111

111112
Upon pressing the menu button, a dialog will appear, displaying choices for every configured flow in the provisioned configuration list. The user will be able to choose which flow they want to trigger (see example below).
112113
![Select flow dialog example](resources/select-flow-dialog.png "Select flow dialog example")
113-
> Note that the web part and its components is SharePoint theme-aware.
114+
115+
If requested user input has been configured for the selected flow, the webpart will dynamically build the input fields and display them to the user, requesting their input. Based on the presence of required fields, the button to trigger the flow will be disabled until all required field maintain a valid value (see example below). ![Dynamic flow input form example](resources/dynamic-flow-input-form.png "Dynamic flow input form example")
116+
117+
If no requested user input has been configured, the webpart will simply show the button to trigger the flow with (see example below). ![No user input configured](resources/no-user-input-configured.png "No user input configured example")
118+
> Note that the web part and its components are SharePoint theme-aware.
114119
115120
If the configured flow uses a POST method, the command set will pass a request body JSON-object to the flow with the following properties:
116121
| Name | Type | Description | Example |
@@ -238,6 +243,7 @@ This request body translates to the following Power Automate body schema:
238243
}
239244
}
240245
````
246+
> Note that inserting the user input schema into the HTTP trigger body is not required. The input field values will still be available to you in your flow, but just not as a dynamic content property
241247
> Note that flows configured with a GET method <u>will not</u> receive a request body, since that is not supported within the Power Automate response (HTTP) trigger.
242248
243249
<br />
@@ -276,6 +282,6 @@ If a message is present, it will be displayed in the dialog that is shown to the
276282

277283
## Download the web part packages
278284

279-
**[<img src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fwww.iconsdb.com%2Ficons%2Fpreview%2Froyal-blue%2Fdata-transfer-download-xxl.png&f=1&nofb=1" alt="Download .sppkg file" style="width:15px;margin-right:10px;"/><u>Download the .sppkg file for custom lists here!</u>](https://github.com/cupo365/enhanced-power-automate-command-set/releases/tag/v1.4.0)**
285+
**[<img src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fwww.iconsdb.com%2Ficons%2Fpreview%2Froyal-blue%2Fdata-transfer-download-xxl.png&f=1&nofb=1" alt="Download .sppkg file" style="width:15px;margin-right:10px;"/><u>Download the .sppkg file for custom lists here!</u>](https://github.com/cupo365/enhanced-power-automate-command-set/releases/tag/v1.5.0)**
280286

281-
**[<img src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fwww.iconsdb.com%2Ficons%2Fpreview%2Froyal-blue%2Fdata-transfer-download-xxl.png&f=1&nofb=1" alt="Download .sppkg file" style="width:15px;margin-right:10px;"/><u>Download the .sppkg file for document libraries here!</u>](https://github.com/cupo365/enhanced-power-automate-command-set/releases/tag/v1.4.0)**
287+
**[<img src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fwww.iconsdb.com%2Ficons%2Fpreview%2Froyal-blue%2Fdata-transfer-download-xxl.png&f=1&nofb=1" alt="Download .sppkg file" style="width:15px;margin-right:10px;"/><u>Download the .sppkg file for document libraries here!</u>](https://github.com/cupo365/enhanced-power-automate-command-set/releases/tag/v1.5.0)**

SPFx/config/package-solution.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"solution": {
44
"name": "doc-enhanced-power-automate-trigger-client-side-solution",
55
"id": "5DA1DC8B-F9A4-43D4-9A0B-C2E89E2D5FBE",
6-
"version": "1.4.0.0",
6+
"version": "1.5.0.0",
77
"includeClientSideAssets": true,
88
"skipFeatureDeployment": false,
99
"isDomainIsolated": false,

SPFx/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "enhanced-power-automate-trigger",
3-
"version": "1.4.0",
3+
"version": "1.5.0",
44
"private": true,
55
"main": "lib/index.js",
66
"description": "Trigger a Power Automate flow from SharePoint while selecting one or more items.",
Binary file not shown.
Binary file not shown.

SPFx/src/extensions/enhancedPowerAutomateTrigger/components/EnhancedPowerAutomateTriggerDialog.tsx

Lines changed: 94 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/* eslint-disable @microsoft/spfx/no-async-await */
2-
import { Dialog, DialogFooter, DialogType, IDialogContentProps, IModalProps, PrimaryButton, Spinner, SpinnerSize, Stack } from "@fluentui/react";
2+
import { Dialog, DialogFooter, DialogType, Dropdown, IDialogContentProps, IDropdownOption, IModalProps, PrimaryButton, Spinner, SpinnerSize, Stack } from "@fluentui/react";
33
import { ListViewCommandSetContext, RowAccessor } from "@microsoft/sp-listview-extensibility";
44
import * as strings from "EnhancedPowerAutomateTriggerCommandSetStrings";
55
import * as React from "react";
6-
import { FlowButton, UserInputForm } from ".";
6+
import { FlowInputForm } from ".";
77
import { stringIsNullOrEmpty, useToggle, validateVisibility } from "../../../library";
88
import { IFlowResponse, ITriggerConfig } from "../../../models";
99
import { IFlowService } from "../../../services";
@@ -24,50 +24,47 @@ export const EnhancedPowerAutomateTriggerDialog: React.FC<IEnhancedPowerAutomate
2424
const [isClosedState, toggleIsClosedState] = useToggle(false);
2525
const [flowResponse, setFlowResponse] = React.useState<IFlowResponse>(undefined);
2626
const [isWaitingForResponse, toggleIsWaitingForResponse] = useToggle(false);
27-
const [showUserInput, toggleShowUserInput] = useToggle(false);
27+
const [showFlowInputForm, toggleShowFlowInputForm] = useToggle(false);
2828
const [selectedFlowTrigger, setSelectedFlowTrigger] = React.useState<ITriggerConfig>(undefined);
29+
const [reValidateInputForm, toggleReValidateInputForm] = useToggle(false);
2930

3031
const dialogContentProps: IDialogContentProps = {
3132
type: DialogType.normal,
3233
showCloseButton: !isWaitingForResponse,
3334
title: isWaitingForResponse
3435
? strings.WaitingForFlowResponseDialogHeader
35-
: showUserInput
36-
? strings.UserInputDialogHeader
37-
: flowResponse === undefined
38-
? strings.SelectFlowDialogHeader
39-
: flowResponse && flowResponse?.statusCode?.toString().indexOf("20") > -1
40-
? strings.SuccessDialogHeader
41-
: strings.FailedDialogHeader,
36+
: flowResponse === undefined
37+
? strings.DefaultDialogHeader
38+
: flowResponse && flowResponse?.statusCode?.toString().indexOf("20") > -1
39+
? strings.SuccessDialogHeader
40+
: strings.FailedDialogHeader,
4241
subText: isWaitingForResponse
4342
? strings.WaitingForFlowResponseDialogSubText
44-
: showUserInput
45-
? strings.UserInputDialogSubText
46-
: !flowResponse
47-
? strings.SelectFlowDialogSubText
48-
: flowResponse && flowResponse?.statusCode === 202
49-
? strings.InvokedDialogSubText + " " + strings.CloseDialogUserInstruction
50-
: flowResponse && flowResponse?.statusCode?.toString().indexOf("20") > -1
51-
? !stringIsNullOrEmpty(flowResponse?.message)
52-
? strings.SuccessDialogSubTextWithMessage.replace(
53-
"$message",
54-
flowResponse?.message
55-
) +
56-
" " +
57-
strings.CloseDialogUserInstruction
58-
: strings.SuccessDialogSubTextWithoutMessage +
59-
" " +
60-
strings.CloseDialogUserInstruction
61-
: !stringIsNullOrEmpty(flowResponse?.message)
62-
? strings.FailedDialogSubTextWithMessage.replace(
63-
"$message",
64-
flowResponse?.message
65-
) +
66-
" " +
67-
strings.CloseDialogUserInstruction
68-
: strings.FailedDialogSubTextWithoutMessage +
69-
" " +
70-
strings.CloseDialogUserInstruction,
43+
: !flowResponse
44+
? strings.DefaultDialogSubtext
45+
: flowResponse && flowResponse?.statusCode === 202
46+
? strings.InvokedDialogSubText + " " + strings.CloseDialogUserInstruction
47+
: flowResponse && flowResponse?.statusCode?.toString().indexOf("20") > -1
48+
? !stringIsNullOrEmpty(flowResponse?.message)
49+
? strings.SuccessDialogSubTextWithMessage.replace(
50+
"$message",
51+
flowResponse?.message
52+
) +
53+
" " +
54+
strings.CloseDialogUserInstruction
55+
: strings.SuccessDialogSubTextWithoutMessage +
56+
" " +
57+
strings.CloseDialogUserInstruction
58+
: !stringIsNullOrEmpty(flowResponse?.message)
59+
? strings.FailedDialogSubTextWithMessage.replace(
60+
"$message",
61+
flowResponse?.message
62+
) +
63+
" " +
64+
strings.CloseDialogUserInstruction
65+
: strings.FailedDialogSubTextWithoutMessage +
66+
" " +
67+
strings.CloseDialogUserInstruction,
7168
};
7269

7370
const modalProps: IModalProps = {
@@ -76,22 +73,6 @@ export const EnhancedPowerAutomateTriggerDialog: React.FC<IEnhancedPowerAutomate
7673
dragOptions: null,
7774
};
7875

79-
/**
80-
* Invokes the flow of the selected trigger button and handles its response
81-
*
82-
* @param flowConfig The selected flow to invoke
83-
* @param userInput Dictionary type mapping of the user input
84-
*/
85-
const onTriggerInvoke = async (flowConfig: ITriggerConfig, userInput: Map<string, string>): Promise<void> => {
86-
if (showUserInput) toggleShowUserInput();
87-
toggleIsWaitingForResponse();
88-
await flowService.invokeFlow(context, flowConfig, selectedItems, userInput)
89-
.then((response: IFlowResponse): void => {
90-
setFlowResponse(response);
91-
toggleIsWaitingForResponse();
92-
});
93-
};
94-
9576
/**
9677
* Closes the dialog and resets the state
9778
*/
@@ -101,7 +82,8 @@ export const EnhancedPowerAutomateTriggerDialog: React.FC<IEnhancedPowerAutomate
10182
// Prevent showing the user the state change while still in dialog closing transition
10283
setFlowResponse(undefined);
10384
setSelectedFlowTrigger(undefined);
104-
if (showUserInput) toggleShowUserInput();
85+
if (showFlowInputForm) toggleShowFlowInputForm();
86+
if (isWaitingForResponse) toggleIsWaitingForResponse();
10587
}, 500);
10688
};
10789

@@ -118,6 +100,20 @@ export const EnhancedPowerAutomateTriggerDialog: React.FC<IEnhancedPowerAutomate
118100
);
119101
};
120102

103+
/**
104+
* Creates dropdown options from the trigger configurations
105+
*/
106+
const createDropdownWorkflowOptions = (): IDropdownOption[] => {
107+
return triggerConfigs.map((triggerConfig: ITriggerConfig): IDropdownOption => {
108+
if (validateVisibility(triggerConfig.fileExtensionBlacklist, triggerConfig.contentTypeBlacklist, triggerConfig.listWhitelist,
109+
triggerConfig.folderWhitelist, triggerConfig.selectionLimit, selectedItems, currentListId)) {
110+
return {
111+
key: triggerConfig.title,
112+
text: triggerConfig.title,
113+
};
114+
}
115+
}).filter(option => option !== undefined);
116+
}
121117

122118
/**
123119
* Renders the children of the dialog
@@ -126,48 +122,53 @@ export const EnhancedPowerAutomateTriggerDialog: React.FC<IEnhancedPowerAutomate
126122
const renderDialogChildren = () => {
127123
return (
128124
<Stack>
129-
<Stack tokens={{ childrenGap: 15 }}>
130-
{
131-
flowResponse === undefined && !showUserInput && !isWaitingForResponse &&
132-
triggerConfigs.map((triggerConfig: ITriggerConfig) => {
133-
if (validateVisibility(triggerConfig.fileExtensionBlacklist, triggerConfig.contentTypeBlacklist, triggerConfig.listWhitelist,
134-
triggerConfig.folderWhitelist, triggerConfig.selectionLimit, selectedItems, currentListId)) {
135-
return (
136-
<FlowButton
137-
triggerConfig={triggerConfig}
138-
onTriggerInvoke={onTriggerInvoke}
139-
toggleShowUserInput={toggleShowUserInput}
140-
setSelectedFlowTrigger={setSelectedFlowTrigger}
141-
/>
142-
)
143-
}
144-
})
145-
}
146-
147-
{
148-
isWaitingForResponse &&
149-
<Spinner
150-
label={strings.WaitingForFlowResponseSpinnerText}
151-
size={SpinnerSize.large}
152-
/>
153-
}
125+
{
126+
flowResponse === undefined && !isWaitingForResponse && (
127+
<Stack tokens={{ childrenGap: 5 }}>
128+
<Dropdown
129+
label={strings.SelectFlowDropdownLabel}
130+
placeholder={strings.SelectFlowDropdownPlaceholder}
131+
options={createDropdownWorkflowOptions()}
132+
required={true}
133+
onChange={(event, option, index) => {
134+
const selectedFlowTriggerOption: ITriggerConfig = triggerConfigs.find((triggerConfig: ITriggerConfig) => triggerConfig.title === option.key.toString());
135+
setSelectedFlowTrigger(selectedFlowTriggerOption);
154136

155-
{
156-
showUserInput &&
157-
<UserInputForm
158-
selectedFlowTrigger={selectedFlowTrigger}
159-
onTriggerInvoke={onTriggerInvoke}
160-
context={context}
161-
/>
162-
}
137+
if (selectedFlowTriggerOption && !showFlowInputForm) {
138+
toggleShowFlowInputForm();
139+
} else if (!selectedFlowTriggerOption && showFlowInputForm) {
140+
toggleShowFlowInputForm();
141+
}
142+
}}
143+
/>
144+
{
145+
selectedFlowTrigger &&
146+
<FlowInputForm
147+
selectedFlowTrigger={selectedFlowTrigger}
148+
flowService={flowService}
149+
selectedItems={selectedItems}
150+
setFlowResponse={setFlowResponse}
151+
toggleIsWaitingForResponse={toggleIsWaitingForResponse}
152+
context={context}
153+
reValidateInputForm={reValidateInputForm}
154+
toggleReValidateInputForm={toggleReValidateInputForm}
155+
/>
156+
}
157+
</Stack>
158+
)
159+
}
163160

164-
</Stack>
161+
{
162+
isWaitingForResponse &&
163+
<Spinner
164+
label={strings.WaitingForFlowResponseSpinnerText}
165+
size={SpinnerSize.large}
166+
/>
167+
}
165168

166169
{
167-
flowResponse !== undefined && !showUserInput && !isWaitingForResponse &&
168-
<Stack className="ms-Grid-row">
169-
<DialogFooter children={renderDialogFooterChildren()} />
170-
</Stack>
170+
flowResponse !== undefined && !isWaitingForResponse &&
171+
<DialogFooter children={renderDialogFooterChildren()} />
171172
}
172173
</Stack>
173174
);
@@ -178,7 +179,7 @@ export const EnhancedPowerAutomateTriggerDialog: React.FC<IEnhancedPowerAutomate
178179
hidden={isClosedState}
179180
onDismiss={() => onCloseDialog()}
180181
maxWidth={800}
181-
minWidth={300}
182+
minWidth={360}
182183
dialogContentProps={dialogContentProps}
183184
modalProps={modalProps}
184185
children={renderDialogChildren()}

SPFx/src/extensions/enhancedPowerAutomateTrigger/components/FlowButton.tsx

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)