Merge pull request #18481 from backstage/orkohunter/catalog-import-fixes

catalog-import: Add a View Component button after registering a new component
This commit is contained in:
Ben Lambert
2023-07-03 14:35:36 +02:00
committed by GitHub
5 changed files with 77 additions and 30 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-import': patch
---
Add a "View Component" button as the primary CTA after registering a new component using a link to catalog-info.yaml
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { LinkButton } from '@backstage/core-components';
import { Button, CircularProgress } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import React, { ComponentProps } from 'react';
@@ -68,3 +69,20 @@ export const BackButton = (props: ComponentProps<typeof Button>) => {
</Button>
);
};
export const ViewComponentButton = (
props: ComponentProps<typeof LinkButton>,
) => {
const classes = useStyles();
return (
<LinkButton
color="primary"
variant="contained"
className={classes.button}
{...props}
>
{props.children}
</LinkButton>
);
};
@@ -17,23 +17,45 @@
import { Grid, Typography } from '@material-ui/core';
import LocationOnIcon from '@material-ui/icons/LocationOn';
import React from 'react';
import { BackButton } from '../Buttons';
import { BackButton, ViewComponentButton } from '../Buttons';
import { EntityListComponent } from '../EntityListComponent';
import { PrepareResult } from '../useImportState';
import { Link } from '@backstage/core-components';
import partition from 'lodash/partition';
import { CompoundEntityRef } from '@backstage/catalog-model';
import { entityRouteRef } from '@backstage/plugin-catalog-react';
import { useRouteRef } from '@backstage/core-plugin-api';
type Props = {
prepareResult: PrepareResult;
onReset: () => void;
};
// Among the newly registered entities, return a software entity (e.g. Component, API, Resource)
const filterComponentEntity = (
newLocations: Array<{
exists?: boolean;
target: string;
entities: CompoundEntityRef[];
}>,
): CompoundEntityRef | null => {
for (const location of newLocations) {
for (const entity of location.entities) {
if (
['component', 'api', 'resource'].includes(
entity.kind.toLocaleLowerCase('en-US'),
)
) {
return entity;
}
}
}
return null;
};
export const StepFinishImportLocation = ({ prepareResult, onReset }: Props) => {
const continueButton = (
<Grid container spacing={0}>
<BackButton onClick={onReset}>Register another</BackButton>
</Grid>
);
const entityRoute = useRouteRef(entityRouteRef);
if (prepareResult.type === 'repository') {
return (
@@ -48,12 +70,13 @@ export const StepFinishImportLocation = ({ prepareResult, onReset }: Props) => {
{prepareResult.pullRequest.url}
</Link>
</Typography>
<Typography paragraph>
Your entities will be imported as soon as the Pull Request is merged.
</Typography>
{continueButton}
<Grid container spacing={0}>
<BackButton onClick={onReset}>Register another</BackButton>
</Grid>
;
</>
);
}
@@ -62,7 +85,7 @@ export const StepFinishImportLocation = ({ prepareResult, onReset }: Props) => {
prepareResult.locations,
l => l.exists,
);
const newComponentEntity = filterComponentEntity(newLocations);
return (
<>
{newLocations.length > 0 && (
@@ -91,7 +114,14 @@ export const StepFinishImportLocation = ({ prepareResult, onReset }: Props) => {
/>
</>
)}
{continueButton}
<Grid container spacing={0}>
{newComponentEntity && (
<ViewComponentButton to={entityRoute(newComponentEntity)}>
View Component
</ViewComponentButton>
)}
<BackButton onClick={onReset}>Register another</BackButton>
</Grid>
</>
);
};
@@ -64,12 +64,8 @@ describe('<StepInitAnalyzeUrl />', () => {
wrapper: Wrapper,
});
expect(
screen.getByRole('textbox', { name: /Repository/i }),
).toBeInTheDocument();
expect(screen.getByRole('textbox', { name: /Repository/i })).toHaveValue(
'',
);
expect(screen.getByRole('textbox', { name: /URL/i })).toBeInTheDocument();
expect(screen.getByRole('textbox', { name: /URL/i })).toHaveValue('');
});
it('should use default analysis url', async () => {
@@ -83,10 +79,8 @@ describe('<StepInitAnalyzeUrl />', () => {
},
);
expect(
screen.getByRole('textbox', { name: /Repository/i }),
).toBeInTheDocument();
expect(screen.getByRole('textbox', { name: /Repository/i })).toHaveValue(
expect(screen.getByRole('textbox', { name: /URL/i })).toBeInTheDocument();
expect(screen.getByRole('textbox', { name: /URL/i })).toHaveValue(
'https://default',
);
});
@@ -120,7 +114,7 @@ describe('<StepInitAnalyzeUrl />', () => {
await act(async () => {
await userEvent.type(
screen.getByRole('textbox', { name: /Repository/i }),
screen.getByRole('textbox', { name: /URL/i }),
'http:/',
);
await userEvent.click(screen.getByRole('button', { name: /Analyze/i }));
@@ -152,7 +146,7 @@ describe('<StepInitAnalyzeUrl />', () => {
await act(async () => {
await userEvent.type(
screen.getByRole('textbox', { name: /Repository/i }),
screen.getByRole('textbox', { name: /URL/i }),
'https://my-repository',
);
await userEvent.click(screen.getByRole('button', { name: /Analyze/i }));
@@ -186,7 +180,7 @@ describe('<StepInitAnalyzeUrl />', () => {
await act(async () => {
await userEvent.type(
screen.getByRole('textbox', { name: /Repository/i }),
screen.getByRole('textbox', { name: /URL/i }),
'https://my-repository-1',
);
await userEvent.click(screen.getByRole('button', { name: /Analyze/i }));
@@ -219,7 +213,7 @@ describe('<StepInitAnalyzeUrl />', () => {
await act(async () => {
await userEvent.type(
screen.getByRole('textbox', { name: /Repository/i }),
screen.getByRole('textbox', { name: /URL/i }),
'https://my-repository-1',
);
await userEvent.click(screen.getByRole('button', { name: /Analyze/i }));
@@ -260,7 +254,7 @@ describe('<StepInitAnalyzeUrl />', () => {
await act(async () => {
await userEvent.type(
screen.getByRole('textbox', { name: /Repository/i }),
screen.getByRole('textbox', { name: /URL/i }),
'https://my-repository-2',
);
await userEvent.click(screen.getByRole('button', { name: /Analyze/i }));
@@ -295,7 +289,7 @@ describe('<StepInitAnalyzeUrl />', () => {
await act(async () => {
await userEvent.type(
screen.getByRole('textbox', { name: /Repository/i }),
screen.getByRole('textbox', { name: /URL/i }),
'https://my-repository-2',
);
await userEvent.click(screen.getByRole('button', { name: /Analyze/i }));
@@ -339,7 +333,7 @@ describe('<StepInitAnalyzeUrl />', () => {
await act(async () => {
await userEvent.type(
screen.getByRole('textbox', { name: /Repository/i }),
screen.getByRole('textbox', { name: /URL/i }),
'https://my-repository-2',
);
await userEvent.click(screen.getByRole('button', { name: /Analyze/i }));
@@ -365,7 +359,7 @@ describe('<StepInitAnalyzeUrl />', () => {
await act(async () => {
await userEvent.type(
screen.getByRole('textbox', { name: /Repository/i }),
screen.getByRole('textbox', { name: /URL/i }),
'https://my-repository-2',
);
await userEvent.click(screen.getByRole('button', { name: /Analyze/i }));
@@ -147,7 +147,7 @@ export const StepInitAnalyzeUrl = (props: StepInitAnalyzeUrlProps) => {
)}
fullWidth
id="url"
label="Repository URL"
label="URL"
placeholder={exampleLocationUrl}
helperText="Enter the full path to your entity file to start tracking your component"
margin="normal"