move TemplateWizardPage content into separate component
Signed-off-by: Paul Cowan <paul.cowan@cutting.scot>
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable no-console */
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
@@ -16,10 +15,30 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { useEntity } from '@backstage/plugin-catalog-react';
|
||||
import {
|
||||
TemplateWizardContent,
|
||||
useGetCustomFields,
|
||||
} from '@backstage/plugin-scaffolder';
|
||||
|
||||
export function SecurityTab(): JSX.Element | null {
|
||||
const entity = useEntity();
|
||||
console.log(entity);
|
||||
return <h1>Security</h1>;
|
||||
interface SecurityTabProps {
|
||||
customExtensionsElement: React.ReactNode;
|
||||
}
|
||||
|
||||
export function SecurityTab(props: SecurityTabProps): JSX.Element | null {
|
||||
// eslint-disable-next-line no-alert
|
||||
const onComplete = async () => alert('success!!!!');
|
||||
const onError = (error: Error | undefined) => (
|
||||
<h2>{error?.message ?? 'Houston we have a problem.'}</h2>
|
||||
);
|
||||
const fieldExtensions = useGetCustomFields(props.customExtensionsElement);
|
||||
|
||||
return (
|
||||
<TemplateWizardContent
|
||||
namespace="default"
|
||||
templateName="docs-template"
|
||||
onComplete={onComplete}
|
||||
onError={onError}
|
||||
customFieldExtensions={fieldExtensions}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,9 @@ export type NextRouterProps = {
|
||||
*/
|
||||
export const Router = (props: PropsWithChildren<NextRouterProps>) => {
|
||||
const { components: { TemplateCardComponent } = {} } = props;
|
||||
|
||||
const outlet = useOutlet() || props.children;
|
||||
|
||||
const customFieldExtensions =
|
||||
useCustomFieldExtensions<NextFieldExtensionOptions>(outlet);
|
||||
const fieldExtensions = [
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { Router } from './Router';
|
||||
export { Router, useGetCustomFields } from './Router';
|
||||
export type { NextRouterProps } from './Router';
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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, { useEffect } from 'react';
|
||||
import {
|
||||
Content,
|
||||
Header,
|
||||
InfoCard,
|
||||
MarkdownContent,
|
||||
Page,
|
||||
Progress,
|
||||
} from '@backstage/core-components';
|
||||
import { stringifyEntityRef } from '@backstage/catalog-model';
|
||||
import { useTemplateParameterSchema } from '../TemplateWizardPage/TemplateWizardPage';
|
||||
import { NextFieldExtensionOptions } from '../../extensions';
|
||||
import type { ErrorTransformer } from '@rjsf/utils';
|
||||
import type { JsonValue } from '@backstage/types';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { errorApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import { Stepper } from '../TemplateWizardPage/Stepper';
|
||||
|
||||
const useStyles = makeStyles<BackstageTheme>(() => ({
|
||||
markdown: {
|
||||
/** to make the styles for React Markdown not leak into the description */
|
||||
'& :first-child': {
|
||||
marginTop: 0,
|
||||
},
|
||||
'& :last-child': {
|
||||
marginBottom: 0,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
export interface TemplateWizardContentProps {
|
||||
namespace: string;
|
||||
templateName: string;
|
||||
customFieldExtensions: NextFieldExtensionOptions<any, any>[];
|
||||
transformErrors?: ErrorTransformer;
|
||||
onComplete: (values: Record<string, JsonValue>) => Promise<void>;
|
||||
onError(error: Error | undefined): JSX.Element | null;
|
||||
}
|
||||
|
||||
export const TemplateWizardContent = (
|
||||
props: TemplateWizardContentProps,
|
||||
): JSX.Element | null => {
|
||||
const styles = useStyles();
|
||||
const templateRef = stringifyEntityRef({
|
||||
kind: 'Template',
|
||||
namespace: props.namespace,
|
||||
name: props.templateName,
|
||||
});
|
||||
|
||||
const errorApi = useApi(errorApiRef);
|
||||
|
||||
const { loading, manifest, error } = useTemplateParameterSchema(templateRef);
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
errorApi.post(new Error(`Failed to load template, ${error}`));
|
||||
}
|
||||
}, [error, errorApi]);
|
||||
|
||||
if (error) {
|
||||
return props.onError(error);
|
||||
}
|
||||
|
||||
return (
|
||||
<Page themeId="website">
|
||||
<Header
|
||||
pageTitleOverride="Create a new component"
|
||||
title="Create a new component"
|
||||
subtitle="Create new software components using standard templates in your organization"
|
||||
/>
|
||||
<Content>
|
||||
{loading && <Progress />}
|
||||
{manifest && (
|
||||
<InfoCard
|
||||
title={manifest.title}
|
||||
subheader={
|
||||
<MarkdownContent
|
||||
className={styles.markdown}
|
||||
content={manifest.description ?? 'No description'}
|
||||
/>
|
||||
}
|
||||
noPadding
|
||||
titleTypographyProps={{ component: 'h2' }}
|
||||
>
|
||||
<Stepper
|
||||
manifest={manifest}
|
||||
extensions={props.customFieldExtensions}
|
||||
onComplete={props.onComplete}
|
||||
transformErrors={props.transformErrors}
|
||||
/>
|
||||
</InfoCard>
|
||||
)}
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* 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 { TemplateWizardContent } from './TemplateWizardContent';
|
||||
@@ -13,20 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React, { useEffect } from 'react';
|
||||
import {
|
||||
Page,
|
||||
Header,
|
||||
Content,
|
||||
Progress,
|
||||
InfoCard,
|
||||
MarkdownContent,
|
||||
} from '@backstage/core-components';
|
||||
import React from 'react';
|
||||
import { Navigate, useNavigate } from 'react-router-dom';
|
||||
import { stringifyEntityRef } from '@backstage/catalog-model';
|
||||
import {
|
||||
AnalyticsContext,
|
||||
errorApiRef,
|
||||
useApi,
|
||||
useRouteRef,
|
||||
useRouteRefParams,
|
||||
@@ -34,37 +25,21 @@ import {
|
||||
import {
|
||||
scaffolderApiRef,
|
||||
useTemplateSecrets,
|
||||
} from '@backstage/plugin-scaffolder-react';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import {
|
||||
Stepper,
|
||||
NextFieldExtensionOptions,
|
||||
} from '@backstage/plugin-scaffolder-react';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { FormProps } from '../types';
|
||||
import { nextRouteRef } from '../routes';
|
||||
import { scaffolderTaskRouteRef, selectedTemplateRouteRef } from '../../routes';
|
||||
import { TemplateWizardContent } from '../TemplateWizardContent/TemplateWizardContent';
|
||||
|
||||
type TemplateWizardPageProps = {
|
||||
customFieldExtensions: NextFieldExtensionOptions<any, any>[];
|
||||
FormProps?: FormProps;
|
||||
};
|
||||
|
||||
const useStyles = makeStyles<BackstageTheme>(() => ({
|
||||
markdown: {
|
||||
/** to make the styles for React Markdown not leak into the description */
|
||||
'& :first-child': {
|
||||
marginTop: 0,
|
||||
},
|
||||
'& :last-child': {
|
||||
marginBottom: 0,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const useTemplateParameterSchema = (templateRef: string) => {
|
||||
export const useTemplateParameterSchema = (templateRef: string) => {
|
||||
const scaffolderApi = useApi(scaffolderApiRef);
|
||||
const { value, loading, error } = useAsync(
|
||||
() => scaffolderApi.getTemplateParameterSchema(templateRef),
|
||||
@@ -75,7 +50,6 @@ const useTemplateParameterSchema = (templateRef: string) => {
|
||||
};
|
||||
|
||||
export const TemplateWizardPage = (props: TemplateWizardPageProps) => {
|
||||
const styles = useStyles();
|
||||
const rootRef = useRouteRef(nextRouteRef);
|
||||
const taskRoute = useRouteRef(scaffolderTaskRouteRef);
|
||||
const { secrets } = useTemplateSecrets();
|
||||
@@ -91,9 +65,6 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => {
|
||||
name: templateName,
|
||||
});
|
||||
|
||||
const errorApi = useApi(errorApiRef);
|
||||
const { loading, manifest, error } = useTemplateParameterSchema(templateRef);
|
||||
|
||||
const onComplete = async (values: Record<string, JsonValue>) => {
|
||||
const { taskId } = await scaffolderApi.scaffold({
|
||||
templateRef,
|
||||
@@ -104,48 +75,17 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => {
|
||||
navigate(taskRoute({ taskId }));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
errorApi.post(new Error(`Failed to load template, ${error}`));
|
||||
}
|
||||
}, [error, errorApi]);
|
||||
|
||||
if (error) {
|
||||
return <Navigate to={rootRef()} />;
|
||||
}
|
||||
const onError = () => <Navigate to={rootRef()} />;
|
||||
|
||||
return (
|
||||
<AnalyticsContext attributes={{ entityRef: templateRef }}>
|
||||
<Page themeId="website">
|
||||
<Header
|
||||
pageTitleOverride="Create a new component"
|
||||
title="Create a new component"
|
||||
subtitle="Create new software components using standard templates in your organization"
|
||||
/>
|
||||
<Content>
|
||||
{loading && <Progress />}
|
||||
{manifest && (
|
||||
<InfoCard
|
||||
title={manifest.title}
|
||||
subheader={
|
||||
<MarkdownContent
|
||||
className={styles.markdown}
|
||||
content={manifest.description ?? 'No description'}
|
||||
/>
|
||||
}
|
||||
noPadding
|
||||
titleTypographyProps={{ component: 'h2' }}
|
||||
>
|
||||
<Stepper
|
||||
manifest={manifest}
|
||||
extensions={props.customFieldExtensions}
|
||||
onComplete={onComplete}
|
||||
FormProps={props.FormProps}
|
||||
/>
|
||||
</InfoCard>
|
||||
)}
|
||||
</Content>
|
||||
</Page>
|
||||
<TemplateWizardContent
|
||||
namespace={namespace}
|
||||
templateName={templateName}
|
||||
onComplete={onComplete}
|
||||
onError={onError}
|
||||
customFieldExtensions={props.customFieldExtensions}
|
||||
/>
|
||||
</AnalyticsContext>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -18,3 +18,4 @@ export * from './TemplateListPage';
|
||||
export * from './TemplateWizardPage';
|
||||
export * from './types';
|
||||
export * from './routes';
|
||||
export * from './TemplateWizardContent';
|
||||
|
||||
Reference in New Issue
Block a user