chore: move the routeRefs back into the scaffolder plugin for now, maybe it makes sense to move them later.
Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
@@ -14,7 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './routes';
|
||||
export * from './extensions';
|
||||
export * from './types';
|
||||
export * from './secrets';
|
||||
|
||||
@@ -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<any, any>[];
|
||||
onComplete: (values: Record<string, JsonValue>) => Promise<void>;
|
||||
templateName?: string;
|
||||
FormProps?: FormProps;
|
||||
|
||||
onComplete: (values: Record<string, JsonValue>) => Promise<void>;
|
||||
};
|
||||
|
||||
// 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',
|
||||
);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -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', () => {
|
||||
>
|
||||
<TemplateCard template={mockTemplate} />
|
||||
</TestApiProvider>,
|
||||
{ mountedRoutes: { '/': nextRouteRef } },
|
||||
);
|
||||
|
||||
expect(getByText('bob')).toBeInTheDocument();
|
||||
@@ -84,7 +82,6 @@ describe('TemplateCard', () => {
|
||||
>
|
||||
<TemplateCard template={mockTemplate} />
|
||||
</TestApiProvider>,
|
||||
{ mountedRoutes: { '/': nextRouteRef } },
|
||||
);
|
||||
|
||||
const description = getByText('hello');
|
||||
@@ -115,7 +112,6 @@ describe('TemplateCard', () => {
|
||||
>
|
||||
<TemplateCard template={mockTemplate} />
|
||||
</TestApiProvider>,
|
||||
{ mountedRoutes: { '/': nextRouteRef } },
|
||||
);
|
||||
|
||||
expect(getByText('No description')).toBeInTheDocument();
|
||||
@@ -145,7 +141,6 @@ describe('TemplateCard', () => {
|
||||
>
|
||||
<TemplateCard template={mockTemplate} />
|
||||
</TestApiProvider>,
|
||||
{ mountedRoutes: { '/': nextRouteRef } },
|
||||
);
|
||||
|
||||
for (const tag of mockTemplate.metadata.tags!) {
|
||||
@@ -185,7 +180,6 @@ describe('TemplateCard', () => {
|
||||
</TestApiProvider>,
|
||||
{
|
||||
mountedRoutes: {
|
||||
'/': nextRouteRef,
|
||||
'/catalog/:kind/:namespace/:name': entityRouteRef,
|
||||
},
|
||||
},
|
||||
@@ -224,7 +218,6 @@ describe('TemplateCard', () => {
|
||||
</TestApiProvider>,
|
||||
{
|
||||
mountedRoutes: {
|
||||
'/': nextRouteRef,
|
||||
'/catalog/:kind/:namespace/:name': entityRouteRef,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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<BackstageTheme>(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 (
|
||||
<Card>
|
||||
<CardHeader template={template} />
|
||||
@@ -157,22 +135,18 @@ export const TemplateCard = (props: TemplateCardProps) => {
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
{(!!viewTechDocsLink || template.metadata.links?.length) && (
|
||||
{(props.additionalLinks || template.metadata.links?.length) && (
|
||||
<>
|
||||
<Grid item xs={12}>
|
||||
<Divider />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={2}>
|
||||
{viewTechDocsLink && (
|
||||
{props.additionalLinks?.map(({ icon, text, url }) => (
|
||||
<Grid className={styles.linkText} item xs={6}>
|
||||
<CardLink
|
||||
icon={iconResolver('docs')}
|
||||
text="View TechDocs"
|
||||
url={viewTechDocsLink}
|
||||
/>
|
||||
<CardLink icon={icon} text={text} url={url} />
|
||||
</Grid>
|
||||
)}
|
||||
))}
|
||||
{template.metadata.links?.map(({ url, icon, title }) => (
|
||||
<Grid className={styles.linkText} item xs={6}>
|
||||
<CardLink
|
||||
@@ -202,7 +176,12 @@ export const TemplateCard = (props: TemplateCardProps) => {
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<Button size="small" variant="outlined" color="primary" to={href}>
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={() => props.onSelected?.(template)}
|
||||
>
|
||||
Choose
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -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<TemplateCardProps>;
|
||||
@@ -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' ? <ContentHeader title={title} /> : title;
|
||||
|
||||
@@ -67,8 +81,13 @@ export const TemplateGroup = (props: TemplateGroupProps) => {
|
||||
<Content>
|
||||
{titleComponent}
|
||||
<ItemCardGrid>
|
||||
{templates.map(template => (
|
||||
<Card key={stringifyEntityRef(template)} template={template} />
|
||||
{templates.map(({ template, additionalLinks }) => (
|
||||
<Card
|
||||
key={stringifyEntityRef(template)}
|
||||
additionalLinks={additionalLinks}
|
||||
template={template}
|
||||
onSelected={onSelected}
|
||||
/>
|
||||
))}
|
||||
</ItemCardGrid>
|
||||
</Content>
|
||||
|
||||
@@ -18,4 +18,3 @@ export * from './extensions';
|
||||
export * from './types';
|
||||
export * from './lib';
|
||||
export * from './hooks';
|
||||
export * from './routes';
|
||||
|
||||
@@ -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<ScaffolderApi> = {
|
||||
scaffold: jest.fn(),
|
||||
|
||||
@@ -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('<ListTasksPage />', () => {
|
||||
const catalogApi: jest.Mocked<CatalogApi> = {
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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?:
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
@@ -32,7 +32,7 @@ import {
|
||||
actionsRouteRef,
|
||||
editRouteRef,
|
||||
scaffolderListTaskRouteRef,
|
||||
} from '@backstage/plugin-scaffolder-react';
|
||||
} from '../../routes';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
button: {
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<NextRouterProps>) => {
|
||||
|
||||
const outlet = useOutlet() || props.children;
|
||||
|
||||
// todo(blam): move this out into a `useFieldExtensions` hook exported by -react
|
||||
const customFieldExtensions = useElementFilter(outlet, elements =>
|
||||
elements
|
||||
.selectByComponentData({
|
||||
|
||||
@@ -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 <Progress />;
|
||||
@@ -66,16 +89,41 @@ export const TemplateGroups = (props: TemplateGroupsProps) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
{groups.map(({ title, filter }, index) => (
|
||||
<TemplateGroup
|
||||
key={index}
|
||||
templates={entities.filter((e): e is TemplateEntityV1beta3 =>
|
||||
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 (
|
||||
<TemplateGroup
|
||||
key={index}
|
||||
templates={templates}
|
||||
title={title}
|
||||
components={{ CardComponent: TemplateCardComponent }}
|
||||
onSelected={onSelected}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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<{
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<any, any>[];
|
||||
|
||||
@@ -17,3 +17,4 @@ export * from './Router';
|
||||
export * from './TemplateListPage';
|
||||
export * from './TemplateWizardPage';
|
||||
export * from './types';
|
||||
export * from './routes';
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user