Skip to content

Commit 129bbef

Browse files
committed
separate actions in the frontend
1 parent 7617c49 commit 129bbef

File tree

15 files changed

+187
-40
lines changed

15 files changed

+187
-40
lines changed
Loading

designer/client/src/components/Process/ProcessStateUtils.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
import { ActionName, PredefinedActionName, ProcessStateType, Scenario } from "./types";
21
import { descriptionProcessArchived, unknownDescription, unknownTooltip } from "./messages";
2+
import type { ActionName, ProcessStateType, Scenario } from "./types";
3+
import { PredefinedActionName } from "./types";
34

45
export const unknownIcon = "/assets/states/status-unknown.svg";
56
const archivedIcon = "/assets/process/archived.svg";
67

78
class ProcessStateUtils {
9+
public canSeeDeploy = (state: ProcessStateType): boolean => state?.visibleActions.includes(PredefinedActionName.Deploy);
10+
811
public canDeploy = (state: ProcessStateType): boolean => state?.allowedActions.includes(PredefinedActionName.Deploy);
912

13+
public canSeeRedeploy = (state: ProcessStateType): boolean => state?.visibleActions.includes(PredefinedActionName.Redeploy);
14+
15+
public canRedeploy = (state: ProcessStateType): boolean => state?.allowedActions.includes(PredefinedActionName.Redeploy);
16+
1017
public canCancel = (state: ProcessStateType): boolean => state?.allowedActions.includes(PredefinedActionName.Cancel);
1118

1219
public canArchive = (state: ProcessStateType): boolean => state?.allowedActions.includes(PredefinedActionName.Archive);

designer/client/src/components/Process/types.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
/* eslint-disable i18next/no-literal-string */
2-
import { Instant } from "../../types/common";
3-
import { ScenarioGraph, ValidationResult } from "../../types";
4-
import { ProcessingMode } from "../../http/HttpService";
2+
import type { ProcessingMode } from "../../http/HttpService";
3+
import type { ScenarioGraph, ValidationResult } from "../../types";
4+
import type { Instant } from "../../types/common";
55

66
export enum PredefinedActionName {
77
Deploy = "DEPLOY",
8+
Redeploy = "REDEPLOY",
89
Cancel = "CANCEL",
910
Archive = "ARCHIVE",
1011
UnArchive = "UNARCHIVE",

designer/client/src/components/modals/DeployProcessDialog.tsx

+11-7
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
import { css, cx } from "@emotion/css";
2-
import { WindowButtonProps, WindowContentProps } from "@touk/window-manager";
2+
import { FormHelperText, Typography } from "@mui/material";
3+
import type { WindowButtonProps, WindowContentProps } from "@touk/window-manager";
34
import React, { useCallback, useMemo, useState } from "react";
45
import { useTranslation } from "react-i18next";
56
import { useSelector } from "react-redux";
7+
8+
import type { NodesDeploymentData } from "../../http/HttpService";
69
import { getProcessName, getProcessVersionId } from "../../reducers/selectors/graph";
710
import { getFeatureSettings } from "../../reducers/selectors/settings";
8-
import { ProcessName, ProcessVersionId } from "../Process/types";
9-
import { PromptContent, WindowKind } from "../../windowManager";
11+
import type { WindowKind } from "../../windowManager";
12+
import { PromptContent } from "../../windowManager";
13+
import { LoadingButtonTypes } from "../../windowManager/LoadingButton";
1014
import CommentInput from "../comment/CommentInput";
15+
import type { ProcessName, ProcessVersionId } from "../Process/types";
16+
import type { ScenarioActionResult} from "../toolbars/scenarioActions/buttons/types";
17+
import { ScenarioActionResultType } from "../toolbars/scenarioActions/buttons/types";
1118
import ProcessDialogWarnings from "./ProcessDialogWarnings";
12-
import { FormHelperText, Typography } from "@mui/material";
13-
import { LoadingButtonTypes } from "../../windowManager/LoadingButton";
14-
import { ScenarioActionResult, ScenarioActionResultType } from "../toolbars/scenarioActions/buttons/types";
15-
import { NodesDeploymentData } from "../../http/HttpService";
1619

1720
export type ToggleProcessActionModalData = {
1821
action: (
@@ -22,6 +25,7 @@ export type ToggleProcessActionModalData = {
2225
nodeData?: NodesDeploymentData,
2326
) => Promise<ScenarioActionResult>;
2427
displayWarnings?: boolean;
28+
actionName?: string;
2529
};
2630

2731
export function DeployProcessDialog(props: WindowContentProps<WindowKind, ToggleProcessActionModalData>): JSX.Element {

designer/client/src/components/modals/DeployWithParameters/AdvancedParameters.tsx

+9-2
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import HttpService from "../../../http/HttpService";
1111
import type { ActionNodeParameters } from "../../../types/action";
1212
import { Expandable } from "../../common/Expandable";
1313
import { NodeTable } from "../../graph/node-modal/NodeDetailsContent/NodeTable";
14+
import { AdvancedParametersSection } from "./AdvancedParametersSection";
1415
import { GroupedActionParameter } from "./GroupedActionParameter";
1516

1617
interface AdvancedParametersProps {
1718
processName: string;
19+
actionName: string;
1820
setParametersValues: (values: NodesDeploymentData) => void;
1921
parametersValues: NodesDeploymentData;
2022
}
@@ -29,15 +31,20 @@ function initialNodesData(params: ActionNodeParameters[]): NodesDeploymentData {
2931
);
3032
}
3133

32-
export const AdvancedParameters: React.FC<AdvancedParametersProps> = ({ processName, setParametersValues, parametersValues }) => {
34+
export const AdvancedParameters: React.FC<AdvancedParametersProps> = ({
35+
processName,
36+
actionName,
37+
setParametersValues,
38+
parametersValues,
39+
}) => {
3340
const { t } = useTranslation();
3441
const { showBoundary } = useErrorBoundary();
3542
const [expandedState, setExpandedState] = useLocalstorageState("actionParametersExpandedState", {});
3643

3744
const parametersDefinition: ActionNodeParameters[] | undefined = suspend(async () => {
3845
return HttpService.getActionParameters(processName)
3946
.then((response) => {
40-
const definition = response.data.actionNameToParameters["DEPLOY"] || ([] as ActionNodeParameters[]);
47+
const definition = response.data.actionNameToParameters[actionName] || ([] as ActionNodeParameters[]);
4148
const initialValues = initialNodesData(definition);
4249

4350
setParametersValues(initialValues);

designer/client/src/components/modals/DeployWithParameters/DeployWithParametersDialog.tsx

+13-11
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,29 @@
11
import { css, cx } from "@emotion/css";
2-
import { WindowButtonProps, WindowContentProps } from "@touk/window-manager";
2+
import { FormHelperText, Typography } from "@mui/material";
3+
import type { WindowButtonProps, WindowContentProps } from "@touk/window-manager";
34
import React, { Suspense, useCallback, useMemo, useState } from "react";
45
import { useTranslation } from "react-i18next";
56
import { useSelector } from "react-redux";
7+
8+
import type { NodesDeploymentData } from "../../../http/HttpService";
69
import { getProcessName, getProcessVersionId } from "../../../reducers/selectors/graph";
710
import { getFeatureSettings } from "../../../reducers/selectors/settings";
8-
import { PromptContent, WindowKind } from "../../../windowManager";
9-
import CommentInput from "../../comment/CommentInput";
10-
import ProcessDialogWarnings from "../ProcessDialogWarnings";
11-
import { FormHelperText, Typography } from "@mui/material";
11+
import type { WindowKind } from "../../../windowManager";
12+
import { PromptContent } from "../../../windowManager";
1213
import { LoadingButtonTypes } from "../../../windowManager/LoadingButton";
13-
import { ScenarioActionResultType } from "../../toolbars/scenarioActions/buttons/types";
14-
import { NodesDeploymentData } from "../../../http/HttpService";
15-
import { ToggleProcessActionModalData } from "../DeployProcessDialog";
16-
import { useLocalstorageState } from "rooks";
17-
import { AdvancedParameters } from "./AdvancedParameters";
14+
import CommentInput from "../../comment/CommentInput";
1815
import { ErrorBoundary } from "../../common/error-boundary";
1916
import { TextErrorBoundaryFallbackComponent } from "../../common/error-boundary";
2017
import LoaderSpinner from "../../spinner/Spinner";
18+
import { ScenarioActionResultType } from "../../toolbars/scenarioActions/buttons/types";
19+
import type { ToggleProcessActionModalData } from "../DeployProcessDialog";
20+
import ProcessDialogWarnings from "../ProcessDialogWarnings";
21+
import { AdvancedParameters } from "./AdvancedParameters";
2122

2223
export function DeployWithParametersDialog(props: WindowContentProps<WindowKind, ToggleProcessActionModalData>): JSX.Element {
2324
// TODO: get rid of meta
2425
const {
25-
meta: { action, displayWarnings },
26+
meta: { action, displayWarnings, actionName },
2627
} = props.data;
2728
const processName = useSelector(getProcessName);
2829
const processVersionId = useSelector(getProcessVersionId);
@@ -92,6 +93,7 @@ export function DeployWithParametersDialog(props: WindowContentProps<WindowKind,
9293
>
9394
<AdvancedParameters
9495
processName={processName}
96+
actionName={actionName}
9597
setParametersValues={setParametersValues}
9698
parametersValues={parametersValues}
9799
/>

designer/client/src/components/toolbarSettings/buttons/BuiltinButtonTypes.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export enum BuiltinButtonTypes {
22
processSave = "process-save",
33
processDeploy = "process-deploy",
4+
processRedeploy = "process-redeploy",
45
processCancel = "process-cancel",
56
processRunOffSchedule = "process-run-off-schedule",
67
editUndo = "edit-undo",

designer/client/src/components/toolbarSettings/buttons/TOOLBAR_BUTTONS_MAP.ts

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import UnArchiveButton from "../../toolbars/process/buttons/UnArchiveButton";
1818
import CancelDeployButton from "../../toolbars/scenarioActions/buttons/CancelDeployButton";
1919
import DeployButton from "../../toolbars/scenarioActions/buttons/DeployButton";
2020
import PropertiesButton from "../../toolbars/scenarioActions/buttons/PropertiesButton";
21+
import RedeployButton from "../../toolbars/scenarioActions/buttons/RedeployButton";
2122
import RunOffScheduleButton from "../../toolbars/scenarioActions/buttons/RunOffScheduleButton";
2223
import AdhocTestingButton from "../../toolbars/test/buttons/AdhocTestingButton";
2324
import CountsButton from "../../toolbars/test/buttons/CountsButton";
@@ -45,6 +46,7 @@ type ToolbarButtonsMap = {
4546
export const TOOLBAR_BUTTONS_MAP: ToolbarButtonsMap = {
4647
[BuiltinButtonTypes.processSave]: SaveButton,
4748
[BuiltinButtonTypes.processDeploy]: DeployButton,
49+
[BuiltinButtonTypes.processRedeploy]: RedeployButton,
4850
[BuiltinButtonTypes.processCancel]: CancelDeployButton,
4951
[BuiltinButtonTypes.processRunOffSchedule]: RunOffScheduleButton,
5052
[BuiltinButtonTypes.viewZoomIn]: ZoomInButton,

designer/client/src/components/toolbars/scenarioActions/buttons/DeployButton.tsx

+20-16
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
getProcessVersionId,
1212
hasError,
1313
isDeployPossible,
14+
isDeployVisible,
1415
isSaveDisabled,
1516
isValidationResultPresent,
1617
} from "../../../../reducers/selectors/graph";
@@ -25,7 +26,8 @@ import type { ToolbarButtonProps } from "../../types";
2526

2627
export default function DeployButton(props: ToolbarButtonProps) {
2728
const dispatch = useDispatch();
28-
const deployPossible = useSelector(isDeployPossible);
29+
const isVisible = useSelector(isDeployVisible);
30+
const isPossible = useSelector(isDeployPossible);
2931
const saveDisabled = useSelector(isSaveDisabled);
3032
const hasErrors = useSelector(hasError);
3133
const validationResultPresent = useSelector(isValidationResultPresent);
@@ -34,7 +36,7 @@ export default function DeployButton(props: ToolbarButtonProps) {
3436
const capabilities = useSelector(getCapabilities);
3537
const { disabled, type } = props;
3638

37-
const available = validationResultPresent && !disabled && deployPossible && capabilities.deploy;
39+
const available = validationResultPresent && !disabled && isPossible && capabilities.deploy;
3840
const { t } = useTranslation();
3941
const deployToolTip = !capabilities.deploy
4042
? t("panels.actions.deploy.tooltips.forbidden", "Deploy forbidden for current scenario.")
@@ -70,7 +72,7 @@ export default function DeployButton(props: ToolbarButtonProps) {
7072
title: message,
7173
kind: WindowKind.deployWithParameters,
7274
width: ACTION_DIALOG_WIDTH,
73-
meta: { action, displayWarnings: true },
75+
meta: { action, displayWarnings: true, actionName: "DEPLOY" },
7476
});
7577
}
7678
},
@@ -81,22 +83,24 @@ export default function DeployButton(props: ToolbarButtonProps) {
8183
title: message,
8284
kind: WindowKind.deployWithParameters,
8385
width: ACTION_DIALOG_WIDTH,
84-
meta: { action, displayWarnings: true },
86+
meta: { action, displayWarnings: true, actionName: "DEPLOY" },
8587
});
8688
}
8789
});
8890
};
8991

90-
return (
91-
<ToolbarButton
92-
name={t("panels.actions.deploy.button", "deploy")}
93-
disabled={!available}
94-
icon={<Icon />}
95-
title={deployToolTip}
96-
onClick={handleOnClick}
97-
onMouseOver={deployMouseOver}
98-
onMouseOut={deployMouseOut}
99-
type={type}
100-
/>
101-
);
92+
if (isVisible) {
93+
return (
94+
<ToolbarButton
95+
name={t("panels.actions.deploy.button", "deploy")}
96+
disabled={!available}
97+
icon={<Icon />}
98+
title={deployToolTip}
99+
onClick={handleOnClick}
100+
onMouseOver={deployMouseOver}
101+
onMouseOut={deployMouseOut}
102+
type={type}
103+
/>
104+
);
105+
} else return <></>;
102106
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import React from "react";
2+
import { useTranslation } from "react-i18next";
3+
import { useDispatch, useSelector } from "react-redux";
4+
5+
import { disableToolTipsHighlight, enableToolTipsHighlight, loadProcessState } from "../../../../actions/nk";
6+
import Icon from "../../../../assets/img/toolbarButtons/redeploy.svg";
7+
import type { NodesDeploymentData } from "../../../../http/HttpService";
8+
import HttpService from "../../../../http/HttpService";
9+
import {
10+
getProcessName,
11+
getProcessVersionId,
12+
hasError,
13+
isRedeployPossible,
14+
isRedeployVisible,
15+
isSaveDisabled,
16+
isValidationResultPresent,
17+
} from "../../../../reducers/selectors/graph";
18+
import { getCapabilities } from "../../../../reducers/selectors/other";
19+
import { ACTION_DIALOG_WIDTH } from "../../../../stylesheets/variables";
20+
import { useWindows } from "../../../../windowManager";
21+
import { WindowKind } from "../../../../windowManager";
22+
import type { ToggleProcessActionModalData } from "../../../modals/DeployProcessDialog";
23+
import type { ProcessName, ProcessVersionId } from "../../../Process/types";
24+
import { ToolbarButton } from "../../../toolbarComponents/toolbarButtons";
25+
import type { ToolbarButtonProps } from "../../types";
26+
27+
export default function RedeployButton(props: ToolbarButtonProps) {
28+
const dispatch = useDispatch();
29+
const isVisible = useSelector(isRedeployVisible);
30+
const isPossible = useSelector(isRedeployPossible);
31+
const saveDisabled = useSelector(isSaveDisabled);
32+
const hasErrors = useSelector(hasError);
33+
const validationResultPresent = useSelector(isValidationResultPresent);
34+
const processName = useSelector(getProcessName);
35+
const processVersionId = useSelector(getProcessVersionId);
36+
const capabilities = useSelector(getCapabilities);
37+
const { disabled, type } = props;
38+
39+
const available = validationResultPresent && !disabled && isPossible && capabilities.deploy;
40+
const { t } = useTranslation();
41+
const deployToolTip = !capabilities.deploy
42+
? t("panels.actions.redeploy.tooltips.forbidden", "Redeploy forbidden for current scenario.")
43+
: hasErrors
44+
? t("panels.actions.redeploy.tooltips.error", "Cannot redeploy due to errors. Please look at the left panel for more details.")
45+
: !saveDisabled
46+
? t("panels.actions.redeploy.tooltips.unsaved", "You have unsaved changes.")
47+
: null;
48+
const deployMouseOver = hasErrors ? () => dispatch(enableToolTipsHighlight()) : null;
49+
const deployMouseOut = hasErrors ? () => dispatch(disableToolTipsHighlight()) : null;
50+
51+
const { open, confirm } = useWindows();
52+
53+
const message = t("panels.actions.redeploy.dialog", "Redeploy scenario {{name}}", { name: processName });
54+
const action = (name: ProcessName, versionId: ProcessVersionId, comment: string, nodesDeploymentData?: NodesDeploymentData) =>
55+
HttpService.deploy(name, comment, nodesDeploymentData).finally(() => dispatch(loadProcessState(name, versionId)));
56+
57+
const handleOnClick = async () => {
58+
await HttpService.validateProcessVersion(processName, processVersionId).then((res) => {
59+
if (!res.data.isLatest) {
60+
confirm({
61+
text: t(
62+
"panels.actions.confirm-unsafe-deployment.message",
63+
`There is newer version #${res.data.latestVersion} created by ${res.data.modifiedBy} available. Scenario will be deployed using the newest version.
64+
You're currently checked out on version #${res.data.localVersion}.
65+
Are you sure you want to perform this action?`,
66+
),
67+
confirmText: t("panels.actions.confirm-unsafe-deployment.confirmButton", "Confirm"),
68+
denyText: t("panels.actions.confirm-unsafe-deployment.cancelButton", "Cancel"),
69+
onConfirmCallback: (confirmed) => {
70+
if (confirmed) {
71+
open<ToggleProcessActionModalData>({
72+
title: message,
73+
kind: WindowKind.deployWithParameters,
74+
width: ACTION_DIALOG_WIDTH,
75+
meta: { action, displayWarnings: true, actionName: "REDEPLOY" },
76+
});
77+
}
78+
},
79+
width: window.innerWidth / 3,
80+
});
81+
} else {
82+
open<ToggleProcessActionModalData>({
83+
title: message,
84+
kind: WindowKind.deployWithParameters,
85+
width: ACTION_DIALOG_WIDTH,
86+
meta: { action, displayWarnings: true, actionName: "REDEPLOY" },
87+
});
88+
}
89+
});
90+
};
91+
92+
if (isVisible) {
93+
return (
94+
<ToolbarButton
95+
name={t("panels.actions.redeploy.button", "redeploy")}
96+
disabled={!available}
97+
icon={<Icon />}
98+
title={deployToolTip}
99+
onClick={handleOnClick}
100+
onMouseOver={deployMouseOver}
101+
onMouseOut={deployMouseOut}
102+
type={type}
103+
/>
104+
);
105+
} else return <></>;
106+
}

designer/client/src/containers/event-tracking/helpers.ts

+3
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ export const mapToolbarButtonToStatisticsEvent = (
5151
case BuiltinButtonTypes.processDeploy: {
5252
return EventTrackingSelector.ActionDeploy;
5353
}
54+
case BuiltinButtonTypes.processRedeploy: {
55+
return EventTrackingSelector.ActionDeploy; // ActionRedeploy ?
56+
}
5457
case BuiltinButtonTypes.processMigrate: {
5558
return EventTrackingSelector.ScenarioMigrate;
5659
}

0 commit comments

Comments
 (0)