This is an automated email from the ASF dual-hosted git repository.
tiagobento pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git
The following commit(s) were added to refs/heads/main by this push:
new c12f4bebbb1 NO-ISSUE: Actions in the ProcessDetails page don't provide
visual feedback (#2991)
c12f4bebbb1 is described below
commit c12f4bebbb1d2338441e0b278527eec624e918de
Author: Thiago Lugli <[email protected]>
AuthorDate: Wed Mar 12 16:42:34 2025 -0300
NO-ISSUE: Actions in the ProcessDetails page don't provide visual feedback
(#2991)
---
.../components/ProcessDetails/ProcessDetails.tsx | 255 +++++++++++----------
.../ProcessVariables/ProcessVariables.tsx | 25 +-
2 files changed, 148 insertions(+), 132 deletions(-)
diff --git
a/packages/runtime-tools-process-enveloped-components/src/processDetails/envelope/components/ProcessDetails/ProcessDetails.tsx
b/packages/runtime-tools-process-enveloped-components/src/processDetails/envelope/components/ProcessDetails/ProcessDetails.tsx
index 0de3359300c..13d5c30a371 100644
---
a/packages/runtime-tools-process-enveloped-components/src/processDetails/envelope/components/ProcessDetails/ProcessDetails.tsx
+++
b/packages/runtime-tools-process-enveloped-components/src/processDetails/envelope/components/ProcessDetails/ProcessDetails.tsx
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import React, { ReactElement, useCallback, useEffect, useState } from "react";
+import React, { ReactElement, useCallback, useEffect, useMemo, useState } from
"react";
import { Flex, FlexItem } from "@patternfly/react-core/dist/js/layouts/Flex";
import { Grid, GridItem } from "@patternfly/react-core/dist/js/layouts/Grid";
import { Split, SplitItem } from
"@patternfly/react-core/dist/js/layouts/Split";
@@ -84,7 +84,7 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
const [displayLabel, setDisplayLabel] = useState<boolean>(false);
const [displaySuccess, setDisplaySuccess] = useState<boolean>(false);
const [errorModalOpen, setErrorModalOpen] = useState<boolean>(false);
- const [confirmationModal, setConfirmationModal] = useState<boolean>(false);
+ const [isConfirmationModalOpen, setIsConfirmationModalOpen] =
useState<boolean>(false);
const [variableError, setVariableError] = useState("");
const [svg, setSvg] = useState<JSX.Element>();
const [svgError, setSvgError] = useState<string>("");
@@ -95,7 +95,13 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
const [infoModalTitle, setInfoModalTitle] = useState<string>("");
const [titleType, setTitleType] = useState<string>("");
const [infoModalContent, setInfoModalContent] = useState<string>("");
- const handleReload = async (): Promise<void> => {
+
+ const loadJobs = useCallback(async () => {
+ const jobsResponse: Job[] = await driver.jobsQuery(processDetails.id);
+ jobsResponse && setJobs(jobsResponse);
+ }, [processDetails.id, driver]);
+
+ const handleReload = useCallback(async () => {
setIsLoading(true);
try {
const processResponse: ProcessInstance = await
driver.processDetailsQuery(processDetails.id);
@@ -106,22 +112,11 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
setError(errorString);
setIsLoading(false);
}
- };
+ }, [driver, loadJobs, processDetails.id]);
- const loadJobs = useCallback(async () => {
- const jobsResponse: Job[] = await driver.jobsQuery(processDetails.id);
- jobsResponse && setJobs(jobsResponse);
- }, [processDetails.id, driver]);
-
- const handleSvgErrorModal = (): void => {
- setSvgErrorModalOpen(!svgErrorModalOpen);
- };
-
- const errorModalAction: JSX.Element[] = [
- <Button data-testid="svg-error-modal" key="confirm-selection"
variant="primary" onClick={handleSvgErrorModal}>
- OK
- </Button>,
- ];
+ const handleSvgErrorModal = useCallback(() => {
+ setSvgErrorModalOpen((currentSvgErrorModalOpen) =>
!currentSvgErrorModalOpen);
+ }, []);
useEffect(() => {
const handleSvgApi = async (): Promise<void> => {
@@ -140,7 +135,6 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
setUpdateJson(data.variables);
}
};
- /* istanbul ignore else*/
if (isEnvelopeConnectedToChannel) {
handleSvgApi();
getVariableJSON();
@@ -160,16 +154,14 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
}, [variableError]);
useEffect(() => {
- /* istanbul ignore else*/
if (isEnvelopeConnectedToChannel) {
setData(processDetails);
loadJobs();
}
}, [isEnvelopeConnectedToChannel, loadJobs, processDetails]);
- /* istanbul ignore next */
- const handleSave = (): void => {
- driver
+ const handleSave = useCallback(async () => {
+ return driver
.handleProcessVariableUpdate(data, updateJson)
.then((updatedJson: Record<string, unknown>) => {
setUpdateJson(updatedJson);
@@ -179,13 +171,12 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
setDisplaySuccess(false);
}, 2000);
})
- .catch((errorMessage: string) => {
- setVariableError(errorMessage);
+ .catch((errorMessage) => {
+ setVariableError(errorMessage?.message ?? "Failed to save process
instance changes.");
});
- };
+ }, [data, driver, updateJson]);
- const updateVariablesButton = (): ReactElement => {
- /* istanbul ignore else*/
+ const updateVariablesButton = useMemo(() => {
if (data.serviceUrl !== null) {
return (
<Button
@@ -201,18 +192,18 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
);
}
return <></>;
- };
+ }, [data.serviceUrl, displayLabel, handleSave]);
- const handleRefresh = (): void => {
+ const handleRefresh = useCallback(() => {
if (displayLabel) {
- setConfirmationModal(true);
+ setIsConfirmationModalOpen(true);
} else {
handleReload();
}
- };
+ }, [displayLabel, handleReload]);
- const refreshButton = (): ReactElement => {
- return (
+ const refreshButton = useMemo(
+ () => (
<Button
variant="plain"
onClick={() => {
@@ -224,35 +215,40 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
>
<SyncIcon />
</Button>
- );
- };
-
- const handleInfoModalToggle = (): void => {
- setIsInfoModalOpen(!isInfoModalOpen);
- };
+ ),
+ [handleRefresh]
+ );
- const onAbortClick = async (processInstance: ProcessInstance): Promise<void>
=> {
- try {
- await driver.handleProcessAbort(processInstance);
- setTitleType(TitleType.SUCCESS);
- setInfoModalTitle("Abort operation");
- setInfoModalContent(
- `The ${singularProcessLabel.toLowerCase()}
${processInstance.processName} was successfully aborted.`
- );
- } catch (abortError) {
- setTitleType(TitleType.FAILURE);
- setInfoModalTitle("Abort operation");
- setInfoModalContent(
- `Failed to abort ${singularProcessLabel.toLowerCase()}
${processInstance.processName}. Message: ${
- abortError.message
- }`
- );
- } finally {
- handleInfoModalToggle();
- }
- };
+ const handleInfoModalToggle = useCallback(() => {
+ setIsInfoModalOpen((currentValue) => !currentValue);
+ }, []);
+
+ const onAbortClick = useCallback(
+ async (processInstance: ProcessInstance): Promise<void> => {
+ try {
+ await driver.handleProcessAbort(processInstance);
+ setTitleType(TitleType.SUCCESS);
+ setInfoModalTitle("Abort operation");
+ setInfoModalContent(
+ `The ${singularProcessLabel.toLowerCase()}
${processInstance.processName} was successfully aborted.`
+ );
+ } catch (abortError) {
+ setTitleType(TitleType.FAILURE);
+ setInfoModalTitle("Abort operation");
+ setInfoModalContent(
+ `Failed to abort ${singularProcessLabel.toLowerCase()}
${processInstance.processName}. Message: ${
+ abortError.message
+ }`
+ );
+ } finally {
+ setIsInfoModalOpen(true);
+ handleReload();
+ }
+ },
+ [driver, singularProcessLabel, handleReload]
+ );
- const abortButton = (): JSX.Element => {
+ const abortButton = useMemo(() => {
if (
(data.state === ProcessInstanceState.Active ||
data.state === ProcessInstanceState.Error ||
@@ -272,10 +268,10 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
</Button>
);
}
- };
+ }, [data, onAbortClick]);
- const renderProcessDiagram = (): JSX.Element => {
- return (
+ const processDiagramBlock = useMemo(
+ () => (
<Flex>
<FlexItem>
{svg && svg.props.src && (
@@ -286,11 +282,12 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
)}
</FlexItem>
</Flex>
- );
- };
+ ),
+ [diagramPreviewSize?.height, diagramPreviewSize?.width, svg]
+ );
- const renderProcessTimeline = (): JSX.Element => {
- return (
+ const processTimelineBlock = useMemo(
+ () => (
<FlexItem>
<ProcessDetailsTimelinePanel
data={data}
@@ -299,11 +296,12 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
omittedProcessTimelineEvents={omittedProcessTimelineEvents}
/>
</FlexItem>
- );
- };
+ ),
+ [data, driver, jobs, omittedProcessTimelineEvents]
+ );
- const renderProcessDetails = (): JSX.Element => {
- return (
+ const processDetailsBlock = useMemo(
+ () => (
<Flex direction={{ default: "column" }} flex={{ default: "flex_1" }}>
<FlexItem>
<ProcessDetailsPanel processInstance={data} driver={driver} />
@@ -314,11 +312,12 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
</FlexItem>
)}
</Flex>
- );
- };
+ ),
+ [data, driver]
+ );
- const renderProcessVariables = (): JSX.Element => {
- return (
+ const processVariablesBlock = useMemo(
+ () => (
<Flex direction={{ default: "column" }} flex={{ default: "flex_1" }}>
{updateJson && Object.keys(updateJson).length > 0 && (
<FlexItem>
@@ -333,45 +332,45 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
</FlexItem>
)}
</Flex>
- );
- };
+ ),
+ [data, displayLabel, displaySuccess, updateJson]
+ );
- const renderPanels = (): JSX.Element => {
+ const panels = useMemo(() => {
if (svg && svg.props.src) {
return (
<Flex direction={{ default: "column" }}>
- {renderProcessDiagram()}
+ {processDiagramBlock}
<Flex>
- {renderProcessDetails()}
- {renderProcessVariables()}
+ {processDetailsBlock}
+ {processVariablesBlock}
</Flex>
</Flex>
);
} else {
return (
<>
- {renderProcessDetails()}
- {renderProcessVariables()}
+ {processDetailsBlock}
+ {processVariablesBlock}
</>
);
}
- };
-
- const handleConfirmationModal = (): void => {
- setConfirmationModal(!confirmationModal);
- };
+ }, [processDetailsBlock, processVariablesBlock, processDiagramBlock, svg]);
- const handleConfirm = (): void => {
- window.location.reload();
- handleConfirmationModal();
- };
+ const handleConfirm = useCallback(() => {
+ handleReload();
+ setDisplayLabel(false);
+ setIsConfirmationModalOpen(false);
+ }, [handleReload]);
- const handleCancel = (): void => {
- handleConfirmationModal();
- };
+ const handleCancel = useCallback(() => {
+ setVariableError("");
+ handleReload();
+ setIsConfirmationModalOpen(false);
+ }, [handleReload]);
- const RenderConfirmationModal = (): JSX.Element => {
- return (
+ const confirmationModal = useMemo(
+ () => (
<Modal
title=""
header={
@@ -383,8 +382,8 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
</>
}
variant={ModalVariant.small}
- isOpen={confirmationModal}
- onClose={handleConfirmationModal}
+ isOpen={isConfirmationModalOpen}
+ onClose={handleCancel}
actions={[
<Button key="Ok" variant="primary" id="confirm-button"
onClick={handleConfirm}>
Ok
@@ -398,27 +397,27 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
>
This action discards changes made on process variables.
</Modal>
- );
- };
+ ),
+ [handleCancel, handleConfirm, isConfirmationModalOpen]
+ );
- const handleErrorModal = (): void => {
- setErrorModalOpen(!errorModalOpen);
- };
+ const handleErrorModal = useCallback(() => {
+ setVariableError("");
+ setErrorModalOpen(false);
+ }, []);
- const handleRetry = (): void => {
+ const handleRetry = useCallback(() => {
handleErrorModal();
- setVariableError("");
- // tslint:disable-next-line: no-floating-promises
handleSave();
- };
+ }, [handleSave, handleErrorModal]);
- const handleDiscard = (): void => {
+ const handleDiscard = useCallback(() => {
handleErrorModal();
handleRefresh();
- };
+ }, [handleRefresh, handleErrorModal]);
- const errorModal = (): JSX.Element => {
- return (
+ const errorModal = useMemo(
+ () => (
<Modal
title=""
header={
@@ -445,8 +444,9 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
>
{variableError}
</Modal>
- );
- };
+ ),
+ [errorModalOpen, handleDiscard, handleErrorModal, handleRetry,
variableError]
+ );
return (
<>
@@ -473,9 +473,9 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
<OverflowMenuContent isPersistent>
<OverflowMenuGroup groupType="button" isPersistent>
<>
- {updateVariablesButton()}
- {abortButton()}
- {refreshButton()}
+ {updateVariablesButton}
+ {abortButton}
+ {refreshButton}
</>
</OverflowMenuGroup>
</OverflowMenuContent>
@@ -488,9 +488,9 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
direction={{ default: "column", lg: "row" }}
className="kogito-process-details--details__marginSpaces"
>
- {renderPanels()}
+ {panels}
<Flex direction={{ default: "column" }} flex={{ default:
"flex_1" }}>
- {renderProcessTimeline()}
+ {processTimelineBlock}
<FlexItem>
<JobsPanel jobs={jobs} driver={driver} />
</FlexItem>
@@ -504,8 +504,8 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
</FlexItem>
)}
</Flex>
- {errorModal()}
- {RenderConfirmationModal()}
+ {errorModal}
+ {confirmationModal}
</Flex>
</>
) : (
@@ -517,7 +517,16 @@ const ProcessDetails: React.FC<ProcessDetailsProps> = ({
<ProcessDetailsErrorModal
errorString={svgError}
errorModalOpen={svgErrorModalOpen}
- errorModalAction={errorModalAction}
+ errorModalAction={[
+ <Button
+ data-testid="svg-error-modal"
+ key="confirm-selection"
+ variant="primary"
+ onClick={handleSvgErrorModal}
+ >
+ OK
+ </Button>,
+ ]}
handleErrorModal={handleSvgErrorModal}
label="svg error modal"
title={setTitle("failure", "Process Diagram")}
diff --git
a/packages/runtime-tools-process-enveloped-components/src/processDetails/envelope/components/ProcessVariables/ProcessVariables.tsx
b/packages/runtime-tools-process-enveloped-components/src/processDetails/envelope/components/ProcessVariables/ProcessVariables.tsx
index a8fdca51cd0..fdfa65f8905 100644
---
a/packages/runtime-tools-process-enveloped-components/src/processDetails/envelope/components/ProcessVariables/ProcessVariables.tsx
+++
b/packages/runtime-tools-process-enveloped-components/src/processDetails/envelope/components/ProcessVariables/ProcessVariables.tsx
@@ -20,7 +20,7 @@ import { Card, CardBody, CardHeader } from
"@patternfly/react-core/dist/js/compo
import { Title } from "@patternfly/react-core/dist/js/components/Title";
import { TextContent } from "@patternfly/react-core/dist/js/components/Text";
import { Label } from "@patternfly/react-core/dist/js/components/Label";
-import React from "react";
+import React, { useCallback, useMemo } from "react";
import ReactJson from "@microlink/react-json-view";
import { InfoCircleIcon } from
"@patternfly/react-icons/dist/js/icons/info-circle-icon";
import "../styles.css";
@@ -46,14 +46,21 @@ const ProcessVariables: React.FC<ProcessVariablesProps &
OUIAProps> = ({
updateJson,
processInstance,
}) => {
- const handleVariablesChange = (e) => {
- setUpdateJson({ ...updateJson, ...e.updated_src });
- setDisplayLabel(true);
- };
- const checkProcessStatus =
- processInstance.state === ProcessInstanceState.Completed ||
processInstance.state === ProcessInstanceState.Aborted
- ? false
- : handleVariablesChange;
+ const handleVariablesChange = useCallback(
+ (e) => {
+ setUpdateJson((currentUpdateJson) => ({ ...currentUpdateJson,
...e.updated_src }));
+ setDisplayLabel(true);
+ },
+ [setDisplayLabel, setUpdateJson]
+ );
+
+ const checkProcessStatus = useMemo(
+ () =>
+ processInstance.state === ProcessInstanceState.Completed ||
processInstance.state === ProcessInstanceState.Aborted
+ ? false
+ : handleVariablesChange,
+ [handleVariablesChange, processInstance.state]
+ );
return (
<Card {...componentOuiaProps(ouiaId, "process-variables", ouiaSafe)}>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]