Compare commits

...

51 Commits

Author SHA1 Message Date
Priscila Oliveira
8c9076d0a2 chore: update emotion dependencies 2019-11-16 00:28:36 +01:00
Priscila Oliveira
ea19a2bb47 Merge branch 'master' into refactor/migrate_autocomplete_to_mui 2019-11-15 23:20:30 +01:00
dependabot-preview[bot]
042571e72f build(deps-dev): bump react-hot-loader from 4.12.16 to 4.12.17 (#270) 2019-11-15 23:19:04 +01:00
dependabot-preview[bot]
dd6ba2cbe9 build(deps-dev): bump ora from 4.0.2 to 4.0.3 (#273) 2019-11-15 23:06:26 +01:00
dependabot-preview[bot]
bf613231f4 build(deps-dev): bump @types/lodash from 4.14.146 to 4.14.147 (#274) 2019-11-15 23:06:00 +01:00
dependabot-preview[bot]
7074eddf27 build(deps-dev): bump lint-staged from 9.4.2 to 9.4.3 (#275) 2019-11-15 23:04:57 +01:00
dependabot-preview[bot]
d3ddd439d1 build(deps-dev): bump stylelint-webpack-plugin from 1.0.3 to 1.0.4 (#276) 2019-11-15 23:03:46 +01:00
dependabot-preview[bot]
26724bb20e build(deps-dev): bump react-dom from 16.11.0 to 16.12.0 (#277) 2019-11-15 22:57:31 +01:00
dependabot-preview[bot]
cba41ceead build(deps-dev): bump eslint-plugin-react-hooks from 2.2.0 to 2.3.0 (#278) 2019-11-15 22:50:16 +01:00
dependabot-preview[bot]
2688b59f5b build(deps-dev): bump react from 16.11.0 to 16.12.0 (#279) 2019-11-15 22:38:50 +01:00
Priscila Oliveira
d9f463688d Merge branch 'master' into refactor/migrate_autocomplete_to_mui 2019-11-13 15:09:22 +01:00
dependabot-preview[bot]
4d285dbb00 build(deps-dev): bump @types/jest from 24.0.22 to 24.0.23 (#271) 2019-11-13 09:07:22 +01:00
dependabot-preview[bot]
739333b1f1 build(deps-dev): bump @material-ui/core from 4.6.0 to 4.6.1 (#272) 2019-11-13 09:05:08 +01:00
dependabot-preview[bot]
5809a9f7cb build(deps-dev): bump @octokit/rest from 16.34.1 to 16.35.0 (#261) 2019-11-12 21:19:34 +01:00
dependabot-preview[bot]
e1c5e30b4c build(deps-dev): bump @typescript-eslint/parser from 2.5.0 to 2.7.0 (#264) 2019-11-12 20:49:49 +01:00
dependabot-preview[bot]
5a3ea02449 build(deps-dev): bump @verdaccio/commons-api from 8.2.0 to 8.3.0 (#265) 2019-11-12 20:49:35 +01:00
dependabot-preview[bot]
535d8f9c85 build(deps-dev): bump typescript from 3.7.1-rc to 3.7.2 (#266) 2019-11-12 20:49:15 +01:00
dependabot-preview[bot]
8a46678698 build(deps-dev): bump resolve-url-loader from 3.1.0 to 3.1.1 (#267) 2019-11-12 20:48:52 +01:00
dependabot-preview[bot]
3265ed561d build(deps-dev): bump @types/node from 12.12.6 to 12.12.7 (#268) 2019-11-12 20:48:29 +01:00
dependabot-preview[bot]
3a6c6f7fb9 build(deps-dev): bump @testing-library/react from 9.3.0 to 9.3.2 (#255) 2019-11-12 08:27:54 +01:00
Priscila Oliveira
09fe1db850 Refactor(#240): Created Reset CSS and added local fonts 2019-11-12 08:18:05 +01:00
dependabot-preview[bot]
f265b6ba33 build(deps-dev): bump validator from 11.1.0 to 12.0.0 (#256) 2019-11-11 13:50:38 +01:00
dependabot-preview[bot]
185b2016d3 build(deps-dev): bump react-hot-loader from 4.12.15 to 4.12.16 (#257) 2019-11-11 13:50:22 +01:00
dependabot-preview[bot]
3751acef1c build(deps-dev): bump lint-staged from 8.2.1 to 9.4.2 (#258) 2019-11-11 13:50:04 +01:00
dependabot-preview[bot]
50fa39f7d6 build(deps-dev): bump date-fns from 2.6.0 to 2.7.0 (#260) 2019-11-11 13:49:41 +01:00
dependabot-preview[bot]
cd2e36513e build(deps-dev): bump prettier from 1.18.2 to 1.19.1 (#254) 2019-11-11 13:49:22 +01:00
dependabot-preview[bot]
b20fe3f44a build(deps-dev): bump @types/lodash from 4.14.144 to 4.14.146 (#253) 2019-11-11 13:49:05 +01:00
dependabot-preview[bot]
be30cbdd14 build(deps-dev): bump @types/jest from 24.0.20 to 24.0.22 (#262) 2019-11-11 13:45:56 +01:00
dependabot-preview[bot]
c6e3fd0b92 build(deps-dev): bump detect-secrets from 1.0.4 to 1.0.5 (#252) 2019-11-11 13:15:39 +01:00
dependabot-preview[bot]
f27254ca6b build(deps-dev): bump @types/react-router-dom from 5.1.0 to 5.1.2 (#247) 2019-11-10 22:08:27 +01:00
Priscila Oliveira
571d9c3fa7 refactor: converting autoComplete to Mui's autocomplete 2019-11-10 16:31:29 +01:00
dependabot-preview[bot]
f4dd8b01b4 build(deps-dev): bump verdaccio-auth-memory from 8.2.0 to 8.3.0 (#250)
Bumps [verdaccio-auth-memory](https://github.com/verdaccio/monorepo/tree/HEAD/plugins/auth-memory) from 8.2.0 to 8.3.0.
- [Release notes](https://github.com/verdaccio/monorepo/releases)
- [Changelog](https://github.com/verdaccio/monorepo/blob/master/plugins/auth-memory/CHANGELOG.md)
- [Commits](https://github.com/verdaccio/monorepo/commits/v8.3.0/plugins/auth-memory)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-09 08:22:39 +01:00
dependabot-preview[bot]
a94485e614 build(deps-dev): bump @types/react-dom from 16.9.3 to 16.9.4 (#248)
Bumps [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) from 16.9.3 to 16.9.4.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-09 00:18:50 +01:00
dependabot-preview[bot]
ce4b13d3b5 build(deps-dev): bump verdaccio-memory from 8.2.0 to 8.3.0 (#249)
Bumps [verdaccio-memory](https://github.com/verdaccio/monorepo/tree/HEAD/plugins/memory) from 8.2.0 to 8.3.0.
- [Release notes](https://github.com/verdaccio/monorepo/releases)
- [Changelog](https://github.com/verdaccio/monorepo/blob/master/plugins/memory/CHANGELOG.md)
- [Commits](https://github.com/verdaccio/monorepo/commits/v8.3.0/plugins/memory)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-09 00:09:57 +01:00
dependabot-preview[bot]
fcd471ef6f build(deps-dev): bump lockfile-lint from 2.1.6 to 2.2.0 (#244)
Bumps [lockfile-lint](https://github.com/lirantal/lockfile-lint) from 2.1.6 to 2.2.0.
- [Release notes](https://github.com/lirantal/lockfile-lint/releases)
- [Commits](https://github.com/lirantal/lockfile-lint/compare/lockfile-lint@2.1.6...lockfile-lint@2.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-08 07:07:01 +01:00
dependabot-preview[bot]
9915fb6193 build(deps-dev): bump @verdaccio/types from 8.1.0 to 8.3.0 (#242)
Bumps [@verdaccio/types](https://github.com/verdaccio/monorepo/tree/HEAD/core/types) from 8.1.0 to 8.3.0.
- [Release notes](https://github.com/verdaccio/monorepo/releases)
- [Changelog](https://github.com/verdaccio/monorepo/blob/master/core/types/CHANGELOG.md)
- [Commits](https://github.com/verdaccio/monorepo/commits/v8.3.0/core/types)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-08 06:47:52 +01:00
dependabot-preview[bot]
886684817b build(deps-dev): bump @types/node from 12.11.7 to 12.12.6 (#243)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 12.11.7 to 12.12.6.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-08 06:44:58 +01:00
dependabot-preview[bot]
76d11d4674 build(deps-dev): bump @octokit/rest from 16.34.0 to 16.34.1 (#241)
Bumps [@octokit/rest](https://github.com/octokit/rest.js) from 16.34.0 to 16.34.1.
- [Release notes](https://github.com/octokit/rest.js/releases)
- [Commits](https://github.com/octokit/rest.js/compare/v16.34.0...v16.34.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-08 06:44:22 +01:00
dependabot-preview[bot]
322197dc70 build(deps-dev): bump webpack-cli from 3.3.9 to 3.3.10 (#245)
Bumps [webpack-cli](https://github.com/webpack/webpack-cli) from 3.3.9 to 3.3.10.
- [Release notes](https://github.com/webpack/webpack-cli/releases)
- [Changelog](https://github.com/webpack/webpack-cli/blob/v3.3.10/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-cli/compare/v3.3.9...v3.3.10)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-08 06:37:20 +01:00
Juan Picado @jotadeveloper
d2e9d68c6d chore(release): 0.3.6 2019-11-08 06:36:19 +01:00
Juan Picado @jotadeveloper
f1971edf6d build: fix e2e (#246)
* fix: e2e testing

* fix: e2e testing

* fix: e2e testing

* fix: e2e testing

* fix: e2e testing

* fix: e2e testing
2019-11-08 06:23:22 +01:00
Juan Picado @jotadeveloper
c9f6bf43ae chore(release): 0.3.5 2019-11-07 18:11:26 +01:00
Anix
bdef686914 feat: added download tarball button at list (#237)
* chore: added download button at packagelist

* feat: added download btn in package list
2019-11-07 18:11:08 +01:00
Priscila Oliveira
84257e1a84 chore: updated material-ui dependencies (#239)
* chore: update material-ui dependencies

* fix: updated snaps
2019-11-07 17:55:20 +01:00
Alfonso Austin
b74ca2285e fix: refactor/116 RegistryInfoContent is converted to functional component (#229)
* refactor:116[PackageList] component is converted to functional

* Refactor:#116 - Registry info content is converted to functional component

* refactor/116 - fix lint error

* refactor:116 - more lint errors

* refactor/116 - lint error

* refactor:116 - remove snapshot

* refactor: address code review comments #116

* refactor: fix lint error

* refactor: code review changes

* refactor add missed file

* refactor: lint error

* refactor: lint

* refactor: lint

* refactor: fix lint error
2019-11-02 17:53:21 +01:00
Ayush Sharma
803da1c532 fix: adds unit tests for api service (#235)
* refactor: adds unit tests for api service

* refactor: fix test dummy url
2019-11-01 07:18:55 +01:00
Andrew Hughson
5cb47ed49e fix: convert Engine component to hooks (#233)
* refactor: convert Engine component to hooks

* inline engine test data only used by one test

* remove  from engines tests

* remove confusing test abstraction

* change tests to not use mutations
2019-10-31 22:17:16 +01:00
Priscila Oliveira
b56e43846b fix: rest MUI components - Introduced ForwardRef (#224)
* refactor(162): added forwardRef Card

* refactor(162): introduced forwardRefDivider

* refactor(162): introduced forwardRef MuiComponents

* refactor(162): introducing forwardRef

* refactor(162): introduced forwardRef

* refactor(162): introduced forwardRef

* fix(162): fixed link

* fix: fixed port number

* fix: fixed duplicated id

* fix: fixed ref iconbutton

* fix: updated snaps

* fix: fixed port

* fix: fixed eslint errors

* fix: the item should be a button

* fix: fixed eslint errors
2019-10-31 08:12:18 +01:00
Ayush Sharma
a4cdd145d2 feat: update date fns to v2 (#232)
* chore: updates date-fns@2

* chore: updates date-fns@2  to new apis

* chore: updates date-fns@2, updates format
2019-10-30 07:02:07 +01:00
Juan Picado @jotadeveloper
0eb0566cde chore(#228): add canary package generator 2019-10-28 10:35:40 +01:00
Juan Picado @jotadeveloper
e6b53c0479 chore: migrate eslint@6.6.0 (#227)
* chore: migrate to eslint6

* chore: migrate to eslint6
2019-10-27 15:49:30 +01:00
150 changed files with 2187 additions and 1550 deletions

50
.github/workflows/canary.yml vendored Normal file
View File

@@ -0,0 +1,50 @@
name: CI Canary
on: [pull_request]
jobs:
build_test_lint:
name: Node Smoke Test Befor Canary
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: '12.x'
registry-url: 'https://registry.verdaccio.org'
- name: Install
run: yarn install --frozen-lockfile
- name: Lint
run: yarn lint
- name: Build
run: yarn build
- name: Archive production artifacts
uses: actions/upload-artifact@v1
with:
name: static
path: static
canary:
name: Publish Canary Version of a PR
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Download math result for job 2
uses: actions/download-artifact@v1
with:
name: static
- uses: verdaccio/github-actions/canary@v0.4.0
with:
message: 'Thanks for your PR, the @verdaccio/ui package will be accessible from here for testing purposes:'
is-global: false
package-name: '@verdaccio/ui-theme'
registry: 'https://registry.verdaccio.org'
repo-token: ${{ secrets.GITHUB_TOKEN }}
bot-token: ${{ secrets.VERDACCIO_BOT_TOKEN }}
- uses: actions/setup-node@v1
with:
node-version: '12.x'
registry-url: 'https://registry.verdaccio.org'
- run: npm publish --tag canary
env:
NODE_AUTH_TOKEN: ${{ secrets.VERDACCIO_TOKEN }}
needs: build_test_lint

View File

@@ -9,20 +9,20 @@ jobs:
strategy:
fail-fast: false
matrix:
node_version: [10, 12]
node_version: [12, 13]
os: [ubuntu-latest, windows-latest, macOS-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node_version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node_version }}
- name: Install
run: yarn install --frozen-lockfile
- name: Build
run: yarn build
- name: Lint
run: yarn lint
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node_version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node_version }}
- name: Install
run: yarn install --frozen-lockfile
- name: Lint
run: yarn lint
- name: Build
run: yarn build

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.
### [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)
### Bug Fixes
* adds unit tests for api service ([#235](https://github.com/verdaccio/ui/issues/235)) ([803da1c](https://github.com/verdaccio/ui/commit/803da1c))
* convert Engine component to hooks ([#233](https://github.com/verdaccio/ui/issues/233)) ([5cb47ed](https://github.com/verdaccio/ui/commit/5cb47ed))
* refactor/116 RegistryInfoContent is converted to functional component ([#229](https://github.com/verdaccio/ui/issues/229)) ([b74ca22](https://github.com/verdaccio/ui/commit/b74ca22)), closes [#116](https://github.com/verdaccio/ui/issues/116) [#116](https://github.com/verdaccio/ui/issues/116)
* rest MUI components - Introduced ForwardRef ([#224](https://github.com/verdaccio/ui/issues/224)) ([b56e438](https://github.com/verdaccio/ui/commit/b56e438))
### Features
* added download tarball button at list ([#237](https://github.com/verdaccio/ui/issues/237)) ([bdef686](https://github.com/verdaccio/ui/commit/bdef686))
* update date fns to v2 ([#232](https://github.com/verdaccio/ui/issues/232)) ([a4cdd14](https://github.com/verdaccio/ui/commit/a4cdd14))
### [0.3.4](https://github.com/verdaccio/ui/compare/v0.3.3...v0.3.4) (2019-10-26)

View File

@@ -15,6 +15,8 @@ global.__APP_VERSION__ = '1.0.0';
// @ts-ignore : Property '__VERDACCIO_BASENAME_UI_OPTIONS' does not exist on type 'Global'.
global.__VERDACCIO_BASENAME_UI_OPTIONS = {};
global.VERDACCIO_API_URL = 'https://verdaccio.tld';
const customGlobal: GlobalWithFetchMock = global as GlobalWithFetchMock;
customGlobal.fetch = require('jest-fetch-mock');
customGlobal.fetchMock = customGlobal.fetch;

View File

@@ -3,7 +3,7 @@
*/
import { Base64 } from 'js-base64';
import addHours from 'date-fns/add_hours';
import addHours from 'date-fns/addHours';
export function generateTokenWithTimeRange(limit = 0) {
const payload = {

View File

@@ -1,6 +1,6 @@
{
"name": "@verdaccio/ui-theme",
"version": "0.3.4",
"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.5.1",
"@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.4.0",
"@typescript-eslint/parser": "2.7.0",
"@verdaccio/babel-preset": "8.2.0",
"@verdaccio/commons-api": "8.2.0",
"@verdaccio/eslint-config": "2.0.0",
"@verdaccio/types": "8.1.0",
"@verdaccio/commons-api": "8.3.0",
"@verdaccio/eslint-config": "8.2.0",
"@verdaccio/types": "8.3.0",
"autosuggest-highlight": "3.1.1",
"babel-loader": "8.0.6",
"bundlesize": "0.18.0",
@@ -45,20 +45,20 @@
"concurrently": "5.0.0",
"cross-env": "6.0.3",
"css-loader": "3.2.0",
"date-fns": "1.30.1",
"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",
"eslint": "6.5.1",
"eslint": "6.6.0",
"eslint-plugin-codeceptjs": "1.1.0",
"eslint-plugin-import": "2.18.2",
"eslint-plugin-jsx-a11y": "6.2.3",
"eslint-plugin-prettier": "3.1.0",
"eslint-plugin-react": "7.14.3",
"eslint-plugin-react-hooks": "2.0.1",
"eslint-plugin-verdaccio": "2.0.0",
"eslint-plugin-prettier": "3.1.1",
"eslint-plugin-react": "7.16.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",
"get-stdin": "7.0.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",
@@ -171,7 +170,6 @@
"lint:lockfile": "lockfile-lint --path yarn.lock --type yarn --validate-https --allowed-hosts verdaccio npm yarn",
"coverage:publish": "codecov",
"pre:webpack": "rimraf static/*",
"prepublish": "in-publish && npm run build || not-in-publish",
"dev:web": "cross-env BABEL_ENV=ui babel-node tools/dev.server.js",
"verdaccio:server": "node tools/verdaccio.js",
"build": "npm run pre:webpack && cross-env BABEL_ENV=ui webpack --config tools/webpack.prod.config.babel.js",
@@ -193,7 +191,7 @@
"relative": true,
"linters": {
"*.{js,tsx,ts}": [
"eslint .",
"eslint . --ext .js,.ts,.tsx",
"prettier --write"
],
"*": [
@@ -215,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"
}
}

View File

@@ -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>
</>
);
}
@@ -146,7 +147,14 @@ export default class App extends Component<{}, AppProps> {
public renderLoginModal = (): ReactElement<HTMLElement> => {
const { error, showLoginModal } = this.state;
return <LoginModal error={error} onCancel={this.handleToggleLoginModal} onSubmit={this.handleDoLogin} visibility={showLoginModal} />;
return (
<LoginModal
error={error}
onCancel={this.handleToggleLoginModal}
onSubmit={this.handleDoLogin}
visibility={showLoginModal}
/>
);
};
public renderContent = (): ReactElement<HTMLElement> => {
@@ -167,6 +175,14 @@ export default class App extends Component<{}, AppProps> {
scope,
} = this.state;
return <Header logo={logoUrl} onLogout={this.handleLogout} onToggleLoginModal={this.handleToggleLoginModal} scope={scope} username={username} />;
return (
<Header
logo={logoUrl}
onLogout={this.handleLogout}
onToggleLoginModal={this.handleToggleLoginModal}
scope={scope}
username={username}
/>
);
};
}

View File

@@ -20,7 +20,8 @@ export interface Action {
export async function downloadHandler(link: string): Promise<void> {
const fileStream: Blob = await api.request(link, 'GET', {
headers: {
['accept']: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
['accept']:
'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
},
credentials: 'include',
});

View File

@@ -2,6 +2,6 @@
exports[`<ActionBar /> component should render the component in default state 1`] = `""`;
exports[`<ActionBar /> component when there is a button to download a tarball 1`] = `"<ul class=\\"MuiList-root MuiList-padding\\"><div class=\\"MuiButtonBase-root MuiListItem-root css-1br2q5z eux6shq0 MuiListItem-gutters MuiListItem-button MuiListItem-alignItemsFlexStart\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><button class=\\"MuiButtonBase-root MuiFab-root css-96oxa0 eux6shq1 MuiFab-sizeSmall\\" tabindex=\\"0\\" type=\\"button\\" title=\\"Download tarball\\"><span class=\\"MuiFab-label\\"><svg class=\\"MuiSvgIcon-root\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM17 13l-5 5-5-5h3V9h4v4h3z\\"></path></svg></span><span class=\\"MuiTouchRipple-root\\"></span></button><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
exports[`<ActionBar /> component when there is a button to download a tarball 1`] = `"<ul class=\\"MuiList-root MuiList-padding\\"><div class=\\"MuiButtonBase-root MuiListItem-root css-1br2q5z eux6shq0 MuiListItem-gutters MuiListItem-button MuiListItem-alignItemsFlexStart\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><button class=\\"MuiButtonBase-root MuiFab-root css-z6z5me eux6shq1 MuiFab-sizeSmall\\" tabindex=\\"0\\" type=\\"button\\" title=\\"Download tarball\\"><span class=\\"MuiFab-label\\"><svg class=\\"MuiSvgIcon-root\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM17 13l-5 5-5-5h3V9h4v4h3z\\"></path></svg></span><span class=\\"MuiTouchRipple-root\\"></span></button><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
exports[`<ActionBar /> component when there is a button to open an issue 1`] = `"<ul class=\\"MuiList-root MuiList-padding\\"><div class=\\"MuiButtonBase-root MuiListItem-root css-1br2q5z eux6shq0 MuiListItem-gutters MuiListItem-button MuiListItem-alignItemsFlexStart\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><a href=\\"https://verdaccio.tld/bugs\\" target=\\"_blank\\"><button class=\\"MuiButtonBase-root MuiFab-root css-96oxa0 eux6shq1 MuiFab-sizeSmall\\" tabindex=\\"0\\" type=\\"button\\"><span class=\\"MuiFab-label\\"><svg class=\\"MuiSvgIcon-root\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5c-.49 0-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z\\"></path></svg></span><span class=\\"MuiTouchRipple-root\\"></span></button></a><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
exports[`<ActionBar /> component when there is a button to open an issue 1`] = `"<ul class=\\"MuiList-root MuiList-padding\\"><div class=\\"MuiButtonBase-root MuiListItem-root css-1br2q5z eux6shq0 MuiListItem-gutters MuiListItem-button MuiListItem-alignItemsFlexStart\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><a href=\\"https://verdaccio.tld/bugs\\" target=\\"_blank\\"><button class=\\"MuiButtonBase-root MuiFab-root css-z6z5me eux6shq1 MuiFab-sizeSmall\\" tabindex=\\"0\\" type=\\"button\\"><span class=\\"MuiFab-label\\"><svg class=\\"MuiSvgIcon-root\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5c-.49 0-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z\\"></path></svg></span><span class=\\"MuiTouchRipple-root\\"></span></button></a><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;

View File

@@ -1,8 +1,8 @@
import styled from 'react-emotion';
import { default as MuiFab } from '@material-ui/core/Fab';
import styled from '@emotion/styled';
import colors from '../../utils/styles/colors';
import ListItem from '../../muiComponents/ListItem';
import FloatingActionButton from '../../muiComponents/FloatingActionButton';
export const ActionListItem = styled(ListItem)({
paddingTop: 0,
@@ -10,10 +10,8 @@ export const ActionListItem = styled(ListItem)({
paddingRight: 0,
});
export const Fab = styled(MuiFab)({
'&&': {
backgroundColor: colors.primary,
color: colors.white,
marginRight: '10px',
},
export const Fab = styled(FloatingActionButton)({
backgroundColor: colors.primary,
color: colors.white,
marginRight: '10px',
});

View File

@@ -1,5 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Author /> component should render the component in default state 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-b8upko e1xuehjw0 MuiTypography-subtitle1\\">Author</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-xugzlj e1xuehjw1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><a href=\\"mailto:verdaccio.user@verdaccio.org?subject=verdaccio@4.0.0\\" target=\\"_top\\"><div class=\\"MuiAvatar-root\\"><img alt=\\"verdaccio user\\" src=\\"https://www.gravatar.com/avatar/000000\\" class=\\"MuiAvatar-img\\"></div></a><div class=\\"MuiListItemText-root css-1vhg3jx e1xuehjw2\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">verdaccio user</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
exports[`<Author /> component should render the component in default state 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-b8upko e1xuehjw0 MuiTypography-subtitle1\\">Author</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-zw46c6 e1xuehjw1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><a href=\\"mailto:verdaccio.user@verdaccio.org?subject=verdaccio@4.0.0\\" target=\\"_top\\"><div class=\\"MuiAvatar-root MuiAvatar-circle\\"><img alt=\\"verdaccio user\\" src=\\"https://www.gravatar.com/avatar/000000\\" class=\\"MuiAvatar-img\\"></div></a><div class=\\"MuiListItemText-root css-fipixf e1xuehjw2\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">verdaccio user</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
exports[`<Author /> component should render the component when there is no author email 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-b8upko e1xuehjw0 MuiTypography-subtitle1\\">Author</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-xugzlj e1xuehjw1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiAvatar-root\\"><img alt=\\"verdaccio user\\" src=\\"https://www.gravatar.com/avatar/000000\\" class=\\"MuiAvatar-img\\"></div><div class=\\"MuiListItemText-root css-1vhg3jx e1xuehjw2\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">verdaccio user</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
exports[`<Author /> component should render the component when there is no author email 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-b8upko e1xuehjw0 MuiTypography-subtitle1\\">Author</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-zw46c6 e1xuehjw1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiAvatar-root MuiAvatar-circle\\"><img alt=\\"verdaccio user\\" src=\\"https://www.gravatar.com/avatar/000000\\" class=\\"MuiAvatar-img\\"></div><div class=\\"MuiListItemText-root css-fipixf e1xuehjw2\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">verdaccio user</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;

View File

@@ -1,9 +1,9 @@
import styled from 'react-emotion';
import ListItemText from '@material-ui/core/ListItemText';
import styled from '@emotion/styled';
import { fontWeight } from '../../utils/styles/sizes';
import ListItem from '../../muiComponents/ListItem';
import Text from '../../muiComponents/Text';
import ListItemText from '../../muiComponents/ListItemText';
export const StyledText = styled(Text)({
fontWeight: fontWeight.bold,
@@ -11,17 +11,13 @@ export const StyledText = styled(Text)({
});
export const AuthorListItem = styled(ListItem)({
'&&': {
padding: 0,
},
'&&:hover': {
padding: 0,
':hover': {
backgroundColor: 'transparent',
},
});
export const AuthorListItemText = styled(ListItemText)({
'&&': {
padding: '0 10px',
margin: 0,
},
padding: '0 10px',
margin: 0,
});

View File

@@ -1,11 +1,10 @@
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';
import MenuItem from '@material-ui/core/MenuItem';
import { fontWeight } from '../../utils/styles/sizes';
import MenuItem from '../../muiComponents/MenuItem';
import { Wrapper, InputField, SuggestionContainer } from './styles';

View File

@@ -1,8 +1,9 @@
import React from 'react';
import styled, { css } from 'react-emotion';
import Paper from '@material-ui/core/Paper';
import styled from '@emotion/styled';
import { css } from '@emotion/core';
import TextField from '../../muiComponents/TextField';
import Paper from '../../muiComponents/Paper';
export interface InputFieldProps {
color: string;

View File

@@ -14,7 +14,12 @@ export interface AvatarDeveloper {
const AvatarTooltip: FC<AvatarDeveloper> = ({ name, packageName, version, avatar, email }) => {
const avatarComponent = <Avatar aria-label={name} src={avatar} />;
function renderLinkForMail(email: string, avatarComponent: JSX.Element, packageName: string, version: string): JSX.Element {
function renderLinkForMail(
email: string,
avatarComponent: JSX.Element,
packageName: string,
version: string
): JSX.Element {
if (!email || isEmail(email) === false) {
return avatarComponent;
}

View File

@@ -1,4 +1,4 @@
import styled from 'react-emotion';
import styled from '@emotion/styled';
import IconButton from '../../muiComponents/IconButton';

View File

@@ -1,7 +1,7 @@
import React, { useContext } from 'react';
import { useHistory } from 'react-router-dom';
import CardContent from '@material-ui/core/CardContent';
import CardContent from '../../muiComponents/CardContent';
import { PackageDependencies } from '../../../types/packageMeta';
import { DetailContext } from '../../pages/Version';
import NoItems from '../NoItems';

View File

@@ -1,14 +1,12 @@
import styled from 'react-emotion';
import Chip from '@material-ui/core/Chip';
import styled from '@emotion/styled';
import { fontWeight } from '../../utils/styles/sizes';
import Text from '../../muiComponents/Text';
import Card from '../../muiComponents/Card';
import Chip from '../../muiComponents/Chip';
export const CardWrap = styled(Card)({
'&&': {
margin: '0 0 16px',
},
margin: '0 0 16px',
});
export const StyledText = styled(Text)({
@@ -17,16 +15,12 @@ export const StyledText = styled(Text)({
});
export const Tags = styled('div')({
'&&': {
display: 'flex',
justifyContent: 'start',
flexWrap: 'wrap',
margin: '0 -5px',
},
display: 'flex',
justifyContent: 'start',
flexWrap: 'wrap',
margin: '0 -5px',
});
export const Tag = styled(Chip)({
'&&': {
margin: '5px',
},
margin: '5px',
});

View File

@@ -1,7 +1,7 @@
import React, { useCallback, useState, ChangeEvent, useContext } from 'react';
import Box from '@material-ui/core/Box';
import { DetailContext } from '../../pages/Version';
import Box from '../../muiComponents/Box';
import DetailContainerTabs from './DetailContainerTabs';
import DetailContainerContent from './DetailContainerContent';

View File

@@ -1,7 +1,8 @@
import React, { ChangeEvent, useState, useEffect } from 'react';
import { default as MuiTabs } from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
import styled from 'react-emotion';
import styled from '@emotion/styled';
import { default as MuiTabs } from '../../muiComponents/Tabs';
import Tab from '../../muiComponents/Tab';
import { TabPosition } from './tabs';
@@ -14,7 +15,8 @@ const Tabs = styled(MuiTabs)({
marginBottom: 16,
});
const getTabIndex = (tabPosition: TabPosition): number => Object.keys(TabPosition).findIndex(position => position === String(tabPosition).toUpperCase());
const getTabIndex = (tabPosition: TabPosition): number =>
Object.keys(TabPosition).findIndex(position => position === String(tabPosition).toUpperCase());
const DetailContainerTabs: React.FC<Props> = ({ tabPosition, onChangeTabPosition }) => {
const [tabPositionIndex, setTabPositionIndex] = useState(0);
@@ -25,7 +27,12 @@ const DetailContainerTabs: React.FC<Props> = ({ tabPosition, onChangeTabPosition
}, [tabPosition]);
return (
<Tabs indicatorColor={'primary'} onChange={onChangeTabPosition} textColor={'primary'} value={tabPositionIndex} variant={'fullWidth'}>
<Tabs
indicatorColor={'primary'}
onChange={onChangeTabPosition}
textColor={'primary'}
value={tabPositionIndex}
variant={'fullWidth'}>
<Tab data-testid={'readme-tab'} id={'readme-tab'} label={TabPosition.README} />
<Tab data-testid={'dependencies-tab'} id={'dependencies-tab'} label={TabPosition.DEPENDENCIES} />
<Tab data-testid={'versions-tab'} id={'versions-tab'} label={TabPosition.VERSIONS} />

View File

@@ -1,5 +1,4 @@
import React, { ReactElement } from 'react';
import CardContent from '@material-ui/core/CardContent';
import { ActionBar } from '../ActionBar/ActionBar';
import Author from '../Author';
@@ -11,10 +10,11 @@ import Repository from '../Repository/Repository';
import { DetailContext } from '../../pages/Version';
import List from '../../muiComponents/List';
import Card from '../../muiComponents/Card';
import CardContent from '../../muiComponents/CardContent';
import { TitleListItem, TitleListItemText, PackageDescription, PackageVersion } from './styles';
const renderLatestDescription = (description, version, isLatest: boolean = true): JSX.Element => {
const renderLatestDescription = (description, version, isLatest = true): JSX.Element => {
return (
<>
<PackageDescription>{description}</PackageDescription>
@@ -42,7 +42,10 @@ const renderTitle = (packageName, packageVersion, packageMeta): JSX.Element => {
return (
<List className="detail-info">
<TitleListItem alignItems="flex-start" button={true}>
<TitleListItemText primary={<b>{packageName}</b>} secondary={renderLatestDescription(packageMeta.latest.description, version, isLatest)} />
<TitleListItemText
primary={<b>{packageName}</b>}
secondary={renderLatestDescription(packageMeta.latest.description, version, isLatest)}
/>
</TitleListItem>
</List>
);

View File

@@ -1,7 +1,7 @@
import styled from 'react-emotion';
import ListItemText from '@material-ui/core/ListItemText';
import styled from '@emotion/styled';
import ListItem from '../../muiComponents/ListItem';
import ListItemText from '../../muiComponents/ListItemText';
export const TitleListItem = styled(ListItem)({
paddingLeft: 0,
@@ -10,21 +10,15 @@ export const TitleListItem = styled(ListItem)({
});
export const TitleListItemText = styled(ListItemText)({
'&&': {
paddingLeft: 0,
paddingRight: 0,
paddingTop: '8px',
},
paddingLeft: 0,
paddingRight: 0,
paddingTop: '8px',
});
export const PackageDescription = styled('span')({
'&&': {
display: 'block',
},
display: 'block',
});
export const PackageVersion = styled('span')({
'&&': {
display: 'block',
},
display: 'block',
});

View File

@@ -122,15 +122,18 @@ exports[`test Developers should render the component for contributors with items
aria-label="dmethvin"
classes={
Object {
"circle": "MuiAvatar-circle",
"colorDefault": "MuiAvatar-colorDefault",
"img": "MuiAvatar-img",
"root": "MuiAvatar-root",
"rounded": "MuiAvatar-rounded",
"square": "MuiAvatar-square",
}
}
>
<div
aria-label="dmethvin"
className="MuiAvatar-root MuiAvatar-colorDefault"
className="MuiAvatar-root MuiAvatar-circle MuiAvatar-colorDefault"
/>
</ForwardRef(Avatar)>
</WithStyles(ForwardRef(Avatar))>
@@ -146,7 +149,7 @@ exports[`test Developers should render the component for contributors with items
>
<div
aria-label="dmethvin"
class="MuiAvatar-root MuiAvatar-colorDefault"
class="MuiAvatar-root MuiAvatar-circle MuiAvatar-colorDefault"
/>
</a>
}
@@ -218,15 +221,18 @@ exports[`test Developers should render the component for contributors with items
aria-label="mgol"
classes={
Object {
"circle": "MuiAvatar-circle",
"colorDefault": "MuiAvatar-colorDefault",
"img": "MuiAvatar-img",
"root": "MuiAvatar-root",
"rounded": "MuiAvatar-rounded",
"square": "MuiAvatar-square",
}
}
>
<div
aria-label="mgol"
className="MuiAvatar-root MuiAvatar-colorDefault"
className="MuiAvatar-root MuiAvatar-circle MuiAvatar-colorDefault"
/>
</ForwardRef(Avatar)>
</WithStyles(ForwardRef(Avatar))>
@@ -242,7 +248,7 @@ exports[`test Developers should render the component for contributors with items
>
<div
aria-label="mgol"
class="MuiAvatar-root MuiAvatar-colorDefault"
class="MuiAvatar-root MuiAvatar-circle MuiAvatar-colorDefault"
/>
</a>
}
@@ -385,15 +391,18 @@ exports[`test Developers should render the component for maintainers with items
aria-label="dmethvin"
classes={
Object {
"circle": "MuiAvatar-circle",
"colorDefault": "MuiAvatar-colorDefault",
"img": "MuiAvatar-img",
"root": "MuiAvatar-root",
"rounded": "MuiAvatar-rounded",
"square": "MuiAvatar-square",
}
}
>
<div
aria-label="dmethvin"
className="MuiAvatar-root MuiAvatar-colorDefault"
className="MuiAvatar-root MuiAvatar-circle MuiAvatar-colorDefault"
/>
</ForwardRef(Avatar)>
</WithStyles(ForwardRef(Avatar))>
@@ -409,7 +418,7 @@ exports[`test Developers should render the component for maintainers with items
>
<div
aria-label="dmethvin"
class="MuiAvatar-root MuiAvatar-colorDefault"
class="MuiAvatar-root MuiAvatar-circle MuiAvatar-colorDefault"
/>
</a>
}
@@ -481,15 +490,18 @@ exports[`test Developers should render the component for maintainers with items
aria-label="mgol"
classes={
Object {
"circle": "MuiAvatar-circle",
"colorDefault": "MuiAvatar-colorDefault",
"img": "MuiAvatar-img",
"root": "MuiAvatar-root",
"rounded": "MuiAvatar-rounded",
"square": "MuiAvatar-square",
}
}
>
<div
aria-label="mgol"
className="MuiAvatar-root MuiAvatar-colorDefault"
className="MuiAvatar-root MuiAvatar-circle MuiAvatar-colorDefault"
/>
</ForwardRef(Avatar)>
</WithStyles(ForwardRef(Avatar))>
@@ -505,7 +517,7 @@ exports[`test Developers should render the component for maintainers with items
>
<div
aria-label="mgol"
class="MuiAvatar-root MuiAvatar-colorDefault"
class="MuiAvatar-root MuiAvatar-circle MuiAvatar-colorDefault"
/>
</a>
}

View File

@@ -1,9 +1,9 @@
import styled from 'react-emotion';
import { default as MuiFab } from '@material-ui/core/Fab';
import styled from '@emotion/styled';
import colors from '../../utils/styles/colors';
import { fontWeight } from '../../utils/styles/sizes';
import Text from '../../muiComponents/Text';
import FloatingActionButton from '../../muiComponents/FloatingActionButton';
export const Details = styled('span')({
display: 'flex',
@@ -26,9 +26,7 @@ export const StyledText = styled(Text)({
textTransform: 'capitalize',
});
export const Fab = styled(MuiFab)({
'&&': {
backgroundColor: colors.primary,
color: colors.white,
},
export const Fab = styled(FloatingActionButton)({
backgroundColor: colors.primary,
color: colors.white,
});

View File

@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Dist /> component should render the component in default state 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-b8upko estxrtg0 MuiTypography-subtitle1\\">Latest Distribution</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-z8a2h0 estxrtg1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiChip-root css-1le6jk6 estxrtg2\\"><span class=\\"MuiChip-label\\"><b>file count</b>: 7</span></div><div class=\\"MuiChip-root css-1le6jk6 estxrtg2\\"><span class=\\"MuiChip-label\\"><b>size</b>: 10.00 Bytes</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
exports[`<Dist /> component should render the component in default state 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-b8upko estxrtg0 MuiTypography-subtitle1\\">Latest Distribution</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-1huthg8 estxrtg1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiChip-root css-42zb18 estxrtg2\\"><span class=\\"MuiChip-label\\"><b>file count</b>: 7</span></div><div class=\\"MuiChip-root css-42zb18 estxrtg2\\"><span class=\\"MuiChip-label\\"><b>size</b>: 10.00 Bytes</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
exports[`<Dist /> component should render the component with license as object 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-b8upko estxrtg0 MuiTypography-subtitle1\\">Latest Distribution</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-z8a2h0 estxrtg1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiChip-root css-1le6jk6 estxrtg2\\"><span class=\\"MuiChip-label\\"><b>file count</b>: 7</span></div><div class=\\"MuiChip-root css-1le6jk6 estxrtg2\\"><span class=\\"MuiChip-label\\"><b>size</b>: 10.00 Bytes</span></div><div class=\\"MuiChip-root css-1le6jk6 estxrtg2\\"><span class=\\"MuiChip-label\\"><b>license</b>: MIT</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
exports[`<Dist /> component should render the component with license as object 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-b8upko estxrtg0 MuiTypography-subtitle1\\">Latest Distribution</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-1huthg8 estxrtg1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiChip-root css-42zb18 estxrtg2\\"><span class=\\"MuiChip-label\\"><b>file count</b>: 7</span></div><div class=\\"MuiChip-root css-42zb18 estxrtg2\\"><span class=\\"MuiChip-label\\"><b>size</b>: 10.00 Bytes</span></div><div class=\\"MuiChip-root css-42zb18 estxrtg2\\"><span class=\\"MuiChip-label\\"><b>license</b>: MIT</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
exports[`<Dist /> component should render the component with license as string 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-b8upko estxrtg0 MuiTypography-subtitle1\\">Latest Distribution</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-z8a2h0 estxrtg1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiChip-root css-1le6jk6 estxrtg2\\"><span class=\\"MuiChip-label\\"><b>file count</b>: 7</span></div><div class=\\"MuiChip-root css-1le6jk6 estxrtg2\\"><span class=\\"MuiChip-label\\"><b>size</b>: 10.00 Bytes</span></div><div class=\\"MuiChip-root css-1le6jk6 estxrtg2\\"><span class=\\"MuiChip-label\\"><b>license</b>: MIT</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
exports[`<Dist /> component should render the component with license as string 1`] = `"<ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-b8upko estxrtg0 MuiTypography-subtitle1\\">Latest Distribution</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-1huthg8 estxrtg1 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiChip-root css-42zb18 estxrtg2\\"><span class=\\"MuiChip-label\\"><b>file count</b>: 7</span></div><div class=\\"MuiChip-root css-42zb18 estxrtg2\\"><span class=\\"MuiChip-label\\"><b>size</b>: 10.00 Bytes</span></div><div class=\\"MuiChip-root css-42zb18 estxrtg2\\"><span class=\\"MuiChip-label\\"><b>license</b>: MIT</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;

View File

@@ -1,11 +1,11 @@
import styled from 'react-emotion';
import { default as MuiFab } from '@material-ui/core/Fab';
import Chip from '@material-ui/core/Chip';
import styled from '@emotion/styled';
import colors from '../../utils/styles/colors';
import { fontWeight } from '../../utils/styles/sizes';
import ListItem from '../../muiComponents/ListItem';
import Text from '../../muiComponents/Text';
import FloatingActionButton from '../../muiComponents/FloatingActionButton';
import Chip from '../../muiComponents/Chip';
export const StyledText = styled(Text)({
fontWeight: fontWeight.bold,
@@ -13,22 +13,16 @@ export const StyledText = styled(Text)({
});
export const DistListItem = styled(ListItem)({
'&&': {
paddingLeft: 0,
paddingRight: 0,
},
paddingLeft: 0,
paddingRight: 0,
});
export const DistChips = styled(Chip)({
'&&': {
marginRight: '5px',
textTransform: 'capitalize',
},
marginRight: '5px',
textTransform: 'capitalize',
});
export const DownloadButton = styled(MuiFab)({
'&&': {
backgroundColor: colors.primary,
color: colors.white,
},
export const DownloadButton = styled(FloatingActionButton)({
backgroundColor: colors.primary,
color: colors.white,
});

View File

@@ -1,71 +1,61 @@
import React from 'react';
import { mount } from 'enzyme';
import { DetailContext } from '../../pages/Version';
import { PackageMetaInterface } from '../../../types/packageMeta';
import Engine from './Engines';
jest.mock('./img/node.png', () => '');
jest.mock('../Install/img/npm.svg', () => '');
const mockPackageMeta: jest.Mock = jest.fn(() => ({
const mockPackageMeta = (engines?: PackageMetaInterface['latest']['engines']): PackageMetaInterface => ({
latest: {
homepage: 'https://verdaccio.tld',
bugs: {
url: 'https://verdaccio.tld/bugs',
},
name: 'verdaccio',
version: '0.0.0',
dist: {
tarball: 'https://verdaccio.tld/download',
fileCount: 1,
unpackedSize: 1,
},
...(engines && { engines }),
},
}));
jest.mock('../../pages/Version', () => ({
DetailContextConsumer: component => {
return component.children({ packageMeta: mockPackageMeta() });
},
}));
_uplinks: {},
});
describe('<Engines /> component', () => {
beforeEach(() => {
jest.resetAllMocks();
});
test('should render the component in default state', () => {
const packageMeta = {
latest: {
engines: {
node: '>= 0.1.98',
npm: '>3',
},
},
};
const packageMeta = mockPackageMeta({
node: '>= 0.1.98',
npm: '>3',
});
mockPackageMeta.mockImplementation(() => packageMeta);
const wrapper = mount(<Engine />);
const wrapper = mount(
<DetailContext.Provider value={{ packageMeta }}>
<Engine />
</DetailContext.Provider>
);
expect(wrapper.html()).toMatchSnapshot();
});
test('should render the component when there is no engine key in package meta', () => {
const packageMeta = {
latest: {},
};
const packageMeta = mockPackageMeta();
mockPackageMeta.mockImplementation(() => packageMeta);
const wrapper = mount(<Engine />);
expect(wrapper.html()).toEqual('');
const wrapper = mount(
<DetailContext.Provider value={{ packageMeta }}>
<Engine />
</DetailContext.Provider>
);
expect(wrapper.html()).toBeNull();
});
test('should render the component when there is no keys in engine in package meta', () => {
const packageMeta = {
latest: {
engines: {},
},
};
const packageMeta = mockPackageMeta({});
mockPackageMeta.mockImplementation(() => packageMeta);
const wrapper = mount(<Engine />);
expect(wrapper.html()).toEqual('');
const wrapper = mount(
<DetailContext.Provider value={{ packageMeta }}>
<Engine />
</DetailContext.Provider>
);
expect(wrapper.html()).toBeNull();
});
});

View File

@@ -1,73 +1,51 @@
import React, { Component, ReactElement } from 'react';
import Grid from '@material-ui/core/Grid';
import ListItemText from '@material-ui/core/ListItemText';
import React, { useContext } from 'react';
import { VersionPageConsumerProps, DetailContextConsumer } from '../../pages/Version';
import { DetailContext } from '../../pages/Version';
import Avatar from '../../muiComponents/Avatar';
import List from '../../muiComponents/List';
import npm from '../Install/img/npm.svg';
import ListItemText from '../../muiComponents/ListItemText';
import Grid from '../../muiComponents/Grid';
import { StyledText, EngineListItem } from './styles';
// @ts-ignore
import node from './img/node.png';
const ICONS = {
'node-JS': <Avatar src={node} />,
'NPM-version': <Avatar src={npm} />,
};
const Engine: React.FC = () => {
const { packageMeta } = useContext(DetailContext);
class Engine extends Component {
public render(): ReactElement<HTMLElement> {
return (
<DetailContextConsumer>
{context => {
return this.renderEngine(context as VersionPageConsumerProps);
}}
</DetailContextConsumer>
);
const engines = packageMeta && packageMeta.latest && packageMeta.latest.engines;
if (!engines || (!engines.node && !engines.npm)) {
return null;
}
private renderEngine = ({ packageMeta }): ReactElement<HTMLElement> | null => {
const { engines } = packageMeta.latest;
if (!engines) {
return null;
}
/* eslint-disable react/jsx-max-depth */
return (
<Grid container={true}>
{engines.node && (
<Grid item={true} xs={6}>
<List subheader={<StyledText variant={'subtitle1'}>{'node JS'}</StyledText>}>
<EngineListItem button={true}>
<Avatar src={node} />
<ListItemText primary={engines.node} />
</EngineListItem>
</List>
</Grid>
)}
const engineDict = {
'node-JS': engines.node,
'NPM-version': engines.npm,
};
const accumulator: React.ReactNode[] = [];
const items = Object.keys(engineDict).reduce((markup, text, key) => {
const heading = engineDict[text];
if (heading) {
markup.push(
<Grid item={true} key={key} xs={6}>
{this.renderListItems(heading, text)}
</Grid>
);
}
return markup;
}, accumulator);
if (items.length < 1) {
return null;
}
return <Grid container={true}>{items}</Grid>;
};
private renderListItems = (heading: string, text: string) => {
return (
<List subheader={<StyledText variant={'subtitle1'}>{text.split('-').join(' ')}</StyledText>}>
<EngineListItem button={true}>
{ICONS[text]}
<ListItemText primary={heading} />
</EngineListItem>
</List>
);
};
}
{engines.npm && (
<Grid item={true} xs={6}>
<List subheader={<StyledText variant={'subtitle1'}>{'NPM version'}</StyledText>}>
<EngineListItem button={true}>
<Avatar src={npm} />
<ListItemText primary={engines.npm} />
</EngineListItem>
</List>
</Grid>
)}
</Grid>
);
/* eslint-enable react/jsx-max-depth */
};
export default Engine;

View File

@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Engines /> component should render the component in default state 1`] = `"<div class=\\"MuiGrid-root MuiGrid-container\\"><div class=\\"MuiGrid-root MuiGrid-item MuiGrid-grid-xs-6\\"><ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-b8upko et66bt70 MuiTypography-subtitle1\\">node JS</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-131yq1t et66bt71 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiAvatar-root MuiAvatar-colorDefault\\"></div><div class=\\"MuiListItemText-root\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">&gt;= 0.1.98</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul></div><div class=\\"MuiGrid-root MuiGrid-item MuiGrid-grid-xs-6\\"><ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-b8upko et66bt70 MuiTypography-subtitle1\\">NPM version</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-131yq1t et66bt71 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiAvatar-root MuiAvatar-colorDefault\\"></div><div class=\\"MuiListItemText-root\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">&gt;3</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul></div></div>"`;
exports[`<Engines /> component should render the component in default state 1`] = `"<div class=\\"MuiGrid-root MuiGrid-container\\"><div class=\\"MuiGrid-root MuiGrid-item MuiGrid-grid-xs-6\\"><ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-b8upko et66bt70 MuiTypography-subtitle1\\">node JS</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-131yq1t et66bt71 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiAvatar-root MuiAvatar-circle MuiAvatar-colorDefault\\"></div><div class=\\"MuiListItemText-root\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">&gt;= 0.1.98</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul></div><div class=\\"MuiGrid-root MuiGrid-item MuiGrid-grid-xs-6\\"><ul class=\\"MuiList-root MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-b8upko et66bt70 MuiTypography-subtitle1\\">NPM version</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-131yq1t et66bt71 MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiAvatar-root MuiAvatar-circle MuiAvatar-colorDefault\\"></div><div class=\\"MuiListItemText-root\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">&gt;3</span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul></div></div>"`;

View File

@@ -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';

View File

@@ -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>"`;

View File

@@ -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';

View File

@@ -17,7 +17,11 @@ describe('<Header /> component with logged in state', () => {
test('should load the component in logged out state', () => {
const { container, queryByTestId, getByText } = render(
<Router>
<Header onLogout={headerProps.handleLogout} onToggleLoginModal={headerProps.handleToggleLoginModal} scope={headerProps.scope} />
<Header
onLogout={headerProps.handleLogout}
onToggleLoginModal={headerProps.handleToggleLoginModal}
scope={headerProps.scope}
/>
</Router>
);
@@ -46,7 +50,11 @@ describe('<Header /> component with logged in state', () => {
test('should open login dialog', async () => {
const { getByText } = render(
<Router>
<Header onLogout={headerProps.handleLogout} onToggleLoginModal={headerProps.handleToggleLoginModal} scope={headerProps.scope} />
<Header
onLogout={headerProps.handleLogout}
onToggleLoginModal={headerProps.handleToggleLoginModal}
scope={headerProps.scope}
/>
</Router>
);
@@ -131,7 +139,9 @@ describe('<Header /> component with logged in state', () => {
const closeBtn = await waitForElement(() => getByText('CLOSE'));
fireEvent.click(closeBtn);
const hasRegistrationInfoModalBeenRemoved = await waitForElementToBeRemoved(() => queryByTestId('registryInfo--dialog'));
const hasRegistrationInfoModalBeenRemoved = await waitForElementToBeRemoved(() =>
queryByTestId('registryInfo--dialog')
);
expect(hasRegistrationInfoModalBeenRemoved).toBeTruthy();
});
test.todo('autocompletion should display suggestions according to the type value');

View File

@@ -38,14 +38,21 @@ const Header: React.FC<Props> = ({ logo, withoutSearch, username, onLogout, onTo
withoutSearch={withoutSearch}
/>
</InnerNavBar>
<HeaderInfoDialog isOpen={isInfoDialogOpen} onCloseDialog={() => setOpenInfoDialog(false)} registryUrl={getRegistryURL()} scope={scope} />
<HeaderInfoDialog
isOpen={isInfoDialogOpen}
onCloseDialog={() => setOpenInfoDialog(false)}
registryUrl={getRegistryURL()}
scope={scope}
/>
</NavBar>
{showMobileNavBar && !withoutSearch && (
<MobileNavBar>
<InnerMobileNavBar>
<Search />
</InnerMobileNavBar>
<Button color="inherit">{'Cancel'}</Button>
<Button color="inherit" onClick={() => setShowMobileNavBar(false)}>
{'Cancel'}
</Button>
</MobileNavBar>
)}
</>

View File

@@ -1,9 +1,9 @@
import React, { MouseEvent } from 'react';
import MenuItem from '@material-ui/core/MenuItem';
import Menu from '@material-ui/core/Menu';
import AccountCircle from '@material-ui/icons/AccountCircle';
import IconButton from '../../muiComponents/IconButton';
import MenuItem from '../../muiComponents/MenuItem';
import Menu from '../../muiComponents/Menu';
import HeaderGreetings from './HeaderGreetings';
@@ -17,9 +17,20 @@ interface Props {
}
/* eslint-disable react/jsx-max-depth */
const HeaderMenu: React.FC<Props> = ({ onLogout, username, isMenuOpen = false, anchorEl, onLoggedInMenu, onLoggedInMenuClose }) => (
const HeaderMenu: React.FC<Props> = ({
onLogout,
username,
isMenuOpen = false,
anchorEl,
onLoggedInMenu,
onLoggedInMenuClose,
}) => (
<>
<IconButton color="inherit" data-testid="header--menu-acountcircle" id="header--button-account" onClick={onLoggedInMenu}>
<IconButton
color="inherit"
data-testid="header--menu-acountcircle"
id="header--button-account"
onClick={onLoggedInMenu}>
<AccountCircle />
</IconButton>
<Menu
@@ -28,7 +39,6 @@ const HeaderMenu: React.FC<Props> = ({ onLogout, username, isMenuOpen = false, a
vertical: 'top',
horizontal: 'right',
}}
id="header--button-account"
onClose={onLoggedInMenuClose}
open={isMenuOpen}
transformOrigin={{
@@ -38,7 +48,7 @@ const HeaderMenu: React.FC<Props> = ({ onLogout, username, isMenuOpen = false, a
<MenuItem disabled={true}>
<HeaderGreetings username={username} />
</MenuItem>
<MenuItem id="header--button-logout" onClick={onLogout}>
<MenuItem button={true} id="header--button-logout" onClick={onLogout}>
{'Logout'}
</MenuItem>
</Menu>

View File

@@ -15,7 +15,14 @@ interface Props {
onLogout: () => void;
}
const HeaderRight: React.FC<Props> = ({ withoutSearch = false, username, onToggleLogin, onLogout, onToggleMobileNav, onOpenRegistryInfoDialog }) => {
const HeaderRight: React.FC<Props> = ({
withoutSearch = false,
username,
onToggleLogin,
onLogout,
onToggleMobileNav,
onOpenRegistryInfoDialog,
}) => {
const [anchorEl, setAnchorEl] = useState();
const [isMenuOpen, setIsMenuOpen] = useState();
@@ -47,7 +54,9 @@ const HeaderRight: React.FC<Props> = ({ withoutSearch = false, username, onToggl
return (
<RightSide>
{!withoutSearch && <HeaderToolTip onClick={onToggleMobileNav} title={'Search packages'} tooltipIconType={'search'} />}
{!withoutSearch && (
<HeaderToolTip onClick={onToggleMobileNav} title={'Search packages'} tooltipIconType={'search'} />
)}
<HeaderToolTip title={'Documentation'} tooltipIconType={'help'} />
<HeaderToolTip onClick={onOpenRegistryInfoDialog} title={'Registry Information'} tooltipIconType={'info'} />
{username ? (

View File

@@ -1,32 +1,46 @@
import React from 'react';
import React, { forwardRef } from 'react';
import Info from '@material-ui/icons/Info';
import Help from '@material-ui/icons/Help';
import Search from '@material-ui/icons/Search';
import IconButton from '../../muiComponents/IconButton';
import { IconSearchButton, StyledExternalLink } from './styles';
import { IconSearchButton, StyledLink } from './styles';
export type TooltipIconType = 'search' | 'help' | 'info';
interface Props {
tooltipIconType: TooltipIconType;
onClick?: () => void;
}
const HeaderToolTipIcon: React.FC<Props> = ({ tooltipIconType, onClick }) => {
type HeaderToolTipIconRef = HTMLButtonElement;
/* eslint-disable react/jsx-no-undef */
/* eslint-disable react/display-name */
const HeaderToolTipIcon = forwardRef<HeaderToolTipIconRef, Props>(function HeaderToolTipIcon(
{ tooltipIconType, onClick },
ref
) {
switch (tooltipIconType) {
case 'help':
return (
<StyledExternalLink blank={true} data-testid={'header--tooltip-documentation'} to={'https://verdaccio.org/docs/en/installation'}>
<StyledLink
data-testid={'header--tooltip-documentation'}
external={true}
to={'https://verdaccio.org/docs/en/installation'}>
<IconButton color={'inherit'}>
<Help />
</IconButton>
</StyledExternalLink>
</StyledLink>
);
case 'info':
return (
<IconButton color="inherit" data-testid={'header--tooltip-info'} id="header--button-registryInfo" onClick={onClick}>
<IconButton
color="inherit"
data-testid={'header--tooltip-info'}
id="header--button-registryInfo"
onClick={onClick}
ref={ref}>
<Info />
</IconButton>
);
@@ -39,6 +53,6 @@ const HeaderToolTipIcon: React.FC<Props> = ({ tooltipIconType, onClick }) => {
default:
return null;
}
};
});
export default HeaderToolTipIcon;

View File

@@ -5,10 +5,10 @@ exports[`<Header /> component with logged in state should load the component in
class="MuiPaper-root MuiPaper-elevation4 MuiAppBar-root MuiAppBar-positionStatic css-rfunvc emotion-9 MuiAppBar-colorPrimary"
>
<div
class="MuiToolbar-root MuiToolbar-regular css-1pwdmmq emotion-8 MuiToolbar-gutters"
class="MuiToolbar-root MuiToolbar-regular css-1bjere7 emotion-8 MuiToolbar-gutters"
>
<div
class="MuiToolbar-root MuiToolbar-regular css-1vacr9s emotion-4 MuiToolbar-gutters"
class="MuiToolbar-root MuiToolbar-regular css-i5xjw9 emotion-4 MuiToolbar-gutters"
>
<a
class="css-1dk30lc"
@@ -19,7 +19,7 @@ exports[`<Header /> component with logged in state should load the component in
/>
</a>
<div
class="css-13zpdre emotion-3"
class="css-12prohx emotion-3"
>
<div
class="css-1crzyyo emotion-2"
@@ -40,7 +40,7 @@ exports[`<Header /> component with logged in state should load the component in
class="MuiInputBase-root MuiInput-root css-n9ojyg MuiInput-underline MuiInputBase-fullWidth MuiInput-fullWidth MuiInputBase-formControl MuiInput-formControl MuiInputBase-adornedStart"
>
<div
class="MuiInputAdornment-root css-16qv2i2 MuiInputAdornment-positionStart"
class="MuiInputAdornment-root css-fvu7gn MuiInputAdornment-positionStart"
>
<svg
aria-hidden="true"
@@ -74,10 +74,10 @@ exports[`<Header /> component with logged in state should load the component in
</div>
</div>
<div
class="MuiToolbar-root MuiToolbar-regular css-m61s5i emotion-7 MuiToolbar-gutters"
class="MuiToolbar-root MuiToolbar-regular css-1qii1b7 emotion-7 MuiToolbar-gutters"
>
<button
class="MuiButtonBase-root MuiIconButton-root css-1y1xi9f emotion-5 MuiIconButton-colorInherit"
class="MuiButtonBase-root MuiIconButton-root css-13o7eu2 emotion-5 MuiIconButton-colorInherit"
tabindex="0"
type="button"
>
@@ -101,35 +101,40 @@ exports[`<Header /> component with logged in state should load the component in
/>
</button>
<a
class="css-1aacqdd emotion-6"
class="css-kbn7if emotion-6"
data-testid="header--tooltip-documentation"
href="https://verdaccio.org/docs/en/installation"
rel="noopener noreferrer"
target="_blank"
>
<button
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit"
tabindex="0"
type="button"
<h6
class="MuiTypography-root MuiTypography-subtitle1"
>
<span
class="MuiIconButton-label"
<button
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit"
tabindex="0"
type="button"
>
<svg
aria-hidden="true"
class="MuiSvgIcon-root"
focusable="false"
role="presentation"
viewBox="0 0 24 24"
<span
class="MuiIconButton-label"
>
<path
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"
/>
</svg>
</span>
<span
class="MuiTouchRipple-root"
/>
</button>
<svg
aria-hidden="true"
class="MuiSvgIcon-root"
focusable="false"
role="presentation"
viewBox="0 0 24 24"
>
<path
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"
/>
</svg>
</span>
<span
class="MuiTouchRipple-root"
/>
</button>
</h6>
</a>
<button
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit"
@@ -193,10 +198,10 @@ exports[`<Header /> component with logged in state should load the component in
class="MuiPaper-root MuiPaper-elevation4 MuiAppBar-root MuiAppBar-positionStatic css-rfunvc emotion-9 MuiAppBar-colorPrimary"
>
<div
class="MuiToolbar-root MuiToolbar-regular css-1pwdmmq emotion-8 MuiToolbar-gutters"
class="MuiToolbar-root MuiToolbar-regular css-1bjere7 emotion-8 MuiToolbar-gutters"
>
<div
class="MuiToolbar-root MuiToolbar-regular css-1vacr9s emotion-4 MuiToolbar-gutters"
class="MuiToolbar-root MuiToolbar-regular css-i5xjw9 emotion-4 MuiToolbar-gutters"
>
<a
class="css-1dk30lc"
@@ -207,7 +212,7 @@ exports[`<Header /> component with logged in state should load the component in
/>
</a>
<div
class="css-13zpdre emotion-3"
class="css-12prohx emotion-3"
>
<div
class="css-1crzyyo emotion-2"
@@ -228,7 +233,7 @@ exports[`<Header /> component with logged in state should load the component in
class="MuiInputBase-root MuiInput-root css-n9ojyg MuiInput-underline MuiInputBase-fullWidth MuiInput-fullWidth MuiInputBase-formControl MuiInput-formControl MuiInputBase-adornedStart"
>
<div
class="MuiInputAdornment-root css-16qv2i2 MuiInputAdornment-positionStart"
class="MuiInputAdornment-root css-fvu7gn MuiInputAdornment-positionStart"
>
<svg
aria-hidden="true"
@@ -262,10 +267,10 @@ exports[`<Header /> component with logged in state should load the component in
</div>
</div>
<div
class="MuiToolbar-root MuiToolbar-regular css-m61s5i emotion-7 MuiToolbar-gutters"
class="MuiToolbar-root MuiToolbar-regular css-1qii1b7 emotion-7 MuiToolbar-gutters"
>
<button
class="MuiButtonBase-root MuiIconButton-root css-1y1xi9f emotion-5 MuiIconButton-colorInherit"
class="MuiButtonBase-root MuiIconButton-root css-13o7eu2 emotion-5 MuiIconButton-colorInherit"
tabindex="0"
type="button"
>
@@ -289,35 +294,40 @@ exports[`<Header /> component with logged in state should load the component in
/>
</button>
<a
class="css-1aacqdd emotion-6"
class="css-kbn7if emotion-6"
data-testid="header--tooltip-documentation"
href="https://verdaccio.org/docs/en/installation"
rel="noopener noreferrer"
target="_blank"
>
<button
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit"
tabindex="0"
type="button"
<h6
class="MuiTypography-root MuiTypography-subtitle1"
>
<span
class="MuiIconButton-label"
<button
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit"
tabindex="0"
type="button"
>
<svg
aria-hidden="true"
class="MuiSvgIcon-root"
focusable="false"
role="presentation"
viewBox="0 0 24 24"
<span
class="MuiIconButton-label"
>
<path
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"
/>
</svg>
</span>
<span
class="MuiTouchRipple-root"
/>
</button>
<svg
aria-hidden="true"
class="MuiSvgIcon-root"
focusable="false"
role="presentation"
viewBox="0 0 24 24"
>
<path
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"
/>
</svg>
</span>
<span
class="MuiTouchRipple-root"
/>
</button>
</h6>
</a>
<button
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit"

View File

@@ -1,72 +1,57 @@
import styled, { css } from 'react-emotion';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import styled from '@emotion/styled';
import { css } from '@emotion/core';
import colors from '../../utils/styles/colors';
import mq from '../../utils/styles/media';
import IconButton from '../../muiComponents/IconButton';
import ExternalLink from '../Link';
import AppBar from '../../muiComponents/AppBar';
import Toolbar from '../../muiComponents/Toolbar';
import Link from '../Link';
export const InnerNavBar = styled(Toolbar)({
'&&': {
justifyContent: 'space-between',
alignItems: 'center',
padding: '0 15px',
},
justifyContent: 'space-between',
alignItems: 'center',
padding: '0 15px',
});
export const Greetings = styled('span')({
'&&': {
margin: '0 5px 0 0',
},
margin: '0 5px 0 0',
});
export const RightSide = styled(Toolbar)({
'&&': {
display: 'flex',
padding: 0,
},
display: 'flex',
padding: 0,
});
export const LeftSide = styled(RightSide)({
'&&': {
flex: 1,
},
flex: 1,
});
export const MobileNavBar = styled('div')({
'&&': {
alignItems: 'center',
display: 'flex',
borderBottom: `1px solid ${colors.greyLight}`,
padding: '8px',
position: 'relative',
},
alignItems: 'center',
display: 'flex',
borderBottom: `1px solid ${colors.greyLight}`,
padding: '8px',
position: 'relative',
});
export const InnerMobileNavBar = styled('div')({
'&&': {
borderRadius: '4px',
backgroundColor: colors.greyLight,
color: colors.white,
width: '100%',
padding: '0 5px',
margin: '0 10px 0 0',
},
borderRadius: '4px',
backgroundColor: colors.greyLight,
color: colors.white,
width: '100%',
padding: '0 5px',
margin: '0 10px 0 0',
});
export const IconSearchButton = styled(IconButton)({
'&&': {
display: 'block',
},
display: 'block',
});
export const SearchWrapper = styled('div')({
'&&': {
display: 'none',
maxWidth: '393px',
width: '100%',
},
// display: 'none',
maxWidth: '393px',
width: '100%',
});
export const NavBar = styled(AppBar)`
@@ -104,8 +89,6 @@ export const NavBar = styled(AppBar)`
}
`;
export const StyledExternalLink = styled(ExternalLink)({
'&&': {
color: 'white',
},
export const StyledLink = styled(Link)({
color: 'white',
});

View File

@@ -1,15 +1,18 @@
import CardActions from '@material-ui/core/CardActions';
import CardContent from '@material-ui/core/CardContent';
import React, { Fragment } from 'react';
import { getRegistryURL } from '../../utils/url';
import CopyToClipBoard from '../CopyToClipBoard';
import Button from '../../muiComponents/Button';
import CardContent from '../../muiComponents/CardContent';
import { default as Typography } from '../../muiComponents/Heading';
import CardActions from '../../muiComponents/CardActions';
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:'}

View File

@@ -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';

View File

@@ -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>"`;

View File

@@ -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')({

View File

@@ -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';

View File

@@ -1,10 +1,10 @@
import React from 'react';
import styled from 'react-emotion';
import ListItemText from '@material-ui/core/ListItemText';
import styled from '@emotion/styled';
import CopyToClipBoard from '../CopyToClipBoard';
import Avatar from '../../muiComponents/Avatar';
import ListItem from '../../muiComponents/ListItem';
import ListItemText from '../../muiComponents/ListItemText';
// logos of package managers
import npmLogo from './img/npm.svg';
@@ -45,21 +45,30 @@ const InstallListItem: React.FC<Interface> = ({ packageName, dependencyManager }
return (
<InstallItem button={true} data-testid={'installListItem-npm'}>
<PackageMangerAvatar alt="npm" src={npmLogo} />
<InstallListItemText primary={<CopyToClipBoard text={`npm install ${packageName}`} />} secondary={'Install using npm'} />
<InstallListItemText
primary={<CopyToClipBoard text={`npm install ${packageName}`} />}
secondary={'Install using npm'}
/>
</InstallItem>
);
case DependencyManager.YARN:
return (
<InstallItem button={true} data-testid={'installListItem-yarn'}>
<PackageMangerAvatar alt="yarn" src={yarnLogo} />
<InstallListItemText primary={<CopyToClipBoard text={`yarn add ${packageName}`} />} secondary={'Install using yarn'} />
<InstallListItemText
primary={<CopyToClipBoard text={`yarn add ${packageName}`} />}
secondary={'Install using yarn'}
/>
</InstallItem>
);
case DependencyManager.PNPM:
return (
<InstallItem button={true} data-testid={'installListItem-pnpm'}>
<PackageMangerAvatar alt={'pnpm'} src={pnpmLogo} />
<InstallListItemText primary={<CopyToClipBoard text={`pnpm install ${packageName}`} />} secondary={'Install using pnpm'} />
<InstallListItemText
primary={<CopyToClipBoard text={`pnpm install ${packageName}`} />}
secondary={'Install using pnpm'}
/>
</InstallItem>
);
default:

View File

@@ -18,7 +18,7 @@ exports[`<Install /> renders correctly 1`] = `
tabindex="0"
>
<div
class="MuiAvatar-root css-19top7x emotion-1"
class="MuiAvatar-root MuiAvatar-circle css-19top7x emotion-1"
>
<img
alt="npm"
@@ -85,7 +85,7 @@ exports[`<Install /> renders correctly 1`] = `
tabindex="0"
>
<div
class="MuiAvatar-root css-19top7x emotion-1"
class="MuiAvatar-root MuiAvatar-circle css-19top7x emotion-1"
>
<img
alt="yarn"
@@ -152,7 +152,7 @@ exports[`<Install /> renders correctly 1`] = `
tabindex="0"
>
<div
class="MuiAvatar-root css-19top7x emotion-1"
class="MuiAvatar-root MuiAvatar-circle css-19top7x emotion-1"
>
<img
alt="pnpm"

View File

@@ -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')};

View File

@@ -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';

View File

@@ -1,14 +0,0 @@
import React from 'react';
import { mount } from 'enzyme';
import Link from './Link';
describe('<Link /> component', () => {
const props = {
to: 'https://github.com/verdaccio/ui',
};
test('should render the component in default state', () => {
const wrapper = mount(<Link blank={true} to={props.to} />);
expect(wrapper.html()).toMatchSnapshot();
});
});

View File

@@ -1,15 +1,26 @@
import React, { ReactNode } from 'react';
import React from 'react';
import { Link as RouterLink } from 'react-router-dom';
interface Props {
children?: ReactNode;
import Text, { TextProps } from '../../muiComponents/Text';
interface Props extends Pick<TextProps, 'variant'> {
external?: boolean;
className?: string;
to: string;
blank?: boolean;
}
const Link: React.FC<Props> = ({ children, to = '#', blank = false, ...props }) => (
<a href={to} target={blank ? '_blank' : '_self'} {...props}>
{children}
</a>
);
/* eslint-disable verdaccio/jsx-spread */
const Link: React.FC<Props> = ({ external, to, children, variant, className, ...props }) => {
const LinkTextContent = <Text variant={variant}>{children}</Text>;
return external ? (
<a className={className} href={to} rel="noopener noreferrer" target="_blank" {...props}>
{LinkTextContent}
</a>
) : (
<RouterLink className={className} to={to} {...props}>
{LinkTextContent}
</RouterLink>
);
};
export default Link;

View File

@@ -1,3 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Link /> component should render the component in default state 1`] = `"<a href=\\"https://github.com/verdaccio/ui\\" target=\\"_blank\\"></a>"`;

View File

@@ -1,4 +1,4 @@
import styled from 'react-emotion';
import styled from '@emotion/styled';
export const Wrapper = styled('div')`
&& {

View File

@@ -1,10 +1,5 @@
import React, { Component } from 'react';
import SnackbarContent from '@material-ui/core/SnackbarContent';
import ErrorIcon from '@material-ui/icons/Error';
import InputLabel from '@material-ui/core/InputLabel';
import Input from '@material-ui/core/Input';
import FormControl from '@material-ui/core/FormControl';
import FormHelperText from '@material-ui/core/FormHelperText';
import { css } from 'emotion';
import Button from '../../muiComponents/Button';
@@ -12,6 +7,11 @@ import Dialog from '../../muiComponents/Dialog';
import DialogTitle from '../../muiComponents/DialogTitle';
import DialogContent from '../../muiComponents/DialogContent';
import DialogActions from '../../muiComponents/DialogActions';
import FormControl from '../../muiComponents/FormControl';
import FormHelperText from '../../muiComponents/FormHelperText';
import Input from '../../muiComponents/Input';
import InputLabel from '../../muiComponents/InputLabel';
import SnackbarContent from '../../muiComponents/SnackbarContent';
import * as classes from './styles';
@@ -172,7 +172,11 @@ export default class LoginModal extends Component<Partial<LoginModalProps>, Logi
}
public renderLoginError({ type, title, description }: FormError): JSX.Element | false {
return type === 'error' && <SnackbarContent className={classes.loginError} message={this.renderMessage(title, description)} />;
return (
type === 'error' && (
<SnackbarContent className={classes.loginError} message={this.renderMessage(title, description)} />
)
);
}
public renderNameField = () => {
@@ -182,8 +186,15 @@ export default class LoginModal extends Component<Partial<LoginModalProps>, Logi
return (
<FormControl error={!username.value && !username.pristine} fullWidth={true} required={username.required}>
<InputLabel htmlFor={'username'}>{'Username'}</InputLabel>
<Input id={'login--form-username'} onChange={this.handleUsernameChange} placeholder={'Your username'} value={username.value} />
{!username.value && !username.pristine && <FormHelperText id={'username-error'}>{username.helperText}</FormHelperText>}
<Input
id={'login--form-username'}
onChange={this.handleUsernameChange}
placeholder={'Your username'}
value={username.value}
/>
{!username.value && !username.pristine && (
<FormHelperText id={'username-error'}>{username.helperText}</FormHelperText>
)}
</FormControl>
);
};
@@ -201,8 +212,16 @@ export default class LoginModal extends Component<Partial<LoginModalProps>, Logi
fullWidth={true}
required={password.required}>
<InputLabel htmlFor={'password'}>{'Password'}</InputLabel>
<Input id={'login--form-password'} onChange={this.handlePasswordChange} placeholder={'Your strong password'} type={'password'} value={password.value} />
{!password.value && !password.pristine && <FormHelperText id={'password-error'}>{password.helperText}</FormHelperText>}
<Input
id={'login--form-password'}
onChange={this.handlePasswordChange}
placeholder={'Your strong password'}
type={'password'}
value={password.value}
/>
{!password.value && !password.pristine && (
<FormHelperText id={'password-error'}>{password.helperText}</FormHelperText>
)}
</FormControl>
);
};
@@ -217,7 +236,11 @@ export default class LoginModal extends Component<Partial<LoginModalProps>, Logi
<Button color={'inherit'} id={'login--form-cancel'} onClick={onCancel} type={'button'}>
{'Cancel'}
</Button>
<Button color={'inherit'} disabled={!password.value || !username.value} id={'login--form-submit'} type={'submit'}>
<Button
color={'inherit'}
disabled={!password.value || !username.value}
id={'login--form-submit'}
type={'submit'}>
{'Login'}
</Button>
</DialogActions>

View File

@@ -1,5 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<LoginModal /> should load the component in default state 1`] = `"<div role=\\"presentation\\" class=\\"MuiDialog-root\\" id=\\"login--form-container\\" style=\\"position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;\\"><div class=\\"MuiBackdrop-root\\" aria-hidden=\\"true\\" style=\\"opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;\\"></div><div tabindex=\\"0\\" data-test=\\"sentinelStart\\"></div><div class=\\"MuiDialog-container MuiDialog-scrollPaper\\" style=\\"opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;\\" role=\\"none presentation\\" tabindex=\\"-1\\"><div class=\\"MuiPaper-root MuiPaper-elevation24 MuiDialog-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthXs MuiDialog-paperFullWidth MuiPaper-rounded\\" role=\\"dialog\\"><form novalidate=\\"\\"><div class=\\"MuiDialogTitle-root\\"><h2 class=\\"MuiTypography-root MuiTypography-h6\\">Login</h2></div><div class=\\"MuiDialogContent-root\\"><div class=\\"MuiFormControl-root MuiFormControl-fullWidth\\"><label class=\\"MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated Mui-required Mui-required\\" data-shrink=\\"false\\" for=\\"username\\">Username<span class=\\"MuiFormLabel-asterisk MuiInputLabel-asterisk\\"> *</span></label><div class=\\"MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-formControl MuiInput-formControl\\"><input aria-invalid=\\"false\\" class=\\"MuiInputBase-input MuiInput-input\\" id=\\"login--form-username\\" placeholder=\\"Your username\\" required=\\"\\" type=\\"text\\" value=\\"\\"></div></div><div class=\\"MuiFormControl-root css-164r41r MuiFormControl-fullWidth\\"><label class=\\"MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated Mui-required Mui-required\\" data-shrink=\\"false\\" for=\\"password\\">Password<span class=\\"MuiFormLabel-asterisk MuiInputLabel-asterisk\\"> *</span></label><div class=\\"MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-formControl MuiInput-formControl\\"><input aria-invalid=\\"false\\" class=\\"MuiInputBase-input MuiInput-input\\" id=\\"login--form-password\\" placeholder=\\"Your strong password\\" required=\\"\\" type=\\"password\\" value=\\"\\"></div></div></div><div class=\\"MuiDialogActions-root dialog-footer MuiDialogActions-spacing\\"><button class=\\"MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-colorInherit\\" tabindex=\\"0\\" type=\\"button\\" id=\\"login--form-cancel\\"><span class=\\"MuiButton-label\\">Cancel</span><span class=\\"MuiTouchRipple-root\\"></span></button><button class=\\"MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-colorInherit Mui-disabled Mui-disabled\\" tabindex=\\"-1\\" type=\\"submit\\" disabled=\\"\\" id=\\"login--form-submit\\"><span class=\\"MuiButton-label\\">Login</span></button></div></form></div></div><div tabindex=\\"0\\" data-test=\\"sentinelEnd\\"></div></div>"`;
exports[`<LoginModal /> should load the component in default state 1`] = `"<div role=\\"presentation\\" class=\\"MuiDialog-root\\" id=\\"login--form-container\\" style=\\"position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;\\"><div class=\\"MuiBackdrop-root\\" aria-hidden=\\"true\\" style=\\"opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;\\"></div><div tabindex=\\"0\\" data-test=\\"sentinelStart\\"></div><div class=\\"MuiDialog-container MuiDialog-scrollPaper\\" style=\\"opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;\\" role=\\"none presentation\\" tabindex=\\"-1\\"><div class=\\"MuiPaper-root MuiPaper-elevation24 MuiDialog-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthXs MuiDialog-paperFullWidth MuiPaper-rounded\\" role=\\"dialog\\"><form novalidate=\\"\\"><div class=\\"MuiDialogTitle-root\\"><h2 class=\\"MuiTypography-root MuiTypography-h6\\">Login</h2></div><div class=\\"MuiDialogContent-root\\"><div class=\\"MuiFormControl-root MuiFormControl-fullWidth\\"><label class=\\"MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated Mui-required Mui-required\\" data-shrink=\\"false\\" for=\\"username\\">Username<span class=\\"MuiFormLabel-asterisk MuiInputLabel-asterisk\\"> *</span></label><div class=\\"MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-formControl MuiInput-formControl\\"><input aria-invalid=\\"false\\" id=\\"login--form-username\\" placeholder=\\"Your username\\" required=\\"\\" type=\\"text\\" class=\\"MuiInputBase-input MuiInput-input\\" value=\\"\\"></div></div><div class=\\"MuiFormControl-root css-164r41r MuiFormControl-fullWidth\\"><label class=\\"MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated Mui-required Mui-required\\" data-shrink=\\"false\\" for=\\"password\\">Password<span class=\\"MuiFormLabel-asterisk MuiInputLabel-asterisk\\"> *</span></label><div class=\\"MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-formControl MuiInput-formControl\\"><input aria-invalid=\\"false\\" id=\\"login--form-password\\" placeholder=\\"Your strong password\\" required=\\"\\" type=\\"password\\" class=\\"MuiInputBase-input MuiInput-input\\" value=\\"\\"></div></div></div><div class=\\"MuiDialogActions-root dialog-footer MuiDialogActions-spacing\\"><button class=\\"MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-colorInherit\\" tabindex=\\"0\\" type=\\"button\\" id=\\"login--form-cancel\\"><span class=\\"MuiButton-label\\">Cancel</span><span class=\\"MuiTouchRipple-root\\"></span></button><button class=\\"MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-colorInherit Mui-disabled Mui-disabled\\" tabindex=\\"-1\\" type=\\"submit\\" disabled=\\"\\" id=\\"login--form-submit\\"><span class=\\"MuiButton-label\\">Login</span></button></div></form></div></div><div tabindex=\\"0\\" data-test=\\"sentinelEnd\\"></div></div>"`;
exports[`<LoginModal /> should load the component with props 1`] = `"<div role=\\"presentation\\" class=\\"MuiDialog-root\\" id=\\"login--form-container\\" style=\\"position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;\\"><div class=\\"MuiBackdrop-root\\" aria-hidden=\\"true\\" style=\\"opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;\\"></div><div tabindex=\\"0\\" data-test=\\"sentinelStart\\"></div><div class=\\"MuiDialog-container MuiDialog-scrollPaper\\" style=\\"opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;\\" role=\\"none presentation\\" tabindex=\\"-1\\"><div class=\\"MuiPaper-root MuiPaper-elevation24 MuiDialog-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthXs MuiDialog-paperFullWidth MuiPaper-rounded\\" role=\\"dialog\\"><form novalidate=\\"\\"><div class=\\"MuiDialogTitle-root\\"><h2 class=\\"MuiTypography-root MuiTypography-h6\\">Login</h2></div><div class=\\"MuiDialogContent-root\\"><div class=\\"MuiTypography-root MuiPaper-root MuiPaper-elevation6 MuiSnackbarContent-root css-11e09xf MuiTypography-body2\\" role=\\"alertdialog\\"><div class=\\"MuiSnackbarContent-message\\"><div class=\\"css-70qvj9\\" id=\\"client-snackbar\\"><svg class=\\"MuiSvgIcon-root css-1mbwbu9\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z\\"></path></svg><span><div><strong>Error Title</strong></div><div>Error Description</div></span></div></div></div><div class=\\"MuiFormControl-root MuiFormControl-fullWidth\\"><label class=\\"MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated Mui-required Mui-required\\" data-shrink=\\"false\\" for=\\"username\\">Username<span class=\\"MuiFormLabel-asterisk MuiInputLabel-asterisk\\"> *</span></label><div class=\\"MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-formControl MuiInput-formControl\\"><input aria-invalid=\\"false\\" class=\\"MuiInputBase-input MuiInput-input\\" id=\\"login--form-username\\" placeholder=\\"Your username\\" required=\\"\\" type=\\"text\\" value=\\"\\"></div></div><div class=\\"MuiFormControl-root css-164r41r MuiFormControl-fullWidth\\"><label class=\\"MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated Mui-required Mui-required\\" data-shrink=\\"false\\" for=\\"password\\">Password<span class=\\"MuiFormLabel-asterisk MuiInputLabel-asterisk\\"> *</span></label><div class=\\"MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-formControl MuiInput-formControl\\"><input aria-invalid=\\"false\\" class=\\"MuiInputBase-input MuiInput-input\\" id=\\"login--form-password\\" placeholder=\\"Your strong password\\" required=\\"\\" type=\\"password\\" value=\\"\\"></div></div></div><div class=\\"MuiDialogActions-root dialog-footer MuiDialogActions-spacing\\"><button class=\\"MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-colorInherit\\" tabindex=\\"0\\" type=\\"button\\" id=\\"login--form-cancel\\"><span class=\\"MuiButton-label\\">Cancel</span><span class=\\"MuiTouchRipple-root\\"></span></button><button class=\\"MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-colorInherit Mui-disabled Mui-disabled\\" tabindex=\\"-1\\" type=\\"submit\\" disabled=\\"\\" id=\\"login--form-submit\\"><span class=\\"MuiButton-label\\">Login</span></button></div></form></div></div><div tabindex=\\"0\\" data-test=\\"sentinelEnd\\"></div></div>"`;
exports[`<LoginModal /> should load the component with props 1`] = `"<div role=\\"presentation\\" class=\\"MuiDialog-root\\" id=\\"login--form-container\\" style=\\"position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;\\"><div class=\\"MuiBackdrop-root\\" aria-hidden=\\"true\\" style=\\"opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;\\"></div><div tabindex=\\"0\\" data-test=\\"sentinelStart\\"></div><div class=\\"MuiDialog-container MuiDialog-scrollPaper\\" style=\\"opacity: 1; webkit-transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;\\" role=\\"none presentation\\" tabindex=\\"-1\\"><div class=\\"MuiPaper-root MuiPaper-elevation24 MuiDialog-paper MuiDialog-paperScrollPaper MuiDialog-paperWidthXs MuiDialog-paperFullWidth MuiPaper-rounded\\" role=\\"dialog\\"><form novalidate=\\"\\"><div class=\\"MuiDialogTitle-root\\"><h2 class=\\"MuiTypography-root MuiTypography-h6\\">Login</h2></div><div class=\\"MuiDialogContent-root\\"><div class=\\"MuiTypography-root MuiPaper-root MuiPaper-elevation6 MuiSnackbarContent-root css-11e09xf MuiTypography-body2\\" role=\\"alert\\"><div class=\\"MuiSnackbarContent-message\\"><div class=\\"css-70qvj9\\" id=\\"client-snackbar\\"><svg class=\\"MuiSvgIcon-root css-1mbwbu9\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z\\"></path></svg><span><div><strong>Error Title</strong></div><div>Error Description</div></span></div></div></div><div class=\\"MuiFormControl-root MuiFormControl-fullWidth\\"><label class=\\"MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated Mui-required Mui-required\\" data-shrink=\\"false\\" for=\\"username\\">Username<span class=\\"MuiFormLabel-asterisk MuiInputLabel-asterisk\\"> *</span></label><div class=\\"MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-formControl MuiInput-formControl\\"><input aria-invalid=\\"false\\" id=\\"login--form-username\\" placeholder=\\"Your username\\" required=\\"\\" type=\\"text\\" class=\\"MuiInputBase-input MuiInput-input\\" value=\\"\\"></div></div><div class=\\"MuiFormControl-root css-164r41r MuiFormControl-fullWidth\\"><label class=\\"MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated Mui-required Mui-required\\" data-shrink=\\"false\\" for=\\"password\\">Password<span class=\\"MuiFormLabel-asterisk MuiInputLabel-asterisk\\"> *</span></label><div class=\\"MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-formControl MuiInput-formControl\\"><input aria-invalid=\\"false\\" id=\\"login--form-password\\" placeholder=\\"Your strong password\\" required=\\"\\" type=\\"password\\" class=\\"MuiInputBase-input MuiInput-input\\" value=\\"\\"></div></div></div><div class=\\"MuiDialogActions-root dialog-footer MuiDialogActions-spacing\\"><button class=\\"MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-colorInherit\\" tabindex=\\"0\\" type=\\"button\\" id=\\"login--form-cancel\\"><span class=\\"MuiButton-label\\">Cancel</span><span class=\\"MuiTouchRipple-root\\"></span></button><button class=\\"MuiButtonBase-root MuiButton-root MuiButton-text MuiButton-colorInherit Mui-disabled Mui-disabled\\" tabindex=\\"-1\\" type=\\"submit\\" disabled=\\"\\" id=\\"login--form-submit\\"><span class=\\"MuiButton-label\\">Login</span></button></div></form></div></div><div tabindex=\\"0\\" data-test=\\"sentinelEnd\\"></div></div>"`;

View File

@@ -1,5 +1,5 @@
import React from 'react';
import styled from 'react-emotion';
import styled from '@emotion/styled';
import logo from './img/logo.svg';

View File

@@ -1,10 +1,10 @@
import Box from '@material-ui/core/Box';
import Typography from '@material-ui/core/Typography';
import styled from 'react-emotion';
import styled from '@emotion/styled';
import React, { useCallback } from 'react';
import { useHistory } from 'react-router-dom';
import Box from '../../muiComponents/Box';
import Button from '../../muiComponents/Button';
import Heading from '../../muiComponents/Heading';
import colors from '../../utils/styles/colors';
import { spacings } from '../../utils/styles/spacings';
@@ -19,7 +19,7 @@ const EmptyPackage = styled('img')({
margin: '0 auto',
});
const StyledHeading = styled(Typography)({
const StyledHeading = styled(Heading)({
color: colors.primary,
marginBottom: spacings.sm,
});
@@ -32,7 +32,14 @@ const NotFound: React.FC = () => {
}, [history]);
return (
<Box alignItems="center" data-testid="404" display="flex" flexDirection="column" flexGrow={1} justifyContent="center" p={2}>
<Box
alignItems="center"
data-testid="404"
display="flex"
flexDirection="column"
flexGrow={1}
justifyContent="center"
p={2}>
<EmptyPackage alt="404 - Page not found" src={PackageImg} />
<StyledHeading className="not-found-text" variant="h4">
{NOT_FOUND_TEXT}

View File

@@ -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';

View File

@@ -27,7 +27,14 @@ describe('<Package /> component', () => {
};
const wrapper = shallow(
<Package author={props.author} description={props.description} license={props.license} name={props.name} time={props.time} version={props.version} />
<Package
author={props.author}
description={props.description}
license={props.license}
name={props.name}
time={props.time}
version={props.version}
/>
);
// integration expectations
@@ -65,7 +72,14 @@ describe('<Package /> component', () => {
description: 'Private NPM repository',
};
const wrapper = shallow(
<Package author={props.author} description={props.description} license={props.license} name={props.name} time={props.time} version={props.version} />
<Package
author={props.author}
description={props.description}
license={props.license}
name={props.name}
time={props.time}
version={props.version}
/>
);
// integration expectations

View File

@@ -1,6 +1,6 @@
import React from 'react';
import BugReport from '@material-ui/icons/BugReport';
import Grid from '@material-ui/core/Grid';
import DownloadIcon from '@material-ui/icons/CloudDownload';
import HomeIcon from '@material-ui/icons/Home';
import { PackageMetaInterface, Author as PackageAuthor } from '../../../types/packageMeta';
@@ -9,7 +9,9 @@ import fileSizeSI from '../../utils/file-size';
import { formatDate, formatDateDistance } from '../../utils/package';
import Tooltip from '../../muiComponents/Tooltip';
import { isURL } from '../../utils/url';
import { downloadHandler } from '../ActionBar/ActionBar';
import ListItem from '../../muiComponents/ListItem';
import Grid from '../../muiComponents/Grid';
import {
Author,
@@ -34,6 +36,7 @@ interface Bugs {
}
interface Dist {
unpackedSize: number;
tarball: string;
}
export interface PackageInterface {
@@ -132,18 +135,34 @@ const Package: React.FC<PackageInterface> = ({
</a>
);
const renderDownloadLink = (): React.ReactNode =>
dist &&
dist.tarball &&
isURL(dist.tarball) && (
// eslint-disable-next-line
<a onClick={() => downloadHandler(dist.tarball.replace(`https://registry.npmjs.org/`, window.location.href))} target={'_blank'}>
<Tooltip aria-label={'Download the tar file'} title={'Download tarball'}>
<IconButton aria-label={'Download'}>
{/* eslint-disable-next-line react/jsx-max-depth */}
<DownloadIcon />
</IconButton>
</Tooltip>
</a>
);
const renderPrimaryComponent = (): React.ReactNode => {
return (
<Grid container={true} item={true} xs={12}>
<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}>
{renderHomePageLink()}
{renderBugsLink()}
{renderDownloadLink()}
</GridRightAligned>
</Grid>
);
@@ -160,8 +179,13 @@ const Package: React.FC<PackageInterface> = ({
};
const renderPackageListItemText = (): React.ReactNode => (
// @ts-ignore
<PackageListItemText className="package-link" component="div" primary={renderPrimaryComponent()} secondary={renderSecondaryComponent()} />
<PackageListItemText
className="package-link"
// @ts-ignore
component="div"
primary={renderPrimaryComponent()}
secondary={renderSecondaryComponent()}
/>
);
return (

View File

@@ -1,7 +1,5 @@
import styled from 'react-emotion';
import styled from '@emotion/styled';
import { Link } from 'react-router-dom';
import Grid from '@material-ui/core/Grid';
import ListItemText from '@material-ui/core/ListItemText';
import { breakpoints } from '../../utils/styles/media';
import Ico from '../Icon';
@@ -12,6 +10,8 @@ import { default as MuiIconButton } from '../../muiComponents/IconButton';
import { default as Photo } from '../../muiComponents/Avatar';
import List from '../../muiComponents/List';
import { default as Typography } from '../../muiComponents/Heading';
import Grid from '../../muiComponents/Grid';
import ListItemText from '../../muiComponents/ListItemText';
export const OverviewItem = styled('span')`
&& {

View File

@@ -1,4 +1,4 @@
import * as React from 'react';
import React, { Fragment, ReactNode } from 'react';
import Package from '../Package';
import Help from '../Help';
@@ -12,22 +12,23 @@ interface Props {
packages: PackageInterface[];
}
export const PackageList: React.FC<Props> = props => {
const renderPackages: () => React.ReactElement<HTMLElement>[] = () => {
return props.packages.map((pkg, i) => {
const { name, version, description, time, keywords, dist, homepage, bugs, author } = pkg;
export const PackageList: React.FC<Props> = ({ packages }) => {
const renderPackages: () => ReactNode[] = () => {
return packages.map(({ name, version, description, time, keywords, dist, homepage, bugs, author, license }, i) => {
// TODO: move format license to API side.
const license = formatLicense(pkg.license);
const _license = formatLicense(license);
return (
<React.Fragment key={i}>
<Fragment key={i}>
{i !== 0 && <Divider />}
<Package {...{ name, dist, version, author, description, license, time, keywords, homepage, bugs }} />
</React.Fragment>
<Package
{...{ name, dist, version, author, description, license: _license, time, keywords, homepage, bugs }}
/>
</Fragment>
);
});
};
const hasPackages: () => boolean = () => props.packages.length > 0;
const hasPackages: () => boolean = () => packages.length > 0;
return (
<div className={'package-list-items'}>

View File

@@ -1,4 +1,4 @@
import { css } from 'emotion';
import { css } from '@emotion/core';
import { fontWeight, fontSize } from '../../utils/styles/sizes';

View File

@@ -3,6 +3,8 @@ import 'github-markdown-css';
import { Props } from './types';
const Readme: React.FC<Props> = ({ description }) => <div className="markdown-body" dangerouslySetInnerHTML={{ __html: description }} />;
const Readme: React.FC<Props> = ({ description }) => (
<div className="markdown-body" dangerouslySetInnerHTML={{ __html: description }} />
);
export default Readme;

View File

@@ -1,23 +1,35 @@
import React from 'react';
import { mount } from 'enzyme';
import { render, cleanup, fireEvent } from '@testing-library/react';
import RegistryInfoContent from './RegistryInfoContent';
describe('<RegistryInfoContent /> component', () => {
test('should render the component in default state with npm tab', () => {
const wrapper = mount(<RegistryInfoContent registryUrl="https://registry.verdaccio.org" scope="@" />);
expect(wrapper.html()).toMatchSnapshot();
afterEach(() => {
cleanup();
});
test('should render the component in default state with pnpm tab', () => {
const wrapper = mount(<RegistryInfoContent registryUrl="https://registry.verdaccio.org" scope="@" />);
wrapper.setState({ tabPosition: 1 });
expect(wrapper.html()).toMatchSnapshot();
test('should load the component with no data', () => {
const { getByTestId } = render(<RegistryInfoContent registryUrl={''} scope={''} />);
const unorderedListOfTodos = getByTestId('tabs-el');
expect(unorderedListOfTodos.children.length).toBe(1);
});
test('should render the component in default state with yarn tab', () => {
const wrapper = mount(<RegistryInfoContent registryUrl="https://registry.verdaccio.org" scope="@" />);
wrapper.setState({ tabPosition: 2 });
expect(wrapper.html()).toMatchSnapshot();
test('should load the appropiate tab content when the tab is clicked', () => {
const props = { registryUrl: 'http://localhost:4872', scope: '@' };
const pnpmTabTextContent = `pnpm adduser --registry ${props.registryUrl}`;
// Render the component.
const { container, getByTestId } = render(
<RegistryInfoContent registryUrl={props.registryUrl} scope={props.scope} />
);
// Assert the text content for pnpm tab is not present intially
expect(container.textContent).not.toContain(pnpmTabTextContent);
const pnpmTab = getByTestId('pnpm-tab');
fireEvent.click(pnpmTab);
// Assert the text content is correct after clicking on the tab.
expect(container.textContent).toContain(pnpmTabTextContent);
});
});

View File

@@ -1,91 +1,81 @@
import React, { Component } from 'react';
import { css } from 'emotion';
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
import React, { useState } from 'react';
import { css } from '@emotion/core';
import CopyToClipBoard from '../CopyToClipBoard';
import { getCLISetRegistry, getCLIChangePassword, getCLISetConfigRegistry } from '../../utils/cli-utils';
import { NODE_MANAGER } from '../../utils/constants';
import { default as Typography } from '../../muiComponents/Heading';
import Tabs from '../../muiComponents/Tabs';
import Tab from '../../muiComponents/Tab';
import { CommandContainer } from './styles';
import { Props, State } from './types';
/* eslint react/prop-types:0 */
function TabContainer({ children }): JSX.Element {
return (
<CommandContainer>
<Typography
className={css`
padding: 0;
min-height: 170;
`}
component="div">
{children}
</Typography>
</CommandContainer>
);
}
class RegistryInfoContent extends Component<Props, State> {
public state = {
tabPosition: 0,
};
public render(): JSX.Element {
return <div>{this.renderTabs()}</div>;
}
private handleChange = (event: React.ChangeEvent<{}>, tabPosition: number) => {
const RegistryInfoContent: React.FC<Props> = props => {
const [tabPosition, setTabPosition] = useState<State['tabPosition']>(0);
const handleChange = (event: React.ChangeEvent<{}>, tabPosition: number): void => {
event.preventDefault();
this.setState({ tabPosition });
setTabPosition(tabPosition);
};
private renderTabs(): JSX.Element {
const { scope, registryUrl } = this.props;
const { tabPosition } = this.state;
const renderNpmTab = (scope: string, registryUrl: string): JSX.Element => {
return (
<React.Fragment>
<Tabs indicatorColor="primary" onChange={this.handleChange} textColor="primary" value={tabPosition} variant="fullWidth">
<Tab label={NODE_MANAGER.npm} />
<Tab label={NODE_MANAGER.pnpm} />
<Tab label={NODE_MANAGER.yarn} />
</Tabs>
{tabPosition === 0 && <TabContainer>{this.renderNpmTab(scope, registryUrl)}</TabContainer>}
{tabPosition === 1 && <TabContainer>{this.renderPNpmTab(scope, registryUrl)}</TabContainer>}
{tabPosition === 2 && <TabContainer>{this.renderYarnTab(scope, registryUrl)}</TabContainer>}
</React.Fragment>
);
}
private renderNpmTab(scope: string, registryUrl: string): JSX.Element {
return (
<React.Fragment>
<>
<CopyToClipBoard text={getCLISetConfigRegistry(`${NODE_MANAGER.npm} set`, scope, registryUrl)} />
<CopyToClipBoard text={getCLISetRegistry(`${NODE_MANAGER.npm} adduser`, registryUrl)} />
<CopyToClipBoard text={getCLIChangePassword(NODE_MANAGER.npm, registryUrl)} />
</React.Fragment>
</>
);
}
};
private renderPNpmTab(scope: string, registryUrl: string): JSX.Element {
const renderPnpmTab = (scope: string, registryUrl: string): JSX.Element => {
return (
<React.Fragment>
<>
<CopyToClipBoard text={getCLISetConfigRegistry(`${NODE_MANAGER.pnpm} set`, scope, registryUrl)} />
<CopyToClipBoard text={getCLISetRegistry(`${NODE_MANAGER.pnpm} adduser`, registryUrl)} />
<CopyToClipBoard text={getCLIChangePassword(NODE_MANAGER.pnpm, registryUrl)} />
</React.Fragment>
</>
);
}
};
const renderYarnTab = (scope: string, registryUrl: string): JSX.Element => {
return <CopyToClipBoard text={getCLISetConfigRegistry(`${NODE_MANAGER.yarn} config set`, scope, registryUrl)} />;
};
const renderTabs = (): JSX.Element => {
const { scope, registryUrl } = props;
private renderYarnTab(scope: string, registryUrl: string): JSX.Element {
return (
<React.Fragment>
<CopyToClipBoard text={getCLISetConfigRegistry(`${NODE_MANAGER.yarn} config set`, scope, registryUrl)} />
</React.Fragment>
<>
<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} />
</Tabs>
{tabPosition === 0 && <TabContainer>{renderNpmTab(scope, registryUrl)}</TabContainer>}
{tabPosition === 1 && <TabContainer>{renderPnpmTab(scope, registryUrl)}</TabContainer>}
{tabPosition === 2 && <TabContainer>{renderYarnTab(scope, registryUrl)}</TabContainer>}
</>
);
}
}
};
/* eslint react/prop-types:0 */
const TabContainer = ({ children }): JSX.Element => {
return (
<CommandContainer>
<Typography
className={css`
padding: 0;
min-height: 170;
`}
component="div">
{children}
</Typography>
</CommandContainer>
);
};
return <div>{renderTabs()}</div>;
};
export default RegistryInfoContent;

View File

@@ -1,7 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<RegistryInfoContent /> component should render the component in default state with npm tab 1`] = `"<div><div class=\\"MuiTabs-root\\"><div class=\\"MuiTabs-scroller MuiTabs-fixed\\" style=\\"overflow: hidden;\\"><div class=\\"MuiTabs-flexContainer\\" role=\\"tablist\\"><button class=\\"MuiButtonBase-root MuiTab-root MuiTab-textColorPrimary Mui-selected MuiTab-fullWidth\\" tabindex=\\"0\\" type=\\"button\\" role=\\"tab\\" aria-selected=\\"true\\"><span class=\\"MuiTab-wrapper\\">npm</span><span class=\\"MuiTouchRipple-root\\"></span></button><button class=\\"MuiButtonBase-root MuiTab-root MuiTab-textColorPrimary MuiTab-fullWidth\\" tabindex=\\"0\\" type=\\"button\\" role=\\"tab\\" aria-selected=\\"false\\"><span class=\\"MuiTab-wrapper\\">pnpm</span><span class=\\"MuiTouchRipple-root\\"></span></button><button class=\\"MuiButtonBase-root MuiTab-root MuiTab-textColorPrimary MuiTab-fullWidth\\" tabindex=\\"0\\" type=\\"button\\" role=\\"tab\\" aria-selected=\\"false\\"><span class=\\"MuiTab-wrapper\\">yarn</span><span class=\\"MuiTouchRipple-root\\"></span></button></div><span class=\\"PrivateTabIndicator-root-25 PrivateTabIndicator-colorPrimary-26 MuiTabs-indicator\\" style=\\"left: 0px; width: 0px;\\"></span></div></div><div class=\\"css-1qvg11o ehfwshd0\\"><div class=\\"MuiTypography-root css-17iubtz MuiTypography-h6\\"><div class=\\"css-1mta3t8 eb8w2fo0\\"><span class=\\"css-lh0wgu eb8w2fo1\\">npm set @registry https://registry.verdaccio.org</span><button class=\\"MuiButtonBase-root MuiIconButton-root css-0 eb8w2fo2\\" tabindex=\\"0\\" type=\\"button\\" title=\\"Copy to Clipboard\\"><span class=\\"MuiIconButton-label\\"><svg class=\\"MuiSvgIcon-root\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z\\"></path></svg></span><span class=\\"MuiTouchRipple-root\\"></span></button></div><div class=\\"css-1mta3t8 eb8w2fo0\\"><span class=\\"css-lh0wgu eb8w2fo1\\">npm adduser --registry https://registry.verdaccio.org</span><button class=\\"MuiButtonBase-root MuiIconButton-root css-0 eb8w2fo2\\" tabindex=\\"0\\" type=\\"button\\" title=\\"Copy to Clipboard\\"><span class=\\"MuiIconButton-label\\"><svg class=\\"MuiSvgIcon-root\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z\\"></path></svg></span><span class=\\"MuiTouchRipple-root\\"></span></button></div><div class=\\"css-1mta3t8 eb8w2fo0\\"><span class=\\"css-lh0wgu eb8w2fo1\\">npm profile set password --registry https://registry.verdaccio.org</span><button class=\\"MuiButtonBase-root MuiIconButton-root css-0 eb8w2fo2\\" tabindex=\\"0\\" type=\\"button\\" title=\\"Copy to Clipboard\\"><span class=\\"MuiIconButton-label\\"><svg class=\\"MuiSvgIcon-root\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z\\"></path></svg></span><span class=\\"MuiTouchRipple-root\\"></span></button></div></div></div></div>"`;
exports[`<RegistryInfoContent /> component should render the component in default state with pnpm tab 1`] = `"<div><div class=\\"MuiTabs-root\\"><div class=\\"MuiTabs-scroller MuiTabs-fixed\\" style=\\"overflow: hidden;\\"><div class=\\"MuiTabs-flexContainer\\" role=\\"tablist\\"><button class=\\"MuiButtonBase-root MuiTab-root MuiTab-textColorPrimary MuiTab-fullWidth\\" tabindex=\\"0\\" type=\\"button\\" role=\\"tab\\" aria-selected=\\"false\\"><span class=\\"MuiTab-wrapper\\">npm</span><span class=\\"MuiTouchRipple-root\\"></span></button><button class=\\"MuiButtonBase-root MuiTab-root MuiTab-textColorPrimary Mui-selected MuiTab-fullWidth\\" tabindex=\\"0\\" type=\\"button\\" role=\\"tab\\" aria-selected=\\"true\\"><span class=\\"MuiTab-wrapper\\">pnpm</span><span class=\\"MuiTouchRipple-root\\"></span></button><button class=\\"MuiButtonBase-root MuiTab-root MuiTab-textColorPrimary MuiTab-fullWidth\\" tabindex=\\"0\\" type=\\"button\\" role=\\"tab\\" aria-selected=\\"false\\"><span class=\\"MuiTab-wrapper\\">yarn</span><span class=\\"MuiTouchRipple-root\\"></span></button></div><span class=\\"PrivateTabIndicator-root-25 PrivateTabIndicator-colorPrimary-26 MuiTabs-indicator\\" style=\\"left: 0px; width: 0px;\\"></span></div></div><div class=\\"css-1qvg11o ehfwshd0\\"><div class=\\"MuiTypography-root css-17iubtz MuiTypography-h6\\"><div class=\\"css-1mta3t8 eb8w2fo0\\"><span class=\\"css-lh0wgu eb8w2fo1\\">pnpm set @registry https://registry.verdaccio.org</span><button class=\\"MuiButtonBase-root MuiIconButton-root css-0 eb8w2fo2\\" tabindex=\\"0\\" type=\\"button\\" title=\\"Copy to Clipboard\\"><span class=\\"MuiIconButton-label\\"><svg class=\\"MuiSvgIcon-root\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z\\"></path></svg></span><span class=\\"MuiTouchRipple-root\\"></span></button></div><div class=\\"css-1mta3t8 eb8w2fo0\\"><span class=\\"css-lh0wgu eb8w2fo1\\">pnpm adduser --registry https://registry.verdaccio.org</span><button class=\\"MuiButtonBase-root MuiIconButton-root css-0 eb8w2fo2\\" tabindex=\\"0\\" type=\\"button\\" title=\\"Copy to Clipboard\\"><span class=\\"MuiIconButton-label\\"><svg class=\\"MuiSvgIcon-root\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z\\"></path></svg></span><span class=\\"MuiTouchRipple-root\\"></span></button></div><div class=\\"css-1mta3t8 eb8w2fo0\\"><span class=\\"css-lh0wgu eb8w2fo1\\">pnpm profile set password --registry https://registry.verdaccio.org</span><button class=\\"MuiButtonBase-root MuiIconButton-root css-0 eb8w2fo2\\" tabindex=\\"0\\" type=\\"button\\" title=\\"Copy to Clipboard\\"><span class=\\"MuiIconButton-label\\"><svg class=\\"MuiSvgIcon-root\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z\\"></path></svg></span><span class=\\"MuiTouchRipple-root\\"></span></button></div></div></div></div>"`;
exports[`<RegistryInfoContent /> component should render the component in default state with yarn tab 1`] = `"<div><div class=\\"MuiTabs-root\\"><div class=\\"MuiTabs-scroller MuiTabs-fixed\\" style=\\"overflow: hidden;\\"><div class=\\"MuiTabs-flexContainer\\" role=\\"tablist\\"><button class=\\"MuiButtonBase-root MuiTab-root MuiTab-textColorPrimary MuiTab-fullWidth\\" tabindex=\\"0\\" type=\\"button\\" role=\\"tab\\" aria-selected=\\"false\\"><span class=\\"MuiTab-wrapper\\">npm</span><span class=\\"MuiTouchRipple-root\\"></span></button><button class=\\"MuiButtonBase-root MuiTab-root MuiTab-textColorPrimary MuiTab-fullWidth\\" tabindex=\\"0\\" type=\\"button\\" role=\\"tab\\" aria-selected=\\"false\\"><span class=\\"MuiTab-wrapper\\">pnpm</span><span class=\\"MuiTouchRipple-root\\"></span></button><button class=\\"MuiButtonBase-root MuiTab-root MuiTab-textColorPrimary Mui-selected MuiTab-fullWidth\\" tabindex=\\"0\\" type=\\"button\\" role=\\"tab\\" aria-selected=\\"true\\"><span class=\\"MuiTab-wrapper\\">yarn</span><span class=\\"MuiTouchRipple-root\\"></span></button></div><span class=\\"PrivateTabIndicator-root-25 PrivateTabIndicator-colorPrimary-26 MuiTabs-indicator\\" style=\\"left: 0px; width: 0px;\\"></span></div></div><div class=\\"css-1qvg11o ehfwshd0\\"><div class=\\"MuiTypography-root css-17iubtz MuiTypography-h6\\"><div class=\\"css-1mta3t8 eb8w2fo0\\"><span class=\\"css-lh0wgu eb8w2fo1\\">yarn config set @registry https://registry.verdaccio.org</span><button class=\\"MuiButtonBase-root MuiIconButton-root css-0 eb8w2fo2\\" tabindex=\\"0\\" type=\\"button\\" title=\\"Copy to Clipboard\\"><span class=\\"MuiIconButton-label\\"><svg class=\\"MuiSvgIcon-root\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z\\"></path></svg></span><span class=\\"MuiTouchRipple-root\\"></span></button></div></div></div></div>"`;

View File

@@ -1,4 +1,4 @@
import styled from 'react-emotion';
import styled from '@emotion/styled';
export const CommandContainer = styled('div')({
'&&': {

View File

@@ -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';

View File

@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Repository /> component should render the component in default state 1`] = `"<ul class=\\"MuiList-root MuiList-dense MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-b8upko e1wmjxnh0 MuiTypography-subtitle1\\">Repository</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-xugzlj e1wmjxnh4 MuiListItem-dense MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiAvatar-root MuiAvatar-colorDefault\\"></div><div class=\\"MuiListItemText-root css-1vhg3jx e1wmjxnh5 MuiListItemText-dense\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body2\\"><div class=\\"css-1mta3t8 eb8w2fo0\\"><span class=\\"css-lh0wgu eb8w2fo1\\"><a href=\\"git+https://github.com/verdaccio/ui.git\\" target=\\"_blank\\" class=\\"css-15gl0ho e1wmjxnh2\\">git+https://github.com/verdaccio/ui.git</a></span><button class=\\"MuiButtonBase-root MuiIconButton-root css-0 eb8w2fo2\\" tabindex=\\"0\\" type=\\"button\\" title=\\"Copy to Clipboard\\"><span class=\\"MuiIconButton-label\\"><svg class=\\"MuiSvgIcon-root\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z\\"></path></svg></span><span class=\\"MuiTouchRipple-root\\"></span></button></div></span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;
exports[`<Repository /> component should render the component in default state 1`] = `"<ul class=\\"MuiList-root MuiList-dense MuiList-padding MuiList-subheader\\"><h6 class=\\"MuiTypography-root css-b8upko e1wmjxnh0 MuiTypography-subtitle1\\">Repository</h6><div class=\\"MuiButtonBase-root MuiListItem-root css-xugzlj e1wmjxnh4 MuiListItem-dense MuiListItem-gutters MuiListItem-button\\" tabindex=\\"0\\" role=\\"button\\" aria-disabled=\\"false\\"><div class=\\"MuiAvatar-root MuiAvatar-circle MuiAvatar-colorDefault\\"></div><div class=\\"MuiListItemText-root css-1vhg3jx e1wmjxnh5 MuiListItemText-dense\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body2\\"><div class=\\"css-1mta3t8 eb8w2fo0\\"><span class=\\"css-lh0wgu eb8w2fo1\\"><a href=\\"git+https://github.com/verdaccio/ui.git\\" target=\\"_blank\\" class=\\"css-15gl0ho e1wmjxnh2\\">git+https://github.com/verdaccio/ui.git</a></span><button class=\\"MuiButtonBase-root MuiIconButton-root css-0 eb8w2fo2\\" tabindex=\\"0\\" type=\\"button\\" title=\\"Copy to Clipboard\\"><span class=\\"MuiIconButton-label\\"><svg class=\\"MuiSvgIcon-root\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm-1 4l6 6v10c0 1.1-.9 2-2 2H7.99C6.89 23 6 22.1 6 21l.01-14c0-1.1.89-2 1.99-2h7zm-1 7h5.5L14 6.5V12z\\"></path></svg></span><span class=\\"MuiTouchRipple-root\\"></span></button></div></span></div><span class=\\"MuiTouchRipple-root\\"></span></div></ul>"`;

View File

@@ -1,12 +1,12 @@
import styled from 'react-emotion';
import Grid from '@material-ui/core/Grid';
import ListItemText from '@material-ui/core/ListItemText';
import styled from '@emotion/styled';
import Github from '../../icons/GitHub';
import colors from '../../utils/styles/colors';
import { fontWeight } from '../../utils/styles/sizes';
import Text from '../../muiComponents/Text';
import ListItem from '../../muiComponents/ListItem';
import ListItemText from '../../muiComponents/ListItemText';
import Grid from '../../muiComponents/Grid';
export const StyledText = styled(Text)({
fontWeight: fontWeight.bold,
@@ -14,9 +14,7 @@ export const StyledText = styled(Text)({
});
export const GridRepo = styled(Grid)({
'&&': {
alignItems: 'center',
},
alignItems: 'center',
});
export const GithubLink = styled('a')({

View File

@@ -1,199 +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 InputAdornment from '@material-ui/core/InputAdornment';
import React from 'react';
import debounce from 'lodash/debounce';
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;

View File

@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Search /> component test should load the component in default state 1`] = `"<div class=\\"css-1crzyyo e1rflf270\\"><div role=\\"combobox\\" aria-haspopup=\\"listbox\\" aria-owns=\\"react-autowhatever-1\\" aria-expanded=\\"false\\" class=\\"react-autosuggest__container\\"><div class=\\"MuiFormControl-root MuiTextField-root react-autosuggest__input MuiFormControl-fullWidth\\" aria-autocomplete=\\"list\\" aria-controls=\\"react-autowhatever-1\\"><div class=\\"MuiInputBase-root MuiInput-root css-n9ojyg MuiInput-underline MuiInputBase-fullWidth MuiInput-fullWidth MuiInputBase-formControl MuiInput-formControl MuiInputBase-adornedStart\\"><div class=\\"MuiInputAdornment-root css-16qv2i2 MuiInputAdornment-positionStart\\"><svg class=\\"MuiSvgIcon-root\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z\\"></path></svg></div><input aria-invalid=\\"false\\" autocomplete=\\"off\\" class=\\"MuiInputBase-input MuiInput-input css-hodoyq MuiInputBase-inputAdornedStart\\" placeholder=\\"Search Packages\\" type=\\"text\\" value=\\"\\"></div></div><div class=\\"MuiPaper-root MuiPaper-elevation1 react-autosuggest__suggestions-container css-cfo6a e1rflf271\\" id=\\"react-autowhatever-1\\" role=\\"listbox\\"></div></div></div>"`;
exports[`<Search /> component test should load the component in default state 1`] = `"<div class=\\"css-1crzyyo e1rflf270\\"><div role=\\"combobox\\" aria-haspopup=\\"listbox\\" aria-owns=\\"react-autowhatever-1\\" aria-expanded=\\"false\\" class=\\"react-autosuggest__container\\"><div class=\\"MuiFormControl-root MuiTextField-root react-autosuggest__input MuiFormControl-fullWidth\\" aria-autocomplete=\\"list\\" aria-controls=\\"react-autowhatever-1\\"><div class=\\"MuiInputBase-root MuiInput-root css-n9ojyg MuiInput-underline MuiInputBase-fullWidth MuiInput-fullWidth MuiInputBase-formControl MuiInput-formControl MuiInputBase-adornedStart\\"><div class=\\"MuiInputAdornment-root css-fvu7gn MuiInputAdornment-positionStart\\"><svg class=\\"MuiSvgIcon-root\\" focusable=\\"false\\" viewBox=\\"0 0 24 24\\" aria-hidden=\\"true\\" role=\\"presentation\\"><path d=\\"M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z\\"></path></svg></div><input aria-invalid=\\"false\\" autocomplete=\\"off\\" placeholder=\\"Search Packages\\" type=\\"text\\" class=\\"MuiInputBase-input MuiInput-input css-hodoyq MuiInputBase-inputAdornedStart\\" value=\\"\\"></div></div><div class=\\"MuiPaper-root MuiPaper-elevation1 react-autosuggest__suggestions-container css-cfo6a e1rflf271\\" id=\\"react-autowhatever-1\\" role=\\"listbox\\"></div></div></div>"`;

View File

@@ -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';

View File

@@ -1,4 +1,4 @@
import styled from 'react-emotion';
import styled from '@emotion/styled';
export const Wrapper = styled('span')({
'&&': {

View File

@@ -2,4 +2,4 @@
exports[`<UpLinks /> component should render the component when there is no uplink 1`] = `"<h6 class=\\"MuiTypography-root MuiTypography-subtitle1 MuiTypography-gutterBottom\\">verdaccio has no uplinks.</h6>"`;
exports[`<UpLinks /> component should render the component with uplinks 1`] = `"<h6 class=\\"MuiTypography-root css-1vg6q84 e14i1sy10 MuiTypography-subtitle1\\">Uplinks</h6><ul class=\\"MuiList-root MuiList-padding\\"><li class=\\"MuiListItem-root MuiListItem-gutters\\"><div class=\\"MuiListItemText-root css-5tz9yo e14i1sy12\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">npmjs</span></div><div class=\\"css-1l1cv61 e14i1sy11\\"></div><div class=\\"MuiListItemText-root css-5tz9yo e14i1sy12\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">over 1 year ago</span></div></li></ul>"`;
exports[`<UpLinks /> component should render the component with uplinks 1`] = `"<h6 class=\\"MuiTypography-root css-1vg6q84 e14i1sy10 MuiTypography-subtitle1\\">Uplinks</h6><ul class=\\"MuiList-root MuiList-padding\\"><li class=\\"MuiListItem-root MuiListItem-gutters\\"><div class=\\"MuiListItemText-root css-o655gb e14i1sy12\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">npmjs</span></div><div class=\\"css-1l1cv61 e14i1sy11\\"></div><div class=\\"MuiListItemText-root css-o655gb e14i1sy12\\"><span class=\\"MuiTypography-root MuiListItemText-primary MuiTypography-body1\\">over 1 year ago</span></div></li></ul>"`;

View File

@@ -1,7 +1,7 @@
import styled from 'react-emotion';
import { default as MuiListItemText } from '@material-ui/core/ListItemText';
import styled from '@emotion/styled';
import Text from '../../muiComponents/Text';
import { default as MuiListItemText } from '../../muiComponents/ListItemText';
import { fontWeight } from '../../utils/styles/sizes';
export const StyledText = styled(Text)({
@@ -16,9 +16,7 @@ export const Spacer = styled('div')({
});
export const ListItemText = styled(MuiListItemText)({
'&&': {
flex: 'none',
color: 'black',
opacity: 0.6,
},
flex: 'none',
color: 'black',
opacity: 0.6,
});

View File

@@ -44,7 +44,9 @@ describe('<Version /> component', () => {
});
test('should not render versions', () => {
const { queryByText } = render(<ComponentToBeRendered contextValue={{ packageName: detailContextValue.packageName }} />);
const { queryByText } = render(
<ComponentToBeRendered contextValue={{ packageName: detailContextValue.packageName }} />
);
expect(queryByText(LABEL_VERSION_HISTORY)).toBeFalsy();
expect(queryByText(LABEL_CURRENT_TAGS)).toBeFalsy();

View File

@@ -1,13 +1,11 @@
import React from 'react';
import Link from '@material-ui/core/Link';
import { Link as RouterLink } from 'react-router-dom';
import { Versions, Time } from '../../../types/packageMeta';
import { formatDateDistance } from '../../utils/package';
import List from '../../muiComponents/List';
import ListItem from '../../muiComponents/ListItem';
import { Spacer, ListItemText } from './styles';
import { Spacer, ListItemText, StyledLink } from './styles';
export const NOT_AVAILABLE = 'Not available';
@@ -23,9 +21,9 @@ const VersionsHistoryList: React.FC<Props> = ({ versions, packageName, time }) =
.reverse()
.map(version => (
<ListItem className="version-item" key={version}>
<Link component={RouterLink} to={`/-/web/detail/${packageName}/v/${version}`}>
<StyledLink to={`/-/web/detail/${packageName}/v/${version}`}>
<ListItemText>{version}</ListItemText>
</Link>
</StyledLink>
<Spacer />
<ListItemText>{time[version] ? `${formatDateDistance(time[version])} ago` : NOT_AVAILABLE}</ListItemText>
</ListItem>

View File

@@ -1,8 +1,9 @@
import styled from 'react-emotion';
import { default as MuiListItemText } from '@material-ui/core/ListItemText';
import styled from '@emotion/styled';
import { fontWeight } from '../../utils/styles/sizes';
import Text from '../../muiComponents/Text';
import { default as MuiListItemText } from '../../muiComponents/ListItemText';
import Link from '../Link';
export const StyledText = styled(Text)({
fontWeight: fontWeight.bold,
@@ -17,9 +18,11 @@ export const Spacer = styled('div')({
});
export const ListItemText = styled(MuiListItemText)({
'&&': {
flex: 'none',
color: 'black',
opacity: 0.6,
},
flex: 'none',
color: 'black',
opacity: 0.6,
});
export const StyledLink = styled(Link)({
textDecoration: 'none',
});

View 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;

View 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;

View File

@@ -0,0 +1,10 @@
import React, { forwardRef } from 'react';
import { default as MaterialUIAppBar, AppBarProps } from '@material-ui/core/AppBar';
type AppBarRef = HTMLElementTagNameMap[keyof HTMLElementTagNameMap];
const AppBar = forwardRef<AppBarRef, AppBarProps>(function AppBar(props, ref) {
return <MaterialUIAppBar {...props} ref={ref} />;
});
export default AppBar;

View File

@@ -0,0 +1 @@
export { default } from './AppBar';

View 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;

View 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;

View File

@@ -0,0 +1 @@
export { default } from './AutoComplete';

View File

@@ -0,0 +1,6 @@
import React from 'react';
import { default as MaterialUIBox, BoxProps } from '@material-ui/core/Box';
const Box: React.FC<BoxProps> = props => <MaterialUIBox {...props} />;
export default Box;

View File

@@ -0,0 +1 @@
export { default } from './Box';

View File

@@ -0,0 +1,10 @@
import React, { forwardRef } from 'react';
import { default as MaterialUICardActions, CardActionsProps } from '@material-ui/core/CardActions';
type CardActionsRef = HTMLDivElement;
const CardActions = forwardRef<CardActionsRef, CardActionsProps>(function CardContentActions(props, ref) {
return <MaterialUICardActions {...props} innerRef={ref} />;
});
export default CardActions;

View File

@@ -0,0 +1 @@
export { default } from './CardActions';

View File

@@ -0,0 +1,10 @@
import React, { forwardRef } from 'react';
import { default as MaterialUICardContent, CardContentProps } from '@material-ui/core/CardContent';
type CardContentRef = HTMLElementTagNameMap[keyof HTMLElementTagNameMap];
const CardContent = forwardRef<CardContentRef, CardContentProps>(function CardContent(props, ref) {
return <MaterialUICardContent {...props} innerRef={ref} />;
});
export default CardContent;

View File

@@ -0,0 +1 @@
export { default } from './CardContent';

View File

@@ -0,0 +1,10 @@
import React, { forwardRef } from 'react';
import { default as MaterialUIChip, ChipProps } from '@material-ui/core/Chip';
type ChipRef = HTMLElementTagNameMap[keyof HTMLElementTagNameMap];
const Chip = forwardRef<ChipRef, ChipProps>(function Chip(props, ref) {
return <MaterialUIChip {...props} innerRef={ref} />;
});
export default Chip;

View File

@@ -0,0 +1 @@
export { default } from './Chip';

View File

@@ -1,7 +1,7 @@
import React, { forwardRef } from 'react';
import { default as MaterialUIDivider, DividerProps } from '@material-ui/core/Divider';
type DividerRef = keyof HTMLElementTagNameMap;
type DividerRef = HTMLElementTagNameMap[keyof HTMLElementTagNameMap];
const Divider = forwardRef<DividerRef, DividerProps>(function Divider(props, ref) {
return <MaterialUIDivider {...props} innerRef={ref} />;

View File

@@ -0,0 +1,10 @@
import React, { forwardRef } from 'react';
import { default as MaterialUIFab, FabProps } from '@material-ui/core/Fab';
type FloatingActionButtonRef = HTMLButtonElement;
const FloatingActionButton = forwardRef<FloatingActionButtonRef, FabProps>(function FloatingActionButton(props, ref) {
return <MaterialUIFab {...props} ref={ref} />;
});
export default FloatingActionButton;

View File

@@ -0,0 +1 @@
export { default } from './FloatingActionButton';

View File

@@ -0,0 +1,10 @@
import React, { forwardRef } from 'react';
import { default as MaterialUIFormControl, FormControlProps } from '@material-ui/core/FormControl';
type FormControlRef = HTMLElementTagNameMap[keyof HTMLElementTagNameMap];
const FormControl = forwardRef<FormControlRef, FormControlProps>(function FormControl(props, ref) {
return <MaterialUIFormControl {...props} innerRef={ref} />;
});
export default FormControl;

View File

@@ -0,0 +1 @@
export { default } from './FormControl';

View File

@@ -0,0 +1,10 @@
import React, { forwardRef } from 'react';
import { default as MaterialUIFormHelperText, FormHelperTextProps } from '@material-ui/core/FormHelperText';
type FormHelperTextRef = HTMLButtonElement;
const FormHelperText = forwardRef<FormHelperTextRef, FormHelperTextProps>(function FormHelperText(props, ref) {
return <MaterialUIFormHelperText {...props} ref={ref} />;
});
export default FormHelperText;

Some files were not shown because too many files have changed in this diff Show More