Skip to content

Commit

Permalink
Feat 336 protected values hidden (#138)
Browse files Browse the repository at this point in the history
* fix: global parameters and team parameters

* feat: run workflow modal w/ secure inputs

* fix: clean up

* fix: updated text helper text in workflow parameter modal

* fix: remove clone-deep, use lodash

* fix: password hidden constant

* Update src/Features/Editor/Properties/PropertiesModal/PropertiesModalContent/PropertiesModalContent.tsx

Co-authored-by: Tim Bula <[email protected]>

* fix: updated copy

* chore: remove @types/clone-deep

Co-authored-by: Tim Bula <[email protected]>
  • Loading branch information
BenjaminRuby and timrbula authored May 20, 2022
1 parent bf1ffe8 commit c5c3404
Show file tree
Hide file tree
Showing 18 changed files with 13,797 additions and 7,776 deletions.
21,343 changes: 13,624 additions & 7,719 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"copy-to-clipboard": "^3.3.1",
"cronstrue": "^1.122.0",
"d3": "<=5.9.2",
"deep-object-diff": "^1.1.7",
"detect-browser": "^4.0.3",
"flagged": "^2.0.1",
"formik": "^2.1.4",
Expand Down Expand Up @@ -120,12 +121,12 @@
"lint-staged": "10.1.1",
"miragejs": "^0.1.40",
"ncp": "^2.0.0",
"sass": "^1.50.0",
"npm-run-all": "4.1.5",
"prettier": "2.0.5",
"react-test-renderer": "^16.13.1",
"sass": "^1.50.0",
"source-map-explorer": "^2.4.2",
"start-server-and-test": "^1.10.11",
"react-test-renderer": "^16.13.1",
"ts-loader": "^9.2.8",
"typescript": "^4.5.4",
"typescript-plugin-css-modules": "^3.4.0",
Expand Down
2 changes: 1 addition & 1 deletion src/ApiServer/fixtures/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const config = [
type: "text",
},
{
value: "ben.value",
value: null,
readOnly: false,
id: "5ebda5350f99fc00010d06d7",
description: "",
Expand Down
12 changes: 7 additions & 5 deletions src/ApiServer/fixtures/userWorkflows.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@ const userWorkflows = {
placeholder: null,
language: null,
disabled: null,
defaultValue: "",
defaultValue: null,
value: null,
values: null,
readOnly: false,
description: "Tenant ID from the platform.",
key: "tenant",
label: "Tenant ID",
type: "text",
type: "password",
min: null,
max: null,
options: null,
helperText: null,
hiddenValue: true,
},
],
description: "",
Expand All @@ -45,19 +46,20 @@ const userWorkflows = {
placeholder: null,
language: null,
disabled: null,
defaultValue: "",
defaultValue: null,
value: null,
values: null,
readOnly: false,
jsonPath: null,
description: "",
description: "here is my test",
key: "system.component.name",
label: "Component Name",
type: "text",
type: "password",
minValueLength: null,
maxValueLength: null,
options: null,
helperText: null,
hiddenValue: true,
},
],
description: "",
Expand Down
12 changes: 11 additions & 1 deletion src/Components/WorkflowCard/WorkflowCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import WorkflowWarningButton from "Components/WorkflowWarningButton";
import UpdateWorkflow from "./UpdateWorkflow";
import WorkflowInputModalContent from "./WorkflowInputModalContent";
import WorkflowRunModalContent from "./WorkflowRunModalContent";
import cloneDeep from "lodash/cloneDeep";
import fileDownload from "js-file-download";
import { formatErrorMessage } from "@boomerang-io/utils";
import { appLink, FeatureFlag } from "Config/appConfig";
Expand All @@ -29,6 +30,8 @@ import workflowIcons from "Assets/workflowIcons";
import { ComposedModalChildProps, FlowTeamQuotas, ModalTriggerProps, WorkflowSummary } from "Types";
import { WorkflowScope } from "Constants";
import styles from "./workflowCard.module.scss";
// @ts-ignore:next-line
import { swapValue } from "Utils";

interface WorkflowCardProps {
scope: string;
Expand Down Expand Up @@ -161,8 +164,14 @@ const WorkflowCard: React.FC<WorkflowCardProps> = ({ scope, teamId, quotas, work

const handleExecuteWorkflow = async (closeModal: () => void, redirect: boolean = false, properties: {} = {}) => {
const { id: workflowId } = workflow;
let newProperties = properties;
if (Object.values(properties).includes("")) {
newProperties = cloneDeep(properties);
swapValue(newProperties);
}
try {
const { data: execution } = await executeWorkflowMutator({ id: workflowId, properties });
// @ts-ignore:next-line
const { data: execution } = await executeWorkflowMutator({ id: workflowId, properties: newProperties });
notify(
<ToastNotification
kind="success"
Expand Down Expand Up @@ -311,6 +320,7 @@ const WorkflowCard: React.FC<WorkflowCardProps> = ({ scope, teamId, quotas, work
executeError={executeError}
executeWorkflow={handleExecuteWorkflow}
isExecuting={isExecuting}
/* @ts-ignore-next-line */
inputs={formattedProperties}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import React from "react";
import { Button, InlineNotification, ModalBody, ModalFooter } from "@boomerang-io/carbon-addons-boomerang-react";
import { DynamicFormik, ModalFlowForm } from "@boomerang-io/carbon-addons-boomerang-react";
import styles from "./workflowInputModalContent.module.scss";
import { InputProperty, InputType, PASSWORD_CONSTANT } from "Constants";

interface WorkflowInputModalContentProps {
closeModal: () => void;
executeError: any;
executeWorkflow: (closeModal: () => void, redirect: boolean, properties: {}) => Promise<void>;
inputs: {}[];
inputs: Array<typeof InputProperty>;
isExecuting: boolean;
}

Expand All @@ -19,11 +20,27 @@ const WorkflowInputModalContent: React.FC<WorkflowInputModalContentProps> = ({
isExecuting,
}) => {
const [isRedirectEnabled, setIsRedirectEnabled] = React.useState(false);

//edit inputs to handle secure values
const secureInputs = inputs.map((input: typeof InputProperty) => {
/* @ts-ignore-next-line */
if (input[InputProperty.Type] === InputType.Password && input?.hiddenValue) {
//if the input type is secure and there is a default value we are going to manipulate the object
return {
//allow the user to submit null
...input,
required: false,
helperText: "To use your secure default value, leave this input blank",
placeholder: PASSWORD_CONSTANT,
};
} else return input;
});

return (
<DynamicFormik
allowCustomPropertySyntax
validateOnMount
inputs={inputs}
inputs={secureInputs}
toggleProps={() => ({
orientation: "vertical",
})}
Expand Down
1 change: 1 addition & 0 deletions src/Constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { CloseOutline32, CheckmarkOutline32, Error32, InProgress32, Timer32 } fr
*/
export const CREATED_DATE_FORMAT = "MMMM DD, YYYY";
export const PROPERTY_KEY_REGEX = /^[a-zA-Z_]([a-zA-Z0-9-_])*$/;
export const PASSWORD_CONSTANT = "******";

/**
* Enums
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ import { Formik, FormikProps } from "formik";
import * as Yup from "yup";
import clonedeep from "lodash/cloneDeep";
import { validateUrlWithProperties } from "Utils/urlPropertySyntaxHelper";
import { InputProperty, InputType, InputTypeCopy, WorkflowPropertyUpdateType, PROPERTY_KEY_REGEX } from "Constants";
import {
InputProperty,
InputType,
InputTypeCopy,
WorkflowPropertyUpdateType,
PROPERTY_KEY_REGEX,
PASSWORD_CONSTANT,
} from "Constants";
import { DataDrivenInput, FormikSetFieldValue } from "Types";
import styles from "./PropertiesModalContent.module.scss";

Expand Down Expand Up @@ -169,9 +176,16 @@ class PropertiesModalContent extends Component<PropertiesModalContentProps> {
labelText="Default Value"
onBlur={handleBlur}
onChange={handleChange}
placeholder="Default Value"
placeholder={
this.props.isEdit && values.type.value === InputType.Password ? PASSWORD_CONSTANT : "Default Value"
}
type={values.type.value}
value={values.defaultValue || ""}
helperText={
values.type.value === InputType.Password
? "Passwords are saved securely in our database. To update the saved value, provide a new default value."
: null
}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ import {
TextInput,
Toggle,
} from "@boomerang-io/carbon-addons-boomerang-react";
import { InputType, PROPERTY_KEY_REGEX } from "Constants";
import { InputType, PROPERTY_KEY_REGEX, PASSWORD_CONSTANT } from "Constants";
import { serviceUrl, resolver } from "Config/servicesConfig";
import { Property } from "Types";
import { Property, PatchProperty } from "Types";
import { updatedDiff } from "deep-object-diff";

type Props = {
closeModal: () => void;
Expand All @@ -29,6 +30,14 @@ type Props = {
const configUrl = serviceUrl.getGlobalConfiguration();

function CreateEditPropertiesContent({ closeModal, isEdit, property, propertyKeys, cancelRequestRef }: Props) {
const initialState = {
label: property?.label ?? "",
description: property?.description ?? "",
key: property?.key ?? "",
value: property?.value ?? "",
secured: property?.type === InputType.Password ?? false,
};

const queryClient = useQueryClient();
/** Add property */
const { mutateAsync: addGlobalPropertyMutation, isLoading: addLoading, error: addError } = useMutation(
Expand All @@ -44,7 +53,7 @@ function CreateEditPropertiesContent({ closeModal, isEdit, property, propertyKey

/** Update property */
const { mutateAsync: updateGlobalPropertyMutation, isLoading: updateLoading, error: updateError } = useMutation(
(args: { id: string; body: Property }) => {
(args: { id: string; body: PatchProperty }) => {
const { promise, cancel } = resolver.patchGlobalPropertyRequest(args);
cancelRequestRef.current = cancel;
return promise;
Expand All @@ -62,8 +71,9 @@ function CreateEditPropertiesContent({ closeModal, isEdit, property, propertyKey
delete newProperty.secured;

if (isEdit) {
const updatedFields = updatedDiff(initialState, newProperty);
try {
await updateGlobalPropertyMutation({ id: newProperty.id, body: newProperty });
await updateGlobalPropertyMutation({ id: newProperty.id, body: updatedFields });
notify(
<ToastNotification
kind="success"
Expand Down Expand Up @@ -97,14 +107,9 @@ function CreateEditPropertiesContent({ closeModal, isEdit, property, propertyKey

return (
<Formik
initialValues={{
label: property && property.label ? property.label : "",
description: property && property.description ? property.description : "",
key: property && property.key ? property.key : "",
value: property && property.value ? property.value : "",
secured: property ? property.type === InputType.Password : false,
}}
initialValues={initialState}
onSubmit={handleSubmit}
validateOnMount
validationSchema={Yup.object().shape({
label: Yup.string().required("Enter a label"),
key: Yup.string()
Expand All @@ -116,7 +121,11 @@ function CreateEditPropertiesContent({ closeModal, isEdit, property, propertyKey
"Only alphanumeric, hyphen and underscore characters allowed. Must begin with a letter or underscore",
validateKey
),
value: Yup.string().required("Enter a value"),
value: Yup.string().when("secured", {
is: (value: boolean) => value && isEdit,
then: Yup.string(),
otherwise: Yup.string().required("Enter a value"),
}),
description: Yup.string(),
secured: Yup.boolean(),
})}
Expand Down Expand Up @@ -153,7 +162,7 @@ function CreateEditPropertiesContent({ closeModal, isEdit, property, propertyKey
<TextInput
data-testid="create-parameter-description"
id="description"
labelText="Description"
labelText="Description (optional)"
name="description"
value={values.description}
onBlur={handleBlur}
Expand All @@ -163,24 +172,32 @@ function CreateEditPropertiesContent({ closeModal, isEdit, property, propertyKey
data-testid="create-parameter-value"
id="value"
labelText="Value"
placeholder="Value"
placeholder={isEdit && values.secured ? PASSWORD_CONSTANT : "Value"}
name="value"
value={values.value}
onBlur={handleBlur}
onChange={handleChange}
invalid={errors.value && touched.value}
invalidText={errors.value}
type={values.secured ? "password" : "text"}
helperText={
isEdit && values.secured
? "Secure values are stored in our database. You can provide a new value to override"
: null
}
/>
<Toggle
id="secured-global-parameters-toggle"
disabled={isEdit}
labelText="Secured"
name="secured"
onChange={handleChange}
orientation="vertical"
toggled={values.secured}
data-testid="secured-global-parameters-toggle"
helperText="Once a parameter is created, secured state will not be able to be updated"
/>

{addError && (
<InlineNotification
lowContrast
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ exports[`CreateEditPropertiesContent --- Snapshot Test Capturing Snapshot of Cre
class="bx--bmrg-text-input__label"
>
<div>
Description
Description (optional)
</div>
</div>
</label>
Expand Down Expand Up @@ -183,6 +183,7 @@ exports[`CreateEditPropertiesContent --- Snapshot Test Capturing Snapshot of Cre
aria-labelledby="secured-global-parameters-toggle-label"
class="bx--toggle-input"
data-testid="secured-global-parameters-toggle"
disabled=""
id="secured-global-parameters-toggle"
name="secured"
type="checkbox"
Expand All @@ -207,6 +208,12 @@ exports[`CreateEditPropertiesContent --- Snapshot Test Capturing Snapshot of Cre
</label>
</div>
</div>
<div
class="bx--form__helper-text"
style="margin-bottom: 0px;"
>
Once a parameter is created, secured state will not be able to be updated
</div>
</div>
</div>
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ import {
} from "@boomerang-io/carbon-addons-boomerang-react";
import ActionsMenu from "./ActionsMenu";
import CreateEditPropertiesModal from "./CreateEditPropertiesModal";
import { stringToPassword } from "Utils/stringHelper";
import { InputType } from "Constants";
import { InputType, PASSWORD_CONSTANT } from "Constants";
import { formatErrorMessage } from "@boomerang-io/utils";
import EmptyState from "Components/EmptyState";
import { serviceUrl, resolver } from "Config/servicesConfig";
Expand Down Expand Up @@ -126,7 +125,7 @@ function PropertiesTable({ properties }: { properties: Property[] }) {
case "value":
const determineValue = value
? property && property.type === InputType.Password
? stringToPassword(value)
? PASSWORD_CONSTANT
: value
: "---";
return <p className={styles.tableTextarea}>{determineValue}</p>;
Expand All @@ -137,7 +136,9 @@ function PropertiesTable({ properties }: { properties: Property[] }) {
<Close32 alt="unsecured" className={`${styles.tableSecured} ${styles.unsecured}`} />
);
case "actions":
return <ActionsMenu deleteProperty={deleteProperty} property={property ?? defaultProperty} properties={properties} />;
return (
<ActionsMenu deleteProperty={deleteProperty} property={property ?? defaultProperty} properties={properties} />
);
default:
return <p className={styles.tableTextarea}>{value || "---"}</p>;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ exports[`PropertiesTable --- Snapshot Test Capturing Snapshot of PropertiesTable
<p
class="tableTextarea"
>
•••••••••
---
</p>
</div>
</td>
Expand Down
Loading

0 comments on commit c5c3404

Please sign in to comment.