Merge pull request #6423 from chicoribas/Mask-or-hide-values-on-Scaffolder-Review-Step

Mask or hide values on scaffolder review step
This commit is contained in:
Ben Lambert
2021-07-14 18:25:03 +02:00
committed by GitHub
4 changed files with 180 additions and 3 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': patch
---
Add options to mask or hide values on review state
@@ -227,6 +227,33 @@ spec:
inputType: tel
```
#### Hide or mask sensitive data on Review step
Sometimes, specially in custom fields, you collect some data on Create form that
must not be shown to the user on Review step. To hide or mask this data, you can
use `ui:widget: password` or set some properties of `ui:backstage`:
```yaml
- title: Hide or mask values
properties:
password:
title: Password
type: string
ui:widget: password # will print '******' as value for property 'password' on Review Step
masked:
title: Masked
type: string
ui:backstage:
review:
mask: '<some-value-to-show>' # will print '<some-value-to-show>' as value for property 'Masked' on Review Step
hidden:
title: Hidden
type: string
ui:backstage:
review:
show: false # wont print any info about 'hidden' property on Review Step
```
#### The Repository Picker
So in order to make working with repository providers easier, we've built a
@@ -0,0 +1,88 @@
/*
* Copyright 2021 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:backstage': {
review: {
show: true,
mask: '******',
},
},
},
open: {
title: 'Open info',
type: 'string',
},
},
},
},
{
title: 'Other fields',
schema: {
title: 'Other fields',
properties: {
hidden: {
title: 'Hidden',
type: 'string',
'ui:backstage': {
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');
});
});
@@ -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,59 @@ type Props = {
fields?: FormProps<any>['fields'];
};
export function getUiSchemasFromSteps(steps: Step[]): UiSchema[] {
const uiSchemas: Array<UiSchema> = [];
steps.forEach(step => {
const schemaProps = step.schema.properties as JsonObject;
for (const key in schemaProps) {
if (schemaProps.hasOwnProperty(key)) {
const uiSchema = schemaProps[key] as UiSchema;
uiSchema.name = key;
uiSchemas.push(uiSchema);
}
}
});
return uiSchemas;
}
export function getReviewData(formData: Record<string, any>, steps: Step[]) {
const uiSchemas = getUiSchemasFromSteps(steps);
const reviewData: Record<string, any> = {};
for (const key in formData) {
if (formData.hasOwnProperty(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:backstage'] || !uiSchema['ui:backstage'].review) {
reviewData[key] = formData[key];
continue;
}
const review = uiSchema['ui:backstage'].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,
@@ -64,8 +117,9 @@ export const MultistepJsonForm = ({
setActiveStep(0);
onReset();
};
const handleNext = () =>
const handleNext = () => {
setActiveStep(Math.min(activeStep + 1, steps.length));
};
const handleBack = () => setActiveStep(Math.max(activeStep - 1, 0));
return (
@@ -113,7 +167,10 @@ export const MultistepJsonForm = ({
<Content>
<Paper square elevation={0}>
<Typography variant="h6">Review and create</Typography>
<StructuredMetadataTable dense metadata={formData} />
<StructuredMetadataTable
dense
metadata={getReviewData(formData, steps)}
/>
<Box mb={4} />
<Button onClick={handleBack}>Back</Button>
<Button onClick={handleReset}>Reset</Button>