1
0
mirror of https://github.com/SomboChea/ui synced 2026-01-19 01:25:51 +07:00

Compare commits

..

16 Commits

Author SHA1 Message Date
Juan Picado @jotadeveloper
f761e36669 feat: enable dark mode 2020-03-02 22:05:24 +01:00
dependabot-preview[bot]
26dbf3d921 build(deps-dev): [security] bump codecov from 3.6.1 to 3.6.5 (#434)
Bumps [codecov](https://github.com/codecov/codecov-node) from 3.6.1 to 3.6.5. **This update includes a security fix.**
- [Release notes](https://github.com/codecov/codecov-node/releases)
- [Commits](https://github.com/codecov/codecov-node/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-20 07:36:02 +01:00
dependabot-preview[bot]
7cb20fa699 build(deps-dev): bump jest-environment-node from 24.9.0 to 25.1.0 (#430)
Bumps [jest-environment-node](https://github.com/facebook/jest/tree/HEAD/packages/jest-environment-node) from 24.9.0 to 25.1.0.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v25.1.0/packages/jest-environment-node)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: Priscila Oliveira <priscilawebdev@gmail.com>
Co-authored-by: Juan Picado @jotadeveloper <juanpicado19@gmail.com>
2020-02-02 09:21:49 +01:00
Juan Picado @jotadeveloper
e6aad5370f chore(release): 0.3.13 2020-02-02 08:37:41 +01:00
Daniel Ruf
d481f54948 fix: do not capitalize heading - closes #428 (#431) 2020-02-02 08:36:55 +01:00
dependabot-preview[bot]
e6e9cfb2b4 build(deps-dev): bump @typescript-eslint/parser from 2.15.0 to 2.18.0 (#429) 2020-02-01 22:17:53 +01:00
Juan Picado @jotadeveloper
6570e3fba1 chore: add snyk as an action (#230) 2020-01-19 09:46:48 +01:00
Alfonso Austin
d4f2720994 chore(build): add missing export (#417)
Co-authored-by: Juan Picado @jotadeveloper <juanpicado19@gmail.com>
2020-01-14 07:43:31 +01:00
Juan Picado @jotadeveloper
1eca1f4079 fix: reload packages on log in (#421)
related https://github.com/verdaccio/ui/pull/415
2020-01-14 07:16:39 +01:00
James George
164cea6c10 fix: typo (#423)
Co-authored-by: Juan Picado @jotadeveloper <juanpicado19@gmail.com>
2020-01-14 04:11:13 +01:00
James George
dad44c46c0 docs: add link to license file (#422) 2020-01-14 03:47:14 +01:00
coolsp
222ffed022 fix: package list refresh based on logged-in user (#415)
* fix: package list refresh based on logged-in user

description:
In `pages/home/Home.tsx` now monitoring any change in a user log-in/out which will trigger a new `API.request` to get the _packages_ from the Verdaccio-server.  This is done by creating a `useEffect` on **isUserLoggedIn**.  Code has been transplanted from `App/App.tsx` including the use of the Loading component during the XHR.  The use of **packages** was removed from other components as no longer needed and tests updated.

Resolves issue #414

* fix: package list refresh based on logged-in user

description:
In `pages/home/Home.tsx` now monitoring any change in a user log-in/out which will trigger a new `API.request` to get the _packages_ from the Verdaccio-server. This is done by creating a `useEffect` on **isUserLoggedIn**. Code has been transplanted from `App/App.tsx` including the use of the Loading component during the XHR. The use of **packages** was removed from other components as no longer needed and tests updated.
Test snapshots updated

Resolves issue #414

Co-authored-by: Juan Picado @jotadeveloper <juanpicado19@gmail.com>
2020-01-12 22:21:29 +01:00
Juan Picado @jotadeveloper
ee1c3f08eb fix: update dependencies (#420)
- just minor updates
- verdaccio internal deps (we know the reason of the major change)
2020-01-12 19:43:05 +01:00
Alfonso Austin
1531cb6226 chore/401 add new script to update tests (#416)
* chore: add new script to update tests #401

* chore: update script name
2020-01-11 22:22:48 +01:00
Juan Picado @jotadeveloper
e514ec95a6 chore(release): 0.3.12 2020-01-09 06:14:09 +01:00
Daniel Ruf
6b322ad553 fix: generate correct registry URL (#413)
* Revert "Revert "fix(#300): correctly reference registry url from options" (#311)"

This reverts commit d955268c25.

* fix: generate full URL from path
2020-01-09 06:12:50 +01:00
40 changed files with 3778 additions and 1318 deletions

11
.github/workflows/security.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
name: Security Flow
on: push
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/node@0.1.0
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

View File

@@ -2,6 +2,24 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [0.3.13](https://github.com/verdaccio/ui/compare/v0.3.12...v0.3.13) (2020-02-02)
### Bug Fixes
* do not capitalize heading - closes [#428](https://github.com/verdaccio/ui/issues/428) ([#431](https://github.com/verdaccio/ui/issues/431)) ([d481f54](https://github.com/verdaccio/ui/commit/d481f549484361c1d1bc011e0858e8f99b8a2528))
* package list refresh based on logged-in user ([#415](https://github.com/verdaccio/ui/issues/415)) ([222ffed](https://github.com/verdaccio/ui/commit/222ffed0226f5aaa62f2d5b91bb08717b2aa24ef)), closes [#414](https://github.com/verdaccio/ui/issues/414) [#414](https://github.com/verdaccio/ui/issues/414)
* reload packages on log in ([#421](https://github.com/verdaccio/ui/issues/421)) ([1eca1f4](https://github.com/verdaccio/ui/commit/1eca1f40797790e87d9592204ca061527d09c4ae))
* typo ([#423](https://github.com/verdaccio/ui/issues/423)) ([164cea6](https://github.com/verdaccio/ui/commit/164cea6c10804c1d2097c2a582eb3e1e51814d4a))
* update dependencies ([#420](https://github.com/verdaccio/ui/issues/420)) ([ee1c3f0](https://github.com/verdaccio/ui/commit/ee1c3f08eb16da2313d8841cfab18358d7f4ea10))
### [0.3.12](https://github.com/verdaccio/ui/compare/v0.3.11...v0.3.12) (2020-01-09)
### Bug Fixes
* generate correct registry URL ([#413](https://github.com/verdaccio/ui/issues/413)) ([6b322ad](https://github.com/verdaccio/ui/commit/6b322ad553e9fb3ee65b2968dcfe856ba42a0bfb)), closes [#300](https://github.com/verdaccio/ui/issues/300) [#311](https://github.com/verdaccio/ui/issues/311)
### [0.3.11](https://github.com/verdaccio/ui/compare/v0.3.10...v0.3.11) (2020-01-08) ### [0.3.11](https://github.com/verdaccio/ui/compare/v0.3.10...v0.3.11) (2020-01-08)

View File

@@ -12,7 +12,7 @@
[![stackshare](https://img.shields.io/badge/Follow%20on-StackShare-blue.svg?logo=stackshare&style=flat)](https://stackshare.io/verdaccio) [![stackshare](https://img.shields.io/badge/Follow%20on-StackShare-blue.svg?logo=stackshare&style=flat)](https://stackshare.io/verdaccio)
[![discord](https://img.shields.io/discord/388674437219745793.svg)](http://chat.verdaccio.org/) [![discord](https://img.shields.io/discord/388674437219745793.svg)](http://chat.verdaccio.org/)
[![node](https://img.shields.io/node/v/@verdaccio/ui-theme/latest.svg)](https://www.npmjs.com/package/@verdaccio/ui-theme) [![node](https://img.shields.io/node/v/@verdaccio/ui-theme/latest.svg)](https://www.npmjs.com/package/@verdaccio/ui-theme)
![MIT](https://img.shields.io/github/license/mashape/apistatus.svg) [![MIT](https://img.shields.io/github/license/mashape/apistatus.svg)](./LICENSE)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/verdaccio/localized.svg)](https://crowdin.com/project/verdaccio) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/verdaccio/localized.svg)](https://crowdin.com/project/verdaccio)
[![codecov](https://codecov.io/gh/verdaccio/ui/branch/master/graph/badge.svg)](https://codecov.io/gh/verdaccio/ui) [![codecov](https://codecov.io/gh/verdaccio/ui/branch/master/graph/badge.svg)](https://codecov.io/gh/verdaccio/ui)

View File

@@ -1 +1 @@
require.requireActual('babel/polyfill'); jest.requireActual('babel/polyfill');

View File

@@ -8,14 +8,13 @@ import Adapter from 'enzyme-adapter-react-16';
import { GlobalWithFetchMock } from 'jest-fetch-mock'; import { GlobalWithFetchMock } from 'jest-fetch-mock';
import 'mutationobserver-shim'; import 'mutationobserver-shim';
// @ts-ignore : Only a void function can be called with the 'new' keyword
configure({ adapter: new Adapter() }); configure({ adapter: new Adapter() });
// @ts-ignore : Property '__APP_VERSION__' does not exist on type 'Global'. // @ts-ignore : Property '__APP_VERSION__' does not exist on type 'Global'.
global.__APP_VERSION__ = '1.0.0'; global.__APP_VERSION__ = '1.0.0';
// @ts-ignore : Property '__VERDACCIO_BASENAME_UI_OPTIONS' does not exist on type 'Global'. // @ts-ignore : Property '__VERDACCIO_BASENAME_UI_OPTIONS' does not exist on type 'Global'.
global.__VERDACCIO_BASENAME_UI_OPTIONS = {}; global.__VERDACCIO_BASENAME_UI_OPTIONS = { base: 'http://localhost' };
// @ts-ignore : Property 'VERDACCIO_API_URL' does not exist on type 'Global'.
global.VERDACCIO_API_URL = 'https://verdaccio.tld'; global.VERDACCIO_API_URL = 'https://verdaccio.tld';
const customGlobal: GlobalWithFetchMock = global as GlobalWithFetchMock; const customGlobal: GlobalWithFetchMock = global as GlobalWithFetchMock;

View File

@@ -1,6 +1,6 @@
{ {
"name": "@verdaccio/ui-theme", "name": "@verdaccio/ui-theme",
"version": "0.3.11", "version": "0.3.13",
"description": "Verdaccio User Interface", "description": "Verdaccio User Interface",
"author": { "author": {
"name": "Verdaccio Core Team", "name": "Verdaccio Core Team",
@@ -13,10 +13,10 @@
"homepage": "https://verdaccio.org", "homepage": "https://verdaccio.org",
"main": "index.js", "main": "index.js",
"devDependencies": { "devDependencies": {
"@babel/plugin-proposal-nullish-coalescing-operator": "7.7.4", "@babel/plugin-proposal-nullish-coalescing-operator": "7.8.0",
"@babel/plugin-proposal-optional-chaining": "7.7.5", "@babel/plugin-proposal-optional-chaining": "7.8.0",
"@commitlint/cli": "8.2.0", "@commitlint/cli": "8.3.4",
"@commitlint/config-conventional": "8.2.0", "@commitlint/config-conventional": "8.3.4",
"@emotion/core": "10.0.22", "@emotion/core": "10.0.22",
"@emotion/styled": "10.0.23", "@emotion/styled": "10.0.23",
"@material-ui/core": "4.8.0", "@material-ui/core": "4.8.0",
@@ -29,33 +29,33 @@
"@types/jest": "24.0.24", "@types/jest": "24.0.24",
"@types/js-base64": "2.3.1", "@types/js-base64": "2.3.1",
"@types/lodash": "4.14.149", "@types/lodash": "4.14.149",
"@types/node": "12.12.21", "@types/node": "13.1.6",
"@types/react": "16.9.17", "@types/react": "16.9.17",
"@types/react-autosuggest": "9.3.13", "@types/react-autosuggest": "9.3.13",
"@types/react-dom": "16.9.4", "@types/react-dom": "16.9.4",
"@types/react-router-dom": "5.1.3", "@types/react-router-dom": "5.1.3",
"@types/request": "2.48.4", "@types/request": "2.48.4",
"@types/validator": "12.0.1", "@types/validator": "12.0.1",
"@types/webpack-env": "1.14.1", "@types/webpack-env": "1.15.0",
"@typescript-eslint/parser": "2.12.0", "@typescript-eslint/parser": "2.18.0",
"@verdaccio/babel-preset": "8.4.2", "@verdaccio/babel-preset": "9.0.0",
"@verdaccio/commons-api": "8.4.2", "@verdaccio/commons-api": "9.0.0",
"@verdaccio/eslint-config": "8.4.2", "@verdaccio/eslint-config": "8.4.2",
"@verdaccio/types": "8.4.2", "@verdaccio/types": "9.0.0",
"autosuggest-highlight": "3.1.1", "autosuggest-highlight": "3.1.1",
"babel-loader": "8.0.6", "babel-loader": "8.0.6",
"bundlesize": "0.18.0", "bundlesize": "0.18.0",
"codeceptjs": "2.3.6", "codeceptjs": "2.4.0",
"codecov": "3.6.1", "codecov": "3.6.5",
"concurrently": "5.0.2", "concurrently": "5.0.2",
"cross-env": "6.0.3", "cross-env": "6.0.3",
"css-loader": "3.4.0", "css-loader": "3.4.2",
"dayjs": "1.8.18", "dayjs": "1.8.19",
"detect-secrets": "1.0.5", "detect-secrets": "1.0.5",
"emotion": "10.0.23", "emotion": "10.0.27",
"emotion-theming": "10.0.19", "emotion-theming": "10.0.27",
"enzyme": "3.10.0", "enzyme": "3.11.0",
"enzyme-adapter-react-16": "1.15.1", "enzyme-adapter-react-16": "1.15.2",
"enzyme-to-json": "3.4.3", "enzyme-to-json": "3.4.3",
"eslint": "6.7.2", "eslint": "6.7.2",
"eslint-plugin-codeceptjs": "1.2.0", "eslint-plugin-codeceptjs": "1.2.0",
@@ -74,16 +74,16 @@
"identity-obj-proxy": "3.0.0", "identity-obj-proxy": "3.0.0",
"in-publish": "2.0.0", "in-publish": "2.0.0",
"jest": "24.9.0", "jest": "24.9.0",
"jest-emotion": "10.0.26", "jest-emotion": "10.0.27",
"jest-environment-jsdom": "24.9.0", "jest-environment-jsdom": "24.9.0",
"jest-environment-jsdom-global": "1.2.0", "jest-environment-jsdom-global": "1.2.0",
"jest-environment-node": "24.9.0", "jest-environment-node": "25.1.0",
"jest-fetch-mock": "2.1.2", "jest-fetch-mock": "3.0.1",
"js-base64": "2.5.1", "js-base64": "2.5.1",
"js-yaml": "3.13.1", "js-yaml": "3.13.1",
"lint-staged": "9.5.0", "lint-staged": "9.5.0",
"localstorage-memory": "1.0.3", "localstorage-memory": "1.0.3",
"lockfile-lint": "3.0.3", "lockfile-lint": "3.0.5",
"lodash": "^4.17.15", "lodash": "^4.17.15",
"mini-css-extract-plugin": "0.9.0", "mini-css-extract-plugin": "0.9.0",
"mutationobserver-shim": "0.3.3", "mutationobserver-shim": "0.3.3",
@@ -113,15 +113,15 @@
"stylelint-webpack-plugin": "1.1.2", "stylelint-webpack-plugin": "1.1.2",
"supertest": "4.0.2", "supertest": "4.0.2",
"typeface-roboto": "0.0.75", "typeface-roboto": "0.0.75",
"typescript": "3.7.3", "typescript": "3.7.4",
"uglifyjs-webpack-plugin": "2.2.0", "uglifyjs-webpack-plugin": "2.2.0",
"url-loader": "3.0.0", "url-loader": "3.0.0",
"validator": "12.1.0", "validator": "12.1.0",
"verdaccio": "4.4.0", "verdaccio": "4.4.2",
"verdaccio-auth-memory": "8.4.2", "verdaccio-auth-memory": "9.0.0",
"verdaccio-memory": "8.4.2", "verdaccio-memory": "9.0.0",
"wait-on": "3.3.0", "wait-on": "3.3.0",
"webpack": "4.41.4", "webpack": "4.41.5",
"webpack-bundle-analyzer": "3.6.0", "webpack-bundle-analyzer": "3.6.0",
"webpack-bundle-size-analyzer": "3.1.0", "webpack-bundle-size-analyzer": "3.1.0",
"webpack-cli": "3.3.10", "webpack-cli": "3.3.10",
@@ -171,6 +171,7 @@
"test:acceptance:server": "concurrently --kill-others \"npm run verdaccio:server\" \"npm run test:acceptance\"", "test:acceptance:server": "concurrently --kill-others \"npm run verdaccio:server\" \"npm run test:acceptance\"",
"test:e2e": "cross-env BABEL_ENV=test jest --config ./test/jest.config.e2e.js", "test:e2e": "cross-env BABEL_ENV=test jest --config ./test/jest.config.e2e.js",
"test": "cross-env NODE_ENV=test BABEL_ENV=test TZ=UTC jest --config ./jest/jest.config.js --maxWorkers 2 --passWithNoTests", "test": "cross-env NODE_ENV=test BABEL_ENV=test TZ=UTC jest --config ./jest/jest.config.js --maxWorkers 2 --passWithNoTests",
"test:update-snapshot": "npm run test -- -u",
"test:size": "bundlesize", "test:size": "bundlesize",
"lint": "npm run lint:js && npm run lint:css && npm run lint:lockfile", "lint": "npm run lint:js && npm run lint:css && npm run lint:lockfile",
"lint:js": "npm run type-check && eslint . --ext .js,.ts,.tsx", "lint:js": "npm run type-check && eslint . --ext .js,.ts,.tsx",

View File

@@ -5,11 +5,9 @@ import { Router } from 'react-router-dom';
import storage from '../utils/storage'; import storage from '../utils/storage';
import { isTokenExpire } from '../utils/login'; import { isTokenExpire } from '../utils/login';
import API from '../utils/api';
import Header from '../components/Header'; import Header from '../components/Header';
import Footer from '../components/Footer'; import Footer from '../components/Footer';
import Box from '../muiComponents/Box'; import Box from '../muiComponents/Box';
import Loading from '../components/Loading';
import StyleBaseline from '../design-tokens/StyleBaseline'; import StyleBaseline from '../design-tokens/StyleBaseline';
import { Theme } from '../design-tokens/theme'; import { Theme } from '../design-tokens/theme';
@@ -17,7 +15,7 @@ import AppContextProvider from './AppContextProvider';
import AppRoute, { history } from './AppRoute'; import AppRoute, { history } from './AppRoute';
const StyledBox = styled(Box)<{ theme?: Theme }>(({ theme }) => ({ const StyledBox = styled(Box)<{ theme?: Theme }>(({ theme }) => ({
backgroundColor: theme && theme.palette.white, backgroundColor: theme && theme.palette.backgroundBody,
})); }));
const StyledBoxContent = styled(Box)<{ theme?: Theme }>(({ theme }) => ({ const StyledBoxContent = styled(Box)<{ theme?: Theme }>(({ theme }) => ({
@@ -33,11 +31,9 @@ const StyledBoxContent = styled(Box)<{ theme?: Theme }>(({ theme }) => ({
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
const App: React.FC = () => { const App: React.FC = () => {
const [user, setUser] = useState(); const [user, setUser] = useState();
const [packages, setPackages] = useState([]);
const [isLoading, setIsLoading] = useState(true);
/** /**
* Logouts user * Logout user
* Required by: <Header /> * Required by: <Header />
*/ */
const logout = () => { const logout = () => {
@@ -59,46 +55,26 @@ const App: React.FC = () => {
setUser({ username }); setUser({ username });
}; };
const loadOnHandler = async () => {
try {
const packages = await API.request('packages', 'GET');
// FIXME add correct type for package
setPackages(packages as never[]);
} catch (error) {
// FIXME: add dialog
console.error({
title: 'Warning',
message: `Unable to load package list: ${error.message}`,
});
}
setIsLoading(false);
};
useEffect(() => { useEffect(() => {
checkUserAlreadyLoggedIn(); checkUserAlreadyLoggedIn();
loadOnHandler();
}, []); }, []);
return ( return (
<> <>
<StyleBaseline /> <StyleBaseline />
<StyledBox display="flex" flexDirection="column" height="100%"> <StyledBox display="flex" flexDirection="column" height="100%">
{isLoading ? ( <>
<Loading /> <Router history={history}>
) : ( <AppContextProvider user={user}>
<> <Header />
<Router history={history}> <StyledBoxContent flexGrow={1}>
<AppContextProvider packages={packages} user={user}> {/* eslint-disable-next-line react/jsx-max-depth */}
<Header /> <AppRoute />
<StyledBoxContent flexGrow={1}> </StyledBoxContent>
<AppRoute /> </AppContextProvider>
</StyledBoxContent> </Router>
</AppContextProvider> <Footer />
</Router> </>
<Footer />
</>
)}
</StyledBox> </StyledBox>
</> </>
); );

View File

@@ -3,7 +3,6 @@ import { createContext } from 'react';
export interface AppProps { export interface AppProps {
user?: User; user?: User;
scope: string; scope: string;
packages: any[];
} }
export interface User { export interface User {

View File

@@ -3,15 +3,13 @@ import React, { useState, useEffect } from 'react';
import AppContext, { AppProps, User } from './AppContext'; import AppContext, { AppProps, User } from './AppContext';
interface Props { interface Props {
packages: any[];
user?: User; user?: User;
} }
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
const AppContextProvider: React.FC<Props> = ({ children, packages, user }) => { const AppContextProvider: React.FC<Props> = ({ children, user }) => {
const [state, setState] = useState<AppProps>({ const [state, setState] = useState<AppProps>({
scope: window.VERDACCIO_SCOPE || '', scope: window.VERDACCIO_SCOPE || '',
packages,
user, user,
}); });
@@ -22,13 +20,6 @@ const AppContextProvider: React.FC<Props> = ({ children, packages, user }) => {
}); });
}, [user]); }, [user]);
useEffect(() => {
setState({
...state,
packages,
});
}, [packages]);
const setUser = (user?: User) => { const setUser = (user?: User) => {
setState({ setState({
...state, ...state,

View File

@@ -30,7 +30,7 @@ const AppRoute: React.FC = () => {
throw Error('The app Context was not correct used'); throw Error('The app Context was not correct used');
} }
const { user, packages } = appContext; const { user } = appContext;
const isUserLoggedIn = user && user.username; const isUserLoggedIn = user && user.username;
@@ -39,7 +39,7 @@ const AppRoute: React.FC = () => {
<Suspense fallback={<Loading />}> <Suspense fallback={<Loading />}>
<Switch> <Switch>
<ReactRouterDomRoute exact={true} path={Route.ROOT}> <ReactRouterDomRoute exact={true} path={Route.ROOT}>
<HomePage isUserLoggedIn={!!isUserLoggedIn} packages={packages || []} /> <HomePage isUserLoggedIn={!!isUserLoggedIn} />
</ReactRouterDomRoute> </ReactRouterDomRoute>
<ReactRouterDomRoute exact={true} path={Route.PACKAGE}> <ReactRouterDomRoute exact={true} path={Route.PACKAGE}>
<VersionContextProvider> <VersionContextProvider>

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@ import Box from '../../muiComponents/Box';
import DetailContainerTabs from './DetailContainerTabs'; import DetailContainerTabs from './DetailContainerTabs';
import DetailContainerContent from './DetailContainerContent'; import DetailContainerContent from './DetailContainerContent';
import { TabPosition } from './tabs'; import { TabPosition } from './tabs';
import { DetailTheme } from './styles';
const DetailContainer: React.FC = () => { const DetailContainer: React.FC = () => {
const [tabPosition, setTabPosition] = useState(TabPosition.README); const [tabPosition, setTabPosition] = useState(TabPosition.README);
@@ -23,10 +24,12 @@ const DetailContainer: React.FC = () => {
); );
return ( return (
<Box component="div" display="flex" flexDirection="column" padding={2}> <Box component="div" display="flex" flexDirection="column">
<DetailContainerTabs onChangeTabPosition={handleChangeTabPosition} tabPosition={tabPosition} /> <DetailContainerTabs onChangeTabPosition={handleChangeTabPosition} tabPosition={tabPosition} />
<DetailContainerContent readDescription={readMe} tabPosition={tabPosition} /> <DetailTheme>
</Box> <DetailContainerContent readDescription={readMe} tabPosition={tabPosition} />
</DetailTheme>
</Box>
); );
}; };

View File

@@ -2,15 +2,18 @@ import React from 'react';
import { preventXSS } from '../../utils/sec-utils'; import { preventXSS } from '../../utils/sec-utils';
import Readme from '../Readme'; import Readme from '../Readme';
import { ReadmeSpacing } from './styles';
interface Props { interface Props {
description?: string; description?: string;
} }
const DetailContainerContentReadme: React.FC<Props> = ({ description }) => { const DetailContainerContentReadme: React.FC<Props> = ({ description }) => {
if (!description) return null; if (!description) {
return null;
}
const encodedReadme = preventXSS(description); const encodedReadme = preventXSS(description);
return <Readme description={encodedReadme} />; return <ReadmeSpacing><Readme description={encodedReadme} /></ReadmeSpacing>;
}; };
export default DetailContainerContentReadme; export default DetailContainerContentReadme;

View File

@@ -28,9 +28,9 @@ const DetailContainerTabs: React.FC<Props> = ({ tabPosition, onChangeTabPosition
return ( return (
<Tabs <Tabs
indicatorColor={'primary'} indicatorColor={'secondary'}
onChange={onChangeTabPosition} onChange={onChangeTabPosition}
textColor={'primary'} textColor={'secondary'}
value={tabPositionIndex} value={tabPositionIndex}
variant={'fullWidth'}> variant={'fullWidth'}>
<Tab data-testid={'readme-tab'} id={'readme-tab'} label={TabPosition.README} /> <Tab data-testid={'readme-tab'} id={'readme-tab'} label={TabPosition.README} />

View File

@@ -0,0 +1,11 @@
import styled from '@emotion/styled';
import { Theme } from '../../design-tokens/theme';
export const DetailTheme = styled('div')<{ theme?: Theme }>(props => ({
backgroundColor: props?.theme?.palette.readmeBackgroundColor,
}));
export const ReadmeSpacing = styled('div')<{ theme?: Theme }>(props => ({
padding: '20px',
}));

View File

@@ -15,7 +15,6 @@ interface Props {
const StyledHeading = styled(Heading)({ const StyledHeading = styled(Heading)({
fontSize: '1rem', fontSize: '1rem',
fontWeight: 700, fontWeight: 700,
textTransform: 'capitalize',
}); });
const StyledBoxVersion = styled(Box)<{ theme?: Theme }>(({ theme }) => ({ const StyledBoxVersion = styled(Box)<{ theme?: Theme }>(({ theme }) => ({

View File

@@ -18,7 +18,7 @@ describe('<Header /> component with logged in state', () => {
test('should load the component in logged out state', () => { test('should load the component in logged out state', () => {
const { container, queryByTestId, getByText } = render( const { container, queryByTestId, getByText } = render(
<Router> <Router>
<AppContextProvider packages={props.packages}> <AppContextProvider>
<Header /> <Header />
</AppContextProvider> </AppContextProvider>
</Router> </Router>
@@ -32,7 +32,7 @@ describe('<Header /> component with logged in state', () => {
test('should load the component in logged in state', () => { test('should load the component in logged in state', () => {
const { container, getByTestId, queryByText } = render( const { container, getByTestId, queryByText } = render(
<Router> <Router>
<AppContextProvider packages={props.packages} user={props.user}> <AppContextProvider user={props.user}>
<Header /> <Header />
</AppContextProvider> </AppContextProvider>
</Router> </Router>
@@ -46,7 +46,7 @@ describe('<Header /> component with logged in state', () => {
test('should open login dialog', async () => { test('should open login dialog', async () => {
const { getByText } = render( const { getByText } = render(
<Router> <Router>
<AppContextProvider packages={props.packages}> <AppContextProvider>
<Header /> <Header />
</AppContextProvider> </AppContextProvider>
</Router> </Router>
@@ -61,7 +61,7 @@ describe('<Header /> component with logged in state', () => {
test('should logout the user', async () => { test('should logout the user', async () => {
const { getByText, getByTestId } = render( const { getByText, getByTestId } = render(
<Router> <Router>
<AppContextProvider packages={props.packages} user={props.user}> <AppContextProvider user={props.user}>
<Header /> <Header />
</AppContextProvider> </AppContextProvider>
</Router> </Router>
@@ -79,7 +79,7 @@ describe('<Header /> component with logged in state', () => {
test("The question icon should open a new tab of verdaccio's website - installation doc", () => { test("The question icon should open a new tab of verdaccio's website - installation doc", () => {
const { getByTestId } = render( const { getByTestId } = render(
<Router> <Router>
<AppContextProvider packages={props.packages} user={props.user}> <AppContextProvider user={props.user}>
<Header /> <Header />
</AppContextProvider> </AppContextProvider>
</Router> </Router>
@@ -92,7 +92,7 @@ describe('<Header /> component with logged in state', () => {
test('should open the registrationInfo modal when clicking on the info icon', async () => { test('should open the registrationInfo modal when clicking on the info icon', async () => {
const { getByTestId } = render( const { getByTestId } = render(
<Router> <Router>
<AppContextProvider packages={props.packages} user={props.user}> <AppContextProvider user={props.user}>
<Header /> <Header />
</AppContextProvider> </AppContextProvider>
</Router> </Router>
@@ -109,7 +109,7 @@ describe('<Header /> component with logged in state', () => {
test('should close the registrationInfo modal when clicking on the button close', async () => { test('should close the registrationInfo modal when clicking on the button close', async () => {
const { getByTestId, getByText, queryByTestId } = render( const { getByTestId, getByText, queryByTestId } = render(
<Router> <Router>
<AppContextProvider packages={props.packages} user={props.user}> <AppContextProvider user={props.user}>
<Header /> <Header />
</AppContextProvider> </AppContextProvider>
</Router> </Router>

View File

@@ -8,7 +8,6 @@ import LoginDialog from './LoginDialog';
const appContextValue: AppContextProps = { const appContextValue: AppContextProps = {
scope: '', scope: '',
packages: [],
setUser: jest.fn(), setUser: jest.fn(),
}; };

View File

@@ -1,9 +1,10 @@
import React from 'react'; import React from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import logo from './img/logo.svg'; import logo from './img/verdaccio-blackwhite.svg';
export enum Size { export enum Size {
Tiny = '20px',
Small = '40px', Small = '40px',
Big = '90px', Big = '90px',
} }

View File

@@ -1 +0,0 @@
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="verdaccio"><Title>Verdaccio</Title><defs><path id="b" d="M48 17.6L32.8 48H24L.4.8h15.2l12.8 25.6 4.4-8.8H48z"/><filter x="-20%" y="-11.7%" width="139.9%" height="140.3%" filterUnits="objectBoundingBox" id="a"><feOffset dy="4" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="2.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0906646286 0" in="shadowBlurOuter1"/></filter><path id="d" d="M50.8 12H35.6L41.2.8h15.2L50.8 12z"/><filter x="-45.7%" y="-49.1%" width="191.3%" height="269.6%" filterUnits="objectBoundingBox" id="c"><feOffset dy="4" in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="2.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0906646286 0" in="shadowBlurOuter1"/></filter></defs><g fill="none" fill-rule="evenodd"><rect fill="#F7F8F6" width="100" height="100" rx="37"/><g transform="translate(22 29)"><use fill="#000" filter="url(#a)" xlink:href="#b"/><path stroke="#405236" stroke-width="2.4" d="M46.058 18.8H33.542L28.4 29.083 14.858 2H2.342l22.4 44.8h7.316l14-28z" stroke-linejoin="square" fill="#405236"/></g><g transform="translate(22 29)"><use fill="#000" filter="url(#c)" xlink:href="#d"/><path stroke="#CD4000" stroke-width="2.4" d="M50.058 10.8l4.4-8.8H41.942l-4.4 8.8h12.516z" stroke-linejoin="square" fill="#CD4000"/></g><path d="M54.06 75.8l2.575-5.112L36.857 31H24.342l22.4 44.8h7.319z" stroke="#405236" stroke-width="2.4" fill="#4A5E3F"/><path d="M59.6 31h15.221M55.6 35h15.221M51.6 39.8h15.221" stroke="#CD4000" stroke-width="2.4" stroke-linecap="square"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,31 @@
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg" id="verdaccio">
<Title>Verdaccio</Title>
<rect width="100" height="100" rx="37" fill="black" />
<g filter="url(#filter0_d)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M70 46.7288L54.6723 77H45.7983L22 30L37.3277 30L50.2353 55.4915L54.6723 46.7288H70Z" fill="white" fill-opacity="0.6" />
</g>
<g filter="url(#filter1_d)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M67.621 41H72.4L78 30H75.621H62.8H58V32.3571H61.6L60.8 33.9286H54V36.2857H59.6L58.4 38.6429H50V41H57.2H67.621Z" fill="white" />
</g>
<path fill-rule="evenodd" clip-rule="evenodd" d="M54.785 77H45.8804L22 30H37.3806L58 70.7175L54.785 77Z" fill="white" />
<defs>
<filter id="filter0_d" x="17" y="29" width="58" height="57" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" />
<feOffset dy="4" />
<feGaussianBlur stdDeviation="2.5" />
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0906646 0" />
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow" />
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape" />
</filter>
<filter id="filter1_d" x="45" y="29" width="38" height="21" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" />
<feOffset dy="4" />
<feGaussianBlur stdDeviation="2.5" />
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0906646 0" />
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow" />
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape" />
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,32 @@
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="verdaccio">
<Title>Verdaccio</Title>
<defs>
<path id="b" d="M48 17.6L32.8 48H24L.4.8h15.2l12.8 25.6 4.4-8.8H48z" />
<filter x="-20%" y="-11.7%" width="139.9%" height="140.3%" filterUnits="objectBoundingBox" id="a">
<feOffset dy="4" in="SourceAlpha" result="shadowOffsetOuter1" />
<feGaussianBlur stdDeviation="2.5" in="shadowOffsetOuter1" result="shadowBlurOuter1" />
<feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1" />
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0906646286 0" in="shadowBlurOuter1" />
</filter>
<path id="d" d="M50.8 12H35.6L41.2.8h15.2L50.8 12z" />
<filter x="-45.7%" y="-49.1%" width="191.3%" height="269.6%" filterUnits="objectBoundingBox" id="c">
<feOffset dy="4" in="SourceAlpha" result="shadowOffsetOuter1" />
<feGaussianBlur stdDeviation="2.5" in="shadowOffsetOuter1" result="shadowBlurOuter1" />
<feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1" />
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.0906646286 0" in="shadowBlurOuter1" />
</filter>
</defs>
<g fill="none" fill-rule="evenodd">
<rect fill="#F7F8F6" width="100" height="100" rx="37" />
<g transform="translate(22 29)">
<use fill="#000" filter="url(#a)" xlink:href="#b" />
<path stroke="#405236" stroke-width="2.4" d="M46.058 18.8H33.542L28.4 29.083 14.858 2H2.342l22.4 44.8h7.316l14-28z" stroke-linejoin="square" fill="#405236" />
</g>
<g transform="translate(22 29)">
<use fill="#000" filter="url(#c)" xlink:href="#d" />
<path stroke="#CD4000" stroke-width="2.4" d="M50.058 10.8l4.4-8.8H41.942l-4.4 8.8h12.516z" stroke-linejoin="square" fill="#CD4000" />
</g>
<path d="M54.06 75.8l2.575-5.112L36.857 31H24.342l22.4 44.8h7.319z" stroke="#405236" stroke-width="2.4" fill="#4A5E3F" />
<path d="M59.6 31h15.221M55.6 35h15.221M51.6 39.8h15.221" stroke="#CD4000" stroke-width="2.4" stroke-linecap="square" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -71,7 +71,7 @@ export const PackageTitle = styled('span')<{ theme?: Theme }>(({ theme }) => ({
fontSize: 20, fontSize: 20,
display: 'block', display: 'block',
marginBottom: 12, marginBottom: 12,
color: theme && theme.palette.eclipse, color: theme?.palette?.eclipse,
cursor: 'pointer', cursor: 'pointer',
':hover': { ':hover': {
color: theme && theme.palette.black, color: theme && theme.palette.black,
@@ -117,7 +117,7 @@ export const PackageListItemText = styled(ListItemText)({
}); });
export const Description = styled(Typography)<{ theme?: Theme }>(props => ({ export const Description = styled(Typography)<{ theme?: Theme }>(props => ({
color: props.theme && props.theme.palette.greyDark2, color: props?.theme?.palette.greyDark2,
fontSize: '14px', fontSize: '14px',
paddingRight: 0, paddingRight: 0,
})); }));

View File

@@ -1,33 +1,24 @@
import createMuiTheme from '@material-ui/core/styles/createMuiTheme'; import createMuiTheme from '@material-ui/core/styles/createMuiTheme';
// Main colors import defaultTheme from './themes/default';
// ------------------------- import darkTheme from './themes/dark';
const colors = { import { ColorsTheme } from './types';
black: '#000',
white: '#fff',
red: '#d32f2f',
orange: '#CD4000',
greySuperLight: '#f5f5f5',
greyLight: '#d3d3d3',
greyLight2: '#908ba1',
greyLight3: '#f3f4f240',
greyDark: '#a9a9a9',
greyDark2: '#586069',
greyChateau: '#95989a',
greyGainsboro: '#e3e3e3',
greyAthens: '#d3dddd',
eclipse: '#3c3c3c',
paleNavy: '#e4e8f1',
saltpan: '#f7f8f6',
snow: '#f9f9f9',
love: '#e25555',
nobel01: '#999999',
nobel02: '#9f9f9f',
primary: window.VERDACCIO_PRIMARY_COLOR || '#4b5e40',
secondary: '#20232a',
};
export type Colors = keyof typeof colors; function getThemeColors() {
// eslint-disable-next-line no-constant-condition
if (false) {
return defaultTheme;
} else {
return darkTheme;
}
}
export type Colors = ColorsTheme;
const padding = {
light: '16px',
regular: '24px',
};
const fontSize = { const fontSize = {
xxl: 26, xxl: 26,
@@ -72,10 +63,10 @@ export const theme = createMuiTheme({
fontFamily: 'inherit', fontFamily: 'inherit',
}, },
palette: { palette: {
...colors, ...getThemeColors(),
primary: { main: colors.primary }, primary: { main: getThemeColors().primary },
secondary: { main: colors.secondary }, secondary: { main: getThemeColors().secondary },
error: { main: colors.red }, error: { main: getThemeColors().red },
}, },
...customizedTheme, ...customizedTheme,
}); });

View File

@@ -0,0 +1,30 @@
const colors = {
black: '#000',
white: '#fff',
red: '#d32f2f',
orange: '#CD4000',
greySuperLight: '#f5f5f5',
greyLight: '#d3d3d3',
greyLight2: '#908ba1',
greyLight3: '#f3f4f240',
greyDark: '#a9a9a9',
greyDark2: '#fff',
greyChateau: '#95989a',
greyGainsboro: '#e3e3e3',
greyAthens: '#d3dddd',
eclipse: '#fff',
paleNavy: '#e4e8f1',
saltpan: '#f7f8f6',
snow: '#f9f9f9',
love: '#e25555',
nobel01: '#999999',
nobel02: '#9f9f9f',
primary: '#000000',
secondary: '#ffffff',
// colors based on features
backgroundBody: '#000',
lightBackgroundColor: '#fff',
readmeBackgroundColor: '#fff',
};
export default colors;

View File

@@ -0,0 +1,28 @@
const colors = {
black: '#000',
white: '#fff',
red: '#d32f2f',
orange: '#CD4000',
greySuperLight: '#f5f5f5',
greyLight: '#d3d3d3',
greyLight2: '#908ba1',
greyLight3: '#f3f4f240',
greyDark: '#a9a9a9',
greyDark2: '#586069',
greyChateau: '#95989a',
greyGainsboro: '#e3e3e3',
greyAthens: '#d3dddd',
eclipse: '#3c3c3c',
paleNavy: '#e4e8f1',
saltpan: '#f7f8f6',
snow: '#f9f9f9',
love: '#e25555',
nobel01: '#999999',
nobel02: '#9f9f9f',
primary: window.VERDACCIO_PRIMARY_COLOR || '#4b5e40',
secondary: '#20232a',
// colors based on features
backgroundBody: '#fff',
};
export default colors;

View File

@@ -0,0 +1,3 @@
export interface ColorsTheme {
[key: string]: string;
}

View File

@@ -1,13 +1,10 @@
import React, { forwardRef } from 'react'; import React, { forwardRef } from 'react';
import { default as MaterialUITypography, TypographyProps } from '@material-ui/core/Typography'; import { default as MaterialUITypography } from '@material-ui/core/Typography';
import { TextProps } from './TextConfig';
type TextType = 'subtitle1' | 'subtitle2' | 'body1' | 'body2';
type TextRef = HTMLElementTagNameMap[keyof HTMLElementTagNameMap]; type TextRef = HTMLElementTagNameMap[keyof HTMLElementTagNameMap];
export interface TextProps extends Omit<TypographyProps, 'variant'> {
variant?: TextType;
}
// The reference is already from type of the Component, so the any below is not a problem // The reference is already from type of the Component, so the any below is not a problem
const Text = forwardRef<TextRef, TextProps>(function Text(props, ref) { const Text = forwardRef<TextRef, TextProps>(function Text(props, ref) {
return <MaterialUITypography {...props} ref={ref} />; return <MaterialUITypography {...props} ref={ref} />;

View File

@@ -0,0 +1,7 @@
import { TypographyProps } from '@material-ui/core/Typography';
type TextType = 'subtitle1' | 'subtitle2' | 'body1' | 'body2';
export interface TextProps extends Omit<TypographyProps, 'variant'> {
variant?: TextType;
}

View File

@@ -1 +1,2 @@
export { default, TextProps } from './Text'; export { default } from './Text';
export { TextProps } from './TextConfig';

View File

@@ -1,24 +1,6 @@
import { createContext, Consumer, Provider } from 'react'; import { createContext, Consumer, Provider } from 'react';
import { PackageMetaInterface } from '../../../types/packageMeta'; import { DetailContextProps, VersionPageConsumerProps } from './version-config';
export interface DetailContextProps {
packageMeta: PackageMetaInterface;
packageVersion?: string;
readMe: string;
packageName: string;
enableLoading: () => void;
isLoading: boolean;
hasNotBeenFound: boolean;
}
export interface VersionPageConsumerProps {
packageMeta: PackageMetaInterface;
readMe: string;
packageName: string;
packageVersion?: string;
// FIXME: looking for the appropiated type here
enableLoading: any;
}
export const DetailContext = createContext<Partial<DetailContextProps>>({}); export const DetailContext = createContext<Partial<DetailContextProps>>({});

View File

@@ -1,8 +1,4 @@
export { export { DetailContext, DetailContextConsumer, DetailContextProvider } from './context';
DetailContext, export { VersionPageConsumerProps, DetailContextProps } from './version-config';
DetailContextConsumer,
DetailContextProvider,
DetailContextProps,
VersionPageConsumerProps,
} from './context';
export { default } from './Version'; export { default } from './Version';

View File

@@ -0,0 +1,19 @@
import { PackageMetaInterface } from '../../../types/packageMeta';
export interface DetailContextProps {
enableLoading: () => void;
hasNotBeenFound: boolean;
isLoading: boolean;
packageMeta: PackageMetaInterface;
packageName: string;
packageVersion?: string;
readMe: string;
}
export interface VersionPageConsumerProps {
enableLoading: () => void;
packageMeta: PackageMetaInterface;
packageName: string;
packageVersion?: string;
readMe: string;
}

View File

@@ -1,17 +1,35 @@
import React from 'react'; import React, { useEffect, useState } from 'react';
import { PackageList } from '../../components/PackageList'; import { PackageList } from '../../components/PackageList';
import { PackageInterface } from '../../components/Package/Package'; import API from '../../utils/api';
import Loading from '../../components/Loading';
interface Props { interface Props {
isUserLoggedIn: boolean; isUserLoggedIn: boolean;
packages: PackageInterface[];
} }
const Home: React.FC<Props> = ({ packages }) => ( const Home: React.FC<Props> = ({ isUserLoggedIn }) => {
<div className="container content"> const [packages, setPackages] = useState([]);
<PackageList packages={packages} /> const [isLoading, setIsLoading] = useState(true);
</div> const loadPackages = async () => {
); try {
const packages = await API.request('packages', 'GET');
// FIXME add correct type for package
setPackages(packages as never[]);
} catch (error) {
// FIXME: add dialog
console.error({
title: 'Warning',
message: `Unable to load package list: ${error.message}`,
});
}
setIsLoading(false);
};
useEffect(() => {
loadPackages().then();
}, [isUserLoggedIn]);
return <div className="container content">{isLoading ? <Loading /> : <PackageList packages={packages} />}</div>;
};
export default Home; export default Home;

View File

@@ -20,7 +20,7 @@ export function handleResponseType(response: Response): Promise<[boolean, Blob |
return Promise.all([response.ok, response.text()]); return Promise.all([response.ok, response.text()]);
} }
// unfortunatelly on download files there is no header available // unfortunately on download files there is no header available
if (response.url && response.url.endsWith('.tgz') === true) { if (response.url && response.url.endsWith('.tgz') === true) {
return Promise.all([response.ok, response.blob()]); return Promise.all([response.ok, response.blob()]);
} }

View File

@@ -17,14 +17,18 @@ describe('utils', () => {
expect(isEmail('')).toBeFalsy(); expect(isEmail('')).toBeFalsy();
}); });
test('getRegistryURL() - should keep slash if location is a sub directory', () => { test('getRegistryURL() - should not change when location change', () => {
expect(getRegistryURL()).toBe('http://localhost');
history.pushState({}, 'page title', '/-/web/detail'); history.pushState({}, 'page title', '/-/web/detail');
expect(getRegistryURL()).toBe('http://localhost/-/web/detail'); expect(getRegistryURL()).toBe('http://localhost');
history.pushState({}, 'page title', '/'); history.pushState({}, 'page title', '/');
}); });
test('getRegistryURL() - should not add slash if location is not a sub directory', () => { test('getRegistryURL() - should change when UI options change', () => {
expect(getRegistryURL()).toBe('http://localhost'); expect(getRegistryURL()).toBe('http://localhost');
window.__VERDACCIO_BASENAME_UI_OPTIONS.base = 'http://localhost/test';
expect(getRegistryURL()).toBe('http://localhost/test');
window.__VERDACCIO_BASENAME_UI_OPTIONS.base = 'http://localhost';
}); });
}); });

View File

@@ -2,6 +2,8 @@ import isURLValidator from 'validator/lib/isURL';
import isEmailValidator from 'validator/lib/isEmail'; import isEmailValidator from 'validator/lib/isEmail';
import '../../types'; import '../../types';
const OCTET_STREAM_TYPE = 'application/octet-stream';
export function isURL(url: string): boolean { export function isURL(url: string): boolean {
return isURLValidator(url || '', { return isURLValidator(url || '', {
protocols: ['http', 'https', 'git+https'], protocols: ['http', 'https', 'git+https'],
@@ -15,8 +17,7 @@ export function isEmail(email: string): boolean {
} }
export function getRegistryURL(): string { export function getRegistryURL(): string {
// Don't add slash if it's not a sub directory return window.__VERDACCIO_BASENAME_UI_OPTIONS.base;
return `${location.origin}${location.pathname === '/' ? '' : location.pathname}`;
} }
export function extractFileName(url: string): string { export function extractFileName(url: string): string {
@@ -38,9 +39,9 @@ export function downloadFile(fileStream: Blob, fileName: string): void {
// @ts-ignore. Please see: https://github.com/microsoft/TypeScript/issues/33792 // @ts-ignore. Please see: https://github.com/microsoft/TypeScript/issues/33792
if (navigator.msSaveBlob) { if (navigator.msSaveBlob) {
// Detect if Edge // Detect if Edge
file = blobToFile(new Blob([fileStream], { type: 'application/octet-stream' }), fileName); file = blobToFile(new Blob([fileStream], { type: OCTET_STREAM_TYPE }), fileName);
} else { } else {
file = new File([fileStream], fileName, { type: 'application/octet-stream', lastModified: Date.now() }); file = new File([fileStream], fileName, { type: OCTET_STREAM_TYPE, lastModified: Date.now() });
} }
const objectURL = URL.createObjectURL(file); const objectURL = URL.createObjectURL(file);

View File

@@ -10,10 +10,10 @@ auth:
users: users:
foo: foo:
name: test name: test
password: test password: test #pragma: allowlist secret
bar: bar:
name: bar name: bar
password: test password: test #pragma: allowlist secret
security: security:
api: api:
jwt: jwt:
@@ -23,7 +23,7 @@ security:
web: web:
sign: sign:
expiresIn: 100d expiresIn: 100d
notBefore: 1 notBefore: 0
uplinks: uplinks:
npmjs: npmjs:

View File

@@ -37,7 +37,7 @@ export default {
}), }),
new HTMLWebpackPlugin({ new HTMLWebpackPlugin({
__UI_OPTIONS: JSON.stringify({ __UI_OPTIONS: JSON.stringify({
base: '/', base: new URL('/', 'https://localhost:4872'),
}), }),
title: 'Verdaccio Dev UI', title: 'Verdaccio Dev UI',
scope: '', scope: '',

3236
yarn.lock

File diff suppressed because it is too large Load Diff