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