mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-03-18 02:22:46 -05:00
feat: ui improvements (#4071)
* feat: add download tarball indicator * Update ActionBar.test.tsx * fix: dark mode and readme css * Create long-jars-collect.md * Update long-jars-collect.md * feat: improve install commands * snapshots * feat: hide deprecated versions option * add testss * feat: display deprecated versions * add i18n * fix e2e * Update Readme.spec.tsx.snap
This commit is contained in:
parent
654caefff9
commit
580319a53a
44 changed files with 2811 additions and 1157 deletions
15
.changeset/long-jars-collect.md
Normal file
15
.changeset/long-jars-collect.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
'@verdaccio/ui-theme': minor
|
||||
'@verdaccio/ui-components': minor
|
||||
---
|
||||
|
||||
feat: ui improvements
|
||||
|
||||
Some UI improvements
|
||||
|
||||
- download progress indicator: https://github.com/verdaccio/verdaccio/discussions/4068
|
||||
- fix dark mode and readme css support https://github.com/verdaccio/verdaccio/discussions/3942 https://github.com/verdaccio/verdaccio/discussions/3467
|
||||
- fix global for yarn packages and add version to the packages on copy
|
||||
- feat: hide deprecated versions option
|
||||
- fix: improve deprecated package style
|
||||
- feat: display deprecated versions
|
|
@ -98,6 +98,7 @@ export type CommonWebConf = {
|
|||
showFooter?: boolean;
|
||||
showThemeSwitch?: boolean;
|
||||
showDownloadTarball?: boolean;
|
||||
hideDeprecatedVersions?: boolean;
|
||||
primaryColor: string;
|
||||
showRaw?: boolean;
|
||||
};
|
||||
|
|
|
@ -42,6 +42,7 @@ export default function renderHTML(config: ConfigYaml, manifest, manifestFiles,
|
|||
const base = getPublicUrl(config?.url_prefix, req);
|
||||
const basename = new URL(base).pathname;
|
||||
const language = config?.i18n?.web ?? DEFAULT_LANGUAGE;
|
||||
const hideDeprecatedVersions = config?.web?.hideDeprecatedVersions ?? false;
|
||||
// @ts-ignore
|
||||
const needHtmlCache = [undefined, null].includes(config?.web?.html_cache)
|
||||
? true
|
||||
|
@ -99,6 +100,7 @@ export default function renderHTML(config: ConfigYaml, manifest, manifestFiles,
|
|||
title,
|
||||
scope,
|
||||
language,
|
||||
hideDeprecatedVersions,
|
||||
};
|
||||
|
||||
let webPage;
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
"babel-loader": "8.3.0",
|
||||
"babel-plugin-dynamic-import-node": "2.3.3",
|
||||
"country-flag-icons": "1.5.5",
|
||||
"css-loader": "6.7.3",
|
||||
"css-loader": "6.8.1",
|
||||
"dayjs": "1.11.7",
|
||||
"dompurify": "2.4.5",
|
||||
"friendly-errors-webpack-plugin": "1.7.0",
|
||||
|
|
|
@ -53,7 +53,9 @@
|
|||
"versions": {
|
||||
"current-tags": "Current Tags",
|
||||
"version-history": "Version History",
|
||||
"not-available": "Not available"
|
||||
"not-available": "Not available",
|
||||
"deprecated": "Deprecated",
|
||||
"hide-deprecated": "All deprecated versions are hidden by global configuration"
|
||||
},
|
||||
"package": {
|
||||
"published-on": "Published on {{time}} •",
|
||||
|
@ -101,13 +103,8 @@
|
|||
},
|
||||
"installation": {
|
||||
"title": "Installation",
|
||||
"install-using-yarn": "Install using yarn",
|
||||
"install-using-yarn-command": "yarn add {{packageName}}",
|
||||
"install-using-npm": "Install using npm",
|
||||
"install-using-npm-command": "npm install {{packageName}}",
|
||||
"install-using-pnpm": "Install using pnpm",
|
||||
"install-using-pnpm-command": "pnpm install {{packageName}}",
|
||||
"global": "View as global"
|
||||
"global": "global package",
|
||||
"yarnModern": "yarn modern syntax"
|
||||
},
|
||||
"repository": {
|
||||
"title": "Repository"
|
||||
|
|
|
@ -4,6 +4,7 @@ web:
|
|||
primary_color: #CCC
|
||||
# showRaw: true
|
||||
# darkMode: true
|
||||
hideDeprecatedVersions: false
|
||||
pkgManagers:
|
||||
- npm
|
||||
- yarn
|
||||
|
|
|
@ -59,7 +59,16 @@ module.exports = {
|
|||
},
|
||||
{
|
||||
test: /\.css$/i,
|
||||
use: ['style-loader', 'css-loader'],
|
||||
use: [
|
||||
'style-loader',
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
importLoaders: 1,
|
||||
modules: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.md$/,
|
||||
|
|
|
@ -28,7 +28,6 @@ module.exports = Object.assign({}, config, {
|
|||
'\\.(svg)$': '<rootDir>/jest/unit/empty.ts',
|
||||
'\\.(jpg)$': '<rootDir>/jest/unit/empty.ts',
|
||||
'\\.(md)$': '<rootDir>/jest/unit/empty-string.ts',
|
||||
'github-markdown-css': '<rootDir>/jest/identity.js',
|
||||
'react-markdown': '<rootDir>/src/__mocks__/react-markdown.tsx',
|
||||
'remark-*': '<rootDir>/src/__mocks__/remark-plugin.ts',
|
||||
},
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"type-check": "tsc --noEmit -p tsconfig.build.json",
|
||||
"build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
|
||||
"build:js": "babel src/ --out-dir build/ --copy-files --no-copy-ignored --extensions \".ts,.tsx\" --source-maps --ignore \"src/**/*.stories.tsx\" --ignore \"src/**/*.test.tsx\" --ignore \"src/**/*.test.ts\"",
|
||||
"watch": "babel src/ --out-dir build/ --watch --copy-files --no-copy-ignored --extensions \".ts,.tsx\" --source-maps --ignore \"src/**/*.stories.tsx\" --ignore \"src/**/*.test.tsx\" --ignore \"src/**/*.test.ts\"",
|
||||
"build": "pnpm run build:js && pnpm run build:types",
|
||||
"start": "start-storybook -p 6006 -s ./public",
|
||||
"build-storybook": "build-storybook"
|
||||
|
@ -33,9 +34,9 @@
|
|||
"country-flag-icons": "1.5.5",
|
||||
"dayjs": "1.11.7",
|
||||
"dompurify": "2.4.5",
|
||||
"github-markdown-css": "5.2.0",
|
||||
"highlight.js": "11.7.0",
|
||||
"history": "4.10.1",
|
||||
"classnames": "2.3.2",
|
||||
"i18next": "20.6.1",
|
||||
"js-base64": "3.7.5",
|
||||
"localstorage-memory": "1.0.3",
|
||||
|
|
|
@ -20,7 +20,7 @@ const packageMeta = {
|
|||
dist: {
|
||||
fileCount: 0,
|
||||
unpackedSize: 0,
|
||||
tarball: 'https://registry.verdaccio.org/storybook/-/storybook-0.2.0.tgz',
|
||||
tarball: 'https://registry.npmjs.org/verdaccio/-/verdaccio-5.26.0.tgz',
|
||||
},
|
||||
homepage: 'https://verdaccio.org',
|
||||
bugs: {
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
import React from 'react';
|
||||
|
||||
import { store } from '../../store/store';
|
||||
import { cleanup, fireEvent, renderWithStore, screen } from '../../test/test-react-testing-library';
|
||||
import {
|
||||
cleanup,
|
||||
fireEvent,
|
||||
renderWithStore,
|
||||
screen,
|
||||
waitFor,
|
||||
} from '../../test/test-react-testing-library';
|
||||
import ActionBar from './ActionBar';
|
||||
|
||||
const defaultPackageMeta = {
|
||||
|
@ -27,8 +33,10 @@ describe('<ActionBar /> component', () => {
|
|||
});
|
||||
|
||||
test('should render the component in default state', () => {
|
||||
const { container } = renderWithStore(<ActionBar packageMeta={defaultPackageMeta} />, store);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
renderWithStore(<ActionBar packageMeta={defaultPackageMeta} />, store);
|
||||
expect(screen.getByTestId('download-tarball-btn')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('BugReportIcon')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('HomeIcon')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('when there is no action bar data', () => {
|
||||
|
@ -45,8 +53,10 @@ describe('<ActionBar /> component', () => {
|
|||
},
|
||||
};
|
||||
|
||||
const { container } = renderWithStore(<ActionBar packageMeta={packageMeta} />, store);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
renderWithStore(<ActionBar packageMeta={packageMeta} />, store);
|
||||
expect(screen.queryByTestId('download-tarball-btn')).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId('BugReportIcon')).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId('HomeIcon')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('when there is a button to download a tarball', () => {
|
||||
|
@ -59,11 +69,10 @@ describe('<ActionBar /> component', () => {
|
|||
expect(screen.getByLabelText('action-bar-action.raw')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('when click button to raw manifest open a dialog with viewver', () => {
|
||||
test('when click button to raw manifest open a dialog with viewer', async () => {
|
||||
renderWithStore(<ActionBar packageMeta={defaultPackageMeta} showRaw={true} />, store);
|
||||
fireEvent.click(screen.getByLabelText('action-bar-action.raw'));
|
||||
// TODO: fix this part
|
||||
// expect(screen.getByTestId('raw-viewver-dialog')).toBeInTheDocument();
|
||||
await waitFor(() => expect(screen.getByTestId('rawViewer--dialog')).toBeInTheDocument());
|
||||
});
|
||||
|
||||
test('should not display download tarball button', () => {
|
||||
|
@ -78,8 +87,6 @@ describe('<ActionBar /> component', () => {
|
|||
|
||||
test('when there is a button to open an issue', () => {
|
||||
renderWithStore(<ActionBar packageMeta={defaultPackageMeta} />, store);
|
||||
// TODO: should be visible by text
|
||||
// expect(screen.getByLabelText('action-bar-action.open-an-issue')).toBeTruthy();
|
||||
expect(screen.getByTestId('BugReportIcon')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
/* eslint-disable verdaccio/jsx-spread */
|
||||
import Box from '@mui/material/Box';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { url } from '../../utils';
|
||||
|
@ -40,18 +42,20 @@ const ActionBar: React.FC<Props> = ({ showRaw, showDownloadTarball = true, packa
|
|||
|
||||
return (
|
||||
<Box alignItems="center" display="flex" marginBottom="14px">
|
||||
{actions.map((action) => (
|
||||
<ActionBarAction key={action.type} {...action} />
|
||||
))}
|
||||
{isRawViewerOpen && (
|
||||
<RawViewer
|
||||
isOpen={isRawViewerOpen}
|
||||
onClose={() => {
|
||||
setIsRawViewerOpen(false);
|
||||
}}
|
||||
packageMeta={packageMeta}
|
||||
/>
|
||||
)}
|
||||
<Stack direction="row" spacing={1}>
|
||||
{actions.map((action) => (
|
||||
<ActionBarAction key={action.type} {...action} />
|
||||
))}
|
||||
{isRawViewerOpen && (
|
||||
<RawViewer
|
||||
isOpen={isRawViewerOpen}
|
||||
onClose={() => {
|
||||
setIsRawViewerOpen(false);
|
||||
}}
|
||||
packageMeta={packageMeta}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -3,25 +3,21 @@ import BugReportIcon from '@mui/icons-material/BugReport';
|
|||
import DownloadIcon from '@mui/icons-material/CloudDownload';
|
||||
import HomeIcon from '@mui/icons-material/Home';
|
||||
import RawOnIcon from '@mui/icons-material/RawOn';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import FabMUI from '@mui/material/Fab';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import React, { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { Theme } from '../../Theme';
|
||||
import { Dispatch } from '../../store/store';
|
||||
import { Dispatch, RootState } from '../../store/store';
|
||||
import { Link } from '../Link';
|
||||
|
||||
export const Fab = styled(FabMUI)<{ theme?: Theme }>(({ theme }) => ({
|
||||
backgroundColor:
|
||||
theme?.palette.mode === 'light' ? theme?.palette.primary.main : theme?.palette.cyanBlue,
|
||||
color: theme?.palette.white,
|
||||
marginRight: 10,
|
||||
':hover': {
|
||||
color: theme?.palette.mode === 'light' ? theme?.palette.primary.main : theme?.palette.cyanBlue,
|
||||
background: theme?.palette.white,
|
||||
},
|
||||
}));
|
||||
|
||||
type ActionType = 'VISIT_HOMEPAGE' | 'OPEN_AN_ISSUE' | 'DOWNLOAD_TARBALL' | 'RAW_DATA';
|
||||
|
@ -36,6 +32,7 @@ export interface ActionBarActionProps {
|
|||
const ActionBarAction: React.FC<ActionBarActionProps> = ({ type, link, action }) => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch<Dispatch>();
|
||||
const isLoading = useSelector((state: RootState) => state?.loading?.models.download);
|
||||
|
||||
const handleDownload = useCallback(async () => {
|
||||
dispatch.download.getTarball({ link });
|
||||
|
@ -65,9 +62,17 @@ const ActionBarAction: React.FC<ActionBarActionProps> = ({ type, link, action })
|
|||
case 'DOWNLOAD_TARBALL':
|
||||
return (
|
||||
<Tooltip title={t('action-bar-action.download-tarball') as string}>
|
||||
<Fab data-testid="download-tarball-btn" onClick={handleDownload} size="small">
|
||||
<DownloadIcon />
|
||||
</Fab>
|
||||
{isLoading ? (
|
||||
<CircularProgress sx={{ marginX: 0 }}>
|
||||
<Fab data-testid="download-tarball-btn" onClick={handleDownload} size="small">
|
||||
<DownloadIcon />
|
||||
</Fab>
|
||||
</CircularProgress>
|
||||
) : (
|
||||
<Fab data-testid="download-tarball-btn" onClick={handleDownload} size="small">
|
||||
<DownloadIcon />
|
||||
</Fab>
|
||||
)}
|
||||
</Tooltip>
|
||||
);
|
||||
case 'RAW_DATA':
|
||||
|
|
|
@ -1,263 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<ActionBar /> component should render the component in default state 1`] = `
|
||||
.emotion-0 {
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.emotion-1 {
|
||||
margin: 0;
|
||||
font-family: -apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.75;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.emotion-3 {
|
||||
display: -webkit-inline-box;
|
||||
display: -webkit-inline-flex;
|
||||
display: -ms-inline-flexbox;
|
||||
display: inline-flex;
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
background-color: transparent;
|
||||
outline: 0;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
vertical-align: middle;
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-webkit-text-decoration: none;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
font-family: -apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.75;
|
||||
text-transform: uppercase;
|
||||
min-height: 36px;
|
||||
-webkit-transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,border-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
|
||||
transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,border-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
|
||||
border-radius: 50%;
|
||||
padding: 0;
|
||||
min-width: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
z-index: 1050;
|
||||
box-shadow: 0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12);
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
background-color: #e0e0e0;
|
||||
background-color: #4b5e40;
|
||||
color: #fff;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.emotion-3::-moz-focus-inner {
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
.emotion-3.Mui-disabled {
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
@media print {
|
||||
.emotion-3 {
|
||||
-webkit-print-color-adjust: exact;
|
||||
color-adjust: exact;
|
||||
}
|
||||
}
|
||||
|
||||
.emotion-3:active {
|
||||
box-shadow: 0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12);
|
||||
}
|
||||
|
||||
.emotion-3:hover {
|
||||
background-color: #f5f5f5;
|
||||
-webkit-text-decoration: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (hover: none) {
|
||||
.emotion-3:hover {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
}
|
||||
|
||||
.emotion-3.Mui-focusVisible {
|
||||
box-shadow: 0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12);
|
||||
}
|
||||
|
||||
.emotion-3.Mui-disabled {
|
||||
color: rgba(0, 0, 0, 0.26);
|
||||
box-shadow: none;
|
||||
background-color: rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.emotion-3:hover {
|
||||
color: #4b5e40;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.emotion-4 {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
display: inline-block;
|
||||
fill: currentColor;
|
||||
-webkit-flex-shrink: 0;
|
||||
-ms-flex-negative: 0;
|
||||
flex-shrink: 0;
|
||||
-webkit-transition: fill 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
|
||||
transition: fill 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.emotion-5 {
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
<div
|
||||
class="MuiBox-root emotion-0"
|
||||
>
|
||||
<a
|
||||
class=""
|
||||
href="https://verdaccio.org"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiTypography-button emotion-1"
|
||||
>
|
||||
<button
|
||||
class="MuiButtonBase-root MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default emotion-2 emotion-3"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium emotion-4"
|
||||
data-testid="HomeIcon"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"
|
||||
/>
|
||||
</svg>
|
||||
<span
|
||||
class="MuiTouchRipple-root emotion-5"
|
||||
/>
|
||||
</button>
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="https://github.com/verdaccio/monorepo/issues"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiTypography-button emotion-1"
|
||||
>
|
||||
<button
|
||||
class="MuiButtonBase-root MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default emotion-2 emotion-3"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium emotion-4"
|
||||
data-testid="BugReportIcon"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5c-.49 0-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z"
|
||||
/>
|
||||
</svg>
|
||||
<span
|
||||
class="MuiTouchRipple-root emotion-5"
|
||||
/>
|
||||
</button>
|
||||
</span>
|
||||
</a>
|
||||
<button
|
||||
aria-label="action-bar-action.download-tarball"
|
||||
class="MuiButtonBase-root MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-default emotion-2 emotion-3"
|
||||
data-mui-internal-clone-element="true"
|
||||
data-testid="download-tarball-btn"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium emotion-4"
|
||||
data-testid="CloudDownloadIcon"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM17 13l-5 5-5-5h3V9h4v4h3z"
|
||||
/>
|
||||
</svg>
|
||||
<span
|
||||
class="MuiTouchRipple-root emotion-5"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<ActionBar /> component when there is no action bar data 1`] = `
|
||||
.emotion-0 {
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
<div
|
||||
class="MuiBox-root emotion-0"
|
||||
/>
|
||||
`;
|
|
@ -1,11 +1,13 @@
|
|||
import { Typography } from '@mui/material';
|
||||
import Avatar from '@mui/material/Avatar';
|
||||
import List from '@mui/material/List';
|
||||
import { useTheme } from '@mui/styles';
|
||||
import i18next from 'i18next';
|
||||
import React, { FC } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { url } from '../../utils';
|
||||
import { AuthorListItem, AuthorListItemText, StyledText } from './styles';
|
||||
import { AuthorListItem, StyledText } from './styles';
|
||||
|
||||
export function getAuthorName(authorName?: string): string {
|
||||
if (!authorName) {
|
||||
|
@ -26,6 +28,8 @@ export function getAuthorName(authorName?: string): string {
|
|||
const Author: FC<{ packageMeta }> = ({ packageMeta }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
if (!packageMeta) {
|
||||
return null;
|
||||
}
|
||||
|
@ -37,8 +41,13 @@ const Author: FC<{ packageMeta }> = ({ packageMeta }) => {
|
|||
}
|
||||
|
||||
const { email, name } = author;
|
||||
|
||||
const avatarComponent = <Avatar alt={author.name} src={author.avatar} />;
|
||||
const avatarComponent = (
|
||||
<Avatar
|
||||
alt={author.name}
|
||||
src={author.avatar}
|
||||
sx={{ width: 40, height: 40, marginRight: theme.spacing(1) }}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<List subheader={<StyledText variant={'subtitle1'}>{t('sidebar.author.title')}</StyledText>}>
|
||||
|
@ -50,7 +59,7 @@ const Author: FC<{ packageMeta }> = ({ packageMeta }) => {
|
|||
{avatarComponent}
|
||||
</a>
|
||||
)}
|
||||
{name && <AuthorListItemText primary={getAuthorName(name)} />}
|
||||
{name && <Typography variant="subtitle2">{getAuthorName(name)}</Typography>}
|
||||
</AuthorListItem>
|
||||
</List>
|
||||
);
|
||||
|
|
|
@ -95,6 +95,9 @@ exports[`<Author /> component should render the component in default state 1`] =
|
|||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.emotion-6 {
|
||||
|
@ -106,24 +109,12 @@ exports[`<Author /> component should render the component in default state 1`] =
|
|||
text-indent: 10000px;
|
||||
}
|
||||
|
||||
.emotion-8 {
|
||||
-webkit-flex: 1 1 auto;
|
||||
-ms-flex: 1 1 auto;
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
padding: 0 10px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.emotion-9 {
|
||||
.emotion-7 {
|
||||
margin: 0;
|
||||
font-family: -apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
display: block;
|
||||
font-weight: 500;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.57;
|
||||
}
|
||||
|
||||
<body>
|
||||
|
@ -153,15 +144,11 @@ exports[`<Author /> component should render the component in default state 1`] =
|
|||
/>
|
||||
</div>
|
||||
</a>
|
||||
<div
|
||||
class="MuiListItemText-root emotion-7 emotion-8"
|
||||
<h6
|
||||
class="MuiTypography-root MuiTypography-subtitle2 emotion-7"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiTypography-body1 MuiListItemText-primary emotion-9"
|
||||
>
|
||||
verdaccio user
|
||||
</span>
|
||||
</div>
|
||||
verdaccio user
|
||||
</h6>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -258,6 +245,9 @@ exports[`<Author /> component should render the component in default state 1`] =
|
|||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.emotion-6 {
|
||||
|
@ -269,24 +259,12 @@ exports[`<Author /> component should render the component in default state 1`] =
|
|||
text-indent: 10000px;
|
||||
}
|
||||
|
||||
.emotion-8 {
|
||||
-webkit-flex: 1 1 auto;
|
||||
-ms-flex: 1 1 auto;
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
padding: 0 10px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.emotion-9 {
|
||||
.emotion-7 {
|
||||
margin: 0;
|
||||
font-family: -apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
display: block;
|
||||
font-weight: 500;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.57;
|
||||
}
|
||||
|
||||
<div>
|
||||
|
@ -315,15 +293,11 @@ exports[`<Author /> component should render the component in default state 1`] =
|
|||
/>
|
||||
</div>
|
||||
</a>
|
||||
<div
|
||||
class="MuiListItemText-root emotion-7 emotion-8"
|
||||
<h6
|
||||
class="MuiTypography-root MuiTypography-subtitle2 emotion-7"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiTypography-body1 MuiListItemText-primary emotion-9"
|
||||
>
|
||||
verdaccio user
|
||||
</span>
|
||||
</div>
|
||||
verdaccio user
|
||||
</h6>
|
||||
</li>
|
||||
</ul>
|
||||
</div>,
|
||||
|
@ -476,6 +450,9 @@ exports[`<Author /> component should render the component when there is no autho
|
|||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.emotion-6 {
|
||||
|
@ -487,24 +464,12 @@ exports[`<Author /> component should render the component when there is no autho
|
|||
text-indent: 10000px;
|
||||
}
|
||||
|
||||
.emotion-8 {
|
||||
-webkit-flex: 1 1 auto;
|
||||
-ms-flex: 1 1 auto;
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
padding: 0 10px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.emotion-9 {
|
||||
.emotion-7 {
|
||||
margin: 0;
|
||||
font-family: -apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
display: block;
|
||||
font-weight: 500;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.57;
|
||||
}
|
||||
|
||||
<body>
|
||||
|
@ -529,15 +494,11 @@ exports[`<Author /> component should render the component when there is no autho
|
|||
src="https://www.gravatar.com/avatar/000000"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="MuiListItemText-root emotion-7 emotion-8"
|
||||
<h6
|
||||
class="MuiTypography-root MuiTypography-subtitle2 emotion-7"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiTypography-body1 MuiListItemText-primary emotion-9"
|
||||
>
|
||||
verdaccio user
|
||||
</span>
|
||||
</div>
|
||||
verdaccio user
|
||||
</h6>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -634,6 +595,9 @@ exports[`<Author /> component should render the component when there is no autho
|
|||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.emotion-6 {
|
||||
|
@ -645,24 +609,12 @@ exports[`<Author /> component should render the component when there is no autho
|
|||
text-indent: 10000px;
|
||||
}
|
||||
|
||||
.emotion-8 {
|
||||
-webkit-flex: 1 1 auto;
|
||||
-ms-flex: 1 1 auto;
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
padding: 0 10px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.emotion-9 {
|
||||
.emotion-7 {
|
||||
margin: 0;
|
||||
font-family: -apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
display: block;
|
||||
font-weight: 500;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.57;
|
||||
}
|
||||
|
||||
<div>
|
||||
|
@ -686,15 +638,11 @@ exports[`<Author /> component should render the component when there is no autho
|
|||
src="https://www.gravatar.com/avatar/000000"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="MuiListItemText-root emotion-7 emotion-8"
|
||||
<h6
|
||||
class="MuiTypography-root MuiTypography-subtitle2 emotion-7"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiTypography-body1 MuiListItemText-primary emotion-9"
|
||||
>
|
||||
verdaccio user
|
||||
</span>
|
||||
</div>
|
||||
verdaccio user
|
||||
</h6>
|
||||
</li>
|
||||
</ul>
|
||||
</div>,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import styled from '@emotion/styled';
|
||||
import { Typography } from '@mui/material';
|
||||
import ListItem from '@mui/material/ListItem';
|
||||
import ListItemText from '@mui/material/ListItemText';
|
||||
|
||||
import { Theme } from '../../Theme';
|
||||
|
||||
|
@ -15,8 +14,3 @@ export const AuthorListItem = styled(ListItem)({
|
|||
backgroundColor: 'transparent',
|
||||
},
|
||||
});
|
||||
|
||||
export const AuthorListItemText = styled(ListItemText)({
|
||||
padding: '0 10px',
|
||||
margin: 0,
|
||||
});
|
||||
|
|
|
@ -4,6 +4,7 @@ import IconButton from '@mui/material/IconButton';
|
|||
import Tooltip from '@mui/material/Tooltip';
|
||||
import React from 'react';
|
||||
|
||||
import { Theme } from '../../Theme';
|
||||
import { copyToClipBoardUtility } from './utils';
|
||||
|
||||
interface Props {
|
||||
|
@ -19,14 +20,14 @@ const Wrapper = styled('div')({
|
|||
justifyContent: 'space-between',
|
||||
});
|
||||
|
||||
const Content = styled('span')({
|
||||
const Content = styled('span')<{ theme?: Theme }>(({ theme }) => ({
|
||||
display: 'inline-block',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
height: 'auto',
|
||||
whiteSpace: 'break-spaces',
|
||||
fontSize: '1rem',
|
||||
});
|
||||
fontSize: theme?.fontSize.sm,
|
||||
}));
|
||||
|
||||
function CopyToClipBoard({ text, children, dataTestId, title, ...props }: Props) {
|
||||
return (
|
||||
|
|
|
@ -1,30 +1,17 @@
|
|||
import Card from '@mui/material/Card';
|
||||
import CardContent from '@mui/material/CardContent';
|
||||
import { styled } from '@mui/system';
|
||||
import Alert from '@mui/material/Alert';
|
||||
import { useTheme } from '@mui/styles';
|
||||
import React from 'react';
|
||||
|
||||
import { Theme } from '../../Theme';
|
||||
|
||||
export const CardStyled = styled(Card)<{ theme?: Theme }>(({ theme }) => {
|
||||
return {
|
||||
marginTop: theme?.spacing(1),
|
||||
marginBottom: theme?.spacing(0.5),
|
||||
backgroundColor: theme?.palette?.error.light,
|
||||
opacity: '0.9',
|
||||
color: theme?.palette?.error.contrastText,
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
});
|
||||
|
||||
export type Props = {
|
||||
message: string;
|
||||
};
|
||||
|
||||
const Deprecated: React.FC<Props> = ({ message }) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<CardStyled>
|
||||
<CardContent>{message}</CardContent>
|
||||
</CardStyled>
|
||||
<Alert severity="warning" sx={{ marginTop: theme.spacing(1), marginBottom: theme.spacing(1) }}>
|
||||
{message}
|
||||
</Alert>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Typography } from '@mui/material';
|
||||
import Avatar from '@mui/material/Avatar';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import List from '@mui/material/List';
|
||||
import ListItemText from '@mui/material/ListItemText';
|
||||
import React, { FC } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
|
@ -24,7 +24,7 @@ const EngineItem: FC<EngineItemProps> = ({ title, element, engineText }) => (
|
|||
<List subheader={<StyledText variant={'subtitle1'}>{title}</StyledText>}>
|
||||
<EngineListItem>
|
||||
<Avatar sx={{ bgcolor: '#FFF' }}>{element}</Avatar>
|
||||
<ListItemText primary={engineText} />
|
||||
<Typography variant="subtitle2">{engineText}</Typography>
|
||||
</EngineListItem>
|
||||
</List>
|
||||
</Grid>
|
||||
|
|
|
@ -69,7 +69,7 @@ exports[`<Help /> component should load the component in default state 1`] = `
|
|||
text-overflow: ellipsis;
|
||||
height: auto;
|
||||
white-space: break-spaces;
|
||||
font-size: 1rem;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.emotion-10 {
|
||||
|
|
|
@ -5,6 +5,7 @@ import { PackageManagers } from '@verdaccio/types';
|
|||
import { useConfig } from '../../providers';
|
||||
import { render, screen } from '../../test/test-react-testing-library';
|
||||
import Install from './Install';
|
||||
import { getGlobalInstall } from './InstallListItem';
|
||||
import data from './__partials__/data.json';
|
||||
|
||||
const ComponentToBeRendered: React.FC<{ pkgManagers?: PackageManagers[] }> = () => {
|
||||
|
@ -16,12 +17,9 @@ const ComponentToBeRendered: React.FC<{ pkgManagers?: PackageManagers[] }> = ()
|
|||
describe('<Install />', () => {
|
||||
test('renders correctly', () => {
|
||||
render(<ComponentToBeRendered />);
|
||||
expect(screen.getByText('sidebar.installation.install-using-pnpm')).toBeInTheDocument();
|
||||
expect(screen.getByText('sidebar.installation.install-using-yarn')).toBeInTheDocument();
|
||||
expect(screen.getByText('sidebar.installation.install-using-npm')).toBeInTheDocument();
|
||||
expect(screen.getByText('sidebar.installation.install-using-npm-command')).toBeInTheDocument();
|
||||
expect(screen.getByText('sidebar.installation.install-using-yarn-command')).toBeInTheDocument();
|
||||
expect(screen.getByText('sidebar.installation.install-using-pnpm-command')).toBeInTheDocument();
|
||||
expect(screen.getByText('yarn add foo@8.0.0')).toBeInTheDocument();
|
||||
expect(screen.getByText('pnpm install foo@8.0.0')).toBeInTheDocument();
|
||||
expect(screen.getByText('npm install foo@8.0.0')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should have 3 children', () => {
|
||||
|
@ -38,47 +36,41 @@ describe('<Install />', () => {
|
|||
render(<ComponentToBeRendered />);
|
||||
|
||||
expect(screen.getByText('sidebar.installation.title')).toBeTruthy();
|
||||
expect(screen.queryByText('sidebar.installation.install-using-pnpm')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('sidebar.installation.install-using-yarn')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('sidebar.installation.install-using-npm')).toBeInTheDocument();
|
||||
expect(screen.getByText('sidebar.installation.install-using-npm-command')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByText('sidebar.installation.install-using-yarn-command')
|
||||
).not.toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByText('sidebar.installation.install-using-pnpm-command')
|
||||
).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('pnpm')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('yarn')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('npm install foo@8.0.0')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should have the element YARN', () => {
|
||||
window.__VERDACCIO_BASENAME_UI_OPTIONS.pkgManagers = ['yarn'];
|
||||
render(<ComponentToBeRendered />);
|
||||
expect(screen.getByText('sidebar.installation.title')).toBeTruthy();
|
||||
expect(screen.queryByText('sidebar.installation.install-using-pnpm')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('sidebar.installation.install-using-yarn')).toBeInTheDocument();
|
||||
expect(screen.queryByText('sidebar.installation.install-using-npm')).not.toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByText('sidebar.installation.install-using-npm-command')
|
||||
).not.toBeInTheDocument();
|
||||
expect(screen.getByText('sidebar.installation.install-using-yarn-command')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByText('sidebar.installation.install-using-pnpm-command')
|
||||
).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('pnpm')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('npm')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('yarn add foo@8.0.0')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should have the element PNPM', () => {
|
||||
window.__VERDACCIO_BASENAME_UI_OPTIONS.pkgManagers = ['pnpm'];
|
||||
render(<ComponentToBeRendered />);
|
||||
expect(screen.getByText('sidebar.installation.title')).toBeTruthy();
|
||||
expect(screen.getByText('sidebar.installation.install-using-pnpm')).toBeInTheDocument();
|
||||
expect(screen.queryByText('sidebar.installation.install-using-yarn')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('sidebar.installation.install-using-npm')).not.toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByText('sidebar.installation.install-using-npm-command')
|
||||
).not.toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByText('sidebar.installation.install-using-yarn-command')
|
||||
).not.toBeInTheDocument();
|
||||
expect(screen.getByText('sidebar.installation.install-using-pnpm-command')).toBeInTheDocument();
|
||||
expect(screen.queryByText('pnpm')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('yarn')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('pnpm install foo@8.0.0')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getGlobalInstall', () => {
|
||||
test('no global', () => {
|
||||
expect(getGlobalInstall(false, 'foo', '1.0.0')).toEqual('1.0.0@foo');
|
||||
});
|
||||
test('global', () => {
|
||||
expect(getGlobalInstall(true, 'foo', '1.0.0')).toEqual('-g 1.0.0@foo');
|
||||
});
|
||||
|
||||
test('yarn no global', () => {
|
||||
expect(getGlobalInstall(false, 'foo', '1.0.0', true)).toEqual('1.0.0@foo');
|
||||
});
|
||||
test('yarn global', () => {
|
||||
expect(getGlobalInstall(true, 'foo', '1.0.0', true)).toEqual('1.0.0@foo');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -27,7 +27,6 @@ export type Props = {
|
|||
const Install: React.FC<Props> = ({ packageMeta, packageName, configOptions }) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
|
||||
if (!packageMeta || !packageName) {
|
||||
return null;
|
||||
}
|
||||
|
@ -51,13 +50,25 @@ const Install: React.FC<Props> = ({ packageMeta, packageName, configOptions }) =
|
|||
subheader={<StyledText variant={'subtitle1'}>{t('sidebar.installation.title')}</StyledText>}
|
||||
>
|
||||
{hasNpm && (
|
||||
<InstallListItem dependencyManager={DependencyManager.NPM} packageName={packageName} />
|
||||
<InstallListItem
|
||||
dependencyManager={DependencyManager.NPM}
|
||||
packageName={packageName}
|
||||
packageVersion={packageMeta.latest.version}
|
||||
/>
|
||||
)}
|
||||
{hasYarn && (
|
||||
<InstallListItem dependencyManager={DependencyManager.YARN} packageName={packageName} />
|
||||
<InstallListItem
|
||||
dependencyManager={DependencyManager.YARN}
|
||||
packageName={packageName}
|
||||
packageVersion={packageMeta.latest.version}
|
||||
/>
|
||||
)}
|
||||
{hasPnpm && (
|
||||
<InstallListItem dependencyManager={DependencyManager.PNPM} packageName={packageName} />
|
||||
<InstallListItem
|
||||
dependencyManager={DependencyManager.PNPM}
|
||||
packageName={packageName}
|
||||
packageVersion={packageMeta.latest.version}
|
||||
/>
|
||||
)}
|
||||
</List>
|
||||
</>
|
||||
|
|
|
@ -2,8 +2,8 @@ import styled from '@emotion/styled';
|
|||
import Avatar from '@mui/material/Avatar';
|
||||
import ListItem from '@mui/material/ListItem';
|
||||
import ListItemText from '@mui/material/ListItemText';
|
||||
import { useTheme } from '@mui/styles';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useSettings } from '../../providers/PersistenceSettingProvider';
|
||||
import CopyToClipBoard from '../CopyClipboard';
|
||||
|
@ -35,78 +35,94 @@ export enum DependencyManager {
|
|||
interface Interface {
|
||||
packageName: string;
|
||||
dependencyManager: DependencyManager;
|
||||
packageVersion?: string;
|
||||
}
|
||||
|
||||
const InstallListItem: React.FC<Interface> = ({ packageName, dependencyManager }) => {
|
||||
const { t } = useTranslation();
|
||||
const { localSettings } = useSettings();
|
||||
const isGlobal = localSettings[packageName]?.global ?? false;
|
||||
const pkgName = isGlobal ? `-g ${packageName}` : packageName;
|
||||
export function getGlobalInstall(isGlobal, packageVersion, packageName, isYarn = false) {
|
||||
const name = isGlobal
|
||||
? `${isYarn ? '' : '-g'} ${packageVersion ? `${packageName}@${packageVersion}` : packageName}`
|
||||
: packageVersion
|
||||
? `${packageName}@${packageVersion}`
|
||||
: packageName;
|
||||
|
||||
return name.trim();
|
||||
}
|
||||
|
||||
const InstallListItem: React.FC<Interface> = ({
|
||||
packageName,
|
||||
dependencyManager,
|
||||
packageVersion,
|
||||
}) => {
|
||||
const { localSettings } = useSettings();
|
||||
const theme = useTheme();
|
||||
const isGlobal = localSettings[packageName]?.global ?? false;
|
||||
switch (dependencyManager) {
|
||||
case DependencyManager.NPM:
|
||||
return (
|
||||
<InstallItem data-testid={'installListItem-npm'}>
|
||||
<PackageMangerAvatar alt="npm" sx={{ bgcolor: '#FFF' }}>
|
||||
<PackageMangerAvatar alt="npm" sx={{ bgcolor: theme.palette.white }}>
|
||||
<Npm />
|
||||
</PackageMangerAvatar>
|
||||
<InstallListItemText
|
||||
primary={
|
||||
<CopyToClipBoard
|
||||
dataTestId="installYarn"
|
||||
text={t('sidebar.installation.install-using-npm-command', {
|
||||
packageName: pkgName,
|
||||
})}
|
||||
title={t('sidebar.installation.install-using-npm-command', {
|
||||
packageName: pkgName,
|
||||
})}
|
||||
dataTestId="instalNpm"
|
||||
text={`npm install ${getGlobalInstall(isGlobal, packageVersion, packageName)}`}
|
||||
title={`npm install ${getGlobalInstall(isGlobal, packageVersion, packageName)}`}
|
||||
/>
|
||||
}
|
||||
secondary={t('sidebar.installation.install-using-npm')}
|
||||
/>
|
||||
</InstallItem>
|
||||
);
|
||||
case DependencyManager.YARN:
|
||||
return (
|
||||
<InstallItem data-testid={'installListItem-yarn'}>
|
||||
<PackageMangerAvatar alt="yarn" sx={{ bgcolor: '#FFF' }}>
|
||||
<PackageMangerAvatar alt="yarn" sx={{ bgcolor: theme.palette.white }}>
|
||||
<Yarn />
|
||||
</PackageMangerAvatar>
|
||||
<InstallListItemText
|
||||
primary={
|
||||
<CopyToClipBoard
|
||||
dataTestId="installYarn"
|
||||
text={t('sidebar.installation.install-using-yarn-command', {
|
||||
packageName: pkgName,
|
||||
})}
|
||||
title={t('sidebar.installation.install-using-yarn-command', {
|
||||
packageName: pkgName,
|
||||
})}
|
||||
text={
|
||||
isGlobal
|
||||
? `yarn ${localSettings.yarnModern ? '' : 'global'} add ${getGlobalInstall(
|
||||
isGlobal,
|
||||
packageVersion,
|
||||
packageName,
|
||||
true
|
||||
)}`
|
||||
: `yarn add ${getGlobalInstall(isGlobal, packageVersion, packageName, true)}`
|
||||
}
|
||||
title={
|
||||
isGlobal
|
||||
? `yarn global add ${getGlobalInstall(
|
||||
isGlobal,
|
||||
packageVersion,
|
||||
packageName,
|
||||
true
|
||||
)}`
|
||||
: `yarn add ${getGlobalInstall(isGlobal, packageVersion, packageName, true)}`
|
||||
}
|
||||
/>
|
||||
}
|
||||
secondary={t('sidebar.installation.install-using-yarn')}
|
||||
/>
|
||||
</InstallItem>
|
||||
);
|
||||
case DependencyManager.PNPM:
|
||||
return (
|
||||
<InstallItem data-testid={'installListItem-pnpm'}>
|
||||
<PackageMangerAvatar alt={'pnpm'} sx={{ bgcolor: '#FFF' }}>
|
||||
<PackageMangerAvatar alt={'pnpm'} sx={{ bgcolor: theme.palette.white }}>
|
||||
<Pnpm />
|
||||
</PackageMangerAvatar>
|
||||
<InstallListItemText
|
||||
primary={
|
||||
<CopyToClipBoard
|
||||
dataTestId="installPnpm"
|
||||
text={t('sidebar.installation.install-using-pnpm-command', {
|
||||
packageName: pkgName,
|
||||
})}
|
||||
title={t('sidebar.installation.install-using-pnpm-command', {
|
||||
packageName: pkgName,
|
||||
})}
|
||||
text={`pnpm install ${getGlobalInstall(isGlobal, packageVersion, packageName)}`}
|
||||
title={`pnpm install ${getGlobalInstall(isGlobal, packageVersion, packageName)}`}
|
||||
/>
|
||||
}
|
||||
secondary={t('sidebar.installation.install-using-pnpm')}
|
||||
/>
|
||||
</InstallItem>
|
||||
);
|
||||
|
|
|
@ -4,6 +4,7 @@ import BugReport from '@mui/icons-material/BugReport';
|
|||
import DownloadIcon from '@mui/icons-material/CloudDownload';
|
||||
import HomeIcon from '@mui/icons-material/Home';
|
||||
import { useTheme } from '@mui/material';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import ListItem from '@mui/material/ListItem';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
|
@ -71,6 +72,7 @@ const Package: React.FC<PackageInterface> = ({
|
|||
const dispatch = useDispatch<Dispatch>();
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const isLoading = useSelector((state: RootState) => state?.loading?.models.download);
|
||||
|
||||
const handleDownload = useCallback(
|
||||
async (tarballDist: string) => {
|
||||
|
@ -173,7 +175,13 @@ const Package: React.FC<PackageInterface> = ({
|
|||
title={t('package.tarball')}
|
||||
>
|
||||
<IconButton aria-label={t('package.download')} size="large">
|
||||
<DownloadIcon />
|
||||
{isLoading ? (
|
||||
<CircularProgress size={13}>
|
||||
<DownloadIcon />
|
||||
</CircularProgress>
|
||||
) : (
|
||||
<DownloadIcon />
|
||||
)}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Link>
|
||||
|
@ -194,6 +202,7 @@ const Package: React.FC<PackageInterface> = ({
|
|||
container={true}
|
||||
item={true}
|
||||
justify="flex-end"
|
||||
spacing={3}
|
||||
xs={true}
|
||||
>
|
||||
{renderHomePageLink()}
|
||||
|
|
|
@ -47,12 +47,7 @@ type Props = {
|
|||
const RawViewer: React.FC<Props> = ({ isOpen = false, onClose, packageMeta }) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Dialog
|
||||
data-testid={'rawViewer--dialog'}
|
||||
fullScreen={true}
|
||||
id="raw-viewer--dialog-container"
|
||||
open={isOpen}
|
||||
>
|
||||
<Dialog data-testid={'rawViewer--dialog'} fullScreen={true} open={isOpen}>
|
||||
<ViewerTitle id="viewer-title" onClose={onClose}>
|
||||
{t('action-bar-action.raw')}
|
||||
</ViewerTitle>
|
||||
|
|
|
@ -1,30 +1,19 @@
|
|||
import styled from '@emotion/styled';
|
||||
import 'github-markdown-css';
|
||||
import 'highlight.js/styles/default.css';
|
||||
import React from 'react';
|
||||
|
||||
import { Theme } from '../../Theme';
|
||||
import { useCustomTheme } from '../../';
|
||||
import ReadmeDark from './ReadmeDark';
|
||||
import ReadmeLight from './ReadmeLight';
|
||||
import { Props } from './types';
|
||||
import { parseReadme } from './utils';
|
||||
|
||||
const Readme: React.FC<Props> = ({ description }) => {
|
||||
return (
|
||||
<Wrapper
|
||||
className="markdown-body"
|
||||
dangerouslySetInnerHTML={{ __html: parseReadme(description) as string }}
|
||||
/>
|
||||
// @ts-ignore
|
||||
const { isDarkMode } = useCustomTheme();
|
||||
|
||||
return isDarkMode ? (
|
||||
<ReadmeDark description={description} />
|
||||
) : (
|
||||
<ReadmeLight description={description} />
|
||||
);
|
||||
};
|
||||
export default Readme;
|
||||
|
||||
const Wrapper = styled('div')<{ theme?: Theme }>(({ theme }) => ({
|
||||
background: theme?.palette.white,
|
||||
color: theme?.palette.black,
|
||||
padding: theme?.spacing(2, 3),
|
||||
ul: {
|
||||
listStyle: 'disc',
|
||||
},
|
||||
img: {
|
||||
maxWidth: '100%',
|
||||
},
|
||||
}));
|
||||
|
|
32
packages/ui-components/src/components/Readme/ReadmeDark.tsx
Normal file
32
packages/ui-components/src/components/Readme/ReadmeDark.tsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
import styled from '@emotion/styled';
|
||||
import cx from 'classnames';
|
||||
import 'highlight.js/styles/default.css';
|
||||
import React from 'react';
|
||||
|
||||
import { Theme } from '../../Theme';
|
||||
// @ts-ignore
|
||||
import styles from './github-markdown-dark.css';
|
||||
import { Props } from './types';
|
||||
import { parseReadme } from './utils';
|
||||
|
||||
const Readme: React.FC<Props> = ({ description }) => {
|
||||
return (
|
||||
<Wrapper
|
||||
className={cx('markdown-body', styles['markdown-body'])}
|
||||
dangerouslySetInnerHTML={{ __html: parseReadme(description) as string }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
export default Readme;
|
||||
|
||||
const Wrapper = styled('div')<{ theme?: Theme }>(({ theme }) => ({
|
||||
background: theme?.palette.white,
|
||||
color: theme?.palette.black,
|
||||
padding: theme?.spacing(2, 3),
|
||||
ul: {
|
||||
listStyle: 'disc',
|
||||
},
|
||||
img: {
|
||||
maxWidth: '100%',
|
||||
},
|
||||
}));
|
32
packages/ui-components/src/components/Readme/ReadmeLight.tsx
Normal file
32
packages/ui-components/src/components/Readme/ReadmeLight.tsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
import styled from '@emotion/styled';
|
||||
import cx from 'classnames';
|
||||
import 'highlight.js/styles/default.css';
|
||||
import React from 'react';
|
||||
|
||||
import { Theme } from '../../Theme';
|
||||
// @ts-ignore
|
||||
import styles from './github-markdown-light.css';
|
||||
import { Props } from './types';
|
||||
import { parseReadme } from './utils';
|
||||
|
||||
const Readme: React.FC<Props> = ({ description }) => {
|
||||
return (
|
||||
<Wrapper
|
||||
className={cx('markdown-body', styles['markdown-body'])}
|
||||
dangerouslySetInnerHTML={{ __html: parseReadme(description) as string }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
export default Readme;
|
||||
|
||||
const Wrapper = styled('div')<{ theme?: Theme }>(({ theme }) => ({
|
||||
background: theme?.palette.white,
|
||||
color: theme?.palette.black,
|
||||
padding: theme?.spacing(2, 3),
|
||||
ul: {
|
||||
listStyle: 'disc',
|
||||
},
|
||||
img: {
|
||||
maxWidth: '100%',
|
||||
},
|
||||
}));
|
|
@ -20,7 +20,7 @@ exports[`<Readme /> component should load the component in default state 1`] = `
|
|||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="markdown-body emotion-0 emotion-1"
|
||||
class="markdown-body markdown-body emotion-0 emotion-1"
|
||||
>
|
||||
<p>
|
||||
test
|
||||
|
@ -46,7 +46,7 @@ exports[`<Readme /> component should load the component in default state 1`] = `
|
|||
|
||||
<div>
|
||||
<div
|
||||
class="markdown-body emotion-0 emotion-1"
|
||||
class="markdown-body markdown-body emotion-0 emotion-1"
|
||||
>
|
||||
<p>
|
||||
test
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -21,14 +21,24 @@ const InstallListItem: React.FC<Props> = ({ packageName }) => {
|
|||
const handleOpenMenu = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
const handleClick = () => {
|
||||
|
||||
const handleGlobalSelect = () => {
|
||||
const statusGlobal = !localSettings[packageName]?.global;
|
||||
updateSettings({ [packageName]: { global: statusGlobal } });
|
||||
updateSettings({ ...localSettings, [packageName]: { global: statusGlobal } });
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleGlobalYarnModern = () => {
|
||||
const statusYarnModern = !localSettings?.yarnModern;
|
||||
updateSettings({ ...localSettings, yarnModern: statusYarnModern });
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const statusGlobal = localSettings[packageName]?.global;
|
||||
return (
|
||||
<>
|
||||
<IconButton
|
||||
|
@ -50,15 +60,24 @@ const InstallListItem: React.FC<Props> = ({ packageName }) => {
|
|||
onClose={handleClose}
|
||||
open={open}
|
||||
>
|
||||
<MenuItem onClick={handleClick}>
|
||||
<MenuItem onClick={handleGlobalSelect}>
|
||||
{' '}
|
||||
{localSettings?.global ? (
|
||||
{statusGlobal === true ? (
|
||||
<ListItemIcon>
|
||||
<Check />
|
||||
</ListItemIcon>
|
||||
) : null}
|
||||
{t('sidebar.installation.global')}
|
||||
</MenuItem>
|
||||
<MenuItem onClick={handleGlobalYarnModern}>
|
||||
{' '}
|
||||
{localSettings?.yarnModern ? (
|
||||
<ListItemIcon>
|
||||
<Check />
|
||||
</ListItemIcon>
|
||||
) : null}
|
||||
{t('sidebar.installation.yarnModern')}
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -78,4 +78,5 @@ const StyledHeading = styled(Heading)({
|
|||
|
||||
const StyledBoxVersion = styled(Box)<{ theme?: Theme }>(({ theme }) => ({
|
||||
color: theme?.palette.text.secondary,
|
||||
fontSize: theme?.fontSize.sm,
|
||||
}));
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import Chip from '@mui/material/Chip';
|
||||
import List from '@mui/material/List';
|
||||
import ListItem from '@mui/material/ListItem';
|
||||
import { useTheme } from '@mui/styles';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useConfig } from '../../providers';
|
||||
import { Time, Versions } from '../../types/packageMeta';
|
||||
import { utils } from '../../utils';
|
||||
import { Link } from '../Link';
|
||||
|
@ -14,18 +17,43 @@ interface Props {
|
|||
time: Time;
|
||||
}
|
||||
|
||||
export function filterDeprecated(versions: Versions) {
|
||||
const versionsIds = Object.keys(versions);
|
||||
return versionsIds.reduce((prev, current) => {
|
||||
if (!versions[current].deprecated) {
|
||||
prev[current] = versions[current];
|
||||
}
|
||||
|
||||
return prev;
|
||||
}, {});
|
||||
}
|
||||
|
||||
const VersionsHistoryList: React.FC<Props> = ({ versions, packageName, time }) => {
|
||||
const { t } = useTranslation();
|
||||
const { configOptions } = useConfig();
|
||||
const theme = useTheme();
|
||||
const hideDeprecatedVersions = configOptions.hideDeprecatedVersions;
|
||||
const listVersions = hideDeprecatedVersions ? filterDeprecated(versions) : versions;
|
||||
|
||||
return (
|
||||
<List dense={true}>
|
||||
{Object.keys(versions)
|
||||
{Object.keys(listVersions)
|
||||
.reverse()
|
||||
.map((version) => (
|
||||
<ListItem className="version-item" data-testid={`version-${version}`} key={version}>
|
||||
<Link to={`/-/web/detail/${packageName}/v/${version}`} variant="caption">
|
||||
<ListItemText disableTypography={false} primary={version}></ListItemText>
|
||||
</Link>
|
||||
{typeof versions[version].deprecated === 'string' ? (
|
||||
<Chip
|
||||
color="warning"
|
||||
data-testid="deprecated-badge"
|
||||
label={t('versions.deprecated')}
|
||||
size="small"
|
||||
sx={{ marginLeft: theme.spacing(1) }}
|
||||
variant="outlined"
|
||||
/>
|
||||
) : null}
|
||||
<Spacer />
|
||||
<ListItemText title={utils.formatDate(time[version])}>
|
||||
{time[version]
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import { cleanup, render } from '../../test/test-react-testing-library';
|
||||
import { cleanup, render, screen } from '../../test/test-react-testing-library';
|
||||
import Versions, { Props } from './Versions';
|
||||
import data from './__partials__/data.json';
|
||||
import dataDeprecated from './__partials__/deprecated-versions.json';
|
||||
|
||||
const ComponentToBeRendered: React.FC<Props> = (props) => (
|
||||
<MemoryRouter>
|
||||
|
@ -26,6 +27,8 @@ describe('<Version /> component', () => {
|
|||
// pick some versions
|
||||
expect(getByText('2.3.0')).toBeTruthy();
|
||||
expect(getByText('canary')).toBeTruthy();
|
||||
// there is one deprecated version deprecated
|
||||
expect(screen.queryByTestId('deprecated-badge')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should not render versions', () => {
|
||||
|
@ -35,5 +38,17 @@ describe('<Version /> component', () => {
|
|||
expect(queryByText('versions.current-tags')).toBeFalsy();
|
||||
});
|
||||
|
||||
test('should render versions deprecated settings', () => {
|
||||
window.__VERDACCIO_BASENAME_UI_OPTIONS.hideDeprecatedVersions = true;
|
||||
const { getByText } = render(
|
||||
<ComponentToBeRendered packageMeta={dataDeprecated} packageName={'foo'} />
|
||||
);
|
||||
expect(getByText('versions.hide-deprecated')).toBeTruthy();
|
||||
|
||||
// pick some versions
|
||||
expect(screen.queryByText('0.0.2')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('0.0.1')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test.todo('should click on version link');
|
||||
});
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import Alert from '@mui/material/Alert';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { useTheme } from '@mui/styles';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useConfig } from '../../providers';
|
||||
import VersionsHistoryList from './HistoryList';
|
||||
import VersionsTagList from './TagList';
|
||||
|
||||
|
@ -9,6 +12,8 @@ export type Props = { packageMeta: any; packageName: string };
|
|||
|
||||
const Versions: React.FC<Props> = ({ packageMeta, packageName }) => {
|
||||
const { t } = useTranslation();
|
||||
const { configOptions } = useConfig();
|
||||
const theme = useTheme();
|
||||
|
||||
if (!packageMeta) {
|
||||
return null;
|
||||
|
@ -18,6 +23,7 @@ const Versions: React.FC<Props> = ({ packageMeta, packageName }) => {
|
|||
|
||||
const hasDistTags = distTags && Object.keys(distTags).length > 0 && packageName;
|
||||
const hasVersionHistory = versions && Object.keys(versions).length > 0 && packageName;
|
||||
const hideDeprecatedVersions = configOptions.hideDeprecatedVersions;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -30,7 +36,17 @@ const Versions: React.FC<Props> = ({ packageMeta, packageName }) => {
|
|||
{hasVersionHistory ? (
|
||||
<>
|
||||
<Typography variant="subtitle1">{t('versions.version-history')}</Typography>
|
||||
<VersionsHistoryList packageName={packageName} time={time} versions={versions} />
|
||||
<>
|
||||
{hideDeprecatedVersions && (
|
||||
<Alert
|
||||
severity="info"
|
||||
sx={{ marginTop: theme.spacing(1), marginBottom: theme.spacing(1) }}
|
||||
>
|
||||
{t('versions.hide-deprecated')}
|
||||
</Alert>
|
||||
)}
|
||||
<VersionsHistoryList packageName={packageName} time={time} versions={versions} />
|
||||
</>
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"0.0.1": {
|
||||
"name": "@verdaccio/local-storage",
|
||||
"version": "0.0.1",
|
||||
"deprecated": "this is deprecated",
|
||||
"description": "local storage implementation",
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
{
|
||||
"versions": {
|
||||
"0.0.1": {
|
||||
"name": "@verdaccio/local-storage",
|
||||
"version": "0.0.1",
|
||||
"description": "local storage implementation",
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
"test": "npm run lint && mocha --require babel-polyfill --compilers js:babel-core/register ./test/**/*.spec.js",
|
||||
"lint": "eslint .",
|
||||
"flow": "flow",
|
||||
"build": "babel src/ --out-dir lib/ --copy-files",
|
||||
"cover": "cross-env NODE_ENV=test nyc npm t"
|
||||
},
|
||||
"dependencies": {
|
||||
"@verdaccio/file-locking": "^0.0.3",
|
||||
"@verdaccio/streams": "^0.0.2",
|
||||
"async": "2.5.0",
|
||||
"http-errors": "1.4.0",
|
||||
"lodash": "4.17.4",
|
||||
"mkdirp": "0.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "0.0.2",
|
||||
"babel-cli": "6.24.1",
|
||||
"babel-core": "6.25.0",
|
||||
"babel-eslint": "^7.2.3",
|
||||
"babel-plugin-istanbul": "4.1.4",
|
||||
"babel-polyfill": "6.23.0",
|
||||
"babel-preset-es2015": "6.24.1",
|
||||
"babel-preset-es2015-node4": "2.1.0",
|
||||
"babel-preset-flow": "6.23.0",
|
||||
"babel-plugin-transform-inline-imports-commonjs": "1.0.0",
|
||||
"babel-plugin-array-includes": "2.0.3",
|
||||
"babel-plugin-transform-runtime": "6.4.3",
|
||||
"cross-env": "5.0.5",
|
||||
"eslint": "4.4.1",
|
||||
"eslint-config-google": "0.9.1",
|
||||
"eslint-plugin-flowtype": "2.35.0",
|
||||
"flow-bin": "0.52.0",
|
||||
"mocha": "3.5.0",
|
||||
"nyc": "11.1.0"
|
||||
},
|
||||
"nyc": {
|
||||
"include": ["src/**/*.js"],
|
||||
"all": true,
|
||||
"cache": true,
|
||||
"sourceMap": false,
|
||||
"instrument": false,
|
||||
"report-dir": "./tests-report",
|
||||
"reporter": ["text", "html"]
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"keywords": ["streams"],
|
||||
"author": {
|
||||
"name": "Juan Picado",
|
||||
"email": "juanpicado19@gmail.com"
|
||||
},
|
||||
"private": false,
|
||||
"license": "MIT",
|
||||
"gitHead": "e7e4ea74f20331dfde0a7133a02b5b95d68696a9",
|
||||
"_id": "@verdaccio/local-storage@0.0.1",
|
||||
"_npmVersion": "5.3.0",
|
||||
"_nodeVersion": "8.2.1",
|
||||
"_npmUser": {
|
||||
"name": "jotadeveloper",
|
||||
"email": "juanpicado19@gmail.com"
|
||||
},
|
||||
"dist": {
|
||||
"integrity": "sha512-J7qeK3r6jbaMOf4mBIqL1bAdb7Iwb+mC4ZaE9PUE2TctzXSkRRnk2M33zWGhZV0ziEPGAF40wC76wWex2GvXeA==",
|
||||
"shasum": "9c71cbeeb922b35efc1b31949d0afa6aac97e9b6",
|
||||
"tarball": "http://localhost:4872/@verdaccio%2flocal-storage/-/local-storage-0.0.1.tgz"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "jotadeveloper",
|
||||
"email": "juanpicado19@gmail.com"
|
||||
}
|
||||
],
|
||||
"_npmOperationalInternal": {
|
||||
"host": "s3://npm-registry-packages",
|
||||
"tmp": "tmp/local-storage-0.0.1.tgz_1502536792670_0.3513342353980988"
|
||||
},
|
||||
"directories": {}
|
||||
},
|
||||
"0.0.2": {
|
||||
"deprecated": "this package is deprecated",
|
||||
"name": "@verdaccio/local-storage",
|
||||
"version": "0.0.2",
|
||||
"description": "local storage implementation",
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
"test": "npm run lint && mocha --require babel-polyfill --compilers js:babel-core/register ./test/**/*.spec.js",
|
||||
"lint": "eslint .",
|
||||
"flow": "flow",
|
||||
"build": "babel src/ --out-dir lib/ --copy-files",
|
||||
"cover": "cross-env NODE_ENV=test nyc npm t"
|
||||
},
|
||||
"dependencies": {
|
||||
"@verdaccio/file-locking": "^0.0.3",
|
||||
"@verdaccio/streams": "^0.0.2",
|
||||
"async": "2.5.0",
|
||||
"http-errors": "1.4.0",
|
||||
"lodash": "4.17.4",
|
||||
"mkdirp": "0.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "0.0.2",
|
||||
"babel-cli": "6.24.1",
|
||||
"babel-core": "6.25.0",
|
||||
"babel-eslint": "^7.2.3",
|
||||
"babel-plugin-istanbul": "4.1.4",
|
||||
"babel-polyfill": "6.23.0",
|
||||
"babel-preset-es2015": "6.24.1",
|
||||
"babel-preset-es2015-node4": "2.1.0",
|
||||
"babel-preset-flow": "6.23.0",
|
||||
"babel-plugin-transform-inline-imports-commonjs": "1.0.0",
|
||||
"babel-plugin-array-includes": "2.0.3",
|
||||
"babel-plugin-transform-runtime": "6.4.3",
|
||||
"cross-env": "5.0.5",
|
||||
"eslint": "4.4.1",
|
||||
"eslint-config-google": "0.9.1",
|
||||
"eslint-plugin-flowtype": "2.35.0",
|
||||
"flow-bin": "0.52.0",
|
||||
"mocha": "3.5.0",
|
||||
"nyc": "11.1.0"
|
||||
},
|
||||
"nyc": {
|
||||
"include": ["src/**/*.js"],
|
||||
"all": true,
|
||||
"cache": true,
|
||||
"sourceMap": false,
|
||||
"instrument": false,
|
||||
"report-dir": "./tests-report",
|
||||
"reporter": ["text", "html"]
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"keywords": ["streams"],
|
||||
"author": {
|
||||
"name": "Juan Picado",
|
||||
"email": "juanpicado19@gmail.com"
|
||||
},
|
||||
"private": false,
|
||||
"license": "MIT",
|
||||
"gitHead": "626ea013ee810da9115550e0a60f44aa3d08e9a0",
|
||||
"_id": "@verdaccio/local-storage@0.0.2",
|
||||
"_npmVersion": "5.3.0",
|
||||
"_nodeVersion": "8.2.1",
|
||||
"_npmUser": {
|
||||
"name": "jotadeveloper",
|
||||
"email": "juanpicado19@gmail.com"
|
||||
},
|
||||
"dist": {
|
||||
"integrity": "sha512-Su0cQpLAaBab3qekpcHO+J/JCfoznTuU0P7e5q9T7R2trGVobYXvsTiIB/usQNmDr2e+1N6iBhMst7Uy+231ag==",
|
||||
"shasum": "fe79ad6f9ceb631857618038486f729098e7b31b",
|
||||
"tarball": "http://localhost:4872/@verdaccio%2flocal-storage/-/local-storage-0.0.2.tgz"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "jotadeveloper",
|
||||
"email": "juanpicado19@gmail.com"
|
||||
}
|
||||
],
|
||||
"_npmOperationalInternal": {
|
||||
"host": "s3://npm-registry-packages",
|
||||
"tmp": "tmp/local-storage-0.0.2.tgz_1502611253150_0.21545960218645632"
|
||||
},
|
||||
"directories": {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ const defaultValues: ConfigProviderProps = {
|
|||
showSearch: true,
|
||||
showRaw: true,
|
||||
showDownloadTarball: true,
|
||||
hideDeprecatedVersions: false,
|
||||
title: 'Verdaccio',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -11,10 +11,12 @@ import useLocalStorage from '../../hooks/useLocalStorage';
|
|||
|
||||
type PersistenceSettingsProps = {
|
||||
isGlobal?: boolean;
|
||||
yarnModern: boolean;
|
||||
};
|
||||
|
||||
const defaultValues: PersistenceSettingsProps = {
|
||||
isGlobal: false,
|
||||
yarnModern: false,
|
||||
};
|
||||
|
||||
const PersistenceSettingContext = createContext<any>(defaultValues);
|
||||
|
|
|
@ -13,7 +13,6 @@ export const download = createModel<RootModel>()({
|
|||
reducers: {},
|
||||
effects: () => ({
|
||||
async getTarball({ link }) {
|
||||
// const basePath = state.configuration.config.base;
|
||||
try {
|
||||
const fileStream: Blob = await API.request(link, 'GET', {
|
||||
headers: {
|
||||
|
|
|
@ -78,6 +78,7 @@ export interface Version {
|
|||
license?: string;
|
||||
main?: string;
|
||||
keywords?: string[];
|
||||
deprecated?: string;
|
||||
}
|
||||
|
||||
export interface Author {
|
||||
|
|
790
pnpm-lock.yaml
generated
790
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue