Merge pull request #10882 from realandersn/techdocs/report-issue-addon
[TechDocs] ReportIssue addon
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs-module-addons-contrib': minor
|
||||
---
|
||||
|
||||
A package for contributed TechDocs addons.
|
||||
|
||||
In this release it will introduce the ReportIssue addon, which lets you select text and open a GitHub/Gitlab issue.
|
||||
@@ -55,6 +55,8 @@
|
||||
"@backstage/plugin-stack-overflow": "^0.1.0",
|
||||
"@backstage/plugin-tech-radar": "^0.5.11",
|
||||
"@backstage/plugin-techdocs": "^1.1.0",
|
||||
"@backstage/plugin-techdocs-react": "^0.1.0",
|
||||
"@backstage/plugin-techdocs-module-addons-contrib": "^0.0.0",
|
||||
"@backstage/plugin-todo": "^0.2.6",
|
||||
"@backstage/plugin-user-settings": "^0.4.3",
|
||||
"@backstage/plugin-tech-insights": "^0.2.0",
|
||||
|
||||
@@ -69,6 +69,8 @@ import {
|
||||
TechDocsReaderPage,
|
||||
techdocsPlugin,
|
||||
} from '@backstage/plugin-techdocs';
|
||||
import { TechDocsAddons } from '@backstage/plugin-techdocs-react';
|
||||
import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib';
|
||||
import {
|
||||
UserSettingsPage,
|
||||
UserSettingsTab,
|
||||
@@ -179,6 +181,9 @@ const routes = (
|
||||
element={<TechDocsReaderPage />}
|
||||
>
|
||||
{techDocsPage}
|
||||
<TechDocsAddons>
|
||||
<ReportIssue />
|
||||
</TechDocsAddons>
|
||||
</Route>
|
||||
<Route
|
||||
path="/create"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
@@ -0,0 +1,35 @@
|
||||
## API Report File for "@backstage/plugin-techdocs-module-addons-contrib"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
/// <reference types="react" />
|
||||
|
||||
import { BackstagePlugin } from '@backstage/core-plugin-api';
|
||||
import { ComponentType } from 'react';
|
||||
|
||||
// @public
|
||||
export const ReportIssue: ComponentType<ReportIssueProps>;
|
||||
|
||||
// @public (undocumented)
|
||||
export type ReportIssueProps = {
|
||||
debounceTime?: number;
|
||||
templateBuilder?: ReportIssueTemplateBuilder;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type ReportIssueTemplate = {
|
||||
title: string;
|
||||
body: string;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type ReportIssueTemplateBuilder = ({
|
||||
selection,
|
||||
}: {
|
||||
selection: Selection;
|
||||
}) => ReportIssueTemplate;
|
||||
|
||||
// @public
|
||||
export const techdocsModuleAddonsContribPlugin: BackstagePlugin<{}, {}>;
|
||||
```
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"name": "@backstage/plugin-techdocs-module-addons-contrib",
|
||||
"description": "Plugin module for contributed TechDocs Addons",
|
||||
"version": "0.0.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.esm.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"backstage": {
|
||||
"role": "frontend-plugin-module"
|
||||
},
|
||||
"homepage": "https://backstage.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "plugins/techdocs-module-addons-contrib"
|
||||
},
|
||||
"keywords": [
|
||||
"backstage",
|
||||
"techdocs"
|
||||
],
|
||||
"scripts": {
|
||||
"start": "backstage-cli package start",
|
||||
"build": "backstage-cli package build",
|
||||
"lint": "backstage-cli package lint",
|
||||
"test": "backstage-cli package test",
|
||||
"clean": "backstage-cli package clean",
|
||||
"prepack": "backstage-cli package prepack",
|
||||
"postpack": "backstage-cli package postpack"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core-components": "^0.9.3",
|
||||
"@backstage/core-plugin-api": "^1.0.1",
|
||||
"@backstage/integration": "^1.1.0",
|
||||
"@backstage/integration-react": "^1.0.1",
|
||||
"@backstage/plugin-techdocs-react": "^0.1.0",
|
||||
"@backstage/theme": "^0.2.15",
|
||||
"@material-ui/core": "^4.9.13",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.57",
|
||||
"git-url-parse": "^11.6.0",
|
||||
"react-use": "^17.2.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.13.1 || ^17.0.0",
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.17.0",
|
||||
"@backstage/core-app-api": "^1.0.1",
|
||||
"@backstage/dev-utils": "^1.0.1",
|
||||
"@backstage/test-utils": "^1.0.1",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^12.1.3",
|
||||
"@testing-library/user-event": "^14.0.0",
|
||||
"@types/jest": "^26.0.7",
|
||||
"@types/node": "^16.11.26",
|
||||
"msw": "^0.35.0",
|
||||
"cross-fetch": "^3.1.5"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
|
||||
import { analyticsApiRef } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
MockAnalyticsApi,
|
||||
TestApiProvider,
|
||||
wrapInTestApp,
|
||||
} from '@backstage/test-utils';
|
||||
|
||||
import { IssueLink } from './IssueLink';
|
||||
|
||||
const defaultProps = {
|
||||
repository: {
|
||||
type: 'github',
|
||||
name: 'backstage',
|
||||
owner: 'backstage',
|
||||
protocol: 'https',
|
||||
resource: 'github.com',
|
||||
},
|
||||
template: {
|
||||
title: 'Documentation feedback',
|
||||
body: '## Documentation Feedback 📝',
|
||||
},
|
||||
};
|
||||
|
||||
describe('FeedbackLink', () => {
|
||||
const apiSpy = new MockAnalyticsApi();
|
||||
|
||||
it('Should open new issue tab', () => {
|
||||
render(
|
||||
wrapInTestApp(
|
||||
<TestApiProvider apis={[[analyticsApiRef, apiSpy]]}>
|
||||
<IssueLink {...defaultProps} />
|
||||
</TestApiProvider>,
|
||||
),
|
||||
);
|
||||
|
||||
const link = screen.getByText(/Open new Github issue/);
|
||||
expect(link).toBeInTheDocument();
|
||||
expect(link).toHaveAttribute('target', '_blank');
|
||||
const encodedTitle = encodeURIComponent(defaultProps.template.title);
|
||||
const encodedBody = encodeURIComponent(defaultProps.template.body);
|
||||
expect(link).toHaveAttribute(
|
||||
'href',
|
||||
`https://github.com/backstage/backstage/issues/new?title=${encodedTitle}&body=${encodedBody}`,
|
||||
);
|
||||
});
|
||||
|
||||
it('Should track click events', async () => {
|
||||
render(
|
||||
wrapInTestApp(
|
||||
<TestApiProvider apis={[[analyticsApiRef, apiSpy]]}>
|
||||
<IssueLink {...defaultProps} />
|
||||
</TestApiProvider>,
|
||||
),
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByText(/Open new Github issue/));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(apiSpy.getEvents()[0]).toMatchObject({
|
||||
action: 'click',
|
||||
subject: 'Open new Github issue',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import BugReportIcon from '@material-ui/icons/BugReport';
|
||||
|
||||
import { Link, GitHubIcon } from '@backstage/core-components';
|
||||
|
||||
import { ReportIssueTemplate, Repository } from './types';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
root: {
|
||||
display: 'grid',
|
||||
gridGap: theme.spacing(1),
|
||||
gridAutoFlow: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
color: theme.palette.common.black,
|
||||
fontSize: theme.typography.button.fontSize,
|
||||
},
|
||||
}));
|
||||
|
||||
type IssueLinkProps = {
|
||||
template: ReportIssueTemplate;
|
||||
repository: Repository;
|
||||
};
|
||||
|
||||
const getIcon = ({ type }: Repository) => {
|
||||
if (type === 'github') {
|
||||
return GitHubIcon;
|
||||
}
|
||||
return BugReportIcon;
|
||||
};
|
||||
|
||||
const getName = ({ type }: Repository) => {
|
||||
if (type === 'github') {
|
||||
return 'Github';
|
||||
}
|
||||
return 'Gitlab';
|
||||
};
|
||||
|
||||
const getUrl = (repository: Repository, template: ReportIssueTemplate) => {
|
||||
const { title, body } = template;
|
||||
const encodedTitle = encodeURIComponent(title);
|
||||
const encodedBody = encodeURIComponent(body);
|
||||
const { protocol, resource, owner, name, type } = repository;
|
||||
const encodedOwner = encodeURIComponent(owner);
|
||||
const encodedName = encodeURIComponent(name);
|
||||
|
||||
const url = `${protocol}://${resource}/${encodedOwner}/${encodedName}`;
|
||||
if (type === 'github') {
|
||||
return `${url}/issues/new?title=${encodedTitle}&body=${encodedBody}`;
|
||||
}
|
||||
return `${url}/issues/new?[title]=${encodedTitle}&[body]=${encodedBody}`;
|
||||
};
|
||||
|
||||
export const IssueLink = ({ template, repository }: IssueLinkProps) => {
|
||||
const classes = useStyles();
|
||||
|
||||
const Icon = getIcon(repository);
|
||||
const url = getUrl(repository, template);
|
||||
|
||||
return (
|
||||
<Link className={classes.root} to={url} target="_blank">
|
||||
<Icon /> Open new {getName(repository)} issue
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
import { makeStyles, Portal, Paper } from '@material-ui/core';
|
||||
|
||||
import { useGitTemplate, 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type ReportIssueProps = {
|
||||
debounceTime?: number;
|
||||
templateBuilder?: ReportIssueTemplateBuilder;
|
||||
};
|
||||
|
||||
/**
|
||||
* Show report issue button when text is highlighted
|
||||
*/
|
||||
export const ReportIssueAddon = ({
|
||||
debounceTime = 500,
|
||||
templateBuilder: buildTemplate,
|
||||
}: ReportIssueProps) => {
|
||||
const classes = useStyles();
|
||||
const [style, setStyle] = useState<Style>();
|
||||
|
||||
const repository = useGitRepository();
|
||||
|
||||
const defaultTemplate = useGitTemplate(debounceTime);
|
||||
|
||||
const selection = useShadowRootSelection(debounceTime);
|
||||
|
||||
const [mainContent, feedbackLink] = useShadowRootElements([
|
||||
PAGE_MAIN_CONTENT_SELECTOR,
|
||||
PAGE_FEEDBACK_LINK_SELECTOR,
|
||||
]);
|
||||
|
||||
let [feedbackContainer] = useShadowRootElements([
|
||||
ADDON_FEEDBACK_CONTAINER_SELECTOR,
|
||||
]);
|
||||
|
||||
if (feedbackLink) {
|
||||
feedbackLink.style.display = 'none';
|
||||
}
|
||||
|
||||
// calculates the position of the selected text to be able to set the position of the addon
|
||||
useEffect(() => {
|
||||
if (
|
||||
// todo(backstage/techdocs-core) handle non-repo rendering
|
||||
!repository ||
|
||||
!selection ||
|
||||
!selection.containsNode(mainContent!, true) ||
|
||||
selection?.containsNode(feedbackContainer!, true)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mainContentPosition = mainContent!.getBoundingClientRect();
|
||||
const selectionPosition = selection.getRangeAt(0).getBoundingClientRect();
|
||||
|
||||
setStyle({
|
||||
top: `${selectionPosition.top - mainContentPosition.top - 16}px`,
|
||||
left: `${selectionPosition.left + selectionPosition.width / 2}px`,
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selection, mainContent, feedbackContainer]);
|
||||
|
||||
if (!selection || !repository) return null;
|
||||
|
||||
if (!feedbackContainer) {
|
||||
feedbackContainer = document.createElement('div');
|
||||
feedbackContainer.setAttribute('id', ADDON_FEEDBACK_CONTAINER_ID);
|
||||
mainContent!.prepend(feedbackContainer);
|
||||
}
|
||||
|
||||
return (
|
||||
<Portal container={feedbackContainer}>
|
||||
<Paper
|
||||
data-testid="report-issue-addon"
|
||||
className={classes.root}
|
||||
style={style}
|
||||
>
|
||||
<IssueLink
|
||||
repository={repository}
|
||||
template={
|
||||
buildTemplate ? buildTemplate({ selection }) : defaultTemplate
|
||||
}
|
||||
/>
|
||||
</Paper>
|
||||
</Portal>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 const ADDON_FEEDBACK_CONTAINER_ID = 'techdocs-report-issue';
|
||||
export const ADDON_FEEDBACK_CONTAINER_SELECTOR = `#${ADDON_FEEDBACK_CONTAINER_ID}`;
|
||||
export const PAGE_EDIT_LINK_SELECTOR = '[title^="Edit this page"]';
|
||||
export const PAGE_FEEDBACK_LINK_SELECTOR = '[title^="Leave feedback for"]';
|
||||
export const PAGE_MAIN_CONTENT_SELECTOR =
|
||||
'[data-md-component="main"] .md-content';
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import parseGitUrl from 'git-url-parse';
|
||||
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
replaceGitHubUrlType,
|
||||
replaceGitLabUrlType,
|
||||
} from '@backstage/integration';
|
||||
import { scmIntegrationsApiRef } from '@backstage/integration-react';
|
||||
import {
|
||||
useShadowRootElements,
|
||||
useShadowRootSelection,
|
||||
} from '@backstage/plugin-techdocs-react';
|
||||
|
||||
import { PAGE_EDIT_LINK_SELECTOR } from './constants';
|
||||
|
||||
const resolveBlobUrl = (url: string, type: string) => {
|
||||
if (type === 'github') {
|
||||
return replaceGitHubUrlType(url, 'blob');
|
||||
} else if (type === 'gitlab') {
|
||||
return replaceGitLabUrlType(url, 'blob');
|
||||
}
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(
|
||||
`Invalid SCM type ${type} found in ReportIssue addon for URL ${url}!`,
|
||||
);
|
||||
return url;
|
||||
};
|
||||
|
||||
export const getTitle = (selection: Selection) => {
|
||||
const text = selection.toString().substring(0, 70);
|
||||
const ellipsis = text.length === 70 ? '...' : '';
|
||||
return `Documentation feedback: ${text}${ellipsis}`;
|
||||
};
|
||||
|
||||
export const getBody = (selection: Selection, markdownUrl: string) => {
|
||||
const title = '## Documentation Feedback 📝';
|
||||
const subheading = '#### The highlighted text:';
|
||||
const commentHeading = '#### The comment on the text:';
|
||||
const commentPlaceholder = '_>replace this line with your comment<_';
|
||||
const highlightedTextAsQuote = selection
|
||||
.toString()
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map(line => `> ${line.trim()}`)
|
||||
.join('\n');
|
||||
|
||||
const facts = [
|
||||
`Backstage URL: <${window.location.href}> \nMarkdown URL: <${markdownUrl}>`,
|
||||
];
|
||||
|
||||
return `${title}\n\n ${subheading} \n\n ${highlightedTextAsQuote}\n\n ${commentHeading} \n ${commentPlaceholder}\n\n ___\n${facts}`;
|
||||
};
|
||||
|
||||
export const useGitTemplate = (debounceTime?: number) => {
|
||||
const initialTemplate = { title: '', body: '' };
|
||||
const selection = useShadowRootSelection(debounceTime);
|
||||
const [editLink] = useShadowRootElements([PAGE_EDIT_LINK_SELECTOR]);
|
||||
const url = (editLink as HTMLAnchorElement)?.href ?? '';
|
||||
const scmIntegrationsApi = useApi(scmIntegrationsApiRef);
|
||||
|
||||
if (!selection || !url) return initialTemplate;
|
||||
|
||||
const type = scmIntegrationsApi.byUrl(url)?.type;
|
||||
|
||||
if (!type) return initialTemplate;
|
||||
|
||||
return {
|
||||
title: getTitle(selection),
|
||||
body: getBody(selection, resolveBlobUrl(url, type)),
|
||||
};
|
||||
};
|
||||
|
||||
export const useGitRepository = () => {
|
||||
const scmIntegrationsApi = useApi(scmIntegrationsApiRef);
|
||||
|
||||
const [editLink] = useShadowRootElements([PAGE_EDIT_LINK_SELECTOR]);
|
||||
const url = (editLink as HTMLAnchorElement)?.href ?? '';
|
||||
|
||||
if (!url) return null;
|
||||
|
||||
const type = scmIntegrationsApi.byUrl(url)?.type;
|
||||
|
||||
if (!type) return null;
|
||||
|
||||
return { ...parseGitUrl(resolveBlobUrl(url, type)), type };
|
||||
};
|
||||
@@ -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 { ReportIssueAddon } from './ReportIssue';
|
||||
export type { ReportIssueProps } from './ReportIssue';
|
||||
export type { ReportIssueTemplate, ReportIssueTemplateBuilder } from './types';
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type ReportIssueTemplate = {
|
||||
title: string;
|
||||
body: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type ReportIssueTemplateBuilder = ({
|
||||
selection,
|
||||
}: {
|
||||
selection: Selection;
|
||||
}) => ReportIssueTemplate;
|
||||
|
||||
export type Repository = {
|
||||
type: string;
|
||||
name: string;
|
||||
owner: string;
|
||||
protocol: string;
|
||||
resource: string;
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A plugin for contributed TechDocs Addons.
|
||||
*
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export { techdocsModuleAddonsContribPlugin, ReportIssue } from './plugin';
|
||||
export type {
|
||||
ReportIssueProps,
|
||||
ReportIssueTemplate,
|
||||
ReportIssueTemplateBuilder,
|
||||
} from './ReportIssue';
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
import { techdocsModuleAddonsContribPlugin } from './plugin';
|
||||
|
||||
describe('techdocs-addons-contrib', () => {
|
||||
it('should export plugin', () => {
|
||||
expect(techdocsModuleAddonsContribPlugin).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { createPlugin } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
createTechDocsAddonExtension,
|
||||
TechDocsAddonLocations,
|
||||
} from '@backstage/plugin-techdocs-react';
|
||||
import { ReportIssueAddon, ReportIssueProps } from './ReportIssue';
|
||||
|
||||
/**
|
||||
* The TechDocs addons contrib plugin
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
export const techdocsModuleAddonsContribPlugin = createPlugin({
|
||||
id: 'techdocsModuleAddonsContrib',
|
||||
});
|
||||
|
||||
/**
|
||||
* TechDocs addon that lets you select text and open GitHub/Gitlab issues
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
export const ReportIssue = techdocsModuleAddonsContribPlugin.provide(
|
||||
createTechDocsAddonExtension<ReportIssueProps>({
|
||||
name: 'ReportIssue',
|
||||
location: TechDocsAddonLocations.Content,
|
||||
component: ReportIssueAddon,
|
||||
}),
|
||||
);
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
import '@testing-library/jest-dom';
|
||||
import 'cross-fetch/polyfill';
|
||||
Reference in New Issue
Block a user