@verdaccio/ui-components 3.0.0-next-7.3 → 3.0.0-next-7.5

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 (81) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/AppTest/AppRoute.js +34 -0
  3. package/build/AppTest/pages/Front/Home.js +9 -0
  4. package/build/{components/SideBarTittle → AppTest/pages/Front}/index.js +2 -2
  5. package/build/AppTest/pages/Version/Version.js +34 -0
  6. package/build/AppTest/pages/Version/index.js +14 -0
  7. package/build/components/Dependencies/Dependencies.js +16 -51
  8. package/build/components/Dependencies/DependencyBlock.js +87 -0
  9. package/build/components/Dependencies/utits.js +10 -0
  10. package/build/components/Forbidden/Forbidden.js +75 -0
  11. package/build/components/Forbidden/index.js +14 -0
  12. package/build/components/NotFound/NotFound.js +16 -14
  13. package/build/components/SideBarTitle/SideBarTitle.js +94 -0
  14. package/build/components/SideBarTitle/index.js +14 -0
  15. package/build/index.js +10 -2
  16. package/build/sections/Header/HeaderSettingsDialog.js +2 -5
  17. package/build/sections/Header/RegistryInfoContent/RegistryInfoContent.js +5 -10
  18. package/build/sections/SideBar/Sidebar.js +12 -13
  19. package/build/src/AppTest/App.stories.d.ts +8 -0
  20. package/build/src/AppTest/AppRoute.d.ts +3 -0
  21. package/build/src/AppTest/pages/Front/Home.d.ts +2 -0
  22. package/build/src/AppTest/pages/Front/index.d.ts +1 -0
  23. package/build/src/AppTest/pages/Version/Version.d.ts +3 -0
  24. package/build/src/AppTest/pages/Version/index.d.ts +1 -0
  25. package/build/src/components/Dependencies/Dependencies.d.ts +1 -0
  26. package/build/src/components/Dependencies/DependencyBlock.d.ts +16 -0
  27. package/build/src/components/Dependencies/DependencyBlock.test.d.ts +1 -0
  28. package/build/src/components/Dependencies/utits.d.ts +3 -0
  29. package/build/src/components/Forbidden/Forbidden.d.ts +3 -0
  30. package/build/src/components/Forbidden/Forbidden.test.d.ts +1 -0
  31. package/build/src/components/Forbidden/index.d.ts +1 -0
  32. package/build/src/components/SideBarTitle/index.d.ts +1 -0
  33. package/build/src/index.d.ts +2 -1
  34. package/build/src/sections/Detail/Detail.stories.d.ts +1 -0
  35. package/build/src/sections/Home/Home.test.d.ts +1 -0
  36. package/build/src/store/models/manifest.d.ts +11 -0
  37. package/build/store/api.js +12 -6
  38. package/build/store/models/manifest.js +20 -2
  39. package/package.json +1 -2
  40. package/src/AppTest/App.stories.tsx +32 -0
  41. package/src/AppTest/AppRoute.tsx +42 -0
  42. package/src/AppTest/pages/Front/Home.ts +3 -0
  43. package/src/AppTest/pages/Front/index.ts +1 -0
  44. package/src/AppTest/pages/Version/Version.tsx +28 -0
  45. package/src/AppTest/pages/Version/index.ts +1 -0
  46. package/src/components/Dependencies/Dependencies.test.tsx +1 -11
  47. package/src/components/Dependencies/Dependencies.tsx +8 -50
  48. package/src/components/Dependencies/DependencyBlock.test.tsx +33 -0
  49. package/src/components/Dependencies/DependencyBlock.tsx +69 -0
  50. package/src/components/Dependencies/utits.ts +3 -0
  51. package/src/components/Forbidden/Forbidden.test.tsx +38 -0
  52. package/src/components/Forbidden/Forbidden.tsx +56 -0
  53. package/src/components/Forbidden/index.ts +1 -0
  54. package/src/components/Loading/Loading.test.tsx +4 -3
  55. package/src/components/NotFound/NotFound.tsx +6 -5
  56. package/src/components/NotFound/Notfound.test.tsx +6 -3
  57. package/src/components/SideBarTitle/index.ts +1 -0
  58. package/src/index.ts +2 -1
  59. package/src/sections/Detail/Detail.stories.tsx +10 -0
  60. package/src/sections/Header/HeaderSettingsDialog.tsx +1 -2
  61. package/src/sections/Header/RegistryInfoContent/RegistryInfoContent.tsx +2 -7
  62. package/src/sections/Home/Home.test.tsx +29 -0
  63. package/src/sections/Home/Home.tsx +0 -1
  64. package/src/sections/SideBar/Sidebar.test.tsx +42 -85
  65. package/src/sections/SideBar/Sidebar.tsx +6 -17
  66. package/src/store/api.test.ts +3 -2
  67. package/src/store/api.ts +13 -6
  68. package/src/store/models/manifest.ts +19 -1
  69. package/build/components/Dependencies/styles.js +0 -64
  70. package/build/components/SideBarTittle/SideBarTittle.js +0 -94
  71. package/build/src/components/Dependencies/styles.d.ts +0 -8
  72. package/build/src/components/SideBarTittle/index.d.ts +0 -1
  73. package/src/components/Dependencies/styles.ts +0 -26
  74. package/src/components/SideBarTittle/index.ts +0 -1
  75. /package/build/components/{SideBarTittle → SideBarTitle}/utils.js +0 -0
  76. /package/build/src/components/{SideBarTittle/SideBarTittle.d.ts → SideBarTitle/SideBarTitle.d.ts} +0 -0
  77. /package/build/src/components/{SideBarTittle/SideBarTittle.stories.d.ts → SideBarTitle/SideBarTitle.stories.d.ts} +0 -0
  78. /package/build/src/components/{SideBarTittle → SideBarTitle}/utils.d.ts +0 -0
  79. /package/src/components/{SideBarTittle/SideBarTittle.stories.tsx → SideBarTitle/SideBarTitle.stories.tsx} +0 -0
  80. /package/src/components/{SideBarTittle/SideBarTittle.tsx → SideBarTitle/SideBarTitle.tsx} +0 -0
  81. /package/src/components/{SideBarTittle → SideBarTitle}/utils.ts +0 -0
