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

improvements of navbar, hd & hp (#962)

* chore: update dependencies

* feat: re-design navbar

* feat: high-dimensional page improvement

* feat: hyper-parameters page improvement
上级 f17540a9
...@@ -38,19 +38,19 @@ ...@@ -38,19 +38,19 @@
"version": "yarn format && git add -A" "version": "yarn format && git add -A"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "4.21.0", "@typescript-eslint/eslint-plugin": "4.24.0",
"@typescript-eslint/parser": "4.21.0", "@typescript-eslint/parser": "4.24.0",
"eslint": "7.23.0", "eslint": "7.26.0",
"eslint-config-prettier": "8.1.0", "eslint-config-prettier": "8.3.0",
"eslint-plugin-license-header": "0.2.0", "eslint-plugin-license-header": "0.2.0",
"eslint-plugin-prettier": "3.3.1", "eslint-plugin-prettier": "3.4.0",
"eslint-plugin-react": "7.23.1", "eslint-plugin-react": "7.23.2",
"eslint-plugin-react-hooks": "4.2.0", "eslint-plugin-react-hooks": "4.2.0",
"lerna": "4.0.0", "lerna": "4.0.0",
"lint-staged": "10.5.4", "lint-staged": "11.0.0",
"prettier": "2.2.1", "prettier": "2.3.0",
"rimraf": "3.0.2", "rimraf": "3.0.2",
"typescript": "4.2.3", "typescript": "4.2.4",
"yarn": "1.22.10" "yarn": "1.22.10"
}, },
"engines": { "engines": {
......
...@@ -35,17 +35,17 @@ ...@@ -35,17 +35,17 @@
], ],
"dependencies": { "dependencies": {
"@visualdl/server": "2.1.5", "@visualdl/server": "2.1.5",
"open": "8.0.5", "open": "8.0.9",
"ora": "5.4.0", "ora": "5.4.0",
"pm2": "4.5.6", "pm2": "4.5.6",
"yargs": "16.2.0" "yargs": "17.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "14.14.37", "@types/node": "15.3.0",
"@types/yargs": "16.0.1", "@types/yargs": "16.0.2",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"ts-node": "9.1.1", "ts-node": "9.1.1",
"typescript": "4.2.3" "typescript": "4.2.4"
}, },
"engines": { "engines": {
"node": ">=12", "node": ">=12",
......
...@@ -39,14 +39,14 @@ ...@@ -39,14 +39,14 @@
"@visualdl/wasm": "2.1.5", "@visualdl/wasm": "2.1.5",
"bignumber.js": "9.0.1", "bignumber.js": "9.0.1",
"classnames": "2.3.1", "classnames": "2.3.1",
"d3": "6.6.2", "d3": "6.7.0",
"d3-format": "2.0.0", "d3-format": "3.0.0",
"echarts": "4.9.0", "echarts": "4.9.0",
"echarts-gl": "1.1.2", "echarts-gl": "1.1.2",
"eventemitter3": "4.0.7", "eventemitter3": "4.0.7",
"file-saver": "2.0.5", "file-saver": "2.0.5",
"i18next": "20.2.1", "i18next": "20.2.4",
"i18next-browser-languagedetector": "6.1.0", "i18next-browser-languagedetector": "6.1.1",
"i18next-fetch-backend": "3.0.0", "i18next-fetch-backend": "3.0.0",
"jszip": "3.6.0", "jszip": "3.6.0",
"lodash": "4.17.21", "lodash": "4.17.21",
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
"moment": "2.29.1", "moment": "2.29.1",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"numeric": "1.2.6", "numeric": "1.2.6",
"polished": "4.1.1", "polished": "4.1.2",
"query-string": "7.0.0", "query-string": "7.0.0",
"react": "17.0.2", "react": "17.0.2",
"react-content-loader": "6.0.3", "react-content-loader": "6.0.3",
...@@ -62,27 +62,27 @@ ...@@ -62,27 +62,27 @@
"react-dnd-html5-backend": "14.0.0", "react-dnd-html5-backend": "14.0.0",
"react-dom": "17.0.2", "react-dom": "17.0.2",
"react-helmet": "6.1.0", "react-helmet": "6.1.0",
"react-i18next": "11.8.12", "react-i18next": "11.8.15",
"react-input-range": "1.3.0", "react-input-range": "1.3.0",
"react-is": "17.0.2", "react-is": "17.0.2",
"react-rangeslider": "2.2.0", "react-rangeslider": "2.2.0",
"react-redux": "7.2.3", "react-redux": "7.2.4",
"react-router-dom": "5.2.0", "react-router-dom": "5.2.0",
"react-spinners": "0.10.6", "react-spinners": "0.10.6",
"react-table": "7.6.3", "react-table": "7.7.0",
"react-table-sticky": "1.1.3", "react-table-sticky": "1.1.3",
"react-toastify": "7.0.3", "react-toastify": "7.0.4",
"redux": "4.0.5", "redux": "4.1.0",
"styled-components": "5.2.3", "styled-components": "5.3.0",
"swr": "0.5.5", "swr": "0.5.6",
"three": "0.127.0", "three": "0.128.0",
"tippy.js": "6.3.1", "tippy.js": "6.3.1",
"umap-js": "1.3.3" "umap-js": "1.3.3"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.13.14", "@babel/core": "7.14.3",
"@babel/plugin-proposal-class-properties": "7.13.0", "@babel/plugin-proposal-class-properties": "7.13.0",
"@babel/preset-env": "7.13.12", "@babel/preset-env": "7.14.2",
"@babel/preset-react": "7.13.13", "@babel/preset-react": "7.13.13",
"@baiducloud/sdk": "1.0.0-rc.28", "@baiducloud/sdk": "1.0.0-rc.28",
"@simbathesailor/use-what-changed": "2.0.0", "@simbathesailor/use-what-changed": "2.0.0",
...@@ -91,40 +91,40 @@ ...@@ -91,40 +91,40 @@
"@snowpack/plugin-optimize": "0.2.10", "@snowpack/plugin-optimize": "0.2.10",
"@snowpack/plugin-run-script": "2.3.0", "@snowpack/plugin-run-script": "2.3.0",
"@svgr/core": "5.5.0", "@svgr/core": "5.5.0",
"@testing-library/jest-dom": "5.11.10", "@testing-library/jest-dom": "5.12.0",
"@testing-library/react": "11.2.6", "@testing-library/react": "11.2.7",
"@types/d3": "6.3.0", "@types/d3": "6.5.0",
"@types/d3-format": "2.0.0", "@types/d3-format": "2.0.0",
"@types/echarts": "4.9.7", "@types/echarts": "4.9.7",
"@types/file-saver": "2.0.1", "@types/file-saver": "2.0.2",
"@types/jest": "26.0.22", "@types/jest": "26.0.23",
"@types/loadable__component": "5.13.3", "@types/loadable__component": "5.13.3",
"@types/lodash": "4.14.168", "@types/lodash": "4.14.169",
"@types/mime-types": "2.1.0", "@types/mime-types": "2.1.0",
"@types/nprogress": "0.2.0", "@types/nprogress": "0.2.0",
"@types/numeric": "1.2.1", "@types/numeric": "1.2.1",
"@types/react": "17.0.3", "@types/react": "17.0.6",
"@types/react-dom": "17.0.3", "@types/react-dom": "17.0.5",
"@types/react-helmet": "6.1.0", "@types/react-helmet": "6.1.1",
"@types/react-rangeslider": "2.2.3", "@types/react-rangeslider": "2.2.3",
"@types/react-redux": "7.1.16", "@types/react-redux": "7.1.16",
"@types/react-router-dom": "5.1.7", "@types/react-router-dom": "5.1.7",
"@types/react-table": "7.0.29", "@types/react-table": "7.7.0",
"@types/snowpack-env": "2.3.3", "@types/snowpack-env": "2.3.3",
"@types/styled-components": "5.1.9", "@types/styled-components": "5.1.9",
"@types/three": "0.127.0", "@types/three": "0.128.0",
"@visualdl/mock": "2.1.5", "@visualdl/mock": "2.1.5",
"babel-plugin-styled-components": "1.12.0", "babel-plugin-styled-components": "1.12.0",
"dotenv": "8.2.0", "dotenv": "9.0.2",
"enhanced-resolve": "5.7.0", "enhanced-resolve": "5.8.2",
"express": "4.17.1", "express": "4.17.1",
"fs-extra": "9.1.0", "fs-extra": "10.0.0",
"html-minifier": "4.0.0", "html-minifier": "4.0.0",
"http-proxy-middleware": "1.1.0", "http-proxy-middleware": "2.0.0",
"jest": "26.6.3", "jest": "26.6.3",
"snowpack": "2.18.5", "snowpack": "2.18.5",
"typescript": "4.2.3", "typescript": "4.2.4",
"yargs": "16.2.0" "yargs": "17.0.1"
}, },
"engines": { "engines": {
"node": ">=14", "node": ">=14",
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
"empty": "暂无数据", "empty": "暂无数据",
"error": "发生错误", "error": "发生错误",
"graph": "网络结构", "graph": "网络结构",
"high-dimensional": "高维数据映射", "high-dimensional": "数据降维",
"histogram": "直方图", "histogram": "直方图",
"hyper-parameter": "超参可视化", "hyper-parameter": "超参可视化",
"image": "图像", "image": "图像",
......
...@@ -212,7 +212,7 @@ const Audio: FunctionComponent<AudioProps & WithStyled> = ({ ...@@ -212,7 +212,7 @@ const Audio: FunctionComponent<AudioProps & WithStyled> = ({
}, []); }, []);
const startTimer = useCallback(() => { const startTimer = useCallback(() => {
tick(); tick();
timer.current = (window.setInterval(tick, 250) as unknown) as number; timer.current = window.setInterval(tick, 250) as unknown as number;
}, [tick]); }, [tick]);
const stopTimer = useCallback(() => { const stopTimer = useCallback(() => {
if (player.current) { if (player.current) {
......
...@@ -40,7 +40,12 @@ export type BarChartRef = { ...@@ -40,7 +40,12 @@ export type BarChartRef = {
const BarChart = React.forwardRef<BarChartRef, BarChartProps & WithStyled>( const BarChart = React.forwardRef<BarChartRef, BarChartProps & WithStyled>(
({options, categories, direction, data, title, loading, className, onInit}, ref) => { ({options, categories, direction, data, title, loading, className, onInit}, ref) => {
const {ref: echartRef, echart, wrapper, saveAsImage} = useECharts<HTMLDivElement>({ const {
ref: echartRef,
echart,
wrapper,
saveAsImage
} = useECharts<HTMLDivElement>({
loading: !!loading, loading: !!loading,
autoFit: true, autoFit: true,
onInit onInit
......
...@@ -114,10 +114,10 @@ const ChartPage = <T extends Item>({ ...@@ -114,10 +114,10 @@ const ChartPage = <T extends Item>({
} }
}, [items, searchValue]); }, [items, searchValue]);
const pageMatchedTags = useMemo(() => matchedTags?.slice((page - 1) * pageSize, page * pageSize) ?? [], [ const pageMatchedTags = useMemo(
matchedTags, () => matchedTags?.slice((page - 1) * pageSize, page * pageSize) ?? [],
page [matchedTags, page]
]); );
useEffect(() => { useEffect(() => {
setPage(1); setPage(1);
......
...@@ -83,7 +83,11 @@ const PRCurveChart: FunctionComponent<PRCurveChartProps> = ({type, runs, tag, ru ...@@ -83,7 +83,11 @@ const PRCurveChart: FunctionComponent<PRCurveChartProps> = ({type, runs, tag, ru
const echart = useRef<LineChartRef>(null); const echart = useRef<LineChartRef>(null);
const {data: dataset, error, loading} = useRunningRequest<PRCurveData[]>( const {
data: dataset,
error,
loading
} = useRunningRequest<PRCurveData[]>(
runs.map(run => `/${type}-curve/list?${queryString.stringify({run: run.label, tag})}`), runs.map(run => `/${type}-curve/list?${queryString.stringify({run: run.label, tag})}`),
!!running, !!running,
(...urls) => cycleFetcher(urls) (...urls) => cycleFetcher(urls)
......
...@@ -208,22 +208,19 @@ const Graph = React.forwardRef<GraphRef, GraphProps>( ...@@ -208,22 +208,19 @@ const Graph = React.forwardRef<GraphRef, GraphProps>(
}, [handler, dispatch]); }, [handler, dispatch]);
useEffect(() => (ready && dispatch('change-files', files)) || undefined, [dispatch, files, ready]); useEffect(() => (ready && dispatch('change-files', files)) || undefined, [dispatch, files, ready]);
useEffect(() => (ready && dispatch('toggle-attributes', showAttributes)) || undefined, [ useEffect(
dispatch, () => (ready && dispatch('toggle-attributes', showAttributes)) || undefined,
showAttributes, [dispatch, showAttributes, ready]
ready );
]); useEffect(
useEffect(() => (ready && dispatch('toggle-initializers', showInitializers)) || undefined, [ () => (ready && dispatch('toggle-initializers', showInitializers)) || undefined,
dispatch, [dispatch, showInitializers, ready]
showInitializers, );
ready
]);
useEffect(() => (ready && dispatch('toggle-names', showNames)) || undefined, [dispatch, showNames, ready]); useEffect(() => (ready && dispatch('toggle-names', showNames)) || undefined, [dispatch, showNames, ready]);
useEffect(() => (ready && dispatch('toggle-direction', horizontal)) || undefined, [ useEffect(
dispatch, () => (ready && dispatch('toggle-direction', horizontal)) || undefined,
horizontal, [dispatch, horizontal, ready]
ready );
]);
useEffect(() => (ready && dispatch('toggle-theme', theme)) || undefined, [dispatch, theme, ready]); useEffect(() => (ready && dispatch('toggle-theme', theme)) || undefined, [dispatch, theme, ready]);
......
...@@ -48,20 +48,31 @@ const Operations = styled.div` ...@@ -48,20 +48,31 @@ const Operations = styled.div`
} }
} }
& + a { & + a > span {
> span {
border-left: 1px solid var(--border-color); border-left: 1px solid var(--border-color);
} }
}
&:hover, &:hover {
&.active {
color: var(--primary-focused-color); color: var(--primary-focused-color);
} }
&:active { &:active {
color: var(--primary-active-color); color: var(--primary-active-color);
} }
&.active {
background-color: var(--primary-color);
color: var(--primary-text-color);
&:hover,
&:active {
color: var(--primary-text-color);
}
+ a > span {
border-left-color: transparent;
}
}
} }
`; `;
......
...@@ -120,9 +120,10 @@ const HighDimensionalChart = React.forwardRef<HighDimensionalChartRef, HighDimen ...@@ -120,9 +120,10 @@ const HighDimensionalChart = React.forwardRef<HighDimensionalChartRef, HighDimen
const [width, setWidth] = useState(0); const [width, setWidth] = useState(0);
const [height, setHeight] = useState(0); const [height, setHeight] = useState(0);
const [showLabelCloud, setShowLabelCloud] = useState(false); const [showLabelCloud, setShowLabelCloud] = useState(false);
const chartType = useMemo<ScatterChartProps['type']>(() => (showLabelCloud ? 'labels' : 'points'), [ const chartType = useMemo<ScatterChartProps['type']>(
showLabelCloud () => (showLabelCloud ? 'labels' : 'points'),
]); [showLabelCloud]
);
useLayoutEffect(() => { useLayoutEffect(() => {
const c = chartElement.current; const c = chartElement.current;
......
...@@ -91,13 +91,13 @@ const HistogramChart: FunctionComponent<HistogramChartProps> = ({run, tag, mode, ...@@ -91,13 +91,13 @@ const HistogramChart: FunctionComponent<HistogramChartProps> = ({run, tag, mode,
const echart = useRef<LineChartRef | StackChartRef>(null); const echart = useRef<LineChartRef | StackChartRef>(null);
const {data: dataset, error, loading} = useRunningRequest<HistogramData>( const {
`/histogram/list?${queryString.stringify({run: run.label, tag})}`, data: dataset,
!!running, error,
{ loading
} = useRunningRequest<HistogramData>(`/histogram/list?${queryString.stringify({run: run.label, tag})}`, !!running, {
refreshInterval: 60 * 1000 refreshInterval: 60 * 1000
} });
);
const [maximized, setMaximized] = useState<boolean>(false); const [maximized, setMaximized] = useState<boolean>(false);
......
...@@ -47,10 +47,10 @@ const IndicatorFilter: FunctionComponent<IndicatorFilterProps> = ({indicators, o ...@@ -47,10 +47,10 @@ const IndicatorFilter: FunctionComponent<IndicatorFilterProps> = ({indicators, o
); );
const [dataType, setDataType] = useState<IndicatorGroup>('hparams'); const [dataType, setDataType] = useState<IndicatorGroup>('hparams');
const indicatorsInGroup = useMemo(() => indicators.filter(indicator => indicator.group === dataType), [ const indicatorsInGroup = useMemo(
dataType, () => indicators.filter(indicator => indicator.group === dataType),
indicators [dataType, indicators]
]); );
const [result, setResult] = useState(indicators); const [result, setResult] = useState(indicators);
useEffect(() => setResult(indicators), [indicators]); useEffect(() => setResult(indicators), [indicators]);
......
...@@ -455,17 +455,16 @@ export default class ScatterChart extends EventEmitter<EventTypes> { ...@@ -455,17 +455,16 @@ export default class ScatterChart extends EventEmitter<EventTypes> {
setScaleMethod(scaleMethod: [ScaleMethod | null, ScaleMethod | null]) { setScaleMethod(scaleMethod: [ScaleMethod | null, ScaleMethod | null]) {
this.scaleMethod = scaleMethod; this.scaleMethod = scaleMethod;
this.brushedIndexes = null;
this.brush.clear(this.svg.select('.brush'));
this.draw(); this.draw();
this.colorizeDots(); this.colorizeDots();
this.scaleDots(); this.scaleDots();
this.drawSelectedDot();
} }
render(data: Point[], type: [IndicatorType, IndicatorType]) { render(data: Point[], type: [IndicatorType, IndicatorType]) {
this.hoveredIndex = null; this.hoveredIndex = null;
this.selectedIndex = null; this.selectedIndex = null;
this.brushedIndexes = [];
this.brush.clear(this.svg.select('.brush'));
this.data = data; this.data = data;
this.type = type; this.type = type;
......
...@@ -259,7 +259,11 @@ const TableViewTable: FunctionComponent<TableViewTableProps> = ({ ...@@ -259,7 +259,11 @@ const TableViewTable: FunctionComponent<TableViewTableProps> = ({
<DndProvider backend={HTML5Backend}> <DndProvider backend={HTML5Backend}>
<Table <Table
{...getTableProps({ {...getTableProps({
className: tableClassNames className: tableClassNames,
style: {
// sticky table doesn't need min-width in table style
minWidth: 'unset'
}
})} })}
ref={table} ref={table}
> >
......
...@@ -55,7 +55,12 @@ const LineChart = React.forwardRef<LineChartRef, LineChartProps & WithStyled>( ...@@ -55,7 +55,12 @@ const LineChart = React.forwardRef<LineChartRef, LineChartProps & WithStyled>(
({options, data, title, loading, zoom, className, onInit}, ref) => { ({options, data, title, loading, zoom, className, onInit}, ref) => {
const {i18n} = useTranslation(); const {i18n} = useTranslation();
const {ref: echartRef, echart, wrapper, saveAsImage} = useECharts<HTMLDivElement>({ const {
ref: echartRef,
echart,
wrapper,
saveAsImage
} = useECharts<HTMLDivElement>({
loading: !!loading, loading: !!loading,
zoom, zoom,
autoFit: true, autoFit: true,
......
...@@ -30,15 +30,15 @@ import {getApiToken} from '~/utils/fetch'; ...@@ -30,15 +30,15 @@ import {getApiToken} from '~/utils/fetch';
import logo from '~/assets/images/logo.svg'; import logo from '~/assets/images/logo.svg';
import queryString from 'query-string'; import queryString from 'query-string';
import styled from 'styled-components'; import styled from 'styled-components';
import useAvailableComponents from '~/hooks/useAvailableComponents';
import useClassNames from '~/hooks/useClassNames'; import useClassNames from '~/hooks/useClassNames';
import useComponents from '~/hooks/useComponents';
import {useTranslation} from 'react-i18next'; import {useTranslation} from 'react-i18next';
const BASE_URI: string = import.meta.env.SNOWPACK_PUBLIC_BASE_URI; const BASE_URI: string = import.meta.env.SNOWPACK_PUBLIC_BASE_URI;
const PUBLIC_PATH: string = import.meta.env.SNOWPACK_PUBLIC_PATH; const PUBLIC_PATH: string = import.meta.env.SNOWPACK_PUBLIC_PATH;
const API_TOKEN_KEY: string = import.meta.env.SNOWPACK_PUBLIC_API_TOKEN_KEY; const API_TOKEN_KEY: string = import.meta.env.SNOWPACK_PUBLIC_API_TOKEN_KEY;
const MAX_ITEM_COUNT_IN_NAVBAR = 5; const MAX_ITEM_COUNT_IN_NAVBAR = 6;
const flatten = <T extends {children?: T[]}>(routes: T[]) => { const flatten = <T extends {children?: T[]}>(routes: T[]) => {
const result: Omit<T, 'children'>[] = []; const result: Omit<T, 'children'>[] = [];
...@@ -274,11 +274,10 @@ const Navbar: FunctionComponent = () => { ...@@ -274,11 +274,10 @@ const Navbar: FunctionComponent = () => {
const currentPath = useMemo(() => pathname.replace(BASE_URI, ''), [pathname]); const currentPath = useMemo(() => pathname.replace(BASE_URI, ''), [pathname]);
const [components, inactiveComponents] = useAvailableComponents(); const [components] = useComponents();
const componentsInNavbar = useMemo(() => components.slice(0, MAX_ITEM_COUNT_IN_NAVBAR), [components]); const componentsInNavbar = useMemo(() => components.slice(0, MAX_ITEM_COUNT_IN_NAVBAR), [components]);
const flattenMoreComponents = useMemo(() => flatten(components.slice(MAX_ITEM_COUNT_IN_NAVBAR)), [components]); const flattenMoreComponents = useMemo(() => flatten(components.slice(MAX_ITEM_COUNT_IN_NAVBAR)), [components]);
const flattenInactiveComponents = useMemo(() => flatten(inactiveComponents), [inactiveComponents]);
const componentsInMoreMenu = useMemo( const componentsInMoreMenu = useMemo(
() => () =>
flattenMoreComponents.map(item => ({ flattenMoreComponents.map(item => ({
...@@ -287,15 +286,6 @@ const Navbar: FunctionComponent = () => { ...@@ -287,15 +286,6 @@ const Navbar: FunctionComponent = () => {
})), })),
[currentPath, flattenMoreComponents] [currentPath, flattenMoreComponents]
); );
const componentsInInactiveMenu = useMemo(
() =>
flattenInactiveComponents.map(item => ({
...item,
active: currentPath === item.path
})),
[currentPath, flattenInactiveComponents]
);
const [navItemsInNavbar, setNavItemsInNavbar] = useState<NavbarItemType[]>([]); const [navItemsInNavbar, setNavItemsInNavbar] = useState<NavbarItemType[]>([]);
useEffect(() => { useEffect(() => {
setNavItemsInNavbar(oldItems => setNavItemsInNavbar(oldItems =>
...@@ -368,11 +358,6 @@ const Navbar: FunctionComponent = () => { ...@@ -368,11 +358,6 @@ const Navbar: FunctionComponent = () => {
{t('common:more')} {t('common:more')}
</SubNav> </SubNav>
) : null} ) : null}
{componentsInInactiveMenu.length ? (
<SubNav menu={componentsInInactiveMenu} showDropdownIcon>
{t('common:inactive')}
</SubNav>
) : null}
</div> </div>
<div className="right"> <div className="right">
<Tippy <Tippy
......
...@@ -117,10 +117,10 @@ const RunAside: FunctionComponent<RunAsideProps> = ({ ...@@ -117,10 +117,10 @@ const RunAside: FunctionComponent<RunAsideProps> = ({
[onChangeRuns, runs] [onChangeRuns, runs]
); );
const filteredRuns = useMemo(() => (search ? runs?.filter(run => run.label.indexOf(search) >= 0) : runs) ?? [], [ const filteredRuns = useMemo(
runs, () => (search ? runs?.filter(run => run.label.indexOf(search) >= 0) : runs) ?? [],
search [runs, search]
]); );
const setSelectedRuns = useCallback( const setSelectedRuns = useCallback(
(run: Run, toggle) => { (run: Run, toggle) => {
......
...@@ -255,7 +255,11 @@ const SampleChart: FunctionComponent<SampleChartProps> = ({ ...@@ -255,7 +255,11 @@ const SampleChart: FunctionComponent<SampleChartProps> = ({
} }
}, []); }, []);
const {data: entityData, error: entityError, loading: entityLoading} = useRequest<BlobResponse>(src ?? null, { const {
data: entityData,
error: entityError,
loading: entityLoading
} = useRequest<BlobResponse>(src ?? null, {
dedupingInterval: 5 * 60 * 1000 dedupingInterval: 5 * 60 * 1000
}); });
......
...@@ -162,7 +162,11 @@ type TextProps = { ...@@ -162,7 +162,11 @@ type TextProps = {
const Text: FunctionComponent<TextProps> = ({run, tag, step, wallTime, index}) => { const Text: FunctionComponent<TextProps> = ({run, tag, step, wallTime, index}) => {
const {t} = useTranslation('sample'); const {t} = useTranslation('sample');
const {data: text, error, loading} = useRequest<string>(getEntityUrl('text', index, run, tag, wallTime), { const {
data: text,
error,
loading
} = useRequest<string>(getEntityUrl('text', index, run, tag, wallTime), {
dedupingInterval: 5 * 60 * 1000 dedupingInterval: 5 * 60 * 1000
}); });
......
...@@ -73,7 +73,11 @@ const ScalarChart: FunctionComponent<ScalarChartProps> = ({ ...@@ -73,7 +73,11 @@ const ScalarChart: FunctionComponent<ScalarChartProps> = ({
}) => { }) => {
const {t, i18n} = useTranslation(['scalar', 'common']); const {t, i18n} = useTranslation(['scalar', 'common']);
const {data: datasets, error, loading} = useRunningRequest<(ScalarDataset | null)[]>( const {
data: datasets,
error,
loading
} = useRunningRequest<(ScalarDataset | null)[]>(
runs.map(run => `/scalar/list?${queryString.stringify({run: run.label, tag})}`), runs.map(run => `/scalar/list?${queryString.stringify({run: run.label, tag})}`),
!!running, !!running,
(...urls) => cycleFetcher(urls) (...urls) => cycleFetcher(urls)
......
...@@ -211,10 +211,10 @@ const Select = <T extends unknown>({ ...@@ -211,10 +211,10 @@ const Select = <T extends unknown>({
const closeDropdown = useCallback(() => setIsOpened(false), []); const closeDropdown = useCallback(() => setIsOpened(false), []);
const [value, setValue] = useState(multiple ? (Array.isArray(propValue) ? propValue : []) : propValue); const [value, setValue] = useState(multiple ? (Array.isArray(propValue) ? propValue : []) : propValue);
useEffect(() => setValue(multiple ? (Array.isArray(propValue) ? propValue : []) : propValue), [ useEffect(
multiple, () => setValue(multiple ? (Array.isArray(propValue) ? propValue : []) : propValue),
propValue [multiple, propValue]
]); );
const isSelected = useMemo( const isSelected = useMemo(
() => !!(multiple ? (value as T[]) && (value as T[]).length !== 0 : value != (null as T)), () => !!(multiple ? (value as T[]) && (value as T[]).length !== 0 : value != (null as T)),
......
...@@ -342,7 +342,12 @@ const StackChart = React.forwardRef<StackChartRef, StackChartProps & WithStyled> ...@@ -342,7 +342,12 @@ const StackChart = React.forwardRef<StackChartRef, StackChartProps & WithStyled>
[onInit, throttled, mouseout] [onInit, throttled, mouseout]
); );
const {ref: echartRef, echart, wrapper, saveAsImage} = useECharts<HTMLDivElement>({ const {
ref: echartRef,
echart,
wrapper,
saveAsImage
} = useECharts<HTMLDivElement>({
loading: !!loading, loading: !!loading,
zoom, zoom,
autoFit: true, autoFit: true,
......
...@@ -15,16 +15,17 @@ ...@@ -15,16 +15,17 @@
*/ */
import routes, {Pages} from '~/routes'; import routes, {Pages} from '~/routes';
import {useCallback, useEffect, useMemo, useState} from 'react'; import {useEffect, useMemo, useState} from 'react';
import type {Route} from '~/routes'; import type {Route} from '~/routes';
import ee from '~/utils/event'; import ee from '~/utils/event';
import useRequest from '~/hooks/useRequest'; import useRequest from '~/hooks/useRequest';
import {useTranslation} from 'react-i18next'; import {useTranslation} from 'react-i18next';
interface RouteWithName extends Route { interface Component extends Route {
name: string; name: string;
children?: Pick<RouteWithName, 'id' | 'path' | 'component' | 'name'>[]; inactive?: boolean;
children?: Pick<Component, 'id' | 'path' | 'component' | 'name' | 'inactive'>[];
} }
export const navMap = { export const navMap = {
...@@ -43,11 +44,10 @@ export const navMap = { ...@@ -43,11 +44,10 @@ export const navMap = {
const useAvailableComponents = () => { const useAvailableComponents = () => {
const {t} = useTranslation('common'); const {t} = useTranslation('common');
const [components, setComponents] = useState<RouteWithName[]>([]); const [refreshInterval, setRefreshInterval] = useState(15 * 1000);
const [inactiveComponents, setInactiveComponents] = useState<RouteWithName[]>([]);
const {data, loading, error, mutate} = useRequest<(keyof typeof navMap)[]>('/components', { const {data, loading, error, mutate} = useRequest<(keyof typeof navMap)[]>('/components', {
refreshInterval: components.length ? 61 * 1000 : 15 * 1000, refreshInterval,
dedupingInterval: 14 * 1000, dedupingInterval: 14 * 1000,
errorRetryInterval: 15 * 1000, errorRetryInterval: 15 * 1000,
errorRetryCount: Number.POSITIVE_INFINITY, errorRetryCount: Number.POSITIVE_INFINITY,
...@@ -64,11 +64,12 @@ const useAvailableComponents = () => { ...@@ -64,11 +64,12 @@ const useAvailableComponents = () => {
}; };
}, [mutate]); }, [mutate]);
const filterRoutes = useCallback( const activeComponentIdArray: string[] = useMemo(() => data?.map(item => navMap[item]) ?? [], [data]);
(pages: Route[], filter: (page: Route) => boolean) => {
const components = useMemo(() => {
const iterator = (pages: Route[], parent?: Route) => { const iterator = (pages: Route[], parent?: Route) => {
const parentName = parent ? t(parent.id) + ' - ' : ''; const parentName = parent ? t(parent.id) + ' - ' : '';
return pages.reduce<RouteWithName[]>((m, page) => { return pages.reduce<Component[]>((m, page) => {
const name = parentName + t(page.id); const name = parentName + t(page.id);
if (page.children) { if (page.children) {
const children = iterator(page.children, page); const children = iterator(page.children, page);
...@@ -76,12 +77,13 @@ const useAvailableComponents = () => { ...@@ -76,12 +77,13 @@ const useAvailableComponents = () => {
m.push({ m.push({
...page, ...page,
name, name,
children: children as RouteWithName['children'] children: children as Component['children']
}); });
} }
} else if (page.visible !== false && filter(page)) { } else if (page.visible !== false) {
m.push({ m.push({
...page, ...page,
inactive: !activeComponentIdArray.includes(page.id),
name, name,
children: undefined children: undefined
}); });
...@@ -89,30 +91,12 @@ const useAvailableComponents = () => { ...@@ -89,30 +91,12 @@ const useAvailableComponents = () => {
return m; return m;
}, []); }, []);
}; };
return iterator(pages); return iterator(routes);
}, }, [activeComponentIdArray, t]);
[t]
);
const legalAvailableComponentIdArray: string[] = useMemo(() => data?.map(item => navMap[item]) ?? [], [data]);
const findAvailableComponents = useCallback(
(pages: Route[]) => filterRoutes(pages, page => legalAvailableComponentIdArray.includes(page.id)),
[filterRoutes, legalAvailableComponentIdArray]
);
const findInactiveComponents = useCallback(
(pages: Route[]) => filterRoutes(pages, page => !legalAvailableComponentIdArray.includes(page.id)),
[filterRoutes, legalAvailableComponentIdArray]
);
useEffect(() => { useEffect(() => setRefreshInterval((components.length ? 61 : 15) * 1000), [components]);
setComponents(findAvailableComponents(routes));
}, [findAvailableComponents]);
useEffect(() => {
setInactiveComponents(findInactiveComponents(routes));
}, [findInactiveComponents]);
return [components, inactiveComponents, loading, error] as const; return [components, loading, error] as const;
}; };
export default useAvailableComponents; export default useAvailableComponents;
...@@ -286,10 +286,10 @@ const Graph: FunctionComponent = () => { ...@@ -286,10 +286,10 @@ const Graph: FunctionComponent = () => {
nodeDocumentation nodeDocumentation
]); ]);
const uploader = useMemo(() => <Uploader onClickUpload={onClickFile} onDropFiles={setModelFile} />, [ const uploader = useMemo(
onClickFile, () => <Uploader onClickUpload={onClickFile} onDropFiles={setModelFile} />,
setModelFile [onClickFile, setModelFile]
]); );
return ( return (
<> <>
......
...@@ -130,9 +130,10 @@ const HighDimensional: FunctionComponent = () => { ...@@ -130,9 +130,10 @@ const HighDimensional: FunctionComponent = () => {
const chart = useRef<HighDimensionalChartRef>(null); const chart = useRef<HighDimensionalChartRef>(null);
const {data: list, loading: loadingList} = useRequest<EmbeddingInfo[]>('/embedding/list'); const {data: list, loading: loadingList} = useRequest<EmbeddingInfo[]>('/embedding/list');
const embeddingList = useMemo(() => list?.map(item => ({value: item.name, label: item.name, ...item})) ?? [], [ const embeddingList = useMemo(
list () => list?.map(item => ({value: item.name, label: item.name, ...item})) ?? [],
]); [list]
);
const [selectedEmbeddingName, setSelectedEmbeddingName] = useState<string>(); const [selectedEmbeddingName, setSelectedEmbeddingName] = useState<string>();
const selectedEmbedding = useMemo( const selectedEmbedding = useMemo(
() => embeddingList.find(embedding => embedding.value === selectedEmbeddingName), () => embeddingList.find(embedding => embedding.value === selectedEmbeddingName),
...@@ -314,10 +315,10 @@ const HighDimensional: FunctionComponent = () => { ...@@ -314,10 +315,10 @@ const HighDimensional: FunctionComponent = () => {
}, [result, showError]); }, [result, showError]);
const hasVector = useMemo(() => dim !== 0, [dim]); const hasVector = useMemo(() => dim !== 0, [dim]);
const dataPath = useMemo(() => (vectorFile ? vectorFile.name : selectedEmbedding?.path ?? ''), [ const dataPath = useMemo(
vectorFile, () => (vectorFile ? vectorFile.name : selectedEmbedding?.path ?? ''),
selectedEmbedding [vectorFile, selectedEmbedding]
]); );
const [perplexity, setPerplexity] = useState(5); const [perplexity, setPerplexity] = useState(5);
const [learningRate, setLearningRate] = useState(10); const [learningRate, setLearningRate] = useState(10);
......
...@@ -14,16 +14,28 @@ ...@@ -14,16 +14,28 @@
* limitations under the License. * limitations under the License.
*/ */
import React, {FunctionComponent, useEffect} from 'react'; import React, {FunctionComponent, useEffect, useMemo} from 'react';
import {headerHeight, primaryColor, rem, size} from '~/utils/style'; import {headerHeight, primaryColor, rem, size} from '~/utils/style';
import {useHistory, useLocation} from 'react-router-dom'; import {useHistory, useLocation} from 'react-router-dom';
import Error from '~/components/Error'; import Error from '~/components/Error';
import HashLoader from 'react-spinners/HashLoader'; import HashLoader from 'react-spinners/HashLoader';
import styled from 'styled-components'; import styled from 'styled-components';
import useAvailableComponents from '~/hooks/useAvailableComponents'; import useComponents from '~/hooks/useComponents';
import {useTranslation} from 'react-i18next'; import {useTranslation} from 'react-i18next';
const flatten = <T extends {children?: T[]}>(routes: T[]) => {
const result: Omit<T, 'children'>[] = [];
routes.forEach(route => {
if (route.children) {
result.push(...flatten(route.children));
} else {
result.push(route);
}
});
return result;
};
const CenterWrapper = styled.div` const CenterWrapper = styled.div`
${size(`calc(100vh - ${headerHeight})`, '100vw')} ${size(`calc(100vh - ${headerHeight})`, '100vw')}
overscroll-behavior: none; overscroll-behavior: none;
...@@ -40,24 +52,22 @@ const Loading = styled.div` ...@@ -40,24 +52,22 @@ const Loading = styled.div`
`; `;
const IndexPage: FunctionComponent = () => { const IndexPage: FunctionComponent = () => {
const [components, , loading] = useAvailableComponents(); const [components, loading] = useComponents();
const history = useHistory(); const history = useHistory();
const {t} = useTranslation('common'); const {t} = useTranslation('common');
const location = useLocation(); const location = useLocation();
const activeComponents = useMemo(() => flatten(components).filter(c => c.inactive !== true), [components]);
useEffect(() => { useEffect(() => {
if (components.length) { if (activeComponents.length) {
if (components[0].path) { history.replace(activeComponents[0].path + location.search);
history.replace(components[0].path + location.search);
} else if (components[0].children?.length && components[0].children[0].path) {
history.replace(components[0].children[0].path + location.search);
}
} else { } else {
// TODO: no component available, add a error tip // TODO: no component available, add a error tip
} }
}, [components, history, location.search]); }, [activeComponents, history, location.search]);
return ( return (
<CenterWrapper> <CenterWrapper>
......
...@@ -53,11 +53,6 @@ const routes: Route[] = [ ...@@ -53,11 +53,6 @@ const routes: Route[] = [
path: '/scalar', path: '/scalar',
component: React.lazy(() => import('~/pages/scalar')) component: React.lazy(() => import('~/pages/scalar'))
}, },
{
id: Pages.Histogram,
path: '/histogram',
component: React.lazy(() => import('~/pages/histogram'))
},
{ {
id: 'sample', id: 'sample',
children: [ children: [
...@@ -83,6 +78,16 @@ const routes: Route[] = [ ...@@ -83,6 +78,16 @@ const routes: Route[] = [
path: '/graph', path: '/graph',
component: React.lazy(() => import('~/pages/graph')) component: React.lazy(() => import('~/pages/graph'))
}, },
{
id: Pages.Histogram,
path: '/histogram',
component: React.lazy(() => import('~/pages/histogram'))
},
{
id: Pages.HyperParameter,
path: '/hyper-parameter',
component: React.lazy(() => import('~/pages/hyper-parameter'))
},
{ {
id: Pages.HighDimensional, id: Pages.HighDimensional,
path: '/high-dimensional', path: '/high-dimensional',
...@@ -97,11 +102,6 @@ const routes: Route[] = [ ...@@ -97,11 +102,6 @@ const routes: Route[] = [
id: Pages.ROCCurve, id: Pages.ROCCurve,
path: '/roc-curve', path: '/roc-curve',
component: React.lazy(() => import('~/pages/curves/roc')) component: React.lazy(() => import('~/pages/curves/roc'))
},
{
id: Pages.HyperParameter,
path: '/hyper-parameter',
component: React.lazy(() => import('~/pages/hyper-parameter'))
} }
]; ];
......
...@@ -34,8 +34,8 @@ ...@@ -34,8 +34,8 @@
"devDependencies": { "devDependencies": {
"@types/express": "4.17.11", "@types/express": "4.17.11",
"@types/mkdirp": "1.0.1", "@types/mkdirp": "1.0.1",
"@types/node": "14.14.37", "@types/node": "15.3.0",
"@types/node-fetch": "2.5.9", "@types/node-fetch": "2.5.10",
"@types/rimraf": "3.0.0", "@types/rimraf": "3.0.0",
"cpy-cli": "3.1.1", "cpy-cli": "3.1.1",
"get-port": "5.1.1", "get-port": "5.1.1",
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
"node-fetch": "2.6.1", "node-fetch": "2.6.1",
"rimraf": "3.0.2", "rimraf": "3.0.2",
"ts-node": "9.1.1", "ts-node": "9.1.1",
"typescript": "4.2.3" "typescript": "4.2.4"
}, },
"peerDependencies": { "peerDependencies": {
"express": "^4.17.1" "express": "^4.17.1"
......
...@@ -35,18 +35,18 @@ ...@@ -35,18 +35,18 @@
}, },
"dependencies": { "dependencies": {
"express": "4.17.1", "express": "4.17.1",
"faker": "5.5.2", "faker": "5.5.3",
"isomorphic-unfetch": "3.1.0", "isomorphic-unfetch": "3.1.0",
"mime-types": "2.1.30" "mime-types": "2.1.30"
}, },
"devDependencies": { "devDependencies": {
"@types/express": "4.17.11", "@types/express": "4.17.11",
"@types/faker": "5.5.0", "@types/faker": "5.5.5",
"@types/node": "14.14.37", "@types/node": "15.3.0",
"cpy-cli": "3.1.1", "cpy-cli": "3.1.1",
"rimraf": "3.0.2", "rimraf": "3.0.2",
"ts-node": "9.1.1", "ts-node": "9.1.1",
"typescript": "4.2.3" "typescript": "4.2.4"
}, },
"engines": { "engines": {
"node": ">=12", "node": ">=12",
......
...@@ -35,24 +35,24 @@ ...@@ -35,24 +35,24 @@
"dagre": "0.8.5", "dagre": "0.8.5",
"flatbuffers": "1.12.0", "flatbuffers": "1.12.0",
"long": "4.0.0", "long": "4.0.0",
"marked": "2.0.1", "marked": "2.0.3",
"netron": "PeterPanZH/netron", "netron": "PeterPanZH/netron",
"pako": "1.0.11" "pako": "1.0.11"
}, },
"devDependencies": { "devDependencies": {
"autoprefixer": "10.2.5", "autoprefixer": "10.2.5",
"copy-webpack-plugin": "8.1.1", "copy-webpack-plugin": "8.1.1",
"css-loader": "5.2.0", "css-loader": "5.2.4",
"html-webpack-plugin": "5.3.1", "html-webpack-plugin": "5.3.1",
"mini-css-extract-plugin": "1.4.0", "mini-css-extract-plugin": "1.6.0",
"postcss": "8.2.10", "postcss": "8.2.15",
"postcss-loader": "5.2.0", "postcss-loader": "5.3.0",
"rimraf": "3.0.2", "rimraf": "3.0.2",
"sass": "1.32.8", "sass": "1.32.13",
"sass-loader": "11.0.1", "sass-loader": "11.1.1",
"terser": "5.6.1", "terser": "5.7.0",
"webpack": "5.30.0", "webpack": "5.37.1",
"webpack-cli": "4.6.0" "webpack-cli": "4.7.0"
}, },
"engines": { "engines": {
"node": ">=12", "node": ">=12",
......
...@@ -38,21 +38,21 @@ ...@@ -38,21 +38,21 @@
], ],
"dependencies": { "dependencies": {
"@visualdl/core": "2.1.5", "@visualdl/core": "2.1.5",
"dotenv": "8.2.0", "dotenv": "9.0.2",
"enhanced-resolve": "5.7.0", "enhanced-resolve": "5.8.2",
"express": "4.17.1", "express": "4.17.1",
"http-proxy-middleware": "1.1.0", "http-proxy-middleware": "2.0.0",
"pm2": "4.5.6" "pm2": "4.5.6"
}, },
"devDependencies": { "devDependencies": {
"@types/enhanced-resolve": "3.0.6", "@types/enhanced-resolve": "3.0.6",
"@types/express": "4.17.11", "@types/express": "4.17.11",
"@types/node": "14.14.37", "@types/node": "15.3.0",
"@visualdl/mock": "2.1.5", "@visualdl/mock": "2.1.5",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"nodemon": "2.0.7", "nodemon": "2.0.7",
"ts-node": "9.1.1", "ts-node": "9.1.1",
"typescript": "4.2.3" "typescript": "4.2.4"
}, },
"optionalDependencies": { "optionalDependencies": {
"@visualdl/demo": "2.1.5" "@visualdl/demo": "2.1.5"
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册