From 912bd110f23b28ba1eab9c6230decb7a88cc119b Mon Sep 17 00:00:00 2001 From: blam Date: Wed, 4 Jan 2023 23:20:28 +0100 Subject: [PATCH] chore: move the routeRefs back into the scaffolder plugin for now, maybe it makes sense to move them later. Signed-off-by: blam --- plugins/scaffolder-react/src/index.ts | 1 - .../src/next/components/Stepper/Stepper.tsx | 15 ++-- .../TemplateCard/TemplateCard.test.tsx | 7 -- .../components/TemplateCard/TemplateCard.tsx | 63 +++++---------- .../TemplateGroup/TemplateGroup.tsx | 27 ++++++- plugins/scaffolder-react/src/next/index.ts | 1 - .../ActionsPage/ActionsPage.test.tsx | 2 +- .../ListTasksPage/ListTaskPage.test.tsx | 2 +- .../ListTasksPage/ListTasksPage.tsx | 2 +- .../MultistepJsonForm/MultistepJsonForm.tsx | 6 +- plugins/scaffolder/src/components/Router.tsx | 14 ++-- .../ScaffolderPage/ScaffolderPage.tsx | 2 +- .../ScaffolderPageContextMenu.test.tsx | 2 +- .../ScaffolderPageContextMenu.tsx | 2 +- .../src/components/TaskPage/TaskPage.tsx | 8 +- .../components/TemplateCard/TemplateCard.tsx | 5 +- .../TemplatePage/TemplatePage.test.tsx | 2 +- .../components/TemplatePage/TemplatePage.tsx | 8 +- plugins/scaffolder/src/components/index.ts | 2 +- plugins/scaffolder/src/deprecated.ts | 12 --- plugins/scaffolder/src/index.ts | 18 +++-- plugins/scaffolder/src/next/Router/Router.tsx | 3 +- .../next/TemplateListPage/TemplateGroups.tsx | 76 +++++++++++++++---- .../TemplateListPage.test.tsx | 2 +- .../TemplateListPage/TemplateListPage.tsx | 2 +- .../TemplateWizardPage.test.tsx | 4 +- .../TemplateWizardPage/TemplateWizardPage.tsx | 5 +- plugins/scaffolder/src/next/index.ts | 1 + .../src/next/routes.ts | 0 plugins/scaffolder/src/plugin.tsx | 10 ++- .../src/routes.ts | 0 31 files changed, 169 insertions(+), 135 deletions(-) rename plugins/{scaffolder-react => scaffolder}/src/next/routes.ts (100%) rename plugins/{scaffolder-react => scaffolder}/src/routes.ts (100%) diff --git a/plugins/scaffolder-react/src/index.ts b/plugins/scaffolder-react/src/index.ts index 14bcb1e44f..a2336a5ca5 100644 --- a/plugins/scaffolder-react/src/index.ts +++ b/plugins/scaffolder-react/src/index.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -export * from './routes'; export * from './extensions'; export * from './types'; export * from './secrets'; diff --git a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx index 8ff4646d1c..05345c34b5 100644 --- a/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx +++ b/plugins/scaffolder-react/src/next/components/Stepper/Stepper.tsx @@ -13,11 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { - useAnalytics, - useApiHolder, - useRouteRefParams, -} from '@backstage/core-plugin-api'; +import { useAnalytics, useApiHolder } from '@backstage/core-plugin-api'; import { JsonValue } from '@backstage/types'; import { Stepper as MuiStepper, @@ -35,7 +31,7 @@ import { createAsyncValidators } from './createAsyncValidators'; import { useTemplateSchema } from '../../hooks/useTemplateSchema'; import { ReviewState } from '../ReviewState'; import validator from '@rjsf/validator-ajv6'; -import { selectedTemplateRouteRef } from '../../../routes'; + import { useFormData } from '../../hooks/useFormData'; import { FormProps } from '../../types'; @@ -61,8 +57,10 @@ const useStyles = makeStyles(theme => ({ export type StepperProps = { manifest: TemplateParameterSchema; extensions: NextFieldExtensionOptions[]; - onComplete: (values: Record) => Promise; + templateName?: string; FormProps?: FormProps; + + onComplete: (values: Record) => Promise; }; // TODO(blam): We require here, as the types in this package depend on @rjsf/core explicitly @@ -75,7 +73,6 @@ const Form = withTheme(require('@rjsf/material-ui-v5').Theme); * @alpha */ export const Stepper = (props: StepperProps) => { - const { templateName } = useRouteRefParams(selectedTemplateRouteRef); const analytics = useAnalytics(); const { steps } = useTemplateSchema(props.manifest); const apiHolder = useApiHolder(); @@ -204,7 +201,7 @@ export const Stepper = (props: StepperProps) => { : undefined; analytics.captureEvent( 'create', - name || `new ${templateName}`, + name ?? props.templateName ?? 'unknown', ); }} > diff --git a/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.test.tsx b/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.test.tsx index 228d8af4e3..f2e2cae8c6 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.test.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.test.tsx @@ -27,7 +27,6 @@ import { TemplateCard } from './TemplateCard'; import React from 'react'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; import { RELATION_OWNED_BY } from '@backstage/catalog-model'; -import { nextRouteRef } from '../../routes'; describe('TemplateCard', () => { it('should render the card title', async () => { @@ -54,7 +53,6 @@ describe('TemplateCard', () => { > , - { mountedRoutes: { '/': nextRouteRef } }, ); expect(getByText('bob')).toBeInTheDocument(); @@ -84,7 +82,6 @@ describe('TemplateCard', () => { > , - { mountedRoutes: { '/': nextRouteRef } }, ); const description = getByText('hello'); @@ -115,7 +112,6 @@ describe('TemplateCard', () => { > , - { mountedRoutes: { '/': nextRouteRef } }, ); expect(getByText('No description')).toBeInTheDocument(); @@ -145,7 +141,6 @@ describe('TemplateCard', () => { > , - { mountedRoutes: { '/': nextRouteRef } }, ); for (const tag of mockTemplate.metadata.tags!) { @@ -185,7 +180,6 @@ describe('TemplateCard', () => { , { mountedRoutes: { - '/': nextRouteRef, '/catalog/:kind/:namespace/:name': entityRouteRef, }, }, @@ -224,7 +218,6 @@ describe('TemplateCard', () => { , { mountedRoutes: { - '/': nextRouteRef, '/catalog/:kind/:namespace/:name': entityRouteRef, }, }, diff --git a/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.tsx b/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.tsx index 1176b01e5d..6f89808405 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.tsx @@ -13,14 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { - DEFAULT_NAMESPACE, - parseEntityRef, - RELATION_OWNED_BY, - stringifyEntityRef, -} from '@backstage/catalog-model'; -import { Button, MarkdownContent, UserIcon } from '@backstage/core-components'; -import { IconComponent, useApp, useRouteRef } from '@backstage/core-plugin-api'; +import { RELATION_OWNED_BY } from '@backstage/catalog-model'; +import { MarkdownContent, UserIcon } from '@backstage/core-components'; +import { IconComponent, useApp } from '@backstage/core-plugin-api'; import { EntityRefLinks, getEntityRelations, @@ -34,13 +29,12 @@ import { CardContent, Chip, Divider, + Button, Grid, makeStyles, } from '@material-ui/core'; import LanguageIcon from '@material-ui/icons/Language'; import React from 'react'; -import { nextSelectedTemplateRouteRef } from '../../routes'; -import { viewTechDocRouteRef } from '../../../routes'; import { CardHeader } from './CardHeader'; import { CardLink } from './CardLink'; @@ -86,7 +80,13 @@ const useStyles = makeStyles(theme => ({ */ export interface TemplateCardProps { template: TemplateEntityV1beta3; - deprecated?: boolean; + additionalLinks?: { + icon: IconComponent; + text: string; + url: string; + }[]; + + onSelected?: (template: TemplateEntityV1beta3) => void; } /** @@ -97,32 +97,10 @@ export const TemplateCard = (props: TemplateCardProps) => { const { template } = props; const styles = useStyles(); const ownedByRelations = getEntityRelations(template, RELATION_OWNED_BY); - const templateRoute = useRouteRef(nextSelectedTemplateRouteRef); - const { name, namespace } = parseEntityRef( - stringifyEntityRef(props.template), - ); - const href = templateRoute({ - templateName: name, - namespace: namespace, - }); - const app = useApp(); const iconResolver = (key?: string): IconComponent => key ? app.getSystemIcon(key) ?? LanguageIcon : LanguageIcon; - // TechDocs Link - const viewTechDoc = useRouteRef(viewTechDocRouteRef); - const viewTechDocsAnnotation = - template.metadata.annotations?.['backstage.io/techdocs-ref']; - const viewTechDocsLink = - !!viewTechDocsAnnotation && - !!viewTechDoc && - viewTechDoc({ - namespace: template.metadata.namespace || DEFAULT_NAMESPACE, - kind: template.kind, - name: template.metadata.name, - }); - return ( @@ -157,22 +135,18 @@ export const TemplateCard = (props: TemplateCardProps) => { )} - {(!!viewTechDocsLink || template.metadata.links?.length) && ( + {(props.additionalLinks || template.metadata.links?.length) && ( <> - {viewTechDocsLink && ( + {props.additionalLinks?.map(({ icon, text, url }) => ( - + - )} + ))} {template.metadata.links?.map(({ url, icon, title }) => ( { )} - diff --git a/plugins/scaffolder-react/src/next/components/TemplateGroup/TemplateGroup.tsx b/plugins/scaffolder-react/src/next/components/TemplateGroup/TemplateGroup.tsx index 74d9242041..8134ea256d 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateGroup/TemplateGroup.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateGroup/TemplateGroup.tsx @@ -24,13 +24,22 @@ import { import { Typography } from '@material-ui/core'; import { stringifyEntityRef } from '@backstage/catalog-model'; import { TemplateCardProps, TemplateCard } from '../TemplateCard'; +import { IconComponent } from '@backstage/core-plugin-api'; /** * The props for the {@link TemplateGroup} component. * @alpha */ export interface TemplateGroupProps { - templates: TemplateEntityV1beta3[]; + templates: { + template: TemplateEntityV1beta3; + additionalLinks?: { + icon: IconComponent; + text: string; + url: string; + }[]; + }[]; + onSelected: (template: TemplateEntityV1beta3) => void; title: React.ReactNode; components?: { CardComponent?: React.ComponentType; @@ -42,7 +51,12 @@ export interface TemplateGroupProps { * @alpha */ export const TemplateGroup = (props: TemplateGroupProps) => { - const { templates, title, components: { CardComponent } = {} } = props; + const { + templates, + title, + components: { CardComponent } = {}, + onSelected, + } = props; const titleComponent = typeof title === 'string' ? : title; @@ -67,8 +81,13 @@ export const TemplateGroup = (props: TemplateGroupProps) => { {titleComponent} - {templates.map(template => ( - + {templates.map(({ template, additionalLinks }) => ( + ))} diff --git a/plugins/scaffolder-react/src/next/index.ts b/plugins/scaffolder-react/src/next/index.ts index fe12e38ad9..a18649f506 100644 --- a/plugins/scaffolder-react/src/next/index.ts +++ b/plugins/scaffolder-react/src/next/index.ts @@ -18,4 +18,3 @@ export * from './extensions'; export * from './types'; export * from './lib'; export * from './hooks'; -export * from './routes'; diff --git a/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx b/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx index a049959ae4..552d0cea6a 100644 --- a/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx +++ b/plugins/scaffolder/src/components/ActionsPage/ActionsPage.test.tsx @@ -16,12 +16,12 @@ import React from 'react'; import { ActionsPage } from './ActionsPage'; import { - rootRouteRef, scaffolderApiRef, ScaffolderApi, } from '@backstage/plugin-scaffolder-react'; import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils'; import { ApiProvider } from '@backstage/core-app-api'; +import { rootRouteRef } from '../../routes'; const scaffolderApiMock: jest.Mocked = { scaffold: jest.fn(), diff --git a/plugins/scaffolder/src/components/ListTasksPage/ListTaskPage.test.tsx b/plugins/scaffolder/src/components/ListTasksPage/ListTaskPage.test.tsx index 4843d9bcc0..b9c5a84da3 100644 --- a/plugins/scaffolder/src/components/ListTasksPage/ListTaskPage.test.tsx +++ b/plugins/scaffolder/src/components/ListTasksPage/ListTaskPage.test.tsx @@ -25,11 +25,11 @@ import React from 'react'; import { identityApiRef } from '@backstage/core-plugin-api'; import { ListTasksPage } from './ListTasksPage'; import { - rootRouteRef, scaffolderApiRef, ScaffolderApi, } from '@backstage/plugin-scaffolder-react'; import { act, fireEvent } from '@testing-library/react'; +import { rootRouteRef } from '../../routes'; describe('', () => { const catalogApi: jest.Mocked = { diff --git a/plugins/scaffolder/src/components/ListTasksPage/ListTasksPage.tsx b/plugins/scaffolder/src/components/ListTasksPage/ListTasksPage.tsx index 68dcedc99f..1edac508d8 100644 --- a/plugins/scaffolder/src/components/ListTasksPage/ListTasksPage.tsx +++ b/plugins/scaffolder/src/components/ListTasksPage/ListTasksPage.tsx @@ -29,7 +29,6 @@ import { CatalogFilterLayout } from '@backstage/plugin-catalog-react'; import useAsync from 'react-use/lib/useAsync'; import React, { useState } from 'react'; import { - rootRouteRef, ScaffolderTask, scaffolderApiRef, } from '@backstage/plugin-scaffolder-react'; @@ -40,6 +39,7 @@ import { TaskStatusColumn, TemplateTitleColumn, } from './columns'; +import { rootRouteRef } from '../../routes'; export interface MyTaskPageProps { initiallySelectedFilter?: 'owned' | 'all'; diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx b/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx index 65db4217be..ed8471ec1e 100644 --- a/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx +++ b/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx @@ -39,10 +39,8 @@ import * as fieldOverrides from './FieldOverrides'; import { LayoutOptions } from '../../layouts'; import { ReviewStepProps } from '../types'; import { ReviewStep } from './ReviewStep'; -import { - selectedTemplateRouteRef, - extractSchemaFromStep, -} from '@backstage/plugin-scaffolder-react'; +import { extractSchemaFromStep } from '@backstage/plugin-scaffolder-react'; +import { selectedTemplateRouteRef } from '../../routes'; const Form = withTheme(MuiTheme); diff --git a/plugins/scaffolder/src/components/Router.tsx b/plugins/scaffolder/src/components/Router.tsx index fefb550aa7..287342007b 100644 --- a/plugins/scaffolder/src/components/Router.tsx +++ b/plugins/scaffolder/src/components/Router.tsx @@ -30,12 +30,6 @@ import { useRouteRefParams, } from '@backstage/core-plugin-api'; import { - actionsRouteRef, - editRouteRef, - legacySelectedTemplateRouteRef, - scaffolderListTaskRouteRef, - scaffolderTaskRouteRef, - selectedTemplateRouteRef, FIELD_EXTENSION_KEY, FIELD_EXTENSION_WRAPPER_KEY, FieldExtensionOptions, @@ -44,6 +38,14 @@ import { import { ListTasksPage } from './ListTasksPage'; import { LayoutOptions, LAYOUTS_KEY, LAYOUTS_WRAPPER_KEY } from '../layouts'; import { ReviewStepProps } from './types'; +import { + actionsRouteRef, + editRouteRef, + legacySelectedTemplateRouteRef, + scaffolderListTaskRouteRef, + scaffolderTaskRouteRef, + selectedTemplateRouteRef, +} from '../routes'; /** * The props for the entrypoint `ScaffolderPage` component the plugin. diff --git a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx b/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx index 7306ae8fd4..50221f3a83 100644 --- a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx +++ b/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx @@ -34,12 +34,12 @@ import { UserListPicker, } from '@backstage/plugin-catalog-react'; import React, { ComponentType } from 'react'; -import { registerComponentRouteRef } from '@backstage/plugin-scaffolder-react'; import { TemplateList } from '../TemplateList'; import { TemplateTypePicker } from '../TemplateTypePicker'; import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common'; import { usePermission } from '@backstage/plugin-permission-react'; import { ScaffolderPageContextMenu } from './ScaffolderPageContextMenu'; +import { registerComponentRouteRef } from '../../routes'; export type ScaffolderPageProps = { TemplateCardComponent?: diff --git a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPageContextMenu.test.tsx b/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPageContextMenu.test.tsx index d9993c16e7..66513591d0 100644 --- a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPageContextMenu.test.tsx +++ b/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPageContextMenu.test.tsx @@ -18,8 +18,8 @@ import userEvent from '@testing-library/user-event'; import { renderInTestApp } from '@backstage/test-utils'; import { screen } from '@testing-library/react'; import React from 'react'; -import { rootRouteRef } from '@backstage/plugin-scaffolder-react'; import { ScaffolderPageContextMenu } from './ScaffolderPageContextMenu'; +import { rootRouteRef } from '../../routes'; describe('ScaffolderPageContextMenu', () => { it('does not render anything if fully disabled', async () => { diff --git a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPageContextMenu.tsx b/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPageContextMenu.tsx index 3c62a34e29..9e69fae68d 100644 --- a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPageContextMenu.tsx +++ b/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPageContextMenu.tsx @@ -32,7 +32,7 @@ import { actionsRouteRef, editRouteRef, scaffolderListTaskRouteRef, -} from '@backstage/plugin-scaffolder-react'; +} from '../../routes'; const useStyles = makeStyles({ button: { diff --git a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx b/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx index 02f27bd0c0..393bd495bf 100644 --- a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx +++ b/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx @@ -48,15 +48,17 @@ import React, { memo, useEffect, useMemo, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import useInterval from 'react-use/lib/useInterval'; import { - rootRouteRef, - scaffolderTaskRouteRef, - selectedTemplateRouteRef, ScaffolderTaskStatus, ScaffolderTaskOutput, } from '@backstage/plugin-scaffolder-react'; import { useTaskEventStream } from '../hooks/useEventStream'; import { TaskErrors } from './TaskErrors'; import { TaskPageLinks } from './TaskPageLinks'; +import { + rootRouteRef, + scaffolderTaskRouteRef, + selectedTemplateRouteRef, +} from '../../routes'; // typings are wrong for this library, so fallback to not parsing types. const humanizeDuration = require('humanize-duration'); diff --git a/plugins/scaffolder/src/components/TemplateCard/TemplateCard.tsx b/plugins/scaffolder/src/components/TemplateCard/TemplateCard.tsx index bf9e022296..984e51f3b5 100644 --- a/plugins/scaffolder/src/components/TemplateCard/TemplateCard.tsx +++ b/plugins/scaffolder/src/components/TemplateCard/TemplateCard.tsx @@ -61,10 +61,7 @@ import { import LanguageIcon from '@material-ui/icons/Language'; import WarningIcon from '@material-ui/icons/Warning'; import React from 'react'; -import { - selectedTemplateRouteRef, - viewTechDocRouteRef, -} from '@backstage/plugin-scaffolder-react'; +import { selectedTemplateRouteRef, viewTechDocRouteRef } from '../../routes'; const useStyles = makeStyles(theme => ({ cardHeader: { diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx index 5de29c42a5..5f43b54534 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx +++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx @@ -23,7 +23,6 @@ import { act, fireEvent, screen, within } from '@testing-library/react'; import React from 'react'; import { Route, Routes } from 'react-router-dom'; import { - rootRouteRef, scaffolderApiRef, ScaffolderApi, } from '@backstage/plugin-scaffolder-react'; @@ -35,6 +34,7 @@ import { } from '@backstage/core-plugin-api'; import { ApiProvider } from '@backstage/core-app-api'; import { errorApiRef } from '@backstage/core-plugin-api'; +import { rootRouteRef } from '../../routes'; jest.mock('react-router-dom', () => { return { diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx index 08254491ce..c1814bf7e9 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx +++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx @@ -20,9 +20,6 @@ import React, { ComponentType, useCallback, useContext, useState } from 'react'; import { Navigate, useNavigate } from 'react-router-dom'; import useAsync from 'react-use/lib/useAsync'; import { - rootRouteRef, - scaffolderTaskRouteRef, - selectedTemplateRouteRef, FieldExtensionOptions, SecretsContext, scaffolderApiRef, @@ -42,6 +39,11 @@ import { import { stringifyEntityRef } from '@backstage/catalog-model'; import { LayoutOptions } from '../../layouts'; import { ReviewStepProps } from '../types'; +import { + rootRouteRef, + scaffolderTaskRouteRef, + selectedTemplateRouteRef, +} from '../../routes'; const useTemplateParameterSchema = (templateRef: string) => { const scaffolderApi = useApi(scaffolderApiRef); diff --git a/plugins/scaffolder/src/components/index.ts b/plugins/scaffolder/src/components/index.ts index 54d3a33d99..a5c17b8ab0 100644 --- a/plugins/scaffolder/src/components/index.ts +++ b/plugins/scaffolder/src/components/index.ts @@ -16,6 +16,6 @@ export * from './fields'; export type { RepoUrlPickerUiOptions } from './fields'; export { TemplateTypePicker } from './TemplateTypePicker'; -export { TaskPage } from './TaskPage'; +export { TaskPage, type TaskPageProps } from './TaskPage'; export type { RouterProps } from './Router'; export type { ReviewStepProps } from './types'; diff --git a/plugins/scaffolder/src/deprecated.ts b/plugins/scaffolder/src/deprecated.ts index 64abbde7a4..41d3568c0b 100644 --- a/plugins/scaffolder/src/deprecated.ts +++ b/plugins/scaffolder/src/deprecated.ts @@ -23,8 +23,6 @@ import { createScaffolderFieldExtension as createScaffolderFieldExtensionTemp, ScaffolderFieldExtensions as ScaffolderFieldExtensionsTemp, - rootRouteRef as rootRouteRefTemp, - selectedTemplateRouteRef as selectedTemplateRouteRefTemp, useTemplateSecrets as useTemplateSecretsTemp, scaffolderApiRef as scaffolderApiRefTemp, type ScaffolderApi as ScaffolderApiTemp, @@ -61,16 +59,6 @@ export const createScaffolderFieldExtension = * @deprecated use import from {@link @backstage/plugin-scaffolder-react#ScaffolderFieldExtensions} instead as this has now been moved. */ export const ScaffolderFieldExtensions = ScaffolderFieldExtensionsTemp; -/** - * @public - * @deprecated use import from {@link @backstage/plugin-scaffolder-react#rootRouteRef} instead as this has now been moved. - */ -export const rootRouteRef = rootRouteRefTemp; -/** - * @public - * @deprecated use import from {@link @backstage/plugin-scaffolder-react#selectedTemplateRouteRef} instead as this has now been moved. - */ -export const selectedTemplateRouteRef = selectedTemplateRouteRefTemp; /** * @public * @deprecated use import from {@link @backstage/plugin-scaffolder-react#useTemplateSecrets} instead as this has now been moved. diff --git a/plugins/scaffolder/src/index.ts b/plugins/scaffolder/src/index.ts index 488ca7d670..b5dd5e5d0d 100644 --- a/plugins/scaffolder/src/index.ts +++ b/plugins/scaffolder/src/index.ts @@ -22,8 +22,14 @@ export { ScaffolderClient } from './api'; -export { createScaffolderLayout, ScaffolderLayouts } from './layouts'; -export type { LayoutOptions, LayoutTemplate, LayoutComponent } from './layouts'; +export { + createScaffolderLayout, + ScaffolderLayouts, + type LayoutOptions, + type LayoutTemplate, + type LayoutComponent, +} from './layouts'; + export { EntityPickerFieldExtension, EntityNamePickerFieldExtension, @@ -34,15 +40,17 @@ export { ScaffolderPage, scaffolderPlugin, } from './plugin'; + export * from './components'; - +export * from './routes'; export * from './deprecated'; -export type { TaskPageProps } from './components/TaskPage'; - /** next exports */ export { NextScaffolderPage } from './plugin'; export { + nextRouteRef, + nextSelectedTemplateRouteRef, + nextScaffolderTaskRouteRef, type TemplateGroupFilter, type NextRouterProps, type FormProps, diff --git a/plugins/scaffolder/src/next/Router/Router.tsx b/plugins/scaffolder/src/next/Router/Router.tsx index 799dd10bca..a9785e6aa6 100644 --- a/plugins/scaffolder/src/next/Router/Router.tsx +++ b/plugins/scaffolder/src/next/Router/Router.tsx @@ -22,7 +22,6 @@ import { FIELD_EXTENSION_KEY, NextFieldExtensionOptions, FieldExtensionOptions, - nextSelectedTemplateRouteRef, SecretsContextProvider, } from '@backstage/plugin-scaffolder-react'; @@ -31,6 +30,7 @@ import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateGroupFilter } from '../TemplateListPage/TemplateGroups'; import { DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from '../../extensions/default'; import { FormProps } from '../types'; +import { nextSelectedTemplateRouteRef } from '../routes'; /** * The Props for the Scaffolder Router @@ -58,6 +58,7 @@ export const Router = (props: PropsWithChildren) => { const outlet = useOutlet() || props.children; + // todo(blam): move this out into a `useFieldExtensions` hook exported by -react const customFieldExtensions = useElementFilter(outlet, elements => elements .selectByComponentData({ diff --git a/plugins/scaffolder/src/next/TemplateListPage/TemplateGroups.tsx b/plugins/scaffolder/src/next/TemplateListPage/TemplateGroups.tsx index e502bfd9a7..485b0e40cd 100644 --- a/plugins/scaffolder/src/next/TemplateListPage/TemplateGroups.tsx +++ b/plugins/scaffolder/src/next/TemplateListPage/TemplateGroups.tsx @@ -13,15 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React from 'react'; +import React, { useCallback } from 'react'; -import { Entity } from '@backstage/catalog-model'; +import { + Entity, + parseEntityRef, + stringifyEntityRef, +} from '@backstage/catalog-model'; import { useEntityList } from '@backstage/plugin-catalog-react'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; -import { Progress, Link } from '@backstage/core-components'; +import { Progress, Link, DocsIcon } from '@backstage/core-components'; import { Typography } from '@material-ui/core'; -import { errorApiRef, useApi } from '@backstage/core-plugin-api'; +import { + errorApiRef, + useApi, + useApp, + useRouteRef, +} from '@backstage/core-plugin-api'; import { TemplateGroup } from '@backstage/plugin-scaffolder-react'; +import { viewTechDocRouteRef } from '../../routes'; +import { nextSelectedTemplateRouteRef } from '../routes'; +import { useNavigate } from 'react-router-dom'; /** * @alpha @@ -42,6 +54,17 @@ export const TemplateGroups = (props: TemplateGroupsProps) => { const { loading, error, entities } = useEntityList(); const { groups, TemplateCardComponent } = props; const errorApi = useApi(errorApiRef); + const app = useApp(); + const viewTechDocsLink = useRouteRef(viewTechDocRouteRef); + const templateRoute = useRouteRef(nextSelectedTemplateRouteRef); + const navigate = useNavigate(); + const onSelected = useCallback( + (template: TemplateEntityV1beta3) => { + const { namespace, name } = parseEntityRef(stringifyEntityRef(template)); + navigate(templateRoute({ namespace, templateName: name })); + }, + [navigate, templateRoute], + ); if (loading) { return ; @@ -66,16 +89,41 @@ export const TemplateGroups = (props: TemplateGroupsProps) => { return ( <> - {groups.map(({ title, filter }, index) => ( - - filter(e), - )} - title={title} - components={{ CardComponent: TemplateCardComponent }} - /> - ))} + {groups.map(({ title, filter }, index) => { + const templates = entities + .filter((e): e is TemplateEntityV1beta3 => filter(e)) + .map(template => { + const { kind, namespace, name } = parseEntityRef( + stringifyEntityRef(template), + ); + const additionalLinks = + template.metadata.annotations?.['backstage.io/techdocs-ref'] && + viewTechDocsLink + ? [ + { + icon: app.getSystemIcon('docs') ?? DocsIcon, + text: 'View TechDocs', + url: viewTechDocsLink({ kind, namespace, name }), + }, + ] + : []; + + return { + template, + additionalLinks, + }; + }); + + return ( + + ); + })} ); }; diff --git a/plugins/scaffolder/src/next/TemplateListPage/TemplateListPage.test.tsx b/plugins/scaffolder/src/next/TemplateListPage/TemplateListPage.test.tsx index 16beeabd32..41e7897819 100644 --- a/plugins/scaffolder/src/next/TemplateListPage/TemplateListPage.test.tsx +++ b/plugins/scaffolder/src/next/TemplateListPage/TemplateListPage.test.tsx @@ -25,7 +25,7 @@ import { TestApiProvider, } from '@backstage/test-utils'; import React from 'react'; -import { nextRouteRef } from '@backstage/plugin-scaffolder-react'; +import { nextRouteRef } from '../routes'; import { TemplateListPage } from './TemplateListPage'; describe('TemplateListPage', () => { diff --git a/plugins/scaffolder/src/next/TemplateListPage/TemplateListPage.tsx b/plugins/scaffolder/src/next/TemplateListPage/TemplateListPage.tsx index bb77ed6479..4eae84b866 100644 --- a/plugins/scaffolder/src/next/TemplateListPage/TemplateListPage.tsx +++ b/plugins/scaffolder/src/next/TemplateListPage/TemplateListPage.tsx @@ -35,8 +35,8 @@ import { import { CategoryPicker } from './CategoryPicker'; import { RegisterExistingButton } from './RegisterExistingButton'; import { useRouteRef } from '@backstage/core-plugin-api'; -import { registerComponentRouteRef } from '@backstage/plugin-scaffolder-react'; import { TemplateGroupFilter, TemplateGroups } from './TemplateGroups'; +import { registerComponentRouteRef } from '../../routes'; export type TemplateListPageProps = { TemplateCardComponent?: React.ComponentType<{ diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx index 52b6451862..469354e75f 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx @@ -23,12 +23,12 @@ import { import { act, fireEvent } from '@testing-library/react'; import React from 'react'; import { - nextRouteRef, - rootRouteRef, ScaffolderApi, scaffolderApiRef, } from '@backstage/plugin-scaffolder-react'; import { TemplateWizardPage } from './TemplateWizardPage'; +import { rootRouteRef } from '../../routes'; +import { nextRouteRef } from '../routes'; jest.mock('react-router-dom', () => { return { diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx index e3717befdb..e446f781a2 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx @@ -36,15 +36,14 @@ import useAsync from 'react-use/lib/useAsync'; import { makeStyles } from '@material-ui/core'; import { BackstageTheme } from '@backstage/theme'; import { - nextRouteRef, - scaffolderTaskRouteRef, - selectedTemplateRouteRef, Stepper, NextFieldExtensionOptions, SecretsContext, } from '@backstage/plugin-scaffolder-react'; import { JsonValue } from '@backstage/types'; import { FormProps } from '../types'; +import { nextRouteRef } from '../routes'; +import { scaffolderTaskRouteRef, selectedTemplateRouteRef } from '../../routes'; type TemplateWizardPageProps = { customFieldExtensions: NextFieldExtensionOptions[]; diff --git a/plugins/scaffolder/src/next/index.ts b/plugins/scaffolder/src/next/index.ts index 6cef3eaa03..1ca9096459 100644 --- a/plugins/scaffolder/src/next/index.ts +++ b/plugins/scaffolder/src/next/index.ts @@ -17,3 +17,4 @@ export * from './Router'; export * from './TemplateListPage'; export * from './TemplateWizardPage'; export * from './types'; +export * from './routes'; diff --git a/plugins/scaffolder-react/src/next/routes.ts b/plugins/scaffolder/src/next/routes.ts similarity index 100% rename from plugins/scaffolder-react/src/next/routes.ts rename to plugins/scaffolder/src/next/routes.ts diff --git a/plugins/scaffolder/src/plugin.tsx b/plugins/scaffolder/src/plugin.tsx index 5bbe51dd2d..be9e14a92b 100644 --- a/plugins/scaffolder/src/plugin.tsx +++ b/plugins/scaffolder/src/plugin.tsx @@ -16,10 +16,6 @@ import { scmIntegrationsApiRef } from '@backstage/integration-react'; import { - nextRouteRef, - registerComponentRouteRef, - rootRouteRef, - viewTechDocRouteRef, createScaffolderFieldExtension, scaffolderApiRef, } from '@backstage/plugin-scaffolder-react'; @@ -58,6 +54,12 @@ import { EntityTagsPicker, EntityTagsPickerSchema, } from './components/fields/EntityTagsPicker/EntityTagsPicker'; +import { + registerComponentRouteRef, + rootRouteRef, + viewTechDocRouteRef, +} from './routes'; +import { nextRouteRef } from './next'; /** * The main plugin export for the scaffolder. diff --git a/plugins/scaffolder-react/src/routes.ts b/plugins/scaffolder/src/routes.ts similarity index 100% rename from plugins/scaffolder-react/src/routes.ts rename to plugins/scaffolder/src/routes.ts