@verdaccio/ui-components 3.0.0-next-7.6 → 3.0.0-next-7.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc +1 -1
- package/CHANGELOG.md +12 -0
- package/build/Theme/theme.js +3 -3
- package/build/components/ActionBar/ActionBar.js +3 -1
- package/build/components/ActionBar/ActionBarAction.js +7 -6
- package/build/components/Author/Author.js +13 -42
- package/build/components/CopyClipboard/utils.js +3 -12
- package/build/components/Dependencies/Dependencies.js +27 -18
- package/build/components/Dependencies/DependencyBlock.js +34 -19
- package/build/components/Developers/DeveloperType.js +12 -0
- package/build/components/Developers/Developers.js +20 -22
- package/build/components/Developers/Title.js +5 -9
- package/build/components/Developers/index.js +4 -4
- package/build/components/Distribution/Dist.js +1 -1
- package/build/components/Distribution/styles.js +10 -23
- package/build/components/Engines/Engines.js +7 -1
- package/build/components/Engines/styles.js +6 -6
- package/build/components/FundButton/FundButton.js +7 -8
- package/build/components/HeaderInfoDialog/HeaderInfoDialog.js +2 -1
- package/build/components/Icons/DevsIcons/CommonJS.js +1 -12
- package/build/components/Icons/DevsIcons/ES6Module.js +2 -13
- package/build/components/Icons/DevsIcons/Git.js +1 -12
- package/build/components/Icons/DevsIcons/NodeJS.js +1 -12
- package/build/components/Icons/DevsIcons/TypeScript.js +1 -12
- package/build/components/Icons/FileBinary.js +11 -5
- package/build/components/Icons/Law.js +12 -6
- package/build/components/Icons/Managers/Npm.js +1 -12
- package/build/components/Icons/Managers/Pnpm.js +1 -12
- package/build/components/Icons/Managers/Yarn.js +1 -12
- package/build/components/Install/Install.js +23 -18
- package/build/components/Install/InstallListItem.js +19 -18
- package/build/components/Keywords/KeywordListItems.js +34 -0
- package/build/components/Keywords/Keywords.js +39 -0
- package/build/{sections/Header/RegistryInfoDialog → components/Keywords}/index.js +2 -2
- package/build/components/Link/Link.js +4 -16
- package/build/components/Link/index.js +1 -1
- package/build/components/LinkExternal/LinkExternal.js +32 -0
- package/build/components/LinkExternal/index.js +14 -0
- package/build/components/Loading/styles.js +3 -2
- package/build/components/LoginDialog/LoginDialog.js +12 -1
- package/build/components/LoginDialog/LoginDialogCloseButton.js +3 -2
- package/build/components/LoginDialog/LoginDialogForm.js +2 -14
- package/build/components/LoginDialog/LoginDialogFormError.js +3 -2
- package/build/components/Logo/Logo.js +13 -6
- package/build/components/Package/Package.js +43 -34
- package/build/components/Package/styles.js +46 -58
- package/build/components/Person/Person.js +48 -0
- package/build/components/Person/PersonTooltip.js +22 -0
- package/build/components/{Package/Tag → Person}/index.js +2 -2
- package/build/components/Person/utils.js +17 -0
- package/build/components/RawViewer/RawViewer.js +11 -5
- package/build/components/Readme/Readme.js +15 -6
- package/build/components/Readme/Readme.js.map +1 -1
- package/build/components/Readme/Readme.spec.js +19 -0
- package/build/components/Readme/Readme.spec.js.map +1 -1
- package/build/components/Readme/utils.js +2 -5
- package/build/components/RegistryInfoDialog/styles.js +9 -10
- package/build/components/Repository/Repository.js +19 -31
- package/build/components/Search/AutoComplete/styles.js +4 -41
- package/build/components/Search/Search.js +4 -2
- package/build/components/Search/SearchItem.js +51 -38
- package/build/components/Search/utils.js +23 -0
- package/build/components/SettingsMenu/SettingsMenu.js +35 -9
- package/build/components/SideBarTitle/SideBarTitle.js +16 -6
- package/build/components/UpLinks/UpLinks.js +35 -6
- package/build/components/UpLinks/UplinkLink.js +22 -0
- package/build/components/UpLinks/styles.js +5 -4
- package/build/components/Versions/HistoryList.js +8 -5
- package/build/components/Versions/TagList.js +8 -4
- package/build/components/Versions/Versions.js +30 -7
- package/build/index.js +27 -3
- package/build/providers/AppConfigurationProvider/AppConfigurationProvider.js +1 -0
- package/build/providers/PersistenceSettingProvider/PersistenceSettingProvider.js +1 -0
- package/build/sections/Detail/Detail.js +6 -2
- package/build/sections/Detail/Tabs.js +4 -3
- package/build/sections/Footer/Footer.js +17 -8
- package/build/sections/Footer/styles.js +13 -10
- package/build/sections/Header/HeaderLeft.js +14 -17
- package/build/sections/Header/HeaderMenu.js +1 -1
- package/build/sections/Header/HeaderRight.js +12 -3
- package/build/sections/Header/HeaderSettingsDialog.js +2 -2
- package/build/sections/Header/styles.js +43 -82
- package/build/sections/SideBar/Sidebar.js +10 -15
- package/build/src/Theme/ThemeProvider.test.d.ts +1 -0
- package/build/src/components/Author/Author.d.ts +0 -5
- package/build/src/components/CopyClipboard/CopyToClipBoard.test.d.ts +1 -0
- package/build/src/components/Dependencies/Dependencies.d.ts +0 -1
- package/build/src/components/Developers/DeveloperType.d.ts +4 -0
- package/build/src/components/Developers/Developers.d.ts +1 -4
- package/build/src/components/Developers/Title.d.ts +1 -4
- package/build/src/components/Developers/index.d.ts +2 -1
- package/build/src/components/Distribution/styles.d.ts +0 -1
- package/build/src/components/ErrorBoundary/ErrorBoundary.test.d.ts +1 -0
- package/build/src/components/HeaderInfoDialog/HeaderInfoDialog.test.d.ts +1 -0
- package/build/src/components/Heading/Heading.test.d.ts +1 -0
- package/build/src/components/Icons/Icons.test.d.ts +1 -0
- package/build/src/components/Install/InstallListItem.d.ts +1 -1
- package/build/src/components/Keywords/KeywordListItems.d.ts +5 -0
- package/build/src/components/Keywords/Keywords.d.ts +6 -0
- package/build/src/components/Keywords/Keywords.stories.d.ts +5 -0
- package/build/src/components/Keywords/Keywords.test.d.ts +1 -0
- package/build/src/components/Keywords/index.d.ts +1 -0
- package/build/src/components/Link/Link.d.ts +0 -3
- package/build/src/components/Link/Link.test.d.ts +1 -0
- package/build/src/components/Link/index.d.ts +1 -1
- package/build/src/components/LinkExternal/LinkExternal.d.ts +3 -0
- package/build/src/components/LinkExternal/LinkExternal.test.d.ts +1 -0
- package/build/src/components/LinkExternal/index.d.ts +1 -0
- package/build/src/components/Logo/Logo.d.ts +1 -0
- package/build/src/components/Logo/Logo.stories.d.ts +5 -0
- package/build/src/components/Package/Package.d.ts +1 -1
- package/build/src/components/Package/styles.d.ts +0 -8
- package/build/src/components/Person/Person.d.ts +9 -0
- package/build/src/components/Person/Person.test.d.ts +1 -0
- package/build/src/components/Person/PersonTooltip.d.ts +6 -0
- package/build/src/components/Person/index.d.ts +1 -0
- package/build/src/components/Person/utils.d.ts +3 -0
- package/build/src/components/Readme/Readme.d.ts +0 -1
- package/build/src/components/Search/AutoComplete/styles.d.ts +0 -8
- package/build/src/components/Search/utils.d.ts +1 -0
- package/build/src/components/SettingsMenu/SettingsMenu.d.ts +2 -2
- package/build/src/components/SettingsMenu/SettingsMenu.test.d.ts +1 -0
- package/build/src/components/UpLinks/UplinkLink.d.ts +6 -0
- package/build/src/components/Versions/Versions.d.ts +1 -0
- package/build/src/index.d.ts +4 -1
- package/build/src/sections/Detail/Tabs.d.ts +1 -0
- package/build/src/sections/Header/styles.d.ts +0 -7
- package/build/src/store/models/routes.d.ts +8 -0
- package/build/src/store/models/utils.d.ts +1 -0
- package/build/src/types/packageMeta.d.ts +7 -5
- package/build/src/utils/routes.d.ts +1 -0
- package/build/src/utils/utils.d.ts +1 -0
- package/build/store/models/configuration.js +2 -1
- package/build/store/models/login.js +4 -2
- package/build/store/models/manifest.js +5 -3
- package/build/store/models/packages.js +4 -2
- package/build/store/models/routes.js +18 -0
- package/build/store/models/search.js +4 -2
- package/build/store/models/utils.js +10 -0
- package/build/utils/routes.js +1 -0
- package/build/utils/utils.js +20 -1
- package/package.json +4 -4
- package/src/AppTest/AppRoute.test.tsx +65 -0
- package/src/Theme/ThemeProvider.test.tsx +27 -0
- package/src/Theme/theme.ts +3 -3
- package/src/components/ActionBar/ActionBar.test.tsx +36 -15
- package/src/components/ActionBar/ActionBar.tsx +1 -1
- package/src/components/ActionBar/ActionBarAction.tsx +8 -5
- package/src/components/Author/Author.test.tsx +7 -1
- package/src/components/Author/Author.tsx +3 -41
- package/src/components/CopyClipboard/CopyToClipBoard.test.tsx +23 -0
- package/src/components/CopyClipboard/utils.ts +2 -13
- package/src/components/Dependencies/Dependencies.stories.tsx +11 -11
- package/src/components/Dependencies/Dependencies.tsx +28 -25
- package/src/components/Dependencies/DependencyBlock.test.tsx +19 -6
- package/src/components/Dependencies/DependencyBlock.tsx +28 -14
- package/src/components/Developers/DeveloperType.tsx +4 -0
- package/src/components/Developers/Developers.test.tsx +37 -10
- package/src/components/Developers/Developers.tsx +13 -13
- package/src/components/Developers/Title.tsx +1 -5
- package/src/components/Developers/index.ts +2 -1
- package/src/components/Distribution/Dist.test.tsx +1 -1
- package/src/components/Distribution/Dist.tsx +2 -4
- package/src/components/Distribution/styles.ts +0 -6
- package/src/components/Engines/Engines.tsx +6 -2
- package/src/components/Engines/styles.ts +1 -1
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +39 -0
- package/src/components/FundButton/FundButton.tsx +5 -5
- package/src/components/HeaderInfoDialog/HeaderInfoDialog.test.tsx +51 -0
- package/src/components/HeaderInfoDialog/HeaderInfoDialog.tsx +2 -2
- package/src/components/Heading/Heading.test.tsx +20 -0
- package/src/components/Icons/DevsIcons/CommonJS.tsx +1 -7
- package/src/components/Icons/DevsIcons/ES6Module.tsx +2 -8
- package/src/components/Icons/DevsIcons/Git.tsx +1 -7
- package/src/components/Icons/DevsIcons/NodeJS.tsx +1 -7
- package/src/components/Icons/DevsIcons/TypeScript.tsx +1 -7
- package/src/components/Icons/FileBinary.tsx +2 -1
- package/src/components/Icons/Icons.stories.tsx +21 -5
- package/src/components/Icons/Icons.test.tsx +70 -0
- package/src/components/Icons/Law.tsx +2 -1
- package/src/components/Icons/Managers/Npm.tsx +1 -7
- package/src/components/Icons/Managers/Pnpm.tsx +1 -7
- package/src/components/Icons/Managers/Yarn.tsx +1 -7
- package/src/components/Install/Install.test.tsx +54 -13
- package/src/components/Install/Install.tsx +12 -11
- package/src/components/Install/InstallListItem.tsx +12 -11
- package/src/components/Keywords/KeywordListItems.tsx +22 -0
- package/src/components/Keywords/Keywords.stories.tsx +19 -0
- package/src/components/Keywords/Keywords.test.tsx +57 -0
- package/src/components/Keywords/Keywords.tsx +35 -0
- package/src/components/Keywords/index.ts +1 -0
- package/src/components/Link/Link.test.tsx +25 -0
- package/src/components/Link/Link.tsx +4 -18
- package/src/components/Link/index.ts +1 -1
- package/src/components/LinkExternal/LinkExternal.test.tsx +18 -0
- package/src/components/LinkExternal/LinkExternal.tsx +22 -0
- package/src/components/LinkExternal/index.ts +1 -0
- package/src/components/Loading/Loading.test.tsx +8 -5
- package/src/components/Loading/styles.ts +1 -0
- package/src/components/LoginDialog/LoginDialog.test.tsx +1 -1
- package/src/components/LoginDialog/LoginDialog.tsx +10 -1
- package/src/components/LoginDialog/LoginDialogCloseButton.tsx +1 -0
- package/src/components/LoginDialog/LoginDialogForm.tsx +0 -2
- package/src/components/LoginDialog/LoginDialogFormError.tsx +1 -1
- package/src/components/Logo/Logo.stories.tsx +16 -0
- package/src/components/Logo/Logo.test.tsx +8 -1
- package/src/components/Logo/Logo.tsx +19 -3
- package/src/components/Package/Package.test.tsx +47 -14
- package/src/components/Package/Package.tsx +41 -44
- package/src/components/Package/styles.ts +7 -17
- package/src/components/PackageList/Packagelist.test.tsx +1 -0
- package/src/components/Person/Person.test.tsx +50 -0
- package/src/components/Person/Person.tsx +45 -0
- package/src/components/Person/PersonTooltip.tsx +26 -0
- package/src/components/Person/index.ts +1 -0
- package/src/components/Person/utils.ts +20 -0
- package/src/components/RawViewer/RawViewer.tsx +8 -4
- package/src/components/Readme/Readme.spec.tsx +17 -0
- package/src/components/Readme/Readme.tsx +10 -5
- package/src/components/Readme/utils.ts +2 -5
- package/src/components/RegistryInfoDialog/styles.ts +5 -4
- package/src/components/Repository/Repository.tsx +9 -14
- package/src/components/Search/AutoComplete/styles.ts +7 -0
- package/src/components/Search/Search.test.tsx +36 -9
- package/src/components/Search/Search.tsx +4 -2
- package/src/components/Search/SearchItem.tsx +19 -8
- package/src/components/Search/utils.ts +17 -0
- package/src/components/SettingsMenu/SettingsMenu.test.tsx +41 -0
- package/src/components/SettingsMenu/SettingsMenu.tsx +48 -10
- package/src/components/SideBarTitle/SideBarTitle.tsx +19 -3
- package/src/components/UpLinks/UpLinks.test.tsx +7 -0
- package/src/components/UpLinks/UpLinks.tsx +38 -15
- package/src/components/UpLinks/UplinkLink.tsx +20 -0
- package/src/components/UpLinks/styles.ts +1 -0
- package/src/components/Versions/HistoryList.tsx +9 -4
- package/src/components/Versions/TagList.tsx +4 -3
- package/src/components/Versions/Versions.test.tsx +2 -0
- package/src/components/Versions/Versions.tsx +57 -32
- package/src/index.ts +4 -1
- package/src/providers/AppConfigurationProvider/AppConfigurationProvider.tsx +1 -0
- package/src/providers/PersistenceSettingProvider/PersistenceSettingProvider.tsx +2 -0
- package/src/providers/VersionProvider/VersionProvider.test.tsx +3 -3
- package/src/sections/Detail/Detail.test.tsx +8 -1
- package/src/sections/Detail/Detail.tsx +11 -4
- package/src/sections/Detail/Tabs.tsx +5 -2
- package/src/sections/Footer/Footer.tsx +15 -4
- package/src/sections/Footer/styles.ts +4 -0
- package/src/sections/Header/Header.test.tsx +12 -10
- package/src/sections/Header/HeaderLeft.tsx +19 -11
- package/src/sections/Header/HeaderMenu.tsx +1 -1
- package/src/sections/Header/HeaderRight.tsx +14 -3
- package/src/sections/Header/HeaderSettingsDialog.tsx +1 -1
- package/src/sections/Header/RegistryInfoContent/RegistryInfoContent.test.tsx +1 -1
- package/src/sections/Header/styles.ts +4 -16
- package/src/sections/Home/Home.test.tsx +12 -4
- package/src/sections/SideBar/Sidebar.test.tsx +20 -13
- package/src/sections/SideBar/Sidebar.tsx +5 -9
- package/src/store/api.test.ts +16 -0
- package/src/store/models/configuration.ts +2 -1
- package/src/store/models/login.ts +10 -12
- package/src/store/models/manifest.ts +6 -5
- package/src/store/models/packages.ts +4 -5
- package/src/store/models/routes.ts +10 -0
- package/src/store/models/search.ts +4 -2
- package/src/store/models/utils.ts +3 -0
- package/src/types/packageMeta.ts +7 -5
- package/src/utils/routes.ts +1 -0
- package/src/utils/utils.test.ts +34 -0
- package/src/utils/utils.ts +20 -5
- package/tsconfig.json +1 -1
- package/build/components/Developers/styles.js +0 -65
- package/build/components/Distribution/utils.js +0 -25
- package/build/components/Distribution/utilts.spec.js +0 -18
- package/build/components/Package/Tag/Tag.js +0 -14
- package/build/components/Package/Tag/styles.js +0 -24
- package/build/sections/Header/RegistryInfoDialog/RegistryInfoDialog.js +0 -36
- package/build/sections/Header/RegistryInfoDialog/styles.js +0 -46
- package/build/sections/Header/RegistryInfoDialog/types.js +0 -6
- package/build/src/components/Developers/styles.d.ts +0 -11
- package/build/src/components/Distribution/utils.d.ts +0 -7
- package/build/src/components/Package/Tag/Tag.d.ts +0 -6
- package/build/src/components/Package/Tag/index.d.ts +0 -1
- package/build/src/components/Package/Tag/styles.d.ts +0 -5
- package/build/src/sections/Header/RegistryInfoDialog/RegistryInfoDialog.d.ts +0 -4
- package/build/src/sections/Header/RegistryInfoDialog/index.d.ts +0 -1
- package/build/src/sections/Header/RegistryInfoDialog/styles.d.ts +0 -13
- package/build/src/sections/Header/RegistryInfoDialog/types.d.ts +0 -7
- package/src/components/Developers/styles.ts +0 -31
- package/src/components/Distribution/utils.ts +0 -32
- package/src/components/Distribution/utilts.spec.ts +0 -17
- package/src/components/Package/Tag/Tag.test.tsx +0 -15
- package/src/components/Package/Tag/Tag.tsx +0 -11
- package/src/components/Package/Tag/index.ts +0 -1
- package/src/components/Package/Tag/styles.ts +0 -11
- package/src/components/Search/AutoComplete/styles.tsx +0 -42
- package/src/sections/Header/RegistryInfoDialog/RegistryInfoDialog.tsx +0 -31
- package/src/sections/Header/RegistryInfoDialog/index.ts +0 -1
- package/src/sections/Header/RegistryInfoDialog/styles.ts +0 -21
- package/src/sections/Header/RegistryInfoDialog/types.ts +0 -8
- /package/build/components/Icons/DevsIcons/{es6modules.svg → es6module.svg} +0 -0
- /package/build/src/{components/Package/Tag/Tag.test.d.ts → AppTest/AppRoute.test.d.ts} +0 -0
- /package/src/components/Icons/DevsIcons/{es6modules.svg → es6module.svg} +0 -0
|
@@ -3,6 +3,7 @@ import Dialog from '@mui/material/Dialog';
|
|
|
3
3
|
import DialogContent from '@mui/material/DialogContent';
|
|
4
4
|
import DialogTitle from '@mui/material/DialogTitle';
|
|
5
5
|
import IconButton from '@mui/material/IconButton';
|
|
6
|
+
import { useTheme } from '@mui/styles';
|
|
6
7
|
import React from 'react';
|
|
7
8
|
import { useTranslation } from 'react-i18next';
|
|
8
9
|
import ReactJson from 'react-json-view';
|
|
@@ -22,6 +23,7 @@ const ViewerTitle = (props: ViewerTitleProps) => {
|
|
|
22
23
|
{onClose ? (
|
|
23
24
|
<IconButton
|
|
24
25
|
aria-label="close"
|
|
26
|
+
data-testid="close-raw-viewer"
|
|
25
27
|
onClick={onClose}
|
|
26
28
|
sx={{
|
|
27
29
|
position: 'absolute',
|
|
@@ -46,18 +48,20 @@ type Props = {
|
|
|
46
48
|
/* eslint-disable verdaccio/jsx-spread */
|
|
47
49
|
const RawViewer: React.FC<Props> = ({ isOpen = false, onClose, packageMeta }) => {
|
|
48
50
|
const { t } = useTranslation();
|
|
51
|
+
const theme = useTheme();
|
|
49
52
|
return (
|
|
50
53
|
<Dialog data-testid={'rawViewer--dialog'} fullScreen={true} open={isOpen}>
|
|
51
54
|
<ViewerTitle id="viewer-title" onClose={onClose}>
|
|
52
|
-
{t('action-bar-action.raw')}
|
|
55
|
+
{t('action-bar-action.raw-title', { package: packageMeta.latest.name })}
|
|
53
56
|
</ViewerTitle>
|
|
54
57
|
<DialogContent>
|
|
55
58
|
<ReactJson
|
|
56
|
-
collapseStringsAfterLength={
|
|
57
|
-
collapsed={
|
|
58
|
-
enableClipboard={
|
|
59
|
+
collapseStringsAfterLength={200}
|
|
60
|
+
collapsed={2}
|
|
61
|
+
enableClipboard={true}
|
|
59
62
|
groupArraysAfterLength={10}
|
|
60
63
|
src={packageMeta as any}
|
|
64
|
+
theme={theme?.palette.mode == 'light' ? 'bright:inverted' : 'bright'}
|
|
61
65
|
/>
|
|
62
66
|
</DialogContent>
|
|
63
67
|
</Dialog>
|
|
@@ -15,4 +15,21 @@ describe('<Readme /> component', () => {
|
|
|
15
15
|
const wrapper = render(<Readme description="<h1>This is a test string</h1>" />);
|
|
16
16
|
expect(wrapper.getByText('This is a test string')).toBeInTheDocument();
|
|
17
17
|
});
|
|
18
|
+
|
|
19
|
+
test('should sanitize html', () => {
|
|
20
|
+
const markdown = `<script>alert('test')</script>`;
|
|
21
|
+
const wrapper = render(<Readme description={markdown} />);
|
|
22
|
+
expect(wrapper.queryAllByText('test')).toHaveLength(0);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('should highlight code', () => {
|
|
26
|
+
const markdown = `\`\`\`js\nconst test = 1 + 2;\n\`\`\``;
|
|
27
|
+
const wrapper = render(<Readme description={markdown} />);
|
|
28
|
+
expect(wrapper.getByText('const')).toBeInTheDocument();
|
|
29
|
+
expect(wrapper.getByText('const')).toHaveClass('hljs-keyword');
|
|
30
|
+
expect(wrapper.getByText('1')).toBeInTheDocument();
|
|
31
|
+
expect(wrapper.getByText('1')).toHaveClass('hljs-number');
|
|
32
|
+
expect(wrapper.getByText('2')).toBeInTheDocument();
|
|
33
|
+
expect(wrapper.getByText('2')).toHaveClass('hljs-number');
|
|
34
|
+
});
|
|
18
35
|
});
|
|
@@ -2,8 +2,6 @@ import styled from '@emotion/styled';
|
|
|
2
2
|
import Box from '@mui/material/Box';
|
|
3
3
|
import Card from '@mui/material/Card';
|
|
4
4
|
import CardContent from '@mui/material/CardContent';
|
|
5
|
-
import { useTheme } from '@mui/styles';
|
|
6
|
-
import 'highlight.js/styles/default.css';
|
|
7
5
|
import React from 'react';
|
|
8
6
|
|
|
9
7
|
import { useCustomTheme } from '../../';
|
|
@@ -14,12 +12,19 @@ import { parseReadme } from './utils';
|
|
|
14
12
|
const Readme: React.FC<Props> = ({ description }) => {
|
|
15
13
|
// @ts-ignore
|
|
16
14
|
const { isDarkMode } = useCustomTheme();
|
|
17
|
-
|
|
15
|
+
|
|
16
|
+
// Stackoverflow theme fits well to Verdaccio dark colors
|
|
17
|
+
// https://highlightjs.org/examples
|
|
18
|
+
if (isDarkMode) {
|
|
19
|
+
require('highlight.js/styles/github-dark.css');
|
|
20
|
+
} else {
|
|
21
|
+
require('highlight.js/styles/github.css');
|
|
22
|
+
}
|
|
18
23
|
|
|
19
24
|
return (
|
|
20
|
-
<Card>
|
|
25
|
+
<Card sx={{ mb: 2 }}>
|
|
21
26
|
<CardContent>
|
|
22
|
-
<Box data-testid="readme" sx={{
|
|
27
|
+
<Box data-testid="readme" sx={{ m: 2 }}>
|
|
23
28
|
<Wrapper
|
|
24
29
|
className={`markdown-body ${isDarkMode ? 'markdown-dark' : 'markdown-light'}`}
|
|
25
30
|
dangerouslySetInnerHTML={{ __html: parseReadme(description) as string }}
|
|
@@ -21,9 +21,6 @@ marked.setOptions({
|
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
export function parseReadme(readme: string): string | void {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return DOMPurify.sanitize(html);
|
|
27
|
-
}
|
|
28
|
-
return '';
|
|
24
|
+
const html = marked.parse(readme);
|
|
25
|
+
return DOMPurify.sanitize(html);
|
|
29
26
|
}
|
|
@@ -4,10 +4,11 @@ import DialogTitle from '@mui/material/DialogTitle';
|
|
|
4
4
|
|
|
5
5
|
import { Theme } from '../../';
|
|
6
6
|
|
|
7
|
-
export const Title = styled(DialogTitle)<{ theme?: Theme }>((
|
|
8
|
-
backgroundColor:
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
export const Title = styled(DialogTitle)<{ theme?: Theme }>(({ theme }) => ({
|
|
8
|
+
backgroundColor:
|
|
9
|
+
theme?.palette.mode === 'light' ? theme?.palette.primary.main : theme?.palette.cyanBlue,
|
|
10
|
+
color: theme?.palette.white,
|
|
11
|
+
fontSize: theme?.fontSize.lg,
|
|
11
12
|
}));
|
|
12
13
|
|
|
13
14
|
export const Content = styled(DialogContent)<{ theme?: Theme }>(({ theme }) => ({
|
|
@@ -4,6 +4,7 @@ import List from '@mui/material/List';
|
|
|
4
4
|
import ListItem from '@mui/material/ListItem';
|
|
5
5
|
import ListItemText from '@mui/material/ListItemText';
|
|
6
6
|
import Typography from '@mui/material/Typography';
|
|
7
|
+
import { useTheme } from '@mui/styles';
|
|
7
8
|
import React from 'react';
|
|
8
9
|
import { useTranslation } from 'react-i18next';
|
|
9
10
|
|
|
@@ -11,20 +12,13 @@ import { Theme } from '../../Theme';
|
|
|
11
12
|
import { url as urlUtils } from '../../utils';
|
|
12
13
|
import CopyClipboard from '../CopyClipboard';
|
|
13
14
|
import { Git } from '../Icons';
|
|
14
|
-
import
|
|
15
|
+
import LinkExternal from '../LinkExternal';
|
|
15
16
|
|
|
16
17
|
const StyledText = styled(Typography)<{ theme?: Theme }>((props) => ({
|
|
17
18
|
fontWeight: props.theme?.fontWeight.bold,
|
|
18
19
|
textTransform: 'capitalize',
|
|
19
20
|
}));
|
|
20
21
|
|
|
21
|
-
const GithubLink = styled(Link)<{ theme?: Theme }>(({ theme }) => ({
|
|
22
|
-
color: theme?.palette.mode === 'light' ? theme?.palette.primary.main : theme?.palette.white,
|
|
23
|
-
':hover': {
|
|
24
|
-
color: theme?.palette.dodgerBlue,
|
|
25
|
-
},
|
|
26
|
-
}));
|
|
27
|
-
|
|
28
22
|
const RepositoryListItem = styled(ListItem)({
|
|
29
23
|
padding: 0,
|
|
30
24
|
':hover': {
|
|
@@ -33,18 +27,19 @@ const RepositoryListItem = styled(ListItem)({
|
|
|
33
27
|
});
|
|
34
28
|
|
|
35
29
|
const RepositoryListItemText = styled(ListItemText)({
|
|
36
|
-
padding: '0 10px',
|
|
30
|
+
padding: '0 0 0 10px',
|
|
37
31
|
margin: 0,
|
|
38
32
|
});
|
|
39
33
|
|
|
40
34
|
const RepositoryAvatar = styled(Avatar)({
|
|
41
|
-
|
|
42
|
-
|
|
35
|
+
padding: 0,
|
|
36
|
+
marginLeft: 0,
|
|
43
37
|
backgroundColor: 'transparent',
|
|
44
38
|
});
|
|
45
39
|
|
|
46
40
|
const Repository: React.FC<{ packageMeta: any }> = ({ packageMeta }) => {
|
|
47
41
|
const { t } = useTranslation();
|
|
42
|
+
const theme = useTheme();
|
|
48
43
|
const url = packageMeta?.latest?.repository?.url;
|
|
49
44
|
if (!url || !urlUtils.isURL(url)) {
|
|
50
45
|
return null;
|
|
@@ -66,15 +61,15 @@ const Repository: React.FC<{ packageMeta: any }> = ({ packageMeta }) => {
|
|
|
66
61
|
subheader={<StyledText variant="subtitle1">{t('sidebar.repository.title')}</StyledText>}
|
|
67
62
|
>
|
|
68
63
|
<RepositoryListItem>
|
|
69
|
-
<RepositoryAvatar sx={{
|
|
64
|
+
<RepositoryAvatar sx={{ bgcolor: theme.palette.white }}>
|
|
70
65
|
<Git />
|
|
71
66
|
</RepositoryAvatar>
|
|
72
67
|
<RepositoryListItemText
|
|
73
68
|
primary={
|
|
74
69
|
<CopyClipboard dataTestId="repositoryID" text={repositoryURL} title={repositoryURL}>
|
|
75
|
-
<
|
|
70
|
+
<LinkExternal to={repositoryURL} variant="outline">
|
|
76
71
|
{repositoryURL}
|
|
77
|
-
</
|
|
72
|
+
</LinkExternal>
|
|
78
73
|
</CopyClipboard>
|
|
79
74
|
}
|
|
80
75
|
/>
|
|
@@ -4,6 +4,7 @@ import { BrowserRouter as Router } from 'react-router-dom';
|
|
|
4
4
|
import { api, store } from '../../';
|
|
5
5
|
import { fireEvent, renderWithStore, screen, waitFor } from '../../test/test-react-testing-library';
|
|
6
6
|
import Search from './Search';
|
|
7
|
+
import { cleanDescription } from './utils';
|
|
7
8
|
|
|
8
9
|
jest.mock('lodash/debounce', () =>
|
|
9
10
|
jest.fn((fn) => {
|
|
@@ -45,7 +46,7 @@ describe('<Search /> component', () => {
|
|
|
45
46
|
});
|
|
46
47
|
|
|
47
48
|
test('handleSearch: when user type package name in search component, show suggestions', async () => {
|
|
48
|
-
const { getByPlaceholderText,
|
|
49
|
+
const { getByPlaceholderText, findAllByText } = renderWithStore(
|
|
49
50
|
<ComponentToBeRendered />,
|
|
50
51
|
store
|
|
51
52
|
);
|
|
@@ -57,14 +58,14 @@ describe('<Search /> component', () => {
|
|
|
57
58
|
|
|
58
59
|
expect(autoCompleteInput).toHaveAttribute('value', 'verdaccio');
|
|
59
60
|
|
|
60
|
-
const suggestionsElements = await waitFor(() =>
|
|
61
|
+
const suggestionsElements = await waitFor(() => findAllByText('verdaccio', { exact: true }));
|
|
61
62
|
|
|
62
63
|
expect(suggestionsElements).toHaveLength(1);
|
|
63
64
|
expect(api.request).toHaveBeenCalledTimes(1);
|
|
64
65
|
});
|
|
65
66
|
|
|
66
67
|
test('onBlur: should cancel all search requests', async () => {
|
|
67
|
-
const { getByPlaceholderText,
|
|
68
|
+
const { getByPlaceholderText, findAllByText } = renderWithStore(
|
|
68
69
|
<ComponentToBeRendered />,
|
|
69
70
|
store
|
|
70
71
|
);
|
|
@@ -75,7 +76,7 @@ describe('<Search /> component', () => {
|
|
|
75
76
|
fireEvent.change(autoCompleteInput, { target: { value: 'verdaccio' } });
|
|
76
77
|
expect(autoCompleteInput).toHaveAttribute('value', 'verdaccio');
|
|
77
78
|
|
|
78
|
-
const suggestionsElements = await waitFor(() =>
|
|
79
|
+
const suggestionsElements = await waitFor(() => findAllByText('verdaccio', { exact: true }));
|
|
79
80
|
expect(suggestionsElements).toHaveLength(1);
|
|
80
81
|
expect(api.request).toHaveBeenCalledTimes(1);
|
|
81
82
|
|
|
@@ -110,7 +111,7 @@ describe('<Search /> component', () => {
|
|
|
110
111
|
});
|
|
111
112
|
|
|
112
113
|
test('handlePackagesClearRequested: should clear suggestions', async () => {
|
|
113
|
-
const { getByPlaceholderText,
|
|
114
|
+
const { getByPlaceholderText, findAllByText } = renderWithStore(
|
|
114
115
|
<ComponentToBeRendered />,
|
|
115
116
|
store
|
|
116
117
|
);
|
|
@@ -120,18 +121,18 @@ describe('<Search /> component', () => {
|
|
|
120
121
|
fireEvent.change(autoCompleteInput, { target: { value: 'verdaccio' } });
|
|
121
122
|
expect(autoCompleteInput).toHaveAttribute('value', 'verdaccio');
|
|
122
123
|
|
|
123
|
-
const suggestionsElements = await waitFor(() =>
|
|
124
|
+
const suggestionsElements = await waitFor(() => findAllByText('verdaccio', { exact: true }));
|
|
124
125
|
expect(suggestionsElements).toHaveLength(1);
|
|
125
126
|
|
|
126
127
|
fireEvent.change(autoCompleteInput, { target: { value: ' ' } });
|
|
127
128
|
const listBoxElement = screen.queryAllByRole('listbox');
|
|
128
|
-
//
|
|
129
|
+
// when the page redirects, the list box should be empty again
|
|
129
130
|
expect(listBoxElement).toHaveLength(0);
|
|
130
131
|
expect(api.request).toHaveBeenCalledTimes(1);
|
|
131
132
|
});
|
|
132
133
|
|
|
133
134
|
test('handleClickSearch: should change the window location on click or return key', async () => {
|
|
134
|
-
const { getByPlaceholderText,
|
|
135
|
+
const { getByPlaceholderText, findAllByText } = renderWithStore(
|
|
135
136
|
<ComponentToBeRendered />,
|
|
136
137
|
store
|
|
137
138
|
);
|
|
@@ -141,7 +142,7 @@ describe('<Search /> component', () => {
|
|
|
141
142
|
fireEvent.change(autoCompleteInput, { target: { value: 'verdaccio' } });
|
|
142
143
|
expect(autoCompleteInput).toHaveAttribute('value', 'verdaccio');
|
|
143
144
|
|
|
144
|
-
const suggestionsElements = await waitFor(() =>
|
|
145
|
+
const suggestionsElements = await waitFor(() => findAllByText('verdaccio', { exact: true }));
|
|
145
146
|
// console.log('suggestionsElements', suggestionsElements);
|
|
146
147
|
expect(suggestionsElements).toHaveLength(1);
|
|
147
148
|
// click on the second suggestion
|
|
@@ -151,3 +152,29 @@ describe('<Search /> component', () => {
|
|
|
151
152
|
expect(listBoxElement).toHaveLength(0);
|
|
152
153
|
});
|
|
153
154
|
});
|
|
155
|
+
|
|
156
|
+
describe('cleanDescription', () => {
|
|
157
|
+
test('should return plain text', () => {
|
|
158
|
+
const description = 'Hello, Mars!';
|
|
159
|
+
const output = cleanDescription(description);
|
|
160
|
+
expect(output).toBe(description);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test('should remove html tags from description', () => {
|
|
164
|
+
const description = '<h1>verdaccio</h1>';
|
|
165
|
+
const output = cleanDescription(description);
|
|
166
|
+
expect(output).toBe('verdaccio');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test('should remove markdown links from description', () => {
|
|
170
|
+
const description = '[verdaccio](https://verdaccio.org)';
|
|
171
|
+
const output = cleanDescription(description);
|
|
172
|
+
expect(output).toBe('verdaccio');
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test('should remove markdown links', () => {
|
|
176
|
+
const description = '[]';
|
|
177
|
+
const output = cleanDescription(description);
|
|
178
|
+
expect(output).toBe('NPM version');
|
|
179
|
+
});
|
|
180
|
+
});
|
|
@@ -9,6 +9,7 @@ import { RouteComponentProps, withRouter } from 'react-router';
|
|
|
9
9
|
import { SearchResultWeb } from '@verdaccio/types';
|
|
10
10
|
|
|
11
11
|
import { Dispatch, RootState, useConfig } from '../../';
|
|
12
|
+
import { Route } from '../../utils';
|
|
12
13
|
import AutoComplete from './AutoComplete';
|
|
13
14
|
import SearchItem from './SearchItem';
|
|
14
15
|
import { StyledInputAdornment, StyledTextField } from './styles';
|
|
@@ -27,6 +28,7 @@ const Search: React.FC<RouteComponentProps> = ({ history }) => {
|
|
|
27
28
|
const { suggestions } = useSelector((state: RootState) => state.search);
|
|
28
29
|
const isLoading = useSelector((state: RootState) => state?.loading?.models.search);
|
|
29
30
|
const dispatch = useDispatch<Dispatch>();
|
|
31
|
+
|
|
30
32
|
/**
|
|
31
33
|
* Cancel all the requests which are in pending state.
|
|
32
34
|
*/
|
|
@@ -60,9 +62,9 @@ const Search: React.FC<RouteComponentProps> = ({ history }) => {
|
|
|
60
62
|
if (searchRemote) {
|
|
61
63
|
// TODO: check this part
|
|
62
64
|
// @ts-ignore
|
|
63
|
-
history.push(
|
|
65
|
+
history.push(`${Route.DETAIL}${value.package.name}`);
|
|
64
66
|
} else {
|
|
65
|
-
history.push(
|
|
67
|
+
history.push(`${Route.DETAIL}${value.name}`);
|
|
66
68
|
}
|
|
67
69
|
break;
|
|
68
70
|
}
|
|
@@ -9,6 +9,8 @@ import Stack from '@mui/material/Stack';
|
|
|
9
9
|
import React from 'react';
|
|
10
10
|
import { useTranslation } from 'react-i18next';
|
|
11
11
|
|
|
12
|
+
import { cleanDescription } from './utils';
|
|
13
|
+
|
|
12
14
|
type SearchItemProps = {
|
|
13
15
|
name: string;
|
|
14
16
|
version?: string;
|
|
@@ -28,15 +30,23 @@ export const Description = styled('div')<{ theme?: Theme }>(({ theme }) => ({
|
|
|
28
30
|
display: 'none',
|
|
29
31
|
color: theme?.palette?.greyLight2,
|
|
30
32
|
lineHeight: '1.5rem',
|
|
33
|
+
whiteSpace: 'nowrap',
|
|
34
|
+
textOverflow: 'ellipsis',
|
|
35
|
+
alignItems: 'center',
|
|
36
|
+
overflow: 'hidden',
|
|
37
|
+
paddingLeft: theme.spacing(),
|
|
38
|
+
fontSize: theme?.fontSize.ssm,
|
|
39
|
+
[`@media (min-width: ${theme?.breakPoints.medium}px)`]: {
|
|
40
|
+
display: 'block',
|
|
41
|
+
width: '300px',
|
|
42
|
+
},
|
|
31
43
|
[`@media (min-width: ${theme?.breakPoints.large}px)`]: {
|
|
32
44
|
display: 'block',
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
paddingLeft: theme.spacing(),
|
|
39
|
-
fontSize: theme?.fontSize.ssm,
|
|
45
|
+
width: '500px',
|
|
46
|
+
},
|
|
47
|
+
[`@media (min-width: 1440px)`]: {
|
|
48
|
+
display: 'block',
|
|
49
|
+
width: '600px',
|
|
40
50
|
},
|
|
41
51
|
}));
|
|
42
52
|
|
|
@@ -68,11 +78,12 @@ const SearchItem: React.FC<SearchItemProps> = ({
|
|
|
68
78
|
// no action assigned by default
|
|
69
79
|
};
|
|
70
80
|
return (
|
|
81
|
+
// eslint-disable-next-line verdaccio/jsx-no-style
|
|
71
82
|
<li {...props} style={{ flexDirection: 'column' }}>
|
|
72
83
|
<Wrapper>
|
|
73
84
|
<NameGroup>
|
|
74
85
|
<Name>{name}</Name>
|
|
75
|
-
{description && <Description>{description}</Description>}
|
|
86
|
+
{description && <Description>{cleanDescription(description)}</Description>}
|
|
76
87
|
</NameGroup>
|
|
77
88
|
{version && <Version>{version}</Version>}
|
|
78
89
|
</Wrapper>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
function removeHtmlTags(input: string): string {
|
|
2
|
+
let previous;
|
|
3
|
+
do {
|
|
4
|
+
previous = input;
|
|
5
|
+
input = input.replace(/<[^>]*>?/gm, '');
|
|
6
|
+
} while (input !== previous);
|
|
7
|
+
return input;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function cleanDescription(description: string): string {
|
|
11
|
+
let output = description;
|
|
12
|
+
// remove html tags from description (e.g. <h1...>)
|
|
13
|
+
output = removeHtmlTags(output);
|
|
14
|
+
// remove markdown links from description (e.g. [link](url))
|
|
15
|
+
output = output.replace(/\(.*?\)/gm, '').replace(/(\[!?|\])/gm, '');
|
|
16
|
+
return output;
|
|
17
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { fireEvent, render, screen } from '../../test/test-react-testing-library';
|
|
4
|
+
import SettingsMenu from './SettingsMenu';
|
|
5
|
+
|
|
6
|
+
describe('<SettingsMenu />', () => {
|
|
7
|
+
test('should handle menu open and close', async () => {
|
|
8
|
+
render(<SettingsMenu packageName="foo" />);
|
|
9
|
+
const button = screen.getByRole('button');
|
|
10
|
+
fireEvent.click(button);
|
|
11
|
+
await screen.findByRole('menu');
|
|
12
|
+
// TODO onClose
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test('should handle latest select', () => {
|
|
16
|
+
const { getByRole, getByText } = render(<SettingsMenu packageName="foo" />);
|
|
17
|
+
const button = getByRole('button');
|
|
18
|
+
fireEvent.click(button);
|
|
19
|
+
const menuItem = getByText('sidebar.installation.latest');
|
|
20
|
+
fireEvent.click(menuItem);
|
|
21
|
+
expect(getByText('sidebar.installation.latest')).toBeInTheDocument();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('should handle global select', () => {
|
|
25
|
+
const { getByRole, getByText } = render(<SettingsMenu packageName="foo" />);
|
|
26
|
+
const button = getByRole('button');
|
|
27
|
+
fireEvent.click(button);
|
|
28
|
+
const menuItem = getByText('sidebar.installation.global');
|
|
29
|
+
fireEvent.click(menuItem);
|
|
30
|
+
expect(getByText('sidebar.installation.global')).toBeInTheDocument();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('should handle yarn modern select', () => {
|
|
34
|
+
const { getByRole, getByText } = render(<SettingsMenu packageName="foo" />);
|
|
35
|
+
const button = getByRole('button');
|
|
36
|
+
fireEvent.click(button);
|
|
37
|
+
const menuItem = getByText('sidebar.installation.yarnModern');
|
|
38
|
+
fireEvent.click(menuItem);
|
|
39
|
+
expect(getByText('sidebar.installation.yarnModern')).toBeInTheDocument();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -7,24 +7,42 @@ import MenuItem from '@mui/material/MenuItem';
|
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import { useTranslation } from 'react-i18next';
|
|
9
9
|
|
|
10
|
+
import { useConfig } from '../../providers';
|
|
10
11
|
import { useSettings } from '../../providers/PersistenceSettingProvider';
|
|
11
12
|
|
|
12
13
|
interface Props {
|
|
13
14
|
packageName: string;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
const
|
|
17
|
+
const SettingsMenu: React.FC<Props> = ({ packageName }) => {
|
|
17
18
|
const { t } = useTranslation();
|
|
18
19
|
const { localSettings, updateSettings } = useSettings();
|
|
20
|
+
const { configOptions } = useConfig();
|
|
19
21
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
|
20
22
|
const open = Boolean(anchorEl);
|
|
21
23
|
const handleOpenMenu = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
22
24
|
setAnchorEl(event.currentTarget);
|
|
23
25
|
};
|
|
24
26
|
|
|
27
|
+
const handleLatestSelect = () => {
|
|
28
|
+
updateSettings({
|
|
29
|
+
...localSettings,
|
|
30
|
+
[packageName]: {
|
|
31
|
+
global: localSettings[packageName]?.global,
|
|
32
|
+
latest: !localSettings[packageName]?.latest,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
setAnchorEl(null);
|
|
36
|
+
};
|
|
37
|
+
|
|
25
38
|
const handleGlobalSelect = () => {
|
|
26
|
-
|
|
27
|
-
|
|
39
|
+
updateSettings({
|
|
40
|
+
...localSettings,
|
|
41
|
+
[packageName]: {
|
|
42
|
+
global: !localSettings[packageName]?.global,
|
|
43
|
+
latest: localSettings[packageName]?.latest,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
28
46
|
setAnchorEl(null);
|
|
29
47
|
};
|
|
30
48
|
|
|
@@ -38,6 +56,7 @@ const InstallListItem: React.FC<Props> = ({ packageName }) => {
|
|
|
38
56
|
setAnchorEl(null);
|
|
39
57
|
};
|
|
40
58
|
|
|
59
|
+
const statusLatest = localSettings[packageName]?.latest;
|
|
41
60
|
const statusGlobal = localSettings[packageName]?.global;
|
|
42
61
|
return (
|
|
43
62
|
<>
|
|
@@ -56,31 +75,50 @@ const InstallListItem: React.FC<Props> = ({ packageName }) => {
|
|
|
56
75
|
'aria-labelledby': 'basic-button',
|
|
57
76
|
}}
|
|
58
77
|
anchorEl={anchorEl}
|
|
78
|
+
anchorOrigin={{
|
|
79
|
+
vertical: 'bottom',
|
|
80
|
+
horizontal: 'right',
|
|
81
|
+
}}
|
|
59
82
|
id="basic-menu"
|
|
60
83
|
onClose={handleClose}
|
|
61
84
|
open={open}
|
|
85
|
+
transformOrigin={{
|
|
86
|
+
vertical: 'top',
|
|
87
|
+
horizontal: 'right',
|
|
88
|
+
}}
|
|
62
89
|
>
|
|
63
|
-
<MenuItem onClick={
|
|
90
|
+
<MenuItem onClick={handleLatestSelect}>
|
|
64
91
|
{' '}
|
|
65
|
-
{
|
|
92
|
+
{statusLatest === true ? (
|
|
66
93
|
<ListItemIcon>
|
|
67
94
|
<Check />
|
|
68
95
|
</ListItemIcon>
|
|
69
96
|
) : null}
|
|
70
|
-
{t('sidebar.installation.
|
|
97
|
+
{t('sidebar.installation.latest')}
|
|
71
98
|
</MenuItem>
|
|
72
|
-
<MenuItem onClick={
|
|
99
|
+
<MenuItem onClick={handleGlobalSelect}>
|
|
73
100
|
{' '}
|
|
74
|
-
{
|
|
101
|
+
{statusGlobal === true ? (
|
|
75
102
|
<ListItemIcon>
|
|
76
103
|
<Check />
|
|
77
104
|
</ListItemIcon>
|
|
78
105
|
) : null}
|
|
79
|
-
{t('sidebar.installation.
|
|
106
|
+
{t('sidebar.installation.global')}
|
|
80
107
|
</MenuItem>
|
|
108
|
+
{configOptions?.pkgManagers?.includes('yarn') && (
|
|
109
|
+
<MenuItem onClick={handleGlobalYarnModern}>
|
|
110
|
+
{' '}
|
|
111
|
+
{localSettings?.yarnModern ? (
|
|
112
|
+
<ListItemIcon>
|
|
113
|
+
<Check />
|
|
114
|
+
</ListItemIcon>
|
|
115
|
+
) : null}
|
|
116
|
+
{t('sidebar.installation.yarnModern')}
|
|
117
|
+
</MenuItem>
|
|
118
|
+
)}
|
|
81
119
|
</Menu>
|
|
82
120
|
</>
|
|
83
121
|
);
|
|
84
122
|
};
|
|
85
123
|
|
|
86
|
-
export default
|
|
124
|
+
export default SettingsMenu;
|
|
@@ -20,11 +20,23 @@ interface Props {
|
|
|
20
20
|
time: string;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
const Icon = styled.div<{ theme?: Theme }>(({ theme }) => ({
|
|
24
|
+
marginLeft: theme?.spacing(1),
|
|
25
|
+
}));
|
|
26
|
+
|
|
23
27
|
const ModuleJS: React.FC<{ module: ModuleType | void }> = ({ module }) => {
|
|
24
28
|
if (module === 'commonjs') {
|
|
25
|
-
return
|
|
29
|
+
return (
|
|
30
|
+
<Icon>
|
|
31
|
+
<CommonJS />
|
|
32
|
+
</Icon>
|
|
33
|
+
);
|
|
26
34
|
} else if (module === 'module') {
|
|
27
|
-
return
|
|
35
|
+
return (
|
|
36
|
+
<Icon>
|
|
37
|
+
<ES6Modules />
|
|
38
|
+
</Icon>
|
|
39
|
+
);
|
|
28
40
|
} else {
|
|
29
41
|
return null;
|
|
30
42
|
}
|
|
@@ -46,7 +58,11 @@ const DetailSidebarTitle: React.FC<Props> = ({
|
|
|
46
58
|
<TitleWrapper>
|
|
47
59
|
<>
|
|
48
60
|
{packageName}
|
|
49
|
-
{hasTypes &&
|
|
61
|
+
{hasTypes && (
|
|
62
|
+
<Icon>
|
|
63
|
+
<TypeScript />
|
|
64
|
+
</Icon>
|
|
65
|
+
)}
|
|
50
66
|
<ModuleJS module={moduleType} />
|
|
51
67
|
</>
|
|
52
68
|
</TitleWrapper>
|
|
@@ -44,4 +44,11 @@ describe('<UpLinks /> component', () => {
|
|
|
44
44
|
|
|
45
45
|
expect(wrapper).toMatchSnapshot();
|
|
46
46
|
});
|
|
47
|
+
|
|
48
|
+
test('should not render if input is missing', () => {
|
|
49
|
+
const wrapper = render(<UpLinks packageMeta={undefined} />);
|
|
50
|
+
// expect nothing to be rendered
|
|
51
|
+
expect(wrapper.queryByTestId('no-uplinks-npm')).toBeNull();
|
|
52
|
+
expect(wrapper.queryByTestId('uplinks')).toBeNull();
|
|
53
|
+
});
|
|
47
54
|
});
|