From 3ae875da8d638ce573eabef4396899896eda872f Mon Sep 17 00:00:00 2001 From: kosukeKK Date: Sat, 30 Dec 2023 18:05:01 +0900 Subject: [PATCH 01/11] implements editUrl for template Signed-off-by: kosukeKK --- .../sample-templates/all-templates.yaml | 2 + .../src/service/router.test.ts | 54 ++++++++++++++ .../scaffolder-backend/src/service/router.ts | 1 + .../components/Workflow/Workflow.test.tsx | 74 ++++++++++++++++++- .../src/next/components/Workflow/Workflow.tsx | 15 +++- plugins/scaffolder-react/src/types.ts | 1 + 6 files changed, 143 insertions(+), 4 deletions(-) diff --git a/plugins/scaffolder-backend/sample-templates/all-templates.yaml b/plugins/scaffolder-backend/sample-templates/all-templates.yaml index 6637c9479b..54a3fb213e 100644 --- a/plugins/scaffolder-backend/sample-templates/all-templates.yaml +++ b/plugins/scaffolder-backend/sample-templates/all-templates.yaml @@ -3,6 +3,8 @@ kind: Location metadata: name: example-templates description: A collection of all Backstage example templates +# annotations: +# backstage.io/edit-url: https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/sample-templates/all-templates.yaml spec: targets: - ./remote-templates.yaml diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index 8bfbd6b915..babe93ad13 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -107,6 +107,7 @@ describe('createRouter', () => { title: 'Create React App Template', annotations: { 'backstage.io/managed-by-location': 'url:https://dev.azure.com', + 'backstage.io/edit-url': 'url:EDIT_URL', }, }, spec: { @@ -878,6 +879,7 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ expect(response.body).toEqual({ title: 'Create React App Template', description: 'Create a new CRA website project', + editUrl: 'url:EDIT_URL', steps: [ { title: 'Please enter the following information', @@ -932,6 +934,7 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ expect(response.body).toEqual({ title: 'Create React App Template', description: 'Create a new CRA website project', + editUrl: 'url:EDIT_URL', steps: [], }); }); @@ -963,6 +966,7 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ expect(response.body).toEqual({ title: 'Create React App Template', description: 'Create a new CRA website project', + editUrl: 'url:EDIT_URL', steps: [ { title: 'Please enter the following information', @@ -983,6 +987,56 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ ], }); }); + it('should not return editUrl', async () => { + jest + .spyOn(catalogClient, 'getEntityByRef') + .mockImplementationOnce(async () => { + const template = getMockTemplate(); + delete template.metadata.annotations?.['backstage.io/edit-url']; + return template; + }); + const response = await request(app) + .get( + '/v2/templates/default/Template/create-react-app-template/parameter-schema', + ) + .send(); + expect(response.status).toEqual(200); + expect(response.body).toEqual({ + title: 'Create React App Template', + description: 'Create a new CRA website project', + steps: [ + { + title: 'Please enter the following information', + schema: { + required: ['requiredParameter1'], + type: 'object', + properties: { + requiredParameter1: { + description: 'Required parameter 1', + type: 'string', + }, + }, + }, + }, + { + title: 'Please enter the following information', + schema: { + type: 'object', + required: ['requiredParameter2'], + 'backstage:permissions': { + tags: ['parameters-tag'], + }, + properties: { + requiredParameter2: { + type: 'string', + description: 'Required parameter 2', + }, + }, + }, + }, + ], + }); + }); }); describe('POST /v2/tasks', () => { diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index c0322af283..a70d6e9800 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -408,6 +408,7 @@ export async function createRouter( res.json({ title: template.metadata.title ?? template.metadata.name, ...(presentation ? { presentation } : {}), + editUrl: template.metadata.annotations?.['backstage.io/edit-url'], description: template.metadata.description, 'ui:options': template.metadata['ui:options'], steps: parameters.map(schema => ({ diff --git a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx index 81c5a697e0..e431e66ca2 100644 --- a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx +++ b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx @@ -20,7 +20,7 @@ import { renderInTestApp, TestApiRegistry, } from '@backstage/test-utils'; -import { act, fireEvent } from '@testing-library/react'; +import { act, fireEvent, screen } from '@testing-library/react'; import React from 'react'; import { Workflow } from './Workflow'; import { analyticsApiRef } from '@backstage/core-plugin-api'; @@ -75,7 +75,7 @@ describe('', () => { title: 'React JSON Schema Form Test', }); - const { getByRole, getAllByRole, getByText } = await renderInTestApp( + const { getByRole, getByText } = await renderInTestApp( ', () => { ).toBeDefined(); await act(async () => { - fireEvent.click(getAllByRole('button')[1] as HTMLButtonElement); + fireEvent.click(getByText('Make') as HTMLButtonElement); }); expect(onCreate).toHaveBeenCalledWith({ @@ -141,4 +141,72 @@ describe('', () => { age: '53', }); }); + it('renders "edit template" button', async () => { + const onCreate = jest.fn(); + const onError = jest.fn(); + const expectedUrl = '/EDIT_URL'; + scaffolderApiMock.getTemplateParameterSchema.mockResolvedValue({ + editUrl: expectedUrl, + steps: [ + { + title: 'Step 1', + schema: {}, + }, + ], + title: 'React JSON Schema Form Test', + }); + await renderInTestApp( + + + , + ); + const editLink = screen.getByTitle('Edit Template').closest('a'); + expect(editLink).toHaveAttribute('href', expectedUrl); + }); + it('renders disable "edit template" button', async () => { + const onCreate = jest.fn(); + const onError = jest.fn(); + scaffolderApiMock.getTemplateParameterSchema.mockResolvedValue({ + steps: [ + { + title: 'Step 1', + schema: {}, + }, + ], + editUrl: undefined, + title: 'React JSON Schema Form Test', + }); + await renderInTestApp( + + + , + ); + const editLink = screen.getByTitle('Edit Template'); + expect(editLink).toBeVisible(); + expect(editLink).toHaveAttribute('href', '/'); + }); }); diff --git a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx index c6030930c5..660f115064 100644 --- a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx +++ b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx @@ -20,6 +20,7 @@ import { InfoCard, MarkdownContent, Progress, + Link, } from '@backstage/core-components'; import { stringifyEntityRef } from '@backstage/catalog-model'; import { makeStyles } from '@material-ui/core'; @@ -29,6 +30,8 @@ import { Stepper, type StepperProps } from '../Stepper/Stepper'; import { SecretsContextProvider } from '../../../secrets/SecretsContext'; import { useFilteredSchemaProperties } from '../../hooks/useFilteredSchemaProperties'; import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; +import IconButton from '@material-ui/core/IconButton'; +import EditIcon from '@material-ui/icons/Edit'; const useStyles = makeStyles({ markdown: { @@ -93,13 +96,23 @@ export const Workflow = (workflowProps: WorkflowProps): JSX.Element | null => { if (error) { return props.onError(error); } - return ( {loading && } {sortedManifest && ( + + + } subheader={ Date: Sun, 31 Dec 2023 00:28:06 +0900 Subject: [PATCH 02/11] added changeset and api report Signed-off-by: kosukeKK --- .changeset/funny-cameras-speak.md | 5 +++++ .changeset/honest-poems-visit.md | 5 +++++ .../scaffolder-backend/sample-templates/all-templates.yaml | 2 -- plugins/scaffolder-react/api-report.md | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 .changeset/funny-cameras-speak.md create mode 100644 .changeset/honest-poems-visit.md diff --git a/.changeset/funny-cameras-speak.md b/.changeset/funny-cameras-speak.md new file mode 100644 index 0000000000..ad206e3cfd --- /dev/null +++ b/.changeset/funny-cameras-speak.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': minor +--- + +Added 'editUrl' to the '/v2/templates/:namespace/:kind/:name/parameter-schema' API response. This 'editUrl' references 'backstage.io/edit-url' in the template metadata annotations diff --git a/.changeset/honest-poems-visit.md b/.changeset/honest-poems-visit.md new file mode 100644 index 0000000000..3e22b0385f --- /dev/null +++ b/.changeset/honest-poems-visit.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': minor +--- + +Added an edit link to the template page for direct access to editing the template diff --git a/plugins/scaffolder-backend/sample-templates/all-templates.yaml b/plugins/scaffolder-backend/sample-templates/all-templates.yaml index 54a3fb213e..6637c9479b 100644 --- a/plugins/scaffolder-backend/sample-templates/all-templates.yaml +++ b/plugins/scaffolder-backend/sample-templates/all-templates.yaml @@ -3,8 +3,6 @@ kind: Location metadata: name: example-templates description: A collection of all Backstage example templates -# annotations: -# backstage.io/edit-url: https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/sample-templates/all-templates.yaml spec: targets: - ./remote-templates.yaml diff --git a/plugins/scaffolder-react/api-report.md b/plugins/scaffolder-react/api-report.md index 400cf24c53..aab1a70cee 100644 --- a/plugins/scaffolder-react/api-report.md +++ b/plugins/scaffolder-react/api-report.md @@ -484,6 +484,7 @@ export type TemplateGroupFilter = { export type TemplateParameterSchema = { title: string; description?: string; + editUrl?: string; presentation?: TemplatePresentationV1beta3; steps: Array<{ title: string; From 6422f7b45af151631c28bc60bc5511eb99533ac3 Mon Sep 17 00:00:00 2001 From: kosukeKK Date: Sat, 2 Mar 2024 01:16:21 +0900 Subject: [PATCH 03/11] move template edit url to header Signed-off-by: kosukeKK --- .../components/Workflow/Workflow.test.tsx | 74 +------------------ .../src/next/components/Workflow/Workflow.tsx | 15 +--- .../TemplateWizardPage.test.tsx | 64 ++++++++++++++++ .../TemplateWizardPage/TemplateWizardPage.tsx | 21 +++++- 4 files changed, 88 insertions(+), 86 deletions(-) diff --git a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx index e431e66ca2..81c5a697e0 100644 --- a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx +++ b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.test.tsx @@ -20,7 +20,7 @@ import { renderInTestApp, TestApiRegistry, } from '@backstage/test-utils'; -import { act, fireEvent, screen } from '@testing-library/react'; +import { act, fireEvent } from '@testing-library/react'; import React from 'react'; import { Workflow } from './Workflow'; import { analyticsApiRef } from '@backstage/core-plugin-api'; @@ -75,7 +75,7 @@ describe('', () => { title: 'React JSON Schema Form Test', }); - const { getByRole, getByText } = await renderInTestApp( + const { getByRole, getAllByRole, getByText } = await renderInTestApp( ', () => { ).toBeDefined(); await act(async () => { - fireEvent.click(getByText('Make') as HTMLButtonElement); + fireEvent.click(getAllByRole('button')[1] as HTMLButtonElement); }); expect(onCreate).toHaveBeenCalledWith({ @@ -141,72 +141,4 @@ describe('', () => { age: '53', }); }); - it('renders "edit template" button', async () => { - const onCreate = jest.fn(); - const onError = jest.fn(); - const expectedUrl = '/EDIT_URL'; - scaffolderApiMock.getTemplateParameterSchema.mockResolvedValue({ - editUrl: expectedUrl, - steps: [ - { - title: 'Step 1', - schema: {}, - }, - ], - title: 'React JSON Schema Form Test', - }); - await renderInTestApp( - - - , - ); - const editLink = screen.getByTitle('Edit Template').closest('a'); - expect(editLink).toHaveAttribute('href', expectedUrl); - }); - it('renders disable "edit template" button', async () => { - const onCreate = jest.fn(); - const onError = jest.fn(); - scaffolderApiMock.getTemplateParameterSchema.mockResolvedValue({ - steps: [ - { - title: 'Step 1', - schema: {}, - }, - ], - editUrl: undefined, - title: 'React JSON Schema Form Test', - }); - await renderInTestApp( - - - , - ); - const editLink = screen.getByTitle('Edit Template'); - expect(editLink).toBeVisible(); - expect(editLink).toHaveAttribute('href', '/'); - }); }); diff --git a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx index 660f115064..c6030930c5 100644 --- a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx +++ b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx @@ -20,7 +20,6 @@ import { InfoCard, MarkdownContent, Progress, - Link, } from '@backstage/core-components'; import { stringifyEntityRef } from '@backstage/catalog-model'; import { makeStyles } from '@material-ui/core'; @@ -30,8 +29,6 @@ import { Stepper, type StepperProps } from '../Stepper/Stepper'; import { SecretsContextProvider } from '../../../secrets/SecretsContext'; import { useFilteredSchemaProperties } from '../../hooks/useFilteredSchemaProperties'; import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; -import IconButton from '@material-ui/core/IconButton'; -import EditIcon from '@material-ui/icons/Edit'; const useStyles = makeStyles({ markdown: { @@ -96,23 +93,13 @@ export const Workflow = (workflowProps: WorkflowProps): JSX.Element | null => { if (error) { return props.onError(error); } + return ( {loading && } {sortedManifest && ( - - - } subheader={ { context: { entityRef: 'template:default/test' }, }); }); + describe('scaffolder page context menu', () => { + it('should render if editUrl is set to url', async () => { + scaffolderApiMock.getTemplateParameterSchema.mockResolvedValue({ + steps: [ + { + title: 'Step 1', + schema: { + properties: { + name: { + type: 'string', + }, + }, + }, + }, + ], + title: 'React JSON Schema Form Test', + editUrl: 'http://example.com/load-testing', + }); + const { queryByTestId } = await renderInTestApp( + + + , + + , + { + mountedRoutes: { + '/create': rootRouteRef, + }, + }, + ); + expect(queryByTestId('menu-button')).toBeInTheDocument(); + }); + it('should not render if editUrl is undefined', async () => { + scaffolderApiMock.getTemplateParameterSchema.mockResolvedValue({ + steps: [ + { + title: 'Step 1', + schema: { + properties: { + name: { + type: 'string', + }, + }, + }, + }, + ], + title: 'React JSON Schema Form Test', + editUrl: undefined, + }); + const { queryByTestId } = await renderInTestApp( + + + , + + , + { + mountedRoutes: { + '/create': rootRouteRef, + }, + }, + ); + expect(queryByTestId('menu-button')).not.toBeInTheDocument(); + }); + }); }); diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx index 611330e76b..5b02454385 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx @@ -30,6 +30,7 @@ import { FieldExtensionOptions, ReviewStepProps, } from '@backstage/plugin-scaffolder-react'; +import { ScaffolderPageContextMenu } from '@backstage/plugin-scaffolder-react/alpha'; import { Workflow } from '@backstage/plugin-scaffolder-react/alpha'; import { JsonValue } from '@backstage/types'; import { Header, Page } from '@backstage/core-components'; @@ -73,6 +74,22 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => { name: templateName, }); + const [editUrl, setEditURL] = React.useState(''); + scaffolderApi.getTemplateParameterSchema(templateRef).then(data => { + if (data.editUrl !== undefined) setEditURL(data.editUrl); + }); + const scaffolderPageContextMenuProps = { + onEditorClicked: + editUrl !== '' + ? () => { + window.location.href = editUrl; + } + : undefined, + onActionsClicked: undefined, + onTasksClicked: undefined, + onCreateClicked: undefined, + }; + const onCreate = async (values: Record) => { const { taskId } = await scaffolderApi.scaffold({ templateRef, @@ -93,7 +110,9 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => { title="Create a new component" subtitle="Create new software components using standard templates in your organization" {...props.headerOptions} - /> + > + + Date: Sat, 2 Mar 2024 01:36:30 +0900 Subject: [PATCH 04/11] added changeset Signed-off-by: kosukeKK --- .changeset/grumpy-lamps-wonder.md | 5 +++++ .changeset/honest-poems-visit.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/grumpy-lamps-wonder.md diff --git a/.changeset/grumpy-lamps-wonder.md b/.changeset/grumpy-lamps-wonder.md new file mode 100644 index 0000000000..c7fe8ebc35 --- /dev/null +++ b/.changeset/grumpy-lamps-wonder.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': minor +--- + +Added a menu to the header of template page for direct access to editing the template diff --git a/.changeset/honest-poems-visit.md b/.changeset/honest-poems-visit.md index 3e22b0385f..150b10a6e0 100644 --- a/.changeset/honest-poems-visit.md +++ b/.changeset/honest-poems-visit.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder-react': minor --- -Added an edit link to the template page for direct access to editing the template +Added an editUrl parameter to TemplateParameterSchema From acebeb8bd2738a6d7eef25250db24449e45662e8 Mon Sep 17 00:00:00 2001 From: kosukeKK Date: Tue, 5 Mar 2024 14:50:42 +0900 Subject: [PATCH 05/11] added ScaffolderWizardContextMenu and revert backend api Signed-off-by: kosukeKK --- .changeset/funny-cameras-speak.md | 5 - .changeset/honest-poems-visit.md | 2 +- .../src/service/router.test.ts | 54 ---------- .../scaffolder-backend/src/service/router.ts | 1 - plugins/scaffolder-react/api-report.md | 1 - .../ScaffolderWizardContextMenu.tsx | 100 ++++++++++++++++++ .../ScaffolderWizardContextMenu/index.ts | 19 ++++ .../src/next/components/index.ts | 1 + plugins/scaffolder-react/src/types.ts | 1 - .../TemplateWizardPage.test.tsx | 74 ++++++++----- .../TemplateWizardPage/TemplateWizardPage.tsx | 21 ++-- 11 files changed, 179 insertions(+), 100 deletions(-) delete mode 100644 .changeset/funny-cameras-speak.md create mode 100644 plugins/scaffolder-react/src/next/components/ScaffolderWizardContextMenu/ScaffolderWizardContextMenu.tsx create mode 100644 plugins/scaffolder-react/src/next/components/ScaffolderWizardContextMenu/index.ts diff --git a/.changeset/funny-cameras-speak.md b/.changeset/funny-cameras-speak.md deleted file mode 100644 index ad206e3cfd..0000000000 --- a/.changeset/funny-cameras-speak.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor ---- - -Added 'editUrl' to the '/v2/templates/:namespace/:kind/:name/parameter-schema' API response. This 'editUrl' references 'backstage.io/edit-url' in the template metadata annotations diff --git a/.changeset/honest-poems-visit.md b/.changeset/honest-poems-visit.md index 150b10a6e0..a0f392c0fc 100644 --- a/.changeset/honest-poems-visit.md +++ b/.changeset/honest-poems-visit.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder-react': minor --- -Added an editUrl parameter to TemplateParameterSchema +Added a header menu for ScaffolderWizard diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index babe93ad13..8bfbd6b915 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -107,7 +107,6 @@ describe('createRouter', () => { title: 'Create React App Template', annotations: { 'backstage.io/managed-by-location': 'url:https://dev.azure.com', - 'backstage.io/edit-url': 'url:EDIT_URL', }, }, spec: { @@ -879,7 +878,6 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ expect(response.body).toEqual({ title: 'Create React App Template', description: 'Create a new CRA website project', - editUrl: 'url:EDIT_URL', steps: [ { title: 'Please enter the following information', @@ -934,7 +932,6 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ expect(response.body).toEqual({ title: 'Create React App Template', description: 'Create a new CRA website project', - editUrl: 'url:EDIT_URL', steps: [], }); }); @@ -966,7 +963,6 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ expect(response.body).toEqual({ title: 'Create React App Template', description: 'Create a new CRA website project', - editUrl: 'url:EDIT_URL', steps: [ { title: 'Please enter the following information', @@ -987,56 +983,6 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{ ], }); }); - it('should not return editUrl', async () => { - jest - .spyOn(catalogClient, 'getEntityByRef') - .mockImplementationOnce(async () => { - const template = getMockTemplate(); - delete template.metadata.annotations?.['backstage.io/edit-url']; - return template; - }); - const response = await request(app) - .get( - '/v2/templates/default/Template/create-react-app-template/parameter-schema', - ) - .send(); - expect(response.status).toEqual(200); - expect(response.body).toEqual({ - title: 'Create React App Template', - description: 'Create a new CRA website project', - steps: [ - { - title: 'Please enter the following information', - schema: { - required: ['requiredParameter1'], - type: 'object', - properties: { - requiredParameter1: { - description: 'Required parameter 1', - type: 'string', - }, - }, - }, - }, - { - title: 'Please enter the following information', - schema: { - type: 'object', - required: ['requiredParameter2'], - 'backstage:permissions': { - tags: ['parameters-tag'], - }, - properties: { - requiredParameter2: { - type: 'string', - description: 'Required parameter 2', - }, - }, - }, - }, - ], - }); - }); }); describe('POST /v2/tasks', () => { diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index a70d6e9800..c0322af283 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -408,7 +408,6 @@ export async function createRouter( res.json({ title: template.metadata.title ?? template.metadata.name, ...(presentation ? { presentation } : {}), - editUrl: template.metadata.annotations?.['backstage.io/edit-url'], description: template.metadata.description, 'ui:options': template.metadata['ui:options'], steps: parameters.map(schema => ({ diff --git a/plugins/scaffolder-react/api-report.md b/plugins/scaffolder-react/api-report.md index aab1a70cee..400cf24c53 100644 --- a/plugins/scaffolder-react/api-report.md +++ b/plugins/scaffolder-react/api-report.md @@ -484,7 +484,6 @@ export type TemplateGroupFilter = { export type TemplateParameterSchema = { title: string; description?: string; - editUrl?: string; presentation?: TemplatePresentationV1beta3; steps: Array<{ title: string; diff --git a/plugins/scaffolder-react/src/next/components/ScaffolderWizardContextMenu/ScaffolderWizardContextMenu.tsx b/plugins/scaffolder-react/src/next/components/ScaffolderWizardContextMenu/ScaffolderWizardContextMenu.tsx new file mode 100644 index 0000000000..5702a5ba62 --- /dev/null +++ b/plugins/scaffolder-react/src/next/components/ScaffolderWizardContextMenu/ScaffolderWizardContextMenu.tsx @@ -0,0 +1,100 @@ +/* + * Copyright 2020 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 IconButton from '@material-ui/core/IconButton'; +import ListItemIcon from '@material-ui/core/ListItemIcon'; +import ListItemText from '@material-ui/core/ListItemText'; +import MenuItem from '@material-ui/core/MenuItem'; +import MenuList from '@material-ui/core/MenuList'; +import Popover from '@material-ui/core/Popover'; +import { makeStyles } from '@material-ui/core/styles'; +import Edit from '@material-ui/icons/Edit'; +import MoreVert from '@material-ui/icons/MoreVert'; +import React, { useState } from 'react'; + +const useStyles = makeStyles(theme => ({ + button: { + color: theme.page.fontColor, + }, +})); + +/** + * @alpha + */ +export type ScaffolderWizardContextMenuProps = { + onEditorClicked?: () => void; +}; + +/** + * @alpha + */ +export function ScaffolderWizardContextMenu( + props: ScaffolderWizardContextMenuProps, +) { + const { onEditorClicked } = props; + const classes = useStyles(); + const [anchorEl, setAnchorEl] = useState(); + + if (!onEditorClicked) { + return null; + } + + const onOpen = (event: React.SyntheticEvent) => { + setAnchorEl(event.currentTarget); + }; + + const onClose = () => { + setAnchorEl(undefined); + }; + + return ( + <> + + + + + + {onEditorClicked && ( + + + + + + + )} + + + + ); +} diff --git a/plugins/scaffolder-react/src/next/components/ScaffolderWizardContextMenu/index.ts b/plugins/scaffolder-react/src/next/components/ScaffolderWizardContextMenu/index.ts new file mode 100644 index 0000000000..51d1458cae --- /dev/null +++ b/plugins/scaffolder-react/src/next/components/ScaffolderWizardContextMenu/index.ts @@ -0,0 +1,19 @@ +/* + * 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 { + ScaffolderWizardContextMenu, + type ScaffolderWizardContextMenuProps, +} from './ScaffolderWizardContextMenu'; diff --git a/plugins/scaffolder-react/src/next/components/index.ts b/plugins/scaffolder-react/src/next/components/index.ts index 119f983a9f..3ea830002a 100644 --- a/plugins/scaffolder-react/src/next/components/index.ts +++ b/plugins/scaffolder-react/src/next/components/index.ts @@ -25,4 +25,5 @@ export * from './TaskSteps'; export * from './TaskLogStream'; export * from './TemplateCategoryPicker'; export * from './ScaffolderPageContextMenu'; +export * from './ScaffolderWizardContextMenu'; export * from './ScaffolderField'; diff --git a/plugins/scaffolder-react/src/types.ts b/plugins/scaffolder-react/src/types.ts index ee0ac1c28c..c1c26f32bb 100644 --- a/plugins/scaffolder-react/src/types.ts +++ b/plugins/scaffolder-react/src/types.ts @@ -27,7 +27,6 @@ import { TemplatePresentationV1beta3 } from '@backstage/plugin-scaffolder-common export type TemplateParameterSchema = { title: string; description?: string; - editUrl?: string; presentation?: TemplatePresentationV1beta3; steps: Array<{ title: string; diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx index 463f40bd9e..f01b0ab003 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx @@ -29,6 +29,7 @@ import { } from '@backstage/plugin-scaffolder-react'; import { TemplateWizardPage } from './TemplateWizardPage'; import { rootRouteRef } from '../../routes'; +import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; jest.mock('react-router-dom', () => { return { @@ -50,12 +51,32 @@ const scaffolderApiMock: jest.Mocked = { listTasks: jest.fn(), }; +const catalogApiMock: jest.Mocked = { + getEntityByRef: jest.fn(), +} as any; + const analyticsMock = new MockAnalyticsApi(); const apis = TestApiRegistry.from( [scaffolderApiRef, scaffolderApiMock], [analyticsApiRef, analyticsMock], + [catalogApiRef, catalogApiMock], ); +const entityRefResponse = { + apiVersion: 'v1', + kind: 'service', + metadata: { + name: 'test', + annotations: { + 'backstage.io/edit-url': 'http://localhost:3000', + }, + }, + spec: { + profile: { + displayName: 'BackUser', + }, + }, +}; describe('TemplateWizardPage', () => { it('captures expected analytics events', async () => { scaffolderApiMock.scaffold.mockResolvedValue({ taskId: 'xyz' }); @@ -74,6 +95,7 @@ describe('TemplateWizardPage', () => { ], title: 'React JSON Schema Form Test', }); + catalogApiMock.getEntityByRef.mockResolvedValue(entityRefResponse); const { findByRole, getByRole } = await renderInTestApp( @@ -119,21 +141,20 @@ describe('TemplateWizardPage', () => { }); describe('scaffolder page context menu', () => { it('should render if editUrl is set to url', async () => { - scaffolderApiMock.getTemplateParameterSchema.mockResolvedValue({ - steps: [ - { - title: 'Step 1', - schema: { - properties: { - name: { - type: 'string', - }, - }, - }, + catalogApiMock.getEntityByRef.mockResolvedValue({ + apiVersion: 'v1', + kind: 'service', + metadata: { + name: 'test', + annotations: { + 'backstage.io/edit-url': 'http://localhost:3000', }, - ], - title: 'React JSON Schema Form Test', - editUrl: 'http://example.com/load-testing', + }, + spec: { + profile: { + displayName: 'BackUser', + }, + }, }); const { queryByTestId } = await renderInTestApp( @@ -150,21 +171,18 @@ describe('TemplateWizardPage', () => { expect(queryByTestId('menu-button')).toBeInTheDocument(); }); it('should not render if editUrl is undefined', async () => { - scaffolderApiMock.getTemplateParameterSchema.mockResolvedValue({ - steps: [ - { - title: 'Step 1', - schema: { - properties: { - name: { - type: 'string', - }, - }, - }, + catalogApiMock.getEntityByRef.mockResolvedValue({ + apiVersion: 'v1', + kind: 'service', + metadata: { + name: 'test', + // annotations are not set + }, + spec: { + profile: { + displayName: 'BackUser', }, - ], - title: 'React JSON Schema Form Test', - editUrl: undefined, + }, }); const { queryByTestId } = await renderInTestApp( diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx index 5b02454385..7f7cee4c7e 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx @@ -30,7 +30,9 @@ import { FieldExtensionOptions, ReviewStepProps, } from '@backstage/plugin-scaffolder-react'; -import { ScaffolderPageContextMenu } from '@backstage/plugin-scaffolder-react/alpha'; +import { catalogApiRef } from '@backstage/plugin-catalog-react'; + +import { ScaffolderWizardContextMenu } from '@backstage/plugin-scaffolder-react/alpha'; import { Workflow } from '@backstage/plugin-scaffolder-react/alpha'; import { JsonValue } from '@backstage/types'; import { Header, Page } from '@backstage/core-components'; @@ -63,6 +65,7 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => { const taskRoute = useRouteRef(scaffolderTaskRouteRef); const { secrets } = useTemplateSecrets(); const scaffolderApi = useApi(scaffolderApiRef); + const catalogApi = useApi(catalogApiRef); const navigate = useNavigate(); const { templateName, namespace } = useRouteRefParams( selectedTemplateRouteRef, @@ -75,19 +78,19 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => { }); const [editUrl, setEditURL] = React.useState(''); - scaffolderApi.getTemplateParameterSchema(templateRef).then(data => { - if (data.editUrl !== undefined) setEditURL(data.editUrl); + catalogApi.getEntityByRef(templateRef).then(data => { + const templateEditUrl = + data?.metadata.annotations?.['backstage.io/edit-url']; + if (templateEditUrl !== undefined) setEditURL(templateEditUrl); }); - const scaffolderPageContextMenuProps = { + + const scaffolderWizardContextMenuProps = { onEditorClicked: editUrl !== '' ? () => { - window.location.href = editUrl; + window.open(editUrl, '_blank'); } : undefined, - onActionsClicked: undefined, - onTasksClicked: undefined, - onCreateClicked: undefined, }; const onCreate = async (values: Record) => { @@ -111,7 +114,7 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => { subtitle="Create new software components using standard templates in your organization" {...props.headerOptions} > - + Date: Wed, 6 Mar 2024 19:52:44 +0900 Subject: [PATCH 06/11] added api report Signed-off-by: kosukeKK --- plugins/scaffolder-react/api-report-alpha.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/scaffolder-react/api-report-alpha.md b/plugins/scaffolder-react/api-report-alpha.md index 683b8cf8be..c7f4101e0b 100644 --- a/plugins/scaffolder-react/api-report-alpha.md +++ b/plugins/scaffolder-react/api-report-alpha.md @@ -149,6 +149,16 @@ export type ScaffolderReactComponentsNameToClassKey = { // @alpha (undocumented) export type ScaffolderReactTemplateCategoryPickerClassKey = 'root' | 'label'; +// @alpha (undocumented) +export function ScaffolderWizardContextMenu( + props: ScaffolderWizardContextMenuProps, +): React_2.JSX.Element | null; + +// @alpha (undocumented) +export type ScaffolderWizardContextMenuProps = { + onEditorClicked?: () => void; +}; + // @alpha export const Stepper: (stepperProps: StepperProps) => React_2.JSX.Element; From 96511604f64e5e0d5cb34dc790ab7117f6a57474 Mon Sep 17 00:00:00 2001 From: kosukeKK Date: Thu, 7 Mar 2024 13:19:30 +0900 Subject: [PATCH 07/11] refactoring code Signed-off-by: kosukeKK --- .../next/TemplateWizardPage/TemplateWizardPage.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx index 7f7cee4c7e..2ceb57f87e 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx @@ -15,6 +15,7 @@ */ import React from 'react'; import { Navigate, useNavigate } from 'react-router-dom'; +import useAsync from 'react-use/lib/useAsync'; import { stringifyEntityRef } from '@backstage/catalog-model'; import { AnalyticsContext, @@ -77,12 +78,10 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => { name: templateName, }); - const [editUrl, setEditURL] = React.useState(''); - catalogApi.getEntityByRef(templateRef).then(data => { - const templateEditUrl = - data?.metadata.annotations?.['backstage.io/edit-url']; - if (templateEditUrl !== undefined) setEditURL(templateEditUrl); - }); + const { value: editUrl } = useAsync(async () => { + const data = await catalogApi.getEntityByRef(templateRef); + return data?.metadata.annotations?.['backstage.io/edit-url'] || ''; + }, [templateRef, catalogApi]); const scaffolderWizardContextMenuProps = { onEditorClicked: From 93acaade9adbf3870035285d9d1f1d7f62db9d58 Mon Sep 17 00:00:00 2001 From: kosukeKK Date: Thu, 7 Mar 2024 22:30:40 +0900 Subject: [PATCH 08/11] moved ScaffolderWizardContextMenu.tsx Signed-off-by: kosukeKK --- .changeset/honest-poems-visit.md | 5 --- plugins/scaffolder-react/api-report-alpha.md | 10 ------ .../ScaffolderWizardContextMenu/index.ts | 19 ----------- .../src/next/components/index.ts | 1 - .../TemplateWizardPage/TemplateWizardPage.tsx | 34 ++++++++++++------- .../TemplateWizardPageContextMenu.tsx} | 12 ++----- 6 files changed, 25 insertions(+), 56 deletions(-) delete mode 100644 .changeset/honest-poems-visit.md delete mode 100644 plugins/scaffolder-react/src/next/components/ScaffolderWizardContextMenu/index.ts rename plugins/{scaffolder-react/src/next/components/ScaffolderWizardContextMenu/ScaffolderWizardContextMenu.tsx => scaffolder/src/next/TemplateWizardPage/TemplateWizardPageContextMenu.tsx} (93%) diff --git a/.changeset/honest-poems-visit.md b/.changeset/honest-poems-visit.md deleted file mode 100644 index a0f392c0fc..0000000000 --- a/.changeset/honest-poems-visit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-react': minor ---- - -Added a header menu for ScaffolderWizard diff --git a/plugins/scaffolder-react/api-report-alpha.md b/plugins/scaffolder-react/api-report-alpha.md index c7f4101e0b..683b8cf8be 100644 --- a/plugins/scaffolder-react/api-report-alpha.md +++ b/plugins/scaffolder-react/api-report-alpha.md @@ -149,16 +149,6 @@ export type ScaffolderReactComponentsNameToClassKey = { // @alpha (undocumented) export type ScaffolderReactTemplateCategoryPickerClassKey = 'root' | 'label'; -// @alpha (undocumented) -export function ScaffolderWizardContextMenu( - props: ScaffolderWizardContextMenuProps, -): React_2.JSX.Element | null; - -// @alpha (undocumented) -export type ScaffolderWizardContextMenuProps = { - onEditorClicked?: () => void; -}; - // @alpha export const Stepper: (stepperProps: StepperProps) => React_2.JSX.Element; diff --git a/plugins/scaffolder-react/src/next/components/ScaffolderWizardContextMenu/index.ts b/plugins/scaffolder-react/src/next/components/ScaffolderWizardContextMenu/index.ts deleted file mode 100644 index 51d1458cae..0000000000 --- a/plugins/scaffolder-react/src/next/components/ScaffolderWizardContextMenu/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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 { - ScaffolderWizardContextMenu, - type ScaffolderWizardContextMenuProps, -} from './ScaffolderWizardContextMenu'; diff --git a/plugins/scaffolder-react/src/next/components/index.ts b/plugins/scaffolder-react/src/next/components/index.ts index 3ea830002a..119f983a9f 100644 --- a/plugins/scaffolder-react/src/next/components/index.ts +++ b/plugins/scaffolder-react/src/next/components/index.ts @@ -25,5 +25,4 @@ export * from './TaskSteps'; export * from './TaskLogStream'; export * from './TemplateCategoryPicker'; export * from './ScaffolderPageContextMenu'; -export * from './ScaffolderWizardContextMenu'; export * from './ScaffolderField'; diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx index 2ceb57f87e..1deefaaa21 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx @@ -16,7 +16,10 @@ import React from 'react'; import { Navigate, useNavigate } from 'react-router-dom'; import useAsync from 'react-use/lib/useAsync'; -import { stringifyEntityRef } from '@backstage/catalog-model'; +import { + stringifyEntityRef, + ANNOTATION_EDIT_URL, +} from '@backstage/catalog-model'; import { AnalyticsContext, useApi, @@ -33,7 +36,6 @@ import { } from '@backstage/plugin-scaffolder-react'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; -import { ScaffolderWizardContextMenu } from '@backstage/plugin-scaffolder-react/alpha'; import { Workflow } from '@backstage/plugin-scaffolder-react/alpha'; import { JsonValue } from '@backstage/types'; import { Header, Page } from '@backstage/core-components'; @@ -44,6 +46,11 @@ import { selectedTemplateRouteRef, } from '../../routes'; +import { + TemplateWizardPageContextMenu, + TemplateWizardPageContextMenuProps, +} from './TemplateWizardPageContextMenu'; + /** * @alpha */ @@ -80,17 +87,18 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => { const { value: editUrl } = useAsync(async () => { const data = await catalogApi.getEntityByRef(templateRef); - return data?.metadata.annotations?.['backstage.io/edit-url'] || ''; + return data?.metadata.annotations?.[ANNOTATION_EDIT_URL] || ''; }, [templateRef, catalogApi]); - const scaffolderWizardContextMenuProps = { - onEditorClicked: - editUrl !== '' - ? () => { - window.open(editUrl, '_blank'); - } - : undefined, - }; + const templateWizardPageContextMenuProps: TemplateWizardPageContextMenuProps = + { + onEditorClicked: + editUrl !== '' + ? () => { + window.open(editUrl, '_blank'); + } + : undefined, + }; const onCreate = async (values: Record) => { const { taskId } = await scaffolderApi.scaffold({ @@ -113,7 +121,9 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => { subtitle="Create new software components using standard templates in your organization" {...props.headerOptions} > - + ({ }, })); -/** - * @alpha - */ -export type ScaffolderWizardContextMenuProps = { +export type TemplateWizardPageContextMenuProps = { onEditorClicked?: () => void; }; -/** - * @alpha - */ -export function ScaffolderWizardContextMenu( - props: ScaffolderWizardContextMenuProps, +export function TemplateWizardPageContextMenu( + props: TemplateWizardPageContextMenuProps, ) { const { onEditorClicked } = props; const classes = useStyles(); From c6864cce724658b5df6ae30606872cec1d207c63 Mon Sep 17 00:00:00 2001 From: kosukeKK Date: Fri, 8 Mar 2024 18:29:35 +0900 Subject: [PATCH 09/11] fix test Signed-off-by: kosukeKK --- .../src/next/TemplateWizardPage/TemplateWizardPage.test.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx index f01b0ab003..5cdae85e8a 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.test.tsx @@ -30,6 +30,7 @@ import { import { TemplateWizardPage } from './TemplateWizardPage'; import { rootRouteRef } from '../../routes'; import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; +import { ANNOTATION_EDIT_URL } from '@backstage/catalog-model'; jest.mock('react-router-dom', () => { return { @@ -68,7 +69,7 @@ const entityRefResponse = { metadata: { name: 'test', annotations: { - 'backstage.io/edit-url': 'http://localhost:3000', + [ANNOTATION_EDIT_URL]: 'http://localhost:3000', }, }, spec: { @@ -147,7 +148,7 @@ describe('TemplateWizardPage', () => { metadata: { name: 'test', annotations: { - 'backstage.io/edit-url': 'http://localhost:3000', + [ANNOTATION_EDIT_URL]: 'http://localhost:3000', }, }, spec: { From be906108320eca41607767bbbead460a58b7bad5 Mon Sep 17 00:00:00 2001 From: kosukeKK Date: Sat, 9 Mar 2024 15:46:04 +0900 Subject: [PATCH 10/11] refactoring code Signed-off-by: kosukeKK --- .../TemplateWizardPage/TemplateWizardPage.tsx | 19 ++---------------- .../TemplateWizardPageContextMenu.tsx | 20 +++++++++---------- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx index 1deefaaa21..6a103b03b3 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx @@ -46,10 +46,7 @@ import { selectedTemplateRouteRef, } from '../../routes'; -import { - TemplateWizardPageContextMenu, - TemplateWizardPageContextMenuProps, -} from './TemplateWizardPageContextMenu'; +import { TemplateWizardPageContextMenu } from './TemplateWizardPageContextMenu'; /** * @alpha @@ -90,16 +87,6 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => { return data?.metadata.annotations?.[ANNOTATION_EDIT_URL] || ''; }, [templateRef, catalogApi]); - const templateWizardPageContextMenuProps: TemplateWizardPageContextMenuProps = - { - onEditorClicked: - editUrl !== '' - ? () => { - window.open(editUrl, '_blank'); - } - : undefined, - }; - const onCreate = async (values: Record) => { const { taskId } = await scaffolderApi.scaffold({ templateRef, @@ -121,9 +108,7 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => { subtitle="Create new software components using standard templates in your organization" {...props.headerOptions} > - + ({ })); export type TemplateWizardPageContextMenuProps = { - onEditorClicked?: () => void; + editUrl?: string; }; export function TemplateWizardPageContextMenu( props: TemplateWizardPageContextMenuProps, ) { - const { onEditorClicked } = props; + const { editUrl } = props; const classes = useStyles(); const [anchorEl, setAnchorEl] = useState(); - if (!onEditorClicked) { + if (!editUrl) { return null; } @@ -79,14 +79,12 @@ export function TemplateWizardPageContextMenu( transformOrigin={{ vertical: 'top', horizontal: 'right' }} > - {onEditorClicked && ( - - - - - - - )} + window.open(editUrl, '_blank')}> + + + + + From fe1adc002a0260ddfe8b92fc910479af6f90b7d7 Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 12 Mar 2024 11:15:50 +0100 Subject: [PATCH 11/11] chore: fix unecessary '' Signed-off-by: blam --- .../src/next/TemplateWizardPage/TemplateWizardPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx index 6a103b03b3..053cf6decf 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx @@ -84,7 +84,7 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => { const { value: editUrl } = useAsync(async () => { const data = await catalogApi.getEntityByRef(templateRef); - return data?.metadata.annotations?.[ANNOTATION_EDIT_URL] || ''; + return data?.metadata.annotations?.[ANNOTATION_EDIT_URL]; }, [templateRef, catalogApi]); const onCreate = async (values: Record) => {