@@ -7,6 +7,8 @@ exports.default = void 0;
7
7
  exports.handleResponseType = handleResponseType;
8
8
  var _storage = _interopRequireDefault(require("./storage"));
9
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ class CustomError extends Error {}
11
+
10
12
  /**
11
13
  * Handles response according to content type
12
14
  * @param {object} response
@@ -31,7 +33,9 @@ function handleResponseType(response) {
31
33
  return Promise.all([response.ok, response.blob()]);
32
34
  }
33
35
  }
34
- return Promise.all([response.ok, response.text()]);
36
+
37
+ // error handling
38
+ return Promise.all([response.ok, response]);
35
39
  }
36
40
  const AuthHeader = 'Authorization';
37
41
  class API {
@@ -52,12 +56,14 @@ class API {
52
56
  signal: options.signal,
53
57
  ...options
54
58
  }).then(handleResponseType).then(response => {
55
- if (response[0]) {
56
- resolve(response[1]);
59
+ const [ok, data] = response;
60
+ if (ok === true) {
61
+ resolve(data);
57
62
  } else {
58
- // eslint-disable-next-line no-console
59
- console.error(response);
60
- reject(new Error('something went wrong'));
63
+ var _data$statusText, _data$status;
64
+ const error = new CustomError((_data$statusText = data === null || data === void 0 ? void 0 : data.statusText) !== null && _data$statusText !== void 0 ? _data$statusText : 'Unknown error');
65
+ error.code = (_data$status = data === null || data === void 0 ? void 0 : data.status) !== null && _data$status !== void 0 ? _data$status : 500;
66
+ reject(error);
61
67
  }
62
68
  }).catch(error => {
63
69
  reject(error);
@@ -29,6 +29,18 @@ const manifest = exports.manifest = (0, _core.createModel)()({
29
29
  return {
30
30
  ...state,
31
31
  hasNotBeenFound: true,
32
+ forbidden: false,
33
+ manifest: undefined,
34
+ packageName: undefined,
35
+ packageVersion: undefined,
36
+ readme: undefined
37
+ };
38
+ },
39
+ forbidden(state) {
40
+ return {
41
+ ...state,
42
+ forbidden: true,
43
+ hasNotBeenFound: false,
32
44
  manifest: undefined,
33
45
  packageName: undefined,
34
46
  packageVersion: undefined,
@@ -46,6 +58,7 @@ const manifest = exports.manifest = (0, _core.createModel)()({
46
58
  ...state,
47
59
  isError: true,
48
60
  hasNotBeenFound: false,
61
+ forbidden: false,
49
62
  manifest: undefined,
50
63
  packageName: undefined,
51
64
  packageVersion: undefined,
@@ -64,7 +77,8 @@ const manifest = exports.manifest = (0, _core.createModel)()({
64
77
  packageName,
65
78
  packageVersion,
66
79
  readme,
67
- hasNotBeenFound: false
80
+ hasNotBeenFound: false,
81
+ forbidden: false
68
82
  };
69
83
  }
70
84
  },
@@ -90,7 +104,11 @@ const manifest = exports.manifest = (0, _core.createModel)()({
90
104
  readme
91
105
  });
92
106
  } catch (error) {
93
- dispatch.manifest.notFound();
107
+ if (error.code === 404) {
108
+ dispatch.manifest.notFound();
109
+ } else {
110
+ dispatch.manifest.forbidden();
111
+ }
94
112
  }
95
113
  }
96
114
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdaccio/ui-components",
3
- "version": "3.0.0-next-7.3",
3
+ "version": "3.0.0-next-7.5",
4
4
  "description": "theme ui component",
5
5
  "author": "Juan Picado <juanpicado19@gmail.com>",
6
6
  "license": "MIT",
@@ -42,7 +42,6 @@
42
42
  "react-router-dom": "5.3.4",
43
43
  "react-virtualized": "9.22.5",
44
44
  "redux": "4.2.1",
45
- "remark-gfm": "3.0.1",
46
45
  "validator": "13.11.0"
47
46
  },
48
47
  "devDependencies": {
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import { MemoryRouter } from 'react-router';
3
+
4
+ import AppRoute from './AppRoute';
5
+
6
+ export default {
7
+ title: 'App/Main',
8
+ };
9
+
10
+ export const ApplicationStoryBook: any = () => (
11
+ <MemoryRouter initialEntries={[`/-/web/detail/storybook`]}>
12
+ <AppRoute />
13
+ </MemoryRouter>
14
+ );
15
+
16
+ export const ApplicationjQuery: any = () => (
17
+ <MemoryRouter initialEntries={[`/-/web/detail/jquery`]}>
18
+ <AppRoute />
19
+ </MemoryRouter>
20
+ );
21
+
22
+ export const ApplicationForbidden: any = () => (
23
+ <MemoryRouter initialEntries={[`/-/web/detail/JSONStream`]}>
24
+ <AppRoute />
25
+ </MemoryRouter>
26
+ );
27
+
28
+ export const ApplicationNotFound: any = () => (
29
+ <MemoryRouter initialEntries={[`/-/web/detail/kleur`]}>
30
+ <AppRoute />
31
+ </MemoryRouter>
32
+ );
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import { Route as ReactRouterDomRoute, Switch } from 'react-router-dom';
3
+
4
+ import { NotFound, Route, VersionProvider, loadable } from '../index';
5
+
6
+ const VersionPage = loadable(() => import(/* webpackChunkName: "Version" */ './pages/Version'));
7
+ const Front = loadable(() => import(/* webpackChunkName: "Home" */ './pages/Front'));
8
+
9
+ const AppRoute: React.FC = () => {
10
+ return (
11
+ <Switch>
12
+ <ReactRouterDomRoute exact={true} path={Route.ROOT}>
13
+ <Front />
14
+ </ReactRouterDomRoute>
15
+ <ReactRouterDomRoute exact={true} path={Route.PACKAGE}>
16
+ <VersionProvider>
17
+ <VersionPage />
18
+ </VersionProvider>
19
+ </ReactRouterDomRoute>
20
+ <ReactRouterDomRoute exact={true} path={Route.PACKAGE_VERSION}>
21
+ <VersionProvider>
22
+ <VersionPage />
23
+ </VersionProvider>
24
+ </ReactRouterDomRoute>
25
+ <ReactRouterDomRoute exact={true} path={Route.SCOPE_PACKAGE_VERSION}>
26
+ <VersionProvider>
27
+ <VersionPage />
28
+ </VersionProvider>
29
+ </ReactRouterDomRoute>
30
+ <ReactRouterDomRoute exact={true} path={Route.SCOPE_PACKAGE}>
31
+ <VersionProvider>
32
+ <VersionPage />
33
+ </VersionProvider>
34
+ </ReactRouterDomRoute>
35
+ <ReactRouterDomRoute>
36
+ <NotFound />
37
+ </ReactRouterDomRoute>
38
+ </Switch>
39
+ );
40
+ };
41
+
42
+ export default AppRoute;
@@ -0,0 +1,3 @@
1
+ import { Home } from '../../../index';
2
+
3
+ export default Home;
@@ -0,0 +1 @@
1
+ export { default } from './Home';
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import { useSelector } from 'react-redux';
3
+
4
+ import Forbidden from '../../../components/Forbidden';
5
+ import { Loading, NotFound, RootState, VersionLayout } from '../../../index';
6
+
7
+ const Version: React.FC = () => {
8
+ const manifestStore = useSelector((state: RootState) => state.manifest);
9
+ const isLoading = useSelector((state: RootState) => state?.loading?.models.manifest);
10
+
11
+ if (isLoading) {
12
+ return <Loading />;
13
+ }
14
+
15
+ // @ts-expect-error
16
+ if (manifestStore.forbidden) {
17
+ return <Forbidden />;
18
+ }
19
+
20
+ // @ts-expect-error
21
+ if (manifestStore.hasNotBeenFound) {
22
+ return <NotFound />;
23
+ }
24
+
25
+ return <VersionLayout />;
26
+ };
27
+
28
+ export default Version;
@@ -0,0 +1 @@
1
+ export { default } from './Version';
@@ -6,7 +6,6 @@ import Dependencies from './Dependencies';
6
6
 
