chore: use the existing secrets provider otherwise existing fields wont work
Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
@@ -16,7 +16,6 @@
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
import { Routes, Route, useOutlet } from 'react-router';
|
||||
import { TemplateListPage } from '../TemplateListPage';
|
||||
import { SecretsContextProvider } from '../TemplateWizardPage/SecretsContext';
|
||||
import { TemplateWizardPage } from '../TemplateWizardPage';
|
||||
import {
|
||||
FieldExtensionOptions,
|
||||
@@ -29,6 +28,7 @@ import { useElementFilter } from '@backstage/core-plugin-api';
|
||||
import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
|
||||
import { TemplateGroupFilter } from '../TemplateListPage/TemplateGroups';
|
||||
import { nextSelectedTemplateRouteRef } from '../../routes';
|
||||
import { SecretsContextProvider } from '../../components/secrets/SecretsContext';
|
||||
|
||||
/**
|
||||
* The Props for the Scaffolder Router
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 React, { useContext } from 'react';
|
||||
import {
|
||||
useTemplateSecrets,
|
||||
SecretsContextProvider,
|
||||
SecretsContext,
|
||||
} from './SecretsContext';
|
||||
import { renderHook, act } from '@testing-library/react-hooks';
|
||||
|
||||
describe('SecretsContext', () => {
|
||||
it('should allow the setting of secrets in the context', async () => {
|
||||
const { result } = renderHook(
|
||||
() => ({
|
||||
hook: useTemplateSecrets(),
|
||||
context: useContext(SecretsContext),
|
||||
}),
|
||||
{
|
||||
wrapper: ({ children }) => (
|
||||
<SecretsContextProvider>{children}</SecretsContextProvider>
|
||||
),
|
||||
},
|
||||
);
|
||||
expect(result.current.context?.secrets.foo).toEqual(undefined);
|
||||
|
||||
act(() => result.current.hook.setSecret({ foo: 'bar' }));
|
||||
|
||||
expect(result.current.context?.secrets.foo).toEqual('bar');
|
||||
});
|
||||
});
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 React, {
|
||||
useState,
|
||||
useCallback,
|
||||
useContext,
|
||||
createContext,
|
||||
PropsWithChildren,
|
||||
} from 'react';
|
||||
|
||||
type SecretsContextContents = {
|
||||
secrets: Record<string, string>;
|
||||
setSecrets: React.Dispatch<React.SetStateAction<Record<string, string>>>;
|
||||
};
|
||||
|
||||
/**
|
||||
* The actual context object.
|
||||
*/
|
||||
export const SecretsContext = createContext<SecretsContextContents | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
/**
|
||||
* The Context Provider that holds the state for the secrets.
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
export const SecretsContextProvider = ({ children }: PropsWithChildren<{}>) => {
|
||||
const [secrets, setSecrets] = useState<Record<string, string>>({});
|
||||
|
||||
return (
|
||||
<SecretsContext.Provider value={{ secrets, setSecrets }}>
|
||||
{children}
|
||||
</SecretsContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to access the secrets context.
|
||||
* @alpha
|
||||
*/
|
||||
export const useTemplateSecrets = () => {
|
||||
const value = useContext(SecretsContext);
|
||||
if (!value) {
|
||||
throw new Error(
|
||||
'useTemplateSecrets must be used within a SecretsContextProvider',
|
||||
);
|
||||
}
|
||||
|
||||
const { setSecrets } = value;
|
||||
|
||||
const setSecret = useCallback(
|
||||
(input: Record<string, string>) => {
|
||||
setSecrets(currentSecrets => ({ ...currentSecrets, ...input }));
|
||||
},
|
||||
[setSecrets],
|
||||
);
|
||||
|
||||
return { setSecret };
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
export {
|
||||
useTemplateSecrets,
|
||||
SecretsContext,
|
||||
SecretsContextProvider,
|
||||
} from './SecretsContext';
|
||||
@@ -22,7 +22,8 @@ import {
|
||||
} from '@material-ui/core';
|
||||
import { withTheme } from '@rjsf/core';
|
||||
import { Theme as MuiTheme } from '@rjsf/material-ui';
|
||||
import React, { useState } from 'react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { FieldExtensionOptions } from '../../../extensions';
|
||||
import { TemplateParameterSchema } from '../../../types';
|
||||
import { useTemplateSchema } from './useTemplateSchema';
|
||||
|
||||
@@ -42,6 +43,7 @@ const useStyles = makeStyles(theme => ({
|
||||
|
||||
export interface StepperProps {
|
||||
manifest: TemplateParameterSchema;
|
||||
extensions: FieldExtensionOptions<any, any>[];
|
||||
}
|
||||
|
||||
const Form = withTheme(MuiTheme);
|
||||
@@ -50,6 +52,13 @@ export const Stepper = (props: StepperProps) => {
|
||||
const { steps } = useTemplateSchema(props.manifest);
|
||||
const [activeStep, setActiveStep] = useState(0);
|
||||
const styles = useStyles();
|
||||
|
||||
const extensions = useMemo(() => {
|
||||
return Object.fromEntries(
|
||||
props.extensions.map(({ name, component }) => [name, component]),
|
||||
);
|
||||
}, [props.extensions]);
|
||||
|
||||
const handleBack = () => {
|
||||
setActiveStep(prevActiveStep => prevActiveStep - 1);
|
||||
};
|
||||
@@ -69,7 +78,9 @@ export const Stepper = (props: StepperProps) => {
|
||||
<div className={styles.formWrapper}>
|
||||
<Form
|
||||
schema={steps[activeStep].schema}
|
||||
uiSchema={steps[activeStep].uiSchema}
|
||||
onSubmit={handleNext}
|
||||
fields={extensions}
|
||||
showErrorList={false}
|
||||
>
|
||||
<div className={styles.footer}>
|
||||
|
||||
@@ -23,14 +23,15 @@ import {
|
||||
MarkdownContent,
|
||||
} from '@backstage/core-components';
|
||||
import { FieldExtensionOptions } from '../../extensions';
|
||||
import { useParams } from 'react-router';
|
||||
import { Navigate, useParams } from 'react-router';
|
||||
import { stringifyEntityRef } from '@backstage/catalog-model';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { errorApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api';
|
||||
import { scaffolderApiRef } from '../../api';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import { Stepper } from './Stepper';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { nextRouteRef } from '../../routes';
|
||||
|
||||
export interface TemplateWizardPageProps {
|
||||
customFieldExtensions: FieldExtensionOptions<any, any>[];
|
||||
@@ -58,9 +59,11 @@ const useTemplateParameterSchema = (templateRef: string) => {
|
||||
return { manifest: value, loading, error };
|
||||
};
|
||||
|
||||
export const TemplateWizardPage = (_props: TemplateWizardPageProps) => {
|
||||
export const TemplateWizardPage = (props: TemplateWizardPageProps) => {
|
||||
const styles = useStyles();
|
||||
const rootRef = useRouteRef(nextRouteRef);
|
||||
const { templateName, namespace } = useParams();
|
||||
const errorApi = useApi(errorApiRef);
|
||||
const { loading, manifest, error } = useTemplateParameterSchema(
|
||||
stringifyEntityRef({
|
||||
kind: 'Template',
|
||||
@@ -69,6 +72,11 @@ export const TemplateWizardPage = (_props: TemplateWizardPageProps) => {
|
||||
}),
|
||||
);
|
||||
|
||||
if (error) {
|
||||
errorApi.post(new Error(`Failed to load template, ${error}`));
|
||||
return <Navigate to={rootRef()} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Page themeId="website">
|
||||
<Header
|
||||
@@ -90,7 +98,10 @@ export const TemplateWizardPage = (_props: TemplateWizardPageProps) => {
|
||||
noPadding
|
||||
titleTypographyProps={{ component: 'h2' }}
|
||||
>
|
||||
<Stepper manifest={manifest} fields={{}} widgets={{}} />
|
||||
<Stepper
|
||||
manifest={manifest}
|
||||
extensions={props.customFieldExtensions}
|
||||
/>
|
||||
</InfoCard>
|
||||
)}
|
||||
</Content>
|
||||
|
||||
Reference in New Issue
Block a user