Skip to content

Commit

Permalink
new form with working deploy parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
gskrobisz committed Oct 1, 2024
1 parent 8a0b15f commit 68932ac
Show file tree
Hide file tree
Showing 15 changed files with 231 additions and 69 deletions.
21 changes: 21 additions & 0 deletions designer/client/src/components/modals/ActivityCommentTextField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { styled, TextField, TextFieldProps } from "@mui/material";
import React from "react";

export const ActivityCommentTextField = styled((props: TextFieldProps) => (
<TextField
fullWidth
multiline
minRows={1}
maxRows={3}
InputLabelProps={{ shrink: true }}
variant="outlined"
label="Comment"
{...props}
/>
))({
flexDirection: "column",
".MuiFormLabel-root": {
margin: 0,
flexDirection: "column",
},
});
33 changes: 33 additions & 0 deletions designer/client/src/components/modals/ActivityHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useSelector } from "react-redux";
import { getProcessName } from "../../reducers/selectors/graph";
import { Box, Typography } from "@mui/material";
import React from "react";
import ProcessDialogWarnings from "./ProcessDialogWarnings";

interface Props {
title: string;
displayWarnings?: boolean;
}

export function ActivityHeader(props: Props): JSX.Element {
const processName = useSelector(getProcessName);
return (
<Box>
<Typography variant={"inherit"} sx={{ width: "100%", "::after": { content: "':'" } }}>
{props.title}
</Typography>
<Typography
variant={"h5"}
sx={{
width: "100%",
fontWeight: "bold",
margin: 0,
lineHeight: "2em",
}}
>
{processName}
</Typography>
{props.displayWarnings && <ProcessDialogWarnings />}
</Box>
);
}
49 changes: 49 additions & 0 deletions designer/client/src/components/modals/ActivityProperty.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { ExpressionLang } from "../graph/node-modal/editors/expression/types";
import React, { useCallback } from "react";
import { FieldLabel } from "../graph/node-modal/FieldLabel";
import { getValidationErrorsForField } from "../graph/node-modal/editors/Validators";
import { ActivityNodeParameters, ActivityParameterConfig } from "../../types/activity";
import { NodesDeploymentData } from "../../http/HttpService";
import { NodeValidationError } from "../../types";
import { default as EditableEditor } from "../graph/node-modal/editors/EditableEditor";

interface Props {
nodeName: string;
propertyName: string;
propertyConfig: ActivityParameterConfig;
nodesData: NodesDeploymentData;
onChange: <K extends keyof ActivityNodeParameters["parameters"]>(
nodeId: string,
property: K,
newValue: ActivityNodeParameters["parameters"][K],
defaultValue?: ActivityNodeParameters["parameters"][K],
) => void;
errors: NodeValidationError[];
}

