1
0
mirror of https://github.com/SomboChea/ui synced 2026-01-20 01:55:56 +07:00

chore: sync with 4.x webui

This commit is contained in:
Juan Picado @jotadeveloper
2019-03-27 23:39:06 +01:00
parent e2d478d65b
commit 133a5f0171
88 changed files with 1302 additions and 1656 deletions

View File

@@ -1,3 +1,3 @@
if (!__DEBUG__) {
__webpack_public_path__ = window.VERDACCIO_API_URL.replace(/\/verdaccio\/$/, '/static/'); // eslint-disable-line
__webpack_public_path__ = window.VERDACCIO_API_URL.replace(/\/verdaccio\/$/, '/static/') // eslint-disable-line
}

View File

@@ -2,48 +2,48 @@ import storage from './storage';
class API {
request(url, method = 'GET', options = {}) {
if (!window.VERDACCIO_API_URL) {
throw new Error('VERDACCIO_API_URL is not defined!');
}
if (!window.VERDACCIO_API_URL) {
throw new Error('VERDACCIO_API_URL is not defined!');
}
const token = storage.getItem('token');
if (token) {
if (!options.headers) options.headers = {};
const token = storage.getItem('token');
if (token) {
if (!options.headers) options.headers = {};
options.headers.authorization = `Bearer ${token}`;
}
options.headers.authorization = `Bearer ${token}`;
}
if (!['http://', 'https://', '//'].some((prefix) => url.startsWith(prefix))) {
url = window.VERDACCIO_API_URL + url;
}
if (!['http://', 'https://', '//'].some((prefix) => url.startsWith(prefix))) {
url = window.VERDACCIO_API_URL + url;
}
/**
* Handles response according to content type
* @param {object} response
* @returns {promise}
*/
function handleResponseType(response) {
if (response.headers) {
const contentType = response.headers.get('Content-Type');
if (contentType.includes('application/pdf')) {
return Promise.all([response.ok, response.blob()]);
}
if (contentType.includes('application/json')) {
return Promise.all([response.ok, response.json()]);
}
// it includes all text types
if (contentType.includes('text/')) {
return Promise.all([response.ok, response.text()]);
/**
* Handles response according to content type
* @param {object} response
* @returns {promise}
*/
function handleResponseType(response) {
if (response.headers) {
const contentType = response.headers.get('Content-Type');
if (contentType.includes('application/pdf')) {
return Promise.all([response.ok, response.blob()]);
}
if (contentType.includes('application/json')) {
return Promise.all([response.ok, response.json()]);
}
// it includes all text types
if (contentType.includes('text/')) {
return Promise.all([response.ok, response.text()]);
}
}
}
}
return new Promise((resolve, reject) => {
fetch(url, {
method,
credentials: 'same-origin',
...options,
})
return new Promise((resolve, reject) => {
fetch(url, {
method,
credentials: 'same-origin',
...options,
})
.then(handleResponseType)
.then(([responseOk, body]) => {
if (responseOk) {
@@ -52,11 +52,11 @@ class API {
reject(body);
}
})
.catch((error) => {
.catch(error => {
reject(error);
});
});
}
});
}
}
export default new API();

View File

@@ -1,24 +1,32 @@
/**
* @prettier
*/
import React from 'react';
export function asyncComponent(getComponent) {
return class AsyncComponent extends React.Component {
static Component = null;
state = {Component: AsyncComponent.Component};
state = { Component: AsyncComponent.Component };
componentDidMount() {
const {Component} = this.state;
const { Component } = this.state;
if (!Component) {
getComponent().then(({default: Component}) => {
AsyncComponent.Component = Component;
/* eslint react/no-did-mount-set-state:0 */
this.setState({Component});
});
getComponent()
.then(({ default: Component }) => {
AsyncComponent.Component = Component;
/* eslint react/no-did-mount-set-state:0 */
this.setState({ Component });
})
.catch(err => {
console.error(err);
});
}
}
render() {
const {Component} = this.state;
const { Component } = this.state;
if (Component) {
// eslint-disable-next-line verdaccio/jsx-spread
return <Component {...this.props} />;
}

5
src/utils/file-size.js Normal file
View File

@@ -0,0 +1,5 @@
export default function fileSizeSI(a, b, c, d, e) {
return (b = Math, c = b.log, d = 1e3, e = c(a) / c(d) | 0, a / b.pow(d, e)).toFixed(2)
+ ' ' + (e ? 'kMGTPEZY'[--e] + 'B' : 'Bytes');
};

View File

@@ -1,76 +1,70 @@
import isString from "lodash/isString";
import isNumber from "lodash/isNumber";
import isEmpty from "lodash/isEmpty";
import { Base64 } from "js-base64";
import API from "./api";
const HEADERS = {
JSON: "application/json",
JSON_CHARSET: "application/json; charset=utf-8",
OCTET_STREAM: "application/octet-stream; charset=utf-8",
TEXT_CHARSET: "text/plain; charset=utf-8",
GZIP: "gzip"
};
import isString from 'lodash/isString';
import isNumber from 'lodash/isNumber';
import isEmpty from 'lodash/isEmpty';
import {Base64} from 'js-base64';
import API from './api';
import {HEADERS} from '../../lib/constants';
export function isTokenExpire(token) {
if (!isString(token)) {
return true;
}
if (!isString(token)) {
return true;
}
let [, payload] = token.split(".");
let [,payload] = token.split('.');
if (!payload) {
return true;
}
if (!payload) {
return true;
}
try {
payload = JSON.parse(Base64.decode(payload));
} catch (error) {
// eslint-disable-next-line
console.error("Invalid token:", error, token);
return true;
}
try {
payload = JSON.parse(Base64.decode(payload));
} catch (error) {
// eslint-disable-next-line
console.error('Invalid token:', error, token);
return true;
}
if (!payload.exp || !isNumber(payload.exp)) {
return true;
}
// Report as expire before (real expire time - 30s)
const jsTimestamp = payload.exp * 1000 - 30000;
const expired = Date.now() >= jsTimestamp;
if (!payload.exp || !isNumber(payload.exp)) {
return true;
}
// Report as expire before (real expire time - 30s)
const jsTimestamp = (payload.exp * 1000) - 30000;
const expired = Date.now() >= jsTimestamp;
return expired;
return expired;
}
export async function makeLogin(username, password) {
// checks isEmpty
if (isEmpty(username) || isEmpty(password)) {
const error = {
title: "Unable to login",
type: "error",
description: "Username or password can't be empty!"
};
return { error };
}
// checks isEmpty
if (isEmpty(username) || isEmpty(password)) {
const error = {
title: 'Unable to login',
type: 'error',
description: 'Username or password can\'t be empty!',
};
return {error};
}
try {
const response = await API.request("login", "POST", {
body: JSON.stringify({ username, password }),
headers: {
Accept: HEADERS.JSON,
"Content-Type": HEADERS.JSON
}
});
const result = {
username: response.username,
token: response.token
};
return result;
} catch (e) {
const error = {
title: "Unable to login",
type: "error",
description: e.error
};
return { error };
}
try {
const response = await API.request('login', 'POST', {
body: JSON.stringify({username, password}),
headers: {
Accept: HEADERS.JSON,
'Content-Type': HEADERS.JSON,
},
});
const result = {
username: response.username,
token: response.token,
};
return result;
} catch (e) {
const error = {
title: 'Unable to login',
type: 'error',
description: e.error,
};
return {error};
}
}

View File

@@ -4,7 +4,6 @@ import format from 'date-fns/format';
import distanceInWordsToNow from 'date-fns/distance_in_words_to_now';
export const TIMEFORMAT = 'DD.MM.YYYY, HH:mm:ss';
export const DEFAULT_USER = 'Anonymous';
/**
* Formats license field for webui.
@@ -39,36 +38,6 @@ export function formatRepository(repository) {
}
/**
* Formats author field for webui.
* @see https://docs.npmjs.com/files/package.json#author
*/
export function formatAuthor(author) {
let authorDetails = {
name: DEFAULT_USER,
email: '',
avatar: '',
};
if (isString(author)) {
authorDetails = {
...authorDetails,
name: author ? author : authorDetails.name,
};
}
if (isObject(author)) {
authorDetails = {
...authorDetails,
name: author.name ? author.name : authorDetails.name,
email: author.email ? author.email : authorDetails.email,
avatar: author.avatar ? author.avatar : authorDetails.avatar,
};
}
return authorDetails;
}
/**
* For <LastSync /> component
* @param {array} uplinks

View File

@@ -10,7 +10,10 @@ const colors = {
grey: '#808080',
greySuperLight: '#f5f5f5',
greyLight: '#d3d3d3',
greyLight2: '#908ba1',
greyLight3: '#f3f4f240',
greyDark: '#a9a9a9',
greyDark2: '#586069',
greyChateau: '#95989a',
greyGainsboro: '#e3e3e3',
greyAthens: '#d3dddd',

View File

@@ -1,6 +1,6 @@
import { css } from 'emotion';
const breakpoints = {
export const breakpoints = {
small: 576,
medium: 768,
large: 1024,

View File

@@ -2,11 +2,3 @@ export function getRegistryURL() {
// Don't add slash if it's not a sub directory
return `${location.origin}${location.pathname === '/' ? '' : location.pathname}`;
}
/**
* Get specified package detail page url
* @param {string} packageName
*/
export function getDetailPageURL(packageName) {
return `${getRegistryURL()}/-/web/version/${packageName}`;
}

View File

@@ -1,3 +1,3 @@
export function goToVerdaccioWebsite() {
window.open('https://www.verdaccio.org/', '_blank');
window.open('https://www.verdaccio.org/', '_blank');
}