forked from sombochea/verdaccio-ui
Compare commits
41 Commits
v0.3.5
...
refactor/m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c9076d0a2 | ||
|
|
ea19a2bb47 | ||
|
|
042571e72f | ||
|
|
dd6ba2cbe9 | ||
|
|
bf613231f4 | ||
|
|
7074eddf27 | ||
|
|
d3ddd439d1 | ||
|
|
26724bb20e | ||
|
|
cba41ceead | ||
|
|
2688b59f5b | ||
|
|
d9f463688d | ||
|
|
4d285dbb00 | ||
|
|
739333b1f1 | ||
|
|
5809a9f7cb | ||
|
|
e1c5e30b4c | ||
|
|
5a3ea02449 | ||
|
|
535d8f9c85 | ||
|
|
8a46678698 | ||
|
|
3265ed561d | ||
|
|
3a6c6f7fb9 | ||
|
|
09fe1db850 | ||
|
|
f265b6ba33 | ||
|
|
185b2016d3 | ||
|
|
3751acef1c | ||
|
|
50fa39f7d6 | ||
|
|
cd2e36513e | ||
|
|
b20fe3f44a | ||
|
|
be30cbdd14 | ||
|
|
c6e3fd0b92 | ||
|
|
f27254ca6b | ||
|
|
571d9c3fa7 | ||
|
|
f4dd8b01b4 | ||
|
|
a94485e614 | ||
|
|
ce4b13d3b5 | ||
|
|
fcd471ef6f | ||
|
|
9915fb6193 | ||
|
|
886684817b | ||
|
|
76d11d4674 | ||
|
|
322197dc70 | ||
|
|
d2e9d68c6d | ||
|
|
f1971edf6d |
@@ -2,6 +2,8 @@
|
||||
|
||||
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.6](https://github.com/verdaccio/ui/compare/v0.3.5...v0.3.6) (2019-11-08)
|
||||
|
||||
### [0.3.5](https://github.com/verdaccio/ui/compare/v0.3.4...v0.3.5) (2019-11-07)
|
||||
|
||||
|
||||
|
||||
68
package.json
68
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@verdaccio/ui-theme",
|
||||
"version": "0.3.5",
|
||||
"version": "0.3.6",
|
||||
"description": "Verdaccio User Interface",
|
||||
"author": {
|
||||
"name": "Verdaccio Core Team",
|
||||
@@ -15,28 +15,28 @@
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "8.2.0",
|
||||
"@commitlint/config-conventional": "8.2.0",
|
||||
"@material-ui/core": "4.6.0",
|
||||
"@material-ui/core": "4.6.1",
|
||||
"@material-ui/icons": "4.5.1",
|
||||
"@octokit/rest": "16.34.0",
|
||||
"@testing-library/react": "9.3.0",
|
||||
"@octokit/rest": "16.35.0",
|
||||
"@testing-library/react": "9.3.2",
|
||||
"@types/autosuggest-highlight": "3.1.0",
|
||||
"@types/enzyme": "3.10.3",
|
||||
"@types/jest": "24.0.20",
|
||||
"@types/jest": "24.0.23",
|
||||
"@types/js-base64": "2.3.1",
|
||||
"@types/lodash": "4.14.144",
|
||||
"@types/node": "12.11.7",
|
||||
"@types/lodash": "4.14.147",
|
||||
"@types/node": "12.12.7",
|
||||
"@types/react": "16.9.11",
|
||||
"@types/react-autosuggest": "9.3.13",
|
||||
"@types/react-dom": "16.9.3",
|
||||
"@types/react-router-dom": "5.1.0",
|
||||
"@types/react-dom": "16.9.4",
|
||||
"@types/react-router-dom": "5.1.2",
|
||||
"@types/request": "2.48.3",
|
||||
"@types/validator": "10.11.3",
|
||||
"@types/webpack-env": "1.14.1",
|
||||
"@typescript-eslint/parser": "2.5.0",
|
||||
"@typescript-eslint/parser": "2.7.0",
|
||||
"@verdaccio/babel-preset": "8.2.0",
|
||||
"@verdaccio/commons-api": "8.2.0",
|
||||
"@verdaccio/commons-api": "8.3.0",
|
||||
"@verdaccio/eslint-config": "8.2.0",
|
||||
"@verdaccio/types": "8.1.0",
|
||||
"@verdaccio/types": "8.3.0",
|
||||
"autosuggest-highlight": "3.1.1",
|
||||
"babel-loader": "8.0.6",
|
||||
"bundlesize": "0.18.0",
|
||||
@@ -45,9 +45,9 @@
|
||||
"concurrently": "5.0.0",
|
||||
"cross-env": "6.0.3",
|
||||
"css-loader": "3.2.0",
|
||||
"date-fns": "2.6.0",
|
||||
"detect-secrets": "1.0.4",
|
||||
"emotion": "9.2.12",
|
||||
"date-fns": "2.7.0",
|
||||
"detect-secrets": "1.0.5",
|
||||
"emotion": "10.0.23",
|
||||
"enzyme": "3.10.0",
|
||||
"enzyme-adapter-react-16": "1.15.1",
|
||||
"enzyme-to-json": "3.4.3",
|
||||
@@ -57,7 +57,7 @@
|
||||
"eslint-plugin-jsx-a11y": "6.2.3",
|
||||
"eslint-plugin-prettier": "3.1.1",
|
||||
"eslint-plugin-react": "7.16.0",
|
||||
"eslint-plugin-react-hooks": "2.2.0",
|
||||
"eslint-plugin-react-hooks": "2.3.0",
|
||||
"eslint-plugin-verdaccio": "8.2.0",
|
||||
"file-loader": "4.2.0",
|
||||
"friendly-errors-webpack-plugin": "1.7.0",
|
||||
@@ -75,26 +75,25 @@
|
||||
"jest-fetch-mock": "2.1.2",
|
||||
"js-base64": "2.5.1",
|
||||
"js-yaml": "3.13.1",
|
||||
"lint-staged": "8.2.1",
|
||||
"lint-staged": "9.4.3",
|
||||
"localstorage-memory": "1.0.3",
|
||||
"lockfile-lint": "2.1.6",
|
||||
"lockfile-lint": "2.2.0",
|
||||
"lodash": "^4.17.15",
|
||||
"mini-css-extract-plugin": "0.8.0",
|
||||
"node-mocks-http": "1.8.0",
|
||||
"normalize.css": "8.0.1",
|
||||
"optimize-css-assets-webpack-plugin": "5.0.3",
|
||||
"ora": "4.0.2",
|
||||
"prettier": "1.18.2",
|
||||
"ora": "4.0.3",
|
||||
"prettier": "1.19.1",
|
||||
"prop-types": "15.7.2",
|
||||
"puppeteer": "1.8.0",
|
||||
"react": "16.11.0",
|
||||
"puppeteer": "2.0.0",
|
||||
"react": "16.12.0",
|
||||
"react-autosuggest": "9.4.3",
|
||||
"react-dom": "16.11.0",
|
||||
"react-emotion": "9.2.12",
|
||||
"react-hot-loader": "4.12.15",
|
||||
"react-dom": "16.12.0",
|
||||
"react-hot-loader": "4.12.17",
|
||||
"react-router-dom": "5.1.2",
|
||||
"request": "2.88.0",
|
||||
"resolve-url-loader": "3.1.0",
|
||||
"resolve-url-loader": "3.1.1",
|
||||
"rimraf": "3.0.0",
|
||||
"source-map-loader": "0.2.4",
|
||||
"standard-version": "7.0.0",
|
||||
@@ -103,21 +102,21 @@
|
||||
"stylelint-config-recommended": "3.0.0",
|
||||
"stylelint-config-styled-components": "0.1.1",
|
||||
"stylelint-processor-styled-components": "1.8.0",
|
||||
"stylelint-webpack-plugin": "1.0.3",
|
||||
"stylelint-webpack-plugin": "1.0.4",
|
||||
"supertest": "4.0.2",
|
||||
"typeface-roboto": "0.0.75",
|
||||
"typescript": "3.7.1-rc",
|
||||
"typescript": "3.7.2",
|
||||
"uglifyjs-webpack-plugin": "2.2.0",
|
||||
"url-loader": "2.2.0",
|
||||
"validator": "11.1.0",
|
||||
"validator": "12.0.0",
|
||||
"verdaccio": "4.3.4",
|
||||
"verdaccio-auth-memory": "8.2.0",
|
||||
"verdaccio-memory": "8.2.0",
|
||||
"verdaccio-auth-memory": "8.3.0",
|
||||
"verdaccio-memory": "8.3.0",
|
||||
"wait-on": "3.3.0",
|
||||
"webpack": "4.41.2",
|
||||
"webpack-bundle-analyzer": "3.6.0",
|
||||
"webpack-bundle-size-analyzer": "3.1.0",
|
||||
"webpack-cli": "3.3.9",
|
||||
"webpack-cli": "3.3.10",
|
||||
"webpack-dev-server": "3.9.0",
|
||||
"webpack-merge": "4.2.2",
|
||||
"whatwg-fetch": "3.0.0",
|
||||
@@ -214,5 +213,10 @@
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/verdaccio",
|
||||
"logo": "https://opencollective.com/verdaccio/logo.txt"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/core": "10.0.22",
|
||||
"@emotion/styled": "10.0.23",
|
||||
"@material-ui/lab": "4.0.0-alpha.31"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import React, { Component, ReactElement } from 'react';
|
||||
import isNil from 'lodash/isNil';
|
||||
import 'normalize.css';
|
||||
import 'typeface-roboto/index.css';
|
||||
|
||||
import storage from '../utils/storage';
|
||||
import { makeLogin, isTokenExpire } from '../utils/login';
|
||||
@@ -10,8 +8,8 @@ import LoginModal from '../components/Login';
|
||||
import Header from '../components/Header';
|
||||
import { Container, Content } from '../components/Layout';
|
||||
import API from '../utils/api';
|
||||
import '../utils/styles/global';
|
||||
import Footer from '../components/Footer';
|
||||
import StyleBaseline from '../design-tokens/StyleBaseline';
|
||||
|
||||
import AppRoute from './AppRoute';
|
||||
import { AppProps, AppContextProvider } from './AppContext';
|
||||
@@ -46,10 +44,13 @@ export default class App extends Component<{}, AppProps> {
|
||||
const context = { isUserLoggedIn, packages, logoUrl, user, scope };
|
||||
|
||||
return (
|
||||
<Container isLoading={isLoading}>
|
||||
{isLoading ? <Loading /> : <AppContextProvider value={context}>{this.renderContent()}</AppContextProvider>}
|
||||
{this.renderLoginModal()}
|
||||
</Container>
|
||||
<>
|
||||
<StyleBaseline />
|
||||
<Container isLoading={isLoading}>
|
||||
{isLoading ? <Loading /> : <AppContextProvider value={context}>{this.renderContent()}</AppContextProvider>}
|
||||
{this.renderLoginModal()}
|
||||
</Container>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import colors from '../../utils/styles/colors';
|
||||
import ListItem from '../../muiComponents/ListItem';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { fontWeight } from '../../utils/styles/sizes';
|
||||
import ListItem from '../../muiComponents/ListItem';
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React, { KeyboardEvent } from 'react';
|
||||
import { css } from 'emotion';
|
||||
import Autosuggest, { SuggestionSelectedEventData, InputProps, ChangeEvent } from 'react-autosuggest';
|
||||
import match from 'autosuggest-highlight/match';
|
||||
import parse from 'autosuggest-highlight/parse';
|
||||
@@ -140,12 +139,7 @@ const AutoComplete = ({
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<Autosuggest
|
||||
{...autosuggestProps}
|
||||
inputProps={inputProps}
|
||||
onSuggestionSelected={onClick}
|
||||
renderSuggestionsContainer={renderSuggestionsContainer}
|
||||
/>
|
||||
<Autosuggest {...autosuggestProps} inputProps={inputProps} onSuggestionSelected={onClick} renderSuggestionsContainer={renderSuggestionsContainer} />
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import styled, { css } from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
import { css } from '@emotion/core';
|
||||
|
||||
import TextField from '../../muiComponents/TextField';
|
||||
import Paper from '../../muiComponents/Paper';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import IconButton from '../../muiComponents/IconButton';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { fontWeight } from '../../utils/styles/sizes';
|
||||
import Text from '../../muiComponents/Text';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { ChangeEvent, useState, useEffect } from 'react';
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { default as MuiTabs } from '../../muiComponents/Tabs';
|
||||
import Tab from '../../muiComponents/Tab';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import ListItem from '../../muiComponents/ListItem';
|
||||
import ListItemText from '../../muiComponents/ListItemText';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import colors from '../../utils/styles/colors';
|
||||
import { fontWeight } from '../../utils/styles/sizes';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import colors from '../../utils/styles/colors';
|
||||
import { fontWeight } from '../../utils/styles/sizes';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { fontWeight } from '../../utils/styles/sizes';
|
||||
import ListItem from '../../muiComponents/ListItem';
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<Footer /> component should load the initial state of Footer component 1`] = `"<div class=\\"css-i0nj2g ezbsl480\\"><div class=\\"css-hzfs9b ezbsl481\\"><div class=\\"css-d8nsp7 ezbsl482\\"> Made with<span class=\\"css-1so4oe0 ezbsl487\\">♥</span>on<span class=\\"css-1ie354y ezbsl484\\"><svg class=\\"ezbsl485 css-tsfgle ek145dl0\\"><title>Earth</title><use xlink:href=\\"[object Object]#earth\\"></use></svg><span class=\\"css-8631ip ezbsl486\\"><svg class=\\"ezbsl488 css-13b76ay ek145dl0\\"><title>Spain</title><use xlink:href=\\"[object Object]#spain\\"></use></svg><svg class=\\"ezbsl488 css-13b76ay ek145dl0\\"><title>Nicaragua</title><use xlink:href=\\"[object Object]#nicaragua\\"></use></svg><svg class=\\"ezbsl488 css-13b76ay ek145dl0\\"><title>India</title><use xlink:href=\\"[object Object]#india\\"></use></svg><svg class=\\"ezbsl488 css-13b76ay ek145dl0\\"><title>Brazil</title><use xlink:href=\\"[object Object]#brazil\\"></use></svg><svg class=\\"ezbsl488 css-13b76ay ek145dl0\\"><title>China</title><use xlink:href=\\"[object Object]#china\\"></use></svg><svg class=\\"ezbsl488 css-13b76ay ek145dl0\\"><title>Austria</title><use xlink:href=\\"[object Object]#austria\\"></use></svg></span></span></div><div class=\\"css-1wbzdyy ezbsl483\\">Powered by<span class=\\"ezbsl488 css-i15wza ek145dl1\\" name=\\"verdaccio\\" title=\\"Verdaccio\\"><img alt=\\"Verdaccio\\" src=\\"[object Object]\\" class=\\"css-1ncdhax ek145dl2\\"></span>/ v.1.0.0</div></div></div>"`;
|
||||
exports[`<Footer /> component should load the initial state of Footer component 1`] = `"<div class=\\"css-i0nj2g ezbsl480\\"><div class=\\"css-hzfs9b ezbsl481\\"><div class=\\"css-d8nsp7 ezbsl482\\"> Made with<span class=\\"css-1so4oe0 ezbsl487\\">♥</span>on<span class=\\"css-1ie354y ezbsl484\\"><svg class=\\"ezbsl485 css-151fgib ek145dl0\\"><title>Earth</title><use xlink:href=\\"[object Object]#earth\\"></use></svg><span class=\\"css-8631ip ezbsl486\\"><svg class=\\"ezbsl488 css-1ah96gu ek145dl0\\"><title>Spain</title><use xlink:href=\\"[object Object]#spain\\"></use></svg><svg class=\\"ezbsl488 css-1ah96gu ek145dl0\\"><title>Nicaragua</title><use xlink:href=\\"[object Object]#nicaragua\\"></use></svg><svg class=\\"ezbsl488 css-1ah96gu ek145dl0\\"><title>India</title><use xlink:href=\\"[object Object]#india\\"></use></svg><svg class=\\"ezbsl488 css-1ah96gu ek145dl0\\"><title>Brazil</title><use xlink:href=\\"[object Object]#brazil\\"></use></svg><svg class=\\"ezbsl488 css-1ah96gu ek145dl0\\"><title>China</title><use xlink:href=\\"[object Object]#china\\"></use></svg><svg class=\\"ezbsl488 css-1ah96gu ek145dl0\\"><title>Austria</title><use xlink:href=\\"[object Object]#austria\\"></use></svg></span></span></div><div class=\\"css-1wbzdyy ezbsl483\\">Powered by<span class=\\"ezbsl488 css-ommwhu ek145dl1\\" name=\\"verdaccio\\" title=\\"Verdaccio\\"><img alt=\\"Verdaccio\\" src=\\"[object Object]\\" class=\\"css-1ncdhax ek145dl2\\"></span>/ v.1.0.0</div></div></div>"`;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import styled, { css } from 'react-emotion';
|
||||
import { css } from '@emotion/core';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import mq from '../../utils/styles/media';
|
||||
import Icon from '../Icon/Icon';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import styled, { css } from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
import { css } from '@emotion/core';
|
||||
|
||||
import colors from '../../utils/styles/colors';
|
||||
import mq from '../../utils/styles/media';
|
||||
@@ -48,7 +49,7 @@ export const IconSearchButton = styled(IconButton)({
|
||||
});
|
||||
|
||||
export const SearchWrapper = styled('div')({
|
||||
display: 'none',
|
||||
// display: 'none',
|
||||
maxWidth: '393px',
|
||||
width: '100%',
|
||||
});
|
||||
|
||||
@@ -10,6 +10,9 @@ import Text from '../../muiComponents/Text';
|
||||
|
||||
import { CardStyled as Card, HelpTitle } from './styles';
|
||||
|
||||
export const HELP_TITLE = 'No Package Published Yet.';
|
||||
export const COMPONENT_HELP_ID = 'help-card__title';
|
||||
|
||||
function renderHeadingClipboardSegments(title: string, text: string): React.ReactNode {
|
||||
return (
|
||||
<Fragment>
|
||||
@@ -25,8 +28,8 @@ const Help: React.FC = () => {
|
||||
return (
|
||||
<Card id="help-card">
|
||||
<CardContent>
|
||||
<Typography component="h2" gutterBottom={true} id="help-card__title" variant="h5">
|
||||
{'No Package Published Yet.'}
|
||||
<Typography component="h2" gutterBottom={true} id={COMPONENT_HELP_ID} variant="h5">
|
||||
{HELP_TITLE}
|
||||
</Typography>
|
||||
<HelpTitle color="textSecondary" gutterBottom={true}>
|
||||
{'To publish your first package just:'}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { default as Typography } from '../../muiComponents/Heading';
|
||||
import Card from '../../muiComponents/Card';
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<Icon /> component should render the component in default state 1`] = `"<svg class=\\"css-snirlv ek145dl0\\"><title>Austria</title><use xlink:href=\\"[object Object]#austria\\"></use></svg>"`;
|
||||
exports[`<Icon /> component should render the component in default state 1`] = `"<svg class=\\"css-j2zgvv ek145dl0\\"><title>Austria</title><use xlink:href=\\"[object Object]#austria\\"></use></svg>"`;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import styled, { css } from 'react-emotion';
|
||||
import { css } from '@emotion/core';
|
||||
import styled from '@emotion/styled';
|
||||
import { Breakpoint } from '@material-ui/core/styles/createBreakpoints';
|
||||
import { StyledOtherComponent } from 'create-emotion-styled';
|
||||
import { DetailedHTMLProps, HTMLAttributes } from 'react';
|
||||
|
||||
const getSize = (size: Breakpoint): string => {
|
||||
@@ -18,7 +18,7 @@ const getSize = (size: Breakpoint): string => {
|
||||
}
|
||||
};
|
||||
|
||||
const commonStyle = ({ size = 'sm' as Breakpoint, pointer, modifiers = null }): string => css`
|
||||
const commonStyle = ({ size = 'sm' as Breakpoint, pointer, modifiers = null }) => css`
|
||||
&& {
|
||||
display: inline-block;
|
||||
cursor: ${pointer ? 'pointer' : 'Developers'};
|
||||
@@ -28,24 +28,13 @@ const commonStyle = ({ size = 'sm' as Breakpoint, pointer, modifiers = null }):
|
||||
`;
|
||||
|
||||
export const Svg = styled('svg')`
|
||||
&& {
|
||||
${commonStyle};
|
||||
}
|
||||
${commonStyle};
|
||||
box-sizing: initial;
|
||||
`;
|
||||
|
||||
export const ImgWrapper: StyledOtherComponent<
|
||||
{
|
||||
size?: Breakpoint;
|
||||
pointer: boolean;
|
||||
modifiers?: null | undefined;
|
||||
name?: string | unknown;
|
||||
},
|
||||
DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>,
|
||||
{}
|
||||
> = styled('span')`
|
||||
&& {
|
||||
${commonStyle};
|
||||
}
|
||||
export const ImgWrapper = styled('span')`
|
||||
${commonStyle};
|
||||
box-sizing: initial;
|
||||
`;
|
||||
|
||||
export const Img = styled('img')({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useContext } from 'react';
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { DetailContext } from '../../pages/Version';
|
||||
import { fontWeight } from '../../utils/styles/sizes';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import CopyToClipBoard from '../CopyToClipBoard';
|
||||
import Avatar from '../../muiComponents/Avatar';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { fontWeight } from '../../utils/styles/sizes';
|
||||
|
||||
@@ -15,7 +15,6 @@ interface WrapperProps {
|
||||
weight: string;
|
||||
modifiers?: null;
|
||||
}
|
||||
|
||||
const Wrapper = styled('div')`
|
||||
font-weight: ${({ weight }: WrapperProps) => fontWeight[weight]};
|
||||
text-transform: ${({ capitalize }: WrapperProps) => (capitalize ? 'capitalize' : 'none')};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import styled, { css } from 'react-emotion';
|
||||
import { css } from '@emotion/core';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import colors from '../../utils/styles/colors';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
export const Wrapper = styled('div')`
|
||||
&& {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import logo from './img/logo.svg';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
import React, { useCallback } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { default as Typography } from '../../muiComponents/Heading';
|
||||
import List from '../../muiComponents/List';
|
||||
|
||||
@@ -156,7 +156,7 @@ const Package: React.FC<PackageInterface> = ({
|
||||
<Grid item={true} xs={true}>
|
||||
<WrapperLink to={`/-/web/detail/${packageName}`}>
|
||||
{/* eslint-disable-next-line react/jsx-max-depth */}
|
||||
<PackageTitle>{packageName}</PackageTitle>
|
||||
<PackageTitle className="package-title">{packageName}</PackageTitle>
|
||||
</WrapperLink>
|
||||
</Grid>
|
||||
<GridRightAligned item={true} xs={true}>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { breakpoints } from '../../utils/styles/media';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { css } from 'emotion';
|
||||
import { css } from '@emotion/core';
|
||||
|
||||
import { fontWeight, fontSize } from '../../utils/styles/sizes';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import { css } from 'emotion';
|
||||
import { css } from '@emotion/core';
|
||||
|
||||
import CopyToClipBoard from '../CopyToClipBoard';
|
||||
import { getCLISetRegistry, getCLIChangePassword, getCLISetConfigRegistry } from '../../utils/cli-utils';
|
||||
@@ -47,13 +47,7 @@ const RegistryInfoContent: React.FC<Props> = props => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tabs
|
||||
data-testid={'tabs-el'}
|
||||
indicatorColor="primary"
|
||||
onChange={handleChange}
|
||||
textColor="primary"
|
||||
value={tabPosition}
|
||||
variant="fullWidth">
|
||||
<Tabs data-testid={'tabs-el'} indicatorColor="primary" onChange={handleChange} textColor="primary" value={tabPosition} variant="fullWidth">
|
||||
<Tab data-testid={'npm-tab'} label={NODE_MANAGER.npm} />
|
||||
<Tab data-testid={'pnpm-tab'} label={NODE_MANAGER.pnpm} />
|
||||
<Tab data-testid={'yarn-tab'} label={NODE_MANAGER.yarn} />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
export const CommandContainer = styled('div')({
|
||||
'&&': {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import colors from '../../utils/styles/colors';
|
||||
import { fontSize } from '../../utils/styles/sizes';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import Github from '../../icons/GitHub';
|
||||
import colors from '../../utils/styles/colors';
|
||||
|
||||
@@ -1,203 +1,80 @@
|
||||
import React, { KeyboardEvent, Component, ReactElement } from 'react';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import { SuggestionSelectedEventData, ChangeEvent } from 'react-autosuggest';
|
||||
import { css } from 'emotion';
|
||||
import { default as IconSearch } from '@material-ui/icons/Search';
|
||||
import React from 'react';
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
import InputAdornment from '../../muiComponents/InputAdornment';
|
||||
import AutoComplete from '../AutoComplete';
|
||||
import colors from '../../utils/styles/colors';
|
||||
import AutoComplete from '../../muiComponents/AutoComplete';
|
||||
import { callSearch } from '../../utils/calls';
|
||||
|
||||
export interface State {
|
||||
search: string;
|
||||
suggestions: unknown[];
|
||||
loading: boolean;
|
||||
loaded: boolean;
|
||||
error: boolean;
|
||||
}
|
||||
|
||||
export type cancelAllSearchRequests = () => void;
|
||||
export type handlePackagesClearRequested = () => void;
|
||||
export type handleSearch = (event: React.FormEvent<HTMLInputElement>, { newValue, method }: ChangeEvent) => void;
|
||||
export type handleClickSearch = (
|
||||
event: KeyboardEvent<HTMLInputElement>,
|
||||
{ suggestionValue, method }: { suggestionValue: object[]; method: string }
|
||||
) => void;
|
||||
export type handleFetchPackages = ({ value: string }) => Promise<void>;
|
||||
export type onBlur = (event: React.FormEvent<HTMLInputElement>) => void;
|
||||
|
||||
const CONSTANTS = {
|
||||
API_DELAY: 300,
|
||||
PLACEHOLDER_TEXT: 'Search Packages',
|
||||
ABORT_ERROR: 'AbortError',
|
||||
};
|
||||
|
||||
export class Search extends Component<RouteComponentProps<{}>, State> {
|
||||
constructor(props: RouteComponentProps<{}>) {
|
||||
super(props);
|
||||
this.state = {
|
||||
search: '',
|
||||
suggestions: [],
|
||||
// loading: A boolean value to indicate that request is in pending state.
|
||||
loading: false,
|
||||
// loaded: A boolean value to indicate that result has been loaded.
|
||||
loaded: false,
|
||||
// error: A boolean value to indicate API error.
|
||||
error: false,
|
||||
};
|
||||
this.requestList = [];
|
||||
}
|
||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
const Search: React.FC = () => {
|
||||
const [suggestions, setSuggestions] = React.useState([]);
|
||||
const [isLoading, setIsLoading] = React.useState();
|
||||
const [hasBeenLoaded, setHasBeenLoaded] = React.useState();
|
||||
const [error, setError] = React.useState();
|
||||
|
||||
public render(): ReactElement<HTMLElement> {
|
||||
const { suggestions, search, loaded, loading, error } = this.state;
|
||||
|
||||
return (
|
||||
<AutoComplete
|
||||
color={colors.white}
|
||||
onBlur={this.handleOnBlur}
|
||||
onChange={this.handleSearch}
|
||||
onCleanSuggestions={this.handlePackagesClearRequested}
|
||||
onClick={this.handleClickSearch}
|
||||
onSuggestionsFetch={debounce(this.handleFetchPackages, CONSTANTS.API_DELAY)}
|
||||
placeholder={CONSTANTS.PLACEHOLDER_TEXT}
|
||||
startAdornment={this.getAdorment()}
|
||||
suggestions={suggestions}
|
||||
suggestionsError={error}
|
||||
suggestionsLoaded={loaded}
|
||||
suggestionsLoading={loading}
|
||||
value={search}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel all the requests which are in pending state.
|
||||
*/
|
||||
private cancelAllSearchRequests: cancelAllSearchRequests = () => {
|
||||
this.requestList.forEach(request => request.abort());
|
||||
this.requestList = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Cancel all the request from list and make request list empty.
|
||||
*/
|
||||
private handlePackagesClearRequested: handlePackagesClearRequested = () => {
|
||||
this.setState({
|
||||
suggestions: [],
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* onChange method for the input element.
|
||||
*/
|
||||
private handleSearch: handleSearch = (event, { newValue, method }) => {
|
||||
// stops event bubbling
|
||||
event.stopPropagation();
|
||||
if (method === 'type') {
|
||||
const value = newValue.trim();
|
||||
this.setState(
|
||||
{
|
||||
search: value,
|
||||
loading: true,
|
||||
loaded: false,
|
||||
error: false,
|
||||
},
|
||||
() => {
|
||||
/**
|
||||
* A use case where User keeps adding and removing value in input field,
|
||||
* so we cancel all the existing requests when input is empty.
|
||||
*/
|
||||
if (value.length === 0) {
|
||||
this.cancelAllSearchRequests();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* When an user select any package by clicking or pressing return key.
|
||||
*/
|
||||
private handleClickSearch = (
|
||||
event: React.FormEvent<HTMLInputElement>,
|
||||
{ suggestionValue, method }: SuggestionSelectedEventData<unknown>
|
||||
): void | undefined => {
|
||||
const { history } = this.props;
|
||||
// stops event bubbling
|
||||
event.stopPropagation();
|
||||
switch (method) {
|
||||
case 'click':
|
||||
case 'enter':
|
||||
this.setState({ search: '' });
|
||||
history.push(`/-/web/detail/${suggestionValue}`);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch packages from API.
|
||||
* For AbortController see: https://developer.mozilla.org/en-US/docs/Web/API/AbortController
|
||||
*/
|
||||
private handleFetchPackages: handleFetchPackages = async ({ value }) => {
|
||||
const handleFetchPackages = debounce(async (value: string) => {
|
||||
try {
|
||||
const controller = new window.AbortController();
|
||||
const signal = controller.signal;
|
||||
// Keep track of search requests.
|
||||
this.requestList.push(controller);
|
||||
// this.requestList.push(controller);
|
||||
const suggestions = await callSearch(value, signal);
|
||||
// @ts-ignore
|
||||
this.setState({
|
||||
suggestions,
|
||||
loaded: true,
|
||||
});
|
||||
setSuggestions(
|
||||
// @ts-ignore
|
||||
suggestions.map(suggestion => ({
|
||||
...suggestion,
|
||||
id: suggestion._id,
|
||||
label: suggestion.name,
|
||||
}))
|
||||
);
|
||||
setHasBeenLoaded(true);
|
||||
} catch (error) {
|
||||
/**
|
||||
* AbortError is not the API error.
|
||||
* It means browser has cancelled the API request.
|
||||
*/
|
||||
if (error.name === CONSTANTS.ABORT_ERROR) {
|
||||
this.setState({ error: false, loaded: false });
|
||||
setError(false);
|
||||
setHasBeenLoaded(false);
|
||||
} else {
|
||||
this.setState({ error: true, loaded: false });
|
||||
setError(true);
|
||||
setHasBeenLoaded(false);
|
||||
}
|
||||
} finally {
|
||||
this.setState({ loading: false });
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
}, CONSTANTS.API_DELAY);
|
||||
|
||||
private requestList: AbortController[];
|
||||
|
||||
public getAdorment(): JSX.Element {
|
||||
return (
|
||||
<InputAdornment
|
||||
className={css`
|
||||
color: ${colors.white};
|
||||
}
|
||||
`}
|
||||
position={'start'}>
|
||||
<IconSearch />
|
||||
</InputAdornment>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* As user focuses out from input, we cancel all the request from requestList
|
||||
* and set the API state parameters to default boolean values.
|
||||
*/
|
||||
private handleOnBlur: onBlur = event => {
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
// stops event bubbling
|
||||
event.stopPropagation();
|
||||
this.setState(
|
||||
{
|
||||
loaded: false,
|
||||
loading: false,
|
||||
error: false,
|
||||
},
|
||||
() => this.cancelAllSearchRequests()
|
||||
);
|
||||
setIsLoading(true);
|
||||
setHasBeenLoaded(false);
|
||||
setError(undefined);
|
||||
handleFetchPackages(event.target.value);
|
||||
};
|
||||
}
|
||||
|
||||
export default withRouter(Search);
|
||||
return (
|
||||
<AutoComplete
|
||||
// onBlur={this.handleOnBlur}
|
||||
onChange={handleChange}
|
||||
// onCleanSuggestions={this.handlePackagesClearRequested}
|
||||
// onClick={this.handleClickSearch}
|
||||
// onSuggestionsFetch={debounce(this.handleFetchPackages, CONSTANTS.API_DELAY)}
|
||||
options={suggestions}
|
||||
placeholder={CONSTANTS.PLACEHOLDER_TEXT}
|
||||
// startAdornment={this.getAdorment()}
|
||||
// suggestionsError={error}
|
||||
// suggestionsLoaded={loaded}
|
||||
// suggestionsLoading={loading}
|
||||
// value={search}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Search;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import styled, { css } from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
import { css } from '@emotion/core';
|
||||
|
||||
import colors from '../../utils/styles/colors';
|
||||
import CircularProgress from '../../muiComponents/CircularProgress';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
export const Wrapper = styled('span')({
|
||||
'&&': {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import Text from '../../muiComponents/Text';
|
||||
import { default as MuiListItemText } from '../../muiComponents/ListItemText';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import styled from 'react-emotion';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { fontWeight } from '../../utils/styles/sizes';
|
||||
import Text from '../../muiComponents/Text';
|
||||
|
||||
38
src/design-tokens/ResetStyles.tsx
Normal file
38
src/design-tokens/ResetStyles.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import { makeStyles } from '@material-ui/styles';
|
||||
import React from 'react';
|
||||
|
||||
import { fontWeight } from '../utils/styles/sizes';
|
||||
import { breakpoints } from '../utils/styles/media';
|
||||
|
||||
const resetStyles = makeStyles(() => ({
|
||||
'@global': {
|
||||
// eslint-disable-next-line max-len
|
||||
'html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video': {
|
||||
fontFamily: '"Roboto", Helvetica Neue, Arial, sans-serif',
|
||||
},
|
||||
strong: {
|
||||
fontWeight: fontWeight.semiBold,
|
||||
},
|
||||
'html, body, #root': {
|
||||
height: '100%',
|
||||
},
|
||||
'.container': {
|
||||
padding: 15,
|
||||
flex: 1,
|
||||
|
||||
[`@media screen and (min-width: ${breakpoints.container}px)`]: {
|
||||
maxWidth: breakpoints.container,
|
||||
width: '100%',
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const ResetStyles: React.FC = ({ children }) => {
|
||||
resetStyles();
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
export default ResetStyles;
|
||||
15
src/design-tokens/StyleBaseline.tsx
Normal file
15
src/design-tokens/StyleBaseline.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
import React from 'react';
|
||||
import 'normalize.css';
|
||||
import 'typeface-roboto/index.css';
|
||||
|
||||
import ResetCSS from './ResetStyles';
|
||||
|
||||
const StyleBaseline: React.FC = () => (
|
||||
<>
|
||||
<CssBaseline />
|
||||
<ResetCSS />
|
||||
</>
|
||||
);
|
||||
|
||||
export default StyleBaseline;
|
||||
93
src/muiComponents/AutoComplete/AutoComplete.tsx
Normal file
93
src/muiComponents/AutoComplete/AutoComplete.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import React, { forwardRef, ChangeEvent, useState } from 'react';
|
||||
import { default as MuiAutoComplete, AutocompleteProps } from '@material-ui/lab/Autocomplete';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import styled from '@emotion/styled';
|
||||
import Search from '@material-ui/icons/Search';
|
||||
|
||||
import CircularProgress from '../CircularProgress';
|
||||
|
||||
import AutoCompleteTextField from './AutoCompleteTextField';
|
||||
|
||||
const StyledAutoComplete = styled(MuiAutoComplete)({
|
||||
width: '100%',
|
||||
color: 'white',
|
||||
});
|
||||
|
||||
const StyledSearch = styled(Search)({
|
||||
color: 'white',
|
||||
marginRight: 10,
|
||||
});
|
||||
|
||||
const StyledTextField = styled(TextField)({
|
||||
'& .MuiInputBase-root': {
|
||||
color: 'white',
|
||||
},
|
||||
'& .MuiInput-underline': {
|
||||
':before': {
|
||||
content: "''",
|
||||
border: 'none',
|
||||
},
|
||||
':after': {
|
||||
borderColor: 'white',
|
||||
},
|
||||
':hover:before': {
|
||||
content: 'none',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
interface Props {
|
||||
placeholder?: string;
|
||||
onChange: (event: ChangeEvent<HTMLInputElement>) => void;
|
||||
options: Array<Option>;
|
||||
}
|
||||
|
||||
interface Option {
|
||||
id: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
type AutoCompleteRef = HTMLDivElement;
|
||||
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
const AutoComplete = forwardRef<AutoCompleteRef, Props>(function AutoComplete({ placeholder, options = [], onChange }, ref) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const isLoading = open && options.length === 0;
|
||||
|
||||
console.log('options', options);
|
||||
|
||||
return (
|
||||
<StyledAutoComplete
|
||||
autoHighlight={true}
|
||||
freeSolo={true}
|
||||
options={options}
|
||||
loading={isLoading}
|
||||
innerRef={ref}
|
||||
open={open}
|
||||
onOpen={() => {
|
||||
setOpen(true);
|
||||
}}
|
||||
onClose={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
getOptionLabel={option => option.label}
|
||||
renderInput={params => (
|
||||
<StyledTextField
|
||||
{...params}
|
||||
onChange={onChange}
|
||||
fullWidth={true}
|
||||
variant="standard"
|
||||
placeholder={placeholder}
|
||||
InputProps={{
|
||||
...params.InputProps,
|
||||
startAdornment: <StyledSearch />,
|
||||
endAdornment: isLoading ? <CircularProgress color="inherit" size={20} /> : null,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export default AutoComplete;
|
||||
35
src/muiComponents/AutoComplete/AutoCompleteTextField.tsx
Normal file
35
src/muiComponents/AutoComplete/AutoCompleteTextField.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import Search from '@material-ui/icons/Search';
|
||||
|
||||
import TextField, { TextFieldProps } from '../TextField';
|
||||
|
||||
const StyledTextField = styled(TextField)({
|
||||
'& .MuiInputBase-root': {
|
||||
color: 'white',
|
||||
},
|
||||
'& .MuiInput-underline': {
|
||||
':before': {
|
||||
content: "''",
|
||||
border: 'none',
|
||||
},
|
||||
':after': {
|
||||
borderColor: 'white',
|
||||
},
|
||||
':hover:before': {
|
||||
content: 'none',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const StyledSearch = styled(Search)({
|
||||
color: 'white',
|
||||
marginRight: 10,
|
||||
});
|
||||
|
||||
const AutoCompleteTextField: React.FC<TextFieldProps> = props => {
|
||||
// @ts-ignore: Types of property 'ref' are incompatible.
|
||||
return <StyledTextField {...props} InputProps={{ startAdornment: <StyledSearch /> }} />;
|
||||
};
|
||||
|
||||
export default AutoCompleteTextField;
|
||||
1
src/muiComponents/AutoComplete/index.ts
Normal file
1
src/muiComponents/AutoComplete/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './AutoComplete';
|
||||
@@ -17,4 +17,5 @@ const TextField = forwardRef<TextFieldRef, TextFieldProps>(function TextField({
|
||||
);
|
||||
});
|
||||
|
||||
export { TextFieldProps };
|
||||
export default TextField;
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { default } from './TextField';
|
||||
export { default, TextFieldProps } from './TextField';
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
import { injectGlobal } from 'emotion';
|
||||
|
||||
import { fontSize, fontWeight } from './sizes';
|
||||
import colors from './colors';
|
||||
import { breakpoints } from './media';
|
||||
|
||||
const fontFamily = `-apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
|
||||
Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`;
|
||||
|
||||
export default injectGlobal`
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: ${fontFamily};
|
||||
font-size: ${fontSize.base};
|
||||
color: ${colors.eclipse};
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: ${fontWeight.semiBold};
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 15px;
|
||||
flex: 1;
|
||||
|
||||
@media screen and (min-width: ${breakpoints.container}px) {
|
||||
max-width: ${breakpoints.container}px;
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
};
|
||||
|
||||
.el-loading-spinner {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.page-full-height {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
&:hover, &:focus {
|
||||
color: ${colors.primary};
|
||||
border-color: ${colors.primary};
|
||||
}
|
||||
}
|
||||
|
||||
.el-input__inner {
|
||||
&:hover, &:focus {
|
||||
border-color: ${colors.primary};
|
||||
}
|
||||
}
|
||||
|
||||
.el-dialog__headerbtn:hover .el-dialog__close {
|
||||
color: ${colors.eclipse};
|
||||
}
|
||||
|
||||
.package-list-items {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
`;
|
||||
@@ -14,7 +14,7 @@ auth:
|
||||
password: test
|
||||
|
||||
logs:
|
||||
- { type: stdout, format: pretty, level: warn }
|
||||
- { type: stdout, format: pretty, level: info }
|
||||
|
||||
packages:
|
||||
'protected-*':
|
||||
|
||||
@@ -14,7 +14,7 @@ auth:
|
||||
password: test
|
||||
|
||||
logs:
|
||||
- { type: stdout, format: pretty, level: warn }
|
||||
- { type: stdout, format: pretty, level: info }
|
||||
|
||||
packages:
|
||||
'@*/*':
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { HELP_TITLE } from '../../src/components/Help/Help';
|
||||
|
||||
const scopedPackageMetadata = require('./partials/pkg-scoped');
|
||||
const protectedPackageMetadata = require('./partials/pkg-protected');
|
||||
|
||||
@@ -12,16 +14,16 @@ describe('/ (Verdaccio Page)', () => {
|
||||
await button.click(options);
|
||||
};
|
||||
|
||||
const evaluateSignIn = async function() {
|
||||
const text = await page.evaluate(
|
||||
() => document.querySelector('button[data-testid="header--button-login"]').textContent
|
||||
);
|
||||
const evaluateSignIn = async function(matchText = 'Login') {
|
||||
const text = await page.evaluate(() => {
|
||||
return document.querySelector('button[data-testid="header--button-login"]').textContent;
|
||||
});
|
||||
|
||||
expect(text).toMatch('Login');
|
||||
expect(text).toMatch(matchText);
|
||||
};
|
||||
|
||||
const getPackages = async function() {
|
||||
return await page.$$('.package-list-items .package-link a');
|
||||
return await page.$$('.package-title');
|
||||
};
|
||||
|
||||
const logIn = async function() {
|
||||
@@ -54,31 +56,34 @@ describe('/ (Verdaccio Page)', () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test('should load without error', async () => {
|
||||
const text = await page.evaluate(() => document.body.textContent);
|
||||
test('should display title', async () => {
|
||||
const text = await page.title();
|
||||
await page.waitFor(1000);
|
||||
|
||||
// FIXME: perhaps it is not the best approach
|
||||
expect(text).toContain('Powered by');
|
||||
expect(text).toContain('verdaccio-server-e2e');
|
||||
});
|
||||
|
||||
test('should match title with no packages published', async () => {
|
||||
const text = await page.evaluate(() => document.querySelector('#help-card__title').textContent);
|
||||
expect(text).toMatch('No Package Published Yet');
|
||||
expect(text).toMatch(HELP_TITLE);
|
||||
});
|
||||
//
|
||||
|
||||
test('should match title with first step', async () => {
|
||||
const text = await page.evaluate(() => document.querySelector('#help-card').textContent);
|
||||
expect(text).toContain('npm adduser --registry http://0.0.0.0:55558');
|
||||
});
|
||||
//
|
||||
|
||||
test('should match title with second step', async () => {
|
||||
const text = await page.evaluate(() => document.querySelector('#help-card').textContent);
|
||||
expect(text).toContain('npm publish --registry http://0.0.0.0:55558');
|
||||
});
|
||||
|
||||
//
|
||||
test('should match button Login to sign in', async () => {
|
||||
await evaluateSignIn();
|
||||
});
|
||||
//
|
||||
|
||||
test('should click on sign in button', async () => {
|
||||
const signInButton = await page.$('button[data-testid="header--button-login"]');
|
||||
@@ -88,6 +93,7 @@ describe('/ (Verdaccio Page)', () => {
|
||||
|
||||
expect(signInDialog).not.toBeNull();
|
||||
});
|
||||
//
|
||||
|
||||
test('should log in an user', async () => {
|
||||
// we open the dialog
|
||||
@@ -96,6 +102,7 @@ describe('/ (Verdaccio Page)', () => {
|
||||
const buttonLogout = await page.$('#header--button-logout');
|
||||
expect(buttonLogout).toBeDefined();
|
||||
});
|
||||
//
|
||||
|
||||
test('should logout an user', async () => {
|
||||
// we assume the user is logged already
|
||||
@@ -105,6 +112,7 @@ describe('/ (Verdaccio Page)', () => {
|
||||
await page.waitFor(1000);
|
||||
await evaluateSignIn();
|
||||
});
|
||||
//
|
||||
|
||||
test('should check registry info dialog', async () => {
|
||||
const registryInfoButton = await page.$('#header--button-registryInfo');
|
||||
@@ -117,6 +125,7 @@ describe('/ (Verdaccio Page)', () => {
|
||||
const closeButton = await page.$('#registryInfo--dialog-close');
|
||||
closeButton.click();
|
||||
});
|
||||
//
|
||||
|
||||
test('should publish a package', async () => {
|
||||
await global.__SERVER__.putPackage(scopedPackageMetadata.name, scopedPackageMetadata);
|
||||
@@ -126,13 +135,16 @@ describe('/ (Verdaccio Page)', () => {
|
||||
const packagesList = await getPackages();
|
||||
expect(packagesList).toHaveLength(1);
|
||||
});
|
||||
//
|
||||
|
||||
test('should navigate to the package detail', async () => {
|
||||
const packagesList = await getPackages();
|
||||
// console.log("-->packagesList:", packagesList);
|
||||
const firstPackage = packagesList[0];
|
||||
await firstPackage.click({ clickCount: 1, delay: 200 });
|
||||
await page.waitFor(1000);
|
||||
const readmeText = await page.evaluate(() => document.querySelector('.markdown-body').textContent);
|
||||
|
||||
expect(readmeText).toMatch('test');
|
||||
});
|
||||
|
||||
@@ -140,7 +152,7 @@ describe('/ (Verdaccio Page)', () => {
|
||||
const versionList = await page.$$('.sidebar-info .detail-info');
|
||||
expect(versionList).toHaveLength(1);
|
||||
});
|
||||
|
||||
//
|
||||
test('should display dependencies tab', async () => {
|
||||
const dependenciesTab = await page.$$('#dependencies-tab');
|
||||
expect(dependenciesTab).toHaveLength(1);
|
||||
|
||||
@@ -10,7 +10,12 @@ const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup');
|
||||
|
||||
module.exports = async function() {
|
||||
console.log(green('Setup Puppeteer'));
|
||||
const browser = await puppeteer.launch({ headless: true, /* slowMo: 300 */ args: ['--no-sandbox'] });
|
||||
const browser = await puppeteer.launch({
|
||||
headless: true,
|
||||
// slowMo: 600,
|
||||
// devtools: true,
|
||||
args: ['--no-sandbox'],
|
||||
});
|
||||
global.__BROWSER__ = browser;
|
||||
mkdirp.sync(DIR);
|
||||
fs.writeFileSync(path.join(DIR, 'wsEndpoint'), browser.wsEndpoint());
|
||||
|
||||
@@ -37,7 +37,7 @@ new WebpackDevServer(compiler, {
|
||||
proxy: [
|
||||
{
|
||||
context: ['/-/verdaccio/**', '**/*.tgz'],
|
||||
target: 'http://localhost:8080',
|
||||
target: 'http://localhost:4873',
|
||||
},
|
||||
],
|
||||
}).listen(4872, 'localhost', function(err) {
|
||||
|
||||
@@ -67,7 +67,8 @@ module.exports = {
|
||||
test: /\.(woff|woff2|eot|ttf|otf)$/,
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
name: '/fonts/[name].[ext]',
|
||||
name: '[name].[ext]',
|
||||
outputPath: 'fonts',
|
||||
limit: 50,
|
||||
},
|
||||
},
|
||||
|
||||
8
types/custom.d.ts
vendored
8
types/custom.d.ts
vendored
@@ -1,11 +1,3 @@
|
||||
// https://stackoverflow.com/questions/44717164/unable-to-import-svg-files-in-typescript
|
||||
declare module '*.svg' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.png';
|
||||
|
||||
declare module 'localstorage-memory' {
|
||||
const memoryStorage: Storage;
|
||||
export default memoryStorage;
|
||||
|
||||
9
types/files.d.ts
vendored
Normal file
9
types/files.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
declare module '*.svg' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.png' {
|
||||
const value: string;
|
||||
export = value;
|
||||
}
|
||||
Reference in New Issue
Block a user