diff --git a/packages/app/src/components/SecurityTab/SecurityTab.tsx b/packages/app/src/components/SecurityTab/SecurityTab.tsx
index 2adca3b0ef..af4d66320d 100644
--- a/packages/app/src/components/SecurityTab/SecurityTab.tsx
+++ b/packages/app/src/components/SecurityTab/SecurityTab.tsx
@@ -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
Security
;
+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) => (
+ {error?.message ?? 'Houston we have a problem.'}
+ );
+ const fieldExtensions = useGetCustomFields(props.customExtensionsElement);
+
+ return (
+
+ );
}
diff --git a/plugins/scaffolder/src/next/Router/Router.tsx b/plugins/scaffolder/src/next/Router/Router.tsx
index 784e17dd55..a7bf16e033 100644
--- a/plugins/scaffolder/src/next/Router/Router.tsx
+++ b/plugins/scaffolder/src/next/Router/Router.tsx
@@ -52,7 +52,9 @@ export type NextRouterProps = {
*/
export const Router = (props: PropsWithChildren) => {
const { components: { TemplateCardComponent } = {} } = props;
+
const outlet = useOutlet() || props.children;
+
const customFieldExtensions =
useCustomFieldExtensions(outlet);
const fieldExtensions = [
diff --git a/plugins/scaffolder/src/next/Router/index.ts b/plugins/scaffolder/src/next/Router/index.ts
index dac1db7b3a..b4df375d1d 100644
--- a/plugins/scaffolder/src/next/Router/index.ts
+++ b/plugins/scaffolder/src/next/Router/index.ts
@@ -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';
diff --git a/plugins/scaffolder/src/next/TemplateWizardContent/TemplateWizardContent.tsx b/plugins/scaffolder/src/next/TemplateWizardContent/TemplateWizardContent.tsx
new file mode 100644
index 0000000000..4dfc9be9e5
--- /dev/null
+++ b/plugins/scaffolder/src/next/TemplateWizardContent/TemplateWizardContent.tsx
@@ -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(() => ({
+ 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[];
+ transformErrors?: ErrorTransformer;
+ onComplete: (values: Record) => Promise;
+ 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 (
+
+
+
+ {loading && }
+ {manifest && (
+
+ }
+ noPadding
+ titleTypographyProps={{ component: 'h2' }}
+ >
+
+
+ )}
+
+
+ );
+};
diff --git a/plugins/scaffolder/src/next/TemplateWizardContent/index.ts b/plugins/scaffolder/src/next/TemplateWizardContent/index.ts
new file mode 100644
index 0000000000..3fda3efb4f
--- /dev/null
+++ b/plugins/scaffolder/src/next/TemplateWizardContent/index.ts
@@ -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';
diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx
index c4e8a51e1f..4ff47e41e9 100644
--- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx
+++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx
@@ -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[];
FormProps?: FormProps;
};
-const useStyles = makeStyles(() => ({
- 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) => {
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 ;
- }
+ const onError = () => ;
return (
-
-
-
- {loading && }
- {manifest && (
-
- }
- noPadding
- titleTypographyProps={{ component: 'h2' }}
- >
-
-
- )}
-
-
+
);
};
diff --git a/plugins/scaffolder/src/next/index.ts b/plugins/scaffolder/src/next/index.ts
index 1ca9096459..fd88d57551 100644
--- a/plugins/scaffolder/src/next/index.ts
+++ b/plugins/scaffolder/src/next/index.ts
@@ -18,3 +18,4 @@ export * from './TemplateListPage';
export * from './TemplateWizardPage';
export * from './types';
export * from './routes';
+export * from './TemplateWizardContent';