aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorMathieu Suen <mathieu.suen@sonarsource.com>2022-10-19 22:59:57 +0200
committersonartech <sonartech@sonarsource.com>2022-10-24 20:04:04 +0000
commiteb249087f989c12a7e25c72a91a8eb7cd3ef0a9d (patch)
tree4b2cddd7eb1efdddf62978eceebc3b50d9093f95 /server
parent3e5e886cab8c75cc587f4978510343e29bc33d95 (diff)
downloadsonarqube-eb249087f989c12a7e25c72a91a8eb7cd3ef0a9d.tar.gz
sonarqube-eb249087f989c12a7e25c72a91a8eb7cd3ef0a9d.zip
SONAR-17221 Documentation links change to static documentation site
- Remove markdown injection - Redirection for old documentation link to the static site - Drop the static documentation app
Diffstat (limited to 'server')
-rw-r--r--server/sonar-docs/src/__tests__/BrokenLinkSafetyNet.test.js23
-rw-r--r--server/sonar-docs/src/pages/setup/upgrade-notes.md8
-rw-r--r--server/sonar-docs/static/SonarQubeNavigationTree.json222
-rw-r--r--server/sonar-web/package.json9
-rw-r--r--server/sonar-web/src/main/js/@types/rehype-raw.d.ts22
-rw-r--r--server/sonar-web/src/main/js/@types/rehype-react.d.ts22
-rw-r--r--server/sonar-web/src/main/js/@types/rehype-slug.d.ts22
-rw-r--r--server/sonar-web/src/main/js/@types/remark-custom-blocks.d.ts22
-rw-r--r--server/sonar-web/src/main/js/@types/remark-react.d.ts33
-rw-r--r--server/sonar-web/src/main/js/@types/remark-rehype.d.ts22
-rw-r--r--server/sonar-web/src/main/js/@types/remark.d.ts22
-rw-r--r--server/sonar-web/src/main/js/@types/unist-util-visit.d.ts25
-rw-r--r--server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts38
-rw-r--r--server/sonar-web/src/main/js/app/components/DocumentationRedirect.tsx51
-rw-r--r--server/sonar-web/src/main/js/app/components/GlobalFooter.tsx3
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/DocumentationRedirect-test.tsx51
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx8
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalFooter-test.tsx.snap18
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLike.tsx10
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/component/branch-like/__tests__/__snapshots__/CurrentBranchLike-test.tsx.snap8
-rw-r--r--server/sonar-web/src/main/js/app/utils/startReactApp.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/audit-logs/components/__tests__/AuditApp-it.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/Header.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/ProfileFacet.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/__tests__/pages-test.ts127
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/App.tsx237
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/Menu.tsx88
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/MenuBlock.tsx103
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/MenuExternalLink.tsx37
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/MenuItem.tsx51
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/SearchResultEntry.tsx131
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/SearchResults.tsx170
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/Sidebar.tsx75
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx139
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/__tests__/Menu-test.tsx58
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/__tests__/MenuBlock-test.tsx89
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/__tests__/MenuItem-test.tsx39
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/__tests__/SearchResultEntry-test.tsx105
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/__tests__/SearchResults-test.tsx262
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/__tests__/Sidebar-test.tsx56
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/App-test.tsx.snap151
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/Menu-test.tsx.snap118
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/MenuBlock-test.tsx.snap124
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/MenuItem-test.tsx.snap37
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/SearchResultEntry-test.tsx.snap142
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/SearchResults-test.tsx.snap80
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/Sidebar-test.tsx.snap145
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/documentation.directory-loader.js24
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/navTreeUtils.ts94
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/pages.ts92
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/routes.tsx31
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/styles.css201
-rw-r--r--server/sonar-web/src/main/js/apps/documentation/utils.ts128
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/App.tsx8
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/App-test.tsx.snap14
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/EditionBox.tsx119
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/EditionBox-test.tsx.snap75
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelNoNewCode.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/MeasuresPanelNoNewCode-test.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanelNoNewCode-test.tsx.snap18
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/AppHeader.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/__snapshots__/AppHeader-test.tsx.snap12
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/PageHeader-test.tsx.snap55
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/EmptyHotspotsPage.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/EmptyHotspotsPage-test.tsx.snap22
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/AnalysisScope.tsx8
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/NewCodePeriod.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AnalysisScope-test.tsx.snap6
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/NewCodePeriod-test.tsx.snap6
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormField.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/AzureForm.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketCloudForm.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketServerForm.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabForm.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionBox-test.tsx.snap14
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormField-test.tsx.snap11
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AzureForm-test.tsx.snap14
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketCloudForm-test.tsx.snap14
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketServerForm-test.tsx.snap7
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubForm-test.tsx.snap14
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabForm-test.tsx.snap14
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/authentication/Authentication.tsx10
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/AlmSpecificForm.tsx8
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/AlmSpecificForm-test.tsx.snap7
-rw-r--r--server/sonar-web/src/main/js/apps/settings/encryption/EncryptionForm.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/settings/encryption/GenerateSecretKeyForm.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/settings/encryption/__tests__/__snapshots__/EncryptionForm-test.tsx.snap7
-rw-r--r--server/sonar-web/src/main/js/apps/settings/encryption/__tests__/__snapshots__/GenerateSecretKeyForm-test.tsx.snap7
-rw-r--r--server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx8
-rw-r--r--server/sonar-web/src/main/js/apps/webhooks/components/PageHeader.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/PageHeader-test.tsx.snap6
-rw-r--r--server/sonar-web/src/main/js/components/common/DocLink.tsx (renamed from server/sonar-web/src/main/js/components/docs/DocImg.tsx)27
-rw-r--r--server/sonar-web/src/main/js/components/common/DocumentationTooltip.tsx15
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/DocumentationTooltip-test.tsx4
-rw-r--r--server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/DocumentationTooltip-test.tsx.snap12
-rw-r--r--server/sonar-web/src/main/js/components/docs/DocCollapsibleBlock.tsx71
-rw-r--r--server/sonar-web/src/main/js/components/docs/DocLink.tsx113
-rw-r--r--server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.css74
-rw-r--r--server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx140
-rw-r--r--server/sonar-web/src/main/js/components/docs/DocToc.tsx155
-rw-r--r--server/sonar-web/src/main/js/components/docs/DocTooltipLink.tsx55
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/DocCollapsibleBlock-test.tsx48
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/DocLink-test.tsx82
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/DocMarkdownBlock-test.tsx153
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/DocToc-test.tsx116
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/DocTooltipLink-test.tsx36
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocCollapsibleBlock-test.tsx.snap50
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocLink-test.tsx.snap69
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocMarkdownBlock-test.tsx.snap148
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocToc-test.tsx.snap62
-rw-r--r--server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltipLink-test.tsx.snap23
-rw-r--r--server/sonar-web/src/main/js/components/docs/plugins/__tests__/remark-only-toc-test.ts51
-rw-r--r--server/sonar-web/src/main/js/components/docs/plugins/remark-only-toc.ts39
-rw-r--r--server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx28
-rw-r--r--server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsSuggestions.json (renamed from server/sonar-docs/src/EmbedDocsSuggestions.json)38
-rw-r--r--server/sonar-web/src/main/js/components/embed-docs-modal/SuggestionsProvider.tsx4
-rw-r--r--server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/SuggestionsProvider-test.tsx7
-rw-r--r--server/sonar-web/src/main/js/components/issue/components/IssueMessageTags.tsx2
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/AlertClassicEditor.tsx6
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/PublishSteps.tsx6
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/CompilationInfo.tsx15
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/ProjectTokenScopeInfo.tsx7
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/CompilationInfo-test.tsx.snap16
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx6
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/PreRequisitesStep-test.tsx.snap21
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/DoneNextSteps.tsx16
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/TokenStep.tsx4
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/__tests__/__snapshots__/DoneNextSteps-test.tsx.snap32
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/__tests__/__snapshots__/TokenStep-test.tsx.snap6
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetExecute.tsx6
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/ExecBuildWrapper.tsx6
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/ExecScanner.tsx6
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/JavaGradle.tsx10
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/JavaMaven.tsx6
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/DotNetExecute-test.tsx.snap7
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/ExecBuildWrapper-test.tsx.snap21
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/ExecScanner-test.tsx.snap35
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap14
-rw-r--r--server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap7
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/markdown-test.ts.snap41
-rw-r--r--server/sonar-web/src/main/js/helpers/__tests__/markdown-test.ts178
-rw-r--r--server/sonar-web/src/main/js/helpers/constants.ts10
-rw-r--r--server/sonar-web/src/main/js/helpers/docs.ts (renamed from server/sonar-web/src/main/js/helpers/markdown.d.ts)20
-rw-r--r--server/sonar-web/src/main/js/helpers/markdown.js119
-rw-r--r--server/sonar-web/src/main/js/helpers/testMocks.ts15
-rw-r--r--server/sonar-web/tsconfig.json1
-rw-r--r--server/sonar-web/yarn.lock823
153 files changed, 686 insertions, 6784 deletions
diff --git a/server/sonar-docs/src/__tests__/BrokenLinkSafetyNet.test.js b/server/sonar-docs/src/__tests__/BrokenLinkSafetyNet.test.js
index b4bd3125731..7b3f96553b5 100644
--- a/server/sonar-docs/src/__tests__/BrokenLinkSafetyNet.test.js
+++ b/server/sonar-docs/src/__tests__/BrokenLinkSafetyNet.test.js
@@ -45,7 +45,7 @@ it('should have at least one instance of all possible frontmatter fields', () =>
/* eslint-disable no-console */
it('should have valid links in trees files', () => {
- const trees = ['SonarQubeNavigationTree.json', 'StaticNavigationTree.json'];
+ const trees = ['StaticNavigationTree.json'];
let hasErrors = false;
trees.forEach(file => {
const tree = JSON.parse(fs.readFileSync(path.join(rootPath, '..', 'static', file), 'utf8'));
@@ -65,27 +65,6 @@ it('should have valid links in trees files', () => {
expect(hasErrors).toBe(false);
});
-it('should have valid links in suggestions file', () => {
- const file = 'EmbedDocsSuggestions.json';
- const suggestions = JSON.parse(fs.readFileSync(path.join(rootPath, file), 'utf8'));
- const hasErrors = Object.keys(suggestions).some(key => {
- return suggestions[key].some(suggestion => {
- if (!suggestion.link.startsWith('/documentation/')) {
- console.log(
- `[${suggestion.link}] should starts with "/documentation/" or be a valid url, in ${file}`
- );
- return true;
- }
- if (!urlExists(parsedFiles, suggestion.link.replace('/documentation', ''))) {
- console.log(`[${suggestion.link}] is not a valid link, in ${file}`);
- return true;
- }
- return false;
- });
- });
- expect(hasErrors).toBe(false);
-});
-
function collectErrors() {
let urlLists = [];
let hasErrors = false;
diff --git a/server/sonar-docs/src/pages/setup/upgrade-notes.md b/server/sonar-docs/src/pages/setup/upgrade-notes.md
index d5dcfe21fe3..f568017cb11 100644
--- a/server/sonar-docs/src/pages/setup/upgrade-notes.md
+++ b/server/sonar-docs/src/pages/setup/upgrade-notes.md
@@ -3,6 +3,14 @@ title: Release Upgrade Notes
url: /setup/upgrade-notes/
---
+## Release 9.8 Upgrade notes
+**Dropping the embedded documentation**
+SonarQube no longer ships with an embedded version of the documentation. The documentation will now only be available at [docs.sonarqube.org](https://docs.sonarqube.org/). ([SONAR-17221](https://sonarsource.atlassian.net/browse/SONAR-17221))
+* All in-app links will now point to the documentation website.
+* External links that pointed to `/documentation` will be correctly redirected to the corresponding page on the documentation website.
+
+[Full release notes](https://sonarsource.atlassian.net/issues/?jql=project%20%3D%2010139%20AND%20fixVersion%20%3D%2013884)
+
## Release 9.7 Upgrade notes
**Change in the database connection pool**
The database connection pool has been replaced for better performance. The `sonar.jdbc.maxIdle`, `sonar.jdbc.minEvictableIdleTimeMillis` and `sonar.jdbc.timeBetweenEvictionRunsMillis` properties no longer have any effect and should be removed from the configuration. Also, the JMX information that is provided to monitor the connection pool has evolved. See the [Monitoring documentation](/instance-administration/monitoring/) for more information. ([SONAR-17200](https://sonarsource.atlassian.net/browse/SONAR-17200)).
diff --git a/server/sonar-docs/static/SonarQubeNavigationTree.json b/server/sonar-docs/static/SonarQubeNavigationTree.json
deleted file mode 100644
index 0e47a473fbb..00000000000
--- a/server/sonar-docs/static/SonarQubeNavigationTree.json
+++ /dev/null
@@ -1,222 +0,0 @@
-[
- {
- "title": "Requirements",
- "children": [
- "/requirements/requirements/",
- "/requirements/hardware-recommendations/"
- ]
- },
- {
- "title": "Analyzing Source Code",
- "children": [
- "/analysis/overview/",
- {
- "title": "Scanners",
- "children": [
- "/analysis/scan/sonarscanner-for-gradle/",
- "/analysis/scan/sonarscanner-for-msbuild/",
- "/analysis/scan/sonarscanner-for-maven/",
- "/analysis/scan/sonarscanner-for-azure-devops/",
- "/analysis/scan/sonarscanner-for-jenkins/",
- "/analysis/scan/sonarscanner-for-ant/",
- "/analysis/scan/sonarscanner/"
- ]
- },
- "/analysis/analysis-parameters/",
- {
- "title": "Languages",
- "children": [
- "/analysis/languages/overview/",
- "/analysis/languages/abap/",
- "/analysis/languages/apex/",
- "/analysis/languages/csharp/",
- "/analysis/languages/cfamily/",
- "/analysis/languages/cobol/",
- "/analysis/languages/flex/",
- "/analysis/languages/go/",
- "/analysis/languages/html/",
- "/analysis/languages/iac/",
- "/analysis/languages/java/",
- "/analysis/languages/javascript/",
- "/analysis/languages/kotlin/",
- "/analysis/languages/php/",
- "/analysis/languages/pli/",
- "/analysis/languages/plsql/",
- "/analysis/languages/python/",
- "/analysis/languages/rpg/",
- "/analysis/languages/ruby/",
- "/analysis/languages/scala/",
- "/analysis/languages/swift/",
- "/analysis/languages/tsql/",
- "/analysis/languages/vbnet/",
- "/analysis/languages/vb6/",
- "/analysis/languages/xml/"
- ]
- },
- {
- "title": "Test Coverage",
- "children": [
- "/analysis/coverage/",
- "/analysis/test-coverage/java-test-coverage/",
- "/analysis/test-coverage/javascript-typescript-test-coverage/",
- "/analysis/test-coverage/dotnet-test-coverage/",
- "/analysis/test-coverage/python-test-coverage/",
- "/analysis/test-coverage/php-test-coverage/",
- "/analysis/test-coverage/c-family-test-coverage/",
- "/analysis/generic-test/",
- "/analysis/test-coverage/test-coverage-parameters/",
- "/analysis/test-coverage/test-execution-parameters/"
- ]
- },
- {
- "title": "Importing External Issues",
- "children": [
- "/analysis/external-issues/",
- "/analysis/generic-issue/"
- ]
- },
- "/analysis/background-tasks/",
- "/analysis/pull-request/",
- {
- "title": "Branches",
- "children": [
- "/branches/overview/",
- "/branches/branches-faq/"
- ]
- },
- {
- "title": "CI Integration",
- "children": [
- "/analysis/ci-integration-overview/",
- "/analysis/jenkins/",
- "/analysis/codemagic/"
- ]
- },
- "/analysis/scm-integration/",
- "/analysis/security_configuration/",
- "/analysis/scanner-environment/"
- ]
- },
- {
- "title": "DevOps Platform Integration",
- "children": [
- "/analysis/github-integration/",
- "/analysis/gitlab-integration/",
- {
- "title": "Bitbucket Integration",
- "children": [
- "/analysis/bitbucket-integration/",
- "/analysis/bitbucket-cloud-integration/"
- ]
- },
- "/analysis/azuredevops-integration/"
- ]
- },
- {
- "title": "User Guide",
- "children": [
- "/user-guide/concepts/",
- "/user-guide/clean-as-you-code/",
- "/user-guide/connected-mode/",
- "/user-guide/metric-definitions/",
- "/user-guide/quality-gates/",
- {
- "title": "Rules",
- "children": [
- "/user-guide/rules/",
- "/user-guide/security-rules/",
- "/user-guide/built-in-rule-tags/"
- ]
- },
- {
- "title": "User Account",
- "children": [
- "/user-guide/user-account/",
- "/user-guide/user-token/"
- ]
- },
- "/user-guide/issues/",
- "/user-guide/security-hotspots/",
- "/user-guide/portfolios/",
- "/user-guide/applications/",
- "/user-guide/security-reports/",
- "/user-guide/activity-history/",
- "/user-guide/project-page/",
- "/user-guide/keyboard-shortcuts/"
- ]
- },
- {
- "title": "Project Administration",
- "children": [
- "/project-administration/project-existence/",
- "/project-administration/managing-project-history/",
- "/project-administration/narrowing-the-focus/",
- "/project-administration/new-code-period/",
- "/project-administration/managing-portfolios/",
- "/project-administration/managing-applications/",
- "/project-administration/portfolio-pdf-configuration/",
- "/project-administration/project-settings/",
- "/project-administration/webhooks/"
- ]
- },
- {
- "title": "Instance Administration",
- "children": [
- "/instance-administration/quality-profiles/",
- "/instance-administration/security/",
- {
- "title": "Authentication",
- "children": [
- "/instance-administration/authentication/overview/",
- "/instance-administration/authentication/http-header/",
- "/instance-administration/authentication/ldap/",
- {
- "title": "SAML",
- "children": [
- "/instance-administration/authentication/saml/overview/",
- "/instance-administration/authentication/saml/azuread/",
- "/instance-administration/authentication/saml/keycloak/",
- "/instance-administration/authentication/saml/okta/"
- ]
- },
- "/instance-administration/authentication/github/",
- "/instance-administration/authentication/gitlab/",
- "/instance-administration/authentication/bitbucket-cloud/"
- ]
- },
- "/instance-administration/look-and-feel/",
- "/instance-administration/marketplace/",
- "/instance-administration/housekeeping/",
- "/instance-administration/audit-logs/",
- "/instance-administration/system-info/",
- "/instance-administration/notifications/",
- "/instance-administration/license-manager/",
- "/instance-administration/monitoring/",
- "/instance-administration/project-move/",
- "/instance-administration/compute-engine-performance/",
- "/instance-administration/db-copy/",
- "/instance-administration/backup-restore/",
- "/instance-administration/telemetry/"
- ]
- },
- {
- "title": "Extension Guide",
- "children": [
- "/extend/web-api/",
- "/extend/adding-coding-rules/",
- {
- "title": "Developing a plugin",
- "children": [
- "/extend/developing-plugin/",
- "/extend/new-languages/",
- "/extend/executable-lines/",
- "/extend/extend-web-app/",
- "/extend/adding-scm/"
- ]
- },
- "/extend/i18n/",
- "/extend/contributing/"
- ]
- },
- "/faq/"
-]
diff --git a/server/sonar-web/package.json b/server/sonar-web/package.json
index d4b7e7592bd..30230f70b88 100644
--- a/server/sonar-web/package.json
+++ b/server/sonar-web/package.json
@@ -22,7 +22,6 @@
"formik": "2.2.9",
"lodash": "4.17.21",
"lunr": "2.3.9",
- "mdast-util-toc": "5.0.2",
"react": "16.13.0",
"react-day-picker": "7.4.10",
"react-dom": "16.13.0",
@@ -34,14 +33,6 @@
"react-select": "4.3.1",
"react-virtualized": "9.22.3",
"regenerator-runtime": "0.13.9",
- "rehype-raw": "4.0.2",
- "rehype-react": "5.0.0",
- "rehype-slug": "3.0.0",
- "remark": "11.0.2",
- "remark-custom-blocks": "2.5.1",
- "remark-react": "7.0.1",
- "remark-rehype": "6.0.0",
- "unist-util-visit": "2.0.2",
"valid-url": "1.0.9"
},
"devDependencies": {
diff --git a/server/sonar-web/src/main/js/@types/rehype-raw.d.ts b/server/sonar-web/src/main/js/@types/rehype-raw.d.ts
deleted file mode 100644
index 3fad41c4560..00000000000
--- a/server/sonar-web/src/main/js/@types/rehype-raw.d.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-declare module 'rehype-raw' {
- export default function rehypeRaw(): any;
-}
diff --git a/server/sonar-web/src/main/js/@types/rehype-react.d.ts b/server/sonar-web/src/main/js/@types/rehype-react.d.ts
deleted file mode 100644
index 50a919d9677..00000000000
--- a/server/sonar-web/src/main/js/@types/rehype-react.d.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-declare module 'rehype-react' {
- export default function rehypeReact(): any;
-}
diff --git a/server/sonar-web/src/main/js/@types/rehype-slug.d.ts b/server/sonar-web/src/main/js/@types/rehype-slug.d.ts
deleted file mode 100644
index 857e1bbcbd0..00000000000
--- a/server/sonar-web/src/main/js/@types/rehype-slug.d.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-declare module 'rehype-slug' {
- export default function rehypeSlug(): any;
-}
diff --git a/server/sonar-web/src/main/js/@types/remark-custom-blocks.d.ts b/server/sonar-web/src/main/js/@types/remark-custom-blocks.d.ts
deleted file mode 100644
index 759096d37b8..00000000000
--- a/server/sonar-web/src/main/js/@types/remark-custom-blocks.d.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-declare module 'remark-custom-blocks' {
- export default function customBlock(): any;
-}
diff --git a/server/sonar-web/src/main/js/@types/remark-react.d.ts b/server/sonar-web/src/main/js/@types/remark-react.d.ts
deleted file mode 100644
index 780409f9aae..00000000000
--- a/server/sonar-web/src/main/js/@types/remark-react.d.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-declare module 'remark-react' {
- interface Options {
- /** `h()` */
- createElement?: (...args: any[]) => JSX.Element;
- /** Key prefix. */
- prefix?: string;
- /** Components. */
- remarkReactComponents?: any;
- /** Sanitation schema. */
- sanitize?: any;
- }
-
- export default function remarkReact(options?: Options): JSX.Element;
-}
diff --git a/server/sonar-web/src/main/js/@types/remark-rehype.d.ts b/server/sonar-web/src/main/js/@types/remark-rehype.d.ts
deleted file mode 100644
index 85a2bb14e97..00000000000
--- a/server/sonar-web/src/main/js/@types/remark-rehype.d.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-declare module 'remark-rehype' {
- export default function remarkRehype(): any;
-}
diff --git a/server/sonar-web/src/main/js/@types/remark.d.ts b/server/sonar-web/src/main/js/@types/remark.d.ts
deleted file mode 100644
index f7beee505c3..00000000000
--- a/server/sonar-web/src/main/js/@types/remark.d.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-declare module 'remark' {
- export default function remark(): any;
-}
diff --git a/server/sonar-web/src/main/js/@types/unist-util-visit.d.ts b/server/sonar-web/src/main/js/@types/unist-util-visit.d.ts
deleted file mode 100644
index 9002a105615..00000000000
--- a/server/sonar-web/src/main/js/@types/unist-util-visit.d.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-declare module 'unist-util-visit' {
- export default function visit(
- ast: any,
- visitor: (node: { type: string; value: string }) => void
- ): void;
-}
diff --git a/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts
index 9f02909bc9f..4ac206dbf5d 100644
--- a/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts
+++ b/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts
@@ -19,34 +19,46 @@
*/
import { cloneDeep } from 'lodash';
import { HousekeepingPolicy } from '../../apps/audit-logs/utils';
+import { BranchParameters } from '../../types/branch-like';
import { SettingsKey, SettingValue } from '../../types/settings';
import { getValue } from '../settings';
export default class SettingsServiceMock {
- settingValue?: SettingValue;
- defaultValues: SettingValue = {
- key: SettingsKey.AuditHouseKeeping,
- value: HousekeepingPolicy.Weekly
- };
+ settingValues: SettingValue[];
+ defaultValues: SettingValue[] = [
+ {
+ key: SettingsKey.AuditHouseKeeping,
+ value: HousekeepingPolicy.Weekly
+ }
+ ];
constructor() {
- this.settingValue = cloneDeep(this.defaultValues);
- (getValue as jest.Mock).mockImplementation(this.getValuesHandler);
+ this.settingValues = cloneDeep(this.defaultValues);
+ (getValue as jest.Mock).mockImplementation(this.handleGetValues);
}
- getValuesHandler = () => {
- return Promise.resolve(this.settingValue);
+ handleGetValues = (data: { key: string; component?: string } & BranchParameters) => {
+ const setting = this.settingValues.find(s => s.key === data.key);
+
+ return this.reply(setting);
};
- unsetHousekeepingPolicy() {
- this.settingValue = undefined;
+ emptySettings() {
+ this.settingValues = [];
}
setYearlyHousekeepingPolicy() {
- this.settingValue = { key: 'test', value: HousekeepingPolicy.Yearly };
+ const auditSetting = this.settingValues.find(s => s.key === SettingsKey.AuditHouseKeeping);
+ if (auditSetting) {
+ auditSetting.value = HousekeepingPolicy.Yearly;
+ }
}
resetSettingvalues = () => {
- this.settingValue = cloneDeep(this.defaultValues);
+ this.settingValues = cloneDeep(this.defaultValues);
};
+
+ reply<T>(response: T): Promise<T> {
+ return Promise.resolve(cloneDeep(response));
+ }
}
diff --git a/server/sonar-web/src/main/js/app/components/DocumentationRedirect.tsx b/server/sonar-web/src/main/js/app/components/DocumentationRedirect.tsx
new file mode 100644
index 00000000000..3f4206d868a
--- /dev/null
+++ b/server/sonar-web/src/main/js/app/components/DocumentationRedirect.tsx
@@ -0,0 +1,51 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { Helmet } from 'react-helmet-async';
+import { useLocation } from 'react-router-dom';
+import Link from '../../components/common/Link';
+import { getUrlForDoc } from '../../helpers/docs';
+import withAppStateContext, { WithAppStateContextProps } from './app-state/withAppStateContext';
+
+const PAUSE_REDIRECT = 1;
+
+function DocumentationRedirect({ appState }: WithAppStateContextProps) {
+ const location = useLocation();
+ const url = getUrlForDoc(appState.version, location.pathname.replace(/^\/documentation/, ''));
+
+ return (
+ <>
+ <Helmet>
+ <meta httpEquiv="refresh" content={`${PAUSE_REDIRECT}; url='${url}'`} />
+ </Helmet>
+ <div className="global-loading">
+ <div className="display-flex-center">
+ <i className="spinner global-loading-spinner" />
+ <span className="spacer-left global-loading-text">Redirecting...</span>
+ </div>
+ <div className="display-flex-justify-content spacer-top large">
+ <Link to={url}>Click here if you&apos;re not being redirected automatically</Link>
+ </div>
+ </div>
+ </>
+ );
+}
+
+export default withAppStateContext(DocumentationRedirect);
diff --git a/server/sonar-web/src/main/js/app/components/GlobalFooter.tsx b/server/sonar-web/src/main/js/app/components/GlobalFooter.tsx
index 7631e5345a6..3ed1bec60b8 100644
--- a/server/sonar-web/src/main/js/app/components/GlobalFooter.tsx
+++ b/server/sonar-web/src/main/js/app/components/GlobalFooter.tsx
@@ -18,6 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import DocLink from '../../components/common/DocLink';
import InstanceMessage from '../../components/common/InstanceMessage';
import Link from '../../components/common/Link';
import { Alert } from '../../components/ui/Alert';
@@ -74,7 +75,7 @@ export function GlobalFooter({ hideLoggedInInfo, appState }: GlobalFooterProps)
</a>
</li>
<li className="page-footer-menu-item">
- <Link to="/documentation">{translate('footer.documentation')}</Link>
+ <DocLink to="/">{translate('footer.documentation')}</DocLink>
</li>
<li className="page-footer-menu-item">
<a
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/DocumentationRedirect-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/DocumentationRedirect-test.tsx
new file mode 100644
index 00000000000..9053428f7d2
--- /dev/null
+++ b/server/sonar-web/src/main/js/app/components/__tests__/DocumentationRedirect-test.tsx
@@ -0,0 +1,51 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { screen } from '@testing-library/react';
+import * as React from 'react';
+import { Route } from 'react-router-dom';
+import { mockAppState } from '../../../helpers/testMocks';
+import { renderAppRoutes } from '../../../helpers/testReactTestingUtils';
+import DocumentationRedirect from '../DocumentationRedirect';
+
+it('should redirect to static doc for specific version', async () => {
+ renderDocumentationRedirect('land', '9.7.1234');
+
+ expect(await screen.findByRole('link')).toHaveAttribute(
+ 'href',
+ 'https://docs.sonarqube.org/9.7/land'
+ );
+});
+
+it('should redirect to static doc for latest version', async () => {
+ renderDocumentationRedirect('land', '9.7-SNAPSHOT');
+
+ expect(await screen.findByRole('link')).toHaveAttribute(
+ 'href',
+ 'https://docs.sonarqube.org/latest/land'
+ );
+});
+
+function renderDocumentationRedirect(navigatge: string, version?: string) {
+ renderAppRoutes(
+ `documentation/${navigatge}`,
+ () => <Route path="/documentation/*" element={<DocumentationRedirect />} />,
+ { appState: mockAppState({ version }) }
+ );
+}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx
index 4d47866e21e..79daabad3ac 100644
--- a/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx
+++ b/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx
@@ -90,14 +90,6 @@ it('should render only the children', async () => {
getWrapper({
appState: mockAppState({ canAdmin: false }),
currentUser: { ...LOGGED_IN_USER },
- location: mockLocation({ pathname: '/documentation/' })
- })
- );
-
- await shouldNotHaveModals(
- getWrapper({
- appState: mockAppState({ canAdmin: false }),
- currentUser: { ...LOGGED_IN_USER },
location: mockLocation({ pathname: '/create-organization' })
})
);
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalFooter-test.tsx.snap b/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalFooter-test.tsx.snap
index 93db6c4ba6f..d9f37661358 100644
--- a/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalFooter-test.tsx.snap
+++ b/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalFooter-test.tsx.snap
@@ -44,11 +44,11 @@ exports[`should display the sq version 1`] = `
<li
className="page-footer-menu-item"
>
- <ForwardRef(Link)
- to="/documentation"
+ <withAppStateContext(DocLink)
+ to="/"
>
footer.documentation
- </ForwardRef(Link)>
+ </withAppStateContext(DocLink)>
</li>
<li
className="page-footer-menu-item"
@@ -108,11 +108,11 @@ exports[`should not render the only logged in information 1`] = `
<li
className="page-footer-menu-item"
>
- <ForwardRef(Link)
- to="/documentation"
+ <withAppStateContext(DocLink)
+ to="/"
>
footer.documentation
- </ForwardRef(Link)>
+ </withAppStateContext(DocLink)>
</li>
<li
className="page-footer-menu-item"
@@ -173,11 +173,11 @@ exports[`should render the only logged in information 1`] = `
<li
className="page-footer-menu-item"
>
- <ForwardRef(Link)
- to="/documentation"
+ <withAppStateContext(DocLink)
+ to="/"
>
footer.documentation
- </ForwardRef(Link)>
+ </withAppStateContext(DocLink)>
</li>
<li
className="page-footer-menu-item"
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLike.tsx b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLike.tsx
index 7c51dd97fa7..3cbee80e9e5 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLike.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLike.tsx
@@ -96,7 +96,8 @@ export function CurrentBranchLike(props: CurrentBranchLikeProps) {
links={[
{
href: 'https://redirect.sonarsource.com/editions/developer.html',
- label: translate('learn_more')
+ label: translate('learn_more'),
+ doc: false
}
]}
title={
@@ -119,17 +120,18 @@ export function CurrentBranchLike(props: CurrentBranchLikeProps) {
data-test="only-one-branch-like"
links={[
{
- href: '/documentation/branches/overview/',
+ href: '/branches/overview/',
label: translate('branch_like_navigation.only_one_branch.documentation')
},
{
- href: '/documentation/analysis/pull-request/',
+ href: '/analysis/pull-request/',
label: translate('branch_like_navigation.only_one_branch.pr_analysis')
},
{
href: `/tutorials?id=${component.key}`,
label: translate('branch_like_navigation.tutorial_for_ci'),
- inPlace: true
+ inPlace: true,
+ doc: false
}
]}
title={translate('branch_like_navigation.only_one_branch.title')}>
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/__tests__/__snapshots__/CurrentBranchLike-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/__tests__/__snapshots__/CurrentBranchLike-test.tsx.snap
index eb009ecfeee..513f07e8cfb 100644
--- a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/__tests__/__snapshots__/CurrentBranchLike-test.tsx.snap
+++ b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/__tests__/__snapshots__/CurrentBranchLike-test.tsx.snap
@@ -127,6 +127,7 @@ exports[`projects should render correctly when branches support is disabled: alm
links={
Array [
Object {
+ "doc": false,
"href": "https://redirect.sonarsource.com/editions/developer.html",
"label": "learn_more",
},
@@ -169,6 +170,7 @@ exports[`projects should render correctly when branches support is disabled: alm
links={
Array [
Object {
+ "doc": false,
"href": "https://redirect.sonarsource.com/editions/developer.html",
"label": "learn_more",
},
@@ -211,6 +213,7 @@ exports[`projects should render correctly when branches support is disabled: def
links={
Array [
Object {
+ "doc": false,
"href": "https://redirect.sonarsource.com/editions/developer.html",
"label": "learn_more",
},
@@ -278,14 +281,15 @@ exports[`projects should render correctly when there is only one branchlike 1`]
links={
Array [
Object {
- "href": "/documentation/branches/overview/",
+ "href": "/branches/overview/",
"label": "branch_like_navigation.only_one_branch.documentation",
},
Object {
- "href": "/documentation/analysis/pull-request/",
+ "href": "/analysis/pull-request/",
"label": "branch_like_navigation.only_one_branch.pr_analysis",
},
Object {
+ "doc": false,
"href": "/tutorials?id=my-project",
"inPlace": true,
"label": "branch_like_navigation.tutorial_for_ci",
diff --git a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx
index 93cc1be5009..44f1ac28530 100644
--- a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx
+++ b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx
@@ -29,7 +29,6 @@ import ChangeAdminPasswordApp from '../../apps/change-admin-password/ChangeAdmin
import codeRoutes from '../../apps/code/routes';
import codingRulesRoutes from '../../apps/coding-rules/routes';
import componentMeasuresRoutes from '../../apps/component-measures/routes';
-import documentationRoutes from '../../apps/documentation/routes';
import groupsRoutes from '../../apps/groups/routes';
import { globalIssuesRoutes, projectIssuesRoutes } from '../../apps/issues/routes';
import maintenanceRoutes from '../../apps/maintenance/routes';
@@ -73,6 +72,7 @@ import {
} from '../components/available-features/AvailableFeaturesContext';
import ComponentContainer from '../components/ComponentContainer';
import CurrentUserContextProvider from '../components/current-user/CurrentUserContextProvider';
+import DocumentationRedirect from '../components/DocumentationRedirect';
import GlobalAdminPageExtension from '../components/extensions/GlobalAdminPageExtension';
import GlobalPageExtension from '../components/extensions/GlobalPageExtension';
import PortfolioPage from '../components/extensions/PortfolioPage';
@@ -142,10 +142,6 @@ function renderRedirects() {
{renderRedirect({ from: '/admin', to: '/admin/settings' })}
{renderRedirect({ from: '/background_tasks', to: '/admin/background_tasks' })}
- {renderRedirect({
- from: '/documentation/analysis/languages/vb',
- to: '/documentation/analysis/languages/vbnet/'
- })}
{renderRedirect({ from: '/groups', to: '/admin/groups' })}
{renderRedirect({ from: '/extension/governance/portfolios', to: '/portfolios' })}
{renderRedirect({ from: '/permission_templates', to: '/admin/permission_templates' })}
@@ -163,6 +159,7 @@ function renderRedirects() {
{renderRedirect({ from: '/users', to: '/admin/users' })}
{renderRedirect({ from: '/onboarding', to: '/projects/create' })}
{renderRedirect({ from: '/markdown/help', to: '/formatting/help' })}
+ <Route path="/documentation/*" element={<DocumentationRedirect />} />
</>
);
}
@@ -265,8 +262,6 @@ export default function startReactApp(
{codingRulesRoutes()}
- {documentationRoutes()}
-
<Route
path="extension/:pluginKey/:extensionKey"
element={<GlobalPageExtension />}
diff --git a/server/sonar-web/src/main/js/apps/audit-logs/components/__tests__/AuditApp-it.tsx b/server/sonar-web/src/main/js/apps/audit-logs/components/__tests__/AuditApp-it.tsx
index 80128101cbe..813ede23e2d 100644
--- a/server/sonar-web/src/main/js/apps/audit-logs/components/__tests__/AuditApp-it.tsx
+++ b/server/sonar-web/src/main/js/apps/audit-logs/components/__tests__/AuditApp-it.tsx
@@ -141,7 +141,7 @@ it('should not render if governance is not enable', () => {
});
it('should show right option when keeping log for month', async () => {
- handler.unsetHousekeepingPolicy();
+ handler.emptySettings();
renderAuditLogs();
expect(await ui.pageTitle.find()).toBeInTheDocument();
expect(ui.todayRadio.get()).toBeInTheDocument();
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/Header.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/Header.tsx
index dd4cbe6f060..020395e1918 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/Header.tsx
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/Header.tsx
@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import Link from '../../../components/common/Link';
+import DocLink from '../../../components/common/DocLink';
import { translate } from '../../../helpers/l10n';
import Workers from './Workers';
@@ -37,12 +37,9 @@ export default function Header(props: Props) {
)}
<p className="page-description">
{translate('background_tasks.page.description')}
- <Link
- className="spacer-left"
- target="_blank"
- to={{ pathname: '/documentation/analysis/background-tasks/' }}>
+ <DocLink className="spacer-left" to="/analysis/background-tasks/">
{translate('learn_more')}
- </Link>
+ </DocLink>
</p>
</header>
);
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/ProfileFacet.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/ProfileFacet.tsx
index 76a12c9d80f..a78cbf07a81 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/ProfileFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/ProfileFacet.tsx
@@ -175,7 +175,7 @@ export default class ProfileFacet extends React.PureComponent<Props> {
content={translate('coding_rules.facet.qprofile.help')}
links={[
{
- href: '/documentation/instance-administration/quality-profiles/',
+ href: '/instance-administration/quality-profiles/',
label: translate('coding_rules.facet.qprofile.link')
}
]}
diff --git a/server/sonar-web/src/main/js/apps/documentation/__tests__/pages-test.ts b/server/sonar-web/src/main/js/apps/documentation/__tests__/pages-test.ts
deleted file mode 100644
index 263144f12bc..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/__tests__/pages-test.ts
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-/* eslint-disable no-console */
-import { filterContent, ParsedContent } from '../../../helpers/markdown';
-import { mockDocumentationMarkdown } from '../../../helpers/testMocks';
-import { Dict } from '../../../types/types';
-
-jest.mock('remark', () => () => ({
- parse: jest.fn().mockReturnValue({})
-}));
-
-jest.mock(
- 'unist-util-visit',
- () => (_: any, cb: (node: { type: string; value: string }) => void) => {
- cb({ type: 'text', value: 'Text content' });
- }
-);
-
-jest.mock('../../../helpers/markdown', () => {
- const markdown = jest.requireActual('../../../helpers/markdown');
- return { ...markdown, filterContent: jest.fn().mockImplementation(markdown.filterContent) };
-});
-
-const lorem = {
- url: 'analysis/languages/lorem',
- title: 'toto doc',
- key: 'toto',
- content: 'TOTO CONTENT'
-};
-const foo = {
- url: `analysis/languages/foo`,
- title: 'foo doc',
- key: 'foo'
-};
-const loremDoc = mockDocumentationMarkdown(lorem);
-const fooDoc = mockDocumentationMarkdown(foo);
-
-jest.mock('../documentation.directory-loader', () => [
- { content: loremDoc, path: lorem.url },
- { content: fooDoc, path: foo.url }
-]);
-
-it('should correctly parse files', () => {
- const pages = getPages();
- expect(pages.length).toBe(2);
-
- expect(pages[0]).toMatchObject({
- relativeName: lorem.url,
- url: `/${lorem.url}/`,
- title: lorem.title,
- navTitle: undefined,
- order: -1,
- scope: undefined,
- content: lorem.content
- });
-
- expect(pages[1]).toMatchObject({
- relativeName: foo.url,
- url: `/${foo.url}/`,
- title: foo.title,
- navTitle: undefined,
- order: -1,
- scope: undefined
- });
-});
-
-it('should correctly handle overrides (replace & add)', () => {
- const overrideFooDoc = {
- content: 'OVERRIDE_FOO',
- title: 'OVERRIDE_TITLE_FOO',
- key: foo.key
- };
- const newDoc = {
- content: 'TATA',
- title: 'TATA_TITLE',
- key: 'tata'
- };
-
- const overrides: Dict<ParsedContent> = {};
- overrides[foo.url] = { frontmatter: overrideFooDoc, content: overrideFooDoc.content };
- overrides[`analysis/languages/${newDoc.key}`] = { frontmatter: newDoc, content: newDoc.content };
- const pages = getPages(overrides);
-
- expect(pages.length).toBe(3);
- expect(pages[1].content).toBe(overrideFooDoc.content);
- expect(pages[1].title).toBe(overrideFooDoc.title);
- expect(pages[2].content).toBe(newDoc.content);
- expect(pages[2].title).toBe(newDoc.title);
-});
-
-it('should not break the whole doc when one page cannot be parsed', () => {
- const originalConsoleError = console.error;
- console.error = jest.fn();
-
- (filterContent as jest.Mock).mockImplementationOnce(() => {
- throw Error('Parse page error');
- });
- const pages = getPages();
- expect(pages.length).toBe(2);
- expect(pages[0].content).toBe('');
- expect(console.error).toHaveBeenCalledTimes(1);
-
- console.error = originalConsoleError;
-});
-
-function getPages(overrides: Dict<ParsedContent> = {}) {
- // This allows the use of out-of-scope data inside jest.mock
- // Usually, it is impossible as jest.mock'ed module is hoisted on the top of the file
- return jest.requireActual('../pages').default(overrides);
-}
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/App.tsx b/server/sonar-web/src/main/js/apps/documentation/components/App.tsx
deleted file mode 100644
index 7834ae8612a..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/App.tsx
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as navigationTreeSonarQube from 'Docs/../static/SonarQubeNavigationTree.json';
-import { DocNavigationItem } from 'Docs/@types/types';
-import * as React from 'react';
-import { Helmet } from 'react-helmet-async';
-import { useLocation, useParams } from 'react-router-dom';
-import { getInstalledPlugins } from '../../../api/plugins';
-import { getPluginStaticFileContent } from '../../../api/static';
-import NotFound from '../../../app/components/NotFound';
-import A11ySkipTarget from '../../../components/a11y/A11ySkipTarget';
-import Link from '../../../components/common/Link';
-import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper';
-import DocMarkdownBlock from '../../../components/docs/DocMarkdownBlock';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
-import { translate } from '../../../helpers/l10n';
-import { ParsedContent, separateFrontMatter } from '../../../helpers/markdown';
-import { addSideBarClass, removeSideBarClass } from '../../../helpers/pages';
-import { isDefined } from '../../../helpers/types';
-import { InstalledPlugin, PluginType } from '../../../types/plugins';
-import { Dict } from '../../../types/types';
-import { getUrlsList } from '../navTreeUtils';
-import getPages from '../pages';
-import '../styles.css';
-import { DocumentationEntry } from '../utils';
-import Sidebar from './Sidebar';
-
-interface Props {
- params: { splat?: string };
- location: { hash: string };
-}
-
-interface State {
- loading: boolean;
- pages: DocumentationEntry[];
- tree: DocNavigationItem[];
-}
-
-const LANGUAGES_BASE_URL = 'analysis/languages';
-
-export class App extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = {
- loading: false,
- pages: [],
- tree: []
- };
-
- componentDidMount() {
- this.mounted = true;
- addSideBarClass();
-
- this.setState({ loading: true });
-
- const tree = (navigationTreeSonarQube as any).default as DocNavigationItem[];
-
- this.getLanguagePluginsDocumentation(tree).then(
- overrides => {
- if (this.mounted) {
- this.setState({
- loading: false,
- pages: getPages(overrides),
- tree
- });
- }
- },
- () => {
- if (this.mounted) {
- this.setState({
- loading: false
- });
- }
- }
- );
- }
-
- componentWillUnmount() {
- this.mounted = false;
- removeSideBarClass();
- }
-
- getLanguagePluginsDocumentation = async (tree: DocNavigationItem[]) => {
- const plugins = await getInstalledPlugins(PluginType.Bundled).catch(
- () => [] as InstalledPlugin[]
- );
-
- const pluginsWithDoc = await Promise.all(
- plugins.map(plugin => {
- if (plugin.documentationPath) {
- const matchArray = /^static\/(.*)/.exec(plugin.documentationPath);
-
- if (matchArray && matchArray.length > 1) {
- return getPluginStaticFileContent(plugin.key, matchArray[1]).then(
- content => ({ ...plugin, content }),
- () => undefined
- );
- }
- }
-
- return undefined;
- })
- );
-
- const regex = new RegExp(`/${LANGUAGES_BASE_URL}/\\w+/$`);
- const overridablePaths = getUrlsList(tree).filter(
- path => regex.test(path) && path !== `/${LANGUAGES_BASE_URL}/overview/`
- );
-
- const parsedContent: Dict<ParsedContent> = {};
-
- pluginsWithDoc.filter(isDefined).forEach(plugin => {
- const parsed = separateFrontMatter(plugin.content);
-
- if (plugin.issueTrackerUrl) {
- // Inject issue tracker link
- let issueTrackerLink = '## Issue Tracker';
- issueTrackerLink += '\r\n';
- issueTrackerLink += `Check the [issue tracker](${plugin.issueTrackerUrl}) for this language.`;
- parsed.content = `${parsed.content}\r\n${issueTrackerLink}`;
- }
-
- if (
- parsed?.frontmatter?.key &&
- overridablePaths.includes(`/${LANGUAGES_BASE_URL}/${parsed.frontmatter.key}/`)
- ) {
- parsedContent[`${LANGUAGES_BASE_URL}/${parsed.frontmatter.key}`] = parsed;
- }
- });
-
- return parsedContent;
- };
-
- render() {
- const { loading, pages, tree } = this.state;
- const {
- params: { splat = '' },
- location: { hash }
- } = this.props;
-
- if (loading) {
- return (
- <div className="page page-limited">
- <DeferredSpinner />
- </div>
- );
- }
-
- const page = pages.find(p => p.url === `/${splat}`);
- const mainTitle = translate('documentation.page_title.sonarqube');
- const isIndex = splat === 'index';
-
- if (!page) {
- return (
- <>
- <Helmet title={mainTitle}>
- <meta content="noindex nofollow" name="robots" />
- </Helmet>
- <A11ySkipTarget anchor="documentation_main" />
- <NotFound withContainer={false} />
- </>
- );
- }
-
- return (
- <div className="layout-page">
- <Helmet
- defer={false}
- title={isIndex || !page.title ? mainTitle : `${page.title} | ${mainTitle}`}>
- <meta content="noindex nofollow" name="robots" />
- </Helmet>
-
- <ScreenPositionHelper className="layout-page-side-outer">
- {({ top }) => (
- <div className="layout-page-side" style={{ top }}>
- <div className="layout-page-side-inner">
- <div className="layout-page-filters">
- <div className="documentation-page-header">
- <A11ySkipTarget
- anchor="documentation_menu"
- label={translate('documentation.skip_to_nav')}
- weight={10}
- />
-
- <Link to="/documentation/">
- <h1>{translate('documentation.page')}</h1>
- </Link>
- </div>
- <Sidebar navigation={tree} pages={pages} splat={splat} />
- </div>
- </div>
- </div>
- )}
- </ScreenPositionHelper>
-
- <div className="layout-page-main">
- <div className="layout-page-main-inner">
- <div className="boxed-group">
- <A11ySkipTarget anchor="documentation_main" />
-
- <DocMarkdownBlock
- className="documentation-content cut-margins boxed-group-inner"
- content={page.content}
- stickyToc={true}
- title={page.title}
- scrollToHref={hash}
- />
- </div>
- </div>
- </div>
- </div>
- );
- }
-}
-
-export default function AppWrapper() {
- const params = useParams();
- const location = useLocation();
-
- return <App params={{ splat: params['*'] }} location={location} />;
-}
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/Menu.tsx b/server/sonar-web/src/main/js/apps/documentation/components/Menu.tsx
deleted file mode 100644
index 87b432afa9c..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/Menu.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { DocNavigationItem } from 'Docs/@types/types';
-import * as React from 'react';
-import {
- getOpenChainFromPath,
- isDocsNavigationBlock,
- isDocsNavigationExternalLink
-} from '../navTreeUtils';
-import { DocumentationEntry, getNodeFromUrl } from '../utils';
-import MenuBlock from './MenuBlock';
-import { MenuExternalLink } from './MenuExternalLink';
-import { MenuItem } from './MenuItem';
-
-interface Props {
- navigation: DocNavigationItem[];
- pages: DocumentationEntry[];
- splat: string;
-}
-
-interface State {
- openChain: DocNavigationItem[];
-}
-
-export default class Menu extends React.PureComponent<Props, State> {
- constructor(props: Props) {
- super(props);
- this.state = {
- openChain: getOpenChainFromPath(this.props.splat, this.props.navigation)
- };
- }
-
- componentWillReceiveProps(nextProps: Props) {
- if (this.props.splat !== nextProps.splat) {
- this.setState({ openChain: getOpenChainFromPath(nextProps.splat, nextProps.navigation) });
- }
- }
-
- render() {
- const { openChain } = this.state;
- return (
- <>
- {this.props.navigation.map(item => {
- if (isDocsNavigationBlock(item)) {
- return (
- <MenuBlock
- block={item}
- key={item.title}
- openByDefault={openChain.includes(item)}
- openChain={openChain}
- pages={this.props.pages}
- splat={this.props.splat}
- title={item.title}
- />
- );
- }
- if (isDocsNavigationExternalLink(item)) {
- return <MenuExternalLink key={item.title} title={item.title} url={item.url} />;
- }
- return (
- <MenuItem
- key={item}
- node={getNodeFromUrl(this.props.pages, item)}
- splat={this.props.splat}
- />
- );
- })}
- </>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/MenuBlock.tsx b/server/sonar-web/src/main/js/apps/documentation/components/MenuBlock.tsx
deleted file mode 100644
index d1687c28859..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/MenuBlock.tsx
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import classNames from 'classnames';
-import { DocNavigationItem, DocsNavigationBlock } from 'Docs/@types/types';
-import * as React from 'react';
-import { ButtonLink } from '../../../components/controls/buttons';
-import OpenCloseIcon from '../../../components/icons/OpenCloseIcon';
-import { isDocsNavigationBlock } from '../navTreeUtils';
-import { DocumentationEntry, getNodeFromUrl } from '../utils';
-import { MenuItem } from './MenuItem';
-
-interface Props {
- block: DocsNavigationBlock;
- depth?: number;
- openByDefault: boolean;
- openChain: DocNavigationItem[];
- pages: DocumentationEntry[];
- splat: string;
- title: string;
-}
-
-interface State {
- open: boolean;
-}
-
-export default class MenuBlock extends React.PureComponent<Props, State> {
- state: State;
-
- constructor(props: Props) {
- super(props);
- this.state = {
- open: props.openByDefault !== undefined ? props.openByDefault : false
- };
- }
-
- handleClick = () => {
- this.setState(prevState => ({
- open: !prevState.open
- }));
- };
-
- renderMenuItems = (block: DocsNavigationBlock): React.ReactNode => {
- const { depth = 0, openChain, pages, splat } = this.props;
- return block.children.map(item => {
- if (typeof item === 'string') {
- return (
- <MenuItem depth={depth + 1} key={item} node={getNodeFromUrl(pages, item)} splat={splat} />
- );
- } else if (isDocsNavigationBlock(item)) {
- return (
- <MenuBlock
- block={item}
- depth={depth + 1}
- key={item.title}
- openByDefault={openChain.includes(item)}
- openChain={openChain}
- pages={pages}
- splat={splat}
- title={item.title}
- />
- );
- } else {
- return null;
- }
- });
- };
-
- render() {
- const { block, depth = 0, title } = this.props;
- const { open } = this.state;
- const maxDepth = Math.min(depth, 3);
- return (
- <>
- <ButtonLink
- className={classNames('list-group-item', { [`depth-${maxDepth}`]: depth > 0 })}
- onClick={this.handleClick}>
- <h3 className="list-group-item-heading">
- <OpenCloseIcon className="little-spacer-right" open={open} />
- {title}
- </h3>
- </ButtonLink>
- {open && this.renderMenuItems(block)}
- </>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/MenuExternalLink.tsx b/server/sonar-web/src/main/js/apps/documentation/components/MenuExternalLink.tsx
deleted file mode 100644
index 3d2bef9ac06..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/MenuExternalLink.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import DetachIcon from '../../../components/icons/DetachIcon';
-
-interface Props {
- title: string;
- url: string;
-}
-
-export function MenuExternalLink({ title, url }: Props) {
- return (
- <a href={url} key={title} target="_blank" rel="noopener noreferrer">
- <h3 className="list-group-item-heading">
- <DetachIcon className="spacer-right" />
- {title}
- </h3>
- </a>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/MenuItem.tsx b/server/sonar-web/src/main/js/apps/documentation/components/MenuItem.tsx
deleted file mode 100644
index e3fcf7f5498..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/MenuItem.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import classNames from 'classnames';
-import * as React from 'react';
-import Link from '../../../components/common/Link';
-import { testPathAgainstUrl } from '../navTreeUtils';
-import { DocumentationEntry } from '../utils';
-
-interface Props {
- depth?: number;
- node: DocumentationEntry | undefined;
- splat: string;
-}
-
-export function MenuItem({ depth = 0, node, splat }: Props) {
- if (!node) {
- return null;
- }
-
- const active = testPathAgainstUrl(node.url, splat);
- const maxDepth = Math.min(depth, 3);
- const title = node.navTitle || node.title;
-
- return (
- <Link
- className={classNames('list-group-item', { active, [`depth-${maxDepth}`]: depth > 0 })}
- key={node.url}
- to={'/documentation' + node.url}>
- <h3 className="list-group-item-heading" title={title}>
- {title}
- </h3>
- </Link>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/SearchResultEntry.tsx b/server/sonar-web/src/main/js/apps/documentation/components/SearchResultEntry.tsx
deleted file mode 100644
index f563d5300aa..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/SearchResultEntry.tsx
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import classNames from 'classnames';
-import * as React from 'react';
-import Link from '../../../components/common/Link';
-import { Dict } from '../../../types/types';
-import { cutWords, DocumentationEntry, highlightMarks } from '../utils';
-
-export interface SearchResult {
- exactMatch?: boolean;
- highlights: Dict<[number, number][]>;
- longestTerm: string;
- page: DocumentationEntry;
- query: string;
-}
-
-interface Props {
- active: boolean;
- result: SearchResult;
-}
-
-export default function SearchResultEntry({ active, result }: Props) {
- return (
- <Link
- className={classNames('list-group-item', { active })}
- to={'/documentation' + result.page.url}>
- <SearchResultTitle result={result} />
- <SearchResultText result={result} />
- </Link>
- );
-}
-
-export function SearchResultTitle({ result }: { result: SearchResult }) {
- let titleWithMarks: React.ReactNode;
-
- const titleHighlights = result.highlights.title;
- if (titleHighlights && titleHighlights.length > 0) {
- const { title } = result.page;
- const tokens = highlightMarks(
- title,
- titleHighlights.map(h => ({ from: h[0], to: h[0] + h[1] }))
- );
- titleWithMarks = <SearchResultTokens tokens={tokens} />;
- } else {
- titleWithMarks = result.page.title;
- }
-
- return (
- <h3 className="list-group-item-heading" style={{ fontWeight: 'normal' }}>
- {titleWithMarks}
- </h3>
- );
-}
-
-export function SearchResultText({ result }: { result: SearchResult }) {
- const textHighlights = result.highlights.text;
- const { text } = result.page;
- let tokens: {
- text: string;
- marked: boolean;
- }[] = [];
-
- if (result.exactMatch) {
- const pageText = result.page.text.toLowerCase();
- const highlights: { from: number; to: number }[] = [];
- let start = 0;
- let index = pageText.indexOf(result.query, start);
- let loopCount = 0;
-
- while (index > -1 && loopCount < 10) {
- loopCount++;
- highlights.push({ from: index, to: index + result.query.length });
- start = index + 1;
- index = pageText.indexOf(result.query, start);
- }
-
- if (highlights.length) {
- tokens = highlightMarks(text, highlights);
- }
- }
-
- if (tokens.length === 0 && textHighlights && textHighlights.length > 0) {
- tokens = highlightMarks(
- text,
- textHighlights.map(h => ({ from: h[0], to: h[0] + h[1] }))
- );
- }
-
- if (tokens.length) {
- return (
- <div className="note">
- <SearchResultTokens tokens={cutWords(tokens)} />
- </div>
- );
- } else {
- return null;
- }
-}
-
-export function SearchResultTokens({
- tokens
-}: {
- tokens: Array<{ text: string; marked: boolean }>;
-}) {
- return (
- <>
- {tokens.map((token, index) => (
- <React.Fragment key={index}>
- {token.marked ? <mark key={index}>{token.text}</mark> : token.text}
- </React.Fragment>
- ))}
- </>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/SearchResults.tsx b/server/sonar-web/src/main/js/apps/documentation/components/SearchResults.tsx
deleted file mode 100644
index 784909c3e40..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/SearchResults.tsx
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { Dict, DocNavigationItem } from 'Docs/@types/types';
-import { sortBy } from 'lodash';
-import lunr, { LunrBuilder, LunrIndex, LunrToken } from 'lunr';
-import * as React from 'react';
-import { isDefined } from '../../../helpers/types';
-import { getUrlsList } from '../navTreeUtils';
-import { DocumentationEntry } from '../utils';
-import SearchResultEntry from './SearchResultEntry';
-
-interface Props {
- navigation: DocNavigationItem[];
- pages: DocumentationEntry[];
- query?: string;
- splat: string;
-}
-
-export default class SearchResults extends React.PureComponent<Props> {
- index: LunrIndex;
-
- constructor(props: Props) {
- super(props);
- this.index = lunr(function() {
- this.use(tokenContextPlugin);
- this.ref('relativeName');
- this.field('title', { boost: 10 });
- this.field('text');
-
- this.metadataWhitelist = ['position', 'tokenContext'];
-
- const urlsList = getUrlsList(props.navigation);
- props.pages.filter(page => urlsList.includes(page.url)).forEach(page => this.add(page));
- });
- }
-
- search(query: string) {
- return this.index
- .search(
- query
- .replace(/[\^\-+:~*]/g, '')
- .split(/\s+/)
- .map(s => `${s}~1 ${s}*`)
- .join(' ')
- )
- .map(match => {
- const page = this.props.pages.find(p => p.relativeName === match.ref);
-
- // This should never happen, but provide this check for type safety.
- if (!page) {
- return undefined;
- }
-
- const highlights: Dict<[number, number][]> = {};
- let longestTerm = '';
- let exactMatch = false;
-
- // Loop over all matching terms/tokens.
- Object.keys(match.matchData.metadata).forEach(term => {
- // Remember the longest term that matches the query as close as possible.
- if (query.includes(term.toLowerCase()) && longestTerm.length < term.length) {
- longestTerm = term;
- }
-
- Object.keys(match.matchData.metadata[term]).forEach(fieldName => {
- const { position: positions, tokenContext: tokenContexts } = match.matchData.metadata[
- term
- ][fieldName];
-
- highlights[fieldName] = [...(highlights[fieldName] || []), ...positions];
-
- // Check if we have an *exact match*.
- if (!exactMatch && tokenContexts) {
- tokenContexts.forEach((tokenContext: string) => {
- if (!exactMatch && tokenContext.includes(query)) {
- exactMatch = true;
- }
- });
- }
- });
- });
-
- return { exactMatch, highlights, longestTerm, page, query };
- })
- .filter(isDefined);
- }
-
- render() {
- const query = this.props.query?.toLowerCase();
-
- if (!query) {
- return null;
- }
-
- const results = this.search(query);
-
- // Re-order results by the length of the longest matched term and by exact
- // match (if applicable). The longer the matched term is, the higher the
- // chance the result is more relevant.
- const sortedResults = sortBy(
- // Sort by longest term.
- sortBy(results, result => -result.longestTerm.length),
- // Sort by exact match.
- result => result.exactMatch && -1
- );
-
- return (
- <>
- {sortedResults.map(result => (
- <SearchResultEntry
- active={result.page.relativeName === this.props.splat}
- key={result.page.relativeName}
- result={result}
- />
- ))}
- </>
- );
- }
-}
-
-// Lunr doesn't support exact multiple-term matching. Meaning "foo bar" will not
-// boost a sentence like "Foo bar baz" more than "Baz bar foo". In order to
-// provide more accurate results, we store the token context, to see if we can
-// perform an "exact match". Unfortunately, we cannot extend the search logic,
-// only the tokenizer at *index time*. This is why we store the context as
-// meta-data, and post-process the matches before rendering (see above). For
-// performance reasons, we only add 2 extra tokens, one in front, one after.
-// This means we support "exact macthing" for up to 3 terms. More search terms
-// would fallback to the regular matching algorithm, which is OK: the more terms
-// searched for, the better the standard algorithm will perform anyway. In the
-// end, the best would be for Lunr to support multi-term matching, as extending
-// the search algorithm for this would be way too complicated.
-export function tokenContextPluginCallback(token: LunrToken, index: number, tokens: LunrToken[]) {
- const prevToken = tokens[index - 1] || '';
- const nextToken = tokens[index + 1] || '';
- token.metadata['tokenContext'] = [prevToken.toString(), token.toString(), nextToken.toString()]
- .filter(s => s.length)
- .join(' ')
- .toLowerCase();
- return token;
-}
-
-let tokenContextPluginRegistered = false;
-
-export function tokenContextPlugin(builder: LunrBuilder) {
- if (!tokenContextPluginRegistered) {
- (lunr as any).Pipeline.registerFunction(tokenContextPluginCallback, 'tokenContext');
- tokenContextPluginRegistered = true;
- }
-
- builder.pipeline.before((lunr as any).stemmer, tokenContextPluginCallback);
- builder.metadataWhitelist.push('tokenContext');
-}
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/Sidebar.tsx b/server/sonar-web/src/main/js/apps/documentation/components/Sidebar.tsx
deleted file mode 100644
index b581b04f3e2..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/Sidebar.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { DocNavigationItem } from 'Docs/@types/types';
-import * as React from 'react';
-import SearchBox from '../../../components/controls/SearchBox';
-import { DocumentationEntry } from '../utils';
-import Menu from './Menu';
-import SearchResults from './SearchResults';
-
-interface Props {
- navigation: DocNavigationItem[];
- pages: DocumentationEntry[];
- splat: string;
-}
-
-interface State {
- query: string;
-}
-
-export default class Sidebar extends React.PureComponent<Props, State> {
- state: State = { query: '' };
-
- handleSearch = (query: string) => {
- this.setState({ query: query.trim() });
- };
-
- render() {
- return (
- <>
- <SearchBox
- className="big-spacer-top spacer-bottom"
- minLength={2}
- onChange={this.handleSearch}
- placeholder="Search for pages or keywords"
- value={this.state.query}
- />
- <div className="documentation-results panel">
- <div className="list-group">
- <SearchResults
- navigation={this.props.navigation}
- pages={this.props.pages}
- query={this.state.query}
- splat={this.props.splat}
- />
-
- {!this.state.query && (
- <Menu
- navigation={this.props.navigation}
- pages={this.props.pages}
- splat={this.props.splat}
- />
- )}
- </div>
- </div>
- </>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx
deleted file mode 100644
index e19bb2e155e..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/App-test.tsx
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { addSideBarClass, removeSideBarClass } from '../../../../helpers/pages';
-import { request } from '../../../../helpers/request';
-import { waitAndUpdate } from '../../../../helpers/testUtils';
-import { InstalledPlugin } from '../../../../types/plugins';
-import getPages from '../../pages';
-import { App } from '../App';
-
-jest.mock('../../../../components/common/ScreenPositionHelper');
-
-jest.mock('Docs/../static/SonarQubeNavigationTree.json', () => [
- {
- title: 'SonarQube',
- children: [
- '/lorem/ipsum/',
- '/analysis/languages/csharp/',
- {
- title: 'Child category',
- children: [
- '/lorem/ipsum/dolor',
- {
- title: 'Grandchild category',
- children: ['/lorem/ipsum/sit']
- },
- '/lorem/ipsum/amet'
- ]
- }
- ]
- }
-]);
-
-jest.mock('../../../../helpers/pages', () => ({
- addSideBarClass: jest.fn(),
- removeSideBarClass: jest.fn()
-}));
-
-jest.mock('../../../../helpers/request', () => {
- const { mockDocumentationMarkdown } = jest.requireActual('../../../../helpers/testMocks');
- return {
- request: jest.fn(() => ({
- submit: jest.fn().mockResolvedValue({
- status: 200,
- text: jest.fn().mockResolvedValue(mockDocumentationMarkdown({ key: 'csharp' }))
- })
- }))
- };
-});
-
-jest.mock('../../pages', () => {
- const { mockDocumentationEntry } = jest.requireActual('../../../../helpers/testMocks');
- return jest
- .fn()
- .mockReturnValue([
- mockDocumentationEntry(),
- mockDocumentationEntry({ url: '/analysis/languages/csharp/' })
- ]);
-});
-
-jest.mock('../../../../api/plugins', () => ({
- getInstalledPlugins: jest.fn().mockResolvedValue([
- {
- key: 'csharp',
- documentationPath: 'static/documentation.md',
- issueTrackerUrl: 'csharp_plugin_issue_tracker_url'
- },
- { key: 'vbnet', documentationPath: 'Sstatic/documentation.md' },
- { key: 'vbnett', documentationPath: undefined }
- ] as InstalledPlugin[])
-}));
-
-beforeEach(() => {
- jest.clearAllMocks();
-});
-
-it('should render correctly for SonarQube', async () => {
- const wrapper = shallowRender();
- expect(wrapper.find('DeferredSpinner').exists()).toBe(true);
- expect(addSideBarClass).toHaveBeenCalled();
-
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
- expect(wrapper.find('ScreenPositionHelper').dive()).toMatchSnapshot();
-
- wrapper.unmount();
- expect(removeSideBarClass).toHaveBeenCalled();
-});
-
-it("should show a 404 if the page doesn't exist", async () => {
- const wrapper = shallowRender({ params: { splat: 'unknown' } });
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should try to fetch language plugin documentation if documentationPath matches', async () => {
- const wrapper = shallowRender();
- await waitAndUpdate(wrapper);
-
- expect(request).toHaveBeenCalledWith('/static/csharp/documentation.md');
- expect(request).not.toHaveBeenCalledWith('/static/vbnet/documentation.md');
- expect(request).not.toHaveBeenCalledWith('/static/vbnett/documentation.md');
- expect(getPages).toHaveBeenCalledWith(
- expect.objectContaining({
- 'analysis/languages/csharp': expect.any(Object)
- })
- );
-});
-
-it('should display the issue tracker url of the plugin if it exists', async () => {
- const wrapper = shallowRender({ params: { splat: 'analysis/languages/csharp/' } });
- await waitAndUpdate(wrapper);
-
- const { content } = (getPages as jest.Mock).mock.calls[0][0]['analysis/languages/csharp'];
-
- expect(content).toContain('csharp_plugin_issue_tracker_url');
-});
-
-function shallowRender(props: Partial<App['props']> = {}) {
- return shallow(<App params={{ splat: 'lorem/ipsum' }} location={{ hash: '#foo' }} {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/Menu-test.tsx b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/Menu-test.tsx
deleted file mode 100644
index f5da4e84c22..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/Menu-test.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import Menu from '../Menu';
-
-function createPage(title: string, relativeName: string, text = '') {
- return { relativeName, url: '/' + relativeName, title, navTitle: undefined, text, content: text };
-}
-
-const pages = [
- createPage(
- 'Lorem Ipsum',
- 'lorem/index',
- "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."
- ),
- createPage(
- 'Where does it come from?',
- 'lorem/origin',
- 'Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words.'
- ),
- createPage(
- 'Where does Foobar come from?',
- 'foobar',
- 'Foobar is a universal variable understood to represent whatever is being discussed.'
- )
-];
-
-it('should render hierarchical menu', () => {
- const wrapper = shallow(
- <Menu
- navigation={[{ title: 'Block', children: ['/lorem/index', '/lorem/origin'] }, 'foobar']}
- pages={pages}
- splat="lorem/origin"
- />
- );
-
- expect(wrapper).toMatchSnapshot();
- wrapper.setProps({ splat: 'baz/bar' });
- expect(wrapper).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/MenuBlock-test.tsx b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/MenuBlock-test.tsx
deleted file mode 100644
index c2ba9a70683..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/MenuBlock-test.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { click } from '../../../../helpers/testUtils';
-import MenuBlock from '../MenuBlock';
-
-it('should render a closed menu block', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should render an opened menu block', () => {
- expect(shallowRender({ openByDefault: true })).toMatchSnapshot();
-});
-
-it('should not render a high depth differently than a depth of 3', () => {
- expect(
- shallowRender({ block: { title: 'Foo', children: ['/foo'] }, depth: 6 })
- ).toMatchSnapshot();
-});
-
-it('can be opened and closed', () => {
- const wrapper = shallowRender();
- expect(wrapper.state('open')).toBe(false);
- click(wrapper.find('ButtonLink'));
- expect(wrapper.state('open')).toBe(true);
-});
-
-function shallowRender(props: Partial<MenuBlock['props']> = {}) {
- return shallow(
- <MenuBlock
- block={{
- title: 'Foo',
- children: [
- '/bar/',
- '/baz/',
- {
- title: 'Baz',
- children: ['/baz/foo']
- },
- {
- title: 'Bar',
- url: 'http://example.com'
- }
- ]
- }}
- openByDefault={false}
- openChain={[]}
- pages={[
- {
- content: 'bar',
- relativeName: '/bar/',
- text: 'bar',
- title: 'Bar',
- navTitle: undefined,
- url: '/bar/'
- },
- {
- content: 'baz',
- relativeName: '/baz/',
- text: 'baz',
- title: 'baz',
- navTitle: 'baznav',
- url: '/baz/'
- }
- ]}
- splat="/foo/"
- title="Foo"
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/MenuItem-test.tsx b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/MenuItem-test.tsx
deleted file mode 100644
index bada3d99f90..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/MenuItem-test.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { DocumentationEntry } from '../../utils';
-import { MenuItem } from '../MenuItem';
-
-it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should render correctly if the current node matches the splat', () => {
- expect(shallowRender({ splat: 'bar' })).toMatchSnapshot();
-});
-
-it('should not render a high depth differently than a depth of 3', () => {
- expect(shallowRender({ depth: 6 })).toMatchSnapshot();
-});
-
-function shallowRender(props = {}) {
- return shallow(<MenuItem node={{ url: '/bar' } as DocumentationEntry} splat="foo" {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/SearchResultEntry-test.tsx b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/SearchResultEntry-test.tsx
deleted file mode 100644
index 34046888c4f..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/SearchResultEntry-test.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import SearchResultEntry, {
- SearchResult,
- SearchResultText,
- SearchResultTitle,
- SearchResultTokens
-} from '../SearchResultEntry';
-
-describe('SearchResultEntry', () => {
- it('should render', () => {
- expect(
- shallow(<SearchResultEntry active={true} result={mockSearchResult()} />)
- ).toMatchSnapshot();
- });
-});
-
-describe('SearchResultText', () => {
- it('should render with highlights', () => {
- expect(
- shallow(<SearchResultText result={mockSearchResult({ highlights: { text: [[12, 9]] } })} />)
- ).toMatchSnapshot();
- });
-
- it('should correctly extract exact matches', () => {
- expect(
- shallow(
- <SearchResultText
- result={mockSearchResult({ exactMatch: true, query: 'variable understood' })}
- />
- )
- ).toMatchSnapshot();
- });
-
- it('should render without highlights', () => {
- expect(shallow(<SearchResultText result={mockSearchResult()} />)).toMatchSnapshot();
- });
-});
-
-describe('SearchResultTitle', () => {
- it('should render with highlights', () => {
- expect(
- shallow(<SearchResultTitle result={mockSearchResult({ highlights: { title: [[0, 6]] } })} />)
- ).toMatchSnapshot();
- });
-
- it('should render not without highlights', () => {
- expect(shallow(<SearchResultTitle result={mockSearchResult()} />)).toMatchSnapshot();
- });
-});
-
-describe('SearchResultTokens', () => {
- it('should render', () => {
- expect(
- shallow(
- <SearchResultTokens
- tokens={[
- { marked: false, text: 'Foobar is a ' },
- { marked: true, text: 'universal' },
- {
- marked: false,
- text: ' variable understood to represent whatever is being discussed.'
- }
- ]}
- />
- )
- ).toMatchSnapshot();
- });
-});
-
-function mockSearchResult(overrides: Partial<SearchResult> = {}) {
- return {
- page: {
- content: '',
- relativeName: 'foo/bar',
- url: '/foo/bar',
- text: 'Foobar is a universal variable understood to represent whatever is being discussed.',
- title: 'Foobar',
- navTitle: undefined
- },
- highlights: {},
- longestTerm: '',
- query: '',
- ...overrides
- };
-}
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/SearchResults-test.tsx b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/SearchResults-test.tsx
deleted file mode 100644
index 429d6b4ebaf..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/SearchResults-test.tsx
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import lunr, { LunrBuilder, LunrToken } from 'lunr';
-import * as React from 'react';
-import { mockDocumentationEntry } from '../../../../helpers/testMocks';
-import { getUrlsList } from '../../navTreeUtils';
-import { DocumentationEntry } from '../../utils';
-import SearchResultEntry from '../SearchResultEntry';
-import SearchResults, { tokenContextPlugin, tokenContextPluginCallback } from '../SearchResults';
-
-jest.mock('../../navTreeUtils', () => ({
- getUrlsList: jest.fn().mockReturnValue([])
-}));
-
-jest.mock('lunr', () => {
- const lunr = jest.fn(() => ({
- search: jest.fn(() => [
- {
- ref: 'lorem/origin',
- matchData: {
- metadata: {
- simply: {
- title: { position: [[19, 5]] },
- text: {
- position: [
- [15, 6],
- [28, 4]
- ],
- tokenContext: ['is simply dummy', 'simply dummy text']
- }
- }
- }
- }
- },
- {
- ref: 'foobar',
- matchData: {
- metadata: {
- simply: {
- title: { position: [[23, 4]] },
- text: {
- position: [
- [111, 6],
- [118, 4]
- ],
- tokenContext: ['dummy simply text']
- }
- }
- }
- }
- }
- ])
- }));
-
- (lunr as any).Pipeline = {
- registerFunction: jest.fn()
- };
-
- return lunr;
-});
-
-it('should render correctly', () => {
- expect(shallowRender()).toMatchSnapshot('default');
- expect(shallowRender({ query: '' }).type()).toBeNull();
-});
-
-describe('search engine', () => {
- class LunrIndexMock {
- plugins: Function[] = [];
- fields: Array<{ field: string; args: any }> = [];
- docs: DocumentationEntry[] = [];
- metadataWhitelist: string[] = [];
-
- use(fn: Function) {
- this.plugins.push(fn);
- }
-
- ref(_ref: string) {
- /* noop */
- }
-
- field(field: string, args = {}) {
- this.fields.push({ field, args });
- }
-
- add(doc: DocumentationEntry) {
- this.docs.push(doc);
- }
- }
-
- it('should correctly populate the index', () => {
- (getUrlsList as jest.Mock).mockReturnValueOnce(['/lorem/index', '/lorem/origin']);
-
- shallowRender();
-
- // Fetch the callback passed to lunr(), which serves as the index constructor.
- const indexConstructor: Function = (lunr as jest.Mock).mock.calls[0][0];
-
- // Apply it to our mock index.
- const lunrMock = new LunrIndexMock();
- indexConstructor.apply(lunrMock);
-
- expect(lunrMock.docs.length).toBe(2);
- expect(lunrMock.plugins).toContain(tokenContextPlugin);
- expect(lunrMock.metadataWhitelist).toEqual(['position', 'tokenContext']);
- expect(lunrMock.fields).toEqual([
- expect.objectContaining({ field: 'title', args: { boost: 10 } }),
- expect.objectContaining({ field: 'text' })
- ]);
- });
-
- it('should correctly look for an exact match', () => {
- // No exact match, should sort as the matches came in.
- const wrapper = shallowRender({ query: 'text simply' });
- expect(
- wrapper
- .find(SearchResultEntry)
- .at(0)
- .props().result.page.relativeName
- ).toBe('lorem/origin');
-
- // Exact match, specific page should be at the top.
- wrapper.setProps({ query: 'simply text' });
- expect(
- wrapper
- .find(SearchResultEntry)
- .at(0)
- .props().result.page.relativeName
- ).toBe('foobar');
- });
-
- it('should trigger a search if query is set', () => {
- const wrapper = shallowRender({ query: undefined });
- expect(wrapper.instance().index.search).not.toHaveBeenCalled();
- wrapper.setProps({ query: 'si:+mply text' });
- expect(wrapper.instance().index.search).toHaveBeenCalledWith('simply~1 simply* text~1 text*');
- });
-});
-
-describe('tokenContextPluginCallback', () => {
- class LunrTokenMock {
- str: string;
- metadata: any;
-
- constructor(str: string) {
- this.str = str;
- this.metadata = {};
- }
-
- toString() {
- return this.str;
- }
- }
-
- class LunrBuilderMock {
- pipeline: { before: (stemmer: any, cb: Function) => void };
- metadataWhitelist: string[];
-
- constructor() {
- this.pipeline = {
- before: () => {
- /* noop */
- }
- };
- this.metadataWhitelist = [];
- }
- }
-
- function mockLunrToken(str: string): LunrToken {
- return new LunrTokenMock(str);
- }
-
- function mockLunrBuilder(): LunrBuilder {
- return new LunrBuilderMock();
- }
-
- it('should correctly provide token context for text', () => {
- const tokens = [
- mockLunrToken('this'),
- mockLunrToken('is'),
- mockLunrToken('some'),
- mockLunrToken('text')
- ];
-
- expect(tokenContextPluginCallback(mockLunrToken('this'), 0, tokens).metadata).toEqual(
- expect.objectContaining({ tokenContext: 'this is' })
- );
- expect(tokenContextPluginCallback(mockLunrToken('is'), 1, tokens).metadata).toEqual(
- expect.objectContaining({ tokenContext: 'this is some' })
- );
- expect(tokenContextPluginCallback(mockLunrToken('some'), 2, tokens).metadata).toEqual(
- expect.objectContaining({ tokenContext: 'is some text' })
- );
- expect(tokenContextPluginCallback(mockLunrToken('text'), 3, tokens).metadata).toEqual(
- expect.objectContaining({ tokenContext: 'some text' })
- );
- });
-
- it('should only register the plugin once', () => {
- tokenContextPlugin(mockLunrBuilder());
- tokenContextPlugin(mockLunrBuilder());
- expect((lunr as any).Pipeline.registerFunction).toHaveBeenCalledTimes(1);
- });
-});
-
-function shallowRender(props: Partial<SearchResults['props']> = {}) {
- return shallow<SearchResults>(
- <SearchResults
- navigation={['lorem/index', 'lorem/origin', 'foobar']}
- pages={[
- mockDocumentationEntry({
- title: 'Lorem Ipsum',
- relativeName: 'lorem/index',
- url: '/lorem/index',
- content:
- "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.",
- text:
- "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book."
- }),
- mockDocumentationEntry({
- title: 'Where does it come from?',
- relativeName: 'lorem/origin',
- url: '/lorem/origin',
- content:
- 'Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words.',
- text:
- 'Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words.'
- }),
- mockDocumentationEntry({
- title: 'Where does Foobar come from?',
- relativeName: 'foobar',
- url: '/foobar',
- content:
- 'Foobar is a universal variable understood to represent whatever is being discussed. Now we need some keywords: simply text.',
- text:
- 'Foobar is a universal variable understood to represent whatever is being discussed. Now we need some keywords: simply text.'
- })
- ]}
- query="what is 42"
- splat="foobar"
- {...props}
- />
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/Sidebar-test.tsx b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/Sidebar-test.tsx
deleted file mode 100644
index 27540d3c1fa..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/Sidebar-test.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import Sidebar from '../Sidebar';
-
-function createPage(title: string, relativeName: string, text = '') {
- return { relativeName, url: '/' + relativeName, title, navTitle: undefined, text, content: text };
-}
-
-const pages = [
- createPage('Lorem Ipsum', 'lorem/index'),
- createPage('Where does Foobar come from?', 'foobar')
-];
-
-it('should render menu', () => {
- expect(
- shallow(
- <Sidebar
- navigation={[{ title: 'Block', children: ['/lorem/index'] }, 'foobar']}
- pages={pages}
- splat="foobar"
- />
- )
- ).toMatchSnapshot();
-});
-
-it('should search', () => {
- const wrapper = shallow(
- <Sidebar
- navigation={[{ title: 'Block', children: ['/lorem/index'] }, 'foobar']}
- pages={pages}
- splat="foobar"
- />
- );
- wrapper.find('SearchBox').prop<Function>('onChange')('foo');
- wrapper.update();
- expect(wrapper).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/App-test.tsx.snap
deleted file mode 100644
index 690037a28e2..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/App-test.tsx.snap
+++ /dev/null
@@ -1,151 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly for SonarQube 1`] = `
-<div
- className="layout-page"
->
- <Helmet
- defer={false}
- encodeSpecialCharacters={true}
- prioritizeSeoTags={false}
- title="Lorem | documentation.page_title.sonarqube"
- >
- <meta
- content="noindex nofollow"
- name="robots"
- />
- </Helmet>
- <ScreenPositionHelper
- className="layout-page-side-outer"
- >
- <Component />
- </ScreenPositionHelper>
- <div
- className="layout-page-main"
- >
- <div
- className="layout-page-main-inner"
- >
- <div
- className="boxed-group"
- >
- <A11ySkipTarget
- anchor="documentation_main"
- />
- <DocMarkdownBlock
- className="documentation-content cut-margins boxed-group-inner"
- content="Lorem ipsum dolor sit amet fredum"
- scrollToHref="#foo"
- stickyToc={true}
- title="Lorem"
- />
- </div>
- </div>
- </div>
-</div>
-`;
-
-exports[`should render correctly for SonarQube 2`] = `
-<div
- className="layout-page-side"
- style={
- Object {
- "top": 0,
- }
- }
->
- <div
- className="layout-page-side-inner"
- >
- <div
- className="layout-page-filters"
- >
- <div
- className="documentation-page-header"
- >
- <A11ySkipTarget
- anchor="documentation_menu"
- label="documentation.skip_to_nav"
- weight={10}
- />
- <ForwardRef(Link)
- to="/documentation/"
- >
- <h1>
- documentation.page
- </h1>
- </ForwardRef(Link)>
- </div>
- <Sidebar
- navigation={
- Array [
- Object {
- "children": Array [
- "/lorem/ipsum/",
- "/analysis/languages/csharp/",
- Object {
- "children": Array [
- "/lorem/ipsum/dolor",
- Object {
- "children": Array [
- "/lorem/ipsum/sit",
- ],
- "title": "Grandchild category",
- },
- "/lorem/ipsum/amet",
- ],
- "title": "Child category",
- },
- ],
- "title": "SonarQube",
- },
- ]
- }
- pages={
- Array [
- Object {
- "content": "Lorem ipsum dolor sit amet fredum",
- "navTitle": undefined,
- "relativeName": "Lorem",
- "text": "Lorem ipsum dolor sit amet fredum",
- "title": "Lorem",
- "url": "/lorem/ipsum",
- },
- Object {
- "content": "Lorem ipsum dolor sit amet fredum",
- "navTitle": undefined,
- "relativeName": "Lorem",
- "text": "Lorem ipsum dolor sit amet fredum",
- "title": "Lorem",
- "url": "/analysis/languages/csharp/",
- },
- ]
- }
- splat="lorem/ipsum"
- />
- </div>
- </div>
-</div>
-`;
-
-exports[`should show a 404 if the page doesn't exist 1`] = `
-<Fragment>
- <Helmet
- defer={true}
- encodeSpecialCharacters={true}
- prioritizeSeoTags={false}
- title="documentation.page_title.sonarqube"
- >
- <meta
- content="noindex nofollow"
- name="robots"
- />
- </Helmet>
- <A11ySkipTarget
- anchor="documentation_main"
- />
- <NotFound
- withContainer={false}
- />
-</Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/Menu-test.tsx.snap b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/Menu-test.tsx.snap
deleted file mode 100644
index 7e95338634f..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/Menu-test.tsx.snap
+++ /dev/null
@@ -1,118 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render hierarchical menu 1`] = `
-<Fragment>
- <MenuBlock
- block={
- Object {
- "children": Array [
- "/lorem/index",
- "/lorem/origin",
- ],
- "title": "Block",
- }
- }
- key="Block"
- openByDefault={true}
- openChain={
- Array [
- Object {
- "children": Array [
- "/lorem/index",
- "/lorem/origin",
- ],
- "title": "Block",
- },
- "/lorem/origin",
- ]
- }
- pages={
- Array [
- Object {
- "content": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.",
- "navTitle": undefined,
- "relativeName": "lorem/index",
- "text": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.",
- "title": "Lorem Ipsum",
- "url": "/lorem/index",
- },
- Object {
- "content": "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words.",
- "navTitle": undefined,
- "relativeName": "lorem/origin",
- "text": "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words.",
- "title": "Where does it come from?",
- "url": "/lorem/origin",
- },
- Object {
- "content": "Foobar is a universal variable understood to represent whatever is being discussed.",
- "navTitle": undefined,
- "relativeName": "foobar",
- "text": "Foobar is a universal variable understood to represent whatever is being discussed.",
- "title": "Where does Foobar come from?",
- "url": "/foobar",
- },
- ]
- }
- splat="lorem/origin"
- title="Block"
- />
- <MenuItem
- key="foobar"
- splat="lorem/origin"
- />
-</Fragment>
-`;
-
-exports[`should render hierarchical menu 2`] = `
-<Fragment>
- <MenuBlock
- block={
- Object {
- "children": Array [
- "/lorem/index",
- "/lorem/origin",
- ],
- "title": "Block",
- }
- }
- key="Block"
- openByDefault={false}
- openChain={Array []}
- pages={
- Array [
- Object {
- "content": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.",
- "navTitle": undefined,
- "relativeName": "lorem/index",
- "text": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.",
- "title": "Lorem Ipsum",
- "url": "/lorem/index",
- },
- Object {
- "content": "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words.",
- "navTitle": undefined,
- "relativeName": "lorem/origin",
- "text": "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words.",
- "title": "Where does it come from?",
- "url": "/lorem/origin",
- },
- Object {
- "content": "Foobar is a universal variable understood to represent whatever is being discussed.",
- "navTitle": undefined,
- "relativeName": "foobar",
- "text": "Foobar is a universal variable understood to represent whatever is being discussed.",
- "title": "Where does Foobar come from?",
- "url": "/foobar",
- },
- ]
- }
- splat="baz/bar"
- title="Block"
- />
- <MenuItem
- key="foobar"
- splat="baz/bar"
- />
-</Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/MenuBlock-test.tsx.snap b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/MenuBlock-test.tsx.snap
deleted file mode 100644
index 6d5600201c8..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/MenuBlock-test.tsx.snap
+++ /dev/null
@@ -1,124 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should not render a high depth differently than a depth of 3 1`] = `
-<Fragment>
- <ButtonLink
- className="list-group-item depth-3"
- onClick={[Function]}
- >
- <h3
- className="list-group-item-heading"
- >
- <OpenCloseIcon
- className="little-spacer-right"
- open={false}
- />
- Foo
- </h3>
- </ButtonLink>
-</Fragment>
-`;
-
-exports[`should render a closed menu block 1`] = `
-<Fragment>
- <ButtonLink
- className="list-group-item"
- onClick={[Function]}
- >
- <h3
- className="list-group-item-heading"
- >
- <OpenCloseIcon
- className="little-spacer-right"
- open={false}
- />
- Foo
- </h3>
- </ButtonLink>
-</Fragment>
-`;
-
-exports[`should render an opened menu block 1`] = `
-<Fragment>
- <ButtonLink
- className="list-group-item"
- onClick={[Function]}
- >
- <h3
- className="list-group-item-heading"
- >
- <OpenCloseIcon
- className="little-spacer-right"
- open={true}
- />
- Foo
- </h3>
- </ButtonLink>
- <MenuItem
- depth={1}
- key="/bar/"
- node={
- Object {
- "content": "bar",
- "navTitle": undefined,
- "relativeName": "/bar/",
- "text": "bar",
- "title": "Bar",
- "url": "/bar/",
- }
- }
- splat="/foo/"
- />
- <MenuItem
- depth={1}
- key="/baz/"
- node={
- Object {
- "content": "baz",
- "navTitle": "baznav",
- "relativeName": "/baz/",
- "text": "baz",
- "title": "baz",
- "url": "/baz/",
- }
- }
- splat="/foo/"
- />
- <MenuBlock
- block={
- Object {
- "children": Array [
- "/baz/foo",
- ],
- "title": "Baz",
- }
- }
- depth={1}
- key="Baz"
- openByDefault={false}
- openChain={Array []}
- pages={
- Array [
- Object {
- "content": "bar",
- "navTitle": undefined,
- "relativeName": "/bar/",
- "text": "bar",
- "title": "Bar",
- "url": "/bar/",
- },
- Object {
- "content": "baz",
- "navTitle": "baznav",
- "relativeName": "/baz/",
- "text": "baz",
- "title": "baz",
- "url": "/baz/",
- },
- ]
- }
- splat="/foo/"
- title="Baz"
- />
-</Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/MenuItem-test.tsx.snap b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/MenuItem-test.tsx.snap
deleted file mode 100644
index 6eb967c4ed3..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/MenuItem-test.tsx.snap
+++ /dev/null
@@ -1,37 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should not render a high depth differently than a depth of 3 1`] = `
-<ForwardRef(Link)
- className="list-group-item depth-3"
- key="/bar"
- to="/documentation/bar"
->
- <h3
- className="list-group-item-heading"
- />
-</ForwardRef(Link)>
-`;
-
-exports[`should render correctly 1`] = `
-<ForwardRef(Link)
- className="list-group-item"
- key="/bar"
- to="/documentation/bar"
->
- <h3
- className="list-group-item-heading"
- />
-</ForwardRef(Link)>
-`;
-
-exports[`should render correctly if the current node matches the splat 1`] = `
-<ForwardRef(Link)
- className="list-group-item active"
- key="/bar"
- to="/documentation/bar"
->
- <h3
- className="list-group-item-heading"
- />
-</ForwardRef(Link)>
-`;
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/SearchResultEntry-test.tsx.snap b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/SearchResultEntry-test.tsx.snap
deleted file mode 100644
index 9537e85112a..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/SearchResultEntry-test.tsx.snap
+++ /dev/null
@@ -1,142 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`SearchResultEntry should render 1`] = `
-<ForwardRef(Link)
- className="list-group-item active"
- to="/documentation/foo/bar"
->
- <SearchResultTitle
- result={
- Object {
- "highlights": Object {},
- "longestTerm": "",
- "page": Object {
- "content": "",
- "navTitle": undefined,
- "relativeName": "foo/bar",
- "text": "Foobar is a universal variable understood to represent whatever is being discussed.",
- "title": "Foobar",
- "url": "/foo/bar",
- },
- "query": "",
- }
- }
- />
- <SearchResultText
- result={
- Object {
- "highlights": Object {},
- "longestTerm": "",
- "page": Object {
- "content": "",
- "navTitle": undefined,
- "relativeName": "foo/bar",
- "text": "Foobar is a universal variable understood to represent whatever is being discussed.",
- "title": "Foobar",
- "url": "/foo/bar",
- },
- "query": "",
- }
- }
- />
-</ForwardRef(Link)>
-`;
-
-exports[`SearchResultText should correctly extract exact matches 1`] = `
-<div
- className="note"
->
- <SearchResultTokens
- tokens={
- Array [
- Object {
- "marked": false,
- "text": "Foobar is a universal ",
- },
- Object {
- "marked": true,
- "text": "variable understood",
- },
- Object {
- "marked": false,
- "text": " to represent whatever is being discussed.",
- },
- ]
- }
- />
-</div>
-`;
-
-exports[`SearchResultText should render with highlights 1`] = `
-<div
- className="note"
->
- <SearchResultTokens
- tokens={
- Array [
- Object {
- "marked": false,
- "text": "Foobar is a ",
- },
- Object {
- "marked": true,
- "text": "universal",
- },
- Object {
- "marked": false,
- "text": " variable understood to represent whatever is being discussed.",
- },
- ]
- }
- />
-</div>
-`;
-
-exports[`SearchResultText should render without highlights 1`] = `""`;
-
-exports[`SearchResultTitle should render not without highlights 1`] = `
-<h3
- className="list-group-item-heading"
- style={
- Object {
- "fontWeight": "normal",
- }
- }
->
- Foobar
-</h3>
-`;
-
-exports[`SearchResultTitle should render with highlights 1`] = `
-<h3
- className="list-group-item-heading"
- style={
- Object {
- "fontWeight": "normal",
- }
- }
->
- <SearchResultTokens
- tokens={
- Array [
- Object {
- "marked": true,
- "text": "Foobar",
- },
- ]
- }
- />
-</h3>
-`;
-
-exports[`SearchResultTokens should render 1`] = `
-<Fragment>
- Foobar is a
- <mark
- key="1"
- >
- universal
- </mark>
- variable understood to represent whatever is being discussed.
-</Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/SearchResults-test.tsx.snap b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/SearchResults-test.tsx.snap
deleted file mode 100644
index ae487ab0528..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/SearchResults-test.tsx.snap
+++ /dev/null
@@ -1,80 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly: default 1`] = `
-<Fragment>
- <SearchResultEntry
- active={false}
- key="lorem/origin"
- result={
- Object {
- "exactMatch": false,
- "highlights": Object {
- "text": Array [
- Array [
- 15,
- 6,
- ],
- Array [
- 28,
- 4,
- ],
- ],
- "title": Array [
- Array [
- 19,
- 5,
- ],
- ],
- },
- "longestTerm": "",
- "page": Object {
- "content": "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words.",
- "navTitle": undefined,
- "relativeName": "lorem/origin",
- "text": "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words.",
- "title": "Where does it come from?",
- "url": "/lorem/origin",
- },
- "query": "what is 42",
- }
- }
- />
- <SearchResultEntry
- active={true}
- key="foobar"
- result={
- Object {
- "exactMatch": false,
- "highlights": Object {
- "text": Array [
- Array [
- 111,
- 6,
- ],
- Array [
- 118,
- 4,
- ],
- ],
- "title": Array [
- Array [
- 23,
- 4,
- ],
- ],
- },
- "longestTerm": "",
- "page": Object {
- "content": "Foobar is a universal variable understood to represent whatever is being discussed. Now we need some keywords: simply text.",
- "navTitle": undefined,
- "relativeName": "foobar",
- "text": "Foobar is a universal variable understood to represent whatever is being discussed. Now we need some keywords: simply text.",
- "title": "Where does Foobar come from?",
- "url": "/foobar",
- },
- "query": "what is 42",
- }
- }
- />
-</Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/Sidebar-test.tsx.snap b/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/Sidebar-test.tsx.snap
deleted file mode 100644
index b83396b9873..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/components/__tests__/__snapshots__/Sidebar-test.tsx.snap
+++ /dev/null
@@ -1,145 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render menu 1`] = `
-<Fragment>
- <SearchBox
- className="big-spacer-top spacer-bottom"
- minLength={2}
- onChange={[Function]}
- placeholder="Search for pages or keywords"
- value=""
- />
- <div
- className="documentation-results panel"
- >
- <div
- className="list-group"
- >
- <SearchResults
- navigation={
- Array [
- Object {
- "children": Array [
- "/lorem/index",
- ],
- "title": "Block",
- },
- "foobar",
- ]
- }
- pages={
- Array [
- Object {
- "content": "",
- "navTitle": undefined,
- "relativeName": "lorem/index",
- "text": "",
- "title": "Lorem Ipsum",
- "url": "/lorem/index",
- },
- Object {
- "content": "",
- "navTitle": undefined,
- "relativeName": "foobar",
- "text": "",
- "title": "Where does Foobar come from?",
- "url": "/foobar",
- },
- ]
- }
- query=""
- splat="foobar"
- />
- <Menu
- navigation={
- Array [
- Object {
- "children": Array [
- "/lorem/index",
- ],
- "title": "Block",
- },
- "foobar",
- ]
- }
- pages={
- Array [
- Object {
- "content": "",
- "navTitle": undefined,
- "relativeName": "lorem/index",
- "text": "",
- "title": "Lorem Ipsum",
- "url": "/lorem/index",
- },
- Object {
- "content": "",
- "navTitle": undefined,
- "relativeName": "foobar",
- "text": "",
- "title": "Where does Foobar come from?",
- "url": "/foobar",
- },
- ]
- }
- splat="foobar"
- />
- </div>
- </div>
-</Fragment>
-`;
-
-exports[`should search 1`] = `
-<Fragment>
- <SearchBox
- className="big-spacer-top spacer-bottom"
- minLength={2}
- onChange={[Function]}
- placeholder="Search for pages or keywords"
- value="foo"
- />
- <div
- className="documentation-results panel"
- >
- <div
- className="list-group"
- >
- <SearchResults
- navigation={
- Array [
- Object {
- "children": Array [
- "/lorem/index",
- ],
- "title": "Block",
- },
- "foobar",
- ]
- }
- pages={
- Array [
- Object {
- "content": "",
- "navTitle": undefined,
- "relativeName": "lorem/index",
- "text": "",
- "title": "Lorem Ipsum",
- "url": "/lorem/index",
- },
- Object {
- "content": "",
- "navTitle": undefined,
- "relativeName": "foobar",
- "text": "",
- "title": "Where does Foobar come from?",
- "url": "/foobar",
- },
- ]
- }
- query="foo"
- splat="foobar"
- />
- </div>
- </div>
-</Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/apps/documentation/documentation.directory-loader.js b/server/sonar-web/src/main/js/apps/documentation/documentation.directory-loader.js
deleted file mode 100644
index 3092d16f949..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/documentation.directory-loader.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-const path = require('path');
-
-module.exports = {
- placeholder: true // doesn't matter, this is replaced by esbuild
-};
diff --git a/server/sonar-web/src/main/js/apps/documentation/navTreeUtils.ts b/server/sonar-web/src/main/js/apps/documentation/navTreeUtils.ts
deleted file mode 100644
index 84b95eff83b..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/navTreeUtils.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import NavigationTree from 'Docs/../static/SonarQubeNavigationTree.json';
-import {
- DocNavigationItem,
- DocsNavigationBlock,
- DocsNavigationExternalLink
-} from 'Docs/@types/types';
-import { flatten } from 'lodash';
-
-export function getNavTree() {
- return NavigationTree as DocNavigationItem[];
-}
-
-export function getUrlsList(navTree: DocNavigationItem[]): string[] {
- return flatten(
- navTree.map(leaf => {
- if (isDocsNavigationBlock(leaf)) {
- return getUrlsList(leaf.children);
- }
- if (isDocsNavigationExternalLink(leaf)) {
- return [leaf.url];
- }
- return [leaf];
- })
- );
-}
-
-export function getOpenChainFromPath(pathname: string, navTree: DocNavigationItem[]) {
- let chain: DocNavigationItem[] = [];
-
- let found = false;
- const walk = (leaf: DocNavigationItem, parents: DocNavigationItem[] = []) => {
- if (found) {
- return;
- }
-
- parents = parents.concat(leaf);
-
- if (isDocsNavigationBlock(leaf)) {
- leaf.children.forEach(child => {
- if (typeof child === 'string' && testPathAgainstUrl(child, pathname)) {
- chain = parents.concat(child);
- found = true;
- } else {
- walk(child, parents);
- }
- });
- } else if (typeof leaf === 'string' && testPathAgainstUrl(leaf, pathname)) {
- chain = parents;
- found = true;
- }
- };
-
- navTree.forEach(leaf => walk(leaf));
-
- return chain;
-}
-
-export function isDocsNavigationBlock(leaf?: DocNavigationItem): leaf is DocsNavigationBlock {
- return typeof leaf === 'object' && (leaf as DocsNavigationBlock).children !== undefined;
-}
-
-export function isDocsNavigationExternalLink(
- leaf?: DocNavigationItem
-): leaf is DocsNavigationExternalLink {
- return typeof leaf === 'object' && (leaf as DocsNavigationExternalLink).url !== undefined;
-}
-
-export function testPathAgainstUrl(path: string, url: string) {
- const leadingRegEx = /^\//;
- const trailingRegEx = /\/$/;
- return (
- path.replace(leadingRegEx, '').replace(trailingRegEx, '') ===
- url.replace(leadingRegEx, '').replace(trailingRegEx, '')
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/documentation/pages.ts b/server/sonar-web/src/main/js/apps/documentation/pages.ts
deleted file mode 100644
index 11b8dca96a7..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/pages.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import remark from 'remark';
-import visit from 'unist-util-visit';
-import { filterContent, ParsedContent, separateFrontMatter } from '../../helpers/markdown';
-import { Dict } from '../../types/types';
-import Docs from './documentation.directory-loader';
-import { DocumentationEntry, DocumentationEntryScope } from './utils';
-
-export default function getPages(parsedOverrides: Dict<ParsedContent> = {}): DocumentationEntry[] {
- // Get entries, merge with overrides if applicable.
- const pages = ((Docs as unknown) as Array<{ content: string; path: string }>).map(file => {
- let parsed = separateFrontMatter(file.content);
-
- if (parsedOverrides[file.path]) {
- const parsedOverride = parsedOverrides[file.path];
- parsed = {
- content: parsedOverride.content,
- frontmatter: { ...parsed.frontmatter, ...parsedOverride.frontmatter }
- };
- delete parsedOverrides[file.path];
- }
-
- return { parsed, file };
- });
-
- // Add new entries.
- Object.keys(parsedOverrides).forEach(path => {
- const parsed = parsedOverrides[path];
- pages.push({
- parsed,
- file: { content: parsed.content, path }
- });
- });
-
- return pages.map(({ parsed, file }) => {
- let content = '';
- let text = '';
- try {
- content = filterContent(parsed.content);
- text = getText(content);
- } catch (e) {
- /* eslint-disable-next-line no-console */
- console.error(
- `Documentation - an error occured while parsing page "${parsed.frontmatter.url ||
- file.path}":`,
- e
- );
- }
-
- return {
- relativeName: file.path,
- url: parsed.frontmatter.url || `/${file.path}/`,
- title: parsed.frontmatter.title,
- navTitle: parsed.frontmatter.nav || undefined,
- order: Number(parsed.frontmatter.order || -1),
- scope: parsed.frontmatter.scope
- ? (parsed.frontmatter.scope.toLowerCase() as DocumentationEntryScope)
- : undefined,
- text,
- content
- };
- });
-}
-
-function getText(content: string) {
- const ast = remark().parse(content);
- const texts: string[] = [];
- visit(ast, node => {
- if (node.type === `text` || node.type === `inlineCode`) {
- texts.push(node.value);
- }
- });
- return texts.join(' ').replace(/\s+/g, ' ');
-}
diff --git a/server/sonar-web/src/main/js/apps/documentation/routes.tsx b/server/sonar-web/src/main/js/apps/documentation/routes.tsx
deleted file mode 100644
index c7be80023d0..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/routes.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { Route } from 'react-router-dom';
-import App from './components/App';
-
-const routes = () => (
- <Route path="documentation">
- <Route index={true} element={<App />} />
- <Route path="*" element={<App />} />
- </Route>
-);
-
-export default routes;
diff --git a/server/sonar-web/src/main/js/apps/documentation/styles.css b/server/sonar-web/src/main/js/apps/documentation/styles.css
deleted file mode 100644
index 599e453ead6..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/styles.css
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-.documentation-page-header {
- margin: 10px 20px;
-}
-
-.documentation-footer div,
-.documentation-footer .page-footer-menu {
- max-width: 740px;
-}
-
-.documentation-content {
- padding: calc(4 * var(--gridSize)) calc(8 * var(--gridSize));
-}
-
-.documentation-content.markdown {
- position: relative;
- font-size: 16px;
- line-height: 1.7;
-}
-
-.documentation-content .markdown-content {
- width: 100%;
-}
-
-.documentation-content.markdown iframe {
- width: 100%;
- border: 0;
- overflow-y: auto;
- height: 65vh;
-}
-
-.documentation-content.markdown .documentation-title {
- font-size: 24px;
- padding-top: var(--gridSize);
- margin-bottom: 2em;
-}
-
-.documentation-content.markdown h2 {
- font-size: 18px;
- font-weight: 800;
- margin-top: 3em;
-}
-
-.documentation-content.markdown h3 {
- font-size: 16px;
- margin-bottom: 0.8em;
-}
-
-.documentation-content.markdown pre {
- border: 1px solid #e6e6e6;
- border-radius: 3px;
- background-color: rgba(0, 0, 0, 0.06);
-}
-
-.documentation-content.markdown .alert,
-.documentation-content.markdown p,
-.documentation-content.markdown pre,
-.documentation-content.markdown table {
- margin: 0.8em 0 2em;
-}
-
-.documentation-content.markdown ul {
- margin: 0 0 2em;
-}
-
-.documentation-content.markdown ul > ul {
- margin: 0;
-}
-
-.documentation-content.markdown p + ul,
-.documentation-content.markdown p + ol,
-.documentation-content.markdown p + pre {
- margin: -1em 0 2em;
-}
-
-.documentation-content.markdown li > p,
-.documentation-content.markdown li > p + pre {
- margin: 0;
-}
-
-.documentation-content.markdown li > p + ul,
-.documentation-content.markdown li > p + ol {
- margin: 0;
-}
-
-.documentation-content.markdown img[src$='.svg'] {
- vertical-align: text-bottom;
-}
-
-.documentation-content.markdown .alert {
- display: block;
- padding: var(--gridSize) calc(2 * var(--gridSize));
-}
-
-.documentation-content.markdown .alert .custom-block-body {
- padding-left: 24px;
- background-position: left 6px;
- background-repeat: no-repeat;
-}
-
-.documentation-content.markdown .alert-success .custom-block-body {
- background-image: url(/images/check.svg);
-}
-
-.documentation-content.markdown .alert-info .custom-block-body {
- background-image: url(/images/info.svg);
-}
-
-.documentation-content.markdown .alert-warning .custom-block-body {
- background-image: url(/images/exclamation.svg);
-}
-
-.documentation-content.markdown .alert-error .custom-block-body,
-.documentation-content.markdown .alert-danger .custom-block-body {
- background-image: url(/images/cross.svg);
-}
-
-.documentation-content.markdown .collapse-container {
- border: 1px solid var(--barBorderColor);
- border-radius: 2px;
- background-color: var(--barBackgroundColor);
- padding: 8px;
- margin: 0.8em 0 2em;
-}
-
-.documentation-content.markdown .collapse-container > a:first-child {
- display: block;
-}
-
-.documentation-content.markdown .collapse-container > a:first-child:focus {
- color: var(--darkBlue);
-}
-
-.documentation-content.markdown .collapse-container *:last-child {
- margin-bottom: 0;
-}
-
-.markdown.has-toc {
- display: flex;
-}
-
-.markdown.has-toc .markdown-content {
- flex-shrink: 1;
- overflow: hidden;
- text-overflow: ellipsis;
- overflow-x: auto;
-}
-
-.markdown-toc {
- flex: 0 0 240px;
- margin-right: -40px;
-}
-
-.markdown-toc-content {
- margin-left: calc(4 * var(--gridSize));
- padding: 0 var(--gridSize);
- font-size: var(--baseFontSize);
- background: white;
- position: sticky;
- top: calc(20px + var(--globalNavHeight));
-}
-
-.markdown-toc-content h4 {
- margin: 0 var(--gridSize) var(--gridSize) var(--gridSize);
- font-size: var(--mediumFontSize);
-}
-
-.markdown-toc-content a {
- display: block;
- color: var(--baseFontColor);
- padding: calc(var(--gridSize) / 2) var(--gridSize);
- border: 1px solid white;
- line-height: 1.2;
- transition: none;
-}
-
-.markdown-toc a:hover {
- border-color: var(--blue);
-}
-
-.markdown-toc a.active {
- font-weight: bold;
-}
diff --git a/server/sonar-web/src/main/js/apps/documentation/utils.ts b/server/sonar-web/src/main/js/apps/documentation/utils.ts
deleted file mode 100644
index a6d8e2d9fc8..00000000000
--- a/server/sonar-web/src/main/js/apps/documentation/utils.ts
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { sortBy } from 'lodash';
-
-export type DocumentationEntryScope = 'sonarqube' | 'sonarcloud' | 'static';
-
-export interface DocumentationEntry {
- content: string;
- relativeName: string;
- navTitle: string | undefined;
- text: string;
- title: string;
- url: string;
-}
-
-export function getNodeFromUrl(pages: DocumentationEntry[], url: string) {
- return pages.find(p => p.url === url);
-}
-
-const WORDS = 6;
-
-function cutLeadingWords(str: string) {
- let words = 0;
- for (let i = str.length - 1; i >= 0; i--) {
- if (/\s/.test(str[i])) {
- words++;
- }
- if (words === WORDS) {
- return i > 0 ? `...${str.substring(i + 1)}` : str;
- }
- }
- return str;
-}
-
-function cutTrailingWords(str: string) {
- let words = 0;
- for (let i = 0; i < str.length; i++) {
- if (/\s/.test(str[i])) {
- words++;
- }
- if (words === WORDS) {
- return i < str.length - 1 ? `${str.substring(0, i)}...` : str;
- }
- }
- return str;
-}
-
-export function cutWords(tokens: Array<{ text: string; marked: boolean }>) {
- const result: Array<{ text: string; marked: boolean }> = [];
- let length = 0;
-
- const highlightPos = tokens.findIndex(token => token.marked);
- if (highlightPos > 0) {
- const text = cutLeadingWords(tokens[highlightPos - 1].text);
- result.push({ text, marked: false });
- length += text.length;
- }
-
- result.push(tokens[highlightPos]);
- length += tokens[highlightPos].text.length;
-
- for (let i = highlightPos + 1; i < tokens.length; i++) {
- if (length + tokens[i].text.length > 100) {
- const text = cutTrailingWords(tokens[i].text);
- result.push({ text, marked: false });
- return result;
- } else {
- result.push(tokens[i]);
- length += tokens[i].text.length;
- }
- }
-
- return result;
-}
-
-export function highlightMarks(str: string, marks: Array<{ from: number; to: number }>) {
- const sortedMarks = sortBy(
- [
- ...marks.map(mark => ({ pos: mark.from, start: true })),
- ...marks.map(mark => ({ pos: mark.to, start: false }))
- ],
- mark => mark.pos,
- mark => Number(!mark.start)
- );
-
- const cuts: Array<{ text: string; marked: boolean }> = [];
- let start = 0;
- let balance = 0;
-
- for (const mark of sortedMarks) {
- if (mark.start) {
- if (balance === 0 && start !== mark.pos) {
- cuts.push({ text: str.substring(start, mark.pos), marked: false });
- start = mark.pos;
- }
- balance++;
- } else {
- balance--;
- if (balance === 0 && start !== mark.pos) {
- cuts.push({ text: str.substring(start, mark.pos), marked: true });
- start = mark.pos;
- }
- }
- }
-
- if (start < str.length - 1) {
- cuts.push({ text: str.substr(start), marked: false });
- }
-
- return cuts;
-}
diff --git a/server/sonar-web/src/main/js/apps/marketplace/App.tsx b/server/sonar-web/src/main/js/apps/marketplace/App.tsx
index 60d03b5b190..ece024efdae 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/App.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/App.tsx
@@ -28,7 +28,7 @@ import {
getPluginUpdates
} from '../../api/plugins';
import { getValue, setSimpleSettingValue } from '../../api/settings';
-import Link from '../../components/common/Link';
+import DocLink from '../../components/common/DocLink';
import Suggestions from '../../components/embed-docs-modal/Suggestions';
import { Location, Router, withRouter } from '../../components/hoc/withRouter';
import { Alert } from '../../components/ui/Alert';
@@ -172,11 +172,9 @@ export class App extends React.PureComponent<Props, State> {
defaultMessage={translate('marketplace.page.plugins.description2')}
values={{
link: (
- <Link
- to="/documentation/instance-administration/marketplace/"
- target="_blank">
+ <DocLink to="/instance-administration/marketplace/">
{translate('marketplace.page.plugins.description2.link')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/App-test.tsx.snap
index dfe9f4507b0..95315b39ff7 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/App-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/App-test.tsx.snap
@@ -43,12 +43,11 @@ exports[`should render correctly: loaded 1`] = `
id="marketplace.page.plugins.description2"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/instance-administration/marketplace/"
+ "link": <withAppStateContext(DocLink)
+ to="/instance-administration/marketplace/"
>
marketplace.page.plugins.description2.link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
@@ -141,12 +140,11 @@ exports[`should render correctly: loading 1`] = `
id="marketplace.page.plugins.description2"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/instance-administration/marketplace/"
+ "link": <withAppStateContext(DocLink)
+ to="/instance-administration/marketplace/"
>
marketplace.page.plugins.description2.link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/EditionBox.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/EditionBox.tsx
index ab37b6e8f59..20f2890ec2e 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/EditionBox.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/EditionBox.tsx
@@ -17,11 +17,8 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import tooltipDCE from 'Docs/tooltips/editions/datacenter.md';
-import tooltipDE from 'Docs/tooltips/editions/developer.md';
-import tooltipEE from 'Docs/tooltips/editions/enterprise.md';
import * as React from 'react';
-import DocMarkdownBlock from '../../../components/docs/DocMarkdownBlock';
+import Link from '../../../components/common/Link';
import { getEditionUrl } from '../../../helpers/editions';
import { translate } from '../../../helpers/l10n';
import { Edition, EditionKey } from '../../../types/editions';
@@ -36,16 +33,116 @@ interface Props {
export default function EditionBox({ edition, ncloc, serverId, currentEdition }: Props) {
return (
<div className="boxed-group boxed-group-inner marketplace-edition">
- {edition.key === 'datacenter' && <DocMarkdownBlock content={tooltipDCE} />}
- {edition.key === 'developer' && <DocMarkdownBlock content={tooltipDE} />}
- {edition.key === 'enterprise' && <DocMarkdownBlock content={tooltipEE} />}
+ {edition.key === EditionKey.datacenter && (
+ <div className="markdown">
+ <div className="markdown-content">
+ <div>
+ <h3 id="data-center-edition">
+ <img
+ alt="SonarQube logo"
+ className="max-width-100 little-spacer-right"
+ src="/images/embed-doc/sq-icon.svg"
+ />
+ Data Center Edition
+ </h3>
+ <p>
+ <em>Designed for High Availability and Scalability</em>
+ </p>
+ <p>Enterprise Edition functionality plus:</p>
+ <ul>
+ <li>Component redundancy</li>
+ <li>Data resiliency</li>
+ <li>Horizontal scalability</li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ )}
+ {edition.key === EditionKey.developer && (
+ <div className="markdown">
+ <div className="markdown-content">
+ <div>
+ <h3 id="developer-edition">
+ <img
+ alt="SonarQube logo"
+ className="max-width-100 little-spacer-right"
+ src="/images/embed-doc/sq-icon.svg"
+ />
+ Developer Edition
+ </h3>
+ <p>
+ <em>Built for Developers by Developers</em>
+ </p>
+ <p>Community Edition functionality plus:</p>
+ <ul>
+ <li>
+ PR / MR decoration &amp; Quality Gate
+ <img
+ alt="GitHub"
+ className="little-spacer-left max-width-100"
+ src="/images/alm/github.svg"
+ />
+ <img
+ alt="GitLab"
+ className="little-spacer-left max-width-100"
+ src="/images/alm/gitlab.svg"
+ />
+ <img
+ alt="Azure DevOps"
+ className="little-spacer-left max-width-100"
+ src="/images/alm/azure.svg"
+ />
+ <img
+ alt="Bitbucket"
+ className="little-spacer-left max-width-100"
+ src="/images/alm/bitbucket.svg"
+ />
+ </li>
+ <li>
+ Taint analysis / Injection flaw detection for Java, C#, PHP, Python, JS &amp; TS
+ </li>
+ <li>Branch analysis</li>
+ <li>Project aggregation</li>
+ <li>Additional languages: C, C++, Obj-C, PS/SQL, ABAP, TSQL &amp; Swift</li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ )}
+ {edition.key === EditionKey.enterprise && (
+ <div className="markdown">
+ <div className="markdown-content">
+ <div>
+ <h3 id="enterprise-edition">
+ <img
+ alt="SonarQube logo"
+ className="max-width-100 little-spacer-right"
+ src="/images/embed-doc/sq-icon.svg"
+ />{' '}
+ Enterprise Edition
+ </h3>
+ <p>
+ <em>Designed to Meet Enterprise Requirements</em>
+ </p>
+ <p>Developer Edition functionality plus:</p>
+ <ul>
+ <li>Faster analysis with parallel processing</li>
+ <li>OWASP/CWE security reports</li>
+ <li>Portfolio management</li>
+ <li>Executive reporting</li>
+ <li>Project transfer</li>
+ <li>Additional languages: Apex, COBOL, PL/I, RPG &amp; VB6</li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ )}
<div className="marketplace-edition-action spacer-top">
- <a
- href={getEditionUrl(edition, { ncloc, serverId, sourceEdition: currentEdition })}
- rel="noopener noreferrer"
+ <Link
+ to={getEditionUrl(edition, { ncloc, serverId, sourceEdition: currentEdition })}
target="_blank">
{translate('marketplace.request_free_trial')}
- </a>
+ </Link>
</div>
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/EditionBox-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/EditionBox-test.tsx.snap
index 51c52c7ea2a..544953e04d3 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/EditionBox-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/EditionBox-test.tsx.snap
@@ -4,19 +4,80 @@ exports[`should display the edition 1`] = `
<div
className="boxed-group boxed-group-inner marketplace-edition"
>
- <DocMarkdownBlock
- content="test-file-stub"
- />
+ <div
+ className="markdown"
+ >
+ <div
+ className="markdown-content"
+ >
+ <div>
+ <h3
+ id="developer-edition"
+ >
+ <img
+ alt="SonarQube logo"
+ className="max-width-100 little-spacer-right"
+ src="/images/embed-doc/sq-icon.svg"
+ />
+ Developer Edition
+ </h3>
+ <p>
+ <em>
+ Built for Developers by Developers
+ </em>
+ </p>
+ <p>
+ Community Edition functionality plus:
+ </p>
+ <ul>
+ <li>
+ PR / MR decoration & Quality Gate
+ <img
+ alt="GitHub"
+ className="little-spacer-left max-width-100"
+ src="/images/alm/github.svg"
+ />
+ <img
+ alt="GitLab"
+ className="little-spacer-left max-width-100"
+ src="/images/alm/gitlab.svg"
+ />
+ <img
+ alt="Azure DevOps"
+ className="little-spacer-left max-width-100"
+ src="/images/alm/azure.svg"
+ />
+ <img
+ alt="Bitbucket"
+ className="little-spacer-left max-width-100"
+ src="/images/alm/bitbucket.svg"
+ />
+ </li>
+ <li>
+ Taint analysis / Injection flaw detection for Java, C#, PHP, Python, JS & TS
+ </li>
+ <li>
+ Branch analysis
+ </li>
+ <li>
+ Project aggregation
+ </li>
+ <li>
+ Additional languages: C, C++, Obj-C, PS/SQL, ABAP, TSQL & Swift
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
<div
className="marketplace-edition-action spacer-top"
>
- <a
- href="https://redirect.sonarsource.com/editions/developer.html?ncloc=1000&serverId=serverId&sourceEdition=community"
- rel="noopener noreferrer"
+ <ForwardRef(Link)
target="_blank"
+ to="https://redirect.sonarsource.com/editions/developer.html?ncloc=1000&serverId=serverId&sourceEdition=community"
>
marketplace.request_free_trial
- </a>
+ </ForwardRef(Link)>
</div>
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelNoNewCode.tsx b/server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelNoNewCode.tsx
index b377671d51f..15cdb87860c 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelNoNewCode.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelNoNewCode.tsx
@@ -19,6 +19,7 @@
*/
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
+import DocLink from '../../../components/common/DocLink';
import Link from '../../../components/common/Link';
import { getBranchLikeQuery } from '../../../helpers/branch-like';
import { translate } from '../../../helpers/l10n';
@@ -94,9 +95,7 @@ export default function MeasuresPanelNoNewCode(props: MeasuresPanelNoNewCodeProp
id="overview.measures.empty_link"
values={{
learn_more_link: (
- <Link to="/documentation/user-guide/clean-as-you-code/">
- {translate('learn_more')}
- </Link>
+ <DocLink to="/user-guide/clean-as-you-code/">{translate('learn_more')}</DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/MeasuresPanelNoNewCode-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/MeasuresPanelNoNewCode-test.tsx
index 76e9ea22aa1..49def02a09b 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/MeasuresPanelNoNewCode-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/MeasuresPanelNoNewCode-test.tsx
@@ -60,11 +60,11 @@ it('should render the default message', () => {
id="overview.measures.empty_link"
values={
Object {
- "learn_more_link": <ForwardRef(Link)
- to="/documentation/user-guide/clean-as-you-code/"
+ "learn_more_link": <withAppStateContext(DocLink)
+ to="/user-guide/clean-as-you-code/"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanelNoNewCode-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanelNoNewCode-test.tsx.snap
index 7929a930024..7bfe4d72fb9 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanelNoNewCode-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanelNoNewCode-test.tsx.snap
@@ -34,11 +34,11 @@ exports[`should render "bad code setting" explanation: no link 1`] = `
id="overview.measures.empty_link"
values={
Object {
- "learn_more_link": <ForwardRef(Link)
- to="/documentation/user-guide/clean-as-you-code/"
+ "learn_more_link": <withAppStateContext(DocLink)
+ to="/user-guide/clean-as-you-code/"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
@@ -81,11 +81,11 @@ exports[`should render "bad code setting" explanation: with link 1`] = `
id="overview.measures.empty_link"
values={
Object {
- "learn_more_link": <ForwardRef(Link)
- to="/documentation/user-guide/clean-as-you-code/"
+ "learn_more_link": <withAppStateContext(DocLink)
+ to="/user-guide/clean-as-you-code/"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
@@ -160,11 +160,11 @@ exports[`should render the default message 6`] = `
id="overview.measures.empty_link"
values={
Object {
- "learn_more_link": <ForwardRef(Link)
- to="/documentation/user-guide/clean-as-you-code/"
+ "learn_more_link": <withAppStateContext(DocLink)
+ to="/user-guide/clean-as-you-code/"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/AppHeader.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/AppHeader.tsx
index 634306b49fb..b1ca7a8665b 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/AppHeader.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/AppHeader.tsx
@@ -19,6 +19,7 @@
*/
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
+import DocLink from '../../../components/common/DocLink';
import Link from '../../../components/common/Link';
import { translate } from '../../../helpers/l10n';
@@ -38,9 +39,9 @@ export default function AppHeader(props: AppHeaderProps) {
id="project_baseline.page.description"
values={{
link: (
- <Link to="/documentation/project-administration/new-code-period/">
+ <DocLink to="/project-administration/new-code-period/">
{translate('project_baseline.page.description.link')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/__snapshots__/AppHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/__snapshots__/AppHeader-test.tsx.snap
index 8ff79641274..b9d9688d93d 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/__snapshots__/AppHeader-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/__tests__/__snapshots__/AppHeader-test.tsx.snap
@@ -17,11 +17,11 @@ exports[`should render correctly: can admin 1`] = `
id="project_baseline.page.description"
values={
Object {
- "link": <ForwardRef(Link)
- to="/documentation/project-administration/new-code-period/"
+ "link": <withAppStateContext(DocLink)
+ to="/project-administration/new-code-period/"
>
project_baseline.page.description.link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
@@ -60,11 +60,11 @@ exports[`should render correctly: cannot admin 1`] = `
id="project_baseline.page.description"
values={
Object {
- "link": <ForwardRef(Link)
- to="/documentation/project-administration/new-code-period/"
+ "link": <withAppStateContext(DocLink)
+ to="/project-administration/new-code-period/"
>
project_baseline.page.description.link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx
index 1df8b307482..4a09610dcbd 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx
@@ -184,7 +184,7 @@ export class Conditions extends React.PureComponent<Props> {
content={translate('quality_gates.conditions.help')}
links={[
{
- href: '/documentation/user-guide/clean-as-you-code/',
+ href: '/user-guide/clean-as-you-code/',
label: translate('quality_gates.conditions.help.link')
}
]}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx
index d0a3a4cd550..8704f5bdaad 100644
--- a/server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx
@@ -54,7 +54,7 @@ export default function ListHeader({ canCreate, refreshQualityGates }: Props) {
content={translate('quality_gates.help')}
links={[
{
- href: '/documentation/user-guide/quality-gates/',
+ href: '/user-guide/quality-gates/',
label: translate('learn_more')
}
]}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx
index 0280b5b11d2..d9811232f4c 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import { Actions } from '../../../api/quality-profiles';
-import Link from '../../../components/common/Link';
+import DocLink from '../../../components/common/DocLink';
import { Button } from '../../../components/controls/buttons';
import { Location, Router, withRouter } from '../../../components/hoc/withRouter';
import { Alert } from '../../../components/ui/Alert';
@@ -106,14 +106,9 @@ export class PageHeader extends React.PureComponent<Props, State> {
{translate('quality_profiles.intro1')}
<br />
{translate('quality_profiles.intro2')}
- <Link
- className="spacer-left"
- target="_blank"
- to={{
- pathname: '/documentation/instance-administration/quality-profiles/'
- }}>
+ <DocLink className="spacer-left" to="/instance-administration/quality-profiles/">
{translate('learn_more')}
- </Link>
+ </DocLink>
</div>
{this.state.restoreFormOpen && (
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/PageHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/PageHeader-test.tsx.snap
index b56ff86f837..3b2de8d69bd 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/PageHeader-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/PageHeader-test.tsx.snap
@@ -15,17 +15,12 @@ exports[`should render correctly 1`] = `
quality_profiles.intro1
<br />
quality_profiles.intro2
- <ForwardRef(Link)
+ <withAppStateContext(DocLink)
className="spacer-left"
- target="_blank"
- to={
- Object {
- "pathname": "/documentation/instance-administration/quality-profiles/",
- }
- }
+ to="/instance-administration/quality-profiles/"
>
learn_more
- </ForwardRef(Link)>
+ </withAppStateContext(DocLink)>
</div>
</header>
`;
@@ -63,17 +58,12 @@ exports[`should render correctly 2`] = `
quality_profiles.intro1
<br />
quality_profiles.intro2
- <ForwardRef(Link)
+ <withAppStateContext(DocLink)
className="spacer-left"
- target="_blank"
- to={
- Object {
- "pathname": "/documentation/instance-administration/quality-profiles/",
- }
- }
+ to="/instance-administration/quality-profiles/"
>
learn_more
- </ForwardRef(Link)>
+ </withAppStateContext(DocLink)>
</div>
</header>
`;
@@ -117,17 +107,12 @@ exports[`should render correctly 3`] = `
quality_profiles.intro1
<br />
quality_profiles.intro2
- <ForwardRef(Link)
+ <withAppStateContext(DocLink)
className="spacer-left"
- target="_blank"
- to={
- Object {
- "pathname": "/documentation/instance-administration/quality-profiles/",
- }
- }
+ to="/instance-administration/quality-profiles/"
>
learn_more
- </ForwardRef(Link)>
+ </withAppStateContext(DocLink)>
</div>
</header>
`;
@@ -165,17 +150,12 @@ exports[`should show a create form 1`] = `
quality_profiles.intro1
<br />
quality_profiles.intro2
- <ForwardRef(Link)
+ <withAppStateContext(DocLink)
className="spacer-left"
- target="_blank"
- to={
- Object {
- "pathname": "/documentation/instance-administration/quality-profiles/",
- }
- }
+ to="/instance-administration/quality-profiles/"
>
learn_more
- </ForwardRef(Link)>
+ </withAppStateContext(DocLink)>
</div>
<CreateProfileForm
languages={
@@ -253,17 +233,12 @@ exports[`should show a restore form 1`] = `
quality_profiles.intro1
<br />
quality_profiles.intro2
- <ForwardRef(Link)
+ <withAppStateContext(DocLink)
className="spacer-left"
- target="_blank"
- to={
- Object {
- "pathname": "/documentation/instance-administration/quality-profiles/",
- }
- }
+ to="/instance-administration/quality-profiles/"
>
learn_more
- </ForwardRef(Link)>
+ </withAppStateContext(DocLink)>
</div>
<RestoreProfileForm
onClose={[Function]}
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/EmptyHotspotsPage.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/EmptyHotspotsPage.tsx
index 05096cc74a4..89599d1fe80 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/EmptyHotspotsPage.tsx
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/EmptyHotspotsPage.tsx
@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import Link from '../../../components/common/Link';
+import DocLink from '../../../components/common/DocLink';
import { translate } from '../../../helpers/l10n';
import { getBaseUrl } from '../../../helpers/system';
@@ -57,12 +57,9 @@ export default function EmptyHotspotsPage(props: EmptyHotspotsPageProps) {
{translate(`hotspots.${translationRoot}.description`)}
</div>
{!(filtered || isStaticListOfHotspots) && (
- <Link
- className="big-spacer-top"
- target="_blank"
- to={{ pathname: '/documentation/user-guide/security-hotspots/' }}>
+ <DocLink className="big-spacer-top" to="/user-guide/security-hotspots/">
{translate('hotspots.learn_more')}
- </Link>
+ </DocLink>
)}
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/EmptyHotspotsPage-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/EmptyHotspotsPage-test.tsx.snap
index 440d4a6e8ae..0a01522c9a7 100644
--- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/EmptyHotspotsPage-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/EmptyHotspotsPage-test.tsx.snap
@@ -20,17 +20,12 @@ exports[`should render correctly 1`] = `
>
hotspots.no_hotspots.description
</div>
- <ForwardRef(Link)
+ <withAppStateContext(DocLink)
className="big-spacer-top"
- target="_blank"
- to={
- Object {
- "pathname": "/documentation/user-guide/security-hotspots/",
- }
- }
+ to="/user-guide/security-hotspots/"
>
hotspots.learn_more
- </ForwardRef(Link)>
+ </withAppStateContext(DocLink)>
</div>
`;
@@ -54,17 +49,12 @@ exports[`should render correctly: file 1`] = `
>
hotspots.no_hotspots_for_file.description
</div>
- <ForwardRef(Link)
+ <withAppStateContext(DocLink)
className="big-spacer-top"
- target="_blank"
- to={
- Object {
- "pathname": "/documentation/user-guide/security-hotspots/",
- }
- }
+ to="/user-guide/security-hotspots/"
>
hotspots.learn_more
- </ForwardRef(Link)>
+ </withAppStateContext(DocLink)>
</div>
`;
diff --git a/server/sonar-web/src/main/js/apps/settings/components/AnalysisScope.tsx b/server/sonar-web/src/main/js/apps/settings/components/AnalysisScope.tsx
index 0421c0a8528..78b71f912cd 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/AnalysisScope.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/AnalysisScope.tsx
@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import Link from '../../../components/common/Link';
+import DocLink from '../../../components/common/DocLink';
import { translate } from '../../../helpers/l10n';
import { AdditionalCategoryComponentProps } from './AdditionalCategories';
import CategoryDefinitionsList from './CategoryDefinitionsList';
@@ -30,11 +30,9 @@ export function AnalysisScope(props: AdditionalCategoryComponentProps) {
<>
<p className="spacer-bottom">
{translate('settings.analysis_scope.wildcards.introduction')}
- <Link
- className="spacer-left"
- to="/documentation/project-administration/narrowing-the-focus/">
+ <DocLink className="spacer-left" to="/project-administration/narrowing-the-focus/">
{translate('learn_more')}
- </Link>
+ </DocLink>
</p>
<table className="data spacer-bottom">
diff --git a/server/sonar-web/src/main/js/apps/settings/components/NewCodePeriod.tsx b/server/sonar-web/src/main/js/apps/settings/components/NewCodePeriod.tsx
index 1fc628761ea..c0cb640c133 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/NewCodePeriod.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/NewCodePeriod.tsx
@@ -20,7 +20,7 @@
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { getNewCodePeriod, setNewCodePeriod } from '../../../api/newCodePeriod';
-import Link from '../../../components/common/Link';
+import DocLink from '../../../components/common/DocLink';
import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
import AlertSuccessIcon from '../../../components/icons/AlertSuccessIcon';
import DeferredSpinner from '../../../components/ui/DeferredSpinner';
@@ -160,9 +160,9 @@ export default class NewCodePeriod extends React.PureComponent<{}, State> {
id="settings.new_code_period.description"
values={{
link: (
- <Link to="/documentation/project-administration/new-code-period/">
+ <DocLink to="/project-administration/new-code-period/">
{translate('learn_more')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AnalysisScope-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AnalysisScope-test.tsx.snap
index 8f3c70f5740..0b50c3ff5b8 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AnalysisScope-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AnalysisScope-test.tsx.snap
@@ -6,12 +6,12 @@ exports[`should render correctly 1`] = `
className="spacer-bottom"
>
settings.analysis_scope.wildcards.introduction
- <ForwardRef(Link)
+ <withAppStateContext(DocLink)
className="spacer-left"
- to="/documentation/project-administration/narrowing-the-focus/"
+ to="/project-administration/narrowing-the-focus/"
>
learn_more
- </ForwardRef(Link)>
+ </withAppStateContext(DocLink)>
</p>
<table
className="data spacer-bottom"
diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/NewCodePeriod-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/NewCodePeriod-test.tsx.snap
index 80f68b5aa3e..d51fc151cfd 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/NewCodePeriod-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/NewCodePeriod-test.tsx.snap
@@ -29,11 +29,11 @@ exports[`should render correctly 1`] = `
id="settings.new_code_period.description"
values={
Object {
- "link": <ForwardRef(Link)
- to="/documentation/project-administration/new-code-period/"
+ "link": <withAppStateContext(DocLink)
+ to="/project-administration/new-code-period/"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx
index e13e9a0a946..0924eedf763 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
-import Link from '../../../../components/common/Link';
+import DocLink from '../../../../components/common/DocLink';
import { Button } from '../../../../components/controls/buttons';
import HelpTooltip from '../../../../components/controls/HelpTooltip';
import Tooltip from '../../../../components/controls/Tooltip';
@@ -230,9 +230,9 @@ export default function AlmBindingDefinitionBox(props: AlmBindingDefinitionBoxPr
)}
values={{
link: (
- <Link target="_blank" to={ALM_DOCUMENTATION_PATHS[AlmKeys.GitHub]}>
+ <DocLink to={ALM_DOCUMENTATION_PATHS[AlmKeys.GitHub]}>
{translate('learn_more')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormField.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormField.tsx
index be83d609cbe..9ebfd7a8d53 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormField.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormField.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
-import Link from '../../../../components/common/Link';
+import DocLink from '../../../../components/common/DocLink';
import { ButtonLink } from '../../../../components/controls/buttons';
import ValidationInput, {
ValidationInputErrorPlacement
@@ -127,14 +127,9 @@ export function AlmBindingDefinitionFormField<B extends AlmBindingDefinitionBase
defaultMessage={translate('settings.almintegration.form.secret.can_encrypt')}
values={{
learn_more: (
- <Link
- target="_blank"
- to={{
- pathname:
- '/documentation/instance-administration/security/#settings-encryption'
- }}>
+ <DocLink to="/instance-administration/security/#settings-encryption">
{translate('learn_more')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AzureForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AzureForm.tsx
index 8cee4e30d84..3b454eb03fe 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AzureForm.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AzureForm.tsx
@@ -19,6 +19,7 @@
*/
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
+import DocLink from '../../../../components/common/DocLink';
import Link from '../../../../components/common/Link';
import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
import { translate } from '../../../../helpers/l10n';
@@ -80,9 +81,9 @@ export default function AzureForm(props: AzureFormProps) {
),
permission: <strong>{'Code > Read & Write'}</strong>,
doc_link: (
- <Link target="_blank" to={ALM_DOCUMENTATION_PATHS[AlmKeys.Azure]}>
+ <DocLink to={ALM_DOCUMENTATION_PATHS[AlmKeys.Azure]}>
{translate('learn_more')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketCloudForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketCloudForm.tsx
index 075775bc4c0..449ecdf5b17 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketCloudForm.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketCloudForm.tsx
@@ -19,6 +19,7 @@
*/
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
+import DocLink from '../../../../components/common/DocLink';
import Link from '../../../../components/common/Link';
import { Alert } from '../../../../components/ui/Alert';
import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
@@ -91,9 +92,9 @@ export default function BitbucketCloudForm(props: BitbucketCloudFormProps) {
),
permission: <strong>Pull Requests: Read</strong>,
doc_link: (
- <Link target="_blank" to={ALM_DOCUMENTATION_PATHS[AlmKeys.BitbucketCloud]}>
+ <DocLink to={ALM_DOCUMENTATION_PATHS[AlmKeys.BitbucketCloud]}>
{translate('learn_more')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketServerForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketServerForm.tsx
index 2920a0d03d6..3b60f43a85c 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketServerForm.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketServerForm.tsx
@@ -19,6 +19,7 @@
*/
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
+import DocLink from '../../../../components/common/DocLink';
import Link from '../../../../components/common/Link';
import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
import { translate } from '../../../../helpers/l10n';
@@ -78,9 +79,9 @@ export default function BitbucketServerForm(props: BitbucketServerFormProps) {
),
permission: <strong>Read</strong>,
doc_link: (
- <Link target="_blank" to={ALM_DOCUMENTATION_PATHS[AlmKeys.BitbucketServer]}>
+ <DocLink to={ALM_DOCUMENTATION_PATHS[AlmKeys.BitbucketServer]}>
{translate('learn_more')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx
index 80709f0a8cb..cda048ea286 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
-import Link from '../../../../components/common/Link';
+import DocLink from '../../../../components/common/DocLink';
import { Alert } from '../../../../components/ui/Alert';
import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
import { translate } from '../../../../helpers/l10n';
@@ -70,9 +70,9 @@ export default function GithubForm(props: GithubFormProps) {
id="settings.almintegration.github.info"
values={{
link: (
- <Link target="_blank" to={ALM_DOCUMENTATION_PATHS[AlmKeys.GitHub]}>
+ <DocLink to={ALM_DOCUMENTATION_PATHS[AlmKeys.GitHub]}>
{translate('learn_more')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabForm.tsx
index e0e8f4b5b11..58686ea35a8 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabForm.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabForm.tsx
@@ -19,6 +19,7 @@
*/
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
+import DocLink from '../../../../components/common/DocLink';
import Link from '../../../../components/common/Link';
import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
import { translate } from '../../../../helpers/l10n';
@@ -76,9 +77,9 @@ export default function GitlabForm(props: GitlabFormProps) {
permission: <strong>Reporter</strong>,
scope: <strong>api</strong>,
doc_link: (
- <Link target="_blank" to={ALM_DOCUMENTATION_PATHS[AlmKeys.GitLab]}>
+ <DocLink to={ALM_DOCUMENTATION_PATHS[AlmKeys.GitLab]}>
{translate('learn_more')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionBox-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionBox-test.tsx.snap
index 188b67245c7..4afcf1ec133 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionBox-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionBox-test.tsx.snap
@@ -522,12 +522,11 @@ exports[`should render correctly: success with alert 1`] = `
id="settings.almintegration.github.additional_permission"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/github-integration/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/github-integration/"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
@@ -649,12 +648,11 @@ exports[`should render correctly: success with branches disabled 1`] = `
id="settings.almintegration.github.additional_permission"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/github-integration/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/github-integration/"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormField-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormField-test.tsx.snap
index 8928255a0de..f878e875d5e 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormField-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionFormField-test.tsx.snap
@@ -81,16 +81,11 @@ exports[`should render correctly: encryptable 1`] = `
id="settings.almintegration.form.secret.can_encrypt"
values={
Object {
- "learn_more": <ForwardRef(Link)
- target="_blank"
- to={
- Object {
- "pathname": "/documentation/instance-administration/security/#settings-encryption",
- }
- }
+ "learn_more": <withAppStateContext(DocLink)
+ to="/instance-administration/security/#settings-encryption"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AzureForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AzureForm-test.tsx.snap
index fb5e0271cef..e7e4fed3d74 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AzureForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AzureForm-test.tsx.snap
@@ -41,12 +41,11 @@ exports[`should render correctly: create 1`] = `
id="settings.almintegration.form.personal_access_token.azure.help"
values={
Object {
- "doc_link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/azuredevops-integration/"
+ "doc_link": <withAppStateContext(DocLink)
+ to="/analysis/azuredevops-integration/"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
"pat": <ForwardRef(Link)
target="_blank"
to="https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate"
@@ -113,12 +112,11 @@ exports[`should render correctly: edit 1`] = `
id="settings.almintegration.form.personal_access_token.azure.help"
values={
Object {
- "doc_link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/azuredevops-integration/"
+ "doc_link": <withAppStateContext(DocLink)
+ to="/analysis/azuredevops-integration/"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
"pat": <ForwardRef(Link)
target="_blank"
to="https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate"
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketCloudForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketCloudForm-test.tsx.snap
index 62a4d83d38f..23f4867930a 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketCloudForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketCloudForm-test.tsx.snap
@@ -45,12 +45,11 @@ exports[`should render correctly: default 1`] = `
id="settings.almintegration.bitbucketcloud.info"
values={
Object {
- "doc_link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/bitbucket-cloud-integration/"
+ "doc_link": <withAppStateContext(DocLink)
+ to="/analysis/bitbucket-cloud-integration/"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
"oauth": <ForwardRef(Link)
target="_blank"
to="https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/"
@@ -131,12 +130,11 @@ exports[`should render correctly: invalid workspace ID 1`] = `
id="settings.almintegration.bitbucketcloud.info"
values={
Object {
- "doc_link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/bitbucket-cloud-integration/"
+ "doc_link": <withAppStateContext(DocLink)
+ to="/analysis/bitbucket-cloud-integration/"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
"oauth": <ForwardRef(Link)
target="_blank"
to="https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/"
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketServerForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketServerForm-test.tsx.snap
index f428bc72620..f580668efb4 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketServerForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/BitbucketServerForm-test.tsx.snap
@@ -36,12 +36,11 @@ exports[`should render correctly 1`] = `
id="settings.almintegration.form.personal_access_token.bitbucket.help"
values={
Object {
- "doc_link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/bitbucket-integration/"
+ "doc_link": <withAppStateContext(DocLink)
+ to="/analysis/bitbucket-integration/"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
"pat": <ForwardRef(Link)
target="_blank"
to="https://confluence.atlassian.com/bitbucketserver0515/personal-access-tokens-961275199.html"
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubForm-test.tsx.snap
index d6125804a6f..71a84ff7946 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GithubForm-test.tsx.snap
@@ -43,12 +43,11 @@ exports[`should render correctly 1`] = `
id="settings.almintegration.github.info"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/github-integration/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/github-integration/"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
@@ -147,12 +146,11 @@ exports[`should render correctly 2`] = `
id="settings.almintegration.github.info"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/github-integration/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/github-integration/"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabForm-test.tsx.snap
index 3b034da6c5a..7af8b68c428 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/GitlabForm-test.tsx.snap
@@ -34,12 +34,11 @@ exports[`should render correctly 1`] = `
id="settings.almintegration.form.personal_access_token.gitlab.help"
values={
Object {
- "doc_link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/gitlab-integration/"
+ "doc_link": <withAppStateContext(DocLink)
+ to="/analysis/gitlab-integration/"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
"pat": <ForwardRef(Link)
target="_blank"
to="https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html"
@@ -102,12 +101,11 @@ exports[`should render correctly 2`] = `
id="settings.almintegration.form.personal_access_token.gitlab.help"
values={
Object {
- "doc_link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/gitlab-integration/"
+ "doc_link": <withAppStateContext(DocLink)
+ to="/analysis/gitlab-integration/"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
"pat": <ForwardRef(Link)
target="_blank"
to="https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html"
diff --git a/server/sonar-web/src/main/js/apps/settings/components/authentication/Authentication.tsx b/server/sonar-web/src/main/js/apps/settings/components/authentication/Authentication.tsx
index d8ce34a0b2d..4653c2a69fb 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/authentication/Authentication.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/authentication/Authentication.tsx
@@ -20,7 +20,7 @@
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { useSearchParams } from 'react-router-dom';
-import Link from '../../../../components/common/Link';
+import DocLink from '../../../../components/common/DocLink';
import ScreenPositionHelper from '../../../../components/common/ScreenPositionHelper';
import BoxedTabs, { getTabId, getTabPanelId } from '../../../../components/controls/BoxedTabs';
import { Alert } from '../../../../components/ui/Alert';
@@ -142,12 +142,10 @@ export default function Authentication(props: Props) {
defaultMessage={translate('settings.authentication.help')}
values={{
link: (
- <Link
- to={`/documentation/instance-administration/authentication/${DOCUMENTATION_LINK_SUFFIXES[currentTab]}/`}
- rel="noopener noreferrer"
- target="_blank">
+ <DocLink
+ to={`/instance-administration/authentication/${DOCUMENTATION_LINK_SUFFIXES[currentTab]}/`}>
{translate('settings.authentication.help.link')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/AlmSpecificForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/AlmSpecificForm.tsx
index ad01fa26e18..5544186be4c 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/AlmSpecificForm.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/AlmSpecificForm.tsx
@@ -22,7 +22,7 @@ import { FormattedMessage } from 'react-intl';
import withAvailableFeatures, {
WithAvailableFeaturesProps
} from '../../../../app/components/available-features/withAvailableFeatures';
-import Link from '../../../../components/common/Link';
+import DocLink from '../../../../components/common/DocLink';
import Toggle from '../../../../components/controls/Toggle';
import { Alert } from '../../../../components/ui/Alert';
import MandatoryFieldMarker from '../../../../components/ui/MandatoryFieldMarker';
@@ -286,11 +286,7 @@ export function AlmSpecificForm(props: AlmSpecificFormProps) {
renderBooleanField({
help: true,
helpParams: {
- doc_link: (
- <Link to={ALM_DOCUMENTATION_PATHS[alm]} target="_blank">
- {translate('learn_more')}
- </Link>
- )
+ doc_link: <DocLink to={ALM_DOCUMENTATION_PATHS[alm]}>{translate('learn_more')}</DocLink>
},
id: 'monorepo',
onFieldChange: props.onFieldChange,
diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/AlmSpecificForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/AlmSpecificForm-test.tsx.snap
index b7413c7b625..26c43916050 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/AlmSpecificForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/__snapshots__/AlmSpecificForm-test.tsx.snap
@@ -802,12 +802,11 @@ exports[`should render the monorepo field when the feature is supported 1`] = `
id="settings.pr_decoration.binding.form.monorepo.help"
values={
Object {
- "doc_link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/azuredevops-integration/"
+ "doc_link": <withAppStateContext(DocLink)
+ to="/analysis/azuredevops-integration/"
>
learn_more
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/encryption/EncryptionForm.tsx b/server/sonar-web/src/main/js/apps/settings/encryption/EncryptionForm.tsx
index af24bb91804..5307a9bd840 100644
--- a/server/sonar-web/src/main/js/apps/settings/encryption/EncryptionForm.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/encryption/EncryptionForm.tsx
@@ -20,7 +20,7 @@
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { encryptValue } from '../../../api/settings';
-import Link from '../../../components/common/Link';
+import DocLink from '../../../components/common/DocLink';
import { SubmitButton } from '../../../components/controls/buttons';
import { ClipboardButton } from '../../../components/controls/clipboard';
import DeferredSpinner from '../../../components/ui/DeferredSpinner';
@@ -129,9 +129,9 @@ export default class EncryptionForm extends React.PureComponent<Props, State> {
id="encryption.form_note"
values={{
moreInformationLink: (
- <Link to="/documentation/instance-administration/security/" target="_blank">
+ <DocLink to="/instance-administration/security/">
{translate('more_information')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/encryption/GenerateSecretKeyForm.tsx b/server/sonar-web/src/main/js/apps/settings/encryption/GenerateSecretKeyForm.tsx
index 66c6ecfb3fd..6fc39716548 100644
--- a/server/sonar-web/src/main/js/apps/settings/encryption/GenerateSecretKeyForm.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/encryption/GenerateSecretKeyForm.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
-import Link from '../../../components/common/Link';
+import DocLink from '../../../components/common/DocLink';
import { SubmitButton } from '../../../components/controls/buttons';
import { ClipboardButton } from '../../../components/controls/clipboard';
import DeferredSpinner from '../../../components/ui/DeferredSpinner';
@@ -112,9 +112,9 @@ export default class GenerateSecretKeyForm extends React.PureComponent<Props, St
id="encryption.secret_key_description"
values={{
moreInformationLink: (
- <Link to="/documentation/instance-administration/security/" target="_blank">
+ <DocLink to="/instance-administration/security/">
{translate('more_information')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/encryption/__tests__/__snapshots__/EncryptionForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/encryption/__tests__/__snapshots__/EncryptionForm-test.tsx.snap
index 4f79df0e425..c8771a86fd7 100644
--- a/server/sonar-web/src/main/js/apps/settings/encryption/__tests__/__snapshots__/EncryptionForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/encryption/__tests__/__snapshots__/EncryptionForm-test.tsx.snap
@@ -50,12 +50,11 @@ exports[`should render correctly 1`] = `
id="encryption.form_note"
values={
Object {
- "moreInformationLink": <ForwardRef(Link)
- target="_blank"
- to="/documentation/instance-administration/security/"
+ "moreInformationLink": <withAppStateContext(DocLink)
+ to="/instance-administration/security/"
>
more_information
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/apps/settings/encryption/__tests__/__snapshots__/GenerateSecretKeyForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/encryption/__tests__/__snapshots__/GenerateSecretKeyForm-test.tsx.snap
index 6073e39503a..82f4f112d07 100644
--- a/server/sonar-web/src/main/js/apps/settings/encryption/__tests__/__snapshots__/GenerateSecretKeyForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/encryption/__tests__/__snapshots__/GenerateSecretKeyForm-test.tsx.snap
@@ -16,12 +16,11 @@ exports[`should render correctly 1`] = `
id="encryption.secret_key_description"
values={
Object {
- "moreInformationLink": <ForwardRef(Link)
- target="_blank"
- to="/documentation/instance-administration/security/"
+ "moreInformationLink": <withAppStateContext(DocLink)
+ to="/instance-administration/security/"
>
more_information
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx b/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx
index f0705457e0b..bffd08731c0 100644
--- a/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx
+++ b/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx
@@ -20,6 +20,7 @@
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { deactivateUser } from '../../../api/users';
+import DocLink from '../../../components/common/DocLink';
import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
import Checkbox from '../../../components/controls/Checkbox';
import Modal from '../../../components/controls/Modal';
@@ -99,12 +100,9 @@ export default class DeactivateForm extends React.PureComponent<Props, State> {
id="delete-user-warning"
values={{
link: (
- <a
- href="/documentation/instance-administration/authentication/overview/"
- rel="noopener noreferrer"
- target="_blank">
+ <DocLink to="/instance-administration/authentication/overview/">
{translate('users.delete_user.help.link')}
- </a>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/PageHeader.tsx b/server/sonar-web/src/main/js/apps/webhooks/components/PageHeader.tsx
index e581653e527..19088eb99ea 100644
--- a/server/sonar-web/src/main/js/apps/webhooks/components/PageHeader.tsx
+++ b/server/sonar-web/src/main/js/apps/webhooks/components/PageHeader.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
-import Link from '../../../components/common/Link';
+import DocLink from '../../../components/common/DocLink';
import { translate } from '../../../helpers/l10n';
interface Props {
@@ -41,9 +41,9 @@ export default function PageHeader({ children, loading }: Props) {
id="webhooks.description"
values={{
url: (
- <Link to="/documentation/project-administration/webhooks/">
+ <DocLink to="/project-administration/webhooks/">
{translate('webhooks.documentation_link')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/PageHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/PageHeader-test.tsx.snap
index b1cbc315ff3..d6cdf4408c1 100644
--- a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/PageHeader-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/PageHeader-test.tsx.snap
@@ -21,11 +21,11 @@ exports[`should render correctly 1`] = `
id="webhooks.description"
values={
Object {
- "url": <ForwardRef(Link)
- to="/documentation/project-administration/webhooks/"
+ "url": <withAppStateContext(DocLink)
+ to="/project-administration/webhooks/"
>
webhooks.documentation_link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/components/docs/DocImg.tsx b/server/sonar-web/src/main/js/components/common/DocLink.tsx
index b5cd154b2bf..53d9c8c4e78 100644
--- a/server/sonar-web/src/main/js/components/docs/DocImg.tsx
+++ b/server/sonar-web/src/main/js/components/common/DocLink.tsx
@@ -18,21 +18,18 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { getBaseUrl } from '../../helpers/system';
+import withAppStateContext, {
+ WithAppStateContextProps
+} from '../../app/components/app-state/withAppStateContext';
+import { getUrlForDoc } from '../../helpers/docs';
+import Link, { LinkProps } from './Link';
-export default function DocImg(props: React.ImgHTMLAttributes<HTMLImageElement>) {
- const { alt, src, ...other } = props;
+type Props = WithAppStateContextProps &
+ Omit<LinkProps, 'to'> & { to: string; innerRef?: React.Ref<HTMLAnchorElement> };
- if (process.env.NODE_ENV === 'development') {
- return <img alt={alt} className="max-width-100" src={getBaseUrl() + src} {...other} />;
- }
-
- return (
- <img
- alt={alt}
- className="max-width-100"
- src={getBaseUrl() + '/images/embed-doc' + src}
- {...other}
- />
- );
+export function DocLink({ appState, to, innerRef, ...props }: Props) {
+ const toStatic = getUrlForDoc(appState.version, to);
+ return <Link ref={innerRef} to={toStatic} target="_blank" {...props} />;
}
+
+export default withAppStateContext(DocLink);
diff --git a/server/sonar-web/src/main/js/components/common/DocumentationTooltip.tsx b/server/sonar-web/src/main/js/components/common/DocumentationTooltip.tsx
index 953f5fa6b04..c44ca0efd50 100644
--- a/server/sonar-web/src/main/js/components/common/DocumentationTooltip.tsx
+++ b/server/sonar-web/src/main/js/components/common/DocumentationTooltip.tsx
@@ -19,13 +19,14 @@
*/
import * as React from 'react';
import HelpTooltip from '../../components/controls/HelpTooltip';
+import DocLink from './DocLink';
import Link from './Link';
export interface DocumentationTooltipProps {
children?: React.ReactNode;
className?: string;
content?: React.ReactNode;
- links?: Array<{ href: string; label: string; inPlace?: boolean }>;
+ links?: Array<{ href: string; label: string; inPlace?: boolean; doc?: boolean }>;
title?: string;
}
@@ -49,7 +50,7 @@ export default function DocumentationTooltip(props: DocumentationTooltipProps) {
<>
<hr className="big-spacer-top big-spacer-bottom" />
- {links.map(({ href, label, inPlace }) => (
+ {links.map(({ href, label, inPlace, doc = true }) => (
<div
className="little-spacer-bottom"
key={label}
@@ -58,9 +59,13 @@ export default function DocumentationTooltip(props: DocumentationTooltipProps) {
// they won't be "clickable"), we hide the whole links section.
// See https://sarahmhigley.com/writing/tooltips-in-wcag-21/
aria-hidden={true}>
- <Link to={href} target={inPlace ? undefined : '_blank'}>
- {label}
- </Link>
+ {doc ? (
+ <DocLink to={href}>{label}</DocLink>
+ ) : (
+ <Link to={href} target={inPlace ? undefined : '_blank'}>
+ {label}
+ </Link>
+ )}
</div>
))}
</>
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/DocumentationTooltip-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/DocumentationTooltip-test.tsx
index 16cca514122..67821c47ea9 100644
--- a/server/sonar-web/src/main/js/components/common/__tests__/DocumentationTooltip-test.tsx
+++ b/server/sonar-web/src/main/js/components/common/__tests__/DocumentationTooltip-test.tsx
@@ -27,8 +27,8 @@ it('renders correctly', () => {
shallowRender({
links: [
{ href: 'http://link.tosome.place', label: 'external link' },
- { href: '/documentation/guide', label: 'internal link' },
- { href: '/projects', label: 'in place', inPlace: true }
+ { href: '/guide', label: 'internal link' },
+ { href: '/projects', label: 'in place', inPlace: true, doc: false }
]
})
).toMatchSnapshot('with links');
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/DocumentationTooltip-test.tsx.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/DocumentationTooltip-test.tsx.snap
index 88d7984d8e3..b1ed2aba980 100644
--- a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/DocumentationTooltip-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/DocumentationTooltip-test.tsx.snap
@@ -77,23 +77,21 @@ exports[`renders correctly: with links 1`] = `
aria-hidden={true}
className="little-spacer-bottom"
>
- <ForwardRef(Link)
- target="_blank"
+ <withAppStateContext(DocLink)
to="http://link.tosome.place"
>
external link
- </ForwardRef(Link)>
+ </withAppStateContext(DocLink)>
</div>
<div
aria-hidden={true}
className="little-spacer-bottom"
>
- <ForwardRef(Link)
- target="_blank"
- to="/documentation/guide"
+ <withAppStateContext(DocLink)
+ to="/guide"
>
internal link
- </ForwardRef(Link)>
+ </withAppStateContext(DocLink)>
</div>
<div
aria-hidden={true}
diff --git a/server/sonar-web/src/main/js/components/docs/DocCollapsibleBlock.tsx b/server/sonar-web/src/main/js/components/docs/DocCollapsibleBlock.tsx
deleted file mode 100644
index 4a3eb1d604a..00000000000
--- a/server/sonar-web/src/main/js/components/docs/DocCollapsibleBlock.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import OpenCloseIcon from '../../components/icons/OpenCloseIcon';
-
-interface State {
- open: boolean;
-}
-
-export default class DocCollapsibleBlock extends React.PureComponent<{}, State> {
- state = { open: false };
-
- handleClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
- this.setState(state => ({ open: !state.open }));
- event.stopPropagation();
- event.preventDefault();
- };
-
- renderTitle(children: any) {
- return (
- <a
- aria-expanded={this.state.open}
- aria-haspopup={true}
- role="button"
- className="link-no-underline"
- href="#"
- onClick={this.handleClick}>
- <OpenCloseIcon className="text-middle little-spacer-right" open={this.state.open} />
- {children.props ? children.props.children : children}
- </a>
- );
- }
-
- render() {
- const childrenAsArray = React.Children.toArray(this.props.children);
- if (childrenAsArray.length < 1) {
- return null;
- }
-
- const firstChildChildren = React.Children.toArray(
- (childrenAsArray[0] as React.ReactElement<any>).props.children
- );
- if (firstChildChildren.length < 2) {
- return null;
- }
-
- return (
- <div className="collapse-container">
- {this.renderTitle(firstChildChildren[0])}
- {this.state.open && firstChildChildren.slice(1)}
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/docs/DocLink.tsx b/server/sonar-web/src/main/js/components/docs/DocLink.tsx
deleted file mode 100644
index 78c3228bb92..00000000000
--- a/server/sonar-web/src/main/js/components/docs/DocLink.tsx
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import withAppStateContext from '../../app/components/app-state/withAppStateContext';
-import { AppState } from '../../types/appstate';
-import Link from '../common/Link';
-
-interface OwnProps {
- appState: AppState;
- customProps?: {
- [k: string]: any;
- };
-}
-
-type Props = OwnProps & React.AnchorHTMLAttributes<HTMLAnchorElement>;
-
-const SONARQUBE_LINK = '/#sonarqube#/';
-const SONARQUBE_ADMIN_LINK = '/#sonarqube-admin#/';
-
-export class DocLink extends React.PureComponent<Props> {
- handleClickOnAnchor = (event: React.MouseEvent<HTMLAnchorElement>) => {
- const { customProps, href = '#' } = this.props;
- if (customProps && customProps.onAnchorClick) {
- customProps.onAnchorClick(href, event);
- }
- };
-
- render() {
- const { appState, children, href, customProps, ...other } = this.props;
- if (href && href.startsWith('#')) {
- return (
- <a href="#" onClick={this.handleClickOnAnchor}>
- {children}
- </a>
- );
- }
-
- if (href && href.startsWith('/')) {
- if (href.startsWith(SONARQUBE_LINK)) {
- return <SonarQubeLink url={href}>{children}</SonarQubeLink>;
- } else if (href.startsWith(SONARQUBE_ADMIN_LINK)) {
- return (
- <SonarQubeAdminLink canAdmin={appState.canAdmin} url={href}>
- {children}
- </SonarQubeAdminLink>
- );
- }
- const url = '/documentation' + href;
- return (
- <Link to={url} {...other}>
- {children}
- </Link>
- );
- }
-
- return href ? (
- <Link to={href} target="_blank" size={12} {...other}>
- {children}
- </Link>
- ) : null;
- }
-}
-
-export default withAppStateContext(DocLink);
-
-interface SonarQubeLinkProps {
- children: React.ReactNode;
- url: string;
-}
-
-function SonarQubeLink({ children, url }: SonarQubeLinkProps) {
- const to = `/${url.substr(SONARQUBE_LINK.length)}`;
- return (
- <Link target="_blank" to={to}>
- {children}
- </Link>
- );
-}
-
-interface SonarQubeAdminLinkProps {
- canAdmin?: boolean;
- children: React.ReactNode;
- url: string;
-}
-
-function SonarQubeAdminLink({ canAdmin, children, url }: SonarQubeAdminLinkProps) {
- if (!canAdmin) {
- return <>{children}</>;
- }
- const to = `/${url.substr(SONARQUBE_ADMIN_LINK.length)}`;
- return (
- <Link target="_blank" to={to}>
- {children}
- </Link>
- );
-}
diff --git a/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.css b/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.css
deleted file mode 100644
index 840ceebe78f..00000000000
--- a/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.css
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-.markdown-content .alert {
- margin-bottom: var(--gridSize);
- border: 1px solid;
- border-radius: 2px;
-}
-
-.markdown-content .alert.is-inline {
- display: inline-flex;
-}
-
-.markdown-content .alert:empty {
- display: none;
-}
-
-.markdown-content .alert-error,
-.markdown-content .alert-danger {
- border-color: var(--alertBorderError);
- background-color: var(--alertBackgroundError);
- color: var(--alertTextError);
-}
-
-.markdown-content .alert-error .alert-icon,
-.markdown-content .alert-danger .alert-icon {
- border-color: var(--alertBorderError);
-}
-
-.markdown-content .alert-warning {
- border-color: var(--alertBorderWarning);
- background-color: var(--alertBackgroundWarning);
- color: var(--alertTextWarning);
-}
-
-.markdown-content .alert-warning .alert-icon {
- border-color: var(--alertBorderWarning);
-}
-
-.markdown-content .alert-info {
- border-color: var(--alertBorderInfo);
- background-color: var(--alertBackgroundInfo);
- color: var(--alertTextInfo);
-}
-
-.markdown-content .alert-info .alert-icon {
- border-color: var(--alertBorderInfo);
-}
-
-.markdown-content .alert-success {
- border-color: var(--alertBorderSuccess);
- background-color: var(--alertBackgroundSuccess);
- color: var(--alertTextSuccess);
-}
-
-.markdown-content .alert-success .alert-icon {
- border-color: var(--alertBorderSuccess);
-}
diff --git a/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx b/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx
deleted file mode 100644
index 2e9a7770578..00000000000
--- a/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import classNames from 'classnames';
-import * as React from 'react';
-import rehypeRaw from 'rehype-raw';
-import rehypeReact from 'rehype-react';
-import rehypeSlug from 'rehype-slug';
-import remark from 'remark';
-import remarkCustomBlocks from 'remark-custom-blocks';
-import remarkRehype from 'remark-rehype';
-import { scrollToElement } from '../../helpers/scrolling';
-import { Dict } from '../../types/types';
-import DocCollapsibleBlock from './DocCollapsibleBlock';
-import DocImg from './DocImg';
-import DocLink from './DocLink';
-import './DocMarkdownBlock.css';
-import DocToc from './DocToc';
-import DocTooltipLink from './DocTooltipLink';
-
-interface Props {
- childProps?: Dict<string>;
- className?: string;
- content: string;
- isTooltip?: boolean;
- scrollToHref?: string;
- stickyToc?: boolean;
- title?: string;
-}
-
-const WAIT_TIMEOUT = 500;
-
-export default class DocMarkdownBlock extends React.PureComponent<Props> {
- node: HTMLElement | null = null;
-
- componentDidMount() {
- const { scrollToHref } = this.props;
- if (scrollToHref) {
- setTimeout(() => {
- this.handleAnchorClick(scrollToHref);
- }, WAIT_TIMEOUT);
- }
- }
-
- handleAnchorClick = (href: string, event?: React.MouseEvent<HTMLAnchorElement>) => {
- if (this.node) {
- const element = this.node.querySelector(href);
- if (element) {
- if (event) {
- event.preventDefault();
- }
- scrollToElement(element, { bottomOffset: window.innerHeight - 80 });
-
- // We cannot use React Router here, because we cannot simply replace a hash.
- if (history.pushState) {
- history.pushState(null, '', href);
- }
- }
- }
- };
-
- render() {
- const { childProps, content, className, title, stickyToc, isTooltip } = this.props;
-
- const md = remark();
-
- // TODO find a way to replace these custom blocks with real Alert components
- md.use(remarkCustomBlocks, {
- danger: { classes: 'alert alert-danger' },
- warning: { classes: 'alert alert-warning' },
- info: { classes: 'alert alert-info' },
- success: { classes: 'alert alert-success' },
- collapse: { classes: 'collapse' }
- })
- .use(remarkRehype, { allowDangerousHTML: true })
- .use(rehypeSlug)
- .use(rehypeRaw)
- .use(rehypeReact, {
- createElement: React.createElement,
- components: {
- div: Block,
- // use custom link to render documentation anchors
- a: isTooltip
- ? withChildProps(DocTooltipLink, childProps)
- : withChildProps(DocLink, { onAnchorClick: this.handleAnchorClick }),
- // use custom img tag to render documentation images
- img: DocImg
- }
- });
-
- return (
- <div
- className={classNames('markdown', className, { 'has-toc': stickyToc })}
- ref={ref => (this.node = ref)}>
- <div className="markdown-content">
- {title !== undefined && <h1 className="documentation-title">{title}</h1>}
- {md.processSync(content).contents}
- </div>
- {stickyToc && <DocToc content={content} onAnchorClick={this.handleAnchorClick} />}
- </div>
- );
- }
-}
-
-function withChildProps<P>(
- WrappedComponent: React.ComponentType<P & { customProps?: Dict<any> }>,
- childProps?: Dict<any>
-) {
- return function withChildProps(props: P) {
- return <WrappedComponent customProps={childProps} {...props} />;
- };
-}
-
-function Block(props: React.HtmlHTMLAttributes<HTMLDivElement>) {
- if (props.className) {
- if (props.className.includes('collapse')) {
- return <DocCollapsibleBlock>{props.children}</DocCollapsibleBlock>;
- } else {
- return <div className={classNames('cut-margins', props.className)}>{props.children}</div>;
- }
- } else {
- return props.children;
- }
-}
diff --git a/server/sonar-web/src/main/js/components/docs/DocToc.tsx b/server/sonar-web/src/main/js/components/docs/DocToc.tsx
deleted file mode 100644
index 2332fd17337..00000000000
--- a/server/sonar-web/src/main/js/components/docs/DocToc.tsx
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import classNames from 'classnames';
-import { debounce, memoize } from 'lodash';
-import * as React from 'react';
-import { findDOMNode } from 'react-dom';
-import remark from 'remark';
-import reactRenderer from 'remark-react';
-import { translate } from '../../helpers/l10n';
-import onlyToc from './plugins/remark-only-toc';
-
-interface Props {
- content: string;
- onAnchorClick: (href: string, event: React.MouseEvent<HTMLAnchorElement>) => void;
-}
-
-interface State {
- anchors: AnchorObject[];
- highlightAnchor?: string;
-}
-
-interface AnchorObject {
- href: string;
- title: string;
-}
-
-export default class DocToc extends React.PureComponent<Props, State> {
- debouncedScrollHandler: () => void;
-
- node: HTMLDivElement | null = null;
-
- state: State = { anchors: [] };
-
- constructor(props: Props) {
- super(props);
- this.debouncedScrollHandler = debounce(this.scrollHandler);
- }
-
- static getDerivedStateFromProps(props: Props) {
- const { content } = props;
- return { anchors: DocToc.getAnchors(content) };
- }
-
- componentDidMount() {
- window.addEventListener('scroll', this.debouncedScrollHandler, true);
- this.scrollHandler();
- }
-
- componentWillUnmount() {
- window.removeEventListener('scroll', this.debouncedScrollHandler, true);
- }
-
- static getAnchors = memoize((content: string) => {
- const file: { contents: JSX.Element } = remark()
- .use(reactRenderer)
- .use(onlyToc)
- .processSync('\n## doctoc\n' + content);
-
- if (file && file.contents.props.children) {
- let list = file.contents;
- let limit = 10;
- while (limit && list.props.children.length && list.type !== 'ul') {
- list = list.props.children[0];
- limit--;
- }
-
- if (list.type === 'ul' && list.props.children.length) {
- return list.props.children
- .map((li: JSX.Element | string) => {
- if (typeof li === 'string') {
- return null;
- }
-
- const anchor = li.props.children[0];
- return {
- href: anchor.props.href,
- title: anchor.props.children[0]
- } as AnchorObject;
- })
- .filter((item: AnchorObject | null) => item);
- }
- }
- return [];
- });
-
- scrollHandler = () => {
- // eslint-disable-next-line react/no-find-dom-node
- const node = findDOMNode(this) as HTMLElement;
-
- if (!node || !node.parentNode) {
- return;
- }
-
- const headings: NodeListOf<HTMLHeadingElement> = node.parentNode.querySelectorAll('h2[id]');
- const scrollTop = window.pageYOffset || document.body.scrollTop;
- let highlightAnchor;
-
- for (let i = 0, len = headings.length; i < len; i++) {
- if (headings.item(i).offsetTop > scrollTop + 120) {
- break;
- }
- highlightAnchor = `#${headings.item(i).id}`;
- }
-
- this.setState({
- highlightAnchor
- });
- };
-
- render() {
- const { anchors, highlightAnchor } = this.state;
-
- if (anchors.length === 0) {
- return null;
- }
-
- return (
- <div className="markdown-toc">
- <div className="markdown-toc-content">
- <h4>{translate('documentation.on_this_page')}</h4>
- {anchors.map(anchor => {
- return (
- <a
- className={classNames({ active: highlightAnchor === anchor.href })}
- href={anchor.href}
- key={anchor.title}
- onClick={(event: React.MouseEvent<HTMLAnchorElement>) => {
- this.props.onAnchorClick(anchor.href, event);
- }}>
- {anchor.title}
- </a>
- );
- })}
- </div>
- </div>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/components/docs/DocTooltipLink.tsx b/server/sonar-web/src/main/js/components/docs/DocTooltipLink.tsx
deleted file mode 100644
index daf1c8c4662..00000000000
--- a/server/sonar-web/src/main/js/components/docs/DocTooltipLink.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { forEach } from 'lodash';
-import * as React from 'react';
-import { Dict } from '../../types/types';
-import Link from '../common/Link';
-
-interface OwnProps {
- customProps?: Dict<string>;
-}
-
-type Props = OwnProps & React.AnchorHTMLAttributes<HTMLAnchorElement>;
-
-export default function DocTooltipLink({ children, customProps, href, ...other }: Props) {
- if (customProps) {
- forEach(customProps, (value, key) => {
- if (href) {
- href = href.replace(`#${key}#`, encodeURIComponent(value));
- }
- });
- }
-
- if (href && href.startsWith('/')) {
- href = `/documentation/${href.substr(1)}`;
-
- return (
- <Link target="_blank" to={href} {...other}>
- {children}
- </Link>
- );
- }
-
- return href ? (
- <Link size={12} to={href} target="_blank" {...other}>
- {children}
- </Link>
- ) : null;
-}
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/DocCollapsibleBlock-test.tsx b/server/sonar-web/src/main/js/components/docs/__tests__/DocCollapsibleBlock-test.tsx
deleted file mode 100644
index b0eba13816e..00000000000
--- a/server/sonar-web/src/main/js/components/docs/__tests__/DocCollapsibleBlock-test.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { click } from '../../../helpers/testUtils';
-import DocCollapsibleBlock from '../DocCollapsibleBlock';
-
-const children = (
- <div>
- <h2>Foo</h2>
- <p>Bar</p>
- </div>
-);
-
-it('should render a collapsible block', () => {
- const wrapper = shallow(<DocCollapsibleBlock>{children}</DocCollapsibleBlock>);
- expect(wrapper).toMatchSnapshot();
-
- click(wrapper.find('a'));
- wrapper.update();
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should not render if not at least 2 children', () => {
- const wrapper = shallow(
- <DocCollapsibleBlock>
- <div>foobar</div>
- </DocCollapsibleBlock>
- );
- expect(wrapper).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/DocLink-test.tsx b/server/sonar-web/src/main/js/components/docs/__tests__/DocLink-test.tsx
deleted file mode 100644
index fbc71124d70..00000000000
--- a/server/sonar-web/src/main/js/components/docs/__tests__/DocLink-test.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockAppState } from '../../../helpers/testMocks';
-import { DocLink } from '../DocLink';
-
-it('should render simple link', () => {
- expect(
- shallow(
- <DocLink appState={mockAppState({ canAdmin: false })} href="http://sample.com">
- link text
- </DocLink>
- )
- ).toMatchSnapshot();
-});
-
-it('should render documentation link', () => {
- expect(
- shallow(
- <DocLink appState={mockAppState({ canAdmin: false })} href="/foo/bar">
- link text
- </DocLink>
- )
- ).toMatchSnapshot();
-});
-
-it('should render sonarqube link on sonarqube', () => {
- const wrapper = shallow(
- <DocLink appState={mockAppState({ canAdmin: false })} href="/#sonarqube#/foo/bar">
- link text
- </DocLink>
- );
- expect(wrapper).toMatchSnapshot();
- expect(wrapper.find('SonarQubeLink').dive()).toMatchSnapshot();
-});
-
-it('should render sonarqube admin link on sonarqube for admin', () => {
- const wrapper = shallow(
- <DocLink appState={mockAppState({ canAdmin: true })} href="/#sonarqube-admin#/foo/bar">
- link text
- </DocLink>
- );
- expect(wrapper).toMatchSnapshot();
- expect(wrapper.find('SonarQubeAdminLink').dive()).toMatchSnapshot();
-});
-
-it('should not render sonarqube admin link on sonarqube for non-admin', () => {
- const wrapper = shallow(
- <DocLink appState={mockAppState({ canAdmin: false })} href="/#sonarqube-admin#/foo/bar">
- link text
- </DocLink>
- );
- expect(wrapper.find('SonarQubeAdminLink').dive()).toMatchSnapshot();
-});
-
-it('should render documentation anchor', () => {
- expect(
- shallow(
- <DocLink appState={mockAppState({ canAdmin: false })} href="#quality-profiles">
- link text
- </DocLink>
- )
- ).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/DocMarkdownBlock-test.tsx b/server/sonar-web/src/main/js/components/docs/__tests__/DocMarkdownBlock-test.tsx
deleted file mode 100644
index 1df772fbe6f..00000000000
--- a/server/sonar-web/src/main/js/components/docs/__tests__/DocMarkdownBlock-test.tsx
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { scrollToElement } from '../../../helpers/scrolling';
-import { mockEvent } from '../../../helpers/testUtils';
-import DocMarkdownBlock from '../DocMarkdownBlock';
-
-const CONTENT = `
-## Lorem ipsum
-
-Quisque vitae tincidunt felis. Nam blandit risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
-
-## Sit amet
-
-### Maecenas diam
-
-Velit, vestibulum nec ultrices id, mollis eget arcu. Sed dapibus, sapien ut auctor consectetur, mi tortor vestibulum ante, eget dapibus lacus risus.
-
-### Integer
-
-At cursus turpis. Aenean at elit fringilla, porttitor mi eget, dapibus nisi. Donec quis congue odio.
-
-## Nam blandit
-
-Risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
-`;
-
-// mock `remark` & co to work around the issue with cjs imports
-jest.mock('remark', () => jest.requireActual('remark'));
-jest.mock('remark-rehype', () => jest.requireActual('remark-rehype'));
-jest.mock('rehype-raw', () => jest.requireActual('rehype-raw'));
-jest.mock('rehype-react', () => jest.requireActual('rehype-react'));
-jest.mock('rehype-slug', () => jest.requireActual('rehype-slug'));
-
-jest.mock('../../../helpers/scrolling', () => ({
- scrollToElement: jest.fn()
-}));
-
-const WINDOW_HEIGHT = 800;
-const originalWindowHeight = window.innerHeight;
-
-const historyPushState = jest.fn();
-const originalHistoryPushState = history.pushState;
-
-beforeEach(jest.clearAllMocks);
-
-beforeAll(() => {
- Object.defineProperty(window, 'innerHeight', {
- writable: true,
- configurable: true,
- value: WINDOW_HEIGHT
- });
- Object.defineProperty(history, 'pushState', {
- writable: true,
- configurable: true,
- value: historyPushState
- });
-});
-
-afterAll(() => {
- Object.defineProperty(window, 'innerHeight', {
- writable: true,
- configurable: true,
- value: originalWindowHeight
- });
- Object.defineProperty(history, 'pushState', {
- writable: true,
- configurable: true,
- value: originalHistoryPushState
- });
-});
-
-it('should render correctly', () => {
- expect(shallowRender({ content: 'this is *bold* text' })).toMatchSnapshot('default');
- expect(
- shallowRender({ content: 'some [link](/quality-profiles)' }).find('withChildProps')
- ).toMatchSnapshot('custom component for links');
- expect(
- shallowRender({
- childProps: { foo: 'bar' },
- content: 'some [link](#quality-profiles)',
- isTooltip: true
- }).find('withChildProps')
- ).toMatchSnapshot('custom props for links');
- expect(shallowRender({ content: CONTENT, stickyToc: true })).toMatchSnapshot('sticky TOC');
-});
-
-it('should correctly scroll to clicked headings', () => {
- const element = {} as Element;
- const querySelector: (selector: string) => Element | null = jest.fn((selector: string) =>
- selector === '#id' ? element : null
- );
- const preventDefault = jest.fn();
- const wrapper = shallowRender();
- const instance = wrapper.instance();
-
- // Node Ref isn't set yet.
- instance.handleAnchorClick('#unknown', mockEvent());
- expect(scrollToElement).not.toHaveBeenCalled();
-
- // Set node Ref.
- instance.node = { querySelector } as HTMLElement;
-
- // Unknown element.
- instance.handleAnchorClick('#unknown', mockEvent());
- expect(scrollToElement).not.toHaveBeenCalled();
-
- // Known element, should scroll.
- instance.handleAnchorClick('#id', mockEvent({ preventDefault }));
- expect(scrollToElement).toHaveBeenCalledWith(element, { bottomOffset: 720 });
- expect(preventDefault).toHaveBeenCalled();
- expect(historyPushState).toHaveBeenCalledWith(null, '', '#id');
-});
-
-it('should correctly scroll to a specific heading if passed as a prop', () => {
- jest.useFakeTimers();
-
- const element = {} as Element;
- const querySelector: (_: string) => Element | null = jest.fn(() => element);
- const wrapper = shallowRender({ scrollToHref: '#id' });
- const instance = wrapper.instance();
- instance.node = { querySelector } as HTMLElement;
-
- expect(scrollToElement).not.toHaveBeenCalled();
-
- jest.runAllTimers();
-
- expect(scrollToElement).toHaveBeenCalledWith(element, { bottomOffset: 720 });
- jest.runOnlyPendingTimers();
- jest.useRealTimers();
-});
-
-function shallowRender(props: Partial<DocMarkdownBlock['props']> = {}) {
- return shallow<DocMarkdownBlock>(<DocMarkdownBlock content="" {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/DocToc-test.tsx b/server/sonar-web/src/main/js/components/docs/__tests__/DocToc-test.tsx
deleted file mode 100644
index 1a837603275..00000000000
--- a/server/sonar-web/src/main/js/components/docs/__tests__/DocToc-test.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { mount } from 'enzyme';
-import * as React from 'react';
-import { click, scrollTo } from '../../../helpers/testUtils';
-import DocToc from '../DocToc';
-
-const OFFSET = 300;
-
-const CONTENT = `
-## Lorem ipsum
-
-Quisque vitae tincidunt felis. Nam blandit risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
-
-## Sit amet
-
-### Maecenas diam
-
-Velit, vestibulum nec ultrices id, mollis eget arcu. Sed dapibus, sapien ut auctor consectetur, mi tortor vestibulum ante, eget dapibus lacus risus.
-
-### Integer
-
-At cursus turpis. Aenean at elit fringilla, porttitor mi eget, dapibus nisi. Donec quis congue odio.
-
-## Nam blandit
-
-Risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
-`;
-
-jest.mock('remark', () => {
- const remark = jest.requireActual('remark');
- return remark;
-});
-
-jest.mock('remark-react', () => {
- const remarkReact = jest.requireActual('remark-react');
- return remarkReact;
-});
-
-jest.mock('lodash', () => {
- const lodash = jest.requireActual('lodash');
- lodash.debounce = (fn: any) => fn;
- return lodash;
-});
-
-jest.mock('react-dom', () => ({
- findDOMNode: jest.fn()
-}));
-
-it('should render correctly', () => {
- const wrapper = renderComponent();
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should trigger the handler when an anchor is clicked', () => {
- const onAnchorClick = jest.fn();
- const wrapper = renderComponent({ onAnchorClick });
- click(wrapper.find('a[href="#sit-amet"]'));
- expect(onAnchorClick).toHaveBeenCalled();
-});
-
-it('should highlight anchors when scrolling', () => {
- mockDomEnv();
- const wrapper = renderComponent();
-
- scrollTo({ top: OFFSET });
- expect(wrapper.state('highlightAnchor')).toEqual('#lorem-ipsum');
-
- scrollTo({ top: OFFSET * 3 });
- expect(wrapper.state('highlightAnchor')).toEqual('#nam-blandit');
-});
-
-function renderComponent(props: Partial<DocToc['props']> = {}) {
- return mount(<DocToc content={CONTENT} onAnchorClick={jest.fn()} {...props} />);
-}
-
-function mockDomEnv() {
- const findDOMNode = require('react-dom').findDOMNode as jest.Mock<any>;
- const parent = document.createElement('div');
- const element = document.createElement('div');
- parent.appendChild(element);
-
- let offset = OFFSET;
- (CONTENT.match(/^## .+$/gm) as Array<string>).forEach(match => {
- const slug = match
- .replace(/^#+ */, '')
- .replace(' ', '-')
- .toLowerCase()
- .trim();
- const heading = document.createElement('h2');
- heading.id = slug;
- Object.defineProperty(heading, 'offsetTop', { value: offset });
- offset += OFFSET;
-
- parent.appendChild(heading);
- });
-
- findDOMNode.mockReturnValue(element);
-}
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/DocTooltipLink-test.tsx b/server/sonar-web/src/main/js/components/docs/__tests__/DocTooltipLink-test.tsx
deleted file mode 100644
index 632d4d31af6..00000000000
--- a/server/sonar-web/src/main/js/components/docs/__tests__/DocTooltipLink-test.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import DocTooltipLink from '../DocTooltipLink';
-
-it('should render simple link', () => {
- expect(shallow(<DocTooltipLink href="http://sample.com" />)).toMatchSnapshot();
-});
-
-it('should render internal link', () => {
- expect(shallow(<DocTooltipLink href="/foo/bar" />)).toMatchSnapshot();
-});
-
-it('should render links with custom props', () => {
- expect(
- shallow(<DocTooltipLink customProps={{ bar: 'baz' }} href="/foo/#bar#" />)
- ).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocCollapsibleBlock-test.tsx.snap b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocCollapsibleBlock-test.tsx.snap
deleted file mode 100644
index 7d1afc88f86..00000000000
--- a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocCollapsibleBlock-test.tsx.snap
+++ /dev/null
@@ -1,50 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should not render if not at least 2 children 1`] = `""`;
-
-exports[`should render a collapsible block 1`] = `
-<div
- className="collapse-container"
->
- <a
- aria-expanded={false}
- aria-haspopup={true}
- className="link-no-underline"
- href="#"
- onClick={[Function]}
- role="button"
- >
- <OpenCloseIcon
- className="text-middle little-spacer-right"
- open={false}
- />
- Foo
- </a>
-</div>
-`;
-
-exports[`should render a collapsible block 2`] = `
-<div
- className="collapse-container"
->
- <a
- aria-expanded={true}
- aria-haspopup={true}
- className="link-no-underline"
- href="#"
- onClick={[Function]}
- role="button"
- >
- <OpenCloseIcon
- className="text-middle little-spacer-right"
- open={true}
- />
- Foo
- </a>
- <p
- key=".1"
- >
- Bar
- </p>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocLink-test.tsx.snap b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocLink-test.tsx.snap
deleted file mode 100644
index 48b6223cb29..00000000000
--- a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocLink-test.tsx.snap
+++ /dev/null
@@ -1,69 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should not render sonarqube admin link on sonarqube for non-admin 1`] = `
-<Fragment>
- link text
-</Fragment>
-`;
-
-exports[`should render documentation anchor 1`] = `
-<a
- href="#"
- onClick={[Function]}
->
- link text
-</a>
-`;
-
-exports[`should render documentation link 1`] = `
-<ForwardRef(Link)
- to="/documentation/foo/bar"
->
- link text
-</ForwardRef(Link)>
-`;
-
-exports[`should render simple link 1`] = `
-<ForwardRef(Link)
- size={12}
- target="_blank"
- to="http://sample.com"
->
- link text
-</ForwardRef(Link)>
-`;
-
-exports[`should render sonarqube admin link on sonarqube for admin 1`] = `
-<SonarQubeAdminLink
- canAdmin={true}
- url="/#sonarqube-admin#/foo/bar"
->
- link text
-</SonarQubeAdminLink>
-`;
-
-exports[`should render sonarqube admin link on sonarqube for admin 2`] = `
-<ForwardRef(Link)
- target="_blank"
- to="/foo/bar"
->
- link text
-</ForwardRef(Link)>
-`;
-
-exports[`should render sonarqube link on sonarqube 1`] = `
-<SonarQubeLink
- url="/#sonarqube#/foo/bar"
->
- link text
-</SonarQubeLink>
-`;
-
-exports[`should render sonarqube link on sonarqube 2`] = `
-<ForwardRef(Link)
- target="_blank"
- to="/foo/bar"
->
- link text
-</ForwardRef(Link)>
-`;
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocMarkdownBlock-test.tsx.snap b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocMarkdownBlock-test.tsx.snap
deleted file mode 100644
index e15b023ec86..00000000000
--- a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocMarkdownBlock-test.tsx.snap
+++ /dev/null
@@ -1,148 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly: custom component for links 1`] = `
-<withChildProps
- href="/quality-profiles"
- key="h-2"
->
- link
-</withChildProps>
-`;
-
-exports[`should render correctly: custom props for links 1`] = `
-<withChildProps
- href="#quality-profiles"
- key="h-2"
->
- link
-</withChildProps>
-`;
-
-exports[`should render correctly: default 1`] = `
-<div
- className="markdown"
->
- <div
- className="markdown-content"
- >
- <div>
- <p
- key="h-1"
- >
- this is
- <em
- key="h-2"
- >
- bold
- </em>
- text
- </p>
- </div>
- </div>
-</div>
-`;
-
-exports[`should render correctly: sticky TOC 1`] = `
-<div
- className="markdown has-toc"
->
- <div
- className="markdown-content"
- >
- <div>
- <Block
- key="h-1"
- >
- <h2
- id="lorem-ipsum"
- key="h-2"
- >
- Lorem ipsum
- </h2>
-
-
- <p
- key="h-3"
- >
- Quisque vitae tincidunt felis. Nam blandit risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
- </p>
-
-
- <h2
- id="sit-amet"
- key="h-4"
- >
- Sit amet
- </h2>
-
-
- <h3
- id="maecenas-diam"
- key="h-5"
- >
- Maecenas diam
- </h3>
-
-
- <p
- key="h-6"
- >
- Velit, vestibulum nec ultrices id, mollis eget arcu. Sed dapibus, sapien ut auctor consectetur, mi tortor vestibulum ante, eget dapibus lacus risus.
- </p>
-
-
- <h3
- id="integer"
- key="h-7"
- >
- Integer
- </h3>
-
-
- <p
- key="h-8"
- >
- At cursus turpis. Aenean at elit fringilla, porttitor mi eget, dapibus nisi. Donec quis congue odio.
- </p>
-
-
- <h2
- id="nam-blandit"
- key="h-9"
- >
- Nam blandit
- </h2>
-
-
- <p
- key="h-10"
- >
- Risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
- </p>
- </Block>
- </div>
- </div>
- <DocToc
- content="
-## Lorem ipsum
-
-Quisque vitae tincidunt felis. Nam blandit risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
-
-## Sit amet
-
-### Maecenas diam
-
-Velit, vestibulum nec ultrices id, mollis eget arcu. Sed dapibus, sapien ut auctor consectetur, mi tortor vestibulum ante, eget dapibus lacus risus.
-
-### Integer
-
-At cursus turpis. Aenean at elit fringilla, porttitor mi eget, dapibus nisi. Donec quis congue odio.
-
-## Nam blandit
-
-Risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
-"
- onAnchorClick={[Function]}
- />
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocToc-test.tsx.snap b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocToc-test.tsx.snap
deleted file mode 100644
index ea33e896b40..00000000000
--- a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocToc-test.tsx.snap
+++ /dev/null
@@ -1,62 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<DocToc
- content="
-## Lorem ipsum
-
-Quisque vitae tincidunt felis. Nam blandit risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
-
-## Sit amet
-
-### Maecenas diam
-
-Velit, vestibulum nec ultrices id, mollis eget arcu. Sed dapibus, sapien ut auctor consectetur, mi tortor vestibulum ante, eget dapibus lacus risus.
-
-### Integer
-
-At cursus turpis. Aenean at elit fringilla, porttitor mi eget, dapibus nisi. Donec quis congue odio.
-
-## Nam blandit
-
-Risus placerat, efficitur enim ut, pellentesque sem. Mauris non lorem auctor, consequat neque eget, dignissim augue.
-"
- onAnchorClick={[MockFunction]}
->
- <div
- className="markdown-toc"
- >
- <div
- className="markdown-toc-content"
- >
- <h4>
- documentation.on_this_page
- </h4>
- <a
- className=""
- href="#lorem-ipsum"
- key="Lorem ipsum"
- onClick={[Function]}
- >
- Lorem ipsum
- </a>
- <a
- className=""
- href="#sit-amet"
- key="Sit amet"
- onClick={[Function]}
- >
- Sit amet
- </a>
- <a
- className=""
- href="#nam-blandit"
- key="Nam blandit"
- onClick={[Function]}
- >
- Nam blandit
- </a>
- </div>
- </div>
-</DocToc>
-`;
diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltipLink-test.tsx.snap b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltipLink-test.tsx.snap
deleted file mode 100644
index 43cac601766..00000000000
--- a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltipLink-test.tsx.snap
+++ /dev/null
@@ -1,23 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render internal link 1`] = `
-<ForwardRef(Link)
- target="_blank"
- to="/documentation/foo/bar"
-/>
-`;
-
-exports[`should render links with custom props 1`] = `
-<ForwardRef(Link)
- target="_blank"
- to="/documentation/foo/baz"
-/>
-`;
-
-exports[`should render simple link 1`] = `
-<ForwardRef(Link)
- size={12}
- target="_blank"
- to="http://sample.com"
-/>
-`;
diff --git a/server/sonar-web/src/main/js/components/docs/plugins/__tests__/remark-only-toc-test.ts b/server/sonar-web/src/main/js/components/docs/plugins/__tests__/remark-only-toc-test.ts
deleted file mode 100644
index e3c6a7cde19..00000000000
--- a/server/sonar-web/src/main/js/components/docs/plugins/__tests__/remark-only-toc-test.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import util from 'mdast-util-toc';
-import onlyToc from '../remark-only-toc';
-
-jest.mock('mdast-util-toc', () => ({
- __esModule: true,
- default: jest.fn().mockReturnValue({})
-}));
-
-it('should only render toc', () => {
- const node = { type: 'test', children: ['a'] };
- onlyToc()(node);
- expect(node.children).toHaveLength(0);
-
- (util as jest.Mock).mockReturnValue({ index: -1 });
- node.children.push('a');
-
- onlyToc()(node);
- expect(node.children).toHaveLength(0);
-
- (util as jest.Mock).mockReturnValue({ index: 0 });
- node.children.push('a');
-
- onlyToc()(node);
- expect(node.children).toHaveLength(0);
-
- (util as jest.Mock).mockReturnValue({ index: 0, map: 'a' });
- node.children.push('a');
-
- onlyToc()(node);
- expect(node.children).toHaveLength(1);
-});
diff --git a/server/sonar-web/src/main/js/components/docs/plugins/remark-only-toc.ts b/server/sonar-web/src/main/js/components/docs/plugins/remark-only-toc.ts
deleted file mode 100644
index 06d95a4ead9..00000000000
--- a/server/sonar-web/src/main/js/components/docs/plugins/remark-only-toc.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import util from 'mdast-util-toc';
-import { Node } from 'unist';
-
-/**
- * This is a simplified version of the remark-toc plugin: https://github.com/remarkjs/remark-toc
- * It *only* renders the TOC, and leaves all the rest out.
- */
-export default function onlyToc() {
- return transformer;
-
- function transformer(node: Node) {
- const result = util(node, { heading: 'doctoc', maxDepth: 2 });
-
- if (result.index === null || result.index === -1 || !result.map) {
- node.children = [];
- } else {
- node.children = [result.map];
- }
- }
-}
diff --git a/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx b/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx
index 256af65b302..d1d5c932654 100644
--- a/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx
+++ b/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx
@@ -21,6 +21,7 @@ import * as React from 'react';
import { translate } from '../../helpers/l10n';
import { getBaseUrl } from '../../helpers/system';
import { SuggestionLink } from '../../types/types';
+import DocLink from '../common/DocLink';
import Link from '../common/Link';
import { DropdownOverlay } from '../controls/Dropdown';
import { SuggestionsContext } from './SuggestionsContext';
@@ -38,7 +39,7 @@ export default class EmbedDocsPopup extends React.PureComponent<Props> {
* If we have at least 1 suggestion, it will make the call first, and prevent 'documentation' from
* getting the focus.
*/
- focusFirstItem = (node: HTMLAnchorElement | null) => {
+ focusFirstItem: React.Ref<HTMLAnchorElement> = (node: HTMLAnchorElement | null) => {
if (node && !this.firstItem) {
this.firstItem = node;
this.firstItem.focus();
@@ -59,16 +60,15 @@ export default class EmbedDocsPopup extends React.PureComponent<Props> {
}
return (
<ul className="menu abs-width-240" role="group">
- {this.renderTitle(translate('embed_docs.suggestion'))}
+ {this.renderTitle(translate('docs.suggestion'))}
{suggestions.map((suggestion, i) => (
<li key={suggestion.link}>
- <Link
- ref={i === 0 ? this.focusFirstItem : undefined}
+ <DocLink
+ innerRef={i === 0 ? this.focusFirstItem : undefined}
onClick={this.props.onClose}
- target="_blank"
to={suggestion.link}>
{suggestion.text}
- </Link>
+ </DocLink>
</li>
))}
</ul>
@@ -96,13 +96,9 @@ export default class EmbedDocsPopup extends React.PureComponent<Props> {
<SuggestionsContext.Consumer>{this.renderSuggestions}</SuggestionsContext.Consumer>
<ul className="menu abs-width-240" role="group">
<li>
- <Link
- ref={this.focusFirstItem}
- onClick={this.props.onClose}
- target="_blank"
- to="/documentation">
- {translate('embed_docs.documentation')}
- </Link>
+ <DocLink innerRef={this.focusFirstItem} onClick={this.props.onClose} to="/">
+ {translate('docs.documentation')}
+ </DocLink>
</li>
<li>
<Link onClick={this.props.onClose} to="/web_api">
@@ -116,17 +112,17 @@ export default class EmbedDocsPopup extends React.PureComponent<Props> {
className="display-flex-center"
to="https://community.sonarsource.com/"
target="_blank">
- {translate('embed_docs.get_help')}
+ {translate('docs.get_help')}
</Link>
</li>
</ul>
<ul className="menu abs-width-240" role="group">
- {this.renderTitle(translate('embed_docs.stay_connected'))}
+ {this.renderTitle(translate('docs.stay_connected'))}
<li>
{this.renderIconLink(
'https://www.sonarqube.org/whats-new/?referrer=sonarqube',
'embed-doc/sq-icon.svg',
- translate('embed_docs.news')
+ translate('docs.news')
)}
</li>
<li>
diff --git a/server/sonar-docs/src/EmbedDocsSuggestions.json b/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsSuggestions.json
index ac1f9b43c9a..af4a5bd79df 100644
--- a/server/sonar-docs/src/EmbedDocsSuggestions.json
+++ b/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsSuggestions.json
@@ -3,24 +3,24 @@
"api_documentation": [],
"background_tasks": [
{
- "link": "/documentation/analysis/background-tasks/",
+ "link": "/analysis/background-tasks/",
"text": "About Background Tasks"
}
],
"code": [],
"coding_rules": [
{
- "link": "/documentation/instance-administration/quality-profiles/",
+ "link": "/instance-administration/quality-profiles/",
"text": "Quality Profiles"
}
],
"component_measures": [
{
- "link": "/documentation/user-guide/clean-as-you-code/",
+ "link": "/user-guide/clean-as-you-code/",
"text": "Clean as You Code"
},
{
- "link": "/documentation/user-guide/metric-definitions/",
+ "link": "/user-guide/metric-definitions/",
"text": "Metric Definitions"
}
],
@@ -29,45 +29,45 @@
"marketplace": [],
"overview": [
{
- "link": "/documentation/analysis/pull-request/",
+ "link": "/analysis/pull-request/",
"text": "Enable Pull Request Decoration"
},
{
- "link": "/documentation/analysis/ci-integration-overview/",
+ "link": "/analysis/ci-integration-overview/",
"text": "Set up CI analysis"
},
{
- "link": "/documentation/user-guide/clean-as-you-code/",
+ "link": "/user-guide/clean-as-you-code/",
"text": "Clean as You Code"
},
{
- "link": "/documentation/user-guide/connected-mode/",
+ "link": "/user-guide/connected-mode/",
"text": "SonarLint Connected Mode"
}
],
"permission_templates": [],
"profiles": [
{
- "link": "/documentation/instance-administration/quality-profiles/",
+ "link": "/instance-administration/quality-profiles/",
"text": "Quality Profiles"
}
],
"project_activity": [],
"project_baseline": [
{
- "link": "/documentation/project-administration/new-code-period/",
+ "link": "/project-administration/new-code-period/",
"text": "Defining New Code"
}
],
"project_quality_gate": [
{
- "link": "/documentation/user-guide/clean-as-you-code/",
+ "link": "/user-guide/clean-as-you-code/",
"text": "Clean as You Code"
}
],
"project_quality_profiles": [
{
- "link": "/documentation/instance-administration/quality-profiles/",
+ "link": "/instance-administration/quality-profiles/",
"text": "About Quality Profiles"
}
],
@@ -75,33 +75,33 @@
"projects": [],
"pull_requests": [
{
- "link": "/documentation/user-guide/clean-as-you-code/",
+ "link": "/user-guide/clean-as-you-code/",
"text": "Clean as You Code"
},
{
- "link": "/documentation/analysis/pull-request/",
+ "link": "/analysis/pull-request/",
"text": "Analyzing Pull Requests"
},
{
- "link": "/documentation/user-guide/connected-mode/",
+ "link": "/user-guide/connected-mode/",
"text": "SonarLint connected mode"
}
],
"quality_gates": [
{
- "link": "/documentation/user-guide/clean-as-you-code/",
+ "link": "/user-guide/clean-as-you-code/",
"text": "Clean as You Code"
}
],
"quality_profiles": [
{
- "link": "/documentation/instance-administration/quality-profiles/",
+ "link": "/instance-administration/quality-profiles/",
"text": "Quality Profiles"
}
],
"security_reports": [
{
- "link": "/documentation/user-guide/security-reports/",
+ "link": "/user-guide/security-reports/",
"text": "About Security Reports"
}
],
@@ -111,7 +111,7 @@
"users": [],
"webhooks": [
{
- "link": "/documentation/project-administration/webhooks/",
+ "link": "/project-administration/webhooks/",
"text": "About Webhooks"
}
]
diff --git a/server/sonar-web/src/main/js/components/embed-docs-modal/SuggestionsProvider.tsx b/server/sonar-web/src/main/js/components/embed-docs-modal/SuggestionsProvider.tsx
index 89481d2ab81..70ec0da9d51 100644
--- a/server/sonar-web/src/main/js/components/embed-docs-modal/SuggestionsProvider.tsx
+++ b/server/sonar-web/src/main/js/components/embed-docs-modal/SuggestionsProvider.tsx
@@ -17,9 +17,9 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import suggestionsJson from 'Docs/EmbedDocsSuggestions.json';
import * as React from 'react';
import { Dict, SuggestionLink } from '../../types/types';
+import suggestionsJson from './EmbedDocsSuggestions.json';
import { SuggestionsContext } from './SuggestionsContext';
type SuggestionsJson = Dict<SuggestionLink[]>;
@@ -41,8 +41,6 @@ export default class SuggestionsProvider extends React.Component<{}, State> {
}
});
- suggestions = suggestions.filter(suggestion => suggestion.scope !== 'sonarcloud');
-
this.setState({ suggestions });
};
diff --git a/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx b/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx
index 87f7315b3b2..c410eea978d 100644
--- a/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx
+++ b/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx
@@ -28,7 +28,7 @@ it('should render with no suggestions', () => {
renderEmbedDocsPopup();
expect(screen.getAllByRole('link')).toHaveLength(5);
- expect(screen.getByText('embed_docs.documentation')).toHaveFocus();
+ expect(screen.getByText('docs.documentation')).toHaveFocus();
});
it('should render with suggestions', () => {
diff --git a/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/SuggestionsProvider-test.tsx b/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/SuggestionsProvider-test.tsx
index 4cff54080c4..28a914dcee1 100644
--- a/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/SuggestionsProvider-test.tsx
+++ b/server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/SuggestionsProvider-test.tsx
@@ -22,12 +22,9 @@ import * as React from 'react';
import SuggestionsProvider from '../SuggestionsProvider';
jest.mock(
- 'Docs/EmbedDocsSuggestions.json',
+ '../EmbedDocsSuggestions.json',
() => ({
- pageA: [
- { link: '/foo', text: 'Foo' },
- { link: '/bar', text: 'Bar', scope: 'sonarcloud' }
- ],
+ pageA: [{ link: '/foo', text: 'Foo' }],
pageB: [{ link: '/qux', text: 'Qux' }]
}),
{ virtual: true }
diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueMessageTags.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueMessageTags.tsx
index b4dc65e4647..77e20ad10a7 100644
--- a/server/sonar-web/src/main/js/components/issue/components/IssueMessageTags.tsx
+++ b/server/sonar-web/src/main/js/components/issue/components/IssueMessageTags.tsx
@@ -72,7 +72,7 @@ export default function IssueMessageTags(props: IssueMessageTagsProps) {
content={translate('rules.status', ruleStatus, 'help')}
links={[
{
- href: '/documentation/user-guide/rules/',
+ href: '/user-guide/rules/',
label: translateWithParameters('see_x', translate('rules'))
}
]}>
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/AlertClassicEditor.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/AlertClassicEditor.tsx
index 1aa48b199d7..b334f5373cd 100644
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/AlertClassicEditor.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/AlertClassicEditor.tsx
@@ -23,7 +23,7 @@ import { Alert } from '../../../../components/ui/Alert';
import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
import { translate } from '../../../../helpers/l10n';
import { AlmKeys } from '../../../../types/alm-settings';
-import Link from '../../../common/Link';
+import DocLink from '../../../common/DocLink';
export default function AlertClassicEditor() {
return (
@@ -33,9 +33,9 @@ export default function AlertClassicEditor() {
defaultMessage={translate('onboarding.tutorial.with.azure_pipelines.BranchAnalysis.info')}
values={{
doc_link: (
- <Link to={ALM_DOCUMENTATION_PATHS[AlmKeys.Azure]} target="_blank">
+ <DocLink to={ALM_DOCUMENTATION_PATHS[AlmKeys.Azure]}>
{translate('onboarding.tutorial.with.azure_pipelines.BranchAnalysis.info.doc_link')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/PublishSteps.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/PublishSteps.tsx
index ea1ed9c725f..20852c0405a 100644
--- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/PublishSteps.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/PublishSteps.tsx
@@ -27,7 +27,7 @@ import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
import { translate } from '../../../../helpers/l10n';
import { AlmKeys } from '../../../../types/alm-settings';
import { Feature } from '../../../../types/features';
-import Link from '../../../common/Link';
+import DocLink from '../../../common/DocLink';
import SentenceWithHighlights from '../../components/SentenceWithHighlights';
export interface PublishStepsProps extends WithAvailableFeaturesProps {}
@@ -67,11 +67,11 @@ export function PublishSteps(props: PublishStepsProps) {
)}
values={{
link: (
- <Link to={ALM_DOCUMENTATION_PATHS[AlmKeys.Azure]} target="_blank">
+ <DocLink to={ALM_DOCUMENTATION_PATHS[AlmKeys.Azure]}>
{translate(
'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.branch_protection.link'
)}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/CompilationInfo.tsx b/server/sonar-web/src/main/js/components/tutorials/components/CompilationInfo.tsx
index cd7fa1e8db5..0753cec1c97 100644
--- a/server/sonar-web/src/main/js/components/tutorials/components/CompilationInfo.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/components/CompilationInfo.tsx
@@ -21,6 +21,7 @@ import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { Alert } from '../../../components/ui/Alert';
import { translate } from '../../../helpers/l10n';
+import DocLink from '../../common/DocLink';
export interface CompilationInfoProps {
className?: string;
@@ -35,12 +36,9 @@ export function CompilationInfo({ className = 'spacer-top spacer-bottom' }: Comp
defaultMessage={translate('onboarding.tutorial.cfamilly.compilation_database_info')}
values={{
link: (
- <a
- href="/documentation/analysis/languages/cfamily/"
- rel="noopener noreferrer"
- target="_blank">
+ <DocLink to="/analysis/languages/cfamily/">
{translate('onboarding.tutorial.cfamilly.compilation_database_info.link')}
- </a>
+ </DocLink>
)
}}
/>
@@ -51,12 +49,9 @@ export function CompilationInfo({ className = 'spacer-top spacer-bottom' }: Comp
defaultMessage={translate('onboarding.tutorial.cfamilly.speed_caching')}
values={{
link: (
- <a
- href="/documentation/analysis/languages/cfamily/#analysis-cache"
- rel="noopener noreferrer"
- target="_blank">
+ <DocLink to="/analysis/languages/cfamily/#analysis-cache">
{translate('onboarding.tutorial.cfamilly.speed_caching.link')}
- </a>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/ProjectTokenScopeInfo.tsx b/server/sonar-web/src/main/js/components/tutorials/components/ProjectTokenScopeInfo.tsx
index 202d297397c..d7cd473c8c8 100644
--- a/server/sonar-web/src/main/js/components/tutorials/components/ProjectTokenScopeInfo.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/components/ProjectTokenScopeInfo.tsx
@@ -21,6 +21,7 @@ import classNames from 'classnames';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { translate } from '../../../helpers/l10n';
+import DocLink from '../../common/DocLink';
import Link from '../../common/Link';
import { Alert } from '../../ui/Alert';
@@ -40,11 +41,7 @@ export default function ProjectTokenScopeInfo({ className }: ProjectTokenScopeIn
{translate('onboarding.token.text.user_account')}
</Link>
),
- doc_link: (
- <Link target="_blank" to="/documentation/user-guide/user-token/">
- {translate('documentation')}
- </Link>
- )
+ doc_link: <DocLink to="/user-guide/user-token/">{translate('documentation')}</DocLink>
}}
/>
</Alert>
diff --git a/server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/CompilationInfo-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/CompilationInfo-test.tsx.snap
index 93595e2e15d..10463c95d30 100644
--- a/server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/CompilationInfo-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/tutorials/components/__tests__/__snapshots__/CompilationInfo-test.tsx.snap
@@ -13,13 +13,11 @@ exports[`should render correctly 1`] = `
id="onboarding.tutorial.cfamilly.compilation_database_info"
values={
Object {
- "link": <a
- href="/documentation/analysis/languages/cfamily/"
- rel="noopener noreferrer"
- target="_blank"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/languages/cfamily/"
>
onboarding.tutorial.cfamilly.compilation_database_info.link
- </a>,
+ </withAppStateContext(DocLink)>,
}
}
/>
@@ -30,13 +28,11 @@ exports[`should render correctly 1`] = `
id="onboarding.tutorial.cfamilly.speed_caching"
values={
Object {
- "link": <a
- href="/documentation/analysis/languages/cfamily/#analysis-cache"
- rel="noopener noreferrer"
- target="_blank"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/languages/cfamily/#analysis-cache"
>
onboarding.tutorial.cfamilly.speed_caching.link
- </a>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx
index f2c4a4d2339..4705527a94f 100644
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx
@@ -25,7 +25,7 @@ import ChevronRightIcon from '../../../components/icons/ChevronRightIcon';
import { Alert } from '../../../components/ui/Alert';
import { translate } from '../../../helpers/l10n';
import { AlmKeys } from '../../../types/alm-settings';
-import Link from '../../common/Link';
+import DocLink from '../../common/DocLink';
import SentenceWithHighlights from '../components/SentenceWithHighlights';
import Step from '../components/Step';
@@ -72,9 +72,9 @@ export default function PreRequisitesStep(props: PreRequisitesStepProps) {
id="onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide"
values={{
link: (
- <Link target="_blank" to="/documentation/analysis/jenkins/">
+ <DocLink to="/analysis/jenkins/">
{translate('onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide.link')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/PreRequisitesStep-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/PreRequisitesStep-test.tsx.snap
index eba200ef8ff..474ed5565f6 100644
--- a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/PreRequisitesStep-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/PreRequisitesStep-test.tsx.snap
@@ -46,12 +46,11 @@ exports[`should render correctly: content 1`] = `
id="onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/jenkins/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/jenkins/"
>
onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide.link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
@@ -106,12 +105,11 @@ exports[`should render correctly: content for branches disabled 1`] = `
id="onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/jenkins/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/jenkins/"
>
onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide.link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
@@ -169,12 +167,11 @@ exports[`should render correctly: content for branches disabled, gitlab 1`] = `
id="onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/jenkins/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/jenkins/"
>
onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide.link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/DoneNextSteps.tsx b/server/sonar-web/src/main/js/components/tutorials/other/DoneNextSteps.tsx
index 292bdc4387e..920b2695ee5 100644
--- a/server/sonar-web/src/main/js/components/tutorials/other/DoneNextSteps.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/other/DoneNextSteps.tsx
@@ -21,7 +21,7 @@ import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { translate } from '../../../helpers/l10n';
import { Component } from '../../../types/types';
-import Link from '../../common/Link';
+import DocLink from '../../common/DocLink';
export interface DoneNextStepsProps {
component: Component;
@@ -51,24 +51,18 @@ export default function DoneNextSteps({ component }: DoneNextStepsProps) {
id="onboarding.analysis.auto_refresh_after_analysis.check_these_links"
values={{
link_branches: (
- <Link
- to="/documentation/branches/overview/"
- target="_blank"
- rel="noopener noreferrer">
+ <DocLink to="/branches/overview/">
{translate(
'onboarding.analysis.auto_refresh_after_analysis.check_these_links.branches'
)}
- </Link>
+ </DocLink>
),
link_pr_analysis: (
- <Link
- to="/documentation/analysis/pull-request/"
- target="_blank"
- rel="noopener noreferrer">
+ <DocLink to="/analysis/pull-request/">
{translate(
'onboarding.analysis.auto_refresh_after_analysis.check_these_links.pr_analysis'
)}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/TokenStep.tsx b/server/sonar-web/src/main/js/components/tutorials/other/TokenStep.tsx
index d4ae7963b23..f28be6ea39f 100644
--- a/server/sonar-web/src/main/js/components/tutorials/other/TokenStep.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/other/TokenStep.tsx
@@ -214,7 +214,7 @@ export default class TokenStep extends React.PureComponent<Props, State> {
content={translate('onboarding.token.name.help')}
links={[
{
- href: '/documentation/user-guide/user-token/',
+ href: '/user-guide/user-token/',
label: translate('learn_more')
}
]}
@@ -282,7 +282,7 @@ export default class TokenStep extends React.PureComponent<Props, State> {
content={translate('onboarding.token.use_existing_token.help')}
links={[
{
- href: '/documentation/user-guide/user-token/',
+ href: '/user-guide/user-token/',
label: translate('learn_more')
}
]}
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/__tests__/__snapshots__/DoneNextSteps-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/other/__tests__/__snapshots__/DoneNextSteps-test.tsx.snap
index c5c553d1340..61cea6b709b 100644
--- a/server/sonar-web/src/main/js/components/tutorials/other/__tests__/__snapshots__/DoneNextSteps-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/tutorials/other/__tests__/__snapshots__/DoneNextSteps-test.tsx.snap
@@ -25,20 +25,16 @@ exports[`should render correctly: default 1`] = `
id="onboarding.analysis.auto_refresh_after_analysis.check_these_links"
values={
Object {
- "link_branches": <ForwardRef(Link)
- rel="noopener noreferrer"
- target="_blank"
- to="/documentation/branches/overview/"
+ "link_branches": <withAppStateContext(DocLink)
+ to="/branches/overview/"
>
onboarding.analysis.auto_refresh_after_analysis.check_these_links.branches
- </ForwardRef(Link)>,
- "link_pr_analysis": <ForwardRef(Link)
- rel="noopener noreferrer"
- target="_blank"
- to="/documentation/analysis/pull-request/"
+ </withAppStateContext(DocLink)>,
+ "link_pr_analysis": <withAppStateContext(DocLink)
+ to="/analysis/pull-request/"
>
onboarding.analysis.auto_refresh_after_analysis.check_these_links.pr_analysis
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
@@ -71,20 +67,16 @@ exports[`should render correctly: project admin 1`] = `
id="onboarding.analysis.auto_refresh_after_analysis.check_these_links"
values={
Object {
- "link_branches": <ForwardRef(Link)
- rel="noopener noreferrer"
- target="_blank"
- to="/documentation/branches/overview/"
+ "link_branches": <withAppStateContext(DocLink)
+ to="/branches/overview/"
>
onboarding.analysis.auto_refresh_after_analysis.check_these_links.branches
- </ForwardRef(Link)>,
- "link_pr_analysis": <ForwardRef(Link)
- rel="noopener noreferrer"
- target="_blank"
- to="/documentation/analysis/pull-request/"
+ </withAppStateContext(DocLink)>,
+ "link_pr_analysis": <withAppStateContext(DocLink)
+ to="/analysis/pull-request/"
>
onboarding.analysis.auto_refresh_after_analysis.check_these_links.pr_analysis
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/__tests__/__snapshots__/TokenStep-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/other/__tests__/__snapshots__/TokenStep-test.tsx.snap
index e0696eebd28..ff1c2346c08 100644
--- a/server/sonar-web/src/main/js/components/tutorials/other/__tests__/__snapshots__/TokenStep-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/tutorials/other/__tests__/__snapshots__/TokenStep-test.tsx.snap
@@ -50,7 +50,7 @@ exports[`generates token 1`] = `
links={
Array [
Object {
- "href": "/documentation/user-guide/user-token/",
+ "href": "/user-guide/user-token/",
"label": "learn_more",
},
]
@@ -210,7 +210,7 @@ exports[`generates token 2`] = `
links={
Array [
Object {
- "href": "/documentation/user-guide/user-token/",
+ "href": "/user-guide/user-token/",
"label": "learn_more",
},
]
@@ -582,7 +582,7 @@ exports[`revokes token 3`] = `
links={
Array [
Object {
- "href": "/documentation/user-guide/user-token/",
+ "href": "/user-guide/user-token/",
"label": "learn_more",
},
]
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetExecute.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetExecute.tsx
index 2a97d7cb8b2..958f2ca6aaa 100644
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetExecute.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetExecute.tsx
@@ -22,8 +22,8 @@ import { FormattedMessage } from 'react-intl';
import { translate } from '../../../../helpers/l10n';
import { Component } from '../../../../types/types';
import CodeSnippet from '../../../common/CodeSnippet';
+import DocLink from '../../../common/DocLink';
import InstanceMessage from '../../../common/InstanceMessage';
-import Link from '../../../common/Link';
import DoneNextSteps from '../DoneNextSteps';
export interface DotNetExecuteProps {
@@ -50,9 +50,9 @@ export default function DotNetExecute({ commands, component }: DotNetExecuteProp
id="onboarding.analysis.docs"
values={{
link: (
- <Link to="/documentation/analysis/scan/sonarscanner-for-msbuild/" target="_blank">
+ <DocLink to="/analysis/scan/sonarscanner-for-msbuild/">
{translate('onboarding.analysis.msbuild.docs_link')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/ExecBuildWrapper.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/ExecBuildWrapper.tsx
index 8d752b03e12..9bc2bfe920c 100644
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/ExecBuildWrapper.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/other/commands/ExecBuildWrapper.tsx
@@ -21,7 +21,7 @@ import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { translate } from '../../../../helpers/l10n';
import CodeSnippet from '../../../common/CodeSnippet';
-import Link from '../../../common/Link';
+import DocLink from '../../../common/DocLink';
import { OSs } from '../../types';
export interface ExecBuildWrapperProps {
@@ -56,9 +56,9 @@ export default function ExecBuildWrapper(props: ExecBuildWrapperProps) {
id="onboarding.analysis.build_wrapper.docs"
values={{
link: (
- <Link to="/documentation/analysis/languages/cfamily/" target="_blank">
+ <DocLink to="/analysis/languages/cfamily/">
{translate('onboarding.analysis.build_wrapper.docs_link')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/ExecScanner.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/ExecScanner.tsx
index c1d2c035f18..067af232fd2 100644
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/ExecScanner.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/other/commands/ExecScanner.tsx
@@ -22,8 +22,8 @@ import { FormattedMessage } from 'react-intl';
import { translate } from '../../../../helpers/l10n';
import { Component } from '../../../../types/types';
import CodeSnippet from '../../../common/CodeSnippet';
+import DocLink from '../../../common/DocLink';
import InstanceMessage from '../../../common/InstanceMessage';
-import Link from '../../../common/Link';
import { OSs } from '../../types';
import { quote } from '../../utils';
import DoneNextSteps from '../DoneNextSteps';
@@ -65,9 +65,9 @@ export default function ExecScanner(props: ExecScannerProps) {
id="onboarding.analysis.sq_scanner.docs"
values={{
link: (
- <Link to="/documentation/analysis/scan/sonarscanner/" target="_blank">
+ <DocLink to="/analysis/scan/sonarscanner/">
{translate('onboarding.analysis.sq_scanner.docs_link')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/JavaGradle.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/JavaGradle.tsx
index afe3ed0030d..85a191cf74a 100644
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/JavaGradle.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/other/commands/JavaGradle.tsx
@@ -22,8 +22,8 @@ import { FormattedMessage } from 'react-intl';
import { translate } from '../../../../helpers/l10n';
import { Component } from '../../../../types/types';
import CodeSnippet from '../../../common/CodeSnippet';
+import DocLink from '../../../common/DocLink';
import InstanceMessage from '../../../common/InstanceMessage';
-import Link from '../../../common/Link';
import DoneNextSteps from '../DoneNextSteps';
export interface JavaGradleProps {
@@ -68,9 +68,7 @@ export default function JavaGradle(props: JavaGradleProps) {
id="onboarding.analysis.java.gradle.latest_version"
values={{
link: (
- <Link to="/documentation/analysis/scan/sonarscanner-for-gradle/" target="_blank">
- {translate('here')}
- </Link>
+ <DocLink to="/analysis/scan/sonarscanner-for-gradle/">{translate('here')}</DocLink>
)
}}
/>
@@ -86,9 +84,9 @@ export default function JavaGradle(props: JavaGradleProps) {
id="onboarding.analysis.docs"
values={{
link: (
- <Link to="/documentation/analysis/scan/sonarscanner-for-gradle/" target="_blank">
+ <DocLink to="/analysis/scan/sonarscanner-for-gradle/">
{translate('onboarding.analysis.java.gradle.docs_link')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/JavaMaven.tsx b/server/sonar-web/src/main/js/components/tutorials/other/commands/JavaMaven.tsx
index 5a939f2a36c..473f99d17ac 100644
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/JavaMaven.tsx
+++ b/server/sonar-web/src/main/js/components/tutorials/other/commands/JavaMaven.tsx
@@ -22,8 +22,8 @@ import { FormattedMessage } from 'react-intl';
import { translate } from '../../../../helpers/l10n';
import { Component } from '../../../../types/types';
import CodeSnippet from '../../../common/CodeSnippet';
+import DocLink from '../../../common/DocLink';
import InstanceMessage from '../../../common/InstanceMessage';
-import Link from '../../../common/Link';
import DoneNextSteps from '../DoneNextSteps';
export interface JavaMavenProps {
@@ -54,9 +54,9 @@ export default function JavaMaven(props: JavaMavenProps) {
id="onboarding.analysis.docs"
values={{
link: (
- <Link to="/documentation/analysis/scan/sonarscanner-for-maven/" target="_blank">
+ <DocLink to="/analysis/scan/sonarscanner-for-maven/">
{translate('onboarding.analysis.java.maven.docs_link')}
- </Link>
+ </DocLink>
)
}}
/>
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/DotNetExecute-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/DotNetExecute-test.tsx.snap
index 8c2722936e3..03cd7a29122 100644
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/DotNetExecute-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/DotNetExecute-test.tsx.snap
@@ -28,12 +28,11 @@ exports[`should render correctly 1`] = `
id="onboarding.analysis.docs"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/scan/sonarscanner-for-msbuild/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/scan/sonarscanner-for-msbuild/"
>
onboarding.analysis.msbuild.docs_link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/ExecBuildWrapper-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/ExecBuildWrapper-test.tsx.snap
index 4060e8cf706..378ca7b16c0 100644
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/ExecBuildWrapper-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/ExecBuildWrapper-test.tsx.snap
@@ -23,12 +23,11 @@ exports[`Shoud renders for "linux" correctly 1`] = `
id="onboarding.analysis.build_wrapper.docs"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/languages/cfamily/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/languages/cfamily/"
>
onboarding.analysis.build_wrapper.docs_link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
@@ -59,12 +58,11 @@ exports[`Shoud renders for "mac" correctly 1`] = `
id="onboarding.analysis.build_wrapper.docs"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/languages/cfamily/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/languages/cfamily/"
>
onboarding.analysis.build_wrapper.docs_link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
@@ -95,12 +93,11 @@ exports[`Shoud renders for "win" correctly 1`] = `
id="onboarding.analysis.build_wrapper.docs"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/languages/cfamily/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/languages/cfamily/"
>
onboarding.analysis.build_wrapper.docs_link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/ExecScanner-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/ExecScanner-test.tsx.snap
index b4b780f819f..ef9958ca68a 100644
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/ExecScanner-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/ExecScanner-test.tsx.snap
@@ -33,12 +33,11 @@ exports[`should render correctly for "linux" 1`] = `
id="onboarding.analysis.sq_scanner.docs"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/scan/sonarscanner/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/scan/sonarscanner/"
>
onboarding.analysis.sq_scanner.docs_link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
@@ -103,12 +102,11 @@ exports[`should render correctly for "mac" 1`] = `
id="onboarding.analysis.sq_scanner.docs"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/scan/sonarscanner/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/scan/sonarscanner/"
>
onboarding.analysis.sq_scanner.docs_link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
@@ -173,12 +171,11 @@ exports[`should render correctly for "win" 1`] = `
id="onboarding.analysis.sq_scanner.docs"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/scan/sonarscanner/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/scan/sonarscanner/"
>
onboarding.analysis.sq_scanner.docs_link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
@@ -243,12 +240,11 @@ exports[`should render correctly for cfamily 1`] = `
id="onboarding.analysis.sq_scanner.docs"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/scan/sonarscanner/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/scan/sonarscanner/"
>
onboarding.analysis.sq_scanner.docs_link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
@@ -313,12 +309,11 @@ exports[`should render correctly for remote execution 1`] = `
id="onboarding.analysis.sq_scanner.docs"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/scan/sonarscanner/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/scan/sonarscanner/"
>
onboarding.analysis.sq_scanner.docs_link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap
index a980bc7303e..3356e83af9e 100644
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap
@@ -28,12 +28,11 @@ exports[`renders correctly 1`] = `
id="onboarding.analysis.java.gradle.latest_version"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/scan/sonarscanner-for-gradle/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/scan/sonarscanner-for-gradle/"
>
here
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
@@ -62,12 +61,11 @@ exports[`renders correctly 1`] = `
id="onboarding.analysis.docs"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/scan/sonarscanner-for-gradle/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/scan/sonarscanner-for-gradle/"
>
onboarding.analysis.java.gradle.docs_link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap
index f91c2cc29cc..c004deea92a 100644
--- a/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap
+++ b/server/sonar-web/src/main/js/components/tutorials/other/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap
@@ -32,12 +32,11 @@ exports[`renders correctly 1`] = `
id="onboarding.analysis.docs"
values={
Object {
- "link": <ForwardRef(Link)
- target="_blank"
- to="/documentation/analysis/scan/sonarscanner-for-maven/"
+ "link": <withAppStateContext(DocLink)
+ to="/analysis/scan/sonarscanner-for-maven/"
>
onboarding.analysis.java.maven.docs_link
- </ForwardRef(Link)>,
+ </withAppStateContext(DocLink)>,
}
}
/>
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/markdown-test.ts.snap b/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/markdown-test.ts.snap
deleted file mode 100644
index cdc1f9a74e0..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/__snapshots__/markdown-test.ts.snap
+++ /dev/null
@@ -1,41 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should cut sonarqube/sonarcloud/static content 1`] = `
-"
-This text has inline text for SonarQube. Donec sed nulla magna.
-
-This is text for SonarQube, multi-line. Consectetur adipiscing elit. Duis dignissim nulla at massa iaculis interdum.
-Aenean sit amet lacus a tortor ullamcorper interdum. Donec sed nulla magna.
-
-
-
-
-
-This is text for SonarQube, single line.
-
-* In hac habitasse
-* Duis sagittis semper sapien nec tempor
-* This is a bullet point for SonarQube
-
-* Platea dictumst
-
-Duis sagittis semper sapien nec tempor. Nullam vehicula nisi vitae nisi interdum aliquam.
-
-| Parameter Name | Description |
-| --------------------- | ------------------ |
-| sonar.pullrequest.github.repository | SLUG of the GitHub Repo |
-| sonar.pullrequest.github.endpoint | The API url for your GitHub instance. |
-"
-`;
-
-exports[`should not break when conditional tags are misused 1`] = `
-"Random SC text
- Break
- Bad SQ conditional formatting
- Break
- SC text
- Break
- Bad SQ conditional formatting
- Break
- Static stuff"
-`;
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/markdown-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/markdown-test.ts
deleted file mode 100644
index 5c74c9f20ab..00000000000
--- a/server/sonar-web/src/main/js/helpers/__tests__/markdown-test.ts
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-/* eslint-disable no-console */
-import { filterContent, getFrontMatter, separateFrontMatter } from '../markdown';
-
-jest.mock('../system', () => ({
- getInstance: () => 'SonarQube'
-}));
-
-it('returns parsed frontmatter of one item', () => {
- expect(
- getFrontMatter(`
- ---
- title: Foo
- ---
-
- some content here
- `)
- ).toEqual({ title: 'Foo' });
-});
-
-it('returns parsed frontmatter of two items', () => {
- expect(
- getFrontMatter(`
- ---
- title: Foo
- scope: sonarcloud
- ---
-
- some content here
- `)
- ).toEqual({ title: 'Foo', scope: 'sonarcloud' });
-});
-
-it('returns empty object when frontmatter is missing', () => {
- expect(
- getFrontMatter(`
- some content here
- `)
- ).toEqual({});
-});
-
-it('returns empty object when frontmatter is unfinished', () => {
- expect(
- getFrontMatter(`
- ---
- title: Foo
-
- some content here
- `)
- ).toEqual({});
-});
-
-it('ignores frontmatter in wrong format', () => {
- expect(
- getFrontMatter(`
- ---
- title: Foo
- scope: sonarcloud: sonarqube
- ---
-
- some content here
- `)
- ).toEqual({ title: 'Foo' });
-});
-
-it('returns parsed frontmatter and the rest of the content', () => {
- expect(
- separateFrontMatter(`
----
-title: Foo
----
-
-some content here`)
- ).toEqual({ content: '\nsome content here', frontmatter: { title: 'Foo' } });
-});
-
-it('returns empty object and content when frontmatter is missing', () => {
- expect(separateFrontMatter('some content here')).toEqual({
- content: 'some content here',
- frontmatter: {}
- });
-});
-
-it('returns full content when frontmatter has bad formatting', () => {
- const content = `
- ----
- title: Foo
- scope: sonarcloud
- ---
-
- some content here`;
-
- expect(separateFrontMatter(content)).toEqual({ content, frontmatter: {} });
-});
-
-it('replaces {instance}', () => {
- expect(
- filterContent('This is {instance} content. It replaces all {instance}{instance} messages')
- ).toBe('This is SonarQube content. It replaces all SonarQubeSonarQube messages');
-});
-
-it('should cut sonarqube/sonarcloud/static content', () => {
- const content = `
-This text has inline text for <!-- sonarqube -->SonarQube<!-- /sonarqube --><!-- sonarcloud -->SonarCloud<!-- /sonarcloud -->. Donec sed nulla magna.
-
-<!-- sonarqube -->
-This is text for SonarQube, multi-line. Consectetur adipiscing elit. Duis dignissim nulla at massa iaculis interdum.
-Aenean sit amet lacus a tortor ullamcorper interdum. Donec sed nulla magna.
-<!-- /sonarqube -->
-
-<!-- sonarcloud -->
-This is text for SonarCloud, multi-line. In hac habitasse platea dictumst. Duis sagittis semper sapien nec tempor. Nullam vehicula nisi vitae nisi interdum aliquam. Mauris volutpat nunc non fermentum rhoncus. Aenean laoreet, orci vitae tempor bibendum,
-metus nisl euismod neque, vitae euismod nibh nisl eu velit. Vivamus luctus suscipit elit vel semper.
-<!-- /sonarcloud -->
-
-<!-- static -->
-This is static text.
-<!-- /static -->
-
-<!-- sonarqube -->
-This is text for SonarQube, single line.
-<!-- /sonarqube -->
-
-* In hac habitasse
-* Duis sagittis semper sapien nec tempor
-<!-- sonarqube -->* This is a bullet point for SonarQube<!-- /sonarqube -->
-<!-- sonarcloud -->* This is a bullet point for SonarCloud<!-- /sonarcloud -->
-* Platea dictumst
-
-Duis sagittis semper sapien nec tempor. Nullam vehicula nisi vitae nisi interdum aliquam.
-
-| Parameter Name | Description |
-| --------------------- | ------------------ |
-| sonar.pullrequest.github.repository | SLUG of the GitHub Repo |
-<!-- sonarqube -->
-| sonar.pullrequest.github.endpoint | The API url for your GitHub instance. |
-<!-- /sonarqube -->
-`;
-
- expect(filterContent(content)).toMatchSnapshot();
-});
-
-it('should not break when conditional tags are misused', () => {
- const originalConsoleError = console.error;
- console.error = jest.fn();
-
- const content = `Random <!-- /sonarqube -->SC <!-- sonarqube -->text
- Break
- Bad <!-- /sonarcloud -->SQ conditional <!-- sonarcloud -->formatting
- Break
- <!-- sonarqube -->SC<!-- /sonarqube --><!-- sonarcloud -->SQ<!-- /sonarcloud --> text
- Break
- Bad <!-- /sonarcloud -->SQ conditional <!-- sonarcloud -->formatting
- Break
- <!-- static -->Static <!-- /sonarcloud -->stuff`;
- expect(filterContent(content)).toMatchSnapshot();
- expect(console.error).toHaveBeenCalledTimes(2);
-
- console.error = originalConsoleError;
-});
diff --git a/server/sonar-web/src/main/js/helpers/constants.ts b/server/sonar-web/src/main/js/helpers/constants.ts
index 9da9a03c8e9..0f73991916f 100644
--- a/server/sonar-web/src/main/js/helpers/constants.ts
+++ b/server/sonar-web/src/main/js/helpers/constants.ts
@@ -57,11 +57,11 @@ export const RATING_COLORS = [
export const PROJECT_KEY_MAX_LEN = 400;
export const ALM_DOCUMENTATION_PATHS = {
- [AlmKeys.Azure]: '/documentation/analysis/azuredevops-integration/',
- [AlmKeys.BitbucketServer]: '/documentation/analysis/bitbucket-integration/',
- [AlmKeys.BitbucketCloud]: '/documentation/analysis/bitbucket-cloud-integration/',
- [AlmKeys.GitHub]: '/documentation/analysis/github-integration/',
- [AlmKeys.GitLab]: '/documentation/analysis/gitlab-integration/'
+ [AlmKeys.Azure]: '/analysis/azuredevops-integration/',
+ [AlmKeys.BitbucketServer]: '/analysis/bitbucket-integration/',
+ [AlmKeys.BitbucketCloud]: '/analysis/bitbucket-cloud-integration/',
+ [AlmKeys.GitHub]: '/analysis/github-integration/',
+ [AlmKeys.GitLab]: '/analysis/gitlab-integration/'
};
export const IMPORT_COMPATIBLE_ALMS = [
diff --git a/server/sonar-web/src/main/js/helpers/markdown.d.ts b/server/sonar-web/src/main/js/helpers/docs.ts
index 629a797df71..6bae9f6f56b 100644
--- a/server/sonar-web/src/main/js/helpers/markdown.d.ts
+++ b/server/sonar-web/src/main/js/helpers/docs.ts
@@ -17,18 +17,14 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-interface FrontMatter {
- [x: string]: string;
-}
-
-interface ParsedContent {
- content: string;
- frontmatter: FrontMatter;
-}
-export function getFrontMatter(content: string): FrontMatter;
+const VERSION_PARSER = /^(\d+\.\d+).*$/;
-export function separateFrontMatter(content: string): ParsedContent;
+export function getUrlForDoc(version: string, to: string) {
+ const versionPrefix = VERSION_PARSER.exec(version);
+ const isSnapshot = version.indexOf('SNAPSHOT') !== -1;
+ const docPrefix =
+ versionPrefix && versionPrefix.length === 2 && !isSnapshot ? versionPrefix[1] : 'latest';
-/** Removes SonarQube/SonarCloud only content */
-export function filterContent(content: string): string;
+ return `https://docs.sonarqube.org/${docPrefix}${to}`;
+}
diff --git a/server/sonar-web/src/main/js/helpers/markdown.js b/server/sonar-web/src/main/js/helpers/markdown.js
deleted file mode 100644
index 6701d972642..00000000000
--- a/server/sonar-web/src/main/js/helpers/markdown.js
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-// keep this file in JavaScript, because it is used by a webpack loader
-module.exports = { getFrontMatter, separateFrontMatter, filterContent };
-
-function getFrontMatter(content) {
- const lines = content.split('\n');
- const position = getFrontMatterPosition(lines);
- return position ? parseFrontMatter(lines.slice(position.firstLine + 1, position.lastLine)) : {};
-}
-
-function separateFrontMatter(content) {
- const lines = content.split('\n');
- const position = getFrontMatterPosition(lines);
- if (position) {
- const frontmatter = parseFrontMatter(lines.slice(position.firstLine + 1, position.lastLine));
- const content = lines.slice(position.lastLine + 1).join('\n');
- return { frontmatter, content };
- }
- return { frontmatter: {}, content };
-}
-
-function getFrontMatterPosition(lines) {
- let firstLine;
- let lastLine;
- for (let i = 0; i < lines.length; i++) {
- const line = lines[i];
- if (line.trim() === '---') {
- if (firstLine === undefined) {
- firstLine = i;
- } else {
- lastLine = i;
- break;
- }
- }
- }
- return lastLine !== undefined ? { firstLine, lastLine } : undefined;
-}
-
-function parseFrontMatter(lines) {
- const data = {};
- for (const element of lines) {
- const tokens = element.split(':').map(x => x.trim());
- if (tokens.length === 2) {
- data[tokens[0]] = tokens[1];
- }
- }
- return data;
-}
-
-/**
- * @param {string} content
- * @returns {string}
- */
-function filterContent(content) {
- const regexBase = '<!-- \\/?(sonarqube|sonarcloud|static) -->';
- const { getInstance } = require('./system');
- const contentWithInstance = content.replace(/{instance}/gi, getInstance());
- const contentWithoutStatic = cutConditionalContent(contentWithInstance, 'static');
- const filteredContent = cutConditionalContent(contentWithoutStatic, 'sonarcloud');
- return filteredContent
- .replace(new RegExp(`^${regexBase}(\n|\r|\r\n|$)`, 'gm'), '') // First, remove single-line ones, including ending carriage-returns.
- .replace(new RegExp(`${regexBase}`, 'g'), ''); // Now remove all remaining ones.
-}
-
-/**
- * @param {string} content
- * @param {string} tag
- * @returns {string}
- */
-function cutConditionalContent(content, tag) {
- const beginning = `<!-- ${tag} -->`;
- const ending = `<!-- /${tag} -->`;
-
- let newContent = content;
- let start = newContent.indexOf(beginning);
- let end = newContent.indexOf(ending);
- while (start !== -1 && end !== -1) {
- if (start < end) {
- newContent = newContent.substring(0, start) + newContent.substring(end + ending.length);
- } else {
- // When conditional tags are incorrectly used we log an error, strip them out and pass to the next pair of tags
- // eslint-disable-next-line no-console
- console.error(
- new Error(
- `Documentation - incorrect usage of conditional formatting tags here: "${newContent.substring(
- end,
- start + beginning.length
- )}"`
- )
- );
- newContent =
- newContent.substring(0, end) +
- newContent.substring(end + ending.length, start) +
- newContent.substring(start + beginning.length);
- }
- start = newContent.indexOf(beginning);
- end = newContent.indexOf(ending);
- }
-
- return newContent;
-}
diff --git a/server/sonar-web/src/main/js/helpers/testMocks.ts b/server/sonar-web/src/main/js/helpers/testMocks.ts
index 0f89329fe9f..d089cfcd86a 100644
--- a/server/sonar-web/src/main/js/helpers/testMocks.ts
+++ b/server/sonar-web/src/main/js/helpers/testMocks.ts
@@ -19,7 +19,6 @@
*/
import { To } from 'react-router-dom';
import { RuleDescriptionSections } from '../apps/coding-rules/rule';
-import { DocumentationEntry } from '../apps/documentation/utils';
import { Exporter, Profile } from '../apps/quality-profiles/types';
import { Location, Router } from '../components/hoc/withRouter';
import { AppState } from '../types/appstate';
@@ -652,20 +651,6 @@ ${overrides.key ? 'key: ' + overrides.key : ''}
${content}`;
}
-export function mockDocumentationEntry(
- overrides: Partial<DocumentationEntry> = {}
-): DocumentationEntry {
- return {
- content: 'Lorem ipsum dolor sit amet fredum',
- relativeName: 'Lorem',
- navTitle: undefined,
- text: 'Lorem ipsum dolor sit amet fredum',
- title: 'Lorem',
- url: '/lorem/ipsum',
- ...overrides
- };
-}
-
export function mockLanguage(overrides: Partial<Language> = {}): Language {
return {
key: 'css',
diff --git a/server/sonar-web/tsconfig.json b/server/sonar-web/tsconfig.json
index 1537162d60d..99489bfd95e 100644
--- a/server/sonar-web/tsconfig.json
+++ b/server/sonar-web/tsconfig.json
@@ -3,7 +3,6 @@
"compilerOptions": {
"baseUrl": ".",
"paths": {
- "Docs/*": ["../sonar-docs/src/*"],
"*": ["./src/main/js/@types/*"]
}
},
diff --git a/server/sonar-web/yarn.lock b/server/sonar-web/yarn.lock
index cd5e871033a..f0c738bd016 100644
--- a/server/sonar-web/yarn.lock
+++ b/server/sonar-web/yarn.lock
@@ -1401,15 +1401,6 @@ __metadata:
languageName: node
linkType: hard
-"@mapbox/hast-util-table-cell-style@npm:^0.1.3":
- version: 0.1.3
- resolution: "@mapbox/hast-util-table-cell-style@npm:0.1.3"
- dependencies:
- unist-util-visit: ^1.3.0
- checksum: 4e563a274ae54bfb15f7d12fb711bbfc9579ff2704149cc8dddbc36b3d007a1cdefa993462c767b6b3da5d392b848680e9cc466b282ed9df8f16b23df685062c
- languageName: node
- linkType: hard
-
"@nodelib/fs.scandir@npm:2.1.4":
version: 2.1.4
resolution: "@nodelib/fs.scandir@npm:2.1.4"
@@ -2077,15 +2068,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/mdast@npm:^3.0.3":
- version: 3.0.3
- resolution: "@types/mdast@npm:3.0.3"
- dependencies:
- "@types/unist": "*"
- checksum: 5318624af815ac531e49de06da1d9458f1570f87274dced00353a240b2d2c4260f1fdd40c5e65784e4a4f49b0c5eb43f77faee60def723b501880ab3747b9916
- languageName: node
- linkType: hard
-
"@types/minimatch@npm:*":
version: 3.0.3
resolution: "@types/minimatch@npm:3.0.3"
@@ -2227,13 +2209,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/unist@npm:*, @types/unist@npm:^2.0.0, @types/unist@npm:^2.0.2, @types/unist@npm:^2.0.3":
- version: 2.0.3
- resolution: "@types/unist@npm:2.0.3"
- checksum: 4427306b094561da28164e7e5250c4e6b382cb8eac40bf7e6bb0ff1e6e00c13e47aaf32e4a08fc8ba54602d07f79a39fb9ba304cc9dc886b1e3caf824649edbd
- languageName: node
- linkType: hard
-
"@types/valid-url@npm:1.0.3":
version: 1.0.3
resolution: "@types/valid-url@npm:1.0.3"
@@ -2513,7 +2488,6 @@ __metadata:
jsdom: 19.0.0
lodash: 4.17.21
lunr: 2.3.9
- mdast-util-toc: 5.0.2
path-browserify: 1.0.1
postcss-calc: 7.0.2
postcss-custom-properties: 9.1.1
@@ -2530,16 +2504,8 @@ __metadata:
react-select-event: 5.5.1
react-virtualized: 9.22.3
regenerator-runtime: 0.13.9
- rehype-raw: 4.0.2
- rehype-react: 5.0.0
- rehype-slug: 3.0.0
- remark: 11.0.2
- remark-custom-blocks: 2.5.1
- remark-react: 7.0.1
- remark-rehype: 6.0.0
testing-library-selector: 0.2.1
typescript: 4.8.4
- unist-util-visit: 2.0.2
valid-url: 1.0.9
whatwg-fetch: 3.6.2
languageName: unknown
@@ -3083,13 +3049,6 @@ __metadata:
languageName: node
linkType: hard
-"bail@npm:^1.0.0":
- version: 1.0.5
- resolution: "bail@npm:1.0.5"
- checksum: 6c334940d7eaa4e656a12fb12407b6555649b6deb6df04270fa806e0da82684ebe4a4e47815b271c794b40f8d6fa286e0c248b14ddbabb324a917fab09b7301a
- languageName: node
- linkType: hard
-
"balanced-match@npm:^1.0.0":
version: 1.0.0
resolution: "balanced-match@npm:1.0.0"
@@ -3282,13 +3241,6 @@ __metadata:
languageName: node
linkType: hard
-"ccount@npm:^1.0.0, ccount@npm:^1.0.3":
- version: 1.0.5
- resolution: "ccount@npm:1.0.5"
- checksum: 231f463a6de16367587740ae8a8a9dd9bbbd4048fae0d93b8b181e6ce6c936b4d376d7629e2b7194434e1102c8ac7809de9c612c00cfb8f0f4575bf16ccd5ae8
- languageName: node
- linkType: hard
-
"chalk@npm:4.1.2, chalk@npm:^4.1.0":
version: 4.1.2
resolution: "chalk@npm:4.1.2"
@@ -3337,34 +3289,6 @@ __metadata:
languageName: node
linkType: hard
-"character-entities-html4@npm:^1.0.0":
- version: 1.1.4
- resolution: "character-entities-html4@npm:1.1.4"
- checksum: 22536aba07a378a2326420423ceadd65c0121032c527f80e84dfc648381992ed5aa666d7c2b267cd269864b3682d5b0315fc2f03a9e7c017d1a96d24ec292d5f
- languageName: node
- linkType: hard
-
-"character-entities-legacy@npm:^1.0.0":
- version: 1.1.4
- resolution: "character-entities-legacy@npm:1.1.4"
- checksum: fe03a82c154414da3a0c8ab3188e4237ec68006cbcd681cf23c7cfb9502a0e76cd30ab69a2e50857ca10d984d57de3b307680fff5328ccd427f400e559c3a811
- languageName: node
- linkType: hard
-
-"character-entities@npm:^1.0.0":
- version: 1.2.4
- resolution: "character-entities@npm:1.2.4"
- checksum: e1545716571ead57beac008433c1ff69517cd8ca5b336889321c5b8ff4a99c29b65589a701e9c086cda8a5e346a67295e2684f6c7ea96819fe85cbf49bf8686d
- languageName: node
- linkType: hard
-
-"character-reference-invalid@npm:^1.0.0":
- version: 1.1.4
- resolution: "character-reference-invalid@npm:1.1.4"
- checksum: 20274574c70e05e2f81135f3b93285536bc8ff70f37f0809b0d17791a832838f1e49938382899ed4cb444e5bbd4314ca1415231344ba29f4222ce2ccf24fea0b
- languageName: node
- linkType: hard
-
"cheerio@npm:^1.0.0-rc.3":
version: 1.0.0-rc.3
resolution: "cheerio@npm:1.0.0-rc.3"
@@ -3483,20 +3407,6 @@ __metadata:
languageName: node
linkType: hard
-"collapse-white-space@npm:^1.0.0":
- version: 1.0.5
- resolution: "collapse-white-space@npm:1.0.5"
- checksum: 80b98d7d49f581280a9afb8da0df30793f25311ffe7b2e1212b7cb256ade1d0968cca0cab10ad25b6a558bcfd1d944d8f9b1fdd1f3d9aa51a37b8e0c0bb13d05
- languageName: node
- linkType: hard
-
-"collapse-white-space@npm:^1.0.2":
- version: 1.0.6
- resolution: "collapse-white-space@npm:1.0.6"
- checksum: 9673fb797952c5c888341435596c69388b22cd5560c8cd3f40edb72734a9c820f56a7c9525166bcb7068b5d5805372e6fd0c4b9f2869782ad070cb5d3faf26e7
- languageName: node
- linkType: hard
-
"collect-v8-coverage@npm:^1.0.0":
version: 1.0.0
resolution: "collect-v8-coverage@npm:1.0.0"
@@ -3552,13 +3462,6 @@ __metadata:
languageName: node
linkType: hard
-"comma-separated-tokens@npm:^1.0.0":
- version: 1.0.7
- resolution: "comma-separated-tokens@npm:1.0.7"
- checksum: 8cae1b00c560d409a5723157f1871d121e6542170546000284c8ebae4e8080fb001899e814c1148e54bca19a47d0dfd14c3d59d0f7348f9c29d393e5f1fa81b5
- languageName: node
- linkType: hard
-
"commander@npm:^2.19.0":
version: 2.20.0
resolution: "commander@npm:2.20.0"
@@ -4117,15 +4020,6 @@ __metadata:
languageName: node
linkType: hard
-"detab@npm:^2.0.0":
- version: 2.0.2
- resolution: "detab@npm:2.0.2"
- dependencies:
- repeat-string: ^1.5.4
- checksum: cc3b62365f9c09fa8c455f254de68046bcd6a32aa553f68528b1f8375cff4e3ff7075e98351345dafa9b83a88277354fae38332a494c27eed19f63116fbcdfa6
- languageName: node
- linkType: hard
-
"detect-newline@npm:^3.0.0":
version: 3.1.0
resolution: "detect-newline@npm:3.1.0"
@@ -4304,13 +4198,6 @@ __metadata:
languageName: node
linkType: hard
-"emoji-regex@npm:>=6.0.0 <=6.1.1":
- version: 6.1.1
- resolution: "emoji-regex@npm:6.1.1"
- checksum: 6c54300a743d0b7af6e52292508d4865945ac966572473b65fdf31b54d5e4d91a1a1d769ea89f541b4023aa0c8dd2a51697fd9d186a698faf2ff380d18e5a016
- languageName: node
- linkType: hard
-
"emoji-regex@npm:^8.0.0":
version: 8.0.0
resolution: "emoji-regex@npm:8.0.0"
@@ -5302,13 +5189,6 @@ __metadata:
languageName: node
linkType: hard
-"extend@npm:^3.0.0, extend@npm:^3.0.2":
- version: 3.0.2
- resolution: "extend@npm:3.0.2"
- checksum: a50a8309ca65ea5d426382ff09f33586527882cf532931cb08ca786ea3146c0553310bda688710ff61d7668eba9f96b923fe1420cdf56a2c3eaf30fcab87b515
- languageName: node
- linkType: hard
-
"fast-deep-equal@npm:^3.1.1":
version: 3.1.1
resolution: "fast-deep-equal@npm:3.1.1"
@@ -5709,15 +5589,6 @@ __metadata:
languageName: node
linkType: hard
-"github-slugger@npm:^1.1.1, github-slugger@npm:^1.2.1":
- version: 1.3.0
- resolution: "github-slugger@npm:1.3.0"
- dependencies:
- emoji-regex: ">=6.0.0 <=6.1.1"
- checksum: fe96b363df9363c78bd2f644697e2ce2a05b1b10391ac0ff918a433992b03d0dcb0b6903b1f44bee972616eb5d8799837f357cbe278fb35c5fef40b69316a8d8
- languageName: node
- linkType: hard
-
"glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2":
version: 5.1.2
resolution: "glob-parent@npm:5.1.2"
@@ -5968,125 +5839,6 @@ __metadata:
languageName: node
linkType: hard
-"hast-to-hyperscript@npm:^7.0.0":
- version: 7.0.4
- resolution: "hast-to-hyperscript@npm:7.0.4"
- dependencies:
- comma-separated-tokens: ^1.0.0
- property-information: ^5.3.0
- space-separated-tokens: ^1.0.0
- style-to-object: ^0.2.1
- unist-util-is: ^3.0.0
- web-namespaces: ^1.1.2
- checksum: b7ce1549dfed58563e849b76b3af8e5cda3141793a5f31c0207cc7fe3234f6b1e63baf7528f1bd53b7826422dd403f212aabb2e54be901fdfb8070b36f750c92
- languageName: node
- linkType: hard
-
-"hast-to-hyperscript@npm:^8.0.0":
- version: 8.0.0
- resolution: "hast-to-hyperscript@npm:8.0.0"
- dependencies:
- comma-separated-tokens: ^1.0.0
- property-information: ^5.0.0
- space-separated-tokens: ^1.0.0
- style-to-object: ^0.3.0
- unist-util-is: ^4.0.0
- web-namespaces: ^1.0.0
- checksum: cf6d4cb2ebe7d9e20aca761fd2c281798043601b3a27b08b4d3db396f61c2c847c1f67a02bc819fa320b51c03e40701b0bfa266b1d93aa12ba6aa5e30029e174
- languageName: node
- linkType: hard
-
-"hast-util-from-parse5@npm:^5.0.0":
- version: 5.0.3
- resolution: "hast-util-from-parse5@npm:5.0.3"
- dependencies:
- ccount: ^1.0.3
- hastscript: ^5.0.0
- property-information: ^5.0.0
- web-namespaces: ^1.1.2
- xtend: ^4.0.1
- checksum: 31ecd040dd03bda38b8efbcb93ed95b19619bc8548da19973b6cdbb36302bc54c84662be345e6a4f3a53cf8b33956b502916e349871dc095802ca39cfe55040a
- languageName: node
- linkType: hard
-
-"hast-util-has-property@npm:^1.0.0":
- version: 1.0.4
- resolution: "hast-util-has-property@npm:1.0.4"
- checksum: 23025cee6692cf9aaf70a369248901deff0886c9bd2e2f0e81735c5f67ff500d1cfd991d3c236fc1d43e02b29d2db4075ee9fd2fe0aea1a7da261f19195046e8
- languageName: node
- linkType: hard
-
-"hast-util-is-element@npm:^1.0.0":
- version: 1.0.4
- resolution: "hast-util-is-element@npm:1.0.4"
- checksum: ca9dfce2a7dccff5e4d9d0b79c4fe4a7f98d3f07d819026718398809b171ee5f93587857005d40a23fc230588683a32f12eec1af8eb1e5f6093ac0c914fc4276
- languageName: node
- linkType: hard
-
-"hast-util-parse-selector@npm:^2.0.0":
- version: 2.2.4
- resolution: "hast-util-parse-selector@npm:2.2.4"
- checksum: 06e8b534626517929856877df116d95b46d384cc159595270c1e5b3af7404f20843065a1c675d60944445f7356c5c876ed10d5e2d66654b62fe06ecc8b423d45
- languageName: node
- linkType: hard
-
-"hast-util-raw@npm:^5.0.0":
- version: 5.0.2
- resolution: "hast-util-raw@npm:5.0.2"
- dependencies:
- hast-util-from-parse5: ^5.0.0
- hast-util-to-parse5: ^5.0.0
- html-void-elements: ^1.0.0
- parse5: ^5.0.0
- unist-util-position: ^3.0.0
- web-namespaces: ^1.0.0
- xtend: ^4.0.0
- zwitch: ^1.0.0
- checksum: 7d36fd990624315ce92f82ebda8b61c1e4b73e756205adfc8bcff9917990b678c90bc93b68ed414f9ee020c5f929f8967742c23c6bf46803f0d0f398af52590f
- languageName: node
- linkType: hard
-
-"hast-util-sanitize@npm:^2.0.0":
- version: 2.0.2
- resolution: "hast-util-sanitize@npm:2.0.2"
- dependencies:
- xtend: ^4.0.0
- checksum: 2fc7e03deb1724bca68d6764de614376cc40dda296a814f5d8a665865860907e62819f3f66a938f67986993c924aed630223f56d799b1ed6e5cda934daf7abd4
- languageName: node
- linkType: hard
-
-"hast-util-to-parse5@npm:^5.0.0":
- version: 5.1.2
- resolution: "hast-util-to-parse5@npm:5.1.2"
- dependencies:
- hast-to-hyperscript: ^7.0.0
- property-information: ^5.0.0
- web-namespaces: ^1.0.0
- xtend: ^4.0.0
- zwitch: ^1.0.0
- checksum: a37b58e48e741efef270bb90347799f0837b6e7e917c991e1874b804128d4d67e76461f741ae9b0d9a1bab829438129a3f77d55753404449b722595fa6677f4c
- languageName: node
- linkType: hard
-
-"hast-util-to-string@npm:^1.0.0":
- version: 1.0.3
- resolution: "hast-util-to-string@npm:1.0.3"
- checksum: 6e8621e716294040537d943db1aa93105dc99986cc9ead37a6d337b07a24ea7f4d1ab9269625edfa99ecfa0475607848ddbbef3b284bcf313968ba676cccb9d4
- languageName: node
- linkType: hard
-
-"hastscript@npm:^5.0.0":
- version: 5.1.2
- resolution: "hastscript@npm:5.1.2"
- dependencies:
- comma-separated-tokens: ^1.0.0
- hast-util-parse-selector: ^2.0.0
- property-information: ^5.0.0
- space-separated-tokens: ^1.0.0
- checksum: 662321af446f09c76d67af31d05823f382ce1e6c007828dc77f899f310cea682c00216b67c317a4ebe7f0c05e50552c4810d214e6ed4e95388f7b7d7fc93158f
- languageName: node
- linkType: hard
-
"history@npm:^5.2.0":
version: 5.3.0
resolution: "history@npm:5.3.0"
@@ -6148,13 +5900,6 @@ __metadata:
languageName: node
linkType: hard
-"html-void-elements@npm:^1.0.0":
- version: 1.0.5
- resolution: "html-void-elements@npm:1.0.5"
- checksum: 1a56f4f6cfbeb994c21701ff72b4b7f556fe784a70e5e554d1566ff775af83b91ea93f10664f039a67802d9f7b40d4a7f1ed20312bab47bd88d89bd792ea84ca
- languageName: node
- linkType: hard
-
"htmlparser2@npm:^3.9.1":
version: 3.10.1
resolution: "htmlparser2@npm:3.10.1"
@@ -6355,7 +6100,7 @@ __metadata:
languageName: node
linkType: hard
-"inherits@npm:2, inherits@npm:^2.0.0, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3":
+"inherits@npm:2, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3":
version: 2.0.4
resolution: "inherits@npm:2.0.4"
checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1
@@ -6369,13 +6114,6 @@ __metadata:
languageName: node
linkType: hard
-"inline-style-parser@npm:0.1.1":
- version: 0.1.1
- resolution: "inline-style-parser@npm:0.1.1"
- checksum: 5d545056a3e1f2bf864c928a886a0e1656a3517127d36917b973de581bd54adc91b4bf1febcb0da054f204b4934763f1a4e09308b4d55002327cf1d48ac5d966
- languageName: node
- linkType: hard
-
"internal-slot@npm:^1.0.3":
version: 1.0.3
resolution: "internal-slot@npm:1.0.3"
@@ -6436,30 +6174,6 @@ __metadata:
languageName: node
linkType: hard
-"is-alphabetical@npm:^1.0.0":
- version: 1.0.4
- resolution: "is-alphabetical@npm:1.0.4"
- checksum: 6508cce44fd348f06705d377b260974f4ce68c74000e7da4045f0d919e568226dc3ce9685c5a2af272195384df6930f748ce9213fc9f399b5d31b362c66312cb
- languageName: node
- linkType: hard
-
-"is-alphanumeric@npm:^1.0.0":
- version: 1.0.0
- resolution: "is-alphanumeric@npm:1.0.0"
- checksum: 2f4f4f227fe4cae977529f628021655edc172e1e5debfb3c30efd547f32e8d390c9bb7a71f3e9fea4187fe6598980072323d5a1b1abd3368379e33ba6504558c
- languageName: node
- linkType: hard
-
-"is-alphanumerical@npm:^1.0.0":
- version: 1.0.4
- resolution: "is-alphanumerical@npm:1.0.4"
- dependencies:
- is-alphabetical: ^1.0.0
- is-decimal: ^1.0.0
- checksum: e2e491acc16fcf5b363f7c726f666a9538dba0a043665740feb45bba1652457a73441e7c5179c6768a638ed396db3437e9905f403644ec7c468fb41f4813d03f
- languageName: node
- linkType: hard
-
"is-arrayish@npm:^0.2.1":
version: 0.2.1
resolution: "is-arrayish@npm:0.2.1"
@@ -6509,13 +6223,6 @@ __metadata:
languageName: node
linkType: hard
-"is-buffer@npm:^2.0.0":
- version: 2.0.4
- resolution: "is-buffer@npm:2.0.4"
- checksum: b1616ff40c1644e219d6038819044608e31edcc60eb287e5f214391222dea889a68c659f0654865ce34b6c4dcfa2c8cae0174343a0f6ae3f2150f7856326cb80
- languageName: node
- linkType: hard
-
"is-callable@npm:^1.1.4":
version: 1.1.4
resolution: "is-callable@npm:1.1.4"
@@ -6585,13 +6292,6 @@ __metadata:
languageName: node
linkType: hard
-"is-decimal@npm:^1.0.0, is-decimal@npm:^1.0.2":
- version: 1.0.4
- resolution: "is-decimal@npm:1.0.4"
- checksum: ed483a387517856dc395c68403a10201fddcc1b63dc56513fbe2fe86ab38766120090ecdbfed89223d84ca8b1cd28b0641b93cb6597b6e8f4c097a7c24e3fb96
- languageName: node
- linkType: hard
-
"is-extendable@npm:^0.1.0":
version: 0.1.1
resolution: "is-extendable@npm:0.1.1"
@@ -6654,13 +6354,6 @@ __metadata:
languageName: node
linkType: hard
-"is-hexadecimal@npm:^1.0.0":
- version: 1.0.4
- resolution: "is-hexadecimal@npm:1.0.4"
- checksum: a452e047587b6069332d83130f54d30da4faf2f2ebaa2ce6d073c27b5703d030d58ed9e0b729c8e4e5b52c6f1dab26781bb77b7bc6c7805f14f320e328ff8cd5
- languageName: node
- linkType: hard
-
"is-lambda@npm:^1.0.1":
version: 1.0.1
resolution: "is-lambda@npm:1.0.1"
@@ -6696,13 +6389,6 @@ __metadata:
languageName: node
linkType: hard
-"is-plain-obj@npm:^2.0.0":
- version: 2.1.0
- resolution: "is-plain-obj@npm:2.1.0"
- checksum: cec9100678b0a9fe0248a81743041ed990c2d4c99f893d935545cfbc42876cbe86d207f3b895700c690ad2fa520e568c44afc1605044b535a7820c1d40e38daa
- languageName: node
- linkType: hard
-
"is-potential-custom-element-name@npm:^1.0.1":
version: 1.0.1
resolution: "is-potential-custom-element-name@npm:1.0.1"
@@ -6834,13 +6520,6 @@ __metadata:
languageName: node
linkType: hard
-"is-whitespace-character@npm:^1.0.0":
- version: 1.0.4
- resolution: "is-whitespace-character@npm:1.0.4"
- checksum: adab8ad9847ccfcb6f1b7000b8f622881b5ba2a09ce8be2794a6d2b10c3af325b469fc562c9fb889f468eed27be06e227ac609d0aa1e3a59b4dbcc88e2b0418e
- languageName: node
- linkType: hard
-
"is-windows@npm:^0.2.0":
version: 0.2.0
resolution: "is-windows@npm:0.2.0"
@@ -6848,13 +6527,6 @@ __metadata:
languageName: node
linkType: hard
-"is-word-character@npm:^1.0.0":
- version: 1.0.4
- resolution: "is-word-character@npm:1.0.4"
- checksum: 1821d6c6abe5bc0b3abe3fdc565d66d7c8a74ea4e93bc77b4a47d26e2e2a306d6ab7d92b353b0d2b182869e3ecaa8f4a346c62d0e31d38ebc0ceaf7cae182c3f
- languageName: node
- linkType: hard
-
"isarray@npm:~1.0.0":
version: 1.0.0
resolution: "isarray@npm:1.0.0"
@@ -7868,13 +7540,6 @@ __metadata:
languageName: node
linkType: hard
-"longest-streak@npm:^2.0.1":
- version: 2.0.4
- resolution: "longest-streak@npm:2.0.4"
- checksum: 28b8234a14963002c5c71035dee13a0a11e9e9d18ffa320fdc8796ed7437399204495702ed69cd2a7087b0af041a2a8b562829b7c1e2042e73a3374d1ecf6580
- languageName: node
- linkType: hard
-
"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.4.0":
version: 1.4.0
resolution: "loose-envify@npm:1.4.0"
@@ -7962,84 +7627,6 @@ __metadata:
languageName: node
linkType: hard
-"markdown-escapes@npm:^1.0.0":
- version: 1.0.4
- resolution: "markdown-escapes@npm:1.0.4"
- checksum: 6833a93d72d3f70a500658872312c6fa8015c20cc835a85ae6901fa232683fbc6ed7118ebe920fea7c80039a560f339c026597d96eee0e9de602a36921804997
- languageName: node
- linkType: hard
-
-"markdown-table@npm:^1.1.0":
- version: 1.1.3
- resolution: "markdown-table@npm:1.1.3"
- checksum: 292e8c956ae833c2ccb0a55cd8d87980cd657ab11cd9ff63c3fcc4d3a518d3b3882ba07410b8f477ba9e30b3f70658677e4e8acf61816dd6cfdd1f6293130664
- languageName: node
- linkType: hard
-
-"mdast-util-compact@npm:^1.0.0":
- version: 1.0.4
- resolution: "mdast-util-compact@npm:1.0.4"
- dependencies:
- unist-util-visit: ^1.1.0
- checksum: 5c2eec96bd9f231d54733bbfb4fbd83ec8e1a6ddd9084a79f502614b6868a27be8ac75946ba5871c3d291673904da1fa63a5738de9c98ac1dbfd011ebb57d853
- languageName: node
- linkType: hard
-
-"mdast-util-definitions@npm:^2.0.0":
- version: 2.0.1
- resolution: "mdast-util-definitions@npm:2.0.1"
- dependencies:
- unist-util-visit: ^2.0.0
- checksum: dd00a97dd8c65d04b5ab501773ab48f81f093f1465b3db3596189f67c4d260f9e02757e55049ac886c80e10e4d51a2641f8a77d5c6e29aee1ec586dbbb82db57
- languageName: node
- linkType: hard
-
-"mdast-util-to-hast@npm:^8.0.0":
- version: 8.1.0
- resolution: "mdast-util-to-hast@npm:8.1.0"
- dependencies:
- collapse-white-space: ^1.0.0
- detab: ^2.0.0
- mdast-util-definitions: ^2.0.0
- mdurl: ^1.0.0
- trim-lines: ^1.0.0
- unist-builder: ^2.0.0
- unist-util-generated: ^1.0.0
- unist-util-position: ^3.0.0
- unist-util-visit: ^2.0.0
- checksum: 6cea5ac6ca5fa09dba237b106a7521af9cd8b5f60955932827d44072a978153dac5a85a6153f2fa32cee307a08519720f64dac3b30af314414e11759c7edb61a
- languageName: node
- linkType: hard
-
-"mdast-util-to-string@npm:^1.0.5":
- version: 1.1.0
- resolution: "mdast-util-to-string@npm:1.1.0"
- checksum: eec1eb283f3341376c8398b67ce512a11ab3e3191e3dbd5644d32a26784eac8d5f6d0b0fb81193af00d75a2c545cde765c8b03e966bd890076efb5d357fb4fe2
- languageName: node
- linkType: hard
-
-"mdast-util-toc@npm:5.0.2":
- version: 5.0.2
- resolution: "mdast-util-toc@npm:5.0.2"
- dependencies:
- "@types/mdast": ^3.0.3
- "@types/unist": ^2.0.3
- extend: ^3.0.2
- github-slugger: ^1.2.1
- mdast-util-to-string: ^1.0.5
- unist-util-is: ^4.0.0
- unist-util-visit: ^2.0.0
- checksum: 0ae885adc00a00f9116f03e49c0fc9383cdd6f895e8e69d82e65e1229de197fd86c7c6a2e4f70da94dac30b3756cc0a0a1c2a59d03c2f8309700fef03c478049
- languageName: node
- linkType: hard
-
-"mdurl@npm:^1.0.0":
- version: 1.0.1
- resolution: "mdurl@npm:1.0.1"
- checksum: 71731ecba943926bfbf9f9b51e28b5945f9411c4eda80894221b47cc105afa43ba2da820732b436f0798fd3edbbffcd1fc1415843c41a87fea08a41cc1e3d02b
- languageName: node
- linkType: hard
-
"memoize-one@npm:^5.0.0":
version: 5.2.1
resolution: "memoize-one@npm:5.2.1"
@@ -8701,20 +8288,6 @@ __metadata:
languageName: node
linkType: hard
-"parse-entities@npm:^1.0.2, parse-entities@npm:^1.1.0":
- version: 1.2.2
- resolution: "parse-entities@npm:1.2.2"
- dependencies:
- character-entities: ^1.0.0
- character-entities-legacy: ^1.0.0
- character-reference-invalid: ^1.0.0
- is-alphanumerical: ^1.0.0
- is-decimal: ^1.0.0
- is-hexadecimal: ^1.0.0
- checksum: abf070c67912647a016efd5547607ecddc7e1963e59fc20c76797419b6699a3a9a522c067efa509feefedd37afd6c2a44200b3e5546a023a973c90e6e650b68a
- languageName: node
- linkType: hard
-
"parse-json@npm:^5.0.0, parse-json@npm:^5.2.0":
version: 5.2.0
resolution: "parse-json@npm:5.2.0"
@@ -8757,13 +8330,6 @@ __metadata:
languageName: node
linkType: hard
-"parse5@npm:^5.0.0":
- version: 5.1.1
- resolution: "parse5@npm:5.1.1"
- checksum: 613a714af4c1101d1cb9f7cece2558e35b9ae8a0c03518223a4a1e35494624d9a9ad5fad4c13eab66a0e0adccd9aa3d522fc8f5f9cc19789e0579f3fa0bdfc65
- languageName: node
- linkType: hard
-
"path-browserify@npm:1.0.1":
version: 1.0.1
resolution: "path-browserify@npm:1.0.1"
@@ -9154,15 +8720,6 @@ __metadata:
languageName: node
linkType: hard
-"property-information@npm:^5.0.0, property-information@npm:^5.3.0":
- version: 5.4.0
- resolution: "property-information@npm:5.4.0"
- dependencies:
- xtend: ^4.0.0
- checksum: be497e34f48f981e53ecf7ad3be1b4cd7c54be055f1e36e8e556110e68d8a1d56b07128fa3c690b2266ca77fe4c672ba30889982fee0efd82ac967915945ac31
- languageName: node
- linkType: hard
-
"prr@npm:~1.0.1":
version: 1.0.1
resolution: "prr@npm:1.0.1"
@@ -9560,138 +9117,6 @@ __metadata:
languageName: node
linkType: hard
-"rehype-raw@npm:4.0.2":
- version: 4.0.2
- resolution: "rehype-raw@npm:4.0.2"
- dependencies:
- hast-util-raw: ^5.0.0
- checksum: 53956b5ef2eb181dbc6e8858da375590ad45cc2144c2fcdb305411d3b443f638dcadec69eecb1b2d7b20373d95bba7b9cdac4669a939970d885bbf304c84022f
- languageName: node
- linkType: hard
-
-"rehype-react@npm:5.0.0":
- version: 5.0.0
- resolution: "rehype-react@npm:5.0.0"
- dependencies:
- "@mapbox/hast-util-table-cell-style": ^0.1.3
- hast-to-hyperscript: ^8.0.0
- checksum: 531723b397f8601e7c741233988f60bf6e61e52a1ae557089cfc3f60177c94695f9cca103ae3be32ec954b842eed770e45739bfb258c3afa7f14b20fe7431e37
- languageName: node
- linkType: hard
-
-"rehype-slug@npm:3.0.0":
- version: 3.0.0
- resolution: "rehype-slug@npm:3.0.0"
- dependencies:
- github-slugger: ^1.1.1
- hast-util-has-property: ^1.0.0
- hast-util-is-element: ^1.0.0
- hast-util-to-string: ^1.0.0
- unist-util-visit: ^2.0.0
- checksum: b4a63d77f306fe0dcf7ba310ec7b21ee4f0273eaf0022e8f0ab13aa94ad6bbd2055445c62d05ca82e5afbbd1e3019088223ee2d2ab24bda01f4753d2d2a47697
- languageName: node
- linkType: hard
-
-"remark-custom-blocks@npm:2.5.1":
- version: 2.5.1
- resolution: "remark-custom-blocks@npm:2.5.1"
- dependencies:
- space-separated-tokens: ^1.1.5
- checksum: 04523f71df625b56faf160d23623e76196848ed4b4061432f0a9e77a71a4a71bd1478b55d00fa4e6561592189532644c1df7af0c5f0312f8e8b0779c725d0eae
- languageName: node
- linkType: hard
-
-"remark-parse@npm:^7.0.0":
- version: 7.0.2
- resolution: "remark-parse@npm:7.0.2"
- dependencies:
- collapse-white-space: ^1.0.2
- is-alphabetical: ^1.0.0
- is-decimal: ^1.0.0
- is-whitespace-character: ^1.0.0
- is-word-character: ^1.0.0
- markdown-escapes: ^1.0.0
- parse-entities: ^1.1.0
- repeat-string: ^1.5.4
- state-toggle: ^1.0.0
- trim: 0.0.1
- trim-trailing-lines: ^1.0.0
- unherit: ^1.0.4
- unist-util-remove-position: ^1.0.0
- vfile-location: ^2.0.0
- xtend: ^4.0.1
- checksum: bf512c5e1c7f08961a032b8422a6f916f1a60f08481b8fbaf62590dbb184d4c583db1c3b7139cf803e55078de20fe6a55a33fd8a62fd06d4fac9133e8c3aa463
- languageName: node
- linkType: hard
-
-"remark-react@npm:7.0.1":
- version: 7.0.1
- resolution: "remark-react@npm:7.0.1"
- dependencies:
- "@mapbox/hast-util-table-cell-style": ^0.1.3
- hast-to-hyperscript: ^8.0.0
- hast-util-sanitize: ^2.0.0
- mdast-util-to-hast: ^8.0.0
- checksum: b7c9dec2c070b7aad9b8fb7eb169a55f8cc2855dd2e93210e2b3aff03e80a35e673c6db71c1c748af46757d9c172f272f97757f755fd3b2e1c0daf6f8c987008
- languageName: node
- linkType: hard
-
-"remark-rehype@npm:6.0.0":
- version: 6.0.0
- resolution: "remark-rehype@npm:6.0.0"
- dependencies:
- mdast-util-to-hast: ^8.0.0
- checksum: ebeab70745cbc8ceba03a6b26adcba556d60620ca349e2003520d824bcfe2d9f399535f8e6db18b3b3cd32b329c9d34788cf01b612353e33d725549bdf850a2c
- languageName: node
- linkType: hard
-
-"remark-stringify@npm:^7.0.0":
- version: 7.0.4
- resolution: "remark-stringify@npm:7.0.4"
- dependencies:
- ccount: ^1.0.0
- is-alphanumeric: ^1.0.0
- is-decimal: ^1.0.0
- is-whitespace-character: ^1.0.0
- longest-streak: ^2.0.1
- markdown-escapes: ^1.0.0
- markdown-table: ^1.1.0
- mdast-util-compact: ^1.0.0
- parse-entities: ^1.0.2
- repeat-string: ^1.5.4
- state-toggle: ^1.0.0
- stringify-entities: ^2.0.0
- unherit: ^1.0.4
- xtend: ^4.0.1
- checksum: bfb99390da47c4a901ae8cf4f3f012b37776c9b1c529f12e357e4ba4626700c5e86ca7dd4a871119f628c32cca9f9f80900f38f578f3cfe6350e1c495e940cf7
- languageName: node
- linkType: hard
-
-"remark@npm:11.0.2":
- version: 11.0.2
- resolution: "remark@npm:11.0.2"
- dependencies:
- remark-parse: ^7.0.0
- remark-stringify: ^7.0.0
- unified: ^8.2.0
- checksum: 1a9ef3bbdef61c4c8dc15a9d18665bccd8c8dd55b42f6d541dc3f71d5a7b12cb768ee8538904d58e40d1cfcda0b7c350e3f0f38a18e0f5105d9c7bffd63ccdea
- languageName: node
- linkType: hard
-
-"repeat-string@npm:^1.5.4":
- version: 1.6.1
- resolution: "repeat-string@npm:1.6.1"
- checksum: 1b809fc6db97decdc68f5b12c4d1a671c8e3f65ec4a40c238bc5200e44e85bcc52a54f78268ab9c29fcf5fe4f1343e805420056d1f30fa9a9ee4c2d93e3cc6c0
- languageName: node
- linkType: hard
-
-"replace-ext@npm:1.0.0":
- version: 1.0.0
- resolution: "replace-ext@npm:1.0.0"
- checksum: 123e5c28046e4f0b82e1cdedb0340058d362ddbd8e17d98e5068bbacc3b3b397b4d8e3c69d603f9c4c0f6a6494852064396570c44f9426a4673dba63850fab34
- languageName: node
- linkType: hard
-
"require-directory@npm:^2.1.1":
version: 2.1.1
resolution: "require-directory@npm:2.1.1"
@@ -10270,20 +9695,6 @@ resolve@^1.3.2:
languageName: node
linkType: hard
-"space-separated-tokens@npm:^1.0.0":
- version: 1.1.4
- resolution: "space-separated-tokens@npm:1.1.4"
- checksum: 4048c44ac1bded6927f4a31bf4bc958d6b878adf3ed3af9b08e7873b789016fe946ee69ca049d8030a3829ec2fe0481b55a93b066f29ab8f529864bcc85e043b
- languageName: node
- linkType: hard
-
-"space-separated-tokens@npm:^1.1.5":
- version: 1.1.5
- resolution: "space-separated-tokens@npm:1.1.5"
- checksum: 8ef68f1cfa8ccad316b7f8d0df0919d0f1f6d32101e8faeee34ea3a923ce8509c1ad562f57388585ee4951e92d27afa211ed0a077d3d5995b5ba9180331be708
- languageName: node
- linkType: hard
-
"specificity@npm:^0.4.1":
version: 0.4.1
resolution: "specificity@npm:0.4.1"
@@ -10318,13 +9729,6 @@ resolve@^1.3.2:
languageName: node
linkType: hard
-"state-toggle@npm:^1.0.0":
- version: 1.0.3
- resolution: "state-toggle@npm:1.0.3"
- checksum: 17398af928413e8d8b866cf0c81fd1b1348bb7d65d8983126ff6ff2317a80d6ee023484fba0c54d8169f5aa544f125434a650ae3a71eddc935cae307d4692b4f
- languageName: node
- linkType: hard
-
"string-hash@npm:^1.1.1":
version: 1.1.3
resolution: "string-hash@npm:1.1.3"
@@ -10501,19 +9905,6 @@ resolve@^1.3.2:
languageName: node
linkType: hard
-"stringify-entities@npm:^2.0.0":
- version: 2.0.0
- resolution: "stringify-entities@npm:2.0.0"
- dependencies:
- character-entities-html4: ^1.0.0
- character-entities-legacy: ^1.0.0
- is-alphanumerical: ^1.0.0
- is-decimal: ^1.0.2
- is-hexadecimal: ^1.0.0
- checksum: 2e3c2ed25c48e9f8383ecf6cc7fa1d74819acf9671e08f9f78109dc12c0e34dab24b003256db9b690a32ba07b27f2dcd4bd2d03bf235b750db909713738aa808
- languageName: node
- linkType: hard
-
"strip-ansi@npm:^3.0.0, strip-ansi@npm:^3.0.1":
version: 3.0.1
resolution: "strip-ansi@npm:3.0.1"
@@ -10587,24 +9978,6 @@ resolve@^1.3.2:
languageName: node
linkType: hard
-"style-to-object@npm:^0.2.1":
- version: 0.2.3
- resolution: "style-to-object@npm:0.2.3"
- dependencies:
- inline-style-parser: 0.1.1
- checksum: dc137512b3ff403c77ec10b8ebb00294ddc6716be195d907ffe80e7625a43bef4144bfe5f745224022ffd3e43b45de812e5e3db1fa25ba402b0877cdb8dc4d2f
- languageName: node
- linkType: hard
-
-"style-to-object@npm:^0.3.0":
- version: 0.3.0
- resolution: "style-to-object@npm:0.3.0"
- dependencies:
- inline-style-parser: 0.1.1
- checksum: 4d7084015207f2a606dfc10c29cb5ba569f2fe8005551df7396110dd694d6ff650f2debafa95bd5d147dfb4ca50f57868e2a7f91bf5d11ef734fe7ccbd7abf59
- languageName: node
- linkType: hard
-
"stylis@npm:4.0.13":
version: 4.0.13
resolution: "stylis@npm:4.0.13"
@@ -10848,13 +10221,6 @@ resolve@^1.3.2:
languageName: node
linkType: hard
-"trim-lines@npm:^1.0.0":
- version: 1.1.2
- resolution: "trim-lines@npm:1.1.2"
- checksum: 2132d4f852b9e1ecebb4b276001424d5348802139fc5c3eb66f91785dd20d2f726a56681ca0baa5954c2eee655db237289294c0903bc039499566e42899dc0e6
- languageName: node
- linkType: hard
-
"trim-right@npm:^1.0.1":
version: 1.0.1
resolution: "trim-right@npm:1.0.1"
@@ -10862,27 +10228,6 @@ resolve@^1.3.2:
languageName: node
linkType: hard
-"trim-trailing-lines@npm:^1.0.0":
- version: 1.1.3
- resolution: "trim-trailing-lines@npm:1.1.3"
- checksum: 7eb4ac54079c330211453114be3d62f6a2f480e422b428982ccb7a48d278c5f826366f9f453e001eef42d50c06c0aafa2ec88280c971ecd6bc00c330a8214045
- languageName: node
- linkType: hard
-
-"trim@npm:0.0.1":
- version: 0.0.1
- resolution: "trim@npm:0.0.1"
- checksum: 2b4646dff99a222e8e1526edd4e3a43bbd925af0b8e837c340455d250157e7deefaa4da49bb891ab841e5c27b1afc5e9e32d4b57afb875d2dfcabf4e319b8f7f
- languageName: node
- linkType: hard
-
-"trough@npm:^1.0.0":
- version: 1.0.5
- resolution: "trough@npm:1.0.5"
- checksum: d6c8564903ed00e5258bab92134b020724dbbe83148dc72e4bf6306c03ed8843efa1bcc773fa62410dd89161ecb067432dd5916501793508a9506cacbc408e25
- languageName: node
- linkType: hard
-
"tsconfig-paths@npm:^3.14.1":
version: 3.14.1
resolution: "tsconfig-paths@npm:3.14.1"
@@ -11012,29 +10357,6 @@ resolve@^1.3.2:
languageName: node
linkType: hard
-"unherit@npm:^1.0.4":
- version: 1.1.3
- resolution: "unherit@npm:1.1.3"
- dependencies:
- inherits: ^2.0.0
- xtend: ^4.0.0
- checksum: fd7922f84fc0bfb7c4df6d1f5a50b5b94a0218e3cda98a54dbbd209226ddd4072d742d3df44d0e295ab08d5ccfd304a1e193dfe31a86d2a91b7cb9fdac093194
- languageName: node
- linkType: hard
-
-"unified@npm:^8.2.0":
- version: 8.4.2
- resolution: "unified@npm:8.4.2"
- dependencies:
- bail: ^1.0.0
- extend: ^3.0.0
- is-plain-obj: ^2.0.0
- trough: ^1.0.0
- vfile: ^4.0.0
- checksum: c2af7662d6375b14721df305786b15ba3228cd39c37da748bff00ed08ababd12ce52568f475347f270b1dea72fb0b9608563574a55c29e4f73f8be7ce0a01b4a
- languageName: node
- linkType: hard
-
"uniq@npm:^1.0.1":
version: 1.0.1
resolution: "uniq@npm:1.0.1"
@@ -11060,98 +10382,6 @@ resolve@^1.3.2:
languageName: node
linkType: hard
-"unist-builder@npm:^2.0.0":
- version: 2.0.3
- resolution: "unist-builder@npm:2.0.3"
- checksum: e946fdf77dbfc320feaece137ce4959ae2da6614abd1623bd39512dc741a9d5f313eb2ba79f8887d941365dccddec7fef4e953827475e392bf49b45336f597f6
- languageName: node
- linkType: hard
-
-"unist-util-generated@npm:^1.0.0":
- version: 1.1.5
- resolution: "unist-util-generated@npm:1.1.5"
- checksum: 7c2a2efb5467f756679761cbc02c36c8d9f8ca7fcb27e8add5e583b9bd9d1beda9c3805b6cb487cbfea8d1d45372a34f6e8d470e35526877fc42fc0c6327f6ab
- languageName: node
- linkType: hard
-
-"unist-util-is@npm:^3.0.0":
- version: 3.0.0
- resolution: "unist-util-is@npm:3.0.0"
- checksum: d24a5dd80c670f763b2ae608651cf062317456aa81be51f66f45cbd7d440a2ab18356e4f48aeac6b5e3d391c69d3c3452ade5fe5aa9574bec4a2de0b10122ed5
- languageName: node
- linkType: hard
-
-"unist-util-is@npm:^4.0.0":
- version: 4.0.2
- resolution: "unist-util-is@npm:4.0.2"
- checksum: 851a07cd0eeadde5ec98fe7453d554804b3cc5be94d892de6f52178c05b683d753dfd7bb566bb42afa7aca8633935e86b1c34816832d151b41a28348bd876cc1
- languageName: node
- linkType: hard
-
-"unist-util-position@npm:^3.0.0":
- version: 3.0.3
- resolution: "unist-util-position@npm:3.0.3"
- checksum: b938a4dadb9960d7ab815a7f6d5d67bd2f26207b149b214067c90062750dd89e8f8882e9c23175098c613c6140e8943d131afb5ba092170223cf582094ae2da8
- languageName: node
- linkType: hard
-
-"unist-util-remove-position@npm:^1.0.0":
- version: 1.1.4
- resolution: "unist-util-remove-position@npm:1.1.4"
- dependencies:
- unist-util-visit: ^1.1.0
- checksum: 74be7078d135601e9d295f392ef2768efc2c0bdb8720480c36fa608df6290cb85d324e82d4bdfc2f38303c466ffbba4f0fa4f9acb25fff45d23926259bdafcf6
- languageName: node
- linkType: hard
-
-"unist-util-stringify-position@npm:^2.0.0":
- version: 2.0.3
- resolution: "unist-util-stringify-position@npm:2.0.3"
- dependencies:
- "@types/unist": ^2.0.2
- checksum: f755cadc959f9074fe999578a1a242761296705a7fe87f333a37c00044de74ab4b184b3812989a57d4cd12211f0b14ad397b327c3a594c7af84361b1c25a7f09
- languageName: node
- linkType: hard
-
-"unist-util-visit-parents@npm:^2.0.0":
- version: 2.1.2
- resolution: "unist-util-visit-parents@npm:2.1.2"
- dependencies:
- unist-util-is: ^3.0.0
- checksum: 048edbb590a8c4bc0043eec9f50d3fe76faa58f1ac663a7e6dee5e895ddd0ce8bc52f2cfe2e633849fa93671e8de021070667acb1518e3d40220768c7f70a3d3
- languageName: node
- linkType: hard
-
-"unist-util-visit-parents@npm:^3.0.0":
- version: 3.0.2
- resolution: "unist-util-visit-parents@npm:3.0.2"
- dependencies:
- "@types/unist": ^2.0.0
- unist-util-is: ^4.0.0
- checksum: fa00ee47427a2ece4ab6a997ac74147844842b824ce512274e5b62f95e83deff79f2b68a0497bca036d0462954b890e8a5263d4a6640595e6be696bd3c844814
- languageName: node
- linkType: hard
-
-"unist-util-visit@npm:2.0.2, unist-util-visit@npm:^2.0.0":
- version: 2.0.2
- resolution: "unist-util-visit@npm:2.0.2"
- dependencies:
- "@types/unist": ^2.0.0
- unist-util-is: ^4.0.0
- unist-util-visit-parents: ^3.0.0
- checksum: 818028efae123a8e1931ac74286f808c43649394a52f091f1632169b421151a4a6dba15db65561ecf3002236928e533aefe038dffdafc94920c3c70324e1afe6
- languageName: node
- linkType: hard
-
-"unist-util-visit@npm:^1.1.0, unist-util-visit@npm:^1.3.0":
- version: 1.4.1
- resolution: "unist-util-visit@npm:1.4.1"
- dependencies:
- unist-util-visit-parents: ^2.0.0
- checksum: e9395205b6908c8d0fe71bc44e65d89d4781d1bb2d453a33cb67ed4124bad0b89d6b1d526ebaecb82a7c48e211bdf6f24351449b8cc115327b345f4617c18728
- languageName: node
- linkType: hard
-
"universalify@npm:^0.1.2":
version: 0.1.2
resolution: "universalify@npm:0.1.2"
@@ -11240,36 +10470,6 @@ resolve@^1.3.2:
languageName: node
linkType: hard
-"vfile-location@npm:^2.0.0":
- version: 2.0.6
- resolution: "vfile-location@npm:2.0.6"
- checksum: ca0da908fdcd86f3df749a328ff777cf8994240eb333da7e6ee270b4fec09058d7b64f174ce9e31a9c591bb9ed01b45c223186a31036860d9f463eca059c058e
- languageName: node
- linkType: hard
-
-"vfile-message@npm:^2.0.0":
- version: 2.0.3
- resolution: "vfile-message@npm:2.0.3"
- dependencies:
- "@types/unist": ^2.0.0
- unist-util-stringify-position: ^2.0.0
- checksum: 3477d6798b2c1051aa5d65448f49ecc157dc9176d2b11feb480698a7c91517fe536adf7bec2b9bc1d93696cf6a843d3aca621f00047514dd009dbd079b717160
- languageName: node
- linkType: hard
-
-"vfile@npm:^4.0.0":
- version: 4.0.3
- resolution: "vfile@npm:4.0.3"
- dependencies:
- "@types/unist": ^2.0.0
- is-buffer: ^2.0.0
- replace-ext: 1.0.0
- unist-util-stringify-position: ^2.0.0
- vfile-message: ^2.0.0
- checksum: 979dc4056dfccfee09982669045f2dcc2012dcb9bedda3645685930a17335a6120922a6df14931e1309cc87536e792491f1159a89ac94346d439457095abeda4
- languageName: node
- linkType: hard
-
"w3c-hr-time@npm:^1.0.2":
version: 1.0.2
resolution: "w3c-hr-time@npm:1.0.2"
@@ -11315,13 +10515,6 @@ resolve@^1.3.2:
languageName: node
linkType: hard
-"web-namespaces@npm:^1.0.0, web-namespaces@npm:^1.1.2":
- version: 1.1.4
- resolution: "web-namespaces@npm:1.1.4"
- checksum: 5149842ccbfbc56fe4f8758957b3f8c8616a281874a5bb84aa1b305e4436a9bad853d21c629a7b8f174902449e1489c7a6c724fccf60965077c5636bd8aed42b
- languageName: node
- linkType: hard
-
"webidl-conversions@npm:^5.0.0":
version: 5.0.0
resolution: "webidl-conversions@npm:5.0.0"
@@ -11549,13 +10742,6 @@ resolve@^1.3.2:
languageName: node
linkType: hard
-"xtend@npm:^4.0.0, xtend@npm:^4.0.1":
- version: 4.0.1
- resolution: "xtend@npm:4.0.1"
- checksum: 6148d4f9b978f858560b21f1666d1d2b8a799289671ce3274a0b2e8b843d960ba7507842d73c2f44705a87ca9adc25ab12d627aac41ba911038f78f9eb6e6d78
- languageName: node
- linkType: hard
-
"y18n@npm:^5.0.5":
version: 5.0.8
resolution: "y18n@npm:5.0.8"
@@ -11605,10 +10791,3 @@ resolve@^1.3.2:
checksum: f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700
languageName: node
linkType: hard
-
-"zwitch@npm:^1.0.0":
- version: 1.0.5
- resolution: "zwitch@npm:1.0.5"
- checksum: 28a1bebacab3bc60150b6b0a2ba1db2ad033f068e81f05e4892ec0ea13ae63f5d140a1d692062ac0657840c8da076f35b94433b5f1c329d7803b247de80f064a
- languageName: node
- linkType: hard