@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.
Files changed (110) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/build/components/ActionBar/ActionBar.js +6 -2
  3. package/build/components/ActionBar/ActionBarAction.js +15 -7
  4. package/build/components/Author/Author.js +15 -7
  5. package/build/components/Author/styles.js +7 -23
  6. package/build/components/CopyClipboard/CopyToClipBoard.js +11 -10
  7. package/build/components/Deprecated/Deprecated.js +11 -19
  8. package/build/components/Engines/Engines.js +7 -7
  9. package/build/components/Install/Install.js +7 -4
  10. package/build/components/Install/InstallListItem.js +25 -37
  11. package/build/components/Link/Link.js +5 -2
  12. package/build/components/Package/Package.js +14 -7
  13. package/build/components/RawViewer/RawViewer.js +0 -1
  14. package/build/components/Readme/Readme.js +11 -26
  15. package/build/components/Readme/Readme.js.map +1 -1
  16. package/build/components/Readme/ReadmeDark.js +46 -0
  17. package/build/components/Readme/ReadmeLight.js +46 -0
  18. package/build/components/Readme/github-markdown-dark.css +1015 -0
  19. package/build/components/Readme/github-markdown-light.css +1014 -0
  20. package/build/components/SettingsMenu/SettingsMenu.js +16 -3
  21. package/build/components/SideBarTittle/SideBarTittle.js +5 -4
  22. package/build/components/Versions/HistoryList.js +32 -4
  23. package/build/components/Versions/Versions.js +16 -2
  24. package/build/components/Versions/__partials__/data.json +1 -0
  25. package/build/components/Versions/__partials__/deprecated-versions.json +175 -0
  26. package/build/providers/AppConfigurationProvider/AppConfigurationProvider.js +1 -0
  27. package/build/providers/PersistenceSettingProvider/PersistenceSettingProvider.js +2 -1
  28. package/build/src/__mocks__/react-markdown.d.ts +2 -2
  29. package/build/src/components/Author/styles.d.ts +0 -4
  30. package/build/src/components/CopyClipboard/CopyToClipBoard.d.ts +1 -1
  31. package/build/src/components/Deprecated/Deprecated.d.ts +0 -1
  32. package/build/src/components/Heading/Heading.d.ts +1 -1
  33. package/build/src/components/Icons/DevsIcons/CommonJS.d.ts +2 -2
  34. package/build/src/components/Icons/DevsIcons/ES6Module.d.ts +2 -2
  35. package/build/src/components/Icons/DevsIcons/Git.d.ts +2 -2
  36. package/build/src/components/Icons/DevsIcons/NodeJS.d.ts +2 -2
  37. package/build/src/components/Icons/DevsIcons/TypeScript.d.ts +2 -2
  38. package/build/src/components/Icons/Earth.d.ts +2 -2
  39. package/build/src/components/Icons/FileBinary.d.ts +2 -2
  40. package/build/src/components/Icons/Law.d.ts +2 -2
  41. package/build/src/components/Icons/License.d.ts +2 -2
  42. package/build/src/components/Icons/Managers/Npm.d.ts +2 -2
  43. package/build/src/components/Icons/Managers/Pnpm.d.ts +2 -2
  44. package/build/src/components/Icons/Managers/Yarn.d.ts +2 -2
  45. package/build/src/components/Icons/SvgIcon.d.ts +1 -1
  46. package/build/src/components/Icons/Time.d.ts +2 -2
  47. package/build/src/components/Icons/Version.d.ts +2 -2
  48. package/build/src/components/Install/InstallListItem.d.ts +2 -0
  49. package/build/src/components/Link/Link.d.ts +1 -1
  50. package/build/src/components/LoginDialog/LoginDialog.stories.d.ts +2 -2
  51. package/build/src/components/LoginDialog/LoginDialogForm.d.ts +1 -1
  52. package/build/src/components/LoginDialog/LoginDialogFormError.d.ts +1 -1
  53. package/build/src/components/MenuItem/MenuItem.d.ts +1 -1
  54. package/build/src/components/Readme/Readme.d.ts +0 -1
  55. package/build/src/components/Readme/ReadmeDark.d.ts +5 -0
  56. package/build/src/components/Readme/ReadmeLight.d.ts +5 -0
  57. package/build/src/components/Search/AutoComplete/styles.d.ts +1 -1
  58. package/build/src/components/Search/Search.stories.d.ts +2 -2
  59. package/build/src/components/Search/styles.d.ts +1 -1
  60. package/build/src/components/TextField/TextField.d.ts +1 -1
  61. package/build/src/components/Versions/HistoryList.d.ts +1 -0
  62. package/build/src/sections/Footer/Footer.d.ts +2 -2
  63. package/build/src/sections/Header/LanguageSwitch.d.ts +2 -2
  64. package/build/src/sections/Header/styles.d.ts +1 -1
  65. package/build/src/store/models/login.d.ts +1 -0
  66. package/build/src/types/packageMeta.d.ts +1 -0
  67. package/build/src/utils/index.d.ts +1 -0
  68. package/build/src/utils/loadable.d.ts +2 -2
  69. package/build/src/utils/token.d.ts +1 -0
  70. package/build/store/models/download.js +0 -1
  71. package/build/store/models/login.js +17 -7
  72. package/build/utils/index.js +22 -0
  73. package/build/utils/token.js +35 -0
  74. package/package.json +14 -11
  75. package/src/components/ActionBar/ActionBar.stories.tsx +1 -1
  76. package/src/components/ActionBar/ActionBar.test.tsx +17 -10
  77. package/src/components/ActionBar/ActionBar.tsx +16 -12
  78. package/src/components/ActionBar/ActionBarAction.tsx +15 -10
  79. package/src/components/Author/Author.tsx +13 -4
  80. package/src/components/Author/styles.ts +0 -6
  81. package/src/components/CopyClipboard/CopyToClipBoard.tsx +4 -3
  82. package/src/components/Deprecated/Deprecated.tsx +6 -19
  83. package/src/components/Engines/Engines.tsx +5 -5
  84. package/src/components/Install/Install.test.tsx +29 -37
  85. package/src/components/Install/Install.tsx +15 -4
  86. package/src/components/Install/InstallListItem.tsx +46 -30
  87. package/src/components/Link/Link.tsx +10 -3
  88. package/src/components/Package/Package.tsx +10 -2
  89. package/src/components/RawViewer/RawViewer.tsx +1 -6
  90. package/src/components/Readme/Readme.tsx +10 -21
  91. package/src/components/Readme/ReadmeDark.tsx +32 -0
  92. package/src/components/Readme/ReadmeLight.tsx +32 -0
  93. package/src/components/Readme/github-markdown-dark.css +1015 -0
  94. package/src/components/Readme/github-markdown-light.css +1014 -0
  95. package/src/components/SettingsMenu/SettingsMenu.tsx +23 -4
  96. package/src/components/SideBarTittle/SideBarTittle.tsx +1 -0
  97. package/src/components/Versions/HistoryList.tsx +29 -1
  98. package/src/components/Versions/Versions.test.tsx +16 -1
  99. package/src/components/Versions/Versions.tsx +17 -1
  100. package/src/components/Versions/__partials__/data.json +1 -0
  101. package/src/components/Versions/__partials__/deprecated-versions.json +175 -0
  102. package/src/providers/AppConfigurationProvider/AppConfigurationProvider.tsx +1 -0
  103. package/src/providers/PersistenceSettingProvider/PersistenceSettingProvider.tsx +2 -0
  104. package/src/store/models/download.ts +0 -1
  105. package/src/store/models/login.test.ts +38 -0
  106. package/src/store/models/login.ts +12 -6
  107. package/src/types/packageMeta.ts +1 -0
  108. package/src/utils/index.ts +1 -0
  109. package/src/utils/token.test.ts +54 -0
  110. 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
