forked from janus-idp/backstage-plugins
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request janus-idp#69 from parodos-dev/pc/horizontal-stepper
horizontal dynamic form stepper
- Loading branch information
Showing
13 changed files
with
342 additions
and
118 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
163 changes: 163 additions & 0 deletions
163
plugins/parodos/src/components/Form/Templates/ArrayFieldTemplate.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
/* eslint-disable no-console */ | ||
import React, { useCallback, useState } from 'react'; | ||
import { | ||
getTemplate, | ||
getUiOptions, | ||
ArrayFieldTemplateProps, | ||
ArrayFieldTemplateItemType, | ||
FormContextType, | ||
RJSFSchema, | ||
StrictRJSFSchema, | ||
} from '@rjsf/utils'; | ||
import { | ||
Button, | ||
ButtonGroup, | ||
makeStyles, | ||
Step, | ||
StepContent, | ||
StepLabel, | ||
Stepper, | ||
} from '@material-ui/core'; | ||
import { assert } from 'assert-ts'; | ||
import { default as Form } from '@rjsf/core-v5'; | ||
import { useStyles as useFormStyles } from '../styles'; | ||
|
||
const useStyles = makeStyles(theme => ({ | ||
stepper: { | ||
marginBottom: theme.spacing(2), | ||
background: theme.palette.background.default, | ||
'& div[class^="MuiPaper-root"]': { | ||
boxShadow: 'none', | ||
background: theme.palette.background.default, | ||
'& input': { | ||
background: theme.palette.background.paper, | ||
}, | ||
}, | ||
}, | ||
})); | ||
|
||
/** The `ArrayFieldTemplate` component is the template used to render all items in an array. | ||
* | ||
* @param props - The `ArrayFieldTemplateItemType` props for the component | ||
*/ | ||
export default function ArrayFieldTemplate< | ||
T = any, | ||
S extends StrictRJSFSchema = RJSFSchema, | ||
F extends FormContextType = any, | ||
>(props: ArrayFieldTemplateProps<T, S, F>) { | ||
const { | ||
idSchema, | ||
uiSchema, | ||
items, | ||
registry, | ||
required, | ||
schema, | ||
title, | ||
formContext, | ||
} = props; | ||
const uiOptions = getUiOptions(uiSchema); | ||
|
||
const ArrayFieldTitleTemplate = getTemplate< | ||
'ArrayFieldTitleTemplate', | ||
T, | ||
S, | ||
F | ||
>('ArrayFieldTitleTemplate', registry, uiOptions); | ||
|
||
const ArrayFieldItemTemplate = getTemplate<'ArrayFieldItemTemplate', T, S, F>( | ||
'ArrayFieldItemTemplate', | ||
registry, | ||
uiOptions, | ||
); | ||
const [activeItem, setActiveItem] = useState(0); | ||
|
||
const form = formContext?.form?.current as Form; | ||
|
||
const handleNext = useCallback(() => { | ||
assert(!!form, 'no form in ArrayFieldTemplate'); | ||
|
||
const isValid = form.validateForm(); | ||
|
||
setTimeout(() => { | ||
if (isValid) { | ||
setActiveItem(prev => prev + 1); | ||
|
||
return; | ||
} | ||
|
||
// find the current array item index to see if we can progress or not | ||
const indexes = form.state.errors.map(error => | ||
Number(error.property?.match(/(\d+)/g)?.[0]), | ||
); | ||
|
||
if (!indexes.includes(activeItem)) { | ||
setActiveItem(prev => prev + 1); | ||
} | ||
}); | ||
}, [activeItem, form]); | ||
|
||
const styles = useStyles(); | ||
const formStyles = useFormStyles(); | ||
|
||
return ( | ||
<> | ||
<ArrayFieldTitleTemplate | ||
idSchema={idSchema} | ||
title={uiOptions.title || title} | ||
schema={schema} | ||
uiSchema={uiSchema} | ||
required={required} | ||
registry={registry} | ||
/> | ||
<Stepper | ||
activeStep={activeItem} | ||
orientation="vertical" | ||
className={styles.stepper} | ||
> | ||
{items && | ||
items.map( | ||
( | ||
{ key, ...itemProps }: ArrayFieldTemplateItemType<T, S, F>, | ||
index, | ||
) => { | ||
return ( | ||
<Step key={key}> | ||
<StepLabel | ||
StepIconProps={{ icon: String.fromCharCode(65 + index) }} | ||
className={formStyles.stepLabel} | ||
> | ||
{uiOptions.title || itemProps.schema.title} | ||
</StepLabel> | ||
<StepContent key={key}> | ||
<> | ||
<ArrayFieldItemTemplate key={key} {...itemProps} /> | ||
<ButtonGroup> | ||
<Button | ||
disabled={activeItem === 0} | ||
className={formStyles.previous} | ||
onClick={() => | ||
setActiveItem(a => (activeItem === 0 ? 0 : a - 1)) | ||
} | ||
> | ||
PREVIOUS | ||
</Button> | ||
<Button | ||
variant="contained" | ||
type="button" | ||
color="primary" | ||
onClick={handleNext} | ||
className={formStyles.next} | ||
> | ||
NEXT | ||
</Button> | ||
</ButtonGroup> | ||
</> | ||
</StepContent> | ||
</Step> | ||
); | ||
}, | ||
)} | ||
</Stepper> | ||
</> | ||
); | ||
} |
2 changes: 1 addition & 1 deletion
2
plugins/parodos/src/components/Form/extensions/Picker/Picker.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { makeStyles } from '@material-ui/core'; | ||
|
||
export const useStyles = makeStyles(theme => ({ | ||
stepLabel: { | ||
'& span': { | ||
fontSize: '1.25rem', | ||
}, | ||
}, | ||
previous: { | ||
border: `1px solid ${theme.palette.primary.main}`, | ||
color: theme.palette.text.primary, | ||
marginRight: theme.spacing(1), | ||
textTransform: 'uppercase', | ||
'&:disabled': { | ||
border: `1px solid ${theme.palette.text.disabled}`, | ||
}, | ||
}, | ||
next: { | ||
paddingRight: theme.spacing(4), | ||
paddingLeft: theme.spacing(4), | ||
}, | ||
backButton: { | ||
marginRight: theme.spacing(1), | ||
}, | ||
buttonContainer: { | ||
marginBottom: theme.spacing(2), | ||
}, | ||
formWrapper: { | ||
padding: theme.spacing(2), | ||
}, | ||
stepper: { | ||
margin: 0, | ||
paddingLeft: theme.spacing(1), | ||
}, | ||
})); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.