Merge remote-tracking branch 'origin/master' into erikengervall/plugin-release-manager-as-a-service
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs': minor
|
||||
---
|
||||
|
||||
Add feedback link icon in Techdocs Reader that directs to GitLab or GitHub repo issue page with pre-filled title and source link.
|
||||
For link to appear, requires `repo_url` and `edit_uri` to be filled in mkdocs.yml, as per https://www.mkdocs.org/user-guide/configuration. An `edit_uri` will need to be specified for self-hosted GitLab/GitHub instances with a different host name.
|
||||
To identify issue URL format as GitHub or GitLab, the host name of source in `repo_url` is checked if it contains `gitlab` or `github`. Alternately this is determined by matching to `host` values from `integrations` in app-config.yaml.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Added support for Datadog rum events
|
||||
@@ -13,9 +13,11 @@ Cloudformation
|
||||
Codecov
|
||||
Codehilite
|
||||
Config
|
||||
Datadog
|
||||
Debounce
|
||||
Discoverability
|
||||
Dockerfile
|
||||
dockerfiles
|
||||
Dockerize
|
||||
Docusaurus
|
||||
Env
|
||||
|
||||
@@ -2,6 +2,12 @@ app:
|
||||
title: Backstage Example App
|
||||
baseUrl: http://localhost:3000
|
||||
googleAnalyticsTrackingId: # UA-000000-0
|
||||
datadogRum:
|
||||
clientToken: '123456789'
|
||||
applicationId: qwerty
|
||||
# site: # datadoghq.eu default = datadoghq.com
|
||||
# env: # optional
|
||||
|
||||
support:
|
||||
url: https://github.com/backstage/backstage/issues # Used by common ErrorPage
|
||||
items: # Used by common SupportButton component
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
FROM nginx:mainline
|
||||
|
||||
# The purpose of this image is to serve the frontend app content separately.
|
||||
# By default the Backstage backend uses the app-backend plugin to serve the
|
||||
# app from the backend itself, but it may be desirable to move the frontend
|
||||
# content serving to a separate deployment, in which case this image can be used.
|
||||
|
||||
# This dockerfile requires the app to be built on the host first, as it
|
||||
# simply copies in the build output into the image.
|
||||
|
||||
RUN apt-get update && apt-get -y install jq && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY packages/app/dist /usr/share/nginx/html
|
||||
COPY docker/default.conf.template /etc/nginx/conf.d/default.conf.template
|
||||
COPY docker/run.sh /usr/local/bin/run.sh
|
||||
CMD run.sh
|
||||
|
||||
ENV PORT 80
|
||||
@@ -0,0 +1,59 @@
|
||||
# The purpose of this image is to serve the frontend app content separately.
|
||||
# By default the Backstage backend uses the app-backend plugin to serve the
|
||||
# app from the backend itself, but it may be desirable to move the frontend
|
||||
# content serving to a separate deployment, in which case this image can be
|
||||
# used.
|
||||
|
||||
# This dockerfile also performs the build first inside docker. This may come
|
||||
# with a build time impact, but is sometimes desirable. If you want to run the
|
||||
# build on the host instead, use the file simply named Dockerfile in this folder
|
||||
# instead.
|
||||
|
||||
# USAGE:
|
||||
#
|
||||
# - Copy this file and the "docker" folder from this directory to your project
|
||||
# root
|
||||
#
|
||||
# - Update your .dockerignore, make sure that the source folders are not
|
||||
# excluded, but do exclude node_modules and build artifacts:
|
||||
#
|
||||
# .git
|
||||
# node_modules
|
||||
# packages/*/dist
|
||||
# packages/*/node_modules
|
||||
# plugins/*/dist
|
||||
# plugins/*/node_modules
|
||||
#
|
||||
# - Update the copy of this file to add configuration arguments to the "build"
|
||||
# command, for example:
|
||||
#
|
||||
# RUN yarn workspace app build --config <config1> --config <config2> ...
|
||||
#
|
||||
# - In your project root, run:
|
||||
#
|
||||
# docker build -t backstage-frontend -f Dockerfile.dockerbuild .
|
||||
|
||||
|
||||
|
||||
FROM node:14-buster AS build
|
||||
|
||||
RUN mkdir /app
|
||||
COPY . /app
|
||||
WORKDIR /app
|
||||
|
||||
RUN yarn install
|
||||
RUN yarn workspace app build
|
||||
|
||||
|
||||
|
||||
FROM nginx:mainline
|
||||
|
||||
RUN apt-get update && apt-get -y install jq && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=build /app/packages/app/dist /usr/share/nginx/html
|
||||
COPY docker/default.conf.template /etc/nginx/conf.d/default.conf.template
|
||||
COPY docker/run.sh /usr/local/bin/run.sh
|
||||
|
||||
CMD run.sh
|
||||
|
||||
ENV PORT 80
|
||||
@@ -0,0 +1,41 @@
|
||||
# The purpose of this image is to serve the frontend app content separately.
|
||||
# By default the Backstage backend uses the app-backend plugin to serve the
|
||||
# app from the backend itself, but it may be desirable to move the frontend
|
||||
# content serving to a separate deployment, in which case this image can be
|
||||
# used.
|
||||
|
||||
# This dockerfile requires the app to be built on the host first, as it
|
||||
# simply copies in the build output into the image. If you want to also perform
|
||||
# the build itself inside docker, use Dockerfile.build in this folder instead.
|
||||
|
||||
|
||||
# USAGE:
|
||||
#
|
||||
# - Copy this file and the "docker" folder from this directory to your project
|
||||
# root
|
||||
#
|
||||
# - Add the following line to your .dockerignore to make sure that the built
|
||||
# frontend actually can be transferred into the docker image:
|
||||
#
|
||||
# !packages/app/dist
|
||||
#
|
||||
# - In your project root, run:
|
||||
#
|
||||
# yarn install
|
||||
# yarn tsc
|
||||
# yarn build --config <config1> --config <config2> ...
|
||||
# docker build -t backstage-frontend -f Dockerfile.hostbuild .
|
||||
|
||||
|
||||
|
||||
FROM nginx:mainline
|
||||
|
||||
RUN apt-get update && apt-get -y install jq && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY packages/app/dist /usr/share/nginx/html
|
||||
COPY docker/default.conf.template /etc/nginx/conf.d/default.conf.template
|
||||
COPY docker/run.sh /usr/local/bin/run.sh
|
||||
|
||||
CMD run.sh
|
||||
|
||||
ENV PORT 80
|
||||
@@ -0,0 +1,16 @@
|
||||
# Frontend with NGINX
|
||||
|
||||
This folder contains Docker images that let you run the Backstage frontend as
|
||||
a separate image, rather than having it served through the `app-backend` plugin
|
||||
from the backend.
|
||||
|
||||
Note that when running the frontend like this, the app configuration becomes
|
||||
embedded into the actual static JavaScript files at build time. This means that
|
||||
you will have to supply the list of configuration files as part of the command
|
||||
line at build.
|
||||
|
||||
## Usage
|
||||
|
||||
There are two variants: one that builds inside Docker, and one that builds on
|
||||
the host. See the comments at the top of the individual dockerfiles for usage
|
||||
instructions.
|
||||
@@ -1,23 +0,0 @@
|
||||
FROM node:12-buster AS build
|
||||
|
||||
RUN mkdir /app
|
||||
COPY . /app
|
||||
WORKDIR /app
|
||||
|
||||
RUN yarn install
|
||||
RUN yarn workspace example-app build
|
||||
|
||||
# Contruct backstage-frontend image
|
||||
FROM nginx:mainline
|
||||
|
||||
RUN apt-get update && apt-get -y install jq && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy from build stage
|
||||
COPY --from=build /app/packages/app/dist /usr/share/nginx/html
|
||||
|
||||
COPY docker/default.conf.template /etc/nginx/conf.d/default.conf.template
|
||||
COPY docker/run.sh /usr/local/bin/run.sh
|
||||
|
||||
CMD run.sh
|
||||
|
||||
ENV PORT 80
|
||||
@@ -1,19 +0,0 @@
|
||||
# Standalone Dockerfile for frontend
|
||||
|
||||
This directory contains the resources which will help you build backstage without any requirements
|
||||
other than docker itself. It uses a multi-stage Dockerfile to build and ship backstage.
|
||||
|
||||
## Usage
|
||||
|
||||
You can simply run the following command to build backstage.
|
||||
|
||||
```
|
||||
# Make sure you are in the root directory of backstage then run
|
||||
docker build -t backstage-frontend -f ./contrib/docker/multi-stage-frontend/Dockerfile .
|
||||
```
|
||||
|
||||
After a successful build, You can simply run backstage frontend with the following command.
|
||||
|
||||
```
|
||||
docker run -it --rm -p 3080:80 backstage-frontend
|
||||
```
|
||||
@@ -232,7 +232,7 @@ package, which is done as follows:
|
||||
Once the `app-backend` is removed from the backend, you can use your favorite
|
||||
static file serving method for serving the frontend. An example of how to set up
|
||||
an NGINX image is available in the
|
||||
[contrib folder in the main repo](https://github.com/backstage/backstage/blob/master/contrib/docker/frontend-with-nginx/Dockerfile)
|
||||
[contrib folder in the main repo](https://github.com/backstage/backstage/blob/master/contrib/docker/frontend-with-nginx)
|
||||
|
||||
Note that if you're building a separate docker build of the frontend you
|
||||
probably need to adjust `.dockerignore` appropriately. Most likely by making
|
||||
|
||||
@@ -45,3 +45,15 @@ metadata annotation is used in the build process of TechDocs. But when
|
||||
annotation should still be present in entity descriptor file (e.g.
|
||||
`catalog-info.yaml`) for Backstage to know that TechDocs is enabled for the
|
||||
entity.
|
||||
|
||||
#### Is it possible for users to suggest changes or provide feedback on a TechDocs page?
|
||||
|
||||
This is supported for TechDocs sites whose source code is hosted in either
|
||||
GitHub or GitLab. In order to add "edit this page" and "leave feedback" buttons
|
||||
on a TechDocs page, be sure that you have `repo_url` and `edit_uri` values in
|
||||
your `mkdocs.yml` files per
|
||||
[MkDocs instructions](https://www.mkdocs.org/user-guide/configuration).
|
||||
|
||||
If the host name of your source code hosting URL does not include `github` or
|
||||
`gitlab`, an `integrations` entry in your `app-config.yaml` pointed at your
|
||||
source code provider is also needed (only the `host` key is necessary).
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
id: installation
|
||||
title: Datadog RUM Installation
|
||||
sidebar_label: Installation
|
||||
# prettier-ignore
|
||||
description: Adding Datadog RUM to Your App
|
||||
---
|
||||
|
||||
There is a basic [Datadog](https://docs.datadoghq.com/real_user_monitoring/)
|
||||
integration built into Backstage. You can enable it by adding the following to
|
||||
your app configuration:
|
||||
|
||||
```yaml
|
||||
app:
|
||||
datadogRum:
|
||||
clientToken: '123456789'
|
||||
applicationId: qwerty
|
||||
# site: # datadoghq.eu default = datadoghq.com
|
||||
# env: # optional
|
||||
```
|
||||
|
||||
Replace the clientToken and applicationId with the ones generated for you
|
||||
Datadog.
|
||||
|
||||
optional arguments:
|
||||
|
||||
```
|
||||
site: datadoghq.eu # default equals datadoghq.com
|
||||
env: dev # allow to specify the environment
|
||||
```
|
||||
@@ -13,6 +13,11 @@ Backstage integrator.
|
||||
See how to install Google Analytics in your app
|
||||
[here](../integrations/google-analytics/installation.md)
|
||||
|
||||
## Datadog RUM Events
|
||||
|
||||
See how to install Datadog Events in your app
|
||||
[here](../integrations/datadog-rum/installation.md)
|
||||
|
||||
## Logging
|
||||
|
||||
The backend supplies a central [winston](https://github.com/winstonjs/winston)
|
||||
|
||||
@@ -49,8 +49,8 @@
|
||||
</style>
|
||||
<title><%= app.title %></title>
|
||||
|
||||
<% if (app.googleAnalyticsTrackingId && typeof app.googleAnalyticsTrackingId
|
||||
=== 'string') { %>
|
||||
<% if (app.googleAnalyticsTrackingId && typeof
|
||||
app.googleAnalyticsTrackingId==='string' ) { %>
|
||||
<script
|
||||
async
|
||||
src="https://www.googletagmanager.com/gtag/js?id=<%= app.googleAnalyticsTrackingId %>"
|
||||
@@ -64,8 +64,43 @@
|
||||
|
||||
gtag('config', '<%= app.googleAnalyticsTrackingId %>');
|
||||
</script>
|
||||
<% } %> <% if (app.datadogRum.clientToken && app.datadogRum.applicationId )
|
||||
{ %>
|
||||
<script>
|
||||
(function (h, o, u, n, d) {
|
||||
h = h[d] = h[d] || {
|
||||
q: [],
|
||||
onReady: function (c) {
|
||||
h.q.push(c);
|
||||
},
|
||||
};
|
||||
d = o.createElement(u);
|
||||
d.async = 1;
|
||||
d.src = n;
|
||||
n = o.getElementsByTagName(u)[0];
|
||||
n.parentNode.insertBefore(d, n);
|
||||
})(
|
||||
window,
|
||||
document,
|
||||
'script',
|
||||
'https://www.datadoghq-browser-agent.com/datadog-rum.js',
|
||||
'DD_RUM',
|
||||
);
|
||||
DD_RUM.onReady(function () {
|
||||
DD_RUM.init({
|
||||
clientToken: '<%= app.datadogRum.clientToken %>',
|
||||
applicationId: '<%= app.datadogRum.applicationId %>',
|
||||
site: '<%= app.datadogRum.site %>' || 'datadoghq.com',
|
||||
service: 'backstage',
|
||||
env: '<%= app.datadogRum.env %>',
|
||||
sampleRate: 100,
|
||||
trackInteractions: true,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<% } %>
|
||||
</head>
|
||||
|
||||
<body style="margin: 0">
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -180,6 +180,36 @@
|
||||
"UA-000000-0"
|
||||
]
|
||||
},
|
||||
"datadogRum": {
|
||||
"type": "object",
|
||||
"description": "Datadog RUM events configuration",
|
||||
"properties": {
|
||||
"env": {
|
||||
"type": "string",
|
||||
"visibility": "frontend",
|
||||
"description": "Environment for Datadog RUM events"
|
||||
},
|
||||
"clientToken": {
|
||||
"type": "string",
|
||||
"visibility": "frontend",
|
||||
"description": "clientToken for Datadog RUM events"
|
||||
},
|
||||
"applicationId": {
|
||||
"type": "string",
|
||||
"visibility": "frontend",
|
||||
"description": "applicationId for Datadog RUM events"
|
||||
},
|
||||
"site": {
|
||||
"type": "string",
|
||||
"visibility": "frontend",
|
||||
"description": "site for Datadog RUM events"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"clientToken",
|
||||
"applicationId"
|
||||
]
|
||||
},
|
||||
"listen": {
|
||||
"type": "object",
|
||||
"description": "Listening configuration for local development",
|
||||
|
||||
@@ -127,6 +127,16 @@ export async function createConfig(
|
||||
googleAnalyticsTrackingId: frontendConfig.getOptionalString(
|
||||
'app.googleAnalyticsTrackingId',
|
||||
),
|
||||
datadogRum: {
|
||||
env: frontendConfig.getOptionalString('app.datadogRum.env'),
|
||||
clientToken: frontendConfig.getOptionalString(
|
||||
'app.datadogRum.clientToken',
|
||||
),
|
||||
applicationId: frontendConfig.getOptionalString(
|
||||
'app.datadogRum.applicationId',
|
||||
),
|
||||
site: frontendConfig.getOptionalString('app.datadogRum.site'),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
||||
@@ -1,12 +1,25 @@
|
||||
# Catalog Frontend
|
||||
|
||||
WORK IN PROGRESS
|
||||
# Backstage Catalog Frontend
|
||||
|
||||
This is the frontend part of the default catalog plugin.
|
||||
|
||||
It will implement the core API for handling your catalog of software, and
|
||||
supply the base views to show and manage them.
|
||||
|
||||
## Getting Started
|
||||
|
||||
This frontend plugin can be started in a standalone mode from directly in this package
|
||||
with `yarn start`. However, it will have limited functionality and that process is
|
||||
most convenient when developing the catalog frontend plugin itself.
|
||||
|
||||
To evaluate the catalog and have a greater amount of functionality available, from the main
|
||||
Backstage root folder, instead do:
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
This will launch both frontend and backend in the same window, populated with some example entities.
|
||||
|
||||
## Links
|
||||
|
||||
- [Backend part of the plugin](https://github.com/backstage/backstage/tree/master/plugins/catalog-backend)
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
"Quiché": "Xe q’ij",
|
||||
"Romani [Sinte]": "Lashi rachi",
|
||||
"Romanian": "Bunã seara",
|
||||
"Russian": "Dobry vyecher",
|
||||
"Russian": "Добрый вечер",
|
||||
"Scottish Gaelic": "Feasgar mhath",
|
||||
"Scots": "Guid eenin",
|
||||
"Sesotho": "Fonane",
|
||||
@@ -91,7 +91,7 @@
|
||||
"Telugu": "శుభ సాయంత్రం",
|
||||
"Thai": "Sawat-dii torn khum",
|
||||
"Turkish": "İyi akşamlar",
|
||||
"Ukrainian": "Dobry vechir",
|
||||
"Ukrainian": "Добрий вечiр",
|
||||
"Uzbek": "Xayrli kech",
|
||||
"Welsh": "Noswaith dda",
|
||||
"Yiddish": "Ah gutn ovnt",
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { EntityName } from '@backstage/catalog-model';
|
||||
import { useApi } from '@backstage/core';
|
||||
import { useApi, configApiRef } from '@backstage/core';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { useTheme } from '@material-ui/core';
|
||||
import { Alert } from '@material-ui/lab';
|
||||
@@ -31,6 +31,7 @@ import transformer, {
|
||||
rewriteDocLinks,
|
||||
sanitizeDOM,
|
||||
simplifyMkdocsFooter,
|
||||
addGitFeedbackLink,
|
||||
} from '../transformers';
|
||||
import { TechDocsNotFound } from './TechDocsNotFound';
|
||||
import TechDocsProgressBar from './TechDocsProgressBar';
|
||||
@@ -52,6 +53,7 @@ export const Reader = ({ entityId, onReady }: Props) => {
|
||||
const [loadedPath, setLoadedPath] = useState('');
|
||||
const [atInitialLoad, setAtInitialLoad] = useState(true);
|
||||
const [newerDocsExist, setNewerDocsExist] = useState(false);
|
||||
const configApi = useApi(configApiRef);
|
||||
|
||||
const {
|
||||
value: isSynced,
|
||||
@@ -142,6 +144,7 @@ export const Reader = ({ entityId, onReady }: Props) => {
|
||||
rewriteDocLinks(),
|
||||
removeMkdocsHeader(),
|
||||
simplifyMkdocsFooter(),
|
||||
addGitFeedbackLink(configApi),
|
||||
injectCss({
|
||||
css: `
|
||||
body {
|
||||
@@ -313,6 +316,7 @@ export const Reader = ({ entityId, onReady }: Props) => {
|
||||
name,
|
||||
newerDocsExist,
|
||||
isSynced,
|
||||
configApi,
|
||||
]);
|
||||
|
||||
// docLoadError not considered an error state if sync request is still ongoing
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* 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 { createTestShadowDom } from '../../test-utils';
|
||||
import { addGitFeedbackLink } from './addGitFeedbackLink';
|
||||
|
||||
const configApi = {
|
||||
getConfigArray: function getConfigArray(key: string) {
|
||||
return key === 'integrations.github'
|
||||
? [{ data: { host: 'self-hosted-git-hub-provider.com' } }]
|
||||
: [];
|
||||
},
|
||||
};
|
||||
|
||||
describe('addGitFeedbackLink', () => {
|
||||
it('adds a feedback link when a Gitlab source edit link is available', () => {
|
||||
const shadowDom = createTestShadowDom(
|
||||
`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<article class="md-content__inner">
|
||||
<h1>HeaderText</h1>
|
||||
<a title="Edit this page" href="https://gitlab.com/reponame/username/docs/TestDoc.md"></>
|
||||
</article>
|
||||
</html>
|
||||
`,
|
||||
{
|
||||
preTransformers: [addGitFeedbackLink(configApi)],
|
||||
postTransformers: [],
|
||||
},
|
||||
);
|
||||
|
||||
expect(shadowDom.querySelector('#git-feedback-link')).toBeTruthy();
|
||||
expect(
|
||||
(shadowDom.querySelector('#git-feedback-link') as HTMLLinkElement)!.href,
|
||||
).toEqual(
|
||||
'https://gitlab.com/reponame/username/issues/new?issue[title]=Documentation%20Feedback%3A%20HeaderText&issue[description]=Page%20source%3A%0Ahttps%3A%2F%2Fgitlab.com%2Freponame%2Fusername%2Fdocs%2FTestDoc.md%0A%0AFeedback%3A',
|
||||
);
|
||||
});
|
||||
|
||||
it('adds a feedback link when a Github source edit link is available', () => {
|
||||
const shadowDom = createTestShadowDom(
|
||||
`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<article class="md-content__inner">
|
||||
<h1>HeaderText</h1>
|
||||
<a title="Edit this page" href="https://github.com/reponame/username/docs/TestDoc.md"></>
|
||||
</article>
|
||||
</html>
|
||||
`,
|
||||
{
|
||||
preTransformers: [addGitFeedbackLink(configApi)],
|
||||
postTransformers: [],
|
||||
},
|
||||
);
|
||||
|
||||
expect(shadowDom.querySelector('#git-feedback-link')).toBeTruthy();
|
||||
expect(
|
||||
(shadowDom.querySelector('#git-feedback-link') as HTMLLinkElement)!.href,
|
||||
).toEqual(
|
||||
'https://github.com/reponame/username/issues/new?title=Documentation%20Feedback%3A%20HeaderText&body=Page%20source%3A%0Ahttps%3A%2F%2Fgithub.com%2Freponame%2Fusername%2Fdocs%2FTestDoc.md%0A%0AFeedback%3A',
|
||||
);
|
||||
});
|
||||
|
||||
it('does not add a feedback link when no source edit link is available', () => {
|
||||
const shadowDom = createTestShadowDom(
|
||||
`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<article class="md-content__inner">
|
||||
<h1>HeaderText<a class="headerlink" href="http://headerlink.com">¶</a></h1>
|
||||
</article>
|
||||
</html>
|
||||
`,
|
||||
{
|
||||
preTransformers: [addGitFeedbackLink(configApi)],
|
||||
postTransformers: [],
|
||||
},
|
||||
);
|
||||
|
||||
expect(shadowDom.querySelector('#git-feedback-link')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('does not add a feedback link when a Gitlab or Github source edit link is not available', () => {
|
||||
const shadowDom = createTestShadowDom(
|
||||
`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<article class="md-content__inner">
|
||||
<h1>HeaderText<a class="headerlink" href="http://headerlink.com">¶</a></h1>
|
||||
<a title="Edit this page" href="https://not-a-git-provider.com/reponame/username/docs/TestDoc.md"/>
|
||||
</article>
|
||||
</html>
|
||||
`,
|
||||
{
|
||||
preTransformers: [addGitFeedbackLink(configApi)],
|
||||
postTransformers: [],
|
||||
},
|
||||
);
|
||||
|
||||
expect(shadowDom.querySelector('#git-feedback-link')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('adds a feedback link when a Gitlab or Github source edit link is not available but hostname matches an integrations host', () => {
|
||||
const shadowDom = createTestShadowDom(
|
||||
`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<article class="md-content__inner">
|
||||
<h1>HeaderText<a class="headerlink" href="http://headerlink.com">¶</a></h1>
|
||||
<a title="Edit this page" href="https://self-hosted-git-hub-provider.com/reponame/username/docs/TestDoc.md"/>
|
||||
</article>
|
||||
</html>
|
||||
`,
|
||||
{
|
||||
preTransformers: [addGitFeedbackLink(configApi)],
|
||||
postTransformers: [],
|
||||
},
|
||||
);
|
||||
|
||||
expect(shadowDom.querySelector('#git-feedback-link')).toBeTruthy();
|
||||
expect(
|
||||
(shadowDom.querySelector('#git-feedback-link') as HTMLLinkElement)!.href,
|
||||
).toEqual(
|
||||
'https://self-hosted-git-hub-provider.com/reponame/username/issues/new?title=Documentation%20Feedback%3A%20HeaderText&body=Page%20source%3A%0Ahttps%3A%2F%2Fself-hosted-git-hub-provider.com%2Freponame%2Fusername%2Fdocs%2FTestDoc.md%0A%0AFeedback%3A',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* 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 type { Transformer } from './index';
|
||||
import FeedbackOutlinedIcon from '@material-ui/icons/FeedbackOutlined';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
// requires repo
|
||||
export const addGitFeedbackLink = (configApi: any): Transformer => {
|
||||
return dom => {
|
||||
// attempting to use selectors that are more likely to be static as MkDocs updates over time
|
||||
const sourceAnchor = dom.querySelector(
|
||||
'[title="Edit this page"]',
|
||||
) as HTMLAnchorElement;
|
||||
|
||||
// don't show if edit link not available in raw page
|
||||
if (!sourceAnchor || !sourceAnchor.href) {
|
||||
return dom;
|
||||
}
|
||||
let gitHost = '';
|
||||
|
||||
const sourceURL = new URL(sourceAnchor.href);
|
||||
const githubHosts = configApi
|
||||
.getConfigArray('integrations.github')
|
||||
.map((integration: any) => integration.data.host);
|
||||
const gitlabHosts = configApi
|
||||
.getConfigArray('integrations.gitlab')
|
||||
.map((integration: any) => integration.data.host);
|
||||
|
||||
// don't show if can't identify edit link hostname as a gitlab/github hosting
|
||||
if (
|
||||
githubHosts.includes(sourceURL.hostname) ||
|
||||
sourceURL.origin.includes('github')
|
||||
) {
|
||||
gitHost = 'github';
|
||||
} else if (
|
||||
gitlabHosts.includes(sourceURL.hostname) ||
|
||||
sourceURL.origin.includes('gitlab')
|
||||
) {
|
||||
gitHost = 'gitlab';
|
||||
} else {
|
||||
return dom;
|
||||
}
|
||||
|
||||
// topmost h1 only contains title for whole page
|
||||
const title = (dom.querySelector('article>h1') as HTMLElement).childNodes[0]
|
||||
.textContent;
|
||||
const issueTitle = encodeURIComponent(`Documentation Feedback: ${title}`);
|
||||
const issueDesc = encodeURIComponent(
|
||||
`Page source:\n${sourceAnchor.href}\n\nFeedback:`,
|
||||
);
|
||||
const repoPath = sourceURL.pathname.split('/').slice(0, 3).join('/');
|
||||
|
||||
const feedbackLink = sourceAnchor.cloneNode() as HTMLAnchorElement;
|
||||
switch (gitHost) {
|
||||
case 'gitlab':
|
||||
feedbackLink.href = `${sourceURL.origin}${repoPath}/issues/new?issue[title]=${issueTitle}&issue[description]=${issueDesc}`;
|
||||
break;
|
||||
case 'github':
|
||||
feedbackLink.href = `${sourceURL.origin}${repoPath}/issues/new?title=${issueTitle}&body=${issueDesc}`;
|
||||
break;
|
||||
default:
|
||||
return dom;
|
||||
}
|
||||
ReactDOM.render(React.createElement(FeedbackOutlinedIcon), feedbackLink);
|
||||
feedbackLink.style.paddingLeft = '5px';
|
||||
feedbackLink.title = 'Leave feedback for this page';
|
||||
feedbackLink.id = 'git-feedback-link';
|
||||
sourceAnchor?.insertAdjacentElement('beforebegin', feedbackLink);
|
||||
return dom;
|
||||
};
|
||||
};
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
export * from './addBaseUrl';
|
||||
export * from './addGitFeedbackLink';
|
||||
export * from './rewriteDocLinks';
|
||||
export * from './addLinkClickListener';
|
||||
export * from './removeMkdocsHeader';
|
||||
|
||||
Reference in New Issue
Block a user