mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-03-25 02:32:52 -05:00
feat: ui set global package on sidebar setting (#3826)
This commit is contained in:
parent
679c19c1b6
commit
7344a7fcf6
57 changed files with 1075 additions and 403 deletions
6
.changeset/khaki-carrots-crash.md
Normal file
6
.changeset/khaki-carrots-crash.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
'@verdaccio/ui-theme': minor
|
||||
'@verdaccio/ui-components': minor
|
||||
---
|
||||
|
||||
feat: ui bugfixes and improvements
|
|
@ -8,7 +8,7 @@
|
|||
"@verdaccio/config": "workspace:6.0.0-6-next.70",
|
||||
"@verdaccio/test-helper": "workspace:2.0.0-6-next.8",
|
||||
"debug": "4.3.4",
|
||||
"cypress": "11.2.0",
|
||||
"cypress": "^11.2.0",
|
||||
"get-port": "5.1.1"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
require('@babel/register')({
|
||||
extensions: ['.ts', '.js'],
|
||||
});
|
||||
module.exports = require('./setup');
|
|
@ -1,26 +0,0 @@
|
|||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
|
||||
const { green } = require('colorette');
|
||||
const puppeteer = require('puppeteer');
|
||||
|
||||
const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup');
|
||||
|
||||
module.exports = async function () {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(green('Setup Puppeteer'));
|
||||
const browser = await puppeteer.launch({
|
||||
isMobile: false,
|
||||
ignoreHTTPSErrors: true,
|
||||
// invert values for local testing
|
||||
devtools: false,
|
||||
headless: true,
|
||||
// slowMo: 6000,
|
||||
// invert values for local testing
|
||||
args: ['--no-sandbox'],
|
||||
});
|
||||
global.__BROWSER__ = browser;
|
||||
fs.mkdirSync(DIR, { recursive: true, force: true });
|
||||
fs.writeFileSync(path.join(DIR, 'wsEndpoint'), browser.wsEndpoint());
|
||||
};
|
|
@ -1,14 +0,0 @@
|
|||
const os = require('os');
|
||||
const path = require('path');
|
||||
|
||||
const { green } = require('kleur');
|
||||
const rimraf = require('rimraf');
|
||||
|
||||
const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup');
|
||||
|
||||
module.exports = async function () {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(green('Teardown Puppeteer'));
|
||||
await global.__BROWSER__.close();
|
||||
rimraf.sync(DIR);
|
||||
};
|
|
@ -106,7 +106,8 @@
|
|||
"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}}"
|
||||
"install-using-pnpm-command": "pnpm install {{packageName}}",
|
||||
"global": "View as global"
|
||||
},
|
||||
"repository": {
|
||||
"title": "Repository"
|
||||
|
|
|
@ -5,6 +5,7 @@ import { Provider } from 'react-redux';
|
|||
|
||||
import {
|
||||
AppConfigurationProvider,
|
||||
PersistenceSettingProvider,
|
||||
StyleBaseline,
|
||||
ThemeProvider,
|
||||
store,
|
||||
|
@ -20,7 +21,9 @@ const AppContainer = () => (
|
|||
<AppConfigurationProvider>
|
||||
<ThemeProvider>
|
||||
<StyleBaseline />
|
||||
<App />
|
||||
<PersistenceSettingProvider>
|
||||
<App />
|
||||
</PersistenceSettingProvider>
|
||||
</ThemeProvider>
|
||||
</AppConfigurationProvider>
|
||||
</Provider>
|
||||
|
|
|
@ -1,16 +1,8 @@
|
|||
{
|
||||
"extends": "../../.babelrc",
|
||||
"plugins": ["@emotion"],
|
||||
"sourceMaps" : "inline",
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"targets": ["last 5 versions"],
|
||||
"bugfixes": true,
|
||||
"modules": "auto",
|
||||
"debug": false
|
||||
}
|
||||
],
|
||||
"@babel/preset-react"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import { Provider } from 'react-redux';
|
|||
import config from '../../plugins/ui-theme/src/i18n/config';
|
||||
import {
|
||||
AppConfigurationProvider,
|
||||
PersistenceSettingProvider,
|
||||
StyleBaseline,
|
||||
ThemeProvider,
|
||||
TranslatorProvider,
|
||||
|
@ -34,12 +35,14 @@ export const parameters = {
|
|||
export const withMuiTheme = (Story) => (
|
||||
<Provider store={store}>
|
||||
<TranslatorProvider onMount={() => {}} i18n={config} listLanguages={listLanguages}>
|
||||
<AppConfigurationProvider>
|
||||
<ThemeProvider>
|
||||
<StyleBaseline />
|
||||
<Story />
|
||||
</ThemeProvider>
|
||||
</AppConfigurationProvider>
|
||||
<PersistenceSettingProvider>
|
||||
<AppConfigurationProvider>
|
||||
<ThemeProvider>
|
||||
<StyleBaseline />
|
||||
<Story />
|
||||
</ThemeProvider>
|
||||
</AppConfigurationProvider>
|
||||
</PersistenceSettingProvider>
|
||||
</TranslatorProvider>
|
||||
</Provider>
|
||||
);
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
"dependencies": {
|
||||
"@emotion/react": "^11.10.6",
|
||||
"@emotion/styled": "^11.10.6",
|
||||
"@fontsource/material-icons": "^4.5.4",
|
||||
"@fontsource/roboto": "^4.5.8",
|
||||
"@mui/icons-material": "5.11.16",
|
||||
"@mui/material": "5.12.0",
|
||||
"@mui/styles": "5.12.0",
|
||||
|
@ -28,8 +30,6 @@
|
|||
"@rematch/core": "2.2.0",
|
||||
"@rematch/loading": "2.1.2",
|
||||
"@rematch/persist": "2.1.2",
|
||||
"@fontsource/material-icons": "^4.5.4",
|
||||
"@fontsource/roboto": "^4.5.8",
|
||||
"country-flag-icons": "1.5.5",
|
||||
"dayjs": "1.11.7",
|
||||
"dompurify": "2.4.5",
|
||||
|
@ -56,7 +56,6 @@
|
|||
"validator": "13.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.25",
|
||||
"@babel/core": "^7.20.7",
|
||||
"@emotion/babel-plugin": "11.10.6",
|
||||
"@emotion/jest": "11.10.5",
|
||||
|
@ -74,6 +73,7 @@
|
|||
"@types/hast": "^2.0.0",
|
||||
"@types/react-router": "^5.1.20",
|
||||
"@types/unist": "^2.0.0",
|
||||
"@verdaccio/types": "workspace:11.0.0-6-next.25",
|
||||
"babel-loader": "^8.3.0",
|
||||
"mockdate": "3.0.5",
|
||||
"msw": "0.49.2"
|
||||
|
|
|
@ -1,50 +1,64 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { clone, merge } from 'lodash';
|
||||
import React from 'react';
|
||||
|
||||
import { default as ActionBar } from '.';
|
||||
|
||||
export default {
|
||||
title: 'ActionBar ',
|
||||
const meta: Meta<typeof ActionBar> = {
|
||||
title: 'Components/Sidebar/ActionBar',
|
||||
component: ActionBar,
|
||||
};
|
||||
|
||||
export const ActionBarAll: any = () => (
|
||||
<ActionBar
|
||||
packageMeta={{
|
||||
_uplinks: {},
|
||||
latest: {
|
||||
name: 'verdaccio-ui/local-storage',
|
||||
version: '8.0.1-next.1',
|
||||
dist: {
|
||||
fileCount: 0,
|
||||
unpackedSize: 0,
|
||||
tarball: 'http://localhost:8080/bootstrap/-/bootstrap-4.3.1.tgz',
|
||||
},
|
||||
homepage: 'https://verdaccio.org',
|
||||
bugs: {
|
||||
url: 'https://github.com/verdaccio/monorepo/issues',
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof ActionBar>;
|
||||
|
||||
export const RawViewer: any = () => (
|
||||
<ActionBar
|
||||
packageMeta={{
|
||||
_uplinks: {},
|
||||
latest: {
|
||||
name: 'verdaccio-ui/local-storage',
|
||||
version: '8.0.1-next.1',
|
||||
dist: {
|
||||
fileCount: 0,
|
||||
unpackedSize: 0,
|
||||
tarball: 'http://localhost:8080/bootstrap/-/bootstrap-4.3.1.tgz',
|
||||
},
|
||||
homepage: 'https://verdaccio.org',
|
||||
bugs: {
|
||||
url: 'https://github.com/verdaccio/monorepo/issues',
|
||||
},
|
||||
},
|
||||
}}
|
||||
showRaw={true}
|
||||
/>
|
||||
);
|
||||
const packageMeta = {
|
||||
_uplinks: {},
|
||||
latest: {
|
||||
name: 'verdaccio-ui/local-storage',
|
||||
version: '8.0.1-next.1',
|
||||
dist: {
|
||||
fileCount: 0,
|
||||
unpackedSize: 0,
|
||||
tarball: 'https://registry.verdaccio.org/storybook/-/storybook-0.2.0.tgz',
|
||||
},
|
||||
homepage: 'https://verdaccio.org',
|
||||
bugs: {
|
||||
url: 'https://github.com/verdaccio/monorepo/issues',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Primary: Story = {
|
||||
name: 'Default',
|
||||
render: () => <ActionBar packageMeta={packageMeta} />,
|
||||
};
|
||||
|
||||
export const Raw: Story = {
|
||||
name: 'Raw viewer',
|
||||
render: () => <ActionBar packageMeta={packageMeta} showRaw={true} />,
|
||||
};
|
||||
|
||||
export const NoLatest: Story = {
|
||||
name: 'No latest (empty)',
|
||||
render: () => <ActionBar packageMeta={{}} showRaw={true} />,
|
||||
};
|
||||
|
||||
export const Download: Story = {
|
||||
name: 'No show download',
|
||||
render: () => <ActionBar packageMeta={{ ...clone(packageMeta) }} showDownloadTarball={false} />,
|
||||
};
|
||||
|
||||
export const Home: Story = {
|
||||
name: 'No home',
|
||||
render: () => (
|
||||
<ActionBar packageMeta={{ ...merge(clone(packageMeta), { latest: { homepage: null } }) }} />
|
||||
),
|
||||
};
|
||||
|
||||
export const Bugs: Story = {
|
||||
name: 'No bugs',
|
||||
render: () => (
|
||||
<ActionBar packageMeta={{ ...merge(clone(packageMeta), { latest: { bugs: null } }) }} />
|
||||
),
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import { default as Author } from '.';
|
||||
|
||||
export default {
|
||||
title: 'Author ',
|
||||
title: 'Components/Sidebar/Author',
|
||||
};
|
||||
|
||||
export const AuthorAll: any = () => (
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import CopyToClipBoard from './CopyToClipBoard';
|
||||
|
||||
export default {
|
||||
title: 'CopyToClipBoard',
|
||||
title: 'Components/Sidebar/CopyToClipBoard',
|
||||
component: CopyToClipBoard,
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
|
|
|
@ -34,12 +34,12 @@ function CopyToClipBoard({ text, children, dataTestId, title, ...props }: Props)
|
|||
<Content>{children ?? text}</Content>
|
||||
{title ? (
|
||||
<Tooltip disableFocusListener={true} title={title}>
|
||||
<IconButton data-testid={dataTestId} onClick={copyToClipBoardUtility(text)} size="large">
|
||||
<IconButton data-testid={dataTestId} onClick={copyToClipBoardUtility(text)} size="small">
|
||||
<FileCopy fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<IconButton data-testid={dataTestId} onClick={copyToClipBoardUtility(text)} size="large">
|
||||
<IconButton data-testid={dataTestId} onClick={copyToClipBoardUtility(text)} size="small">
|
||||
<FileCopy fontSize="small" />
|
||||
</IconButton>
|
||||
)}
|
||||
|
|
|
@ -1,58 +1,158 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { default as Dependencies } from '.';
|
||||
|
||||
export default {
|
||||
title: 'Dependencies ',
|
||||
const meta: Meta<typeof Dependencies> = {
|
||||
title: 'Components/Detail/Dependencies',
|
||||
component: Dependencies,
|
||||
};
|
||||
|
||||
export const DeprecatedAll: any = () => (
|
||||
<Dependencies
|
||||
packageMeta={{
|
||||
latest: {
|
||||
name: 'verdaccio',
|
||||
version: '4.0.0',
|
||||
author: {
|
||||
name: 'verdaccio user',
|
||||
email: 'verdaccio.user@verdaccio.org',
|
||||
url: '',
|
||||
avatar: 'https://www.gravatar.com/avatar/000000',
|
||||
},
|
||||
dist: { fileCount: 0, unpackedSize: 0 },
|
||||
dependencies: {
|
||||
react: '16.9.0',
|
||||
'react-dom': '16.9.0',
|
||||
},
|
||||
devDependencies: {
|
||||
'babel-core': '7.0.0-beta6',
|
||||
},
|
||||
peerDependencies: {
|
||||
'styled-components': '5.0.0',
|
||||
},
|
||||
},
|
||||
_uplinks: {},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Dependencies>;
|
||||
|
||||
export const NoDependencies: any = () => (
|
||||
<Dependencies
|
||||
packageMeta={{
|
||||
latest: {
|
||||
name: 'verdaccio',
|
||||
version: '4.0.0',
|
||||
author: {
|
||||
name: 'verdaccio user',
|
||||
email: 'verdaccio.user@verdaccio.org',
|
||||
url: '',
|
||||
avatar: 'https://www.gravatar.com/avatar/000000',
|
||||
},
|
||||
dist: { fileCount: 0, unpackedSize: 0 },
|
||||
dependencies: {},
|
||||
devDependencies: {},
|
||||
peerDependencies: {},
|
||||
},
|
||||
_uplinks: {},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
const packageMeta = {
|
||||
latest: {
|
||||
name: 'verdaccio',
|
||||
version: '4.0.0',
|
||||
author: {
|
||||
name: 'verdaccio user',
|
||||
email: 'verdaccio.user@verdaccio.org',
|
||||
url: '',
|
||||
avatar: 'https://www.gravatar.com/avatar/000000',
|
||||
},
|
||||
dist: { fileCount: 0, unpackedSize: 0 },
|
||||
dependencies: {
|
||||
react: '16.9.0',
|
||||
'react-dom': '16.9.0',
|
||||
'@storybook/codemod': '^3.2.6',
|
||||
chalk: '^2.1.0',
|
||||
'child-process-promise': '^2.2.1',
|
||||
commander: '^2.11.0',
|
||||
'cross-spawn': '^5.0.1',
|
||||
jscodeshift: '^0.3.30',
|
||||
json5: '^0.5.1',
|
||||
'latest-version': '^3.1.0',
|
||||
'merge-dirs': '^0.2.1',
|
||||
opencollective: '^1.0.3',
|
||||
shelljs: '^0.7.8',
|
||||
'update-notifier': '^2.1.0',
|
||||
},
|
||||
devDependencies: {
|
||||
'babel-core': '7.0.0-beta6',
|
||||
'cross-spawn': '^5.0.1',
|
||||
jscodeshift: '^0.3.30',
|
||||
json5: '^0.5.1',
|
||||
'latest-version': '^3.1.0',
|
||||
'merge-dirs': '^0.2.1',
|
||||
opencollective: '^1.0.3',
|
||||
shelljs: '^0.7.8',
|
||||
'update-notifier': '^2.1.0',
|
||||
},
|
||||
peerDependencies: {
|
||||
'styled-components': '5.0.0',
|
||||
'cross-spawn': '^5.0.1',
|
||||
jscodeshift: '^0.3.30',
|
||||
json5: '^0.5.1',
|
||||
'latest-version': '^3.1.0',
|
||||
'merge-dirs': '^0.2.1',
|
||||
opencollective: '^1.0.3',
|
||||
shelljs: '^0.7.8',
|
||||
'update-notifier': '^2.1.0',
|
||||
},
|
||||
optionalDependencies: {
|
||||
'styled-components': '5.0.0',
|
||||
'cross-spawn': '^5.0.1',
|
||||
jscodeshift: '^0.3.30',
|
||||
json5: '^0.5.1',
|
||||
'latest-version': '^3.1.0',
|
||||
'merge-dirs': '^0.2.1',
|
||||
opencollective: '^1.0.3',
|
||||
shelljs: '^0.7.8',
|
||||
'update-notifier': '^2.1.0',
|
||||
},
|
||||
bundleDependencies: {
|
||||
'styled-components': '5.0.0',
|
||||
'cross-spawn': '^5.0.1',
|
||||
jscodeshift: '^0.3.30',
|
||||
json5: '^0.5.1',
|
||||
'latest-version': '^3.1.0',
|
||||
'merge-dirs': '^0.2.1',
|
||||
opencollective: '^1.0.3',
|
||||
shelljs: '^0.7.8',
|
||||
'update-notifier': '^2.1.0',
|
||||
},
|
||||
},
|
||||
_uplinks: {},
|
||||
};
|
||||
|
||||
export const Primary: Story = {
|
||||
name: 'Default',
|
||||
render: () => {
|
||||
return <Dependencies packageMeta={packageMeta} />;
|
||||
},
|
||||
};
|
||||
|
||||
export const OnlyDeps: Story = {
|
||||
name: 'Only dependencies',
|
||||
render: () => {
|
||||
return (
|
||||
<Dependencies
|
||||
packageMeta={{
|
||||
latest: {
|
||||
name: 'verdaccio',
|
||||
version: '4.0.0',
|
||||
author: {
|
||||
name: 'verdaccio user',
|
||||
email: 'verdaccio.user@verdaccio.org',
|
||||
url: '',
|
||||
avatar: 'https://www.gravatar.com/avatar/000000',
|
||||
},
|
||||
dist: { fileCount: 0, unpackedSize: 0 },
|
||||
dependencies: {
|
||||
'styled-components': '5.0.0',
|
||||
'cross-spawn': '^5.0.1',
|
||||
jscodeshift: '^0.3.30',
|
||||
json5: '^0.5.1',
|
||||
'latest-version': '^3.1.0',
|
||||
'merge-dirs': '^0.2.1',
|
||||
opencollective: '^1.0.3',
|
||||
shelljs: '^0.7.8',
|
||||
'update-notifier': '^2.1.0',
|
||||
},
|
||||
devDependencies: { jscodeshift: '^0.3.30', json5: '^0.5.1' },
|
||||
peerDependencies: {},
|
||||
},
|
||||
_uplinks: {},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const NoDependencies: Story = {
|
||||
name: 'No dependencies',
|
||||
render: () => {
|
||||
return (
|
||||
<Dependencies
|
||||
packageMeta={{
|
||||
latest: {
|
||||
name: 'verdaccio',
|
||||
version: '4.0.0',
|
||||
author: {
|
||||
name: 'verdaccio user',
|
||||
email: 'verdaccio.user@verdaccio.org',
|
||||
url: '',
|
||||
avatar: 'https://www.gravatar.com/avatar/000000',
|
||||
},
|
||||
dist: { fileCount: 0, unpackedSize: 0 },
|
||||
dependencies: {},
|
||||
devDependencies: {},
|
||||
peerDependencies: {},
|
||||
},
|
||||
_uplinks: {},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import Box from '@mui/material/Box';
|
||||
import CardContent from '@mui/material/CardContent';
|
||||
import { useTheme } from '@mui/styles';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
@ -10,44 +12,38 @@ import { CardWrap, StyledText, Tag, Tags } from './styles';
|
|||
interface DependencyBlockProps {
|
||||
title: string;
|
||||
dependencies: PackageDependencies;
|
||||
enableLoading?: () => void;
|
||||
}
|
||||
|
||||
const DependencyBlock: React.FC<DependencyBlockProps> = ({
|
||||
title,
|
||||
dependencies,
|
||||
enableLoading,
|
||||
}) => {
|
||||
const DependencyBlock: React.FC<DependencyBlockProps> = ({ title, dependencies }) => {
|
||||
const history = useHistory();
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
|
||||
const deps = Object.entries(dependencies);
|
||||
|
||||
function handleClick(name: string): void {
|
||||
enableLoading?.();
|
||||
|
||||
history.push(`/-/web/detail/${name}`);
|
||||
}
|
||||
|
||||
return (
|
||||
<CardWrap data-testid={title}>
|
||||
<CardContent>
|
||||
<StyledText variant="subtitle1">{`${title} (${deps.length})`}</StyledText>
|
||||
<Tags>
|
||||
{deps.map(([name, version]) => (
|
||||
<Tag
|
||||
className={'dep-tag'}
|
||||
clickable={true}
|
||||
data-testid={name}
|
||||
key={name}
|
||||
label={t('dependencies.dependency-block', { package: name, version })}
|
||||
// eslint-disable-next-line
|
||||
onClick={() => handleClick(name)}
|
||||
/>
|
||||
))}
|
||||
</Tags>
|
||||
</CardContent>
|
||||
</CardWrap>
|
||||
<Box data-testid={title} sx={{ margin: theme.spacing(2) }}>
|
||||
<StyledText sx={{ marginBottom: theme.spacing(1) }} variant="subtitle1">
|
||||
{`${title} (${deps.length})`}
|
||||
</StyledText>
|
||||
<Tags>
|
||||
{deps.map(([name, version]) => (
|
||||
<Tag
|
||||
className={'dep-tag'}
|
||||
clickable={true}
|
||||
data-testid={name}
|
||||
key={name}
|
||||
label={t('dependencies.dependency-block', { package: name, version })}
|
||||
// eslint-disable-next-line
|
||||
onClick={() => handleClick(name)}
|
||||
/>
|
||||
))}
|
||||
</Tags>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -65,37 +61,51 @@ const Dependencies: React.FC<{ packageMeta: any }> = ({ packageMeta }) => {
|
|||
const { latest } = packageMeta;
|
||||
// FIXME: add dependencies to package meta type
|
||||
// @ts-ignore
|
||||
const { dependencies, devDependencies, peerDependencies, name } = latest;
|
||||
const dependencyMap = { dependencies, devDependencies, peerDependencies };
|
||||
const {
|
||||
dependencies,
|
||||
devDependencies,
|
||||
peerDependencies,
|
||||
optionalDependencies,
|
||||
bundleDependencies,
|
||||
name,
|
||||
} = latest;
|
||||
const dependencyMap = {
|
||||
dependencies,
|
||||
devDependencies,
|
||||
peerDependencies,
|
||||
bundleDependencies,
|
||||
optionalDependencies,
|
||||
};
|
||||
const hasDependencies =
|
||||
hasKeys(dependencies) || hasKeys(devDependencies) || hasKeys(peerDependencies);
|
||||
|
||||
hasKeys(dependencies) ||
|
||||
hasKeys(bundleDependencies) ||
|
||||
hasKeys(optionalDependencies) ||
|
||||
hasKeys(devDependencies) ||
|
||||
hasKeys(peerDependencies);
|
||||
if (hasDependencies) {
|
||||
return (
|
||||
<>
|
||||
{Object.entries(dependencyMap).map(([dependencyType, dependencies]) => {
|
||||
if (!dependencies || Object.keys(dependencies).length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<DependencyBlock
|
||||
dependencies={dependencies}
|
||||
key={dependencyType}
|
||||
title={dependencyType}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
<CardWrap>
|
||||
<CardContent>
|
||||
{Object.entries(dependencyMap).map(([dependencyType, dependencies]) => {
|
||||
if (!dependencies || Object.keys(dependencies).length === 0) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<DependencyBlock
|
||||
dependencies={dependencies}
|
||||
key={dependencyType}
|
||||
title={dependencyType}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</CardContent>
|
||||
</CardWrap>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<NoItems
|
||||
className="no-dependencies"
|
||||
text={t('dependencies.has-no-dependencies', { package: name })}
|
||||
/>
|
||||
);
|
||||
return <NoItems text={t('dependencies.has-no-dependencies', { package: name })} />;
|
||||
};
|
||||
|
||||
export default Dependencies;
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import { default as Deprecated } from '.';
|
||||
|
||||
export default {
|
||||
title: 'Deprecated',
|
||||
title: 'Components/Detail/Deprecated',
|
||||
};
|
||||
|
||||
export const DeprecatedAll: any = () => <Deprecated message="this is deprecated" />;
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import { DeveloperType, default as Developers } from '.';
|
||||
|
||||
export default {
|
||||
title: 'Developers',
|
||||
title: 'Components/Sidebar/Developers',
|
||||
};
|
||||
|
||||
export const DevelopersAll: any = () => (
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import { default as Dist } from '.';
|
||||
|
||||
export default {
|
||||
title: 'Dist',
|
||||
title: 'Components/Sidebar/Dist',
|
||||
};
|
||||
|
||||
export const AllProperties: any = () => (
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import { default as Engines } from '.';
|
||||
|
||||
export default {
|
||||
title: 'Engines',
|
||||
title: 'Components/Sidebar/Engines',
|
||||
};
|
||||
|
||||
export const EnginesNpmNode: any = () => (
|
||||
|
|
|
@ -1,25 +1,56 @@
|
|||
import Box from '@mui/material/Box';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { default as FundButton } from '.';
|
||||
|
||||
export default {
|
||||
title: 'FundButton',
|
||||
const meta: Meta<typeof FundButton> = {
|
||||
title: 'Components/Sidebar/FundButton',
|
||||
component: FundButton,
|
||||
};
|
||||
|
||||
export const FundButtonUrl: any = () => (
|
||||
<Box sx={{ width: '100%' }}>
|
||||
<Stack spacing={2}>
|
||||
<FundButton
|
||||
packageMeta={{
|
||||
latest: {
|
||||
funding: {
|
||||
url: 'https://opencollective.com/verdaccio',
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof FundButton>;
|
||||
|
||||
export const Primary: Story = {
|
||||
name: 'Default',
|
||||
render: () => {
|
||||
return (
|
||||
<Box sx={{ width: '100%' }}>
|
||||
<Stack spacing={2}>
|
||||
<FundButton
|
||||
packageMeta={{
|
||||
latest: {
|
||||
funding: {
|
||||
url: 'https://opencollective.com/verdaccio',
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const Bad: Story = {
|
||||
name: 'Bad Link (empty)',
|
||||
render: () => {
|
||||
return (
|
||||
<Box sx={{ width: '100%' }}>
|
||||
<Stack spacing={2}>
|
||||
<FundButton
|
||||
packageMeta={{
|
||||
latest: {
|
||||
funding: {
|
||||
url: 'bad_link',
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import { default as Help } from '.';
|
||||
|
||||
export default {
|
||||
title: 'Help',
|
||||
title: 'Components/Home/Help',
|
||||
};
|
||||
|
||||
export const HelpMessage: any = () => <Help />;
|
||||
|
|
|
@ -116,8 +116,8 @@ exports[`<Help /> component should load the component in default state 1`] = `
|
|||
color: rgba(0, 0, 0, 0.54);
|
||||
-webkit-transition: background-color 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
|
||||
transition: background-color 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
|
||||
padding: 12px;
|
||||
font-size: 1.75rem;
|
||||
padding: 5px;
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
|
||||
.emotion-10::-moz-focus-inner {
|
||||
|
@ -315,7 +315,7 @@ exports[`<Help /> component should load the component in default state 1`] = `
|
|||
help.first-step-command-line
|
||||
</span>
|
||||
<button
|
||||
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-sizeLarge emotion-10"
|
||||
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-sizeSmall emotion-10"
|
||||
data-testid="segments"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
|
@ -350,7 +350,7 @@ exports[`<Help /> component should load the component in default state 1`] = `
|
|||
help.second-step-command-line
|
||||
</span>
|
||||
<button
|
||||
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-sizeLarge emotion-10"
|
||||
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-sizeSmall emotion-10"
|
||||
data-testid="segments"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
} from '.';
|
||||
|
||||
export default {
|
||||
title: 'Icons',
|
||||
title: 'Components/Icons/Overview',
|
||||
};
|
||||
|
||||
export const Icons: any = () => (
|
||||
|
|
|
@ -1,34 +1,87 @@
|
|||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { default as Install } from '.';
|
||||
import { useConfig } from '../../';
|
||||
|
||||
export default {
|
||||
title: 'Install ',
|
||||
const meta: Meta<typeof Install> = {
|
||||
title: 'Components/Sidebar/Install',
|
||||
component: Install,
|
||||
};
|
||||
|
||||
export const ActionBarAll: any = () => {
|
||||
const { configOptions } = useConfig();
|
||||
return (
|
||||
<Install
|
||||
configOptions={{ ...configOptions, pkgManagers: ['npm', 'yarn', 'pnpm'] }}
|
||||
packageMeta={{
|
||||
_uplinks: {},
|
||||
latest: {
|
||||
name: 'verdaccio-ui/local-storage',
|
||||
version: '8.0.1-next.1',
|
||||
dist: {
|
||||
fileCount: 0,
|
||||
unpackedSize: 0,
|
||||
tarball: 'http://localhost:8080/bootstrap/-/bootstrap-4.3.1.tgz',
|
||||
},
|
||||
homepage: 'https://verdaccio.org',
|
||||
bugs: {
|
||||
url: 'https://github.com/verdaccio/monorepo/issues',
|
||||
},
|
||||
},
|
||||
}}
|
||||
packageName="jquery"
|
||||
/>
|
||||
);
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Install>;
|
||||
|
||||
const packageMeta = {
|
||||
_uplinks: {},
|
||||
latest: {
|
||||
name: 'verdaccio-ui/local-storage',
|
||||
version: '8.0.1-next.1',
|
||||
dist: {
|
||||
fileCount: 0,
|
||||
unpackedSize: 0,
|
||||
tarball: 'http://localhost:8080/bootstrap/-/bootstrap-4.3.1.tgz',
|
||||
},
|
||||
homepage: 'https://verdaccio.org',
|
||||
bugs: {
|
||||
url: 'https://github.com/verdaccio/monorepo/issues',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Primary: Story = {
|
||||
name: 'Default',
|
||||
render: () => {
|
||||
const { configOptions } = useConfig();
|
||||
return (
|
||||
<Install
|
||||
configOptions={{ ...configOptions, pkgManagers: ['npm', 'yarn', 'pnpm'] }}
|
||||
packageMeta={packageMeta}
|
||||
packageName="jquery"
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const npmOnly: Story = {
|
||||
name: 'Only NPM',
|
||||
render: () => {
|
||||
const { configOptions } = useConfig();
|
||||
return (
|
||||
<Install
|
||||
configOptions={{ ...configOptions, pkgManagers: ['npm'] }}
|
||||
packageMeta={packageMeta}
|
||||
packageName="jquery"
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const yarnOnly: Story = {
|
||||
name: 'Only Yarn',
|
||||
render: () => {
|
||||
const { configOptions } = useConfig();
|
||||
return (
|
||||
<Install
|
||||
configOptions={{ ...configOptions, pkgManagers: ['yarn'] }}
|
||||
packageMeta={packageMeta}
|
||||
packageName="jquery"
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const pnpmOnly: Story = {
|
||||
name: 'Only Pnpm',
|
||||
render: () => {
|
||||
const { configOptions } = useConfig();
|
||||
return (
|
||||
<Install
|
||||
configOptions={{ ...configOptions, pkgManagers: ['pnpm'] }}
|
||||
packageMeta={packageMeta}
|
||||
packageName="jquery"
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import styled from '@emotion/styled';
|
||||
import { Typography } from '@mui/material';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import List from '@mui/material/List';
|
||||
import { useTheme } from '@mui/styles';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
|
@ -8,6 +10,7 @@ import { TemplateUIOptions } from '@verdaccio/types';
|
|||
|
||||
import { Theme } from '../../Theme';
|
||||
import { PackageMetaInterface } from '../../types/packageMeta';
|
||||
import { SettingsMenu } from '../SettingsMenu';
|
||||
import InstallListItem, { DependencyManager } from './InstallListItem';
|
||||
|
||||
const StyledText = styled(Typography)<{ theme?: Theme }>((props) => ({
|
||||
|
@ -23,30 +26,41 @@ export type Props = {
|
|||
|
||||
const Install: React.FC<Props> = ({ packageMeta, packageName, configOptions }) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
|
||||
if (!packageMeta || !packageName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const hasNpm = configOptions?.pkgManagers?.includes('npm');
|
||||
const hasYarn = configOptions?.pkgManagers?.includes('yarn');
|
||||
const hasPnpm = configOptions?.pkgManagers?.includes('pnpm') ?? true;
|
||||
const hasPkgManagers = hasNpm || hasPnpm || hasYarn;
|
||||
|
||||
return hasPkgManagers ? (
|
||||
<List
|
||||
data-testid={'installList'}
|
||||
subheader={<StyledText variant={'subtitle1'}>{t('sidebar.installation.title')}</StyledText>}
|
||||
>
|
||||
{hasNpm && (
|
||||
<InstallListItem dependencyManager={DependencyManager.NPM} packageName={packageName} />
|
||||
)}
|
||||
{hasYarn && (
|
||||
<InstallListItem dependencyManager={DependencyManager.YARN} packageName={packageName} />
|
||||
)}
|
||||
{hasPnpm && (
|
||||
<InstallListItem dependencyManager={DependencyManager.PNPM} packageName={packageName} />
|
||||
)}
|
||||
</List>
|
||||
<>
|
||||
<Grid
|
||||
container={true}
|
||||
justifyContent="flex-end"
|
||||
sx={{ marginRight: theme.spacing(10), alingText: 'right' }}
|
||||
>
|
||||
<SettingsMenu packageName={packageName} />
|
||||
</Grid>
|
||||
<List
|
||||
data-testid={'installList'}
|
||||
subheader={<StyledText variant={'subtitle1'}>{t('sidebar.installation.title')}</StyledText>}
|
||||
>
|
||||
{hasNpm && (
|
||||
<InstallListItem dependencyManager={DependencyManager.NPM} packageName={packageName} />
|
||||
)}
|
||||
{hasYarn && (
|
||||
<InstallListItem dependencyManager={DependencyManager.YARN} packageName={packageName} />
|
||||
)}
|
||||
{hasPnpm && (
|
||||
<InstallListItem dependencyManager={DependencyManager.PNPM} packageName={packageName} />
|
||||
)}
|
||||
</List>
|
||||
</>
|
||||
) : null;
|
||||
};
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import ListItemText from '@mui/material/ListItemText';
|
|||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useSettings } from '../../providers/PersistenceSettingProvider';
|
||||
import CopyToClipBoard from '../CopyClipboard';
|
||||
import { Npm, Pnpm, Yarn } from '../Icons';
|
||||
|
||||
|
@ -16,13 +17,13 @@ const InstallItem = styled(ListItem)({
|
|||
});
|
||||
|
||||
const InstallListItemText = styled(ListItemText)({
|
||||
padding: '0 10px',
|
||||
padding: '0 0 0 10px',
|
||||
margin: 0,
|
||||
});
|
||||
|
||||
const PackageMangerAvatar = styled(Avatar)({
|
||||
borderRadius: '0px',
|
||||
padding: '0',
|
||||
padding: 0,
|
||||
});
|
||||
|
||||
export enum DependencyManager {
|
||||
|
@ -38,6 +39,9 @@ interface Interface {
|
|||
|
||||
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;
|
||||
|
||||
switch (dependencyManager) {
|
||||
case DependencyManager.NPM:
|
||||
|
@ -50,8 +54,12 @@ const InstallListItem: React.FC<Interface> = ({ packageName, dependencyManager }
|
|||
primary={
|
||||
<CopyToClipBoard
|
||||
dataTestId="installYarn"
|
||||
text={t('sidebar.installation.install-using-npm-command', { packageName })}
|
||||
title={t('sidebar.installation.install-using-npm-command', { packageName })}
|
||||
text={t('sidebar.installation.install-using-npm-command', {
|
||||
packageName: pkgName,
|
||||
})}
|
||||
title={t('sidebar.installation.install-using-npm-command', {
|
||||
packageName: pkgName,
|
||||
})}
|
||||
/>
|
||||
}
|
||||
secondary={t('sidebar.installation.install-using-npm')}
|
||||
|
@ -68,8 +76,12 @@ const InstallListItem: React.FC<Interface> = ({ packageName, dependencyManager }
|
|||
primary={
|
||||
<CopyToClipBoard
|
||||
dataTestId="installYarn"
|
||||
text={t('sidebar.installation.install-using-yarn-command', { packageName })}
|
||||
title={t('sidebar.installation.install-using-yarn-command', { packageName })}
|
||||
text={t('sidebar.installation.install-using-yarn-command', {
|
||||
packageName: pkgName,
|
||||
})}
|
||||
title={t('sidebar.installation.install-using-yarn-command', {
|
||||
packageName: pkgName,
|
||||
})}
|
||||
/>
|
||||
}
|
||||
secondary={t('sidebar.installation.install-using-yarn')}
|
||||
|
@ -86,8 +98,12 @@ const InstallListItem: React.FC<Interface> = ({ packageName, dependencyManager }
|
|||
primary={
|
||||
<CopyToClipBoard
|
||||
dataTestId="installPnpm"
|
||||
text={t('sidebar.installation.install-using-pnpm-command', { packageName })}
|
||||
title={t('sidebar.installation.install-using-pnpm-command', { packageName })}
|
||||
text={t('sidebar.installation.install-using-pnpm-command', {
|
||||
packageName: pkgName,
|
||||
})}
|
||||
title={t('sidebar.installation.install-using-pnpm-command', {
|
||||
packageName: pkgName,
|
||||
})}
|
||||
/>
|
||||
}
|
||||
secondary={t('sidebar.installation.install-using-pnpm')}
|
||||
|
|
|
@ -4,7 +4,7 @@ import React from 'react';
|
|||
import Loading from './Loading';
|
||||
|
||||
export default {
|
||||
title: 'Loading',
|
||||
title: 'Components/Detail/Loading',
|
||||
};
|
||||
|
||||
export const Icons: any = () => (
|
||||
|
|
|
@ -5,7 +5,7 @@ import React from 'react';
|
|||
import LoginDialog from './LoginDialog';
|
||||
|
||||
export default {
|
||||
title: 'LoginDialog',
|
||||
title: 'Components/Dialog/LoginDialog',
|
||||
};
|
||||
|
||||
export const OpenLoginDialog = {
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import { default as NoItems } from '.';
|
||||
|
||||
export default {
|
||||
title: 'Install ',
|
||||
title: 'Components/Detail/No Items',
|
||||
};
|
||||
|
||||
export const NoItemsText: any = () => {
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
import Alert from '@mui/material/Alert';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import React from 'react';
|
||||
|
||||
interface Props {
|
||||
text: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const NoItems: React.FC<Props> = ({ className, text, ...props }) => (
|
||||
// eslint-disable-next-line verdaccio/jsx-spread
|
||||
<Typography {...props} className={className} gutterBottom={true} variant="subtitle1">
|
||||
{text}
|
||||
</Typography>
|
||||
const NoItems: React.FC<Props> = ({ text, ...props }) => (
|
||||
<Alert severity="info">
|
||||
<Typography {...props}>{text}</Typography>
|
||||
</Alert>
|
||||
);
|
||||
|
||||
export default NoItems;
|
||||
|
|
|
@ -2,17 +2,98 @@
|
|||
|
||||
exports[`<NoItem /> component should load the component in default state 1`] = `
|
||||
.emotion-0 {
|
||||
background-color: #fff;
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
-webkit-transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
|
||||
transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
|
||||
border-radius: 4px;
|
||||
box-shadow: none;
|
||||
font-family: -apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.43;
|
||||
background-color: rgb(229, 246, 253);
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
padding: 6px 16px;
|
||||
color: rgb(1, 67, 97);
|
||||
}
|
||||
|
||||
.emotion-0 .MuiAlert-icon {
|
||||
color: #0288d1;
|
||||
}
|
||||
|
||||
.emotion-1 {
|
||||
margin-right: 12px;
|
||||
padding: 7px 0;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
font-size: 22px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.emotion-2 {
|
||||
-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: inherit;
|
||||
}
|
||||
|
||||
.emotion-3 {
|
||||
padding: 8px 0;
|
||||
min-width: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.emotion-4 {
|
||||
margin: 0;
|
||||
font-family: -apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 1rem;
|
||||
line-height: 1.75;
|
||||
margin-bottom: 0.35em;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
<h6
|
||||
class="MuiTypography-root MuiTypography-subtitle1 MuiTypography-gutterBottom emotion-0"
|
||||
<div
|
||||
class="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation0 MuiAlert-root MuiAlert-standardInfo MuiAlert-standard emotion-0"
|
||||
role="alert"
|
||||
>
|
||||
test
|
||||
</h6>
|
||||
<div
|
||||
class="MuiAlert-icon emotion-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiSvgIcon-fontSizeInherit emotion-2"
|
||||
data-testid="InfoOutlinedIcon"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20, 12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10, 10 0 0,0 12,2M11,17H13V11H11V17Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="MuiAlert-message emotion-3"
|
||||
>
|
||||
<p
|
||||
class="MuiTypography-root MuiTypography-body1 emotion-4"
|
||||
>
|
||||
test
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -1,31 +1,39 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { default as Repository } from '.';
|
||||
|
||||
export default {
|
||||
title: 'Repository',
|
||||
const meta: Meta<typeof Repository> = {
|
||||
title: 'Components/Sidebar/Repository',
|
||||
component: Repository,
|
||||
};
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Repository>;
|
||||
|
||||
export const RepositoryGit: any = () => {
|
||||
return (
|
||||
<Repository
|
||||
packageMeta={{
|
||||
_uplinks: {},
|
||||
latest: {
|
||||
name: 'verdaccio-ui/local-storage',
|
||||
version: '8.0.1-next.1',
|
||||
repository: {
|
||||
type: 'git',
|
||||
url: 'git://github.com/verdaccio/ui.git',
|
||||
export const Primary: Story = {
|
||||
name: 'Git Repository',
|
||||
render: () => {
|
||||
return (
|
||||
<Repository
|
||||
packageMeta={{
|
||||
_uplinks: {},
|
||||
latest: {
|
||||
name: 'verdaccio-ui/local-storage',
|
||||
version: '8.0.1-next.1',
|
||||
repository: {
|
||||
type: 'git',
|
||||
url: 'git://github.com/verdaccio/ui.git',
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const RepositoryHTTPS: any = () => {
|
||||
return (
|
||||
export const HTTPS: Story = {
|
||||
name: 'Https repo',
|
||||
render: () => (
|
||||
<Repository
|
||||
packageMeta={{
|
||||
_uplinks: {},
|
||||
|
@ -39,5 +47,24 @@ export const RepositoryHTTPS: any = () => {
|
|||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
),
|
||||
};
|
||||
|
||||
export const HTTP: Story = {
|
||||
name: 'Http repo',
|
||||
render: () => (
|
||||
<Repository
|
||||
packageMeta={{
|
||||
_uplinks: {},
|
||||
latest: {
|
||||
name: 'verdaccio-ui/local-storage',
|
||||
version: '8.0.1-next.1',
|
||||
repository: {
|
||||
type: 'http',
|
||||
url: 'http://github.com/verdaccio/ui.git',
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
|
|
@ -47,13 +47,11 @@ const RepositoryAvatar = styled(Avatar)({
|
|||
|
||||
const Repository: React.FC<{ packageMeta: any }> = ({ packageMeta }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!packageMeta?.latest?.repository?.url || !urlUtils.isURL(packageMeta.latest.repository.url)) {
|
||||
const url = packageMeta?.latest?.repository?.url;
|
||||
if (!url || !urlUtils.isURL(url)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { url } = packageMeta.latest.repository;
|
||||
|
||||
const getCorrectRepositoryURL = (): string => {
|
||||
if (!url.includes('git+')) {
|
||||
return url;
|
||||
|
|
|
@ -6,7 +6,7 @@ import { MemoryRouter } from 'react-router';
|
|||
import Search from './Search';
|
||||
|
||||
export default {
|
||||
title: 'Search',
|
||||
title: 'Components/Header/Search',
|
||||
};
|
||||
|
||||
export const SearchByQuery = {
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
import Check from '@mui/icons-material/Check';
|
||||
import Settings from '@mui/icons-material/Settings';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import ListItemIcon from '@mui/material/ListItemIcon';
|
||||
import Menu from '@mui/material/Menu';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useSettings } from '../../providers/PersistenceSettingProvider';
|
||||
|
||||
interface Props {
|
||||
packageName: string;
|
||||
}
|
||||
|
||||
const InstallListItem: React.FC<Props> = ({ packageName }) => {
|
||||
const { t } = useTranslation();
|
||||
const { localSettings, updateSettings } = useSettings();
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const open = Boolean(anchorEl);
|
||||
const handleOpenMenu = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
const handleClick = () => {
|
||||
const statusGlobal = !localSettings[packageName]?.global;
|
||||
updateSettings({ [packageName]: { global: statusGlobal } });
|
||||
setAnchorEl(null);
|
||||
};
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<IconButton
|
||||
aria-controls={open ? 'basic-menu' : undefined}
|
||||
aria-expanded={open ? 'true' : undefined}
|
||||
aria-haspopup="true"
|
||||
id="basic-button"
|
||||
onClick={handleOpenMenu}
|
||||
size="small"
|
||||
>
|
||||
<Settings fontSize="small" />
|
||||
</IconButton>
|
||||
<Menu
|
||||
MenuListProps={{
|
||||
'aria-labelledby': 'basic-button',
|
||||
}}
|
||||
anchorEl={anchorEl}
|
||||
id="basic-menu"
|
||||
onClose={handleClose}
|
||||
open={open}
|
||||
>
|
||||
<MenuItem onClick={handleClick}>
|
||||
{' '}
|
||||
{localSettings?.global ? (
|
||||
<ListItemIcon>
|
||||
<Check />
|
||||
</ListItemIcon>
|
||||
) : null}
|
||||
{t('sidebar.installation.global')}
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default InstallListItem;
|
|
@ -0,0 +1 @@
|
|||
export { default as SettingsMenu } from './SettingsMenu';
|
|
@ -0,0 +1,68 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import React from 'react';
|
||||
|
||||
import { default as SideBarTittle } from '.';
|
||||
|
||||
const meta: Meta<typeof SideBarTittle> = {
|
||||
title: 'Components/Sidebar/Title',
|
||||
component: SideBarTittle,
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof SideBarTittle>;
|
||||
|
||||
export const Commonjs: Story = {
|
||||
name: 'CommonJS package',
|
||||
render: () => (
|
||||
<SideBarTittle
|
||||
isLatest={false}
|
||||
moduleType="commonjs"
|
||||
packageName="jquery"
|
||||
time="2012-12-31T06:54:14.275Z"
|
||||
version="1.0.0"
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
||||
export const ES6: Story = {
|
||||
name: 'ES6 package',
|
||||
render: () => (
|
||||
<SideBarTittle
|
||||
isLatest={true}
|
||||
moduleType="module"
|
||||
packageName="react"
|
||||
time="2012-12-31T06:54:14.275Z"
|
||||
version="14.0.0"
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
||||
export const Description: Story = {
|
||||
name: 'With description',
|
||||
render: () => (
|
||||
<SideBarTittle
|
||||
description="Storybook's CLI - easiest method of adding storybook to your projects"
|
||||
isLatest={true}
|
||||
moduleType="module"
|
||||
packageName="storybook"
|
||||
time="2012-12-31T06:54:14.275Z"
|
||||
version="14.0.0"
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
||||
export const WithTypes: Story = {
|
||||
name: 'With types declaration',
|
||||
render: () => (
|
||||
<SideBarTittle
|
||||
description="Storybook's CLI - easiest method of adding storybook to your projects"
|
||||
hasTypes={true}
|
||||
isLatest={true}
|
||||
moduleType="module"
|
||||
packageName="storybook"
|
||||
time="2012-12-31T06:54:14.275Z"
|
||||
version="14.0.0"
|
||||
/>
|
||||
),
|
||||
};
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import { default as Uplinks } from '.';
|
||||
|
||||
export default {
|
||||
title: 'Uplinks',
|
||||
title: 'Components/Detail/Uplinks',
|
||||
};
|
||||
|
||||
export const UplinksAll: any = () => {
|
||||
|
|
|
@ -4,40 +4,202 @@ exports[`<UpLinks /> component should render the component when there is no upli
|
|||
{
|
||||
"asFragment": [Function],
|
||||
"baseElement": .emotion-0 {
|
||||
background-color: #fff;
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
-webkit-transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
|
||||
transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
|
||||
border-radius: 4px;
|
||||
box-shadow: none;
|
||||
font-family: -apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.43;
|
||||
background-color: rgb(229, 246, 253);
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
padding: 6px 16px;
|
||||
color: rgb(1, 67, 97);
|
||||
}
|
||||
|
||||
.emotion-0 .MuiAlert-icon {
|
||||
color: #0288d1;
|
||||
}
|
||||
|
||||
.emotion-1 {
|
||||
margin-right: 12px;
|
||||
padding: 7px 0;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
font-size: 22px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.emotion-2 {
|
||||
-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: inherit;
|
||||
}
|
||||
|
||||
.emotion-3 {
|
||||
padding: 8px 0;
|
||||
min-width: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.emotion-4 {
|
||||
margin: 0;
|
||||
font-family: -apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 1rem;
|
||||
line-height: 1.75;
|
||||
margin-bottom: 0.35em;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h6
|
||||
class="MuiTypography-root MuiTypography-subtitle1 MuiTypography-gutterBottom emotion-0"
|
||||
data-testid="no-uplinks"
|
||||
<div
|
||||
class="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation0 MuiAlert-root MuiAlert-standardInfo MuiAlert-standard emotion-0"
|
||||
role="alert"
|
||||
>
|
||||
uplinks.no-items
|
||||
</h6>
|
||||
<div
|
||||
class="MuiAlert-icon emotion-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiSvgIcon-fontSizeInherit emotion-2"
|
||||
data-testid="InfoOutlinedIcon"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20, 12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10, 10 0 0,0 12,2M11,17H13V11H11V17Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="MuiAlert-message emotion-3"
|
||||
>
|
||||
<p
|
||||
class="MuiTypography-root MuiTypography-body1 emotion-4"
|
||||
data-testid="no-uplinks"
|
||||
>
|
||||
uplinks.no-items
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>,
|
||||
"container": .emotion-0 {
|
||||
background-color: #fff;
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
-webkit-transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
|
||||
transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
|
||||
border-radius: 4px;
|
||||
box-shadow: none;
|
||||
font-family: -apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.43;
|
||||
background-color: rgb(229, 246, 253);
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
padding: 6px 16px;
|
||||
color: rgb(1, 67, 97);
|
||||
}
|
||||
|
||||
.emotion-0 .MuiAlert-icon {
|
||||
color: #0288d1;
|
||||
}
|
||||
|
||||
.emotion-1 {
|
||||
margin-right: 12px;
|
||||
padding: 7px 0;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
font-size: 22px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.emotion-2 {
|
||||
-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: inherit;
|
||||
}
|
||||
|
||||
.emotion-3 {
|
||||
padding: 8px 0;
|
||||
min-width: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.emotion-4 {
|
||||
margin: 0;
|
||||
font-family: -apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 1rem;
|
||||
line-height: 1.75;
|
||||
margin-bottom: 0.35em;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
<div>
|
||||
<h6
|
||||
class="MuiTypography-root MuiTypography-subtitle1 MuiTypography-gutterBottom emotion-0"
|
||||
data-testid="no-uplinks"
|
||||
<div
|
||||
class="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation0 MuiAlert-root MuiAlert-standardInfo MuiAlert-standard emotion-0"
|
||||
role="alert"
|
||||
>
|
||||
uplinks.no-items
|
||||
</h6>
|
||||
<div
|
||||
class="MuiAlert-icon emotion-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiSvgIcon-fontSizeInherit emotion-2"
|
||||
data-testid="InfoOutlinedIcon"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20, 12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10, 10 0 0,0 12,2M11,17H13V11H11V17Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="MuiAlert-message emotion-3"
|
||||
>
|
||||
<p
|
||||
class="MuiTypography-root MuiTypography-body1 emotion-4"
|
||||
data-testid="no-uplinks"
|
||||
>
|
||||
uplinks.no-items
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
"debug": [Function],
|
||||
"findAllByAltText": [Function],
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { PackageMetaInterface } from '../../types/packageMeta';
|
||||
|
||||
export interface DetailContextProps {
|
||||
enableLoading: () => void;
|
||||
hasNotBeenFound: boolean;
|
||||
isLoading: boolean;
|
||||
packageMeta: PackageMetaInterface;
|
||||
|
@ -11,7 +10,6 @@ export interface DetailContextProps {
|
|||
}
|
||||
|
||||
export interface VersionPageConsumerProps {
|
||||
enableLoading: () => void;
|
||||
packageMeta: PackageMetaInterface;
|
||||
packageName: string;
|
||||
packageVersion?: string;
|
||||
|
|
|
@ -42,6 +42,8 @@ export { VersionLayout } from './layouts/Version';
|
|||
|
||||
// providers
|
||||
export { default as AppConfigurationProvider } from './providers/AppConfigurationProvider';
|
||||
export { default as PersistenceSettingProvider } from './providers/PersistenceSettingProvider';
|
||||
|
||||
export * from './providers/AppConfigurationProvider';
|
||||
export { TranslatorProvider, useLanguage, LanguageItem } from './providers/TranslatorProvider';
|
||||
export * from './providers/TranslatorProvider';
|
||||
|
|
|
@ -1,29 +1,44 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import React from 'react';
|
||||
import { MemoryRouter, Route } from 'react-router';
|
||||
|
||||
import { VersionProvider } from '../../providers';
|
||||
import VersionLayout from './Version';
|
||||
|
||||
export default {
|
||||
title: 'VersionLayout',
|
||||
const meta: Meta<typeof VersionLayout> = {
|
||||
title: 'Layout/Version',
|
||||
component: VersionLayout,
|
||||
};
|
||||
|
||||
export const VersionLayoutStorybook: any = () => (
|
||||
<MemoryRouter initialEntries={[`/-/web/detail/storybook`]}>
|
||||
<Route exact={true} path="/-/web/detail/:package">
|
||||
<VersionProvider>
|
||||
<VersionLayout />
|
||||
</VersionProvider>
|
||||
</Route>
|
||||
</MemoryRouter>
|
||||
);
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof VersionLayout>;
|
||||
|
||||
export const VersionLayoutJquery: any = () => (
|
||||
<MemoryRouter initialEntries={[`/-/web/detail/jquery`]}>
|
||||
<Route exact={true} path="/-/web/detail/:package">
|
||||
<VersionProvider>
|
||||
<VersionLayout />
|
||||
</VersionProvider>
|
||||
</Route>
|
||||
</MemoryRouter>
|
||||
);
|
||||
export const Primary: Story = {
|
||||
name: 'Storybook',
|
||||
render: () => {
|
||||
return (
|
||||
<MemoryRouter initialEntries={[`/-/web/detail/storybook`]}>
|
||||
<Route exact={true} path="/-/web/detail/:package">
|
||||
<VersionProvider>
|
||||
<VersionLayout />
|
||||
</VersionProvider>
|
||||
</Route>
|
||||
</MemoryRouter>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const jQuery: Story = {
|
||||
name: 'jQuery',
|
||||
render: () => {
|
||||
return (
|
||||
<MemoryRouter initialEntries={[`/-/web/detail/jquery`]}>
|
||||
<Route exact={true} path="/-/web/detail/:package">
|
||||
<VersionProvider>
|
||||
<VersionLayout />
|
||||
</VersionProvider>
|
||||
</Route>
|
||||
</MemoryRouter>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -54,7 +54,6 @@ const AppConfigurationContext = createContext<ConfigProviderProps>(defaultValues
|
|||
const AppConfigurationProvider: FunctionComponent<{ children: React.ReactElement<any> }> = ({
|
||||
children,
|
||||
}) => {
|
||||
// Read only
|
||||
const [configOptions] = useState<TemplateUIOptions>(getConfiguration());
|
||||
|
||||
const value = useMemo(
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
import React, {
|
||||
FunctionComponent,
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import useLocalStorage from '../../hooks/useLocalStorage';
|
||||
|
||||
type PersistenceSettingsProps = {
|
||||
isGlobal?: boolean;
|
||||
};
|
||||
|
||||
const defaultValues: PersistenceSettingsProps = {
|
||||
isGlobal: false,
|
||||
};
|
||||
|
||||
const PersistenceSettingContext = createContext<any>(defaultValues);
|
||||
|
||||
const PersistenceSettingProvider: FunctionComponent<{ children: React.ReactElement<any> }> = ({
|
||||
children,
|
||||
}) => {
|
||||
// get the initial state from the local storage
|
||||
const [settings, setSettings] = useLocalStorage(`settings-ui-verdaccio`, {});
|
||||
|
||||
const [localSettings, setLocalSettings] = useState<PersistenceSettingsProps>(
|
||||
settings ? settings : {}
|
||||
);
|
||||
|
||||
const updateSettings = useCallback(
|
||||
(newSettings: React.SetStateAction<PersistenceSettingsProps>) => {
|
||||
setLocalSettings(newSettings);
|
||||
setSettings(newSettings);
|
||||
},
|
||||
[setSettings]
|
||||
);
|
||||
|
||||
const value = useMemo(
|
||||
() => ({
|
||||
localSettings: localSettings ? localSettings : {},
|
||||
updateSettings,
|
||||
}),
|
||||
[localSettings, updateSettings]
|
||||
);
|
||||
|
||||
return (
|
||||
<PersistenceSettingContext.Provider value={value}>
|
||||
{children}
|
||||
</PersistenceSettingContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default PersistenceSettingProvider;
|
||||
|
||||
export const useSettings = () => useContext(PersistenceSettingContext);
|
|
@ -0,0 +1 @@
|
|||
export { default, useSettings } from './PersistenceSettingProvider';
|
|
@ -15,7 +15,6 @@ function getRouterPackageName(packageName: string, scope?: string): string {
|
|||
}
|
||||
|
||||
export interface DetailContextProps {
|
||||
enableLoading: () => void;
|
||||
hasNotBeenFound: boolean;
|
||||
isLoading: boolean;
|
||||
packageMeta: PackageMetaInterface;
|
||||
|
@ -25,7 +24,6 @@ export interface DetailContextProps {
|
|||
}
|
||||
|
||||
export interface VersionPageConsumerProps {
|
||||
enableLoading: () => void;
|
||||
packageMeta: PackageMetaInterface;
|
||||
packageName: string;
|
||||
packageVersion?: string;
|
||||
|
|
|
@ -5,7 +5,7 @@ import { VersionProvider } from '../../providers';
|
|||
import Detail from './Detail';
|
||||
|
||||
export default {
|
||||
title: 'Detail',
|
||||
title: 'Sections/Detail',
|
||||
};
|
||||
|
||||
export const DetailStorybook: any = () => (
|
||||
|
|
|
@ -23,7 +23,7 @@ exports[`DetailContainer renders correctly 1`] = `
|
|||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
@media (max-width:599.95px) {
|
||||
@media (max-width:399.95px) {
|
||||
.emotion-2 .MuiTabs-scrollButtons {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import { VersionProvider } from '../../providers';
|
|||
import Header from './Header';
|
||||
|
||||
export default {
|
||||
title: 'Header',
|
||||
title: 'Sections/Header',
|
||||
};
|
||||
|
||||
function CustomInfoDialog({ onCloseDialog, title, isOpen }) {
|
||||
|
|
|
@ -4,7 +4,7 @@ import { MemoryRouter, Route } from 'react-router';
|
|||
import Home from './Home';
|
||||
|
||||
export default {
|
||||
title: 'Home',
|
||||
title: 'Sections/Home',
|
||||
};
|
||||
|
||||
export const HomeDefault: any = () => (
|
||||
|
|
|
@ -5,7 +5,7 @@ import { VersionProvider } from '../../providers';
|
|||
import DetailSidebar from './Sidebar';
|
||||
|
||||
export default {
|
||||
title: 'Sidebar',
|
||||
title: 'Sections/Sidebar',
|
||||
};
|
||||
|
||||
export const SidebarLatestPackage: any = () => (
|
||||
|
|
|
@ -43,7 +43,6 @@ const packageMeta = {
|
|||
// const detailContextValue = {
|
||||
// packageName: 'foo',
|
||||
// readMe: 'test',
|
||||
// enableLoading: () => {},
|
||||
// isLoading: false,
|
||||
// hasNotBeenFound: false,
|
||||
// packageMeta: ,
|
||||
|
|
|
@ -6,6 +6,7 @@ import { Provider } from 'react-redux';
|
|||
|
||||
import { ThemeProvider } from '../Theme';
|
||||
import AppConfigurationProvider from '../providers/AppConfigurationProvider';
|
||||
import PersistenceSettingProvider from '../providers/PersistenceSettingProvider';
|
||||
import { Store } from '../store/store';
|
||||
import i18nConfig from './i18n-config';
|
||||
|
||||
|
@ -13,13 +14,15 @@ const renderWithStore = (ui: React.ReactElement<any>, store: Store) =>
|
|||
render(ui, {
|
||||
wrapper: ({ children }) => (
|
||||
<Provider store={store}>
|
||||
<AppConfigurationProvider>
|
||||
<StyledEngineProvider injectFirst={true}>
|
||||
<ThemeProvider>
|
||||
<I18nextProvider i18n={i18nConfig}>{children}</I18nextProvider>
|
||||
</ThemeProvider>
|
||||
</StyledEngineProvider>
|
||||
</AppConfigurationProvider>
|
||||
<PersistenceSettingProvider>
|
||||
<AppConfigurationProvider>
|
||||
<StyledEngineProvider injectFirst={true}>
|
||||
<ThemeProvider>
|
||||
<I18nextProvider i18n={i18nConfig}>{children}</I18nextProvider>
|
||||
</ThemeProvider>
|
||||
</StyledEngineProvider>
|
||||
</AppConfigurationProvider>
|
||||
</PersistenceSettingProvider>
|
||||
</Provider>
|
||||
),
|
||||
});
|
||||
|
@ -27,11 +30,13 @@ const renderWithStore = (ui: React.ReactElement<any>, store: Store) =>
|
|||
const customRender = (node: React.ReactElement, ...options: any) => {
|
||||
return render(
|
||||
<AppConfigurationProvider>
|
||||
<StyledEngineProvider injectFirst={true}>
|
||||
<ThemeProvider>
|
||||
<I18nextProvider i18n={i18nConfig}>{node}</I18nextProvider>
|
||||
</ThemeProvider>
|
||||
</StyledEngineProvider>
|
||||
<PersistenceSettingProvider>
|
||||
<StyledEngineProvider injectFirst={true}>
|
||||
<ThemeProvider>
|
||||
<I18nextProvider i18n={i18nConfig}>{node}</I18nextProvider>
|
||||
</ThemeProvider>
|
||||
</StyledEngineProvider>
|
||||
</PersistenceSettingProvider>
|
||||
</AppConfigurationProvider>,
|
||||
...options
|
||||
);
|
||||
|
|
|
@ -16,6 +16,10 @@ describe('utils', () => {
|
|||
test('isEmail() - should return false if invalid', () => {
|
||||
expect(isEmail('')).toBeFalsy();
|
||||
});
|
||||
|
||||
test('git repo is valid', () => {
|
||||
expect(isURL('git://github.com/verdaccio/ui.git')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('extractFileName', () => {
|
||||
|
|
|
@ -3,7 +3,7 @@ import isURLValidator from 'validator/lib/isURL';
|
|||
|
||||
export function isURL(url: string): boolean {
|
||||
return isURLValidator(url || '', {
|
||||
protocols: ['http', 'https', 'git+https'],
|
||||
protocols: ['http', 'https', 'git+https', 'git'],
|
||||
require_protocol: true,
|
||||
require_tld: false,
|
||||
});
|
||||
|
|
22
pnpm-lock.yaml
generated
22
pnpm-lock.yaml
generated
|
@ -484,7 +484,7 @@ importers:
|
|||
specifier: workspace:2.0.0-6-next.8
|
||||
version: link:../../packages/tools/helpers
|
||||
cypress:
|
||||
specifier: 11.2.0
|
||||
specifier: ^11.2.0
|
||||
version: 11.2.0
|
||||
debug:
|
||||
specifier: 4.3.4
|
||||
|
@ -3840,7 +3840,7 @@ packages:
|
|||
'@babel/core': ^7.0.0-0
|
||||
dependencies:
|
||||
'@babel/core': 7.20.7
|
||||
'@babel/helper-plugin-utils': 7.21.5
|
||||
'@babel/helper-plugin-utils': 7.20.2
|
||||
|
||||
/@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.21.4):
|
||||
resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==}
|
||||
|
@ -3848,7 +3848,7 @@ packages:
|
|||
'@babel/core': ^7.0.0-0
|
||||
dependencies:
|
||||
'@babel/core': 7.21.4
|
||||
'@babel/helper-plugin-utils': 7.21.5
|
||||
'@babel/helper-plugin-utils': 7.20.2
|
||||
dev: true
|
||||
|
||||
/@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.21.8):
|
||||
|
@ -5811,7 +5811,7 @@ packages:
|
|||
'@babel/core': ^7.0.0-0
|
||||
dependencies:
|
||||
'@babel/core': 7.20.7
|
||||
'@babel/helper-plugin-utils': 7.20.2
|
||||
'@babel/helper-plugin-utils': 7.21.5
|
||||
'@babel/helper-validator-option': 7.21.0
|
||||
'@babel/plugin-transform-react-display-name': 7.18.6(@babel/core@7.20.7)
|
||||
'@babel/plugin-transform-react-jsx': 7.21.0(@babel/core@7.20.7)
|
||||
|
@ -5825,7 +5825,7 @@ packages:
|
|||
'@babel/core': ^7.0.0-0
|
||||
dependencies:
|
||||
'@babel/core': 7.21.4
|
||||
'@babel/helper-plugin-utils': 7.20.2
|
||||
'@babel/helper-plugin-utils': 7.21.5
|
||||
'@babel/helper-validator-option': 7.21.0
|
||||
'@babel/plugin-transform-react-display-name': 7.18.6(@babel/core@7.21.4)
|
||||
'@babel/plugin-transform-react-jsx': 7.21.0(@babel/core@7.21.4)
|
||||
|
@ -15034,7 +15034,7 @@ packages:
|
|||
pretty-bytes: 5.6.0
|
||||
proxy-from-env: 1.0.0
|
||||
request-progress: 3.0.0
|
||||
semver: 7.4.0
|
||||
semver: 7.5.0
|
||||
supports-color: 8.1.1
|
||||
tmp: 0.2.1
|
||||
untildify: 4.0.0
|
||||
|
@ -24785,7 +24785,7 @@ packages:
|
|||
peerDependencies:
|
||||
react: '>=15'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.21.5
|
||||
'@babel/runtime': 7.21.0
|
||||
history: 4.10.1
|
||||
hoist-non-react-statics: 3.3.2
|
||||
loose-envify: 1.4.0
|
||||
|
@ -25720,14 +25720,6 @@ packages:
|
|||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/semver@7.4.0:
|
||||
resolution: {integrity: sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
lru-cache: 6.0.0
|
||||
dev: true
|
||||
|
||||
/semver@7.5.0:
|
||||
resolution: {integrity: sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==}
|
||||
engines: {node: '>=10'}
|
||||
|
|
Loading…
Add table
Reference in a new issue