From ac96bc7975e611caaca49d2425943a08ffa195c9 Mon Sep 17 00:00:00 2001 From: chicoribas Date: Fri, 9 Jul 2021 10:22:42 -0300 Subject: [PATCH] Add ui:options to mask and hide Signed-off-by: chicoribas --- .../MultistepJsonForm.test.tsx | 88 +++++++++++++++++++ .../MultistepJsonForm/MultistepJsonForm.tsx | 68 +++++++++++++- 2 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.test.tsx diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.test.tsx b/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.test.tsx new file mode 100644 index 0000000000..261892c4ac --- /dev/null +++ b/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.test.tsx @@ -0,0 +1,88 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { getReviewData } from './MultistepJsonForm'; + +describe('MultistepJsonForm', () => { + const formDataMock = { + password: 'password', + masked: 'Some info to mask', + open: 'Some open info', + hidden: 'Some info to hide', + 'other-open': 'Other open info', + }; + + const stepsMock = [ + { + title: 'The test template', + schema: { + title: 'The test template', + properties: { + password: { + title: 'Password', + type: 'string', + 'ui:widget': 'password', + }, + masked: { + title: 'Masked', + type: 'string', + 'ui:options': { + review: { + show: true, + mask: '******', + }, + }, + }, + open: { + title: 'Open info', + type: 'string', + }, + }, + }, + }, + { + title: 'Other fields', + schema: { + title: 'Other fields', + properties: { + hidden: { + title: 'Hidden', + type: 'string', + 'ui:options': { + review: { + show: false, + }, + }, + }, + 'other-open': { + title: 'Other Open Info', + type: 'string', + }, + }, + }, + }, + ]; + + test('Fields are defined to be hidden or masked', () => { + const reviewData = getReviewData(formDataMock, stepsMock); + + expect(reviewData.password).toBe('******'); + expect(reviewData.masked).toBe('******'); + expect(reviewData.open).toBe('Some open info'); + expect(reviewData.hidden).toBeUndefined(); + expect(reviewData['other-open']).toBe('Other open info'); + }); +}); diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx b/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx index 0fc998f82e..676d3562e1 100644 --- a/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx +++ b/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx @@ -24,7 +24,7 @@ import { Stepper, Typography, } from '@material-ui/core'; -import { FormProps, IChangeEvent, withTheme } from '@rjsf/core'; +import { FormProps, IChangeEvent, UiSchema, withTheme } from '@rjsf/core'; import { Theme as MuiTheme } from '@rjsf/material-ui'; import React, { useState } from 'react'; import { transformSchemaToProps } from './schema'; @@ -49,6 +49,62 @@ type Props = { fields?: FormProps['fields']; }; +export function getUiSchemasFromSteps(steps: Step[]): UiSchema[] { + const uiSchemas: Array = []; + steps.forEach(step => { + if (!step.schema || !step.schema.properties) return; + + const schemaProps = step.schema.properties as JsonObject; + for (const key in schemaProps) { + if (Object.prototype.hasOwnProperty.call(schemaProps, key)) { + const uiSchema = schemaProps[key] as UiSchema; + uiSchema.name = key; + uiSchemas.push(uiSchema); + } + } + }); + + return uiSchemas; +} + +export function getReviewData(formData: Record, steps: Step[]) { + const uiSchemas = getUiSchemasFromSteps(steps); + const reviewData: Record = {}; + for (const key in formData) { + if (Object.prototype.hasOwnProperty.call(formData, key)) { + const uiSchema = uiSchemas.find(us => us.name === key); + + if (!uiSchema) { + reviewData[key] = formData[key]; + continue; + } + + if (uiSchema['ui:widget'] === 'password') { + reviewData[key] = '******'; + continue; + } + + if (!uiSchema['ui:options'] || !uiSchema['ui:options'].review) { + reviewData[key] = formData[key]; + continue; + } + + const review = uiSchema['ui:options'].review as JsonObject; + if (!review.show) { + continue; + } + + if (review.mask) { + reviewData[key] = review.mask; + continue; + } + reviewData[key] = formData[key]; + } + } + + return reviewData; +} + export const MultistepJsonForm = ({ steps, formData, @@ -59,13 +115,19 @@ export const MultistepJsonForm = ({ widgets, }: Props) => { const [activeStep, setActiveStep] = useState(0); + const [reviewData, setReviewData] = useState({}); const handleReset = () => { setActiveStep(0); onReset(); }; - const handleNext = () => + const handleNext = () => { setActiveStep(Math.min(activeStep + 1, steps.length)); + + if (Math.min(activeStep + 1, steps.length) === steps.length) { + setReviewData(getReviewData(formData, steps)); + } + }; const handleBack = () => setActiveStep(Math.max(activeStep - 1, 0)); return ( @@ -113,7 +175,7 @@ export const MultistepJsonForm = ({ Review and create - +