From 73076973ec704d470474227dcacbd78ead961f23 Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Wed, 28 Jun 2023 17:42:15 +0530 Subject: [PATCH 1/7] catalog-import: replace Repository URL text with URL Repository URL is confusing term as users often paste the link to a repository, while in most cases it's a link to the catalog-info.yaml path. Signed-off-by: Himanshu Mishra --- .../src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.tsx b/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.tsx index 3c655ec11b..588217974c 100644 --- a/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.tsx +++ b/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.tsx @@ -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" From f1d27555ab5398e6963932f2b5f9a985c901fb69 Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Wed, 28 Jun 2023 18:49:10 +0530 Subject: [PATCH 2/7] catalog-import: Add a View Component CTA after finishing import Signed-off-by: Himanshu Mishra --- .../src/components/Buttons/index.tsx | 18 +++++++ .../StepFinishImportLocation.tsx | 50 ++++++++++++++----- .../src/components/useImportState.ts | 12 +++-- 3 files changed, 63 insertions(+), 17 deletions(-) diff --git a/plugins/catalog-import/src/components/Buttons/index.tsx b/plugins/catalog-import/src/components/Buttons/index.tsx index a478bfd4cc..4b9043cd6d 100644 --- a/plugins/catalog-import/src/components/Buttons/index.tsx +++ b/plugins/catalog-import/src/components/Buttons/index.tsx @@ -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) => { ); }; + +export const ViewComponentButton = ( + props: ComponentProps, +) => { + const classes = useStyles(); + + return ( + + {props.children} + + ); +}; diff --git a/plugins/catalog-import/src/components/StepFinishImportLocation/StepFinishImportLocation.tsx b/plugins/catalog-import/src/components/StepFinishImportLocation/StepFinishImportLocation.tsx index 8d1a588079..4d09b9129f 100644 --- a/plugins/catalog-import/src/components/StepFinishImportLocation/StepFinishImportLocation.tsx +++ b/plugins/catalog-import/src/components/StepFinishImportLocation/StepFinishImportLocation.tsx @@ -17,23 +17,41 @@ 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 { PrepareResult, NewLocations } 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: NewLocations, +): 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 = ( - - Register another - - ); + const entityRoute = useRouteRef(entityRouteRef); if (prepareResult.type === 'repository') { return ( @@ -48,12 +66,13 @@ export const StepFinishImportLocation = ({ prepareResult, onReset }: Props) => { {prepareResult.pullRequest.url} - Your entities will be imported as soon as the Pull Request is merged. - - {continueButton} + + Register another + + ; ); } @@ -62,7 +81,7 @@ export const StepFinishImportLocation = ({ prepareResult, onReset }: Props) => { prepareResult.locations, l => l.exists, ); - + const newComponentEntity = filterComponentEntity(newLocations); return ( <> {newLocations.length > 0 && ( @@ -91,7 +110,14 @@ export const StepFinishImportLocation = ({ prepareResult, onReset }: Props) => { /> )} - {continueButton} + + {newComponentEntity && ( + + View Component + + )} + Register another + ); }; diff --git a/plugins/catalog-import/src/components/useImportState.ts b/plugins/catalog-import/src/components/useImportState.ts index 965f855f30..da34b8b1d7 100644 --- a/plugins/catalog-import/src/components/useImportState.ts +++ b/plugins/catalog-import/src/components/useImportState.ts @@ -32,6 +32,12 @@ export type ImportFlows = // the available states of the stepper type ImportStateTypes = 'analyze' | 'prepare' | 'review' | 'finish'; +export type NewLocations = Array<{ + exists?: boolean; + target: string; + entities: CompoundEntityRef[]; +}>; + /** * Result of the prepare state. * @@ -40,11 +46,7 @@ type ImportStateTypes = 'analyze' | 'prepare' | 'review' | 'finish'; export type PrepareResult = | { type: 'locations'; - locations: Array<{ - exists?: boolean; - target: string; - entities: CompoundEntityRef[]; - }>; + locations: NewLocations; } | { type: 'repository'; From 36b7edf39585cef91513713d46a4fef63e82312e Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Wed, 28 Jun 2023 18:50:16 +0530 Subject: [PATCH 3/7] add changeset Signed-off-by: Himanshu Mishra --- .changeset/mean-bobcats-taste.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/mean-bobcats-taste.md diff --git a/.changeset/mean-bobcats-taste.md b/.changeset/mean-bobcats-taste.md new file mode 100644 index 0000000000..299273209c --- /dev/null +++ b/.changeset/mean-bobcats-taste.md @@ -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 From aca073bf92e1d4781c5b6f29a65c2ebc6f3e84cc Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Wed, 28 Jun 2023 19:12:07 +0530 Subject: [PATCH 4/7] catalog-import: fix tests Signed-off-by: Himanshu Mishra --- .../StepInitAnalyzeUrl.test.tsx | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.test.tsx b/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.test.tsx index a9d662cab0..d8a12d0e5c 100644 --- a/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.test.tsx +++ b/plugins/catalog-import/src/components/StepInitAnalyzeUrl/StepInitAnalyzeUrl.test.tsx @@ -64,12 +64,8 @@ describe('', () => { 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('', () => { }, ); - 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('', () => { 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('', () => { 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('', () => { 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('', () => { 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('', () => { 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('', () => { 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('', () => { 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('', () => { 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 })); From 71c1c639d6cb3814e72a90557e40cad42be1a513 Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Wed, 28 Jun 2023 22:09:56 +0530 Subject: [PATCH 5/7] catalog-import: api reports Signed-off-by: Himanshu Mishra --- plugins/catalog-import/api-report.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/plugins/catalog-import/api-report.md b/plugins/catalog-import/api-report.md index b4c8e854aa..7fd3bd9dd6 100644 --- a/plugins/catalog-import/api-report.md +++ b/plugins/catalog-import/api-report.md @@ -244,11 +244,7 @@ export type PreparePullRequestFormProps< export type PrepareResult = | { type: 'locations'; - locations: Array<{ - exists?: boolean; - target: string; - entities: CompoundEntityRef[]; - }>; + locations: NewLocations; } | { type: 'repository'; @@ -364,4 +360,5 @@ export interface StepPrepareCreatePullRequestProps { // Warnings were encountered during analysis: // // src/api/CatalogImportApi.d.ts:25:5 - (ae-forgotten-export) The symbol "PartialEntity" needs to be exported by the entry point index.d.ts +// src/components/useImportState.d.ts:21:5 - (ae-forgotten-export) The symbol "NewLocations" needs to be exported by the entry point index.d.ts ``` From 63e880700e4b5c727161ad58908d80f199afafb6 Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Fri, 30 Jun 2023 00:05:00 +0530 Subject: [PATCH 6/7] do not export catalog-import Signed-off-by: Himanshu Mishra --- .../StepFinishImportLocation/StepFinishImportLocation.tsx | 8 +++++++- plugins/catalog-import/src/components/useImportState.ts | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/catalog-import/src/components/StepFinishImportLocation/StepFinishImportLocation.tsx b/plugins/catalog-import/src/components/StepFinishImportLocation/StepFinishImportLocation.tsx index 4d09b9129f..1d566253c3 100644 --- a/plugins/catalog-import/src/components/StepFinishImportLocation/StepFinishImportLocation.tsx +++ b/plugins/catalog-import/src/components/StepFinishImportLocation/StepFinishImportLocation.tsx @@ -19,7 +19,7 @@ import LocationOnIcon from '@material-ui/icons/LocationOn'; import React from 'react'; import { BackButton, ViewComponentButton } from '../Buttons'; import { EntityListComponent } from '../EntityListComponent'; -import { PrepareResult, NewLocations } from '../useImportState'; +import { PrepareResult } from '../useImportState'; import { Link } from '@backstage/core-components'; import partition from 'lodash/partition'; import { CompoundEntityRef } from '@backstage/catalog-model'; @@ -31,6 +31,12 @@ type Props = { onReset: () => void; }; +type NewLocations = Array<{ + exists?: boolean; + target: string; + entities: CompoundEntityRef[]; +}>; + // Among the newly registered entities, return a software entity (e.g. Component, API, Resource) const filterComponentEntity = ( newLocations: NewLocations, diff --git a/plugins/catalog-import/src/components/useImportState.ts b/plugins/catalog-import/src/components/useImportState.ts index da34b8b1d7..01649d5edb 100644 --- a/plugins/catalog-import/src/components/useImportState.ts +++ b/plugins/catalog-import/src/components/useImportState.ts @@ -32,7 +32,7 @@ export type ImportFlows = // the available states of the stepper type ImportStateTypes = 'analyze' | 'prepare' | 'review' | 'finish'; -export type NewLocations = Array<{ +type NewLocations = Array<{ exists?: boolean; target: string; entities: CompoundEntityRef[]; From 08b075b00a4e7927559940b30984925abb33b489 Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Mon, 3 Jul 2023 15:40:10 +0530 Subject: [PATCH 7/7] catalog-import: use type locally Signed-off-by: Himanshu Mishra --- plugins/catalog-import/api-report.md | 7 +++++-- .../StepFinishImportLocation.tsx | 12 +++++------- .../catalog-import/src/components/useImportState.ts | 12 +++++------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/plugins/catalog-import/api-report.md b/plugins/catalog-import/api-report.md index 7fd3bd9dd6..b4c8e854aa 100644 --- a/plugins/catalog-import/api-report.md +++ b/plugins/catalog-import/api-report.md @@ -244,7 +244,11 @@ export type PreparePullRequestFormProps< export type PrepareResult = | { type: 'locations'; - locations: NewLocations; + locations: Array<{ + exists?: boolean; + target: string; + entities: CompoundEntityRef[]; + }>; } | { type: 'repository'; @@ -360,5 +364,4 @@ export interface StepPrepareCreatePullRequestProps { // Warnings were encountered during analysis: // // src/api/CatalogImportApi.d.ts:25:5 - (ae-forgotten-export) The symbol "PartialEntity" needs to be exported by the entry point index.d.ts -// src/components/useImportState.d.ts:21:5 - (ae-forgotten-export) The symbol "NewLocations" needs to be exported by the entry point index.d.ts ``` diff --git a/plugins/catalog-import/src/components/StepFinishImportLocation/StepFinishImportLocation.tsx b/plugins/catalog-import/src/components/StepFinishImportLocation/StepFinishImportLocation.tsx index 1d566253c3..38372e59ba 100644 --- a/plugins/catalog-import/src/components/StepFinishImportLocation/StepFinishImportLocation.tsx +++ b/plugins/catalog-import/src/components/StepFinishImportLocation/StepFinishImportLocation.tsx @@ -31,15 +31,13 @@ type Props = { onReset: () => void; }; -type NewLocations = Array<{ - exists?: boolean; - target: string; - entities: CompoundEntityRef[]; -}>; - // Among the newly registered entities, return a software entity (e.g. Component, API, Resource) const filterComponentEntity = ( - newLocations: NewLocations, + newLocations: Array<{ + exists?: boolean; + target: string; + entities: CompoundEntityRef[]; + }>, ): CompoundEntityRef | null => { for (const location of newLocations) { for (const entity of location.entities) { diff --git a/plugins/catalog-import/src/components/useImportState.ts b/plugins/catalog-import/src/components/useImportState.ts index 01649d5edb..965f855f30 100644 --- a/plugins/catalog-import/src/components/useImportState.ts +++ b/plugins/catalog-import/src/components/useImportState.ts @@ -32,12 +32,6 @@ export type ImportFlows = // the available states of the stepper type ImportStateTypes = 'analyze' | 'prepare' | 'review' | 'finish'; -type NewLocations = Array<{ - exists?: boolean; - target: string; - entities: CompoundEntityRef[]; -}>; - /** * Result of the prepare state. * @@ -46,7 +40,11 @@ type NewLocations = Array<{ export type PrepareResult = | { type: 'locations'; - locations: NewLocations; + locations: Array<{ + exists?: boolean; + target: string; + entities: CompoundEntityRef[]; + }>; } | { type: 'repository';