7
7
  describe('<Dependencies /> component', () => {
8
8
  test('Renders a message when there are no dependencies', () => {
9
- // Given
10
9
  const packageMeta = {
11
10
  latest: {
12
11
  name: 'verdaccio',
@@ -25,15 +24,12 @@ describe('<Dependencies /> component', () => {
25
24
  _uplinks: {},
26
25
  };
27
26
 
28
- // When
29
27
  const { getByText } = render(<Dependencies packageMeta={packageMeta} />);
30
28
 
31
- // Then
32
29
  expect(getByText('dependencies.has-no-dependencies')).toBeDefined();
33
30
  });
34
31
 
35
- test('Renders a link to each dependency', () => {
36
- // Given
32
+ test('renders a link to each dependency', () => {
37
33
  const packageMeta = {
38
34
  latest: {
39
35
  name: 'verdaccio',
@@ -59,18 +55,12 @@ describe('<Dependencies /> component', () => {
59
55
  _uplinks: {},
60
56
  };
61
57
 
62
- // When
63
58
  const { getByText } = render(
64
59
  <HashRouter>
65
60
  <Dependencies packageMeta={packageMeta} />
66
61
  </HashRouter>
67
62
  );
68
63
 
69
- // Then
70
- // FIXME: currently MaterialUI chips do not support the children
71
- // prop, therefore it is impossible to use proper links for
72
- // dependencies. Those are for now clickable spans
73
-
74
64
  expect(getByText('dependencies (2)')).toBeDefined();
75
65
  expect(getByText('devDependencies (1)')).toBeDefined();
76
66
  expect(getByText('peerDependencies (1)')).toBeDefined();
@@ -1,63 +1,21 @@
1
- import Box from '@mui/material/Box';
1
+ import styled from '@emotion/styled';
2
+ import Card from '@mui/material/Card';
2
3
  import CardContent from '@mui/material/CardContent';
3
- import { useTheme } from '@mui/styles';
4
4
  import React from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
- import { useHistory } from 'react-router-dom';
7
6
 
8
- import { PackageDependencies } from '../../types/packageMeta';
7
+ import { Theme } from '../../Theme';
9
8
  import NoItems from '../NoItems';
10
- import { CardWrap, StyledText, Tag, Tags } from './styles';
9
+ import { DependencyBlock } from './DependencyBlock';
10
+ import { hasKeys } from './utits';
11
11
 
12
- interface DependencyBlockProps {
13
- title: string;
14
- dependencies: PackageDependencies;
15
- }
16
-
17
- const DependencyBlock: React.FC<DependencyBlockProps> = ({ title, dependencies }) => {
18
- const history = useHistory();
19
- const { t } = useTranslation();
20
- const theme = useTheme();
21
-
22
- const deps = Object.entries(dependencies);
23
-
24
- function handleClick(name: string): void {
25
- history.push(`/-/web/detail/${name}`);
26
- }
27
-
28
- return (
29
- <Box data-testid={title} sx={{ margin: theme.spacing(2) }}>
30
- <StyledText sx={{ marginBottom: theme.spacing(1) }} variant="subtitle1">
31
- {`${title} (${deps.length})`}
32
- </StyledText>
33
- <Tags>
34
- {deps.map(([name, version]) => (
35
- <Tag
36
- className={'dep-tag'}
37
- clickable={true}
38
- data-testid={name}
39
- key={name}
40
- label={t('dependencies.dependency-block', { package: name, version })}
41
- // eslint-disable-next-line
42
- onClick={() => handleClick(name)}
43
- />
44
- ))}
45
- </Tags>
46
- </Box>
47
- );
48
- };
49
-
50
- function hasKeys(object?: { [key: string]: any }): boolean {
51
- return !!object && Object.keys(object).length > 0;
52
- }
12
+ export const CardWrap = styled(Card)<{ theme?: Theme }>((props) => ({
13
+ marginBottom: props.theme.spacing(2),
14
+ }));
53
15
 
54
16
  const Dependencies: React.FC<{ packageMeta: any }> = ({ packageMeta }) => {
55
17
  const { t } = useTranslation();
56
18
 
57
- if (!packageMeta) {
58
- throw new Error(t('error.package-meta-is-required-at-detail-context'));
59
- }
60
-
61
19
  const { latest } = packageMeta;
62
20
  // FIXME: add dependencies to package meta type
63
21
  // @ts-ignore
@@ -0,0 +1,33 @@
1
+ import userEvent from '@testing-library/user-event';
2
+ import React from 'react';
3
+ import { MemoryRouter, Route } from 'react-router';
4
+
5
+ import { render, screen } from '../../test/test-react-testing-library';
6
+ import { DependencyBlock } from './DependencyBlock';
7
+
8
+ describe('<DependencyBlock /> component', () => {
9
+ test('renders dependency block', () => {
10
+ render(<DependencyBlock dependencies={{ jquery: '1.0.0' }} title="foo" />);
11
+
12
+ expect(screen.getByText('foo (1)')).toBeInTheDocument();
13
+ expect(screen.getByText('dependencies.dependency-block')).toBeInTheDocument();
14
+
15
+ userEvent.click(screen.getByText('dependencies.dependency-block'));
16
+ });
17
+
18
+ test.todo('test the click event');
19
+ test.skip('handle change route handler', () => {
20
+ render(
21
+ <MemoryRouter
22
+ initialEntries={[`/-/web/detail/some-dep`, `/-/web/detail/jquery`]}
23
+ initialIndex={0}
24
+ >
25
+ <Route exact={true} path="/-/web/detail/:package">
26
+ <DependencyBlock dependencies={{ jquery: '1.0.0' }} title="foo" />
27
+ </Route>
28
+ </MemoryRouter>
29
+ );
30
+
31
+ userEvent.click(screen.getByTestId('jquery'));
32
+ });
33
+ });
@@ -0,0 +1,69 @@
1
+ import styled from '@emotion/styled';
2
+ import Box from '@mui/material/Box';
3
+ import Chip from '@mui/material/Chip';
4
+ import Typography from '@mui/material/Typography';
5
+ import { useTheme } from '@mui/styles';
6
+ import React from 'react';
7
+ import { useTranslation } from 'react-i18next';
8
+ import { useHistory } from 'react-router-dom';
9
+
10
+ import { Theme } from '../../Theme';
11
+ import { PackageDependencies } from '../../types/packageMeta';
12
+
13
+ interface DependencyBlockProps {
14
+ title: string;
15
+ dependencies: PackageDependencies;
16
+ }
17
+
18
+ export const StyledText = styled(Typography)<{ theme?: Theme }>((props) => ({
19
+ fontWeight: props.theme && props.theme.fontWeight.bold,
20
+ textTransform: 'capitalize',
21
+ }));
22
+
23
+ export const Tags = styled('div')<{ theme?: Theme }>((props) => ({
24
+ display: 'flex',
25
+ justifyContent: 'start',
26
+ flexWrap: 'wrap',
27
+ // force title to be on the same line as the title
28
+ // could be better to avoid margin on the first element
29
+ // but it is a bit tricky to do with flexbox
30
+ marginLeft: props.theme.spacing(-0.6),
31
+ }));
32
+
33
+ export const Tag = styled(Chip)<{ theme?: Theme }>((props) => ({
34
+ margin: props.theme.spacing(0.6),
35
+ }));
36
+
37
+ export const DependencyBlock: React.FC<DependencyBlockProps> = ({ title, dependencies }) => {
38
+ const history = useHistory();
39
+ const { t } = useTranslation();
40
+ const theme = useTheme();
41
+ const deps = Object.entries(dependencies);
42
+
43
+ function handleClick(name: string): void {
44
+ history.push(`/-/web/detail/${name}`);
45
+ }
46
+
47
+ return (
48
+ <Box data-testid={title} sx={{ margin: theme.spacing(2) }}>
49
+ <StyledText sx={{ marginBottom: theme.spacing(1) }} variant="subtitle1">
50
+ {`${title} (${deps.length})`}
51
+ </StyledText>
52
+ <Tags>
53
+ {deps.map(([name, version]) => (
54
+ <Tag
55
+ className={'dep-tag'}
56
+ clickable={true}
57
+ data-testid={name}
58
+ key={name}
59
+ label={t('dependencies.dependency-block', { package: name, version })}
60
+ // eslint-disable-next-line
61
+ onClick={() => {
62
+ handleClick(name);
63
+ }}
64
+ />
65
+ ))}
66
+ </Tags>
67
+ </Box>
68
+ );
69
+ };
@@ -0,0 +1,3 @@
1
+ export function hasKeys(object?: { [key: string]: any }): boolean {
2
+ return !!object && Object.keys(object).length > 0;
3
+ }
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import { MemoryRouter } from 'react-router';
3
+
4
+ import { fireEvent, render, screen } from '../../test/test-react-testing-library';
5
+ import Forbidden from './Forbidden';
6
+
7
+ const mockHistory = jest.fn();
8
+
9
+ jest.mock('react-router-dom', () => ({
10
+ useHistory: () => ({
11
+ push: mockHistory,
12
+ }),
13
+ }));
14
+
15
+ describe('<Forbidden /> component', () => {
16
+ test('should load the component in default state', () => {
17
+ render(
18
+ <MemoryRouter>
19
+ <Forbidden />
20
+ </MemoryRouter>
21
+ );
22
+ expect(screen.getByTestId('LockIcon')).toBeInTheDocument();
23
+ expect(screen.getByText('error.401.sorry-no-access')).toBeInTheDocument();
24
+ expect(screen.getByText('button.go-to-the-home-page')).toBeInTheDocument();
25
+ });
26
+
27
+ test('go to Home Page button click', async () => {
28
+ const { getByTestId } = render(
29
+ <MemoryRouter>
30
+ <Forbidden />
31
+ </MemoryRouter>
32
+ );
33
+
34
+ const node = getByTestId('not-found-go-to-home-button');
35
+ fireEvent.click(node);
36
+ expect(mockHistory).toHaveBeenCalled();
37
+ });
38
+ });
@@ -0,0 +1,56 @@
1
+ /* eslint-disable react/forbid-component-props */
2
+
3
+ /* eslint-disable verdaccio/jsx-no-style */
4
+ import styled from '@emotion/styled';
5
+ import LockIcon from '@mui/icons-material/Lock';
6
+ import Box from '@mui/material/Box';
7
+ import Button from '@mui/material/Button';
8
+ import React, { useCallback } from 'react';
9
+ import { useTranslation } from 'react-i18next';
10
+ import { useHistory } from 'react-router-dom';
11
+
12
+ import { Theme } from '../..';
13
+ import Heading from '../Heading';
14
+
15
+ const Foebidden: React.FC = () => {
16
+ const history = useHistory();
17
+
18
+ const { t } = useTranslation();
19
+
20
+ const handleGoHome = useCallback(() => {
21
+ history.push('/');
22
+ }, [history]);
23
+
24
+ return (
25
+ <Box
26
+ alignItems="center"
27
+ data-testid="404"
28
+ display="flex"
29
+ flexDirection="column"
30
+ flexGrow={1}
31
+ justifyContent="center"
32
+ p={2}
33
+ >
34
+ <Container>
35
+ <LockIcon color="primary" style={{ fontSize: 236 }} />
36
+ </Container>
37
+ <StyledHeading className="not-found-text" variant="h4">
38
+ {t('error.401.sorry-no-access')}
39
+ </StyledHeading>
40
+ <Button data-testid="not-found-go-to-home-button" onClick={handleGoHome} variant="contained">
41
+ {t('button.go-to-the-home-page')}
42
+ </Button>
43
+ </Box>
44
+ );
45
+ };
46
+
47
+ export default Foebidden;
48
+
49
+ const Container = styled('div')({
50
+ margin: '0 auto',
51
+ });
52
+
53
+ const StyledHeading = styled(Heading)<{ theme?: Theme }>(({ theme }) => ({
54
+ color: theme?.palette.mode === 'light' ? theme?.palette.primary.main : theme?.palette.white,
55
+ marginBottom: 16,
56
+ }));
@@ -0,0 +1 @@
1
+ export { default } from './Forbidden';
@@ -1,11 +1,12 @@
1
1
  import React from 'react';
2
2
 
3
- import { render } from '../../test/test-react-testing-library';
3
+ import { render, screen } from '../../test/test-react-testing-library';
4
4
  import Loading from './Loading';
5
5
 
6
6
  describe('<Loading /> component', () => {
7
7
  test('should render the component in default state', () => {
8
- const { container } = render(<Loading />);
9
- expect(container.firstChild).toMatchSnapshot();
8
+ render(<Loading />);
9
+ screen.debug();
10
+ expect(screen.getByTestId('loading')).toBeInTheDocument();
10
11
  });
11
12
  });
@@ -1,4 +1,6 @@
1
+ /* eslint-disable verdaccio/jsx-no-style */
1
2
  import styled from '@emotion/styled';
3
+ import FolderOffIcon from '@mui/icons-material/FolderOff';
2
4
  import Box from '@mui/material/Box';
3
5
  import Button from '@mui/material/Button';
4
6
  import React, { useCallback } from 'react';
@@ -7,8 +9,6 @@ import { useHistory } from 'react-router-dom';
7
9
 
8
10
  import { Theme } from '../../';
9
11
  import Heading from '../Heading';
10
- // @ts-ignore
11
- import PackageImg from './img/package.svg';
12
12
 
13
13
  const NotFound: React.FC = () => {
14
14
  const history = useHistory();
@@ -28,7 +28,9 @@ const NotFound: React.FC = () => {
28
28
  justifyContent="center"
29
29
  p={2}
30
30
  >
31
- <EmptyPackage alt={t('error.404.page-not-found')} src={PackageImg} />
31
+ <Container>
32
+ <FolderOffIcon color="primary" style={{ fontSize: 236 }} />
33
+ </Container>
32
34
  <StyledHeading className="not-found-text" variant="h4">
33
35
  {t('error.404.sorry-we-could-not-find-it')}
34
36
  </StyledHeading>
@@ -41,8 +43,7 @@ const NotFound: React.FC = () => {
41
43
 
42
44
  export default NotFound;
43
45
 
44
- const EmptyPackage = styled('img')({
45
- width: '150px',
46
+ const Container = styled('div')({
46
47
  margin: '0 auto',
47
48
  });
48
49
 
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { MemoryRouter } from 'react-router';
3
3
 
4
- import { fireEvent, render } from '../../test/test-react-testing-library';
4
+ import { fireEvent, render, screen } from '../../test/test-react-testing-library';
5
5
  import NotFound from './NotFound';
6
6
 
7
7
  const mockHistory = jest.fn();
@@ -14,12 +14,15 @@ jest.mock('react-router-dom', () => ({
14
14
 
15
15
  describe('<NotFound /> component', () => {
16
16
  test('should load the component in default state', () => {
17
- const { container } = render(
17
+ render(
18
18
  <MemoryRouter>
19
19
  <NotFound />
20
20
  </MemoryRouter>
21
21
  );
22
- expect(container.firstChild).toMatchSnapshot();
22
+
23
+ expect(screen.getByTestId('FolderOffIcon')).toBeInTheDocument();
24
+ expect(screen.getByText('button.go-to-the-home-page')).toBeInTheDocument();
25
+ expect(screen.getByText('error.404.sorry-we-could-not-find-it')).toBeInTheDocument();
23
26
  });
24
27
 
25
28
  test('go to Home Page button click', async () => {
@@ -0,0 +1 @@
1
+ export { default } from './SideBarTitle';
package/src/index.ts CHANGED
@@ -14,7 +14,7 @@ export * as Icons from './components/Icons';
14
14
  export { default as Install } from './components/Install';
15
15
  export { default as RawViewer } from './components/RawViewer';
16
16
  export { default as Readme } from './components/Readme';
17
- export { default as SideBarTitle } from './components/SideBarTittle';
17
+ export { default as SideBarTitle } from './components/SideBarTitle';
18
18
  export { default as UpLinks } from './components/UpLinks';
19
19
  export { default as Versions } from './components/Versions';
20
20
  export { default as TextField } from './components/TextField';
@@ -22,6 +22,7 @@ export { default as Label } from './components/Label';
22
22
  export { default as Logo } from './components/Logo';
23
23
  export { default as MenuItem } from './components/MenuItem';
24
24
  export { default as NotFound } from './components/NotFound';
25
+ export { default as Forbidden } from './components/Forbidden';
25
26
  export { default as LoginDialog } from './components/LoginDialog';
26
27
  export { default as Search } from './components/Search';
27
28
  export { default as HeaderInfoDialog } from './components/HeaderInfoDialog';
@@ -27,3 +27,13 @@ export const DetailJquery: any = () => (
27
27
  </Route>
28
28
  </MemoryRouter>
29
29
  );
30
+
31
+ export const DetailForbidden: any = () => (
32
+ <MemoryRouter initialEntries={[`/-/web/detail/JSONStream`]}>
33
+ <Route exact={true} path="/-/web/detail/:package">
34
+ <VersionProvider>
35
+ <Detail />
36
+ </VersionProvider>
37
+ </Route>
38
+ </MemoryRouter>
39
+ );