未验证 提交 cdb82390 编写于 作者: P Peter Pan 提交者: GitHub

frontend 2.0.0-beta.24: more style lint rules, add server language detection,...

frontend 2.0.0-beta.24: more style lint rules, add server language detection, build process improvement (#604)

* chore: fit requirements of python 3

* feat: fix global frontend lint

* build: use cached frontend package

* feat: add browser language detection

* style: introduce sort imports, more style mixins

* 2.0.0-beta.24
上级 3f9a02f5
#!/bin/bash #!/bin/bash
# if there are no staged changes, we can exit immediately set -e
# this is fast and prevents issues when popping a stash we didn't create
STAGED_CHANGES=`git diff-index --cached HEAD --name-only --diff-filter ACMR`
if [ -z "$STAGED_CHANGES" ]; then
exit 0
fi
# Capture the path to the eslint
cd frontend cd frontend
ESLINT_EXECUTABLE=$(npm bin)/eslint `npm bin`/lint-staged
cd ..
# Test against with both .js and .vue files
git diff --cached --name-only --diff-filter ACMR | egrep '.(js|vue)$' | xargs $ESLINT_EXECUTABLE --fix
RESULT=$? RESULT=$?
cd ..
[ $RESULT -ne 0 ] && exit 1 [ $RESULT -ne 0 ] && exit 1
exit 0 exit 0
...@@ -32,6 +32,7 @@ module.exports = { ...@@ -32,6 +32,7 @@ module.exports = {
'react/react-in-jsx-scope': 'off', 'react/react-in-jsx-scope': 'off',
'react-hooks/rules-of-hooks': 'error', 'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn', 'react-hooks/exhaustive-deps': 'warn',
'no-console': 'warn' 'no-console': 'warn',
'sort-imports': 'error'
} }
}; };
from node:12-alpine FROM node:12-alpine
# Create app directory # Create app directory
WORKDIR /usr/src/app WORKDIR /usr/src/app
......
...@@ -25,7 +25,7 @@ const argv = require('yargs') ...@@ -25,7 +25,7 @@ const argv = require('yargs')
.demandOption(['b']) .demandOption(['b'])
.help('h') .help('h')
.alias('h', 'help') .alias('h', 'help')
.epilog('Visit https://github.com/PaddlePaddle/VisualDL for more infomation.').argv; .epilog('Visit https://github.com/PaddlePaddle/VisualDL for more information.').argv;
const command = argv._[0]; const command = argv._[0];
......
import React, {FunctionComponent} from 'react'; import React, {FunctionComponent} from 'react';
import styled from 'styled-components';
import {rem} from '~/utils/style'; import {rem} from '~/utils/style';
import styled from 'styled-components';
const Divider = styled.hr<{height?: string | number}>` const Divider = styled.hr<{height?: string | number}>`
background-color: transparent; background-color: transparent;
......
import React, {FunctionComponent} from 'react'; import React, {FunctionComponent} from 'react';
import styled from 'styled-components';
import { import {
WithStyled, WithStyled,
ellipsis,
em, em,
half, half,
textInvertColor, primaryActiveColor,
primaryColor, primaryColor,
primaryFocusedColor, primaryFocusedColor,
primaryActiveColor, textInvertColor,
duration, transitionProps
easing,
ellipsis,
transitions
} from '~/utils/style'; } from '~/utils/style';
import RawIcon from '~/components/Icon'; import RawIcon from '~/components/Icon';
import styled from 'styled-components';
const height = em(36); const height = em(36);
...@@ -26,7 +25,7 @@ const Wrapper = styled.a` ...@@ -26,7 +25,7 @@ const Wrapper = styled.a`
color: ${textInvertColor}; color: ${textInvertColor};
display: block; display: block;
text-align: center; text-align: center;
${transitions('background-color', `${duration} ${easing}`)} ${transitionProps('background-color')}
${ellipsis()} ${ellipsis()}
&:hover, &:hover,
......
import React, {FunctionComponent} from 'react'; import React, {FunctionComponent} from 'react';
import styled from 'styled-components';
import { import {
WithStyled, WithStyled,
primaryColor,
backgroundColor, backgroundColor,
borderColor,
borderRadius, borderRadius,
duration, math,
easing, primaryColor,
transitions, sameBorder,
math transitionProps
} from '~/utils/style'; } from '~/utils/style';
import styled from 'styled-components';
const Div = styled.div` const Div = styled.div`
background-color: ${backgroundColor}; background-color: ${backgroundColor};
border: 1px solid ${borderColor}; ${sameBorder({radius: math(`${borderRadius} * 2`)})}
border-radius: ${math(`${borderRadius} * 2`)}; ${transitionProps(['border-color', 'box-shadow'])}
${transitions(['border-color', 'box-shadow'], `${duration} ${easing}`)}
&:hover { &:hover {
border-color: ${primaryColor}; border-color: ${primaryColor};
......
import React, {FunctionComponent, useState, useMemo} from 'react'; import React, {FunctionComponent, useMemo, useState} from 'react';
import styled from 'styled-components'; import {WithStyled, primaryColor, rem} from '~/utils/style';
import BarLoader from 'react-spinners/BarLoader'; import BarLoader from 'react-spinners/BarLoader';
import {WithStyled, rem, primaryColor} from '~/utils/style';
import {useTranslation} from '~/utils/i18n';
import Chart from '~/components/Chart'; import Chart from '~/components/Chart';
import Pagination from '~/components/Pagination'; import Pagination from '~/components/Pagination';
import styled from 'styled-components';
import {useTranslation} from '~/utils/i18n';
const Wrapper = styled.div` const Wrapper = styled.div`
display: flex; display: flex;
...@@ -38,7 +39,7 @@ const Empty = styled.div` ...@@ -38,7 +39,7 @@ const Empty = styled.div`
`; `;
// TODO: add types // TODO: add types
// eslint-disable-next-line // eslint-disable-next-line @typescript-eslint/no-explicit-any
type ChartPageProps<T = any> = { type ChartPageProps<T = any> = {
items?: T[]; items?: T[];
loading?: boolean; loading?: boolean;
......
import React, {FunctionComponent, useState, useEffect, useCallback} from 'react'; import React, {FunctionComponent, useCallback, useEffect, useState} from 'react';
import styled from 'styled-components';
import { import {
WithStyled, WithStyled,
em,
textLighterColor,
textInvertColor,
backgroundColor, backgroundColor,
primaryColor, darken,
duration,
size,
easing,
ellipsis, ellipsis,
transitions, em,
half,
lighten,
math, math,
darken, position,
lighten primaryColor,
sameBorder,
size,
textInvertColor,
textLighterColor,
transitionProps
} from '~/utils/style'; } from '~/utils/style';
import styled from 'styled-components';
const height = em(20); const height = em(20);
const checkSize = em(16); const checkSize = em(16);
const checkMark = const checkMark =
...@@ -34,10 +36,8 @@ const Input = styled.input.attrs<{disabled?: boolean}>(props => ({ ...@@ -34,10 +36,8 @@ const Input = styled.input.attrs<{disabled?: boolean}>(props => ({
type: 'checkbox', type: 'checkbox',
disabled: !!props.disabled disabled: !!props.disabled
}))` }))`
${size(0, 0)} ${size(0)}
position: absolute; ${position('absolute', 0, null, null, 0)}
left: 0;
top: 0;
opacity: 0; opacity: 0;
pointer-events: none; pointer-events: none;
`; `;
...@@ -46,14 +46,14 @@ const Inner = styled.div<{checked?: boolean; size?: string; disabled?: boolean}> ...@@ -46,14 +46,14 @@ const Inner = styled.div<{checked?: boolean; size?: string; disabled?: boolean}>
color: ${props => (props.checked ? textInvertColor : 'transparent')}; color: ${props => (props.checked ? textInvertColor : 'transparent')};
flex-shrink: 0; flex-shrink: 0;
${props => size(math(`${checkSize} * ${props.size === 'small' ? 0.875 : 1}`))} ${props => size(math(`${checkSize} * ${props.size === 'small' ? 0.875 : 1}`))}
margin: ${math(`(${height} - ${checkSize}) / 2`)} 0; margin: ${half(`${height} - ${checkSize}`)} 0;
margin-right: ${em(4)}; margin-right: ${em(4)};
border: 1px solid ${props => (props.disabled || !props.checked ? textLighterColor : primaryColor)}; ${props => sameBorder({color: props.disabled || !props.checked ? textLighterColor : primaryColor})};
background-color: ${props => background-color: ${props =>
props.disabled props.disabled
? props.checked ? props.checked
? textLighterColor ? textLighterColor
: lighten(0.333, textLighterColor) : lighten(1 / 3, textLighterColor)
: props.checked : props.checked
? primaryColor ? primaryColor
: backgroundColor}; : backgroundColor};
...@@ -62,7 +62,7 @@ const Inner = styled.div<{checked?: boolean; size?: string; disabled?: boolean}> ...@@ -62,7 +62,7 @@ const Inner = styled.div<{checked?: boolean; size?: string; disabled?: boolean}>
background-position: center center; background-position: center center;
background-size: ${em(10)} ${em(8)}; background-size: ${em(10)} ${em(8)};
position: relative; position: relative;
${transitions(['border-color', 'background-color', 'color'], `${duration} ${easing}`)} ${transitionProps(['border-color', 'background-color', 'color'])}
${Wrapper}:hover > & { ${Wrapper}:hover > & {
border-color: ${props => border-color: ${props =>
......
import React, {FunctionComponent} from 'react'; import React, {FunctionComponent} from 'react';
import styled from 'styled-components'; import {asideWidth, backgroundColor, headerHeight, math, position, primaryColor, rem, size} from '~/utils/style';
import HashLoader from 'react-spinners/HashLoader'; import HashLoader from 'react-spinners/HashLoader';
import {rem, math, headerHeight, asideWidth, backgroundColor, primaryColor} from '~/utils/style'; import styled from 'styled-components';
const margin = rem(20); const margin = rem(20);
const padding = rem(20); const padding = rem(20);
...@@ -20,25 +21,17 @@ const Article = styled.article<{aside?: boolean}>` ...@@ -20,25 +21,17 @@ const Article = styled.article<{aside?: boolean}>`
`; `;
const Aside = styled.aside` const Aside = styled.aside`
width: ${asideWidth};
padding: ${padding}; padding: ${padding};
background-color: ${backgroundColor}; background-color: ${backgroundColor};
height: calc(100vh - ${headerHeight}); ${size(`calc(100vh - ${headerHeight})`, asideWidth)}
position: fixed; ${position('fixed', headerHeight, 0, null, null)}
top: ${headerHeight};
right: 0;
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
`; `;
const Loading = styled.div` const Loading = styled.div`
width: 100vw; ${size('100vh', '100vw')}
height: 100vh; ${position('fixed', 0, 0, 0, 0)}
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 255, 255, 0.8); background-color: rgba(255, 255, 255, 0.8);
display: flex; display: flex;
justify-content: center; justify-content: center;
......
import React, {FunctionComponent} from 'react'; import React, {FunctionComponent} from 'react';
import styled from 'styled-components';
import {WithStyled, rem} from '~/utils/style'; import {WithStyled, rem} from '~/utils/style';
import styled from 'styled-components';
const Wrapper = styled.div` const Wrapper = styled.div`
& + & { & + & {
margin-top: ${rem(20)}; margin-top: ${rem(20)};
......
import React, {FunctionComponent} from 'react';
import {useTranslation} from '~/utils/i18n';
import {NodeType, TypedNode} from '~/resource/graphs'; import {NodeType, TypedNode} from '~/resource/graphs';
import React, {FunctionComponent} from 'react';
import {WithStyled, textLightColor} from '~/utils/style';
import styled from 'styled-components'; import styled from 'styled-components';
import {WithStyled} from '~/utils/style'; import {useTranslation} from '~/utils/i18n';
const typeName: {[k in NodeType]: string} = { const typeName: {[k in NodeType]: string} = {
[NodeType.Input]: 'input', [NodeType.Input]: 'input',
...@@ -29,14 +30,15 @@ const DataList: FunctionComponent<{items: {key: string; value: string | string[] ...@@ -29,14 +30,15 @@ const DataList: FunctionComponent<{items: {key: string; value: string | string[]
const PropertyList = styled(DataList)` const PropertyList = styled(DataList)`
padding: 0; padding: 0;
list-style: none; list-style: none;
color: #666; color: ${textLightColor};
li + li { li + li {
margin-top: 1em; margin-top: 1em;
} }
`; `;
const NodeInfo: FunctionComponent<NodeInfoProps> = props => { const NodeInfo: FunctionComponent<NodeInfoProps> = props => {
const {t} = useTranslation(['graphs']); const {t} = useTranslation('graphs');
if (!props.node) { if (!props.node) {
return <p>{t('click-node')}</p>; return <p>{t('click-node')}</p>;
} }
...@@ -51,7 +53,7 @@ const NodeInfo: FunctionComponent<NodeInfoProps> = props => { ...@@ -51,7 +53,7 @@ const NodeInfo: FunctionComponent<NodeInfoProps> = props => {
{key: t('node-type'), value: typeName[node.type]}, {key: t('node-type'), value: typeName[node.type]},
{key: t('node-name'), value: node.name}, {key: t('node-name'), value: node.name},
{key: t('node-data-shape'), value: node.shape}, {key: t('node-data-shape'), value: node.shape},
{key: t('node-data-tyep'), value: node.data_type} {key: t('node-data-type'), value: node.data_type}
]} ]}
/> />
); );
...@@ -69,7 +71,7 @@ const NodeInfo: FunctionComponent<NodeInfoProps> = props => { ...@@ -69,7 +71,7 @@ const NodeInfo: FunctionComponent<NodeInfoProps> = props => {
case 'unknown': case 'unknown':
return <PropertyList items={[{key: t('node-type'), value: typeName[node.guessType]}]} />; return <PropertyList items={[{key: t('node-type'), value: typeName[node.guessType]}]} />;
default: default:
return <></>; return null;
} }
}; };
......
import {Dimension, DivideParams, Point, Reduction, divide} from '~/resource/high-dimensional';
import React, {FunctionComponent, useMemo} from 'react'; import React, {FunctionComponent, useMemo} from 'react';
import styled from 'styled-components'; import {primaryColor, rem} from '~/utils/style';
import ScatterChart from '~/components/ScatterChart';
import queryString from 'query-string'; import queryString from 'query-string';
import {rem, primaryColor} from '~/utils/style'; import styled from 'styled-components';
import {useTranslation} from '~/utils/i18n';
import {useRunningRequest} from '~/hooks/useRequest';
import useHeavyWork from '~/hooks/useHeavyWork'; import useHeavyWork from '~/hooks/useHeavyWork';
import {divide, Dimension, Reduction, DivideParams, Point} from '~/resource/high-dimensional'; import {useRunningRequest} from '~/hooks/useRequest';
import ScatterChart from '~/components/ScatterChart'; import {useTranslation} from '~/utils/i18n';
const height = rem(600); const height = rem(600);
......
import React, {FunctionComponent} from 'react'; import React, {FunctionComponent} from 'react';
import {WithStyled} from '~/utils/style'; import {WithStyled} from '~/utils/style';
type IconProps = { type IconProps = {
......
import React, {FunctionComponent, useLayoutEffect, useState} from 'react'; import React, {FunctionComponent, useLayoutEffect, useState} from 'react';
import useRequest from '~/hooks/useRequest';
import GridLoader from 'react-spinners/GridLoader';
import {blobFetcher} from '~/utils/fetch';
import {primaryColor} from '~/utils/style'; import {primaryColor} from '~/utils/style';
import useRequest from '~/hooks/useRequest';
import {useTranslation} from '~/utils/i18n'; import {useTranslation} from '~/utils/i18n';
import {blobFetcher} from '~/utils/fetch';
import GridLoader from 'react-spinners/GridLoader';
type ImageProps = { type ImageProps = {
src?: string; src?: string;
......
import React, {FunctionComponent} from 'react'; import React, {FunctionComponent} from 'react';
import {WithStyled, borderFocusedColor, em, half, sameBorder, textLighterColor, transitionProps} from '~/utils/style';
import styled from 'styled-components'; import styled from 'styled-components';
import {
WithStyled,
em,
textLighterColor,
borderColor,
borderFocusedColor,
borderRadius,
duration,
easing,
math
} from '~/utils/style';
export const padding = em(10); export const padding = em(10);
export const height = em(36); export const height = em(36);
...@@ -20,10 +11,9 @@ const StyledInput = styled.input<{rounded?: boolean}>` ...@@ -20,10 +11,9 @@ const StyledInput = styled.input<{rounded?: boolean}>`
height: ${height}; height: ${height};
line-height: ${height}; line-height: ${height};
display: inline-block; display: inline-block;
border: 1px solid ${borderColor};
border-radius: ${props => (props.rounded ? math(`${height} / 2`) : borderRadius)};
transition: border-color ${duration} ${easing};
outline: none; outline: none;
${props => sameBorder({radius: !props.rounded || half(height)})};
${transitionProps('border-color')}
&:hover, &:hover,
&:focus { &:focus {
......
import React, {FunctionComponent} from 'react'; import React, {FunctionComponent} from 'react';
import styled from 'styled-components'; import {headerHeight, position, size} from '~/utils/style';
import {headerHeight} from '~/utils/style';
import Navbar from '~/components/Navbar'; import Navbar from '~/components/Navbar';
import styled from 'styled-components';
const Main = styled.main` const Main = styled.main`
padding-top: ${headerHeight}; padding-top: ${headerHeight};
`; `;
const Header = styled.header` const Header = styled.header`
position: fixed;
z-index: 10000; z-index: 10000;
width: 100%;
height: ${headerHeight}; ${size(headerHeight, '100%')}
top: 0; ${position('fixed', 0, 0, null, 0)}
left: 0;
right: 0;
`; `;
const Layout: FunctionComponent = ({children}) => ( const Layout: FunctionComponent = ({children}) => (
......
import React, {FunctionComponent, useEffect, useCallback} from 'react'; import * as chart from '~/utils/chart';
import styled from 'styled-components';
import React, {FunctionComponent, useCallback, useEffect} from 'react';
import {WithStyled, position, primaryColor, size} from '~/utils/style';
import {EChartOption} from 'echarts'; import {EChartOption} from 'echarts';
import GridLoader from 'react-spinners/GridLoader'; import GridLoader from 'react-spinners/GridLoader';
import {WithStyled, primaryColor} from '~/utils/style';
import {useTranslation} from '~/utils/i18n';
import useECharts from '~/hooks/useECharts';
import {formatTime} from '~/utils'; import {formatTime} from '~/utils';
import * as chart from '~/utils/chart'; import styled from 'styled-components';
import useECharts from '~/hooks/useECharts';
import {useTranslation} from '~/utils/i18n';
const Wrapper = styled.div` const Wrapper = styled.div`
position: relative; position: relative;
...@@ -16,11 +18,8 @@ const Wrapper = styled.div` ...@@ -16,11 +18,8 @@ const Wrapper = styled.div`
} }
> .loading { > .loading {
position: absolute; ${size('100%')}
top: 0; ${position('absolute', 0, null, null, 0)}
left: 0;
height: 100%;
width: 100%;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
......
import {Link, useTranslation} from '~/utils/i18n';
import React, {FunctionComponent} from 'react'; import React, {FunctionComponent} from 'react';
import {
border,
navbarBackgroundColor,
navbarHighlightColor,
navbarHoverBackgroundColor,
rem,
size,
textInvertColor,
transitionProps
} from '~/utils/style';
import styled from 'styled-components'; import styled from 'styled-components';
import {useRouter} from 'next/router'; import {useRouter} from 'next/router';
import {useTranslation, Link} from '~/utils/i18n';
import {rem, headerColor, duration, easing, lighten, transitions} from '~/utils/style';
const navItems = ['scalars', 'samples', 'graphs', 'high-dimensional']; const navItems = ['scalars', 'samples', 'graphs', 'high-dimensional'];
const Nav = styled.nav` const Nav = styled.nav`
background-color: ${headerColor}; background-color: ${navbarBackgroundColor};
color: #fff; color: ${textInvertColor};
height: 100%; ${size('100%')}
width: 100%;
padding: 0 ${rem(20)}; padding: 0 ${rem(20)};
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
...@@ -25,8 +34,7 @@ const Logo = styled.a` ...@@ -25,8 +34,7 @@ const Logo = styled.a`
margin-right: ${rem(40)}; margin-right: ${rem(40)};
> img { > img {
width: ${rem(98)}; ${size(rem(31), rem(98))}
height: ${rem(31)};
vertical-align: middle; vertical-align: middle;
margin-right: ${rem(8)}; margin-right: ${rem(8)};
} }
...@@ -42,17 +50,17 @@ const NavItem = styled.a<{active: boolean}>` ...@@ -42,17 +50,17 @@ const NavItem = styled.a<{active: boolean}>`
display: inline-flex; display: inline-flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
background-color: ${headerColor}; background-color: ${navbarBackgroundColor};
${transitions(['background-color'], `${duration} ${easing}`)} ${transitionProps('background-color')}
&:hover { &:hover {
background-color: ${lighten(0.05, headerColor)}; background-color: ${navbarHoverBackgroundColor};
} }
> span { > span {
padding: ${rem(10)} 0 ${rem(7)}; padding: ${rem(10)} 0 ${rem(7)};
border-bottom: ${rem(3)} solid ${props => (props.active ? '#596cd6' : 'transparent')}; ${props => border('bottom', rem(3), 'solid', props.active ? navbarHighlightColor : 'transparent')}
${transitions(['border-bottom'], `${duration} ${easing}`)} ${transitionProps('border-bottom')}
text-transform: uppercase; text-transform: uppercase;
} }
`; `;
......
import React, {FunctionComponent, useMemo, useCallback} from 'react'; // cSpell:words hellip
import styled from 'styled-components';
import React, {FunctionComponent, useCallback, useMemo} from 'react';
import { import {
WithStyled, WithStyled,
em,
primaryColor,
backgroundColor, backgroundColor,
borderColor, borderColor,
textInvertColor,
textColor,
borderRadius,
borderFocusedColor, borderFocusedColor,
duration, em,
easing, primaryColor,
transitions, sameBorder,
size size,
textColor,
textInvertColor,
transitionProps
} from '~/utils/style'; } from '~/utils/style';
import styled from 'styled-components';
const height = em(36); const height = em(36);
const Wrapper = styled.nav` const Wrapper = styled.nav`
...@@ -49,9 +50,8 @@ const A = styled.a<{current?: boolean}>` ...@@ -49,9 +50,8 @@ const A = styled.a<{current?: boolean}>`
min-width: ${height}; min-width: ${height};
padding: 0 ${em(10)}; padding: 0 ${em(10)};
text-align: center; text-align: center;
border: 1px solid ${props => (props.current ? primaryColor : borderColor)}; ${props => sameBorder({color: props.current ? primaryColor : borderColor, radius: true})};
border-radius: ${borderRadius}; ${transitionProps(['color', 'border-color', 'background-color'])}
${transitions(['color', 'border-color', 'background-color'], `${duration} ${easing}`)}
&:hover { &:hover {
border-color: ${props => (props.current ? primaryColor : borderFocusedColor)}; border-color: ${props => (props.current ? primaryColor : borderFocusedColor)};
......
import React, {FunctionComponent} from 'react'; import React, {FunctionComponent} from 'react';
import Head from 'next/head'; import Head from 'next/head';
type PreloaderProps = { type PreloaderProps = {
......
import React, {FunctionComponent, useContext, useCallback} from 'react'; import {EventContext, ValueContext} from '~/components/RadioGroup';
import styled from 'styled-components'; import React, {FunctionComponent, useCallback, useContext} from 'react';
import { import {
WithStyled, WithStyled,
em, backgroundColor,
textColor,
textInvertColor,
borderColor, borderColor,
borderFocusedColor,
borderRadius, borderRadius,
backgroundColor, borderRadiusShortHand,
primaryColor,
duration,
easing,
ellipsis, ellipsis,
transitions, em,
borderFocusedColor primaryColor,
sameBorder,
textColor,
textInvertColor,
transitionProps
} from '~/utils/style'; } from '~/utils/style';
import {ValueContext, EventContext} from '~/components/RadioGroup';
import styled from 'styled-components';
const height = em(36); const height = em(36);
const minWidth = em(72); const minWidth = em(72);
...@@ -28,10 +29,11 @@ const Button = styled.a<{selected?: boolean}>` ...@@ -28,10 +29,11 @@ const Button = styled.a<{selected?: boolean}>`
height: ${height}; height: ${height};
line-height: calc(${height} - 2px); line-height: calc(${height} - 2px);
min-width: ${minWidth}; min-width: ${minWidth};
${ellipsis(maxWidth)}
text-align: center; text-align: center;
border: 1px solid ${props => (props.selected ? primaryColor : borderColor)}; ${ellipsis(maxWidth)}
${transitions(['color', 'border-color', 'background-color'], `${duration} ${easing}`)} ${props => sameBorder({color: props.selected ? primaryColor : borderColor})};
${transitionProps(['color', 'border-color', 'background-color'])}
/* bring selected one to top in order to cover the sibling's border */ /* bring selected one to top in order to cover the sibling's border */
${props => (props.selected ? 'position: relative;' : '')} ${props => (props.selected ? 'position: relative;' : '')}
...@@ -40,13 +42,11 @@ const Button = styled.a<{selected?: boolean}>` ...@@ -40,13 +42,11 @@ const Button = styled.a<{selected?: boolean}>`
} }
&:first-of-type { &:first-of-type {
border-top-left-radius: ${borderRadius}; ${borderRadiusShortHand('left', borderRadius)}
border-bottom-left-radius: ${borderRadius};
} }
&:last-of-type { &:last-of-type {
border-top-right-radius: ${borderRadius}; ${borderRadiusShortHand('right', borderRadius)}
border-bottom-right-radius: ${borderRadius};
} }
& + & { & + & {
......
import React, {FunctionComponent, createContext, useState, useCallback} from 'react'; import React, {FunctionComponent, createContext, useCallback, useState} from 'react';
import styled from 'styled-components';
import {WithStyled} from '~/utils/style'; import {WithStyled} from '~/utils/style';
import styled from 'styled-components';
const Wrapper = styled.div` const Wrapper = styled.div`
display: inline-flex; display: inline-flex;
......
import InputRange, {Range} from 'react-input-range';
import React, {FunctionComponent, useCallback} from 'react'; import React, {FunctionComponent, useCallback} from 'react';
import {
WithStyled,
backgroundColor,
em,
half,
position,
primaryColor,
sameBorder,
size,
textLighterColor
} from '~/utils/style';
import styled from 'styled-components'; import styled from 'styled-components';
import {WithStyled, em, size, half, math, primaryColor, textLighterColor, backgroundColor} from '~/utils/style';
import InputRange, {Range} from 'react-input-range';
const height = em(20); const height = em(20);
const railHeight = em(4); const railHeight = em(4);
...@@ -23,10 +34,8 @@ const Wrapper = styled.div<{disabled?: boolean}>` ...@@ -23,10 +34,8 @@ const Wrapper = styled.div<{disabled?: boolean}>`
cursor: ${props => (props.disabled ? 'not-allowed' : 'pointer')}; cursor: ${props => (props.disabled ? 'not-allowed' : 'pointer')};
&--background { &--background {
height: ${railHeight}; ${size(railHeight, '100%')}
width: 100%; ${position('absolute', '50%', null, null, null)}
position: absolute;
top: 50%;
margin-top: -${half(railHeight)}; margin-top: -${half(railHeight)};
background-color: ${railColor}; background-color: ${railColor};
border-radius: ${half(railHeight)}; border-radius: ${half(railHeight)};
...@@ -42,14 +51,18 @@ const Wrapper = styled.div<{disabled?: boolean}>` ...@@ -42,14 +51,18 @@ const Wrapper = styled.div<{disabled?: boolean}>`
} }
&__slider-container { &__slider-container {
top: -${math(`(${thumbSize} - ${railHeight}) / 2`)}; top: -${half(`${thumbSize} - ${railHeight}`)};
margin-left: -${half(thumbSize)}; margin-left: -${half(thumbSize)};
} }
&__slider { &__slider {
${size(thumbSize)} ${size(thumbSize)}
border-radius: ${half(thumbSize)}; ${props =>
border: ${em(3)} solid ${props => (props.disabled ? textLighterColor : primaryColor)}; sameBorder({
width: em(3),
color: props.disabled ? textLighterColor : primaryColor,
radius: half(thumbSize)
})}
background-color: ${backgroundColor}; background-color: ${backgroundColor};
} }
} }
......
import React, {FunctionComponent} from 'react'; import React, {FunctionComponent} from 'react';
import styled from 'styled-components'; import Select, {SelectValueType} from '~/components/Select';
import {rem} from '~/utils/style'; import {rem} from '~/utils/style';
import styled from 'styled-components';
import {useTranslation} from '~/utils/i18n'; import {useTranslation} from '~/utils/i18n';
import Select, {SelectValueType} from '~/components/Select';
const Title = styled.div` const Title = styled.div`
font-size: ${rem(16)}; font-size: ${rem(16)};
......
import React, {FunctionComponent, useState, useEffect} from 'react'; import React, {FunctionComponent, useEffect, useState} from 'react';
import styled from 'styled-components';
import Button from '~/components/Button';
import {rem} from '~/utils/style'; import {rem} from '~/utils/style';
import styled from 'styled-components';
import {useTranslation} from '~/utils/i18n'; import {useTranslation} from '~/utils/i18n';
import Button from '~/components/Button';
const StyledButton = styled(Button)` const StyledButton = styled(Button)`
margin-top: ${rem(40)}; margin-top: ${rem(40)};
......
import React, {FunctionComponent, useState, useMemo, useRef, useEffect, useCallback} from 'react'; import React, {FunctionComponent, useCallback, useEffect, useMemo, useRef, useState} from 'react';
import styled from 'styled-components'; import {ellipsis, em, primaryColor, size, textLightColor} from '~/utils/style';
import queryString from 'query-string';
import isEmpty from 'lodash/isEmpty';
import GridLoader from 'react-spinners/GridLoader'; import GridLoader from 'react-spinners/GridLoader';
import {em, size, ellipsis, primaryColor, textLightColor} from '~/utils/style';
import {useTranslation} from '~/utils/i18n';
import {useRunningRequest} from '~/hooks/useRequest';
import Image from '~/components/Image'; import Image from '~/components/Image';
import StepSlider from '~/components/SamplesPage/StepSlider'; import StepSlider from '~/components/SamplesPage/StepSlider';
import isEmpty from 'lodash/isEmpty';
import queryString from 'query-string';
import styled from 'styled-components';
import {useRunningRequest} from '~/hooks/useRequest';
import {useTranslation} from '~/utils/i18n';
const width = em(430); const width = em(430);
const height = em(384); const height = em(384);
...@@ -60,8 +61,7 @@ const Container = styled.div<{fit?: boolean}>` ...@@ -60,8 +61,7 @@ const Container = styled.div<{fit?: boolean}>`
overflow: hidden; overflow: hidden;
> img { > img {
width: 100%; ${size('100%')}
height: 100%;
object-fit: ${props => (props.fit ? 'contain' : 'scale-down')}; object-fit: ${props => (props.fit ? 'contain' : 'scale-down')};
flex-shrink: 1; flex-shrink: 1;
} }
......
import React, {FunctionComponent, useState, useEffect, useCallback} from 'react'; import React, {FunctionComponent, useCallback, useEffect, useState} from 'react';
import styled from 'styled-components';
import {em, textLightColor} from '~/utils/style'; import {em, textLightColor} from '~/utils/style';
import {useTranslation} from '~/utils/i18n';
import RangeSlider from '~/components/RangeSlider'; import RangeSlider from '~/components/RangeSlider';
import styled from 'styled-components';
import {useTranslation} from '~/utils/i18n';
const Label = styled.div` const Label = styled.div`
color: ${textLightColor}; color: ${textLightColor};
......
import React, {FunctionComponent, useCallback, useMemo} from 'react';
import styled from 'styled-components';
import queryString from 'query-string';
import {EChartOption} from 'echarts';
import {em, size} from '~/utils/style';
import {useTranslation} from '~/utils/i18n';
import {useRunningRequest} from '~/hooks/useRequest';
import useHeavyWork from '~/hooks/useHeavyWork';
import {cycleFetcher} from '~/utils/fetch';
import { import {
transform,
chartData,
range,
tooltip,
sortingMethodMap,
xAxisMap,
Dataset, Dataset,
Range, Range,
RangeParams,
TransformParams, TransformParams,
RangeParams chartData,
range,
sortingMethodMap,
tooltip,
transform,
xAxisMap
} from '~/resource/scalars'; } from '~/resource/scalars';
import React, {FunctionComponent, useCallback, useMemo} from 'react';
import {em, size} from '~/utils/style';
import {EChartOption} from 'echarts';
import LineChart from '~/components/LineChart'; import LineChart from '~/components/LineChart';
import {cycleFetcher} from '~/utils/fetch';
import queryString from 'query-string';
import styled from 'styled-components';
import useHeavyWork from '~/hooks/useHeavyWork';
import {useRunningRequest} from '~/hooks/useRequest';
import {useTranslation} from '~/utils/i18n';
const width = em(430); const width = em(430);
const height = em(320); const height = em(320);
......
import React, {FunctionComponent, useState} from 'react'; import React, {FunctionComponent, useState} from 'react';
import styled from 'styled-components';
import {useTranslation} from '~/utils/i18n';
import Field from '~/components/Field'; import Field from '~/components/Field';
import RangeSlider from '~/components/RangeSlider'; import RangeSlider from '~/components/RangeSlider';
import styled from 'styled-components';
import {useTranslation} from '~/utils/i18n';
const FullWidthRangeSlider = styled(RangeSlider)` const FullWidthRangeSlider = styled(RangeSlider)`
width: 100%; width: 100%;
......
import React, {FunctionComponent, useEffect, useMemo} from 'react'; import React, {FunctionComponent, useEffect, useMemo} from 'react';
import styled from 'styled-components'; import {WithStyled, position, primaryColor, size} from '~/utils/style';
import GridLoader from 'react-spinners/GridLoader'; import GridLoader from 'react-spinners/GridLoader';
import {WithStyled, primaryColor} from '~/utils/style'; import styled from 'styled-components';
import useECharts from '~/hooks/useECharts'; import useECharts from '~/hooks/useECharts';
const Wrapper = styled.div` const Wrapper = styled.div`
...@@ -12,11 +13,8 @@ const Wrapper = styled.div` ...@@ -12,11 +13,8 @@ const Wrapper = styled.div`
} }
> .loading { > .loading {
position: absolute; ${position('absolute', 0, null, null, 0)}
top: 0; ${size('100%')}
left: 0;
height: 100%;
width: 100%;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
......
import Input, {InputProps, padding} from '~/components/Input';
import React, {FunctionComponent} from 'react'; import React, {FunctionComponent} from 'react';
import styled from 'styled-components'; import {WithStyled, backgroundColor, em, math, position, textLighterColor} from '~/utils/style';
import {WithStyled, em, math, textLighterColor} from '~/utils/style';
import Input, {padding, InputProps} from '~/components/Input';
import Icon from '~/components/Icon'; import Icon from '~/components/Icon';
import styled from 'styled-components';
const iconSize = em(16); const iconSize = em(16);
...@@ -12,16 +13,14 @@ const StyledInput = styled(Input)` ...@@ -12,16 +13,14 @@ const StyledInput = styled(Input)`
`; `;
const Control = styled.div` const Control = styled.div`
background-color: #fff; background-color: ${backgroundColor};
position: relative; position: relative;
`; `;
const SearchIcon = styled(Icon)` const SearchIcon = styled(Icon)`
font-size: ${iconSize}; font-size: ${iconSize};
display: block; display: block;
position: absolute; ${position('absolute', padding, padding, null, null)}
top: ${padding};
right: ${padding};
pointer-events: none; pointer-events: none;
color: ${textLighterColor}; color: ${textLighterColor};
`; `;
......
import React, {FunctionComponent, useState, useCallback, useEffect, useMemo} from 'react'; import React, {FunctionComponent, useCallback, useEffect, useMemo, useState} from 'react';
import styled from 'styled-components';
import without from 'lodash/without';
import {useTranslation} from '~/utils/i18n';
import useClickOutside from '~/hooks/useClickOutside';
import { import {
WithStyled, WithStyled,
em,
backgroundColor, backgroundColor,
backgroundFocusedColor, backgroundFocusedColor,
textLighterColor,
selectedColor,
borderColor, borderColor,
borderFocusedColor, borderFocusedColor,
borderRadius, borderRadius,
duration, borderRadiusShortHand,
easing, css,
ellipsis, ellipsis,
transitions, em,
math, math,
css sameBorder,
selectedColor,
size,
textLighterColor,
transitionProps
} from '~/utils/style'; } from '~/utils/style';
import Checkbox from '~/components/Checkbox'; import Checkbox from '~/components/Checkbox';
import Icon from '~/components/Icon'; import Icon from '~/components/Icon';
import styled from 'styled-components';
import useClickOutside from '~/hooks/useClickOutside';
import {useTranslation} from '~/utils/i18n';
import without from 'lodash/without';
export const padding = em(10); export const padding = em(10);
export const height = em(36); export const height = em(36);
const minWidth = em(160); const minWidth = em(160);
// prettier-ignore
const Wrapper = styled.div<{opened?: boolean}>` const Wrapper = styled.div<{opened?: boolean}>`
height: ${height}; height: ${height};
line-height: calc(${height} - 2px); line-height: calc(${height} - 2px);
...@@ -35,11 +36,10 @@ const Wrapper = styled.div<{opened?: boolean}>` ...@@ -35,11 +36,10 @@ const Wrapper = styled.div<{opened?: boolean}>`
max-width: 100%; max-width: 100%;
display: inline-block; display: inline-block;
position: relative; position: relative;
border: 1px solid ${borderColor};
/* eslint-disable-next-line */
border-radius: ${borderRadius} ${borderRadius} ${props => (props.opened ? '0 0' : `${borderRadius} ${borderRadius}`)};
transition: border-color ${duration} ${easing};
background-color: ${backgroundColor}; background-color: ${backgroundColor};
${sameBorder({radius: true})}
${props => (props.opened ? borderRadiusShortHand('bottom', '0') : '')}
${transitionProps('border-color')}
&:hover { &:hover {
border-color: ${borderFocusedColor}; border-color: ${borderFocusedColor};
...@@ -49,8 +49,7 @@ const Wrapper = styled.div<{opened?: boolean}>` ...@@ -49,8 +49,7 @@ const Wrapper = styled.div<{opened?: boolean}>`
const Trigger = styled.div<{selected?: boolean}>` const Trigger = styled.div<{selected?: boolean}>`
padding: ${padding}; padding: ${padding};
display: inline-flex; display: inline-flex;
width: 100%; ${size('100%')}
height: 100%;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
cursor: pointer; cursor: pointer;
...@@ -58,13 +57,12 @@ const Trigger = styled.div<{selected?: boolean}>` ...@@ -58,13 +57,12 @@ const Trigger = styled.div<{selected?: boolean}>`
`; `;
const TriggerIcon = styled(Icon)<{opened?: boolean}>` const TriggerIcon = styled(Icon)<{opened?: boolean}>`
width: ${em(14)}; ${size(em(14))}
height: ${em(14)};
text-align: center; text-align: center;
display: block; display: block;
flex-shrink: 0; flex-shrink: 0;
transform: rotate(${props => (props.opened ? '180' : '0')}deg) scale(${10 / 14}); transform: rotate(${props => (props.opened ? '180' : '0')}deg) scale(${10 / 14});
transition: transform ${duration} ${easing}; ${transitionProps('transform')}
`; `;
const Label = styled.span` const Label = styled.span`
...@@ -84,7 +82,7 @@ const List = styled.div<{opened?: boolean; empty?: boolean}>` ...@@ -84,7 +82,7 @@ const List = styled.div<{opened?: boolean; empty?: boolean}>`
padding: ${padding} 0; padding: ${padding} 0;
border: inherit; border: inherit;
border-top-color: ${borderColor}; border-top-color: ${borderColor};
border-radius: 0 0 ${borderRadius} ${borderRadius}; ${borderRadiusShortHand('bottom', borderRadius)}
display: ${props => (props.opened ? 'block' : 'none')}; display: ${props => (props.opened ? 'block' : 'none')};
z-index: 9999; z-index: 9999;
line-height: 1; line-height: 1;
...@@ -92,10 +90,10 @@ const List = styled.div<{opened?: boolean; empty?: boolean}>` ...@@ -92,10 +90,10 @@ const List = styled.div<{opened?: boolean; empty?: boolean}>`
box-shadow: 0 5px 6px 0 rgba(0, 0, 0, 0.05); box-shadow: 0 5px 6px 0 rgba(0, 0, 0, 0.05);
${props => ${props =>
props.empty props.empty
? ` ? {
color: ${textLighterColor}; color: textLighterColor,
text-align: center; textAlign: 'center'
` }
: ''} : ''}
`; `;
...@@ -103,10 +101,10 @@ const listItem = css` ...@@ -103,10 +101,10 @@ const listItem = css`
display: block; display: block;
cursor: pointer; cursor: pointer;
padding: 0 ${padding}; padding: 0 ${padding};
height: ${height}; ${size(height, '100%')}
line-height: ${height}; line-height: ${height};
width: 100%; ${transitionProps(['color', 'background-color'])}
${transitions(['color', 'background-color'], `${duration} ${easing}`)}
&:hover { &:hover {
background-color: ${backgroundFocusedColor}; background-color: ${backgroundFocusedColor};
} }
......
import React, {FunctionComponent} from 'react'; import React, {FunctionComponent} from 'react';
import styled from 'styled-components';
import { import {
WithStyled, WithStyled,
backgroundColor,
em, em,
primaryColor, half,
lightActiveColor,
lightColor, lightColor,
lightFocusedColor, lightFocusedColor,
lightActiveColor, primaryColor,
duration, transitionProps
easing,
math,
transitions
} from '~/utils/style'; } from '~/utils/style';
import styled from 'styled-components';
const height = em(36); const height = em(36);
const Span = styled.span<{active?: boolean}>` const Span = styled.span<{active?: boolean}>`
...@@ -20,11 +20,11 @@ const Span = styled.span<{active?: boolean}>` ...@@ -20,11 +20,11 @@ const Span = styled.span<{active?: boolean}>`
height: ${height}; height: ${height};
line-height: ${height}; line-height: ${height};
display: inline-block; display: inline-block;
border-radius: ${math(`${height} / 2`)}; border-radius: ${half(height)};
${transitions(['color', 'background-color'], `${duration} ${easing}`)} color: ${prop => (prop.active ? backgroundColor : primaryColor)};
color: ${prop => (prop.active ? '#FFF' : primaryColor)};
background-color: ${prop => (prop.active ? primaryColor : lightColor)}; background-color: ${prop => (prop.active ? primaryColor : lightColor)};
cursor: pointer; cursor: pointer;
${transitionProps(['color', 'background-color'])}
&:hover { &:hover {
background-color: ${prop => (prop.active ? primaryColor : lightFocusedColor)}; background-color: ${prop => (prop.active ? primaryColor : lightFocusedColor)};
......
import React, {FunctionComponent, useState, useCallback, useEffect, useMemo} from 'react'; import React, {FunctionComponent, useCallback, useEffect, useMemo, useState} from 'react';
import styled from 'styled-components'; import {ellipsis, math, rem} from '~/utils/style';
import groupBy from 'lodash/groupBy';
import sortBy from 'lodash/sortBy';
import {useTranslation} from '~/utils/i18n';
import {rem, math, ellipsis} from '~/utils/style';
import SearchInput from '~/components/SearchInput'; import SearchInput from '~/components/SearchInput';
import Tag from '~/components/Tag'; import Tag from '~/components/Tag';
import {Tag as TagType} from '~/types'; import {Tag as TagType} from '~/types';
import groupBy from 'lodash/groupBy';
import sortBy from 'lodash/sortBy';
import styled from 'styled-components';
import {useTranslation} from '~/utils/i18n';
const margin = rem(16); const margin = rem(16);
......
import React, {FunctionComponent} from 'react'; import React, {FunctionComponent} from 'react';
import Head from 'next/head'; import Head from 'next/head';
const Title: FunctionComponent = ({children: title}) => ( const Title: FunctionComponent = ({children: title}) => (
......
// cSpell:words autorestart
/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-var-requires */
module.exports = { module.exports = {
......
import {useRef, useEffect, useCallback} from 'react'; import {useCallback, useEffect, useRef} from 'react';
const useClickOutside = (callback: () => void) => { const useClickOutside = (callback: () => void) => {
const ref = useRef(null); const ref = useRef(null);
......
import {useState, useEffect} from 'react'; import {useEffect, useState} from 'react';
const useDebounce = <T>(value: T, delay: number): T => { const useDebounce = <T>(value: T, delay: number): T => {
const [debouncedValue, setDebouncedValue] = useState(value); const [debouncedValue, setDebouncedValue] = useState(value);
......
import {useRef, useEffect, useCallback, useState, MutableRefObject} from 'react'; import {MutableRefObject, useCallback, useEffect, useRef, useState} from 'react';
import {maskColor, primaryColor, textColor} from '~/utils/style';
import {ECharts} from 'echarts'; import {ECharts} from 'echarts';
import {primaryColor, textColor, maskColor} from '~/utils/style';
const useECharts = <T extends HTMLElement>(options: { const useECharts = <T extends HTMLElement>(options: {
loading?: boolean; loading?: boolean;
......
import {useEffect, useRef, useState, useCallback} from 'react'; import {useCallback, useEffect, useRef, useState} from 'react';
const useHeavyWork = <T = unknown, P = unknown>( const useHeavyWork = <T = unknown, P = unknown>(
createWasm: (() => Promise<(arg: P) => T> | null) | null, createWasm: (() => Promise<(arg: P) => T> | null) | null,
......
import {useMemo, useEffect} from 'react'; import {useEffect, useMemo} from 'react';
import useSWR, {responseInterface, keyInterface, ConfigInterface} from 'swr'; import useSWR, {ConfigInterface, keyInterface, responseInterface} from 'swr';
import {fetcherFn} from 'swr/dist/types'; import {fetcherFn} from 'swr/dist/types';
type Response<D, E> = responseInterface<D, E> & { type Response<D, E> = responseInterface<D, E> & {
......
import {useReducer, useEffect, useCallback, useMemo} from 'react'; import {useCallback, useEffect, useMemo, useReducer} from 'react';
import {useRouter} from 'next/router';
import {Tag} from '~/types';
import groupBy from 'lodash/groupBy'; import groupBy from 'lodash/groupBy';
import uniq from 'lodash/uniq';
import intersection from 'lodash/intersection'; import intersection from 'lodash/intersection';
import uniq from 'lodash/uniq';
import useRequest from '~/hooks/useRequest'; import useRequest from '~/hooks/useRequest';
import {Tag} from '~/types'; import {useRouter} from 'next/router';
type Runs = string[]; type Runs = string[];
type Tags = Record<string, string[]>; type Tags = Record<string, string[]>;
...@@ -45,14 +46,16 @@ type ActionSetFilteredTags = { ...@@ -45,14 +46,16 @@ type ActionSetFilteredTags = {
type Action = ActionSetRuns | ActionInitTags | ActionSetTags | ActionSetFilteredTags; type Action = ActionSetRuns | ActionInitTags | ActionSetTags | ActionSetFilteredTags;
type SingleTag = {label: Tag['label']; run: Tag['runs'][number]};
const groupTags = (runs: Runs, tags?: Tags): Tag[] => const groupTags = (runs: Runs, tags?: Tags): Tag[] =>
Object.entries( Object.entries(
groupBy<{label: Tag['label']; run: Tag['runs'][number]}>( groupBy<SingleTag>(
runs runs
// get tags of selected runs // get tags of selected runs
.filter(run => runs.includes(run)) .filter(run => runs.includes(run))
// group by runs // group by runs
.reduce((prev, run) => { .reduce<SingleTag[]>((prev, run) => {
if (tags && tags[run]) { if (tags && tags[run]) {
Array.prototype.push.apply( Array.prototype.push.apply(
prev, prev,
......
import fetch from 'isomorphic-unfetch';
import {Request, Response} from 'express'; import {Request, Response} from 'express';
import fetch from 'isomorphic-unfetch';
const images = [ const images = [
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1583866603102&di=13e63561829699f6eda8405ba5a84cad&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201704%2F30%2F20170430172141_YSjU4.jpeg', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1583866603102&di=13e63561829699f6eda8405ba5a84cad&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201704%2F30%2F20170430172141_YSjU4.jpeg',
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1582889403799&di=bb4db115c1227e081852bbb95336150b&imgtype=0&src=http%3A%2F%2Fres.hpoi.net.cn%2Fgk%2Fcover%2Fn%2F2015%2F02%2Fff897b88ccd5417f91d4159a8ea343a6.jpg%3Fdate%3D1464606291000', 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1582889403799&di=bb4db115c1227e081852bbb95336150b&imgtype=0&src=http%3A%2F%2Fres.hpoi.net.cn%2Fgk%2Fcover%2Fn%2F2015%2F02%2Fff897b88ccd5417f91d4159a8ea343a6.jpg%3Fdate%3D1464606291000',
......
/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-var-requires */
const path = require('path'); const path = require('path');
const pkg = require('./package.json'); const pkg = require('./package.json');
......
{ {
"name": "visualdl", "name": "visualdl",
"version": "2.0.0-beta.23", "version": "2.0.0-beta.24",
"title": "VisualDL", "title": "VisualDL",
"description": "A platform to visualize the deep learning process and result.", "description": "A platform to visualize the deep learning process and result.",
"keywords": [ "keywords": [
......
import {NextI18NextPage, useTranslation} from '~/utils/i18n';
import {headerHeight, rem} from '~/utils/style';
import styled from 'styled-components'; import styled from 'styled-components';
import {rem, headerHeight} from '~/utils/style';
import {useTranslation, NextI18NextPage} from '~/utils/i18n';
const Error = styled.div` const Error = styled.div`
height: calc(100vh - ${headerHeight}); height: calc(100vh - ${headerHeight});
......
import React from 'react'; import {Router, appWithTranslation} from '~/utils/i18n';
import App from 'next/app'; import App from 'next/app';
import {GlobalStyle} from '~/utils/style';
import Head from 'next/head'; import Head from 'next/head';
import Layout from '~/components/Layout';
import NProgress from 'nprogress'; import NProgress from 'nprogress';
import React from 'react';
import {SWRConfig} from 'swr'; import {SWRConfig} from 'swr';
import {Router, appWithTranslation} from '~/utils/i18n';
import {fetcher} from '~/utils/fetch'; import {fetcher} from '~/utils/fetch';
import {GlobalStyle} from '~/utils/style';
import Layout from '~/components/Layout';
Router.events.on('routeChangeStart', () => NProgress.start()); Router.events.on('routeChangeStart', () => NProgress.start());
Router.events.on('routeChangeComplete', () => NProgress.done()); Router.events.on('routeChangeComplete', () => NProgress.done());
......
import Document, {Html, Head, Main, NextScript, DocumentContext, DocumentProps} from 'next/document'; import Document, {DocumentContext, DocumentProps, Head, Html, Main, NextScript} from 'next/document';
import {ServerStyleSheet} from '~/utils/style'; import {ServerStyleSheet} from '~/utils/style';
interface VDLDocumentProps extends DocumentProps { interface VDLDocumentProps extends DocumentProps {
...@@ -19,7 +20,7 @@ export default class VDLDocument extends Document<VDLDocumentProps> { ...@@ -19,7 +20,7 @@ export default class VDLDocument extends Document<VDLDocumentProps> {
}); });
const initialProps = await Document.getInitialProps(ctx); const initialProps = await Document.getInitialProps(ctx);
// stealed from https://github.com/isaachinman/next-i18next/issues/20#issuecomment-558799264 // steal from https://github.com/isaachinman/next-i18next/issues/20#issuecomment-558799264
// FIXME: https://github.com/i18next/i18next-express-middleware/blob/master/src/index.js#L23-L26 // FIXME: https://github.com/i18next/i18next-express-middleware/blob/master/src/index.js#L23-L26
const additionalProps = { const additionalProps = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
......
import {NextI18NextPage, useTranslation} from '~/utils/i18n';
import {headerHeight, rem} from '~/utils/style';
import styled from 'styled-components'; import styled from 'styled-components';
import {rem, headerHeight} from '~/utils/style';
import {useTranslation, NextI18NextPage} from '~/utils/i18n';
const ErrorDiv = styled.div` const ErrorDiv = styled.div`
height: calc(100vh - ${headerHeight}); height: calc(100vh - ${headerHeight});
......
import React, {useState, useEffect, useMemo} from 'react'; import {Graph, collectDagFacts} from '~/resource/graphs';
import styled from 'styled-components'; import {NextI18NextPage, useTranslation} from '~/utils/i18n';
import {saveSvgAsPng} from 'save-svg-as-png'; import NodeInfo, {NodeInfoProps} from '~/components/GraphsPage/NodeInfo';
import isEmpty from 'lodash/isEmpty'; import React, {useEffect, useMemo, useState} from 'react';
import useRequest from '~/hooks/useRequest';
import {rem} from '~/utils/style';
import {useTranslation, NextI18NextPage} from '~/utils/i18n';
import RawButton from '~/components/Button';
import RawRangeSlider from '~/components/RangeSlider';
import Content from '~/components/Content'; import Content from '~/components/Content';
import Title from '~/components/Title';
import Field from '~/components/Field'; import Field from '~/components/Field';
import NodeInfo, {NodeInfoProps} from '~/components/GraphsPage/NodeInfo';
import Preloader from '~/components/Preloader'; import Preloader from '~/components/Preloader';
import {Graph, collectDagFacts} from '~/resource/graphs'; import RawButton from '~/components/Button';
import RawRangeSlider from '~/components/RangeSlider';
import Title from '~/components/Title';
import isEmpty from 'lodash/isEmpty';
import {rem} from '~/utils/style';
import {saveSvgAsPng} from 'save-svg-as-png';
import styled from 'styled-components';
import useRequest from '~/hooks/useRequest';
// eslint-disable-next-line @typescript-eslint/no-empty-function // eslint-disable-next-line @typescript-eslint/no-empty-function
const dumbFn = () => {}; const dumbFn = () => {};
...@@ -40,6 +41,7 @@ const Empty = styled.div` ...@@ -40,6 +41,7 @@ const Empty = styled.div`
const RangeSlider = styled(RawRangeSlider)` const RangeSlider = styled(RawRangeSlider)`
width: 100%; width: 100%;
`; `;
const GraphSvg = styled('svg')` const GraphSvg = styled('svg')`
width: 100%; width: 100%;
...@@ -272,8 +274,8 @@ const Graphs: NextI18NextPage = () => { ...@@ -272,8 +274,8 @@ const Graphs: NextI18NextPage = () => {
</SubSection> </SubSection>
<SubSection> <SubSection>
<Field label={`${t('node-info')}:`}></Field> <Field label={`${t('node-info')}:`} />
<NodeInfo node={currentNode}></NodeInfo> <NodeInfo node={currentNode} />
</SubSection> </SubSection>
</section> </section>
); );
......
import React, {useState, useEffect} from 'react'; import {Dimension, Reduction} from '~/resource/high-dimensional';
import styled from 'styled-components'; import {NextI18NextPage, useTranslation} from '~/utils/i18n';
import {useRouter} from 'next/router'; import React, {useEffect, useState} from 'react';
import useRequest from '~/hooks/useRequest'; import Select, {SelectValueType} from '~/components/Select';
import useSearchValue from '~/hooks/useSearchValue'; import {em, rem} from '~/utils/style';
import {rem, em} from '~/utils/style';
import {useTranslation, NextI18NextPage} from '~/utils/i18n'; import AsideDivider from '~/components/AsideDivider';
import Title from '~/components/Title'; import Checkbox from '~/components/Checkbox';
import Content from '~/components/Content'; import Content from '~/components/Content';
import SearchInput from '~/components/SearchInput';
import Icon from '~/components/Icon';
import Field from '~/components/Field'; import Field from '~/components/Field';
import Checkbox from '~/components/Checkbox'; import HighDimensionalChart from '~/components/HighDimensionalPage/HighDimensionalChart';
import RadioGroup from '~/components/RadioGroup'; import Icon from '~/components/Icon';
import Preloader from '~/components/Preloader';
import RadioButton from '~/components/RadioButton'; import RadioButton from '~/components/RadioButton';
import RadioGroup from '~/components/RadioGroup';
import RunningToggle from '~/components/RunningToggle'; import RunningToggle from '~/components/RunningToggle';
import Select, {SelectValueType} from '~/components/Select'; import SearchInput from '~/components/SearchInput';
import AsideDivider from '~/components/AsideDivider'; import Title from '~/components/Title';
import Preloader from '~/components/Preloader'; import styled from 'styled-components';
import HighDimensionalChart from '~/components/HighDimensionalPage/HighDimensionalChart'; import useRequest from '~/hooks/useRequest';
import {Dimension, Reduction} from '~/resource/high-dimensional'; import {useRouter} from 'next/router';
import useSearchValue from '~/hooks/useSearchValue';
const dimensions = ['2d', '3d']; const dimensions = ['2d', '3d'];
const reductions = ['pca', 'tsne']; const reductions = ['pca', 'tsne'];
...@@ -47,7 +48,7 @@ const HighDimensional: NextI18NextPage = () => { ...@@ -47,7 +48,7 @@ const HighDimensional: NextI18NextPage = () => {
useEffect(() => setRun(selectedRun), [setRun, selectedRun]); useEffect(() => setRun(selectedRun), [setRun, selectedRun]);
const [search, setSearch] = useState(''); const [search, setSearch] = useState('');
const debouncedSearch = useSearchValue(search); const debounceSearch = useSearchValue(search);
const [dimension, setDimension] = useState(dimensions[0] as Dimension); const [dimension, setDimension] = useState(dimensions[0] as Dimension);
const [reduction, setReduction] = useState(reductions[0] as Reduction); const [reduction, setReduction] = useState(reductions[0] as Reduction);
const [running, setRunning] = useState(true); const [running, setRunning] = useState(true);
...@@ -112,7 +113,7 @@ const HighDimensional: NextI18NextPage = () => { ...@@ -112,7 +113,7 @@ const HighDimensional: NextI18NextPage = () => {
) : loading ? null : ( ) : loading ? null : (
<HighDimensionalChart <HighDimensionalChart
dimension={dimension} dimension={dimension}
keyword={debouncedSearch} keyword={debounceSearch}
run={run ?? ''} run={run ?? ''}
running={running} running={running}
labelVisibility={labelVisibility} labelVisibility={labelVisibility}
......
import {useEffect} from 'react';
import {NextI18NextPage, Router} from '~/utils/i18n'; import {NextI18NextPage, Router} from '~/utils/i18n';
import {useEffect} from 'react';
const Index: NextI18NextPage = () => { const Index: NextI18NextPage = () => {
useEffect(() => { useEffect(() => {
Router.replace('/scalars'); Router.replace('/scalars');
......
import React, {useState, useCallback, useMemo} from 'react'; // cSpell:words ungrouped
import styled from 'styled-components';
import {useTranslation, NextI18NextPage} from '~/utils/i18n'; import {NextI18NextPage, useTranslation} from '~/utils/i18n';
import {rem, em} from '~/utils/style'; import React, {useCallback, useMemo, useState} from 'react';
import useTagFilter from '~/hooks/useTagFilter'; import {em, rem} from '~/utils/style';
import Title from '~/components/Title';
import AsideDivider from '~/components/AsideDivider';
import ChartPage from '~/components/ChartPage';
import Checkbox from '~/components/Checkbox';
import Content from '~/components/Content'; import Content from '~/components/Content';
import RunSelect from '~/components/RunSelect';
import TagFilter from '~/components/TagFilter';
import Icon from '~/components/Icon';
import Field from '~/components/Field'; import Field from '~/components/Field';
import Checkbox from '~/components/Checkbox'; import Icon from '~/components/Icon';
import Preloader from '~/components/Preloader';
import RunSelect from '~/components/RunSelect';
import RunningToggle from '~/components/RunningToggle'; import RunningToggle from '~/components/RunningToggle';
import AsideDivider from '~/components/AsideDivider';
import ChartPage from '~/components/ChartPage';
import SampleChart from '~/components/SamplesPage/SampleChart'; import SampleChart from '~/components/SamplesPage/SampleChart';
import Preloader from '~/components/Preloader'; import TagFilter from '~/components/TagFilter';
import Title from '~/components/Title';
import styled from 'styled-components';
import useTagFilter from '~/hooks/useTagFilter';
const StyledIcon = styled(Icon)` const StyledIcon = styled(Icon)`
font-size: ${rem(16)}; font-size: ${rem(16)};
......
import React, {useState, useCallback} from 'react'; import {NextI18NextPage, useTranslation} from '~/utils/i18n';
import {useTranslation, NextI18NextPage} from '~/utils/i18n'; import React, {useCallback, useState} from 'react';
import useTagFilter from '~/hooks/useTagFilter';
import useSearchValue from '~/hooks/useSearchValue';
import Title from '~/components/Title';
import Content from '~/components/Content';
import RunSelect from '~/components/RunSelect';
import TagFilter from '~/components/TagFilter';
import Select, {SelectValueType} from '~/components/Select'; import Select, {SelectValueType} from '~/components/Select';
import Field from '~/components/Field'; import {sortingMethodMap, xAxisMap} from '~/resource/scalars';
import Checkbox from '~/components/Checkbox';
import RunningToggle from '~/components/RunningToggle';
import AsideDivider from '~/components/AsideDivider'; import AsideDivider from '~/components/AsideDivider';
import ChartPage from '~/components/ChartPage'; import ChartPage from '~/components/ChartPage';
import SmoothingSlider from '~/components/ScalarsPage/SmoothingSlider'; import Checkbox from '~/components/Checkbox';
import ScalarChart from '~/components/ScalarsPage/ScalarChart'; import Content from '~/components/Content';
import Field from '~/components/Field';
import Preloader from '~/components/Preloader'; import Preloader from '~/components/Preloader';
import {xAxisMap, sortingMethodMap} from '~/resource/scalars'; import RunSelect from '~/components/RunSelect';
import RunningToggle from '~/components/RunningToggle';
import ScalarChart from '~/components/ScalarsPage/ScalarChart';
import SmoothingSlider from '~/components/ScalarsPage/SmoothingSlider';
import {Tag} from '~/types'; import {Tag} from '~/types';
import TagFilter from '~/components/TagFilter';
import Title from '~/components/Title';
import useSearchValue from '~/hooks/useSearchValue';
import useTagFilter from '~/hooks/useTagFilter';
type XAxis = keyof typeof xAxisMap; type XAxis = keyof typeof xAxisMap;
const xAxisValues = ['step', 'relative', 'wall']; const xAxisValues = ['step', 'relative', 'wall'];
type TooltiopSorting = keyof typeof sortingMethodMap; type TooltipSorting = keyof typeof sortingMethodMap;
const toolTipSortingValues = ['default', 'descending', 'ascending', 'nearest']; const toolTipSortingValues = ['default', 'descending', 'ascending', 'nearest'];
const Scalars: NextI18NextPage = () => { const Scalars: NextI18NextPage = () => {
...@@ -30,16 +31,16 @@ const Scalars: NextI18NextPage = () => { ...@@ -30,16 +31,16 @@ const Scalars: NextI18NextPage = () => {
'scalars' 'scalars'
); );
const debouncedTags = useSearchValue(selectedTags); const debounceTags = useSearchValue(selectedTags);
const [smoothing, setSmoothing] = useState(0.6); const [smoothing, setSmoothing] = useState(0.6);
const [xAxis, setXAxis] = useState(xAxisValues[0] as XAxis); const [xAxis, setXAxis] = useState(xAxisValues[0] as XAxis);
const onChangeXAxis = (value: SelectValueType | SelectValueType[]) => setXAxis(value as XAxis); const onChangeXAxis = (value: SelectValueType | SelectValueType[]) => setXAxis(value as XAxis);
const [tooltipSorting, setTooltipSorting] = useState(toolTipSortingValues[0] as TooltiopSorting); const [tooltipSorting, setTooltipSorting] = useState(toolTipSortingValues[0] as TooltipSorting);
const onChangeTooltipSorting = (value: SelectValueType | SelectValueType[]) => const onChangeTooltipSorting = (value: SelectValueType | SelectValueType[]) =>
setTooltipSorting(value as TooltiopSorting); setTooltipSorting(value as TooltipSorting);
const [ignoreOutliers, setIgnoreOutliers] = useState(false); const [ignoreOutliers, setIgnoreOutliers] = useState(false);
...@@ -55,7 +56,7 @@ const Scalars: NextI18NextPage = () => { ...@@ -55,7 +56,7 @@ const Scalars: NextI18NextPage = () => {
list={xAxisValues.map(value => ({label: t(`x-axis-value.${value}`), value}))} list={xAxisValues.map(value => ({label: t(`x-axis-value.${value}`), value}))}
value={xAxis} value={xAxis}
onChange={onChangeXAxis} onChange={onChangeXAxis}
></Select> />
</Field> </Field>
<Field label={t('tooltip-sorting')}> <Field label={t('tooltip-sorting')}>
<Select <Select
...@@ -95,7 +96,7 @@ const Scalars: NextI18NextPage = () => { ...@@ -95,7 +96,7 @@ const Scalars: NextI18NextPage = () => {
<Title>{t('common:scalars')}</Title> <Title>{t('common:scalars')}</Title>
<Content aside={aside} loading={loadingRuns}> <Content aside={aside} loading={loadingRuns}>
<TagFilter tags={tags} onChange={onFilterTags} /> <TagFilter tags={tags} onChange={onFilterTags} />
<ChartPage items={debouncedTags} withChart={withChart} loading={loadingRuns || loadingTags} /> <ChartPage items={debounceTags} withChart={withChart} loading={loadingRuns || loadingTags} />
</Content> </Content>
</> </>
); );
......
import {Graph, Node, NodeUID, InputNode, NodeType} from './types'; import {Graph, InputNode, Node, NodeType, NodeUID} from './types';
interface DagNode { interface DagNode {
key: string; key: string;
......
import {Point, DivideParams} from './types'; import {DivideParams, Point} from './types';
export * from './types'; export * from './types';
......
import * as chart from '~/utils/chart';
import {ChartDataParams, RangeParams, TooltipData, TransformParams, xAxisMap} from './types';
import {formatTime, quantile} from '~/utils';
import {I18n} from '~/utils/i18next/types';
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';
import minBy from 'lodash/minBy'; import compact from 'lodash/compact';
import maxBy from 'lodash/maxBy'; import maxBy from 'lodash/maxBy';
import minBy from 'lodash/minBy';
import sortBy from 'lodash/sortBy'; import sortBy from 'lodash/sortBy';
import compact from 'lodash/compact';
import {formatTime, quantile} from '~/utils';
import * as chart from '~/utils/chart';
import {I18n} from '~/utils/i18next/types';
import {xAxisMap, TooltipData, TransformParams, ChartDataParams, RangeParams} from './types';
export * from './types'; export * from './types';
......
...@@ -2,13 +2,13 @@ ...@@ -2,13 +2,13 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
import path from 'path'; import config from '../next.config';
import express from 'express'; import express from 'express';
import next from 'next'; import next from 'next';
import {setConfig} from 'next/config';
import {nextI18NextMiddleware} from '../utils/i18next/middlewares'; import {nextI18NextMiddleware} from '../utils/i18next/middlewares';
import nextI18next from '../utils/i18n'; import nextI18next from '../utils/i18n';
import config from '../next.config'; import path from 'path';
import {setConfig} from 'next/config';
const isDev = process.env.NODE_ENV !== 'production'; const isDev = process.env.NODE_ENV !== 'production';
......
// dagre-d.ts // dagre-d.ts
// Copied from existing type definition @types/dagre-d3, with some modification // Copied from existing type definition @types/dagre-d3, with some modification
/* eslint-disable @typescript-eslint/no-explicit-any */
declare module 'dagre-d3' { declare module 'dagre-d3' {
import {Selection, BaseType} from 'd3';
import * as dagre from 'dagre'; import * as dagre from 'dagre';
import {BaseType, Selection} from 'd3';
export const graphlib = dagre.graphlib; export const graphlib = dagre.graphlib;
export const render: {new (): Render}; export const render: {new (): Render};
......
...@@ -16,9 +16,8 @@ export const color = [ ...@@ -16,9 +16,8 @@ export const color = [
'#FF0900', '#FF0900',
'#FF6600', '#FF6600',
'#FFEA00', '#FFEA00',
'FE4A3B' '#FE4A3B'
]; ];
export const colorAlt = [ export const colorAlt = [
'#9498F0', '#9498F0',
'#66E0B8', '#66E0B8',
......
// TODO: use this instead // TODO: use this instead
// https://github.com/zeit/swr/blob/master/examples/axios-typescript/libs/useRequest.ts // https://github.com/zeit/swr/blob/master/examples/axios-typescript/libs/useRequest.ts
import fetch from 'isomorphic-unfetch';
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import fetch from 'isomorphic-unfetch';
export const fetcher = async <T = any>(url: string, options?: any): Promise<T> => { export const fetcher = async <T = any>(url: string, options?: any): Promise<T> => {
const res = await fetch(process.env.API_URL + url, options); const res = await fetch(process.env.API_URL + url, options);
const response = await res.json(); const response = await res.json();
......
import {NextComponentType, NextPageContext} from 'next'; import {NextComponentType, NextPageContext} from 'next';
import moment from 'moment';
import NextI18Next from './i18next'; import NextI18Next from './i18next';
import {env} from '../next.config'; import {env} from '../next.config';
import moment from 'moment';
const defaultLanguage = env.DEFAULT_LANGUAGE; const defaultLanguage = env.DEFAULT_LANGUAGE;
const allLanguages = env.LANGUAGES; const allLanguages = env.LANGUAGES;
......
...@@ -18,14 +18,14 @@ ...@@ -18,14 +18,14 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react'; import {Config, I18n} from '../types';
import PropTypes from 'prop-types';
import NextLink, {LinkProps} from 'next/link'; import NextLink, {LinkProps} from 'next/link';
import {withTranslation} from 'react-i18next';
import {I18n, Config} from '../types';
import {lngPathCorrector, subpathIsRequired} from '../utils'; import {lngPathCorrector, subpathIsRequired} from '../utils';
import PropTypes from 'prop-types';
import React from 'react';
import {withTranslation} from 'react-i18next';
const removeWithTranslationProps = (props: any) => { const removeWithTranslationProps = (props: any) => {
const strippedProps = Object.assign({}, props); const strippedProps = Object.assign({}, props);
delete strippedProps.defaultNS; delete strippedProps.defaultNS;
......
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react';
import PropTypes from 'prop-types';
import PropTypes from 'prop-types';
import React from 'react';
import {withTranslation} from 'react-i18next'; import {withTranslation} from 'react-i18next';
interface Props { interface Props {
......
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import {defaultConfig} from './default-config';
import {consoleMessage, isServer} from '../utils'; import {consoleMessage, isServer} from '../utils';
import {Config} from '../types'; import {Config} from '../types';
import {defaultConfig} from './default-config';
const deepMergeObjects = ['backend', 'detection']; const deepMergeObjects = ['backend', 'detection'];
const dedupe = (names: string[]) => names.filter((v, i) => names.indexOf(v) === i); const dedupe = (names: string[]) => names.filter((v, i) => names.indexOf(v) === i);
......
import isNode from 'detect-node'; import {Config, InitPromise} from './types';
import I18nextBrowserLanguageDetector from 'i18next-browser-languagedetector';
import i18n from 'i18next'; import i18n from 'i18next';
import i18nextXHRBackend from 'i18next-xhr-backend'; import i18nextXHRBackend from 'i18next-xhr-backend';
import I18nextBrowserLanguageDetector from 'i18next-browser-languagedetector'; import isNode from 'detect-node';
import {InitPromise, Config} from './types';
export default (config: Config) => { export default (config: Config) => {
let initPromise: InitPromise | null = null; let initPromise: InitPromise | null = null;
......
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react';
import {NextPageContext} from 'next';
import {AppContext} from 'next/app';
import {withRouter} from 'next/router';
import hoistNonReactStatics from 'hoist-non-react-statics';
import {I18nextProvider, withSSR} from 'react-i18next'; import {I18nextProvider, withSSR} from 'react-i18next';
import {isServer, lngFromReq, lngPathCorrector, lngsToLoad} from '../utils'; import {isServer, lngFromReq, lngPathCorrector, lngsToLoad} from '../utils';
import {NextStaticProvider} from '../components';
import NextI18Next from '../index'; import {AppContext} from 'next/app';
import {I18n} from '../types'; import {I18n} from '../types';
import NextI18Next from '../index';
import {NextPageContext} from 'next';
import {NextStaticProvider} from '../components';
import React from 'react';
import hoistNonReactStatics from 'hoist-non-react-statics';
import {withRouter} from 'next/router';
interface Props { interface Props {
initialLanguage: string; initialLanguage: string;
...@@ -168,7 +168,7 @@ export const appWithTranslation = function(this: NextI18Next, WrappedComponent: ...@@ -168,7 +168,7 @@ export const appWithTranslation = function(this: NextI18Next, WrappedComponent:
const languagesToLoad = lngsToLoad(initialLanguage, fallbackLng, config.otherLanguages); const languagesToLoad = lngsToLoad(initialLanguage, fallbackLng, config.otherLanguages);
/* /*
Initialise the store with the languagesToLoad and Initialize the store with the languagesToLoad and
necessary namespaces needed to render this specific tree necessary namespaces needed to render this specific tree
*/ */
languagesToLoad.forEach(lng => { languagesToLoad.forEach(lng => {
...@@ -180,7 +180,7 @@ export const appWithTranslation = function(this: NextI18Next, WrappedComponent: ...@@ -180,7 +180,7 @@ export const appWithTranslation = function(this: NextI18Next, WrappedComponent:
}); });
} else if (Array.isArray(i18n.languages) && i18n.languages.length > 0) { } else if (Array.isArray(i18n.languages) && i18n.languages.length > 0) {
/* /*
Load newly-required translations if changing route clientside Load newly-required translations if changing route client side
*/ */
await clientLoadNamespaces(i18n.languages[0], namespacesRequired as string[]); await clientLoadNamespaces(i18n.languages[0], namespacesRequired as string[]);
......
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react';
import {NextI18NextInternals} from '../types'; import {NextI18NextInternals} from '../types';
import React from 'react';
export const withInternals = (WrappedComponent: any, config: NextI18NextInternals) => { export const withInternals = (WrappedComponent: any, config: NextI18NextInternals) => {
class WithInternals extends React.Component { class WithInternals extends React.Component {
static displayName = `withnextI18NextInternals(${WrappedComponent.displayName || static displayName = `withNextI18NextInternals(${WrappedComponent.displayName ||
WrappedComponent.name || WrappedComponent.name ||
'Component'})`; 'Component'})`;
......
import {withTranslation, useTranslation, Trans} from 'react-i18next';
import hoistNonReactStatics from 'hoist-non-react-statics';
import {createConfig} from './config/create-config';
import createI18NextClient from './create-i18next-client';
import {appWithTranslation, withInternals} from './hocs';
import {consoleMessage} from './utils';
import {Link} from './components';
import {wrapRouter} from './router';
import { import {
AppWithTranslation, AppWithTranslation,
Config, Config,
InitConfig,
Trans as TransType,
Link as LinkType,
I18n, I18n,
InitConfig,
InitPromise, InitPromise,
Link as LinkType,
Router,
Trans as TransType,
UseTranslation, UseTranslation,
WithTranslationHocType, WithTranslationHocType
Router
} from './types'; } from './types';
import {Trans, useTranslation, withTranslation} from 'react-i18next';
import {appWithTranslation, withInternals} from './hocs';
import {Link} from './components';
import {consoleMessage} from './utils';
import {createConfig} from './config/create-config';
import createI18NextClient from './create-i18next-client';
import hoistNonReactStatics from 'hoist-non-react-statics';
import {wrapRouter} from './router';
export {withTranslation} from 'react-i18next'; export {withTranslation} from 'react-i18next';
......
import {NextFunction, Request, Response} from 'express'; import {NextFunction, Request, Response} from 'express';
import i18nextMiddleware from 'i18next-express-middleware';
import pathMatch from 'path-match';
import NextI18Next from '../index';
import { import {
addSubpath, addSubpath,
lngFromReq, lngFromReq,
...@@ -13,6 +9,10 @@ import { ...@@ -13,6 +9,10 @@ import {
subpathIsRequired subpathIsRequired
} from '../utils'; } from '../utils';
import NextI18Next from '../index';
import i18nextMiddleware from 'i18next-express-middleware';
import pathMatch from 'path-match';
const route = pathMatch(); const route = pathMatch();
export default function(nexti18next: NextI18Next) { export default function(nexti18next: NextI18Next) {
......
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import * as React from 'react'; import * as React from 'react';
import {TFunction as I18NextTFunction, InitOptions, i18n} from 'i18next';
import { import {
useTranslation, WithTranslation as ReactI18nextWithTranslation,
TransProps, TransProps,
withTranslation, useTranslation,
WithTranslation as ReactI18nextWithTranslation withTranslation
} from 'react-i18next'; } from 'react-i18next';
import {LinkProps} from 'next/link'; import {LinkProps} from 'next/link';
import {SingletonRouter} from 'next/router'; import {SingletonRouter} from 'next/router';
import {InitOptions, i18n, TFunction as I18NextTFunction} from 'i18next';
export type InitConfig = { export type InitConfig = {
browserLanguageDetection?: boolean; browserLanguageDetection?: boolean;
......
/* eslint-disable no-console */ /* eslint-disable no-console */
import NextI18Next from '../index';
import {Config} from '../types'; import {Config} from '../types';
import NextI18Next from '../index';
type MessageType = 'error' | 'info' | 'warn'; type MessageType = 'error' | 'info' | 'warn';
......
import {Request} from 'express';
import {Config} from '../types'; import {Config} from '../types';
import {Request} from 'express';
export const lngFromReq = (req: Request) => { export const lngFromReq = (req: Request) => {
if (!req.i18n) { if (!req.i18n) {
......
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import {format as formatUrl, parse as parseUrl} from 'url'; import {format as formatUrl, parse as parseUrl} from 'url';
import {removeSubpath, subpathFromLng, subpathIsPresent, subpathIsRequired} from './index';
import {Config} from '../types'; import {Config} from '../types';
import {removeSubpath, subpathIsPresent, subpathIsRequired, subpathFromLng} from './index';
const parseAs = (originalAs: string | undefined, href: any) => { const parseAs = (originalAs: string | undefined, href: any) => {
const asType = typeof originalAs; const asType = typeof originalAs;
......
import * as polished from 'polished';
import {createGlobalStyle, keyframes} from 'styled-components'; import {createGlobalStyle, keyframes} from 'styled-components';
import {rem as rem16, em as em16, math, normalize, darken, lighten, size} from 'polished';
import vdlIcon from '!!css-loader!~/public/style/vdl-icon.css'; import vdlIcon from '!!css-loader!~/public/style/vdl-icon.css';
export {default as styled} from 'styled-components'; export {default as styled} from 'styled-components';
export * from 'styled-components'; export * from 'styled-components';
export * from 'polished'; export * from 'polished';
// rename conflict shorthands
export {borderRadius as borderRadiusShortHand, borderColor as borderColorShortHand} from 'polished';
const fontSize = '14px'; const {math, size, lighten, darken, normalize, fontFace, transitions, border, position} = polished;
export const rem = (pxval: string | number): string => rem16(pxval, fontSize);
export const em = (pxval: string | number, base?: string | number): string => em16(pxval, base || fontSize);
export const half = (value: string | number): string => math(`${value} / 2`);
// sizes // sizes
const fontSize = '14px';
export const rem = (pxval: string | number): string => polished.rem(pxval, fontSize);
export const em = (pxval: string | number, base?: string | number): string => polished.em(pxval, base || fontSize);
export const half = (value: string | number): string => math(`(${value}) / 2`);
export const headerHeight = rem(60); export const headerHeight = rem(60);
export const asideWidth = rem(260); export const asideWidth = rem(260);
export const borderRadius = '4px'; export const borderRadius = '4px';
export const progressSpinnerSize = '20px'; export const progressSpinnerSize = '20px';
// colors // colors
export const headerColor = '#1527C2';
export const primaryColor = '#2932E1'; export const primaryColor = '#2932E1';
export const primaryFocusedColor = lighten(0.08, primaryColor); export const primaryFocusedColor = lighten(0.08, primaryColor);
export const primaryActiveColor = lighten(0.12, primaryColor); export const primaryActiveColor = lighten(0.12, primaryColor);
...@@ -34,6 +38,9 @@ export const backgroundColor = '#FFF'; ...@@ -34,6 +38,9 @@ export const backgroundColor = '#FFF';
export const backgroundFocusedColor = '#F6F6F6'; export const backgroundFocusedColor = '#F6F6F6';
export const borderColor = '#DDD'; export const borderColor = '#DDD';
export const borderFocusedColor = darken(0.15, borderColor); export const borderFocusedColor = darken(0.15, borderColor);
export const navbarBackgroundColor = '#1527C2';
export const navbarHoverBackgroundColor = lighten(0.05, navbarBackgroundColor);
export const navbarHighlightColor = '#596cd6';
export const progressBarColor = '#FFF'; export const progressBarColor = '#FFF';
export const maskColor = 'rgba(255, 255, 255, 0.8)'; export const maskColor = 'rgba(255, 255, 255, 0.8)';
...@@ -41,6 +48,38 @@ export const maskColor = 'rgba(255, 255, 255, 0.8)'; ...@@ -41,6 +48,38 @@ export const maskColor = 'rgba(255, 255, 255, 0.8)';
export const duration = '75ms'; export const duration = '75ms';
export const easing = 'ease-in'; export const easing = 'ease-in';
// mixins
export const sameBorder = (
width = '1px' as
| string
| number
| {width?: string | number; type?: string; color?: string; radius?: string | boolean},
type = 'solid',
color = borderColor,
radius?: string | boolean
) => {
if ('object' === typeof width) {
type = width.type ?? 'solid';
color = width.color ?? borderColor;
radius = width.radius === true ? borderRadius : width.radius;
width = width.width ?? '1px';
}
return Object.assign(
{},
border(width, type, color),
radius ? {borderRadius: radius === true ? borderRadius : radius} : undefined
);
};
export const transitionProps = (props: string | string[], args?: string) => {
if ('string' === typeof props) {
props = [props];
}
if (!args) {
args = `${duration} ${easing}`;
}
return transitions(props, args);
};
const spinner = keyframes` const spinner = keyframes`
0% { 0% {
transform: rotate(0deg); transform: rotate(0deg);
...@@ -58,15 +97,14 @@ export type WithStyled = { ...@@ -58,15 +97,14 @@ export type WithStyled = {
export const GlobalStyle = createGlobalStyle` export const GlobalStyle = createGlobalStyle`
${normalize} ${normalize}
@font-face { ${fontFace({
font-family: 'vdl-icon'; fontFamily: 'vdl-icon',
src: url("${process.env.PUBLIC_PATH}/style/fonts/vdl-icon.ttf?5sp5gl") format('truetype'), fontFilePath: `${process.env.PUBLIC_PATH}/style/fonts/vdl-icon`,
url("${process.env.PUBLIC_PATH}/style/fonts/vdl-icon.woff?5sp5gl") format('woff'), fileFormats: ['ttf', 'woff', 'svg'],
url("${process.env.PUBLIC_PATH}/style/fonts/vdl-icon.svg?5sp5gl#vdl-icon") format('svg'); fontWeight: 'normal',
font-weight: normal; fontStyle: 'normal',
font-style: normal; fontDisplay: 'block'
font-display: block; })}
}
${vdlIcon.toString()} ${vdlIcon.toString()}
...@@ -103,22 +141,15 @@ export const GlobalStyle = createGlobalStyle` ...@@ -103,22 +141,15 @@ export const GlobalStyle = createGlobalStyle`
#nprogress .bar { #nprogress .bar {
background: ${progressBarColor}; background: ${progressBarColor};
position: fixed;
z-index: 99999; z-index: 99999;
top: 0; ${position('fixed', 0, null, null, 0)}
left: 0; ${size('2px', '100%')}
width: 100%;
height: 2px;
} }
#nprogress .peg { #nprogress .peg {
display: block; display: block;
position: absolute; ${position('absolute', null, 0, null, null)}
right: 0; ${size('100%', rem(100))}
width: ${rem(100)};
height: 100%;
box-shadow: 0 0 rem(10) ${progressBarColor}, 0 0 ${rem(5)} ${progressBarColor}; box-shadow: 0 0 rem(10) ${progressBarColor}, 0 0 ${rem(5)} ${progressBarColor};
opacity: 1; opacity: 1;
transform: rotate(3deg) translate(0px, -${rem(4)}); transform: rotate(3deg) translate(0px, -${rem(4)});
...@@ -126,10 +157,8 @@ export const GlobalStyle = createGlobalStyle` ...@@ -126,10 +157,8 @@ export const GlobalStyle = createGlobalStyle`
#nprogress .spinner { #nprogress .spinner {
display: block; display: block;
position: fixed;
z-index: 99999; z-index: 99999;
top: ${progressSpinnerSize}; ${position('fixed', progressSpinnerSize, progressSpinnerSize, null, null)}
right: ${progressSpinnerSize};
} }
#nprogress .spinner-icon { #nprogress .spinner-icon {
......
import {DivideParams, divide} from '~/resource/high-dimensional';
import {exposeWorker} from 'react-hooks-worker'; import {exposeWorker} from 'react-hooks-worker';
import {divide, DivideParams} from '~/resource/high-dimensional';
// exposeWorker can only handle Promise // exposeWorker can only handle Promise
exposeWorker((data: DivideParams) => Promise.resolve(divide(data))); exposeWorker((data: DivideParams) => Promise.resolve(divide(data)));
import {RangeParams, range} from '~/resource/scalars';
import {exposeWorker} from 'react-hooks-worker'; import {exposeWorker} from 'react-hooks-worker';
import {range, RangeParams} from '~/resource/scalars';
// exposeWorker can only handle Promise // exposeWorker can only handle Promise
exposeWorker((data: RangeParams) => Promise.resolve(range(data))); exposeWorker((data: RangeParams) => Promise.resolve(range(data)));
import {TransformParams, transform} from '~/resource/scalars';
import {exposeWorker} from 'react-hooks-worker'; import {exposeWorker} from 'react-hooks-worker';
import {transform, TransformParams} from '~/resource/scalars';
// exposeWorker can only handle Promise // exposeWorker can only handle Promise
exposeWorker((data: TransformParams) => Promise.resolve(transform(data))); exposeWorker((data: TransformParams) => Promise.resolve(transform(data)));
numpy==1.16.6 numpy == 1.16.6; python_version < "3.0"
recommonmark==0.6.0 numpy == 1.18.2; python_version >= "3.0"
scipy==1.2.3 recommonmark == 0.6.0
Sphinx==1.8.5 scipy == 1.2.3; python_version < "3.0"
sphinx-rtd-theme==0.4.3 scipy == 1.4.1; python_version >= "3.0"
flake8==3.7.9 Sphinx == 1.8.5; python_version < "3.0"
Pillow==6.2.2 Sphinx == 2.4.4; python_version >= "3.0"
pre-commit==1.21.0 sphinx-rtd-theme == 0.4.3
flask==1.1.1 flake8 == 3.7.9
six==1.14.0 Pillow == 6.2.2; python_version < "3.0"
protobuf==3.11.3 Pillow == 7.0.0; python_version >= "3.0"
pre-commit == 1.21.0; python_version <= "3.5"
pre-commit == 2.2.0; python_version > "3.5"
flask == 1.1.1
Flask-Babel === 1.0.0
six == 1.14.0
protobuf == 3.11.3
...@@ -14,23 +14,60 @@ build_frontend_from_source() { ...@@ -14,23 +14,60 @@ build_frontend_from_source() {
} }
build_frontend() { build_frontend() {
local PACKAGE_NAME="visualdl" local PACKAGE="visualdl"
echo "Donwloading npm package, please wait..." local TAG="latest"
local PACKAGE=`(cd $BUILD_DIR && npm pack ${PACKAGE_NAME}@latest)` local TARBALL="${PACKAGE}@${TAG}"
local SHA1SUM=`npm view ${PACKAGE_NAME}@latest dist.shasum`
# get version
local VERSION=`npm view ${TARBALL} dist-tags.${TAG}`
if [ "$?" -ne "0" ]; then if [ "$?" -ne "0" ]; then
echo "Cannot get sha1sum" echo "Cannot get version"
exit 1 exit 1
fi fi
echo "${SHA1SUM} ${PACKAGE}" > "$BUILD_DIR/${PACKAGE}.sha1" local FILENAME="${PACKAGE}-${VERSION}.tgz"
(cd $BUILD_DIR && sha1sum -c "${PACKAGE}.sha1")
# get sha1sum
local SHA1SUM=`npm view ${TARBALL} dist.shasum`
if [ "$?" -ne "0" ]; then if [ "$?" -ne "0" ]; then
echo "Check sum failed, download may not finish correctly." echo "Cannot get sha1sum"
exit 1 exit 1
else
echo "Check sum pass."
fi fi
tar zxf "$BUILD_DIR/$PACKAGE" -C "$BUILD_DIR" rm -f "$BUILD_DIR/${PACKAGE}-*.tgz.sha1"
echo "${SHA1SUM} ${FILENAME}" > "$BUILD_DIR/${FILENAME}.sha1"
local DOWNLOAD="1"
# cached file exists
if [ -f "$BUILD_DIR/$FILENAME" ]; then
# check sha1sum
(cd $BUILD_DIR && sha1sum -c "${FILENAME}.sha1")
# check pass, use chached file
if [ "$?" -eq "0" ]; then
echo "Using cached npm package file ${FILENAME}"
DOWNLOAD="0"
fi
fi
if [ "$DOWNLOAD" -eq "1" ]; then
echo "Donwloading npm package, please wait..."
# remove cache
rm -f "$BUILD_DIR/${PACKAGE}-*.tgz"
# download file
FILENAME=`(cd $BUILD_DIR && npm pack ${TARBALL})`
# check sha1sum of downloaded file
(cd $BUILD_DIR && sha1sum -c "${FILENAME}.sha1")
if [ "$?" -ne "0" ]; then
echo "Check sum failed, download may not finish correctly."
exit 1
else
echo "Check sum pass."
fi
fi
# extract
tar zxf "$BUILD_DIR/$FILENAME" -C "$BUILD_DIR"
} }
build_frontend_fake() { build_frontend_fake() {
...@@ -61,8 +98,6 @@ clean_env() { ...@@ -61,8 +98,6 @@ clean_env() {
rm -rf $BUILD_DIR/lib* rm -rf $BUILD_DIR/lib*
rm -rf $BUILD_DIR/temp* rm -rf $BUILD_DIR/temp*
rm -rf $BUILD_DIR/scripts* rm -rf $BUILD_DIR/scripts*
rm -rf $BUILD_DIR/*.tgz
rm -rf $BUILD_DIR/*.sha1
rm -rf $BUILD_DIR/package rm -rf $BUILD_DIR/package
} }
......
...@@ -24,6 +24,7 @@ from argparse import ArgumentParser ...@@ -24,6 +24,7 @@ from argparse import ArgumentParser
from flask import (Flask, Response, redirect, request, send_file, from flask import (Flask, Response, redirect, request, send_file,
send_from_directory) send_from_directory)
from flask_babel import Babel
import visualdl import visualdl
import visualdl.server import visualdl.server
...@@ -41,24 +42,26 @@ try: ...@@ -41,24 +42,26 @@ try:
except: except:
pass pass
support_language = ["en", "zh"]
default_language = support_language[0]
app = Flask(__name__, static_url_path="") app = Flask(__name__, static_url_path="")
# set static expires in a short time to reduce browser's memory usage. # set static expires in a short time to reduce browser's memory usage.
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 30 app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 30
app.config['BABEL_DEFAULT_LOCALE'] = default_language
babel = Babel(app)
error_retry_times = 3 error_retry_times = 3
error_sleep_time = 2 # seconds error_sleep_time = 2 # seconds
SERVER_DIR = os.path.join(visualdl.ROOT, 'server') SERVER_DIR = os.path.join(visualdl.ROOT, 'server')
support_language = ["en", "zh"]
default_language = support_language[0]
def try_call(function, *args, **kwargs): def try_call(function, *args, **kwargs):
res = lib.retry(error_retry_times, function, error_sleep_time, *args, res = lib.retry(error_retry_times, function, error_sleep_time, *args,
**kwargs) **kwargs)
if not res: if not res:
logger.error("server temporary error, will retry latter.") logger.error("Internal server error. Retry later.")
return res return res
...@@ -107,7 +110,6 @@ def parse_args(): ...@@ -107,7 +110,6 @@ def parse_args():
"-L", "-L",
"--language", "--language",
type=str, type=str,
default=default_language,
action="store", action="store",
help="set the default language") help="set the default language")
...@@ -146,11 +148,17 @@ def gen_result(status, msg, data): ...@@ -146,11 +148,17 @@ def gen_result(status, msg, data):
return result return result
@babel.localeselector
def get_locale():
language = args.language
if not language or not language in support_language:
language = request.accept_languages.best_match(support_language)
return language
@app.route("/") @app.route("/")
def index(): def index():
language = args.language language = get_locale()
if not language in support_language:
language = default_language
if language == default_language: if language == default_language:
return redirect('/app/index', code=302) return redirect('/app/index', code=302)
return redirect('/app/' + language + '/index', code=302) return redirect('/app/' + language + '/index', code=302)
...@@ -182,9 +190,7 @@ def runs(): ...@@ -182,9 +190,7 @@ def runs():
@app.route('/api/language') @app.route('/api/language')
def language(): def language():
data = args.language data = get_locale()
if not data in support_language:
data = default_language
result = gen_result(0, "", data) result = gen_result(0, "", data)
return Response(json.dumps(result), mimetype='application/json') return Response(json.dumps(result), mimetype='application/json')
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册