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

frontend 2.0.0-beta.25: user experience improvement of scalars page (#608)

* chore: update dependencies

* build: update frontend build from source

* fix: use bignumber.js to keep data precision

* feat: if there is only one point, place it in the middle

* style: update lint staged config

* style: fit prettier 2.0

* fix: globalize bignumber config
上级 cdb82390
...@@ -26,16 +26,20 @@ const Wrapper = styled.div` ...@@ -26,16 +26,20 @@ const Wrapper = styled.div`
} }
`; `;
type Range = {
min: EChartOption.BasicComponents.CartesianAxis['min'];
max: EChartOption.BasicComponents.CartesianAxis['max'];
};
type LineChartProps = { type LineChartProps = {
title?: string; title?: string;
legend?: string[]; legend?: string[];
data?: Partial<NonNullable<EChartOption<EChartOption.SeriesLine>['series']>>; data?: Partial<NonNullable<EChartOption<EChartOption.SeriesLine>['series']>>;
xAxis?: string; xAxis?: string;
yAxis?: string;
type?: EChartOption.BasicComponents.CartesianAxis.Type; type?: EChartOption.BasicComponents.CartesianAxis.Type;
yRange?: { xRange?: Range;
min: number; yRange?: Range;
max: number;
};
tooltip?: string | EChartOption.Tooltip.Formatter; tooltip?: string | EChartOption.Tooltip.Formatter;
loading?: boolean; loading?: boolean;
}; };
...@@ -45,7 +49,9 @@ const LineChart: FunctionComponent<LineChartProps & WithStyled> = ({ ...@@ -45,7 +49,9 @@ const LineChart: FunctionComponent<LineChartProps & WithStyled> = ({
legend, legend,
data, data,
xAxis, xAxis,
yAxis,
type, type,
xRange,
yRange, yRange,
tooltip, tooltip,
loading, loading,
...@@ -93,21 +99,25 @@ const LineChart: FunctionComponent<LineChartProps & WithStyled> = ({ ...@@ -93,21 +99,25 @@ const LineChart: FunctionComponent<LineChartProps & WithStyled> = ({
axisLabel: { axisLabel: {
...chart.xAxis.axisLabel, ...chart.xAxis.axisLabel,
formatter: xAxisFormatter formatter: xAxisFormatter
} },
...(xRange || {})
}, },
yAxis: { yAxis: {
...chart.yAxis, ...chart.yAxis,
name: yAxis || '',
...(yRange || {}) ...(yRange || {})
}, },
series: data?.map(item => ({ series: data?.map(item => ({
...chart.series, ...chart.series,
// show symbol if there is only one point
showSymbol: (item?.data?.length ?? 0) <= 1,
...item ...item
})) }))
} as EChartOption, } as EChartOption,
{notMerge: true} {notMerge: true}
); );
} }
}, [data, title, legend, xAxis, type, xAxisFormatter, yRange, tooltip, echart]); }, [data, title, legend, xAxis, yAxis, type, xAxisFormatter, xRange, yRange, tooltip, echart]);
return ( return (
<Wrapper className={className}> <Wrapper className={className}>
......
...@@ -5,6 +5,7 @@ import { ...@@ -5,6 +5,7 @@ import {
TransformParams, TransformParams,
chartData, chartData,
range, range,
singlePointRange,
sortingMethodMap, sortingMethodMap,
tooltip, tooltip,
transform, transform,
...@@ -101,6 +102,20 @@ const ScalarChart: FunctionComponent<ScalarChartProps> = ({ ...@@ -101,6 +102,20 @@ const ScalarChart: FunctionComponent<ScalarChartProps> = ({
); );
const yRange = useHeavyWork(rangeWasm, rangeWorker, range, rangeParams); const yRange = useHeavyWork(rangeWasm, rangeWorker, range, rangeParams);
const ranges: Record<'x' | 'y', Range | undefined> = useMemo(() => {
let x: Range | undefined = undefined;
let y: Range | undefined = yRange;
// if there is only one point, place it in the middle
if (smoothedDatasets.length === 1 && smoothedDatasets[0].length === 1) {
if (['value', 'log'].includes(type)) {
x = singlePointRange(smoothedDatasets[0][0][xAxisMap[xAxis]]);
}
y = singlePointRange(smoothedDatasets[0][0][2]);
}
return {x, y};
}, [smoothedDatasets, yRange, type, xAxis]);
const data = useMemo( const data = useMemo(
() => () =>
chartData({ chartData({
...@@ -157,7 +172,8 @@ const ScalarChart: FunctionComponent<ScalarChartProps> = ({ ...@@ -157,7 +172,8 @@ const ScalarChart: FunctionComponent<ScalarChartProps> = ({
<StyledLineChart <StyledLineChart
title={tag} title={tag}
xAxis={xAxisLabel} xAxis={xAxisLabel}
yRange={yRange} xRange={ranges.x}
yRange={ranges.y}
type={type} type={type}
tooltip={formatter} tooltip={formatter}
data={data} data={data}
......
module.exports = { module.exports = {
'**/*.ts?(x)': filenames => [ '**/*.ts?(x)': () => ['tsc -p tsconfig.json --noEmit', 'tsc -p server/tsconfig.json --noEmit'],
'tsc -p tsconfig.json --noEmit', '**/*.(j|t)s?(x)': filenames => `eslint ${filenames.join(' ')}`
'tsc -p server/tsconfig.json --noEmit',
`eslint ${filenames.join(' ')}`
],
'**/*.js?(x)': filenames => `eslint ${filenames.join(' ')}`
}; };
{ {
"name": "visualdl", "name": "visualdl",
"version": "2.0.0-beta.24", "version": "2.0.0-beta.25",
"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": [
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
"export": "next export -o serverless", "export": "next export -o serverless",
"start": "pm2-runtime ecosystem.config.js", "start": "pm2-runtime ecosystem.config.js",
"lint": "tsc -p tsconfig.json --noEmit && tsc -p server/tsconfig.json --noEmit && eslint --ext .tsx,.jsx.ts,.js --ignore-path .gitignore .", "lint": "tsc -p tsconfig.json --noEmit && tsc -p server/tsconfig.json --noEmit && eslint --ext .tsx,.jsx.ts,.js --ignore-path .gitignore .",
"format": "prettier --write \"**/*.ts\" \"**/*.tsx\" \"**/*.js\" \"**/*.jsx\"", "format": "prettier --write \"**/*.ts\" \"**/*.tsx\" \"**/*.js\"",
"test": "echo \"Error: no test specified\" && exit 0", "test": "echo \"Error: no test specified\" && exit 0",
"prepublishOnly": "yarn lint && yarn test && ./scripts/build.sh", "prepublishOnly": "yarn lint && yarn test && ./scripts/build.sh",
"preversion": "yarn lint", "preversion": "yarn lint",
...@@ -51,9 +51,10 @@ ...@@ -51,9 +51,10 @@
"ecosystem.config.js" "ecosystem.config.js"
], ],
"dependencies": { "dependencies": {
"bignumber.js": "9.0.0",
"dagre-d3": "0.6.4", "dagre-d3": "0.6.4",
"detect-node": "2.0.4", "detect-node": "2.0.4",
"echarts": "4.6.0", "echarts": "4.7.0",
"echarts-gl": "1.1.1", "echarts-gl": "1.1.1",
"express": "4.17.1", "express": "4.17.1",
"hoist-non-react-statics": "3.3.2", "hoist-non-react-statics": "3.3.2",
...@@ -72,15 +73,15 @@ ...@@ -72,15 +73,15 @@
"ora": "4.0.3", "ora": "4.0.3",
"path-match": "1.2.4", "path-match": "1.2.4",
"pm2": "4.2.3", "pm2": "4.2.3",
"polished": "3.4.4", "polished": "3.5.1",
"prop-types": "15.7.2", "prop-types": "15.7.2",
"query-string": "6.11.1", "query-string": "6.11.1",
"react": "16.13.0", "react": "16.13.1",
"react-dom": "16.13.0", "react-dom": "16.13.1",
"react-hooks-worker": "0.9.0", "react-hooks-worker": "0.9.0",
"react-i18next": "11.3.3", "react-i18next": "11.3.4",
"react-input-range": "1.3.0", "react-input-range": "1.3.0",
"react-is": "16.13.0", "react-is": "16.13.1",
"react-spinners": "0.8.1", "react-spinners": "0.8.1",
"save-svg-as-png": "1.4.17", "save-svg-as-png": "1.4.17",
"styled-components": "5.0.1", "styled-components": "5.0.1",
...@@ -89,22 +90,22 @@ ...@@ -89,22 +90,22 @@
"yargs": "15.3.1" "yargs": "15.3.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.8.7", "@babel/core": "7.9.0",
"@types/d3": "5.7.2", "@types/d3": "5.7.2",
"@types/dagre": "0.7.42", "@types/dagre-d3": "^0.4.39",
"@types/echarts": "4.4.3", "@types/echarts": "4.4.3",
"@types/express": "4.17.3", "@types/express": "4.17.3",
"@types/faker": "4.1.10", "@types/faker": "4.1.10",
"@types/lodash": "4.14.149", "@types/lodash": "4.14.149",
"@types/node": "13.9.1", "@types/node": "13.9.3",
"@types/nprogress": "0.2.0", "@types/nprogress": "0.2.0",
"@types/react": "16.9.23", "@types/react": "16.9.25",
"@types/react-dom": "16.9.5", "@types/react-dom": "16.9.5",
"@types/styled-components": "5.0.1", "@types/styled-components": "5.0.1",
"@types/webpack": "4.41.7", "@types/webpack": "4.41.8",
"@types/yargs": "15.0.4", "@types/yargs": "15.0.4",
"@typescript-eslint/eslint-plugin": "2.24.0", "@typescript-eslint/eslint-plugin": "2.25.0",
"@typescript-eslint/parser": "2.24.0", "@typescript-eslint/parser": "2.25.0",
"@wasm-tool/wasm-pack-plugin": "1.2.0", "@wasm-tool/wasm-pack-plugin": "1.2.0",
"babel-plugin-emotion": "10.0.29", "babel-plugin-emotion": "10.0.29",
"babel-plugin-styled-components": "1.10.7", "babel-plugin-styled-components": "1.10.7",
...@@ -112,16 +113,16 @@ ...@@ -112,16 +113,16 @@
"core-js": "3", "core-js": "3",
"cross-env": "7.0.2", "cross-env": "7.0.2",
"eslint": "6.8.0", "eslint": "6.8.0",
"eslint-config-prettier": "6.10.0", "eslint-config-prettier": "6.10.1",
"eslint-plugin-prettier": "3.1.2", "eslint-plugin-prettier": "3.1.2",
"eslint-plugin-react": "7.19.0", "eslint-plugin-react": "7.19.0",
"eslint-plugin-react-hooks": "2.5.0", "eslint-plugin-react-hooks": "2.5.1",
"faker": "4.1.0", "faker": "4.1.0",
"husky": "4.2.3", "husky": "4.2.3",
"lint-staged": "10.0.8", "lint-staged": "10.0.9",
"nodemon": "2.0.2", "nodemon": "2.0.2",
"prettier": "1.19.1", "prettier": "2.0.2",
"ts-node": "8.6.2", "ts-node": "8.8.1",
"typescript": "3.8.3", "typescript": "3.8.3",
"worker-plugin": "4.0.2", "worker-plugin": "4.0.2",
"yarn": "1.22.4" "yarn": "1.22.4"
......
import {Graph, collectDagFacts} from '~/resource/graphs'; import {Graph, NodeType, TypedNode, collectDagFacts} from '~/resource/graphs';
import {NextI18NextPage, useTranslation} from '~/utils/i18n'; import {NextI18NextPage, useTranslation} from '~/utils/i18n';
import NodeInfo, {NodeInfoProps} from '~/components/GraphsPage/NodeInfo'; import NodeInfo, {NodeInfoProps} from '~/components/GraphsPage/NodeInfo';
import React, {useEffect, useMemo, useState} from 'react'; import React, {useEffect, useMemo, useState} from 'react';
...@@ -154,7 +154,7 @@ const useDagreD3 = (graph?: Graph) => { ...@@ -154,7 +154,7 @@ const useDagreD3 = (graph?: Graph) => {
return; return;
} }
const g = new dagre.graphlib.Graph(); const g = new dagre.graphlib.Graph<{type: NodeType; elem: HTMLElement}>();
g.setGraph({}).setDefaultEdgeLabel(() => ({})); g.setGraph({}).setDefaultEdgeLabel(() => ({}));
dagInfo.nodes.forEach(n => g.setNode(n.key, n)); dagInfo.nodes.forEach(n => g.setNode(n.key, n));
...@@ -172,7 +172,7 @@ const useDagreD3 = (graph?: Graph) => { ...@@ -172,7 +172,7 @@ const useDagreD3 = (graph?: Graph) => {
const zoom = d3 const zoom = d3
.zoom<HTMLElement, any>() // eslint-disable-line @typescript-eslint/no-explicit-any .zoom<HTMLElement, any>() // eslint-disable-line @typescript-eslint/no-explicit-any
.scaleExtent([MIN_SCALE, MAX_SCALE]) .scaleExtent([MIN_SCALE, MAX_SCALE])
.on('zoom', function() { .on('zoom', function () {
setScaleValue(d3.event.transform.k / scaleFactor); setScaleValue(d3.event.transform.k / scaleFactor);
inner.attr('transform', d3.event.transform); inner.attr('transform', d3.event.transform);
}) })
...@@ -196,7 +196,7 @@ const useDagreD3 = (graph?: Graph) => { ...@@ -196,7 +196,7 @@ const useDagreD3 = (graph?: Graph) => {
return; return;
} }
setCurrentNode({...node, type}); setCurrentNode({...node, type} as TypedNode);
}); });
const fitScreen = () => { const fitScreen = () => {
......
...@@ -3,6 +3,7 @@ import * as chart from '~/utils/chart'; ...@@ -3,6 +3,7 @@ import * as chart from '~/utils/chart';
import {ChartDataParams, RangeParams, TooltipData, TransformParams, xAxisMap} from './types'; import {ChartDataParams, RangeParams, TooltipData, TransformParams, xAxisMap} from './types';
import {formatTime, quantile} from '~/utils'; import {formatTime, quantile} from '~/utils';
import BigNumber from 'bignumber.js';
import {I18n} from '~/utils/i18next/types'; import {I18n} from '~/utils/i18next/types';
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';
import compact from 'lodash/compact'; import compact from 'lodash/compact';
...@@ -10,6 +11,8 @@ import maxBy from 'lodash/maxBy'; ...@@ -10,6 +11,8 @@ import maxBy from 'lodash/maxBy';
import minBy from 'lodash/minBy'; import minBy from 'lodash/minBy';
import sortBy from 'lodash/sortBy'; import sortBy from 'lodash/sortBy';
BigNumber.config({EXPONENTIAL_AT: [-6, 7]});
export * from './types'; export * from './types';
export const sortingMethodMap = { export const sortingMethodMap = {
...@@ -24,11 +27,12 @@ export const transform = ({datasets, smoothing}: TransformParams) => ...@@ -24,11 +27,12 @@ export const transform = ({datasets, smoothing}: TransformParams) =>
// https://en.wikipedia.org/wiki/Moving_average // https://en.wikipedia.org/wiki/Moving_average
datasets.map(seriesData => { datasets.map(seriesData => {
const data = cloneDeep(seriesData); const data = cloneDeep(seriesData);
let last = data.length > 0 ? 0 : Number.NaN; let last = new BigNumber(data.length > 0 ? 0 : Number.NaN);
let numAccum = 0; let numAccum = 0;
let startValue = 0; let startValue = 0;
const bigSmoothing = new BigNumber(smoothing);
data.forEach((d, i) => { data.forEach((d, i) => {
const nextVal = d[2]; const nextVal = new BigNumber(d[2]);
// second to millisecond. // second to millisecond.
const millisecond = (d[0] = Math.floor(d[0] * 1000)); const millisecond = (d[0] = Math.floor(d[0] * 1000));
if (i === 0) { if (i === 0) {
...@@ -36,16 +40,19 @@ export const transform = ({datasets, smoothing}: TransformParams) => ...@@ -36,16 +40,19 @@ export const transform = ({datasets, smoothing}: TransformParams) =>
} }
// Relative time, millisecond to hours. // Relative time, millisecond to hours.
d[4] = Math.floor(millisecond - startValue) / (60 * 60 * 1000); d[4] = Math.floor(millisecond - startValue) / (60 * 60 * 1000);
if (!isFinite(nextVal)) { if (!nextVal.isFinite()) {
d[3] = nextVal; d[3] = nextVal.toNumber();
} else { } else {
last = last * smoothing + (1 - smoothing) * nextVal; // last = last * smoothing + (1 - smoothing) * nextVal;
last = last.multipliedBy(bigSmoothing).plus(bigSmoothing.minus(1).negated().multipliedBy(nextVal));
numAccum++; numAccum++;
let debiasWeight = 1; let debiasWeight = new BigNumber(1);
if (smoothing !== 1.0) { if (!bigSmoothing.isEqualTo(1)) {
debiasWeight = 1.0 - Math.pow(smoothing, numAccum); //debiasWeight = 1.0 - Math.pow(smoothing, numAccum);
debiasWeight = bigSmoothing.exponentiatedBy(numAccum).minus(1).negated();
} }
d[3] = last / debiasWeight; // d[3] = last / debiasWeight;
d[3] = last.dividedBy(debiasWeight).toNumber();
} }
}); });
return data; return data;
...@@ -95,22 +102,28 @@ export const chartData = ({data, runs, smooth, xAxis}: ChartDataParams) => ...@@ -95,22 +102,28 @@ export const chartData = ({data, runs, smooth, xAxis}: ChartDataParams) =>
}) })
.flat(); .flat();
export const singlePointRange = (value: number) => ({
min: value ? Math.min(value * 2, 0) : -0.5,
max: value ? Math.max(value * 2, 0) : 0.5
});
export const range = ({datasets, outlier}: RangeParams) => { export const range = ({datasets, outlier}: RangeParams) => {
const ranges = compact( const ranges = compact(
datasets?.map(dataset => { datasets?.map(dataset => {
if (dataset.length == 0) return; if (dataset.length == 0) return;
const values = dataset.map(v => v[2]);
if (!outlier) { if (!outlier) {
// Get the orgin data range. // Get the orgin data range.
return { return {
min: minBy(dataset, items => items[2])?.[2] ?? 0, min: Math.min(...values) ?? 0,
max: maxBy(dataset, items => items[2])?.[2] ?? 0 max: Math.max(...values) ?? 0
}; };
} else { } else {
// Get the quantile range. // Get the quantile range.
const sorted = sortBy(dataset, [item => item[2]]); const sorted = dataset.map(v => v[2]).sort();
return { return {
min: quantile(sorted, 0.05, item => item[2]), min: quantile(sorted, 0.05),
max: quantile(dataset, 0.95, item => item[2]) max: quantile(values, 0.95)
}; };
} }
}) })
...@@ -140,7 +153,7 @@ export const tooltip = (data: TooltipData[], i18n: I18n) => { ...@@ -140,7 +153,7 @@ export const tooltip = (data: TooltipData[], i18n: I18n) => {
Run: 60, Run: 60,
Time: 120, Time: 120,
Step: 40, Step: 40,
Value: 50, Value: 60,
Smoothed: 60, Smoothed: 60,
Relative: 60 Relative: 60
}; };
...@@ -156,9 +169,9 @@ export const tooltip = (data: TooltipData[], i18n: I18n) => { ...@@ -156,9 +169,9 @@ export const tooltip = (data: TooltipData[], i18n: I18n) => {
const data = item.item; const data = item.item;
return { return {
Run: item.run, Run: item.run,
// Keep six number for easy-read. // use precision then toString to remove trailling 0
Smoothed: data[indexPropMap.Smoothed]?.toString().slice(0, 6), Smoothed: new BigNumber(data[indexPropMap.Smoothed] ?? Number.NaN).precision(5).toString(),
Value: data[indexPropMap.Value]?.toString().slice(0, 6), Value: new BigNumber(data[indexPropMap.Smoothed] ?? Number.NaN).precision(5).toString(),
Step: data[indexPropMap.Step], Step: data[indexPropMap.Step],
Time: formatTime(data[indexPropMap.Time], i18n.language), Time: formatTime(data[indexPropMap.Time], i18n.language),
// Relative display value should take easy-read into consideration. // Relative display value should take easy-read into consideration.
......
#!/bin/bash #!/bin/bash
set -e set -ex
# rust toolchain # rust toolchain
# https://rustup.rs/ # https://rustup.rs/
curl https://sh.rustup.rs -sSf | sh -s -- --no-modify-path --default-toolchain nightly -y if ! hash rustup 2>/dev/null; then
source $HOME/.cargo/env curl https://sh.rustup.rs -sSf | sh -s -- --no-modify-path --default-toolchain nightly -y
source $HOME/.cargo/env
fi
# wasm-pack # wasm-pack
# https://rustwasm.github.io/wasm-pack/installer/ # https://rustwasm.github.io/wasm-pack/installer/
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh if ! hash wasm-pack 2>/dev/null; then
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
fi
# yarn install # yarn install
yarn install --frozen-lockfile yarn install --frozen-lockfile
...@@ -134,6 +134,7 @@ export const xAxis = { ...@@ -134,6 +134,7 @@ export const xAxis = {
export const yAxis = { export const yAxis = {
type: 'value', type: 'value',
name: '',
splitNumber: 4, splitNumber: 4,
axisLine: { axisLine: {
lineStyle: { lineStyle: {
...@@ -146,7 +147,7 @@ export const yAxis = { ...@@ -146,7 +147,7 @@ export const yAxis = {
axisLabel: { axisLabel: {
fontSize: 12, fontSize: 12,
color: '#666', color: '#666',
formatter: (v: number) => v.toString().slice(0, 5) formatter: (v: number) => Number.parseFloat(v.toPrecision(5))
}, },
splitLine: { splitLine: {
lineStyle: { lineStyle: {
...@@ -157,7 +158,6 @@ export const yAxis = { ...@@ -157,7 +158,6 @@ export const yAxis = {
export const series = { export const series = {
type: 'line', type: 'line',
showSymbol: false,
hoverAnimation: false, hoverAnimation: false,
animationDuration: 100, animationDuration: 100,
lineStyle: { lineStyle: {
......
...@@ -38,7 +38,7 @@ type I18nRes = { ...@@ -38,7 +38,7 @@ type I18nRes = {
}; };
}; };
export const appWithTranslation = function(this: NextI18Next, WrappedComponent: any) { export const appWithTranslation = function (this: NextI18Next, WrappedComponent: any) {
const WrappedComponentWithSSR = withSSR()(WrappedComponent); const WrappedComponentWithSSR = withSSR()(WrappedComponent);
const {config, i18n} = this; const {config, i18n} = this;
const consoleMessage = this.consoleMessage.bind(this); const consoleMessage = this.consoleMessage.bind(this);
...@@ -140,10 +140,9 @@ export const appWithTranslation = function(this: NextI18Next, WrappedComponent: ...@@ -140,10 +140,9 @@ export const appWithTranslation = function(this: NextI18Next, WrappedComponent:
} else { } else {
consoleMessage( consoleMessage(
'warn', 'warn',
`You have not declared a namespacesRequired array on your page-level component: ${ctx.Component `You have not declared a namespacesRequired array on your page-level component: ${
.displayName || ctx.Component.displayName || ctx.Component.name || 'Component'
ctx.Component.name || }. This will cause all namespaces to be sent down to the client, possibly negatively impacting the performance of your app. For more info, see: https://github.com/isaachinman/next-i18next#4-declaring-namespace-dependencies`
'Component'}. This will cause all namespaces to be sent down to the client, possibly negatively impacting the performance of your app. For more info, see: https://github.com/isaachinman/next-i18next#4-declaring-namespace-dependencies`
); );
} }
......
...@@ -5,9 +5,9 @@ import React from 'react'; ...@@ -5,9 +5,9 @@ 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.name || WrappedComponent.displayName || WrappedComponent.name || 'Component'
'Component'})`; })`;
render() { render() {
return <WrappedComponent {...this.props} nextI18NextInternals={config} />; return <WrappedComponent {...this.props} nextI18NextInternals={config} />;
......
...@@ -15,7 +15,7 @@ import pathMatch from 'path-match'; ...@@ -15,7 +15,7 @@ import pathMatch from 'path-match';
const route = pathMatch(); const route = pathMatch();
export default function(nexti18next: NextI18Next) { export default function (nexti18next: NextI18Next) {
const {config, i18n} = nexti18next; const {config, i18n} = nexti18next;
const {allLanguages, ignoreRoutes, localeSubpaths} = config; const {allLanguages, ignoreRoutes, localeSubpaths} = config;
......
...@@ -21,7 +21,7 @@ const logMessage = (messageType: MessageType, message: string) => { ...@@ -21,7 +21,7 @@ const logMessage = (messageType: MessageType, message: string) => {
} }
}; };
export const consoleMessage = function( export const consoleMessage = function (
this: NextI18Next | void, this: NextI18Next | void,
messageType: MessageType, messageType: MessageType,
message: string, message: string,
......
import BigNumber from 'bignumber.js';
import moment from 'moment'; import moment from 'moment';
export const formatTime = (value: number, language: string, formatter = 'L LTS') => export const formatTime = (value: number, language: string, formatter = 'L LTS') =>
moment(Math.floor(value), 'x') moment(Math.floor(value), 'x').locale(language).format(formatter);
.locale(language)
.format(formatter);
export const quantile = ( export const quantile = (values: number[], p: number) => {
values: number[][],
p: number,
valueOf: (value: number[], index: number, values: number[][]) => number
) => {
const n = values.length; const n = values.length;
if (!n) { if (!n) {
return NaN; return NaN;
} }
if ((p = +p) <= 0 || n < 2) { if ((p = +p) <= 0 || n < 2) {
return valueOf(values[0], 0, values); return values[0];
} }
if (p >= 1) { if (p >= 1) {
return valueOf(values[n - 1], n - 1, values); return values[n - 1];
} }
const i = (n - 1) * p; const i = new BigNumber(p).multipliedBy(n - 1);
const i0 = Math.floor(i); const i0 = i.integerValue().toNumber();
const value0 = valueOf(values[i0], i0, values); const value0 = new BigNumber(values[i0]);
const value1 = valueOf(values[i0 + 1], i0 + 1, values); const value1 = new BigNumber(values[i0 + 1]);
return value0 + (value1 - value0) * (i - i0); // return value0 + (value1 - value0) * (i - i0);
return value0.plus(value1.minus(value0).multipliedBy(i.minus(i0))).toNumber();
}; };
此差异已折叠。
...@@ -8,9 +8,19 @@ BUILD_DIR=$TOP_DIR/build ...@@ -8,9 +8,19 @@ BUILD_DIR=$TOP_DIR/build
mkdir -p $BUILD_DIR mkdir -p $BUILD_DIR
build_frontend_fake() {
mkdir -p "$BUILD_DIR/package/serverless"
}
build_frontend_from_source() { build_frontend_from_source() {
build_frontend_fake
cd $FRONTEND_DIR cd $FRONTEND_DIR
PUBLIC_PATH="/app" API_URL="/api" ./scripts/build.sh ./scripts/install.sh
./scripts/build.sh
# extract
tar zxf "$FRONTEND_DIR/output/serverless.tar.gz" -C "$BUILD_DIR/package/serverless"
} }
build_frontend() { build_frontend() {
...@@ -70,10 +80,6 @@ build_frontend() { ...@@ -70,10 +80,6 @@ build_frontend() {
tar zxf "$BUILD_DIR/$FILENAME" -C "$BUILD_DIR" tar zxf "$BUILD_DIR/$FILENAME" -C "$BUILD_DIR"
} }
build_frontend_fake() {
mkdir -p "$BUILD_DIR/package/serverless"
}
build_backend() { build_backend() {
cd $BUILD_DIR cd $BUILD_DIR
if [[ $WITH_PYTHON3 ]]; then if [[ $WITH_PYTHON3 ]]; then
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册