export function ActivityProperty(props: Props): JSX.Element {
const { nodeName, propertyName, propertyConfig, errors, nodesData, onChange } = props;

const current = nodesData[nodeName][propertyName] || "";
const expressionObj = { expression: current, value: current, language: ExpressionLang.String };
const onValueChange = useCallback((newValue) => onChange(nodeName, propertyName, newValue), [onChange, nodeName, propertyName]);

return (
<EditableEditor
key={propertyName}
param={propertyConfig}
fieldLabel={propertyConfig.label || propertyName}
onValueChange={onValueChange}
expressionObj={expressionObj}
renderFieldLabel={() => (
<FieldLabel title={propertyConfig.label} label={propertyConfig.label} hintText={propertyConfig.hintText} />
)}
readOnly={false}
showSwitch={false}
showValidation={true}
//ScenarioProperties do not use any variables
variableTypes={{}}
fieldErrors={getValidationErrorsForField(errors, propertyName)}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React, { PropsWithChildren } from "react";
import Accordion from "@mui/material/Accordion";
import AccordionSummary from "@mui/material/AccordionSummary";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import { Typography } from "@mui/material";
import AccordionDetails from "@mui/material/AccordionDetails";

interface Props {
nodeId: string;
}

export function AdvancedParametersSection({ children, nodeId }: PropsWithChildren<Props>): JSX.Element {
return (
<Accordion disableGutters elevation={0} sx={{ border: 0, "&::before": { display: "none" } }}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls={`${nodeId}-content`}
id={`${nodeId}-header`}
sx={{ flexDirection: "row-reverse", px: 0, border: 0 }}
>
<Typography>{nodeId}</Typography>
</AccordionSummary>
<AccordionDetails>{children}</AccordionDetails>
</Accordion>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export function CountsDialog({ children, ...props }: PropsWithChildren<WindowCon
classname: LoadingButtonTypes.secondaryButton,
},
{
title: t("dialog.button.ok", "Ok"),
title: t("dialog.button.ok", "Apply"),
disabled: !isStateValid,
action: async () => {
await confirm();
Expand Down
28 changes: 11 additions & 17 deletions designer/client/src/components/modals/CustomActionDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { loadProcessState } from "../../actions/nk";
import HttpService, { CustomActionValidationRequest } from "../../http/HttpService";
import { CustomAction, NodeValidationError } from "../../types";
import { UnknownRecord } from "../../types/common";
import { WindowContent, WindowKind } from "../../windowManager";
import { PromptContent, WindowKind } from "../../windowManager";
import { ChangeableValue } from "../ChangeableValue";
import { editors, ExtendedEditor, SimpleEditor } from "../graph/node-modal/editors/expression/Editor";
import { ExpressionLang } from "../graph/node-modal/editors/expression/types";
Expand All @@ -18,7 +18,8 @@ import { LoadingButtonTypes } from "../../windowManager/LoadingButton";
import { nodeValue } from "../graph/node-modal/NodeDetailsContent/NodeTableStyled";
import { getValidationErrorsForField } from "../graph/node-modal/editors/Validators";
import { getFeatureSettings } from "../../reducers/selectors/settings";
import CommentInput from "../comment/CommentInput";
import { ActivityCommentTextField } from "./ActivityCommentTextField";
import { ActivityHeader } from "./ActivityHeader";

interface CustomActionFormProps extends ChangeableValue<UnknownRecord> {
action: CustomAction;
Expand Down Expand Up @@ -123,32 +124,25 @@ export function CustomActionDialog(props: WindowContentProps<WindowKind, CustomA
const buttons: WindowButtonProps[] = useMemo(
() => [
{ title: t("dialog.button.cancel", "Cancel"), action: () => props.close(), classname: LoadingButtonTypes.secondaryButton },
{ title: t("dialog.button.confirm", "Ok"), action: () => confirmAction() },
{ title: t("dialog.button.confirm", "Apply"), action: () => confirmAction() },
],
[confirmAction, props, t],
);

return (
<WindowContent {...props} buttons={buttons}>
<PromptContent {...props} buttons={buttons}>
<div className={cx("modalContentDark", css({ padding: "1em", minWidth: 600 }))}>
<CommentInput
<ActivityHeader title={props.data.title} />
<ActivityCommentTextField
placeholder={deploymentCommentSettings?.exampleComment}
error={!!validationError}
helperText={validationError}
onChange={(e) => setComment(e.target.value)}
value={comment}
defaultValue={deploymentCommentSettings?.exampleComment}
className={cx(
css({
minWidth: 600,
minHeight: 80,
}),
)}
autoFocus
/>
<FormHelperText title={validationError} error>
{validationError}
</FormHelperText>
<CustomActionForm action={action} value={value} onChange={setValue} />
</div>
</WindowContent>
</PromptContent>
);
}

Expand Down
89 changes: 64 additions & 25 deletions designer/client/src/components/modals/DeployProcessDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,43 @@ import { getActivityParameters, getProcessName } from "../../reducers/selectors/
import { getFeatureSettings } from "../../reducers/selectors/settings";
import { ProcessName } from "../Process/types";
import { PromptContent, WindowKind } from "../../windowManager";
import CommentInput from "../comment/CommentInput";
import ProcessDialogWarnings from "./ProcessDialogWarnings";
import { FormHelperText, Typography } from "@mui/material";
import { LoadingButtonTypes } from "../../windowManager/LoadingButton";
import { ActivityNodeParameters } from "../../types/activity";
import { AdvancedParametersSection } from "./AdvancedParametersSection";
import { mapValues } from "lodash";
import { NodesDeploymentData } from "../../http/HttpService";
import { ActivityProperty } from "./ActivityProperty";
import { ActivityCommentTextField } from "./ActivityCommentTextField";
import { ActivityHeader } from "./ActivityHeader";
import { NodeTable } from "../graph/node-modal/NodeDetailsContent/NodeTable";

export type ToggleProcessActionModalData = {
action: (processName: ProcessName, comment: string) => Promise<unknown>;
action: (processName: ProcessName, comment: string, nodeData: NodesDeploymentData) => Promise<unknown>;
activityName: string;
displayWarnings?: boolean;
};

function initialNodesData(params: ActivityNodeParameters[]) {
return params.reduce(
(paramObj, { nodeId, parameters }) => ({
...paramObj,
[nodeId]: mapValues(parameters, (value) => value.defaultValue || ""),
}),
{},
);
}

export function DeployProcessDialog(props: WindowContentProps<WindowKind, ToggleProcessActionModalData>): JSX.Element {
// TODO: get rid of meta
const {
meta: { action, displayWarnings },
meta: { action, activityName, displayWarnings },
} = props.data;
const processName = useSelector(getProcessName);

const activityParameters = useSelector(getActivityParameters);
const activityNodeParameters = activityParameters["DEPLOY"] || [];
console.log(activityNodeParameters);
const activityNodeParameters = activityParameters[activityName] || ([] as ActivityNodeParameters[]);
const initialValues = useMemo(() => initialNodesData(activityNodeParameters), [activityNodeParameters]);
const [values, setValues] = useState(initialValues);

const [comment, setComment] = useState("");
const [validationError, setValidationError] = useState("");
Expand All @@ -37,7 +54,7 @@ export function DeployProcessDialog(props: WindowContentProps<WindowKind, Toggle

const confirmAction = useCallback(async () => {
try {
await action(processName, comment);
await action(processName, comment, values);
props.close();
} catch (error) {
setValidationError(error?.response?.data);
Expand All @@ -47,32 +64,54 @@ export function DeployProcessDialog(props: WindowContentProps<WindowKind, Toggle
const { t } = useTranslation();
const buttons: WindowButtonProps[] = useMemo(
() => [
{ title: t("dialog.button.cancel", "Cancel"), action: () => props.close(), classname: LoadingButtonTypes.secondaryButton },
{ title: t("dialog.button.ok", "Ok"), action: () => confirmAction() },
{
title: t("dialog.button.cancel", "Cancel"),
action: () => props.close(),
classname: LoadingButtonTypes.secondaryButton,
},
{ title: t("dialog.button.ok", "Apply"), action: () => confirmAction() },
],
[confirmAction, props, t],
);

return (
<PromptContent {...props} buttons={buttons}>
<div className={cx("modalContentDark")}>
<Typography variant={"h3"}>{props.data.title}</Typography>
{displayWarnings && <ProcessDialogWarnings />}
<CommentInput
<div className={cx("modalContentDark", css({ minWidth: 600 }))}>
<ActivityHeader title={props.data.title} displayWarnings={displayWarnings} />
<ActivityCommentTextField
placeholder={deploymentCommentSettings?.exampleComment}
error={!!validationError}
helperText={validationError}
onChange={(e) => setComment(e.target.value)}
value={comment}
defaultValue={deploymentCommentSettings?.exampleComment}
className={cx(
css({
minWidth: 600,
minHeight: 80,
}),
)}
autoFocus
/>
<FormHelperText title={validationError} error>
{validationError}
</FormHelperText>
{activityNodeParameters.map((anp: ActivityNodeParameters) => (
<AdvancedParametersSection key={anp.nodeId} nodeId={anp.nodeId}>
<NodeTable>
{Object.entries(anp.parameters).map(([paramName, paramConfig]) => {
return (
<ActivityProperty
key={paramName}
nodeName={anp.nodeId}
propertyName={paramName}
propertyConfig={paramConfig}
errors={[]}
onChange={(nodeId, paramName, newValue) => {
setValues({
...values,
[nodeId]: {
...values[nodeId],
[paramName]: newValue,
},
});
}}
nodesData={values}
/>
);
})}
</NodeTable>
</AdvancedParametersSection>
))}
</div>
</PromptContent>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function GenerateTestDataDialog(props: WindowContentProps): JSX.Element {
const buttons: WindowButtonProps[] = useMemo(
() => [
{ title: t("dialog.button.cancel", "Cancel"), action: () => props.close(), classname: LoadingButtonTypes.secondaryButton },
{ title: t("dialog.button.ok", "Ok"), disabled: !isValid, action: () => confirmAction() },
{ title: t("dialog.button.ok", "Apply"), disabled: !isValid, action: () => confirmAction() },
],
[t, confirmAction, props, isValid],
);
Expand Down
18 changes: 5 additions & 13 deletions designer/client/src/components/modals/SaveProcessDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { useTranslation } from "react-i18next";
import { useDispatch } from "react-redux";
import { displayCurrentProcessVersion, displayProcessActivity, loadProcessToolbarsConfiguration } from "../../actions/nk";
import { PromptContent } from "../../windowManager";
import { CommentInput } from "../comment/CommentInput";
import { ThunkAction } from "../../actions/reduxTypes";
import {
getScenarioGraph,
Expand All @@ -18,8 +17,9 @@ import HttpService from "../../http/HttpService";
import { ActionCreators as UndoActionCreators } from "redux-undo";
import { visualizationUrl } from "../../common/VisualizationUrl";
import { useLocation, useNavigate } from "react-router-dom";
import { Typography } from "@mui/material";
import { LoadingButtonTypes } from "../../windowManager/LoadingButton";
import { ActivityCommentTextField } from "./ActivityCommentTextField";
import { ActivityHeader } from "./ActivityHeader";

export function SaveProcessDialog(props: WindowContentProps): JSX.Element {
const location = useLocation();
Expand Down Expand Up @@ -70,24 +70,16 @@ export function SaveProcessDialog(props: WindowContentProps): JSX.Element {
const buttons: WindowButtonProps[] = useMemo(
() => [
{ title: t("dialog.button.cancel", "Cancel"), action: () => props.close(), classname: LoadingButtonTypes.secondaryButton },
{ title: t("dialog.button.ok", "Ok"), action: () => confirmAction() },
{ title: t("dialog.button.ok", "Apply"), action: () => confirmAction() },
],
[confirmAction, props, t],
);

return (
<PromptContent {...props} buttons={buttons}>
<div className={cx("modalContentDark", css({ minWidth: 600 }))}>
<Typography variant={"h3"}>{props.data.title}</Typography>
<CommentInput
onChange={(e) => setState(e.target.value)}
value={comment}
className={css({
minWidth: 600,
minHeight: 80,
})}
autoFocus
/>
<ActivityHeader title={props.data.title} />
<ActivityCommentTextField onChange={(e) => setState(e.target.value)} autoFocus />
</div>
</PromptContent>
);
Expand Down
Loading

0 comments on commit 68932ac

Please sign in to comment.