From 9c12a76c9e072cc2033ce3c7aeec433867da2e38 Mon Sep 17 00:00:00 2001 From: Andy Ladjadj Date: Thu, 27 Mar 2025 00:40:26 +0100 Subject: [PATCH] fix(techdocs): prevent to throw an error when the SCM provider is not supported (#29154) * fix(techdocs): prevent to throw error on undefined 'selection' Error TypeError Message Failed to execute 'containsNode' on 'Selection': parameter 1 is not of type 'Node'. Stack Trace TypeError: parameter 1 is not of type 'Node'. at https://backstage.mpi-internal.com/static/module-backstage.b2517ed5.js:618:1729 at ul (https://backstage.mpi-internal.com/static/module-react-dom.b4fe5cf3.js:16:24313) at Ct (https://backstage.mpi-internal.com/static/module-react-dom.b4fe5cf3.js:16:42455) at qs (https://backstage.mpi-internal.com/static/module-react-dom.b4fe5cf3.js:16:34578) at Ln (https://backstage.mpi-internal.com/static/module-react-dom.b4fe5cf3.js:24:1590) at MessagePort.Zn (https://backstage.mpi-internal.com/static/module-react-dom.b4fe5cf3.js:24:1980) Signed-off-by: Andy LADJADJ * doc: add changeset Signed-off-by: Andy LADJADJ * chore(techinsights-addon): doesn't load the component for unsuported repositories Signed-off-by: Andy LADJADJ * Update plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssueContent.tsx Co-authored-by: Thomas Cardonne Signed-off-by: Andy Ladjadj * Update plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssueContent.tsx Co-authored-by: Thomas Cardonne Signed-off-by: Andy Ladjadj * fix: doesn't test that selection contains feebackContainer Signed-off-by: Andy LADJADJ * ci: update the changeset Signed-off-by: Andy LADJADJ --------- Signed-off-by: Andy LADJADJ Signed-off-by: Andy Ladjadj Co-authored-by: Thomas Cardonne --- .changeset/unlucky-carrots-shave.md | 5 + .../src/ReportIssue/IssueLink.tsx | 5 +- .../src/ReportIssue/ReportIssue.test.tsx | 53 ++++++- .../src/ReportIssue/ReportIssue.tsx | 129 ++--------------- .../src/ReportIssue/ReportIssueContent.tsx | 133 ++++++++++++++++++ .../src/ReportIssue/constants.ts | 1 + 6 files changed, 203 insertions(+), 123 deletions(-) create mode 100644 .changeset/unlucky-carrots-shave.md create mode 100644 plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssueContent.tsx diff --git a/.changeset/unlucky-carrots-shave.md b/.changeset/unlucky-carrots-shave.md new file mode 100644 index 0000000000..e0b4c0128b --- /dev/null +++ b/.changeset/unlucky-carrots-shave.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-module-addons-contrib': patch +--- + +Fixed rendering issues in `ReportIssue` addon for unsupported repository types and improved shadow DOM event handling. The addon now properly prevents initialization when encountering unsupported repository types and correctly handles selection events within the shadow DOM. diff --git a/plugins/techdocs-module-addons-contrib/src/ReportIssue/IssueLink.tsx b/plugins/techdocs-module-addons-contrib/src/ReportIssue/IssueLink.tsx index eb16476fa6..f0d9b194ce 100644 --- a/plugins/techdocs-module-addons-contrib/src/ReportIssue/IssueLink.tsx +++ b/plugins/techdocs-module-addons-contrib/src/ReportIssue/IssueLink.tsx @@ -48,10 +48,7 @@ const getIcon = ({ type }: Repository) => { }; const getName = ({ type }: Repository) => { - if (type === 'github') { - return 'Github'; - } - return 'Gitlab'; + return type.charAt(0).toLocaleUpperCase('en-US') + type.slice(1); }; const getUrl = (repository: Repository, template: ReportIssueTemplate) => { diff --git a/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.test.tsx b/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.test.tsx index 459fa1b65e..97df773f76 100644 --- a/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.test.tsx +++ b/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.test.tsx @@ -116,7 +116,7 @@ describe('ReportIssue', () => { it('renders gitlab link without exploding', async () => { byUrl.mockReturnValue({ type: 'gitlab' }); - const { shadowRoot, getByText } = + const { shadowRoot, getByText, queryByTestId } = await TechDocsAddonTester.buildAddonsInTechDocs([ , ]) @@ -164,6 +164,8 @@ describe('ReportIssue', () => { fireSelectionChangeEvent(window); await waitFor(() => { + expect(queryByTestId('report-issue-addon')).toBeInTheDocument(); + const link = getByText('Open new Gitlab issue'); expect(link).toHaveAttribute( 'href', @@ -180,7 +182,7 @@ describe('ReportIssue', () => { body: options.selection.toString().trim(), }); - const { shadowRoot, getByText } = + const { shadowRoot, getByText, queryByTestId } = await TechDocsAddonTester.buildAddonsInTechDocs([ , ]) @@ -228,6 +230,8 @@ describe('ReportIssue', () => { fireSelectionChangeEvent(window); await waitFor(() => { + expect(queryByTestId('report-issue-addon')).toBeInTheDocument(); + const link = getByText('Open new Gitlab issue'); expect(link).toHaveAttribute( 'href', @@ -235,4 +239,49 @@ describe('ReportIssue', () => { ); }); }); + + it('does not render report issue link for unsupported repository type', async () => { + byUrl.mockReturnValue({ type: 'gerrit', resource: 'gerrit.example.com' }); + + const { shadowRoot, getByText, queryByTestId } = + await TechDocsAddonTester.buildAddonsInTechDocs([ + , + ]) + .withDom( + + + +
+
+ +
+
+ + , + ) + .withApis([[scmIntegrationsApiRef, { byUrl }]]) + .renderWithEffects(); + + (shadowRoot as ShadowRoot & Pick).getSelection = + () => selection; + + await waitFor(() => { + expect(getByText('Edit page')).toBeInTheDocument(); + }); + + fireSelectionChangeEvent(window); + + await waitFor(() => { + expect(queryByTestId('report-issue-addon')).not.toBeInTheDocument(); + }); + }); }); diff --git a/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.tsx b/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.tsx index a6d8021b9d..3a5511376c 100644 --- a/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.tsx +++ b/plugins/techdocs-module-addons-contrib/src/ReportIssue/ReportIssue.tsx @@ -14,39 +14,11 @@ * limitations under the License. */ -import React, { useState, useEffect } from 'react'; - -import { makeStyles, Portal, Paper } from '@material-ui/core'; - -import { useGitTemplate, useGitRepository } from './hooks'; +import React from 'react'; +import { useGitRepository } from './hooks'; import { ReportIssueTemplateBuilder } from './types'; -import { - PAGE_MAIN_CONTENT_SELECTOR, - PAGE_FEEDBACK_LINK_SELECTOR, - ADDON_FEEDBACK_CONTAINER_ID, - ADDON_FEEDBACK_CONTAINER_SELECTOR, -} from './constants'; -import { IssueLink } from './IssueLink'; - -import { - useShadowRootElements, - useShadowRootSelection, -} from '@backstage/plugin-techdocs-react'; - -const useStyles = makeStyles(theme => ({ - root: { - transform: 'translate(-100%, -100%)', - position: 'absolute', - padding: theme.spacing(1), - zIndex: theme.zIndex.tooltip, - background: theme.palette.common.white, - }, -})); - -type Style = { - top: string; - left: string; -}; +import { ADDON_ISSUE_REPO_TYPES_SUPPORTED } from './constants'; +import { ReportIssueAddonContent } from './ReportIssueContent'; /** * Props customizing the Addon. @@ -67,101 +39,24 @@ export type ReportIssueProps = { templateBuilder?: ReportIssueTemplateBuilder; }; -/** - * Show report issue button when text is highlighted - */ export const ReportIssueAddon = ({ debounceTime = 500, - templateBuilder: buildTemplate, + templateBuilder, }: ReportIssueProps) => { - const classes = useStyles(); - const [style, setStyle] = useState