@verdaccio/ui-components 3.0.0-next.0 → 3.0.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/build/components/ActionBar/ActionBar.js +6 -2
- package/build/components/ActionBar/ActionBarAction.js +15 -7
- package/build/components/Author/Author.js +15 -7
- package/build/components/Author/styles.js +7 -23
- package/build/components/CopyClipboard/CopyToClipBoard.js +11 -10
- package/build/components/Deprecated/Deprecated.js +11 -19
- package/build/components/Engines/Engines.js +7 -7
- package/build/components/Install/Install.js +7 -4
- package/build/components/Install/InstallListItem.js +25 -37
- package/build/components/Link/Link.js +5 -2
- package/build/components/Package/Package.js +14 -7
- package/build/components/RawViewer/RawViewer.js +0 -1
- package/build/components/Readme/Readme.js +11 -26
- package/build/components/Readme/Readme.js.map +1 -1
- package/build/components/Readme/ReadmeDark.js +46 -0
- package/build/components/Readme/ReadmeLight.js +46 -0
- package/build/components/Readme/github-markdown-dark.css +1015 -0
- package/build/components/Readme/github-markdown-light.css +1014 -0
- package/build/components/SettingsMenu/SettingsMenu.js +16 -3
- package/build/components/SideBarTittle/SideBarTittle.js +5 -4
- package/build/components/Versions/HistoryList.js +32 -4
- package/build/components/Versions/Versions.js +16 -2
- package/build/components/Versions/__partials__/data.json +1 -0
- package/build/components/Versions/__partials__/deprecated-versions.json +175 -0
- package/build/providers/AppConfigurationProvider/AppConfigurationProvider.js +1 -0
- package/build/providers/PersistenceSettingProvider/PersistenceSettingProvider.js +2 -1
- package/build/src/__mocks__/react-markdown.d.ts +2 -2
- package/build/src/components/Author/styles.d.ts +0 -4
- package/build/src/components/CopyClipboard/CopyToClipBoard.d.ts +1 -1
- package/build/src/components/Deprecated/Deprecated.d.ts +0 -1
- package/build/src/components/Heading/Heading.d.ts +1 -1
- package/build/src/components/Icons/DevsIcons/CommonJS.d.ts +2 -2
- package/build/src/components/Icons/DevsIcons/ES6Module.d.ts +2 -2
- package/build/src/components/Icons/DevsIcons/Git.d.ts +2 -2
- package/build/src/components/Icons/DevsIcons/NodeJS.d.ts +2 -2
- package/build/src/components/Icons/DevsIcons/TypeScript.d.ts +2 -2
- package/build/src/components/Icons/Earth.d.ts +2 -2
- package/build/src/components/Icons/FileBinary.d.ts +2 -2
- package/build/src/components/Icons/Law.d.ts +2 -2
- package/build/src/components/Icons/License.d.ts +2 -2
- package/build/src/components/Icons/Managers/Npm.d.ts +2 -2
- package/build/src/components/Icons/Managers/Pnpm.d.ts +2 -2
- package/build/src/components/Icons/Managers/Yarn.d.ts +2 -2
- package/build/src/components/Icons/SvgIcon.d.ts +1 -1
- package/build/src/components/Icons/Time.d.ts +2 -2
- package/build/src/components/Icons/Version.d.ts +2 -2
- package/build/src/components/Install/InstallListItem.d.ts +2 -0
- package/build/src/components/Link/Link.d.ts +1 -1
- package/build/src/components/LoginDialog/LoginDialog.stories.d.ts +2 -2
- package/build/src/components/LoginDialog/LoginDialogForm.d.ts +1 -1
- package/build/src/components/LoginDialog/LoginDialogFormError.d.ts +1 -1
- package/build/src/components/MenuItem/MenuItem.d.ts +1 -1
- package/build/src/components/Readme/Readme.d.ts +0 -1
- package/build/src/components/Readme/ReadmeDark.d.ts +5 -0
- package/build/src/components/Readme/ReadmeLight.d.ts +5 -0
- package/build/src/components/Search/AutoComplete/styles.d.ts +1 -1
- package/build/src/components/Search/Search.stories.d.ts +2 -2
- package/build/src/components/Search/styles.d.ts +1 -1
- package/build/src/components/TextField/TextField.d.ts +1 -1
- package/build/src/components/Versions/HistoryList.d.ts +1 -0
- package/build/src/sections/Footer/Footer.d.ts +2 -2
- package/build/src/sections/Header/LanguageSwitch.d.ts +2 -2
- package/build/src/sections/Header/styles.d.ts +1 -1
- package/build/src/store/models/login.d.ts +1 -0
- package/build/src/types/packageMeta.d.ts +1 -0
- package/build/src/utils/index.d.ts +1 -0
- package/build/src/utils/loadable.d.ts +2 -2
- package/build/src/utils/token.d.ts +1 -0
- package/build/store/models/download.js +0 -1
- package/build/store/models/login.js +17 -7
- package/build/utils/index.js +22 -0
- package/build/utils/token.js +35 -0
- package/package.json +14 -11
- package/src/components/ActionBar/ActionBar.stories.tsx +1 -1
- package/src/components/ActionBar/ActionBar.test.tsx +17 -10
- package/src/components/ActionBar/ActionBar.tsx +16 -12
- package/src/components/ActionBar/ActionBarAction.tsx +15 -10
- package/src/components/Author/Author.tsx +13 -4
- package/src/components/Author/styles.ts +0 -6
- package/src/components/CopyClipboard/CopyToClipBoard.tsx +4 -3
- package/src/components/Deprecated/Deprecated.tsx +6 -19
- package/src/components/Engines/Engines.tsx +5 -5
- package/src/components/Install/Install.test.tsx +29 -37
- package/src/components/Install/Install.tsx +15 -4
- package/src/components/Install/InstallListItem.tsx +46 -30
- package/src/components/Link/Link.tsx +10 -3
- package/src/components/Package/Package.tsx +10 -2
- package/src/components/RawViewer/RawViewer.tsx +1 -6
- package/src/components/Readme/Readme.tsx +10 -21
- package/src/components/Readme/ReadmeDark.tsx +32 -0
- package/src/components/Readme/ReadmeLight.tsx +32 -0
- package/src/components/Readme/github-markdown-dark.css +1015 -0
- package/src/components/Readme/github-markdown-light.css +1014 -0
- package/src/components/SettingsMenu/SettingsMenu.tsx +23 -4
- package/src/components/SideBarTittle/SideBarTittle.tsx +1 -0
- package/src/components/Versions/HistoryList.tsx +29 -1
- package/src/components/Versions/Versions.test.tsx +16 -1
- package/src/components/Versions/Versions.tsx +17 -1
- package/src/components/Versions/__partials__/data.json +1 -0
- package/src/components/Versions/__partials__/deprecated-versions.json +175 -0
- package/src/providers/AppConfigurationProvider/AppConfigurationProvider.tsx +1 -0
- package/src/providers/PersistenceSettingProvider/PersistenceSettingProvider.tsx +2 -0
- package/src/store/models/download.ts +0 -1
- package/src/store/models/login.test.ts +38 -0
- package/src/store/models/login.ts +12 -6
- package/src/types/packageMeta.ts +1 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/token.test.ts +54 -0
- package/src/utils/token.ts +33 -0
|
@@ -21,14 +21,24 @@ const InstallListItem: React.FC<Props> = ({ packageName }) => {
|
|
|
21
21
|
const handleOpenMenu = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
22
22
|
setAnchorEl(event.currentTarget);
|
|
23
23
|
};
|
|
24
|
-
|
|
24
|
+
|
|
25
|
+
const handleGlobalSelect = () => {
|
|
25
26
|
const statusGlobal = !localSettings[packageName]?.global;
|
|
26
|
-
updateSettings({ [packageName]: { global: statusGlobal } });
|
|
27
|
+
updateSettings({ ...localSettings, [packageName]: { global: statusGlobal } });
|
|
28
|
+
setAnchorEl(null);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const handleGlobalYarnModern = () => {
|
|
32
|
+
const statusYarnModern = !localSettings?.yarnModern;
|
|
33
|
+
updateSettings({ ...localSettings, yarnModern: statusYarnModern });
|
|
27
34
|
setAnchorEl(null);
|
|
28
35
|
};
|
|
36
|
+
|
|
29
37
|
const handleClose = () => {
|
|
30
38
|
setAnchorEl(null);
|
|
31
39
|
};
|
|
40
|
+
|
|
41
|
+
const statusGlobal = localSettings[packageName]?.global;
|
|
32
42
|
return (
|
|
33
43
|
<>
|
|
34
44
|
<IconButton
|
|
@@ -50,15 +60,24 @@ const InstallListItem: React.FC<Props> = ({ packageName }) => {
|
|
|
50
60
|
onClose={handleClose}
|
|
51
61
|
open={open}
|
|
52
62
|
>
|
|
53
|
-
<MenuItem onClick={
|
|
63
|
+
<MenuItem onClick={handleGlobalSelect}>
|
|
54
64
|
{' '}
|
|
55
|
-
{
|
|
65
|
+
{statusGlobal === true ? (
|
|
56
66
|
<ListItemIcon>
|
|
57
67
|
<Check />
|
|
58
68
|
</ListItemIcon>
|
|
59
69
|
) : null}
|
|
60
70
|
{t('sidebar.installation.global')}
|
|
61
71
|
</MenuItem>
|
|
72
|
+
<MenuItem onClick={handleGlobalYarnModern}>
|
|
73
|
+
{' '}
|
|
74
|
+
{localSettings?.yarnModern ? (
|
|
75
|
+
<ListItemIcon>
|
|
76
|
+
<Check />
|
|
77
|
+
</ListItemIcon>
|
|
78
|
+
) : null}
|
|
79
|
+
{t('sidebar.installation.yarnModern')}
|
|
80
|
+
</MenuItem>
|
|
62
81
|
</Menu>
|
|
63
82
|
</>
|
|
64
83
|
);
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import Chip from '@mui/material/Chip';
|
|
1
2
|
import List from '@mui/material/List';
|
|
2
3
|
import ListItem from '@mui/material/ListItem';
|
|
4
|
+
import { useTheme } from '@mui/styles';
|
|
3
5
|
import React from 'react';
|
|
4
6
|
import { useTranslation } from 'react-i18next';
|
|
5
7
|
|
|
8
|
+
import { useConfig } from '../../providers';
|
|
6
9
|
import { Time, Versions } from '../../types/packageMeta';
|
|
7
10
|
import { utils } from '../../utils';
|
|
8
11
|
import { Link } from '../Link';
|
|
@@ -14,18 +17,43 @@ interface Props {
|
|
|
14
17
|
time: Time;
|
|
15
18
|
}
|
|
16
19
|
|
|
20
|
+
export function filterDeprecated(versions: Versions) {
|
|
21
|
+
const versionsIds = Object.keys(versions);
|
|
22
|
+
return versionsIds.reduce((prev, current) => {
|
|
23
|
+
if (!versions[current].deprecated) {
|
|
24
|
+
prev[current] = versions[current];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return prev;
|
|
28
|
+
}, {});
|
|
29
|
+
}
|
|
30
|
+
|
|
17
31
|
const VersionsHistoryList: React.FC<Props> = ({ versions, packageName, time }) => {
|
|
18
32
|
const { t } = useTranslation();
|
|
33
|
+
const { configOptions } = useConfig();
|
|
34
|
+
const theme = useTheme();
|
|
35
|
+
const hideDeprecatedVersions = configOptions.hideDeprecatedVersions;
|
|
36
|
+
const listVersions = hideDeprecatedVersions ? filterDeprecated(versions) : versions;
|
|
19
37
|
|
|
20
38
|
return (
|
|
21
39
|
<List dense={true}>
|
|
22
|
-
{Object.keys(
|
|
40
|
+
{Object.keys(listVersions)
|
|
23
41
|
.reverse()
|
|
24
42
|
.map((version) => (
|
|
25
43
|
<ListItem className="version-item" data-testid={`version-${version}`} key={version}>
|
|
26
44
|
<Link to={`/-/web/detail/${packageName}/v/${version}`} variant="caption">
|
|
27
45
|
<ListItemText disableTypography={false} primary={version}></ListItemText>
|
|
28
46
|
</Link>
|
|
47
|
+
{typeof versions[version].deprecated === 'string' ? (
|
|
48
|
+
<Chip
|
|
49
|
+
color="warning"
|
|
50
|
+
data-testid="deprecated-badge"
|
|
51
|
+
label={t('versions.deprecated')}
|
|
52
|
+
size="small"
|
|
53
|
+
sx={{ marginLeft: theme.spacing(1) }}
|
|
54
|
+
variant="outlined"
|
|
55
|
+
/>
|
|
56
|
+
) : null}
|
|
29
57
|
<Spacer />
|
|
30
58
|
<ListItemText title={utils.formatDate(time[version])}>
|
|
31
59
|
{time[version]
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { MemoryRouter } from 'react-router-dom';
|
|
4
4
|
|
|
5
|
-
import { cleanup, render } from '../../test/test-react-testing-library';
|
|
5
|
+
import { cleanup, render, screen } from '../../test/test-react-testing-library';
|
|
6
6
|
import Versions, { Props } from './Versions';
|
|
7
7
|
import data from './__partials__/data.json';
|
|
8
|
+
import dataDeprecated from './__partials__/deprecated-versions.json';
|
|
8
9
|
|
|
9
10
|
const ComponentToBeRendered: React.FC<Props> = (props) => (
|
|
10
11
|
<MemoryRouter>
|
|
@@ -26,6 +27,8 @@ describe('<Version /> component', () => {
|
|
|
26
27
|
// pick some versions
|
|
27
28
|
expect(getByText('2.3.0')).toBeTruthy();
|
|
28
29
|
expect(getByText('canary')).toBeTruthy();
|
|
30
|
+
// there is one deprecated version deprecated
|
|
31
|
+
expect(screen.queryByTestId('deprecated-badge')).toBeInTheDocument();
|
|
29
32
|
});
|
|
30
33
|
|
|
31
34
|
test('should not render versions', () => {
|
|
@@ -35,5 +38,17 @@ describe('<Version /> component', () => {
|
|
|
35
38
|
expect(queryByText('versions.current-tags')).toBeFalsy();
|
|
36
39
|
});
|
|
37
40
|
|
|
41
|
+
test('should render versions deprecated settings', () => {
|
|
42
|
+
window.__VERDACCIO_BASENAME_UI_OPTIONS.hideDeprecatedVersions = true;
|
|
43
|
+
const { getByText } = render(
|
|
44
|
+
<ComponentToBeRendered packageMeta={dataDeprecated} packageName={'foo'} />
|
|
45
|
+
);
|
|
46
|
+
expect(getByText('versions.hide-deprecated')).toBeTruthy();
|
|
47
|
+
|
|
48
|
+
// pick some versions
|
|
49
|
+
expect(screen.queryByText('0.0.2')).not.toBeInTheDocument();
|
|
50
|
+
expect(screen.getByText('0.0.1')).toBeInTheDocument();
|
|
51
|
+
});
|
|
52
|
+
|
|
38
53
|
test.todo('should click on version link');
|
|
39
54
|
});
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import Alert from '@mui/material/Alert';
|
|
1
2
|
import Typography from '@mui/material/Typography';
|
|
3
|
+
import { useTheme } from '@mui/styles';
|
|
2
4
|
import React from 'react';
|
|
3
5
|
import { useTranslation } from 'react-i18next';
|
|
4
6
|
|
|
7
|
+
import { useConfig } from '../../providers';
|
|
5
8
|
import VersionsHistoryList from './HistoryList';
|
|
6
9
|
import VersionsTagList from './TagList';
|
|
7
10
|
|
|
@@ -9,6 +12,8 @@ export type Props = { packageMeta: any; packageName: string };
|
|
|
9
12
|
|
|
10
13
|
const Versions: React.FC<Props> = ({ packageMeta, packageName }) => {
|
|
11
14
|
const { t } = useTranslation();
|
|
15
|
+
const { configOptions } = useConfig();
|
|
16
|
+
const theme = useTheme();
|
|
12
17
|
|
|
13
18
|
if (!packageMeta) {
|
|
14
19
|
return null;
|
|
@@ -18,6 +23,7 @@ const Versions: React.FC<Props> = ({ packageMeta, packageName }) => {
|
|
|
18
23
|
|
|
19
24
|
const hasDistTags = distTags && Object.keys(distTags).length > 0 && packageName;
|
|
20
25
|
const hasVersionHistory = versions && Object.keys(versions).length > 0 && packageName;
|
|
26
|
+
const hideDeprecatedVersions = configOptions.hideDeprecatedVersions;
|
|
21
27
|
|
|
22
28
|
return (
|
|
23
29
|
<>
|
|
@@ -30,7 +36,17 @@ const Versions: React.FC<Props> = ({ packageMeta, packageName }) => {
|
|
|
30
36
|
{hasVersionHistory ? (
|
|
31
37
|
<>
|
|
32
38
|
<Typography variant="subtitle1">{t('versions.version-history')}</Typography>
|
|
33
|
-
|
|
39
|
+
<>
|
|
40
|
+
{hideDeprecatedVersions && (
|
|
41
|
+
<Alert
|
|
42
|
+
severity="info"
|
|
43
|
+
sx={{ marginTop: theme.spacing(1), marginBottom: theme.spacing(1) }}
|
|
44
|
+
>
|
|
45
|
+
{t('versions.hide-deprecated')}
|
|
46
|
+
</Alert>
|
|
47
|
+
)}
|
|
48
|
+
<VersionsHistoryList packageName={packageName} time={time} versions={versions} />
|
|
49
|
+
</>
|
|
34
50
|
</>
|
|
35
51
|
) : null}
|
|
36
52
|
</>
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
{
|
|
2
|
+
"versions": {
|
|
3
|
+
"0.0.1": {
|
|
4
|
+
"name": "@verdaccio/local-storage",
|
|
5
|
+
"version": "0.0.1",
|
|
6
|
+
"description": "local storage implementation",
|
|
7
|
+
"main": "lib/index.js",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "npm run lint && mocha --require babel-polyfill --compilers js:babel-core/register ./test/**/*.spec.js",
|
|
10
|
+
"lint": "eslint .",
|
|
11
|
+
"flow": "flow",
|
|
12
|
+
"build": "babel src/ --out-dir lib/ --copy-files",
|
|
13
|
+
"cover": "cross-env NODE_ENV=test nyc npm t"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@verdaccio/file-locking": "^0.0.3",
|
|
17
|
+
"@verdaccio/streams": "^0.0.2",
|
|
18
|
+
"async": "2.5.0",
|
|
19
|
+
"http-errors": "1.4.0",
|
|
20
|
+
"lodash": "4.17.4",
|
|
21
|
+
"mkdirp": "0.5.1"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@verdaccio/types": "0.0.2",
|
|
25
|
+
"babel-cli": "6.24.1",
|
|
26
|
+
"babel-core": "6.25.0",
|
|
27
|
+
"babel-eslint": "^7.2.3",
|
|
28
|
+
"babel-plugin-istanbul": "4.1.4",
|
|
29
|
+
"babel-polyfill": "6.23.0",
|
|
30
|
+
"babel-preset-es2015": "6.24.1",
|
|
31
|
+
"babel-preset-es2015-node4": "2.1.0",
|
|
32
|
+
"babel-preset-flow": "6.23.0",
|
|
33
|
+
"babel-plugin-transform-inline-imports-commonjs": "1.0.0",
|
|
34
|
+
"babel-plugin-array-includes": "2.0.3",
|
|
35
|
+
"babel-plugin-transform-runtime": "6.4.3",
|
|
36
|
+
"cross-env": "5.0.5",
|
|
37
|
+
"eslint": "4.4.1",
|
|
38
|
+
"eslint-config-google": "0.9.1",
|
|
39
|
+
"eslint-plugin-flowtype": "2.35.0",
|
|
40
|
+
"flow-bin": "0.52.0",
|
|
41
|
+
"mocha": "3.5.0",
|
|
42
|
+
"nyc": "11.1.0"
|
|
43
|
+
},
|
|
44
|
+
"nyc": {
|
|
45
|
+
"include": ["src/**/*.js"],
|
|
46
|
+
"all": true,
|
|
47
|
+
"cache": true,
|
|
48
|
+
"sourceMap": false,
|
|
49
|
+
"instrument": false,
|
|
50
|
+
"report-dir": "./tests-report",
|
|
51
|
+
"reporter": ["text", "html"]
|
|
52
|
+
},
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"registry": "https://registry.npmjs.org/"
|
|
55
|
+
},
|
|
56
|
+
"keywords": ["streams"],
|
|
57
|
+
"author": {
|
|
58
|
+
"name": "Juan Picado",
|
|
59
|
+
"email": "juanpicado19@gmail.com"
|
|
60
|
+
},
|
|
61
|
+
"private": false,
|
|
62
|
+
"license": "MIT",
|
|
63
|
+
"gitHead": "e7e4ea74f20331dfde0a7133a02b5b95d68696a9",
|
|
64
|
+
"_id": "@verdaccio/local-storage@0.0.1",
|
|
65
|
+
"_npmVersion": "5.3.0",
|
|
66
|
+
"_nodeVersion": "8.2.1",
|
|
67
|
+
"_npmUser": {
|
|
68
|
+
"name": "jotadeveloper",
|
|
69
|
+
"email": "juanpicado19@gmail.com"
|
|
70
|
+
},
|
|
71
|
+
"dist": {
|
|
72
|
+
"integrity": "sha512-J7qeK3r6jbaMOf4mBIqL1bAdb7Iwb+mC4ZaE9PUE2TctzXSkRRnk2M33zWGhZV0ziEPGAF40wC76wWex2GvXeA==",
|
|
73
|
+
"shasum": "9c71cbeeb922b35efc1b31949d0afa6aac97e9b6",
|
|
74
|
+
"tarball": "http://localhost:4872/@verdaccio%2flocal-storage/-/local-storage-0.0.1.tgz"
|
|
75
|
+
},
|
|
76
|
+
"maintainers": [
|
|
77
|
+
{
|
|
78
|
+
"name": "jotadeveloper",
|
|
79
|
+
"email": "juanpicado19@gmail.com"
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
"_npmOperationalInternal": {
|
|
83
|
+
"host": "s3://npm-registry-packages",
|
|
84
|
+
"tmp": "tmp/local-storage-0.0.1.tgz_1502536792670_0.3513342353980988"
|
|
85
|
+
},
|
|
86
|
+
"directories": {}
|
|
87
|
+
},
|
|
88
|
+
"0.0.2": {
|
|
89
|
+
"deprecated": "this package is deprecated",
|
|
90
|
+
"name": "@verdaccio/local-storage",
|
|
91
|
+
"version": "0.0.2",
|
|
92
|
+
"description": "local storage implementation",
|
|
93
|
+
"main": "lib/index.js",
|
|
94
|
+
"scripts": {
|
|
95
|
+
"test": "npm run lint && mocha --require babel-polyfill --compilers js:babel-core/register ./test/**/*.spec.js",
|
|
96
|
+
"lint": "eslint .",
|
|
97
|
+
"flow": "flow",
|
|
98
|
+
"build": "babel src/ --out-dir lib/ --copy-files",
|
|
99
|
+
"cover": "cross-env NODE_ENV=test nyc npm t"
|
|
100
|
+
},
|
|
101
|
+
"dependencies": {
|
|
102
|
+
"@verdaccio/file-locking": "^0.0.3",
|
|
103
|
+
"@verdaccio/streams": "^0.0.2",
|
|
104
|
+
"async": "2.5.0",
|
|
105
|
+
"http-errors": "1.4.0",
|
|
106
|
+
"lodash": "4.17.4",
|
|
107
|
+
"mkdirp": "0.5.1"
|
|
108
|
+
},
|
|
109
|
+
"devDependencies": {
|
|
110
|
+
"@verdaccio/types": "0.0.2",
|
|
111
|
+
"babel-cli": "6.24.1",
|
|
112
|
+
"babel-core": "6.25.0",
|
|
113
|
+
"babel-eslint": "^7.2.3",
|
|
114
|
+
"babel-plugin-istanbul": "4.1.4",
|
|
115
|
+
"babel-polyfill": "6.23.0",
|
|
116
|
+
"babel-preset-es2015": "6.24.1",
|
|
117
|
+
"babel-preset-es2015-node4": "2.1.0",
|
|
118
|
+
"babel-preset-flow": "6.23.0",
|
|
119
|
+
"babel-plugin-transform-inline-imports-commonjs": "1.0.0",
|
|
120
|
+
"babel-plugin-array-includes": "2.0.3",
|
|
121
|
+
"babel-plugin-transform-runtime": "6.4.3",
|
|
122
|
+
"cross-env": "5.0.5",
|
|
123
|
+
"eslint": "4.4.1",
|
|
124
|
+
"eslint-config-google": "0.9.1",
|
|
125
|
+
"eslint-plugin-flowtype": "2.35.0",
|
|
126
|
+
"flow-bin": "0.52.0",
|
|
127
|
+
"mocha": "3.5.0",
|
|
128
|
+
"nyc": "11.1.0"
|
|
129
|
+
},
|
|
130
|
+
"nyc": {
|
|
131
|
+
"include": ["src/**/*.js"],
|
|
132
|
+
"all": true,
|
|
133
|
+
"cache": true,
|
|
134
|
+
"sourceMap": false,
|
|
135
|
+
"instrument": false,
|
|
136
|
+
"report-dir": "./tests-report",
|
|
137
|
+
"reporter": ["text", "html"]
|
|
138
|
+
},
|
|
139
|
+
"publishConfig": {
|
|
140
|
+
"registry": "https://registry.npmjs.org/"
|
|
141
|
+
},
|
|
142
|
+
"keywords": ["streams"],
|
|
143
|
+
"author": {
|
|
144
|
+
"name": "Juan Picado",
|
|
145
|
+
"email": "juanpicado19@gmail.com"
|
|
146
|
+
},
|
|
147
|
+
"private": false,
|
|
148
|
+
"license": "MIT",
|
|
149
|
+
"gitHead": "626ea013ee810da9115550e0a60f44aa3d08e9a0",
|
|
150
|
+
"_id": "@verdaccio/local-storage@0.0.2",
|
|
151
|
+
"_npmVersion": "5.3.0",
|
|
152
|
+
"_nodeVersion": "8.2.1",
|
|
153
|
+
"_npmUser": {
|
|
154
|
+
"name": "jotadeveloper",
|
|
155
|
+
"email": "juanpicado19@gmail.com"
|
|
156
|
+
},
|
|
157
|
+
"dist": {
|
|
158
|
+
"integrity": "sha512-Su0cQpLAaBab3qekpcHO+J/JCfoznTuU0P7e5q9T7R2trGVobYXvsTiIB/usQNmDr2e+1N6iBhMst7Uy+231ag==",
|
|
159
|
+
"shasum": "fe79ad6f9ceb631857618038486f729098e7b31b",
|
|
160
|
+
"tarball": "http://localhost:4872/@verdaccio%2flocal-storage/-/local-storage-0.0.2.tgz"
|
|
161
|
+
},
|
|
162
|
+
"maintainers": [
|
|
163
|
+
{
|
|
164
|
+
"name": "jotadeveloper",
|
|
165
|
+
"email": "juanpicado19@gmail.com"
|
|
166
|
+
}
|
|
167
|
+
],
|
|
168
|
+
"_npmOperationalInternal": {
|
|
169
|
+
"host": "s3://npm-registry-packages",
|
|
170
|
+
"tmp": "tmp/local-storage-0.0.2.tgz_1502611253150_0.21545960218645632"
|
|
171
|
+
},
|
|
172
|
+
"directories": {}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
@@ -11,10 +11,12 @@ import useLocalStorage from '../../hooks/useLocalStorage';
|
|
|
11
11
|
|
|
12
12
|
type PersistenceSettingsProps = {
|
|
13
13
|
isGlobal?: boolean;
|
|
14
|
+
yarnModern: boolean;
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
const defaultValues: PersistenceSettingsProps = {
|
|
17
18
|
isGlobal: false,
|
|
19
|
+
yarnModern: false,
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
const PersistenceSettingContext = createContext<any>(defaultValues);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// eslint-disable-next-line jest/no-mocks-import
|
|
2
|
+
import { generateTokenWithTimeRange } from '../../../jest/unit/components/__mocks__/token';
|
|
3
|
+
|
|
4
|
+
describe('getDefaultUserState', (): void => {
|
|
5
|
+
const username = 'xyz';
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
jest.resetModules();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test('should return state with empty user', (): void => {
|
|
12
|
+
const token = 'token-xx-xx-xx';
|
|
13
|
+
|
|
14
|
+
jest.doMock('../storage', () => ({
|
|
15
|
+
getItem: (key: string) => (key === 'token' ? token : username),
|
|
16
|
+
}));
|
|
17
|
+
const { getDefaultUserState } = require('./login');
|
|
18
|
+
const result = {
|
|
19
|
+
token: null,
|
|
20
|
+
username: null,
|
|
21
|
+
};
|
|
22
|
+
expect(getDefaultUserState()).toEqual(result);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('should return state with user from storage', (): void => {
|
|
26
|
+
const token = generateTokenWithTimeRange(24);
|
|
27
|
+
|
|
28
|
+
jest.doMock('../storage', () => ({
|
|
29
|
+
getItem: (key: string) => (key === 'token' ? token : username),
|
|
30
|
+
}));
|
|
31
|
+
const { getDefaultUserState } = require('./login');
|
|
32
|
+
const result = {
|
|
33
|
+
token,
|
|
34
|
+
username,
|
|
35
|
+
};
|
|
36
|
+
expect(getDefaultUserState()).toEqual(result);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -2,6 +2,7 @@ import { createModel } from '@rematch/core';
|
|
|
2
2
|
import i18next from 'i18next';
|
|
3
3
|
|
|
4
4
|
import type { RootModel } from '.';
|
|
5
|
+
import { isTokenExpire } from '../../utils';
|
|
5
6
|
import API from '../api';
|
|
6
7
|
import storage from '../storage';
|
|
7
8
|
|
|
@@ -23,12 +24,17 @@ export type LoginBody = {
|
|
|
23
24
|
error?: LoginError;
|
|
24
25
|
} & LoginResponse;
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
token
|
|
30
|
-
|
|
31
|
-
};
|
|
27
|
+
export function getDefaultUserState(): LoginBody {
|
|
28
|
+
const token = storage.getItem('token');
|
|
29
|
+
const username = storage.getItem('username');
|
|
30
|
+
const defaultUserState = isTokenExpire(token)
|
|
31
|
+
? { token: null, username: null }
|
|
32
|
+
: { token, username };
|
|
33
|
+
|
|
34
|
+
return defaultUserState;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const defaultUserState: LoginBody = getDefaultUserState();
|
|
32
38
|
|
|
33
39
|
/**
|
|
34
40
|
*
|
package/src/types/packageMeta.ts
CHANGED
package/src/utils/index.ts
CHANGED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// eslint-disable-next-line jest/no-mocks-import
|
|
2
|
+
import {
|
|
3
|
+
generateInvalidToken,
|
|
4
|
+
generateTokenWithExpirationAsString,
|
|
5
|
+
generateTokenWithOutExpiration,
|
|
6
|
+
generateTokenWithTimeRange,
|
|
7
|
+
} from '../../jest/unit/components/__mocks__/token';
|
|
8
|
+
import { isTokenExpire } from './token';
|
|
9
|
+
|
|
10
|
+
/* eslint-disable no-console */
|
|
11
|
+
console.error = jest.fn();
|
|
12
|
+
|
|
13
|
+
describe('isTokenExpire', (): void => {
|
|
14
|
+
test('isTokenExpire - null is not a valid payload', (): void => {
|
|
15
|
+
expect(isTokenExpire(null)).toBeTruthy();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('isTokenExpire - token is not a valid payload', (): void => {
|
|
19
|
+
expect(isTokenExpire('not_a_valid_token')).toBeTruthy();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('isTokenExpire - token should not expire in 24 hrs range', (): void => {
|
|
23
|
+
const token = generateTokenWithTimeRange(24);
|
|
24
|
+
expect(isTokenExpire(token)).toBeFalsy();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('isTokenExpire - token should expire for current time', (): void => {
|
|
28
|
+
const token = generateTokenWithTimeRange();
|
|
29
|
+
expect(isTokenExpire(token)).toBeTruthy();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('isTokenExpire - token expiration is not available', (): void => {
|
|
33
|
+
const token = generateTokenWithOutExpiration();
|
|
34
|
+
expect(isTokenExpire(token)).toBeTruthy();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('isTokenExpire - token is not a valid json token', (): void => {
|
|
38
|
+
const NODE_MAJOR_VERSION = +process.versions.node.split('.')[0];
|
|
39
|
+
const errorToken = new SyntaxError(
|
|
40
|
+
NODE_MAJOR_VERSION >= 20
|
|
41
|
+
? 'Unexpected token \'i\', "invalidtoken" is not valid JSON'
|
|
42
|
+
: 'Unexpected token i in JSON at position 0'
|
|
43
|
+
);
|
|
44
|
+
const token = generateInvalidToken();
|
|
45
|
+
const result = ['Invalid token:', errorToken, 'xxxxxx.aW52YWxpZHRva2Vu.xxxxxx'];
|
|
46
|
+
expect(isTokenExpire(token)).toBeTruthy();
|
|
47
|
+
expect(console.error).toHaveBeenCalledWith(...result);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('isTokenExpire - token expiration is not a number', (): void => {
|
|
51
|
+
const token = generateTokenWithExpirationAsString();
|
|
52
|
+
expect(isTokenExpire(token)).toBeTruthy();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Base64 } from 'js-base64';
|
|
2
|
+
import isNumber from 'lodash/isNumber';
|
|
3
|
+
import isString from 'lodash/isString';
|
|
4
|
+
|
|
5
|
+
export function isTokenExpire(token: string | null): boolean {
|
|
6
|
+
if (!isString(token)) {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const [, payload] = token.split('.');
|
|
11
|
+
|
|
12
|
+
if (!payload) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let exp: number;
|
|
17
|
+
try {
|
|
18
|
+
exp = JSON.parse(Base64.decode(payload)).exp;
|
|
19
|
+
} catch (error: any) {
|
|
20
|
+
// eslint-disable-next-line no-console
|
|
21
|
+
console.error('Invalid token:', error, token);
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!exp || !isNumber(exp)) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
// Report as expire before (real expire time - 30s)
|
|
29
|
+
const jsTimestamp = exp * 1000 - 30000;
|
|
30
|
+
const expired = Date.now() >= jsTimestamp;
|
|
31
|
+
|
|
32
|
+
return expired;
|
|
33
|
+
}
|