diff --git a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx index e7c56378a7..ff6782c512 100644 --- a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx +++ b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx @@ -23,11 +23,17 @@ import { import { stringifyEntityRef } from '@backstage/catalog-model'; import { makeStyles } from '@material-ui/core'; import { BackstageTheme } from '@backstage/theme'; -import { errorApiRef, useApi } from '@backstage/core-plugin-api'; +import { + errorApiRef, + useApi, + featureFlagsApiRef, +} from '@backstage/core-plugin-api'; import { useTemplateParameterSchema } from '../../hooks/useTemplateParameterSchema'; import { Stepper, type StepperProps } from '../Stepper/Stepper'; import { SecretsContextProvider } from '../../../secrets/SecretsContext'; import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; +import cloneDeep from 'lodash/cloneDeep'; +import { useMemo, useCallback } from 'react'; const useStyles = makeStyles(() => ({ markdown: { @@ -81,6 +87,64 @@ export const Workflow = (workflowProps: WorkflowProps): JSX.Element | null => { const { loading, manifest, error } = useTemplateParameterSchema(templateRef); + const featureFlagKey = 'backstage:featureFlag'; + const featureFlagApi = useApi(featureFlagsApiRef); + + // return manifest with updates steps + const filterOutStepProperties = useCallback(() => { + if (manifest) { + const filteredSteps = manifest.steps + .filter(step => { + const featureFlag = step.schema[featureFlagKey]; + return ( + typeof featureFlag !== 'string' || + featureFlagApi.isActive(featureFlag) + ); + }) + .map(step => { + const filteredStep = cloneDeep(step); + const removedPropertyKeys: Array = []; + if (filteredStep.schema.properties) { + filteredStep.schema.properties = Object.fromEntries( + Object.entries(filteredStep.schema.properties).filter( + ([key, value]) => { + if (value[featureFlagKey]) { + if (featureFlagApi.isActive(value[featureFlagKey])) { + return true; + } + + removedPropertyKeys.push(key); + return false; + } + return true; + }, + ), + ); + + // remove the feature flag property key from required if they are not active + filteredStep.schema.required = Array.isArray( + filteredStep.schema.required, + ) + ? filteredStep.schema.required?.filter( + r => !removedPropertyKeys.includes(r as string), + ) + : filteredStep.schema.required; + } + + return filteredStep; + }); + + return { ...manifest, steps: filteredSteps }; + } + + return manifest; + }, [manifest, featureFlagKey, featureFlagApi]); + + const sortedManifest = useMemo( + () => filterOutStepProperties(), + [filterOutStepProperties], + ); + useEffect(() => { if (error) { errorApi.post(new Error(`Failed to load template, ${error}`)); @@ -94,19 +158,25 @@ export const Workflow = (workflowProps: WorkflowProps): JSX.Element | null => { return ( {loading && } - {manifest && ( + {sortedManifest && ( } noPadding titleTypographyProps={{ component: 'h2' }} > - + )}