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