- const handleClick = () => {
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={handleClick}>
63
+ <MenuItem onClick={handleGlobalSelect}>
54
64
  {' '}
55
- {localSettings?.global ? (
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
  );
@@ -78,4 +78,5 @@ const StyledHeading = styled(Heading)({
78
78
 
79
79
  const StyledBoxVersion = styled(Box)<{ theme?: Theme }>(({ theme }) => ({
80
80
  color: theme?.palette.text.secondary,
81
+ fontSize: theme?.fontSize.sm,
81
82
  }));
@@ -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(versions)
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
- <VersionsHistoryList packageName={packageName} time={time} versions={versions} />
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
  </>
@@ -3,6 +3,7 @@
3
3
  "0.0.1": {
4
4
  "name": "@verdaccio/local-storage",
5
5
  "version": "0.0.1",
6
+ "deprecated": "this is deprecated",
6
7
  "description": "local storage implementation",
7
8
  "main": "lib/index.js",
8
9
  "scripts": {
@@ -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
+ }
@@ -28,6 +28,7 @@ const defaultValues: ConfigProviderProps = {
28
28
  showSearch: true,
29
29
  showRaw: true,
30
30
  showDownloadTarball: true,
31
+ hideDeprecatedVersions: false,
31
32
  title: 'Verdaccio',
32
33
  },
33
34
  };
@@ -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);
@@ -13,7 +13,6 @@ export const download = createModel<RootModel>()({
13
13
  reducers: {},
14
14
  effects: () => ({
15
15
  async getTarball({ link }) {
16
- // const basePath = state.configuration.config.base;
17
16
  try {
18
17
  const fileStream: Blob = await API.request(link, 'GET', {
19
18
  headers: {
@@ -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
- const token = storage.getItem('token');
27
- const username = storage.getItem('username');
28
- const defaultUserState: LoginBody = {
29
- token,
30
- username,
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
  *
@@ -78,6 +78,7 @@ export interface Version {
78
78
  license?: string;
79
79
  main?: string;
80
80
  keywords?: string[];
81
+ deprecated?: string;
81
82
  }
82
83
 
83
84
  export interface Author {
@@ -8,3 +8,4 @@ export {
8
8
  } from './cli-utils';
9
9
  export { default as loadable } from './loadable';
10
10
  export { Route } from './routes';
11
+ export * from './token';
@@ -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
+ }