diff --git a/.changeset/pink-apples-nail.md b/.changeset/pink-apples-nail.md
new file mode 100644
index 000000000..6bac4ddbe
--- /dev/null
+++ b/.changeset/pink-apples-nail.md
@@ -0,0 +1,7 @@
+---
+'@verdaccio/ui-theme': minor
+'@verdaccio/ui-components': minor
+'@verdaccio/config': minor
+---
+
+feat: forbidden user interface
diff --git a/package.json b/package.json
index 26ce2c287..e3f97dd18 100644
--- a/package.json
+++ b/package.json
@@ -137,7 +137,7 @@
"docker": "docker build -t verdaccio/verdaccio:local . --no-cache",
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,yml,yaml,md}\"",
"format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,json,yml,yaml,md}\"",
- "lint": "eslint --max-warnings 100 \"**/*.{js,jsx,ts,tsx}\"",
+ "lint": "eslint --max-warnings 70 \"**/*.{js,jsx,ts,tsx}\"",
"test": "pnpm --filter \"./packages/**\" test",
"test:e2e:cli": "pnpm --filter ...@verdaccio/e2e-cli-* test -- --coverage=false",
"test:e2e:ui": "pnpm --filter ...@verdaccio/e2e-ui test",
diff --git a/packages/api/test/integration/config/user.jwt.yaml b/packages/api/test/integration/config/user.jwt.yaml
index 41f407442..b5e65581c 100644
--- a/packages/api/test/integration/config/user.jwt.yaml
+++ b/packages/api/test/integration/config/user.jwt.yaml
@@ -10,7 +10,7 @@ auth:
uplinks:
ver:
- url: https://registry.verdaccio.org
+ url: https://registry.npmjs.org
security:
api:
diff --git a/packages/api/test/integration/config/user.yaml b/packages/api/test/integration/config/user.yaml
index 318133982..7de8dae66 100644
--- a/packages/api/test/integration/config/user.yaml
+++ b/packages/api/test/integration/config/user.yaml
@@ -7,7 +7,7 @@ web:
uplinks:
ver:
- url: https://registry.verdaccio.org
+ url: https://registry.npmjs.org
log: { type: stdout, format: pretty, level: trace }
diff --git a/packages/config/src/package-access.ts b/packages/config/src/package-access.ts
index 4057c99f8..8b9b86460 100644
--- a/packages/config/src/package-access.ts
+++ b/packages/config/src/package-access.ts
@@ -1,9 +1,12 @@
import assert from 'assert';
+import buildDebug from 'debug';
import _ from 'lodash';
import { errorUtils } from '@verdaccio/core';
import { PackageAccess } from '@verdaccio/types';
+const debug = buildDebug('verdaccio:config:utils');
+
export interface LegacyPackageList {
[key: string]: PackageAccess;
}
@@ -61,6 +64,7 @@ export function normalisePackageAccess(packages: LegacyPackageList): LegacyPacka
for (const pkg in packages) {
if (Object.prototype.hasOwnProperty.call(packages, pkg)) {
const packageAccess = packages[pkg];
+ debug('package access %s for %s ', packageAccess, pkg);
const isInvalid = _.isObject(packageAccess) && _.isArray(packageAccess) === false;
assert(isInvalid, `CONFIG: bad "'${pkg}'" package description (object expected)`);
diff --git a/packages/plugins/ui-theme/src/i18n/crowdin/ui.json b/packages/plugins/ui-theme/src/i18n/crowdin/ui.json
index 0738ac394..941c02ce2 100644
--- a/packages/plugins/ui-theme/src/i18n/crowdin/ui.json
+++ b/packages/plugins/ui-theme/src/i18n/crowdin/ui.json
@@ -147,9 +147,11 @@
"error": {
"unspecific": "Something went wrong.",
"404": {
- "page-not-found": "404 - Page not found",
"sorry-we-could-not-find-it": "Sorry, we couldn't find it..."
},
+ "401": {
+ "sorry-no-access": "Sorry, you need credentials access to see this page."
+ },
"app-context-not-correct-used": "The app context was not used correctly",
"theme-context-not-correct-used": "The theme context was not used correctly",
"package-meta-is-required-at-detail-context": "packageMeta is required at DetailContext"
diff --git a/packages/plugins/ui-theme/src/pages/Version/Version.tsx b/packages/plugins/ui-theme/src/pages/Version/Version.tsx
index 891e53edd..29bfea952 100644
--- a/packages/plugins/ui-theme/src/pages/Version/Version.tsx
+++ b/packages/plugins/ui-theme/src/pages/Version/Version.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { useSelector } from 'react-redux';
-import { Loading, NotFound, RootState, VersionLayout } from '@verdaccio/ui-components';
+import { Forbidden, Loading, NotFound, RootState, VersionLayout } from '@verdaccio/ui-components';
const Version: React.FC = () => {
const manifestStore = useSelector((state: RootState) => state.manifest);
@@ -11,10 +11,13 @@ const Version: React.FC = () => {
return ;
}
+ if (manifestStore.forbidden) {
+ return ;
+ }
+
if (manifestStore.hasNotBeenFound) {
return ;
}
-
return ;
};
diff --git a/packages/ui-components/jest/jest.config.js b/packages/ui-components/jest/jest.config.js
index 187198e8b..08aa8cf07 100644
--- a/packages/ui-components/jest/jest.config.js
+++ b/packages/ui-components/jest/jest.config.js
@@ -37,7 +37,7 @@ module.exports = Object.assign({}, config, {
branches: 70,
functions: 76,
lines: 80,
- statements: 82,
+ statements: 81,
},
},
});
diff --git a/packages/ui-components/jest/server-handlers.ts b/packages/ui-components/jest/server-handlers.ts
index c1e35b29f..806cbd8f7 100644
--- a/packages/ui-components/jest/server-handlers.ts
+++ b/packages/ui-components/jest/server-handlers.ts
@@ -31,6 +31,15 @@ export const handlers = [
rest.get('http://localhost:9000/-/verdaccio/data/sidebar/jquery', (req, res, ctx) => {
return res(ctx.json(require('./api/jquery-sidebar.json')));
}),
+ rest.get('http://localhost:9000/-/verdaccio/data/sidebar/JSONStream', (req, res, ctx) => {
+ return res(ctx.status(401));
+ }),
+ rest.get('http://localhost:9000/-/verdaccio/data/sidebar/semver', (req, res, ctx) => {
+ return res(ctx.status(500));
+ }),
+ rest.get('http://localhost:9000/-/verdaccio/data/sidebar/kleur', (req, res, ctx) => {
+ return res(ctx.status(404));
+ }),
rest.get('http://localhost:9000/-/verdaccio/data/sidebar/glob', (req, res, ctx) => {
return res(ctx.json(require('./api/glob-sidebar.json')));
}),
diff --git a/packages/ui-components/src/AppTest/App.stories.tsx b/packages/ui-components/src/AppTest/App.stories.tsx
new file mode 100644
index 000000000..09793b096
--- /dev/null
+++ b/packages/ui-components/src/AppTest/App.stories.tsx
@@ -0,0 +1,32 @@
+import React from 'react';
+import { MemoryRouter } from 'react-router';
+
+import AppRoute from './AppRoute';
+
+export default {
+ title: 'App/Main',
+};
+
+export const ApplicationStoryBook: any = () => (
+
+
+
+);
+
+export const ApplicationjQuery: any = () => (
+
+
+
+);
+
+export const ApplicationForbidden: any = () => (
+
+
+
+);
+
+export const ApplicationNotFound: any = () => (
+
+
+
+);
diff --git a/packages/ui-components/src/AppTest/AppRoute.tsx b/packages/ui-components/src/AppTest/AppRoute.tsx
new file mode 100644
index 000000000..732b0bff8
--- /dev/null
+++ b/packages/ui-components/src/AppTest/AppRoute.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { Route as ReactRouterDomRoute, Switch } from 'react-router-dom';
+
+import { NotFound, Route, VersionProvider, loadable } from '../index';
+
+const VersionPage = loadable(() => import(/* webpackChunkName: "Version" */ './pages/Version'));
+const Front = loadable(() => import(/* webpackChunkName: "Home" */ './pages/Front'));
+
+const AppRoute: React.FC = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default AppRoute;
diff --git a/packages/ui-components/src/AppTest/pages/Front/Home.ts b/packages/ui-components/src/AppTest/pages/Front/Home.ts
new file mode 100644
index 000000000..3784ce454
--- /dev/null
+++ b/packages/ui-components/src/AppTest/pages/Front/Home.ts
@@ -0,0 +1,3 @@
+import { Home } from '../../../index';
+
+export default Home;
diff --git a/packages/ui-components/src/AppTest/pages/Front/index.ts b/packages/ui-components/src/AppTest/pages/Front/index.ts
new file mode 100644
index 000000000..41e08eefd
--- /dev/null
+++ b/packages/ui-components/src/AppTest/pages/Front/index.ts
@@ -0,0 +1 @@
+export { default } from './Home';
diff --git a/packages/ui-components/src/AppTest/pages/Version/Version.tsx b/packages/ui-components/src/AppTest/pages/Version/Version.tsx
new file mode 100644
index 000000000..9c71f3d79
--- /dev/null
+++ b/packages/ui-components/src/AppTest/pages/Version/Version.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import { useSelector } from 'react-redux';
+
+import Forbidden from '../../../components/Forbidden';
+import { Loading, NotFound, RootState, VersionLayout } from '../../../index';
+
+const Version: React.FC = () => {
+ const manifestStore = useSelector((state: RootState) => state.manifest);
+ const isLoading = useSelector((state: RootState) => state?.loading?.models.manifest);
+
+ if (isLoading) {
+ return ;
+ }
+
+ // @ts-expect-error
+ if (manifestStore.forbidden) {
+ return ;
+ }
+
+ // @ts-expect-error
+ if (manifestStore.hasNotBeenFound) {
+ return ;
+ }
+
+ return ;
+};
+
+export default Version;
diff --git a/packages/ui-components/src/AppTest/pages/Version/index.ts b/packages/ui-components/src/AppTest/pages/Version/index.ts
new file mode 100644
index 000000000..19a6473af
--- /dev/null
+++ b/packages/ui-components/src/AppTest/pages/Version/index.ts
@@ -0,0 +1 @@
+export { default } from './Version';
diff --git a/packages/ui-components/src/components/Forbidden/Forbidden.test.tsx b/packages/ui-components/src/components/Forbidden/Forbidden.test.tsx
new file mode 100644
index 000000000..79069cef8
--- /dev/null
+++ b/packages/ui-components/src/components/Forbidden/Forbidden.test.tsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import { MemoryRouter } from 'react-router';
+
+import { fireEvent, render, screen } from '../../test/test-react-testing-library';
+import Forbidden from './Forbidden';
+
+const mockHistory = jest.fn();
+
+jest.mock('react-router-dom', () => ({
+ useHistory: () => ({
+ push: mockHistory,
+ }),
+}));
+
+describe(' component', () => {
+ test('should load the component in default state', () => {
+ render(
+
+
+
+ );
+ expect(screen.getByTestId('LockIcon')).toBeInTheDocument();
+ expect(screen.getByText('error.401.sorry-no-access')).toBeInTheDocument();
+ expect(screen.getByText('button.go-to-the-home-page')).toBeInTheDocument();
+ });
+
+ test('go to Home Page button click', async () => {
+ const { getByTestId } = render(
+
+
+
+ );
+
+ const node = getByTestId('not-found-go-to-home-button');
+ fireEvent.click(node);
+ expect(mockHistory).toHaveBeenCalled();
+ });
+});
diff --git a/packages/ui-components/src/components/Forbidden/Forbidden.tsx b/packages/ui-components/src/components/Forbidden/Forbidden.tsx
new file mode 100644
index 000000000..54a9d5455
--- /dev/null
+++ b/packages/ui-components/src/components/Forbidden/Forbidden.tsx
@@ -0,0 +1,56 @@
+/* eslint-disable react/forbid-component-props */
+
+/* eslint-disable verdaccio/jsx-no-style */
+import styled from '@emotion/styled';
+import LockIcon from '@mui/icons-material/Lock';
+import Box from '@mui/material/Box';
+import Button from '@mui/material/Button';
+import React, { useCallback } from 'react';
+import { useTranslation } from 'react-i18next';
+import { useHistory } from 'react-router-dom';
+
+import { Theme } from '../..';
+import Heading from '../Heading';
+
+const Foebidden: React.FC = () => {
+ const history = useHistory();
+
+ const { t } = useTranslation();
+
+ const handleGoHome = useCallback(() => {
+ history.push('/');
+ }, [history]);
+
+ return (
+
+
+
+
+
+ {t('error.401.sorry-no-access')}
+
+
+
+ );
+};
+
+export default Foebidden;
+
+const Container = styled('div')({
+ margin: '0 auto',
+});
+
+const StyledHeading = styled(Heading)<{ theme?: Theme }>(({ theme }) => ({
+ color: theme?.palette.mode === 'light' ? theme?.palette.primary.main : theme?.palette.white,
+ marginBottom: 16,
+}));
diff --git a/packages/ui-components/src/components/Forbidden/index.ts b/packages/ui-components/src/components/Forbidden/index.ts
new file mode 100644
index 000000000..f25fb237d
--- /dev/null
+++ b/packages/ui-components/src/components/Forbidden/index.ts
@@ -0,0 +1 @@
+export { default } from './Forbidden';
diff --git a/packages/ui-components/src/components/NotFound/NotFound.tsx b/packages/ui-components/src/components/NotFound/NotFound.tsx
index b01490834..6a1f898b6 100644
--- a/packages/ui-components/src/components/NotFound/NotFound.tsx
+++ b/packages/ui-components/src/components/NotFound/NotFound.tsx
@@ -1,4 +1,6 @@
+/* eslint-disable verdaccio/jsx-no-style */
import styled from '@emotion/styled';
+import FolderOffIcon from '@mui/icons-material/FolderOff';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import React, { useCallback } from 'react';
@@ -7,8 +9,6 @@ import { useHistory } from 'react-router-dom';
import { Theme } from '../../';
import Heading from '../Heading';
-// @ts-ignore
-import PackageImg from './img/package.svg';
const NotFound: React.FC = () => {
const history = useHistory();
@@ -28,7 +28,9 @@ const NotFound: React.FC = () => {
justifyContent="center"
p={2}
>
-
+
+
+
{t('error.404.sorry-we-could-not-find-it')}
@@ -41,8 +43,7 @@ const NotFound: React.FC = () => {
export default NotFound;
-const EmptyPackage = styled('img')({
- width: '150px',
+const Container = styled('div')({
margin: '0 auto',
});
diff --git a/packages/ui-components/src/components/NotFound/Notfound.test.tsx b/packages/ui-components/src/components/NotFound/Notfound.test.tsx
index 85cabd383..6c7278396 100644
--- a/packages/ui-components/src/components/NotFound/Notfound.test.tsx
+++ b/packages/ui-components/src/components/NotFound/Notfound.test.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { MemoryRouter } from 'react-router';
-import { fireEvent, render } from '../../test/test-react-testing-library';
+import { fireEvent, render, screen } from '../../test/test-react-testing-library';
import NotFound from './NotFound';
const mockHistory = jest.fn();
@@ -14,12 +14,15 @@ jest.mock('react-router-dom', () => ({
describe(' component', () => {
test('should load the component in default state', () => {
- const { container } = render(
+ render(
);
- expect(container.firstChild).toMatchSnapshot();
+
+ expect(screen.getByTestId('FolderOffIcon')).toBeInTheDocument();
+ expect(screen.getByText('button.go-to-the-home-page')).toBeInTheDocument();
+ expect(screen.getByText('error.404.sorry-we-could-not-find-it')).toBeInTheDocument();
});
test('go to Home Page button click', async () => {
diff --git a/packages/ui-components/src/components/NotFound/__snapshots__/Notfound.test.tsx.snap b/packages/ui-components/src/components/NotFound/__snapshots__/Notfound.test.tsx.snap
deleted file mode 100644
index 7804bc84e..000000000
--- a/packages/ui-components/src/components/NotFound/__snapshots__/Notfound.test.tsx.snap
+++ /dev/null
@@ -1,171 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[` component should load the component in default state 1`] = `
-.emotion-0 {
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-flex-direction: column;
- -ms-flex-direction: column;
- flex-direction: column;
- -webkit-box-flex: 1;
- -webkit-flex-grow: 1;
- -ms-flex-positive: 1;
- flex-grow: 1;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- padding: 16px;
-}
-
-.emotion-1 {
- width: 150px;
- margin: 0 auto;
-}
-
-.emotion-4 {
- margin: 0;
- font-family: -apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
- font-weight: 400;
- font-size: 2.125rem;
- line-height: 1.235;
- color: #4b5e40;
- margin-bottom: 16px;
-}
-
-.emotion-5 {
- display: -webkit-inline-box;
- display: -webkit-inline-flex;
- display: -ms-inline-flexbox;
- display: inline-flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- position: relative;
- box-sizing: border-box;
- -webkit-tap-highlight-color: transparent;
- background-color: transparent;
- outline: 0;
- border: 0;
- margin: 0;
- border-radius: 0;
- padding: 0;
- cursor: pointer;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- vertical-align: middle;
- -moz-appearance: none;
- -webkit-appearance: none;
- -webkit-text-decoration: none;
- text-decoration: none;
- color: inherit;
- font-family: -apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
- font-weight: 500;
- font-size: 0.875rem;
- line-height: 1.75;
- text-transform: uppercase;
- min-width: 64px;
- padding: 6px 16px;
- border-radius: 4px;
- -webkit-transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,border-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
- transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,border-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
- color: #fff;
- background-color: #4b5e40;
- box-shadow: 0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12);
-}
-
-.emotion-5::-moz-focus-inner {
- border-style: none;
-}
-
-.emotion-5.Mui-disabled {
- pointer-events: none;
- cursor: default;
-}
-
-@media print {
- .emotion-5 {
- -webkit-print-color-adjust: exact;
- color-adjust: exact;
- }
-}
-
-.emotion-5:hover {
- -webkit-text-decoration: none;
- text-decoration: none;
- background-color: rgb(52, 65, 44);
- box-shadow: 0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12);
-}
-
-@media (hover: none) {
- .emotion-5:hover {
- background-color: #4b5e40;
- }
-}
-
-.emotion-5:active {
- box-shadow: 0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12);
-}
-
-.emotion-5.Mui-focusVisible {
- box-shadow: 0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12);
-}
-
-.emotion-5.Mui-disabled {
- color: rgba(0, 0, 0, 0.26);
- box-shadow: none;
- background-color: rgba(0, 0, 0, 0.12);
-}
-
-.emotion-6 {
- overflow: hidden;
- pointer-events: none;
- position: absolute;
- z-index: 0;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- border-radius: inherit;
-}
-
-
-
-
- error.404.sorry-we-could-not-find-it
-
-
-
-`;
diff --git a/packages/ui-components/src/index.ts b/packages/ui-components/src/index.ts
index 085636b6a..d113a369b 100644
--- a/packages/ui-components/src/index.ts
+++ b/packages/ui-components/src/index.ts
@@ -22,6 +22,7 @@ export { default as Label } from './components/Label';
export { default as Logo } from './components/Logo';
export { default as MenuItem } from './components/MenuItem';
export { default as NotFound } from './components/NotFound';
+export { default as Forbidden } from './components/Forbidden';
export { default as LoginDialog } from './components/LoginDialog';
export { default as Search } from './components/Search';
export { default as HeaderInfoDialog } from './components/HeaderInfoDialog';
diff --git a/packages/ui-components/src/sections/Detail/Detail.stories.tsx b/packages/ui-components/src/sections/Detail/Detail.stories.tsx
index 648c7ad1f..7d3cc86eb 100644
--- a/packages/ui-components/src/sections/Detail/Detail.stories.tsx
+++ b/packages/ui-components/src/sections/Detail/Detail.stories.tsx
@@ -27,3 +27,13 @@ export const DetailJquery: any = () => (
);
+
+export const DetailForbidden: any = () => (
+
+
+
+
+
+
+
+);
diff --git a/packages/ui-components/src/store/api.test.ts b/packages/ui-components/src/store/api.test.ts
index 3db3fbad2..03019e75f 100644
--- a/packages/ui-components/src/store/api.test.ts
+++ b/packages/ui-components/src/store/api.test.ts
@@ -14,7 +14,8 @@ describe('api', () => {
const handled = await handleResponseType(response);
- expect(handled).toEqual([ok, responseText]);
+ expect(handled[0]).toBeFalsy();
+ expect(handled[1]).toBeDefined();
});
test('should test tgz scenario', async () => {
@@ -123,7 +124,7 @@ describe('api', () => {
})
);
- await expect(api.request('/resource')).rejects.toThrow(new Error('something went wrong'));
+ await expect(api.request('/resource')).rejects.toThrow(new Error('Unknown error'));
});
test('when api returns an error 5.x.x', async () => {
diff --git a/packages/ui-components/src/store/api.ts b/packages/ui-components/src/store/api.ts
index 4f322fc6d..85c26f3b2 100644
--- a/packages/ui-components/src/store/api.ts
+++ b/packages/ui-components/src/store/api.ts
@@ -1,5 +1,10 @@
import storage from './storage';
+class CustomError extends Error {
+ // @ts-ignore
+ code: number;
+}
+
/**
* Handles response according to content type
* @param {object} response
@@ -25,7 +30,8 @@ export function handleResponseType(response: Response): Promise<[boolean, any]>
}
}
- return Promise.all([response.ok, response.text()]);
+ // error handling
+ return Promise.all([response.ok, response]);
}
const AuthHeader = 'Authorization';
@@ -55,12 +61,13 @@ class API {
})
.then(handleResponseType)
.then((response) => {
- if (response[0]) {
- resolve(response[1]);
+ const [ok, data] = response;
+ if (ok === true) {
+ resolve(data);
} else {
- // eslint-disable-next-line no-console
- console.error(response);
- reject(new Error('something went wrong'));
+ const error = new CustomError(data?.statusText ?? 'Unknown error');
+ error.code = data?.status ?? 500;
+ reject(error);
}
})
.catch((error) => {
diff --git a/packages/ui-components/src/store/models/manifest.ts b/packages/ui-components/src/store/models/manifest.ts
index 9914ca4c8..80f54094e 100644
--- a/packages/ui-components/src/store/models/manifest.ts
+++ b/packages/ui-components/src/store/models/manifest.ts
@@ -33,6 +33,18 @@ export const manifest = createModel()({
return {
...state,
hasNotBeenFound: true,
+ forbidden: false,
+ manifest: undefined,
+ packageName: undefined,
+ packageVersion: undefined,
+ readme: undefined,
+ };
+ },
+ forbidden(state) {
+ return {
+ ...state,
+ forbidden: true,
+ hasNotBeenFound: false,
manifest: undefined,
packageName: undefined,
packageVersion: undefined,
@@ -50,6 +62,7 @@ export const manifest = createModel()({
...state,
isError: true,
hasNotBeenFound: false,
+ forbidden: false,
manifest: undefined,
packageName: undefined,
packageVersion: undefined,
@@ -64,6 +77,7 @@ export const manifest = createModel()({
packageVersion,
readme,
hasNotBeenFound: false,
+ forbidden: false,
};
},
},
@@ -91,7 +105,11 @@ export const manifest = createModel()({
);
dispatch.manifest.saveManifest({ packageName, packageVersion, manifest, readme });
} catch (error: any) {
- dispatch.manifest.notFound();
+ if (error.code === 404) {
+ dispatch.manifest.notFound();
+ } else {
+ dispatch.manifest.forbidden();
+ }
}
},
}),