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

Text (#916)

* chore: update dependencies

* build: fix build error

* chore: update dependencies

* feat: text sample

* fix: color mismatch in dark mode

* fix: align step in text page
上级 f883251f
......@@ -38,10 +38,10 @@
"version": "yarn format && git add -A"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "4.12.0",
"@typescript-eslint/parser": "4.12.0",
"eslint": "7.17.0",
"eslint-config-prettier": "7.1.0",
"@typescript-eslint/eslint-plugin": "4.14.0",
"@typescript-eslint/parser": "4.14.0",
"eslint": "7.18.0",
"eslint-config-prettier": "7.2.0",
"eslint-plugin-license-header": "0.2.0",
"eslint-plugin-prettier": "3.3.1",
"eslint-plugin-react": "7.22.0",
......
......@@ -36,12 +36,12 @@
"dependencies": {
"@visualdl/server": "2.1.4",
"open": "7.3.1",
"ora": "5.2.0",
"ora": "5.3.0",
"pm2": "4.5.1",
"yargs": "16.2.0"
},
"devDependencies": {
"@types/node": "14.14.20",
"@types/node": "14.14.22",
"@types/yargs": "15.0.12",
"cross-env": "7.0.3",
"ts-node": "9.1.1",
......
......@@ -38,7 +38,7 @@
"@visualdl/netron": "2.1.4",
"@visualdl/wasm": "2.1.4",
"bignumber.js": "9.0.1",
"d3": "6.3.1",
"d3": "6.4.0",
"d3-format": "2.0.0",
"echarts": "4.9.0",
"echarts-gl": "1.1.2",
......@@ -53,10 +53,10 @@
"moment": "2.29.1",
"nprogress": "0.2.0",
"numeric": "1.2.6",
"polished": "4.0.5",
"polished": "4.1.0",
"query-string": "6.13.8",
"react": "17.0.1",
"react-content-loader": "5.1.4",
"react-content-loader": "6.0.1",
"react-dom": "17.0.1",
"react-helmet": "6.1.0",
"react-i18next": "11.8.5",
......@@ -69,7 +69,7 @@
"react-toastify": "6.2.0",
"redux": "4.0.5",
"styled-components": "5.2.1",
"swr": "0.3.11",
"swr": "0.4.0",
"three": "0.124.0",
"tippy.js": "6.2.7",
"umap-js": "1.3.3"
......@@ -84,17 +84,17 @@
"@snowpack/app-scripts-react": "1.12.6",
"@snowpack/plugin-dotenv": "2.0.5",
"@snowpack/plugin-optimize": "0.2.10",
"@snowpack/plugin-run-script": "2.2.1",
"@snowpack/plugin-run-script": "2.3.0",
"@svgr/core": "5.5.0",
"@testing-library/jest-dom": "5.11.8",
"@testing-library/react": "11.2.2",
"@testing-library/jest-dom": "5.11.9",
"@testing-library/react": "11.2.3",
"@types/d3": "6.2.0",
"@types/d3-format": "2.0.0",
"@types/echarts": "4.9.3",
"@types/file-saver": "2.0.1",
"@types/jest": "26.0.20",
"@types/loadable__component": "5.13.1",
"@types/lodash": "4.14.167",
"@types/lodash": "4.14.168",
"@types/mime-types": "2.1.0",
"@types/nprogress": "0.2.0",
"@types/numeric": "1.2.1",
......@@ -102,16 +102,16 @@
"@types/react-dom": "17.0.0",
"@types/react-helmet": "6.1.0",
"@types/react-rangeslider": "2.2.3",
"@types/react-redux": "7.1.15",
"@types/react-redux": "7.1.16",
"@types/react-router-dom": "5.1.7",
"@types/snowpack-env": "2.3.3",
"@types/styled-components": "5.1.7",
"@visualdl/mock": "2.1.4",
"babel-plugin-styled-components": "1.12.0",
"dotenv": "8.2.0",
"enhanced-resolve": "5.4.1",
"enhanced-resolve": "5.7.0",
"express": "4.17.1",
"fs-extra": "9.0.1",
"fs-extra": "9.1.0",
"html-minifier": "4.0.0",
"http-proxy-middleware": "1.0.6",
"jest": "26.6.3",
......
......@@ -32,6 +32,7 @@
"stop": "Stop",
"stop-realtime-refresh": "Stop realtime refresh",
"stopped": "Stopped",
"text": "Text",
"theme": {
"auto": "Auto",
"dark": "Dark",
......
......@@ -13,8 +13,8 @@
"loading": "数据载入中,请稍等",
"next-page": "下一页",
"pr-curve": "PR曲线",
"roc-curve": "ROC曲线",
"previous-page": "上一页",
"roc-curve": "ROC曲线",
"run": "运行",
"running": "运行中",
"runs": "数据流",
......@@ -32,6 +32,7 @@
"stop": "停止",
"stop-realtime-refresh": "停止实时数据刷新",
"stopped": "已停止",
"text": "文本",
"theme": {
"auto": "自动",
"dark": "深色",
......
......@@ -37,7 +37,7 @@ module.exports = {
{
minifyHTML: false, // we will do it later in post-build
preloadModules: true,
target: ['chrome63', 'firefox67', 'safari11.1', 'edge79'] // browsers support es module
target: ['chrome79', 'firefox67', 'safari11.1', 'edge79'] // browsers support es module
}
],
[
......
......@@ -14,10 +14,9 @@
* limitations under the License.
*/
import React, {FunctionComponent, useCallback, useEffect, useState} from 'react';
import React, {FunctionComponent} from 'react';
import {WithStyled, borderRadius, headerHeight, math, rem, sameBorder, size, transitionProps} from '~/utils/style';
import ee from '~/utils/event';
import styled from 'styled-components';
const Div = styled.div<{maximized?: boolean; divWidth?: string; divHeight?: string}>`
......@@ -38,28 +37,12 @@ const Div = styled.div<{maximized?: boolean; divWidth?: string; divHeight?: stri
`;
type ChartProps = {
cid: symbol;
maximized?: boolean;
width?: string;
height?: string;
};
const Chart: FunctionComponent<ChartProps & WithStyled> = ({cid, width, height, className, children}) => {
const [maximized, setMaximized] = useState(false);
const toggleMaximize = useCallback(
(id: symbol, value: boolean) => {
if (id === cid) {
setMaximized(value);
}
},
[cid]
);
useEffect(() => {
ee.on('toggle-chart-size', toggleMaximize);
return () => {
ee.off('toggle-chart-size', toggleMaximize);
};
}, [toggleMaximize]);
const Chart: FunctionComponent<ChartProps & WithStyled> = ({maximized, width, height, className, children}) => {
return (
<Div
maximized={maximized}
......
......@@ -14,13 +14,12 @@
* limitations under the License.
*/
import {ChartCollapseTitle as ChartCollapseTitleLoader, Chart as ChartLoader} from '~/components/Loader/ChartPage';
import React, {FunctionComponent, PropsWithChildren, useCallback, useEffect, useMemo, useState} from 'react';
import {Trans, useTranslation} from 'react-i18next';
import {WithStyled, headerHeight, link, rem, transitionProps} from '~/utils/style';
import Chart from '~/components/Chart';
import ChartCollapse from '~/components/ChartCollapse';
import {ChartCollapseTitle as ChartCollapseTitleLoader} from '~/components/Loader/ChartPage';
import Pagination from '~/components/Pagination';
import SearchInput from '~/components/SearchInput';
import groupBy from 'lodash/groupBy';
......@@ -79,26 +78,23 @@ type Item = {
label: string;
};
export interface WithChart<T extends Item> {
(item: T & {cid: symbol}, index: number): React.ReactNode;
export interface RenderChart<T extends Item> {
(item: T, index: number): React.ReactNode;
}
type ChartPageProps<T extends Item> = {
items?: T[];
running?: boolean;
loading?: boolean | React.ReactNode;
chartSize?: {
width?: string;
height?: string;
};
withChart?: WithChart<T>;
loading?: boolean;
loader: React.ReactNode;
renderChart?: RenderChart<T>;
};
const ChartPage = <T extends Item>({
items,
loading,
chartSize,
withChart,
loader,
renderChart,
className
}: PropsWithChildren<ChartPageProps<T> & WithStyled>): ReturnType<FunctionComponent> => {
const {t} = useTranslation('common');
......@@ -145,33 +141,14 @@ const ChartPage = <T extends Item>({
const total = useMemo(() => Math.ceil(matchedTags.length / pageSize), [matchedTags]);
const withCharts = useCallback(
const renderCharts = useCallback(
(charts: T[], search?: boolean) => (
<Wrapper>
{loading ? (
Array.from({length: 2}).map((_, index) => (
<Chart
cid={Symbol()}
key={index}
width={chartSize?.width ?? rem(430)}
height={chartSize?.height ?? rem(337)}
>
{loading === true ? <ChartLoader /> : loading}
</Chart>
))
loader
) : charts.length ? (
charts.map((item, j) => {
const cid = Symbol(item.label);
return (
<Chart
cid={cid}
key={item.id || item.label}
width={chartSize?.width ?? rem(430)}
height={chartSize?.height ?? rem(337)}
>
{withChart?.({...item, cid}, j)}
</Chart>
);
return <React.Fragment key={item.id || item.label}>{renderChart?.(item, j)}</React.Fragment>;
})
) : (
<Empty height={rem(500)}>
......@@ -188,21 +165,21 @@ const ChartPage = <T extends Item>({
)}
</Wrapper>
),
[loading, t, chartSize?.width, chartSize?.height, withChart]
[loading, t, loader, renderChart]
);
const content = useMemo(() => {
if (loading) {
return Array.from({length: 3}).map((_, index) => (
<ChartCollapse key={index} title={<ChartCollapseTitleLoader />} opened={!index}>
{withCharts([])}
{renderCharts([])}
</ChartCollapse>
));
}
if (searchValue) {
return (
<ChartCollapse title={t('common:search-result')} total={matchedTags.length}>
{withCharts(pageMatchedTags, true)}
{renderCharts(pageMatchedTags, true)}
{pageMatchedTags.length ? <StyledPagination page={page} total={total} onChange={setPage} /> : null}
</ChartCollapse>
);
......@@ -215,7 +192,7 @@ const ChartPage = <T extends Item>({
total={groupedItem[1].length}
opened={i === 0}
>
{withCharts(groupedItem[1])}
{renderCharts(groupedItem[1])}
</ChartCollapse>
));
}
......@@ -228,7 +205,7 @@ const ChartPage = <T extends Item>({
</Trans>
</Empty>
);
}, [groupedItems, loading, matchedTags.length, page, pageMatchedTags, searchValue, t, total, withCharts]);
}, [groupedItems, loading, matchedTags.length, page, pageMatchedTags, searchValue, t, total, renderCharts]);
return (
<div className={className}>
......
......@@ -26,6 +26,7 @@ const Section = styled.section`
const Article = styled.article`
flex: auto;
min-width: 0;
margin: ${contentMargin};
min-height: ${contentHeight};
`;
......
......@@ -20,11 +20,12 @@ import React, {FunctionComponent, useCallback, useMemo, useRef, useState} from '
import {options as chartOptions, nearestPoint} from '~/resource/curves';
import {rem, size} from '~/utils/style';
import Chart from '~/components/Chart';
import {Chart as ChartLoader} from '~/components/Loader/ChartPage';
import ChartToolbox from '~/components/ChartToolbox';
import type {EChartOption} from 'echarts';
import TooltipTable from '~/components/TooltipTable';
import {cycleFetcher} from '~/utils/fetch';
import ee from '~/utils/event';
import {format} from 'd3-format';
import queryString from 'query-string';
import {renderToStaticMarkup} from 'react-dom/server';
......@@ -61,15 +62,23 @@ const Error = styled.div`
align-items: center;
`;
const chartSize = {
width: 430,
height: 337
};
const chartSizeInRem = {
width: rem(chartSize.width),
height: rem(chartSize.height)
};
type PRCurveChartProps = {
type: CurveType;
cid: symbol;
runs: Run[];
tag: string;
running?: boolean;
};
const PRCurveChart: FunctionComponent<PRCurveChartProps> = ({type, cid, runs, tag, running}) => {
const PRCurveChart: FunctionComponent<PRCurveChartProps> = ({type, runs, tag, running}) => {
const {t} = useTranslation(['curves', 'common']);
const echart = useRef<LineChartRef>(null);
......@@ -81,10 +90,6 @@ const PRCurveChart: FunctionComponent<PRCurveChartProps> = ({type, cid, runs, ta
);
const [maximized, setMaximized] = useState<boolean>(false);
const toggleMaximized = useCallback(() => {
ee.emit('toggle-chart-size', cid, !maximized);
setMaximized(m => !m);
}, [cid, maximized]);
const selectedData = useMemo<[number, number, number[][]][]>(
() =>
......@@ -202,32 +207,45 @@ const PRCurveChart: FunctionComponent<PRCurveChartProps> = ({type, cid, runs, ta
}
return (
<Wrapper>
<StyledLineChart ref={echart} title={tag} options={options} data={data} loading={loading} zoom />
<Toolbox
items={[
{
icon: 'maximize',
activeIcon: 'minimize',
tooltip: t('curves:maximize'),
activeTooltip: t('curves:minimize'),
toggle: true,
onClick: toggleMaximized
},
{
icon: 'restore-size',
tooltip: t('curves:restore'),
onClick: () => echart.current?.restore()
},
{
icon: 'download',
tooltip: t('curves:download-image'),
onClick: () => echart.current?.saveAsImage()
}
]}
/>
</Wrapper>
<Chart maximized={maximized} {...chartSizeInRem}>
<Wrapper>
<StyledLineChart ref={echart} title={tag} options={options} data={data} loading={loading} zoom />
<Toolbox
items={[
{
icon: 'maximize',
activeIcon: 'minimize',
tooltip: t('curves:maximize'),
activeTooltip: t('curves:minimize'),
toggle: true,
onClick: () => setMaximized(m => !m)
},
{
icon: 'restore-size',
tooltip: t('curves:restore'),
onClick: () => echart.current?.restore()
},
{
icon: 'download',
tooltip: t('curves:download-image'),
onClick: () => echart.current?.saveAsImage()
}
]}
/>
</Wrapper>
</Chart>
);
};
export default PRCurveChart;
export const Loader: FunctionComponent = () => (
<>
<Chart {...chartSizeInRem}>
<ChartLoader width={chartSize.width - 2} height={chartSize.height - 2} />
</Chart>
<Chart {...chartSizeInRem}>
<ChartLoader width={chartSize.width - 2} height={chartSize.height - 2} />
</Chart>
</>
);
......@@ -24,10 +24,11 @@ import React, {FunctionComponent, useCallback, useEffect, useMemo, useRef, useSt
import StackChart, {StackChartProps, StackChartRef} from '~/components/StackChart';
import {rem, size} from '~/utils/style';
import Chart from '~/components/Chart';
import {Chart as ChartLoader} from '~/components/Loader/ChartPage';
import ChartToolbox from '~/components/ChartToolbox';
import type {Run} from '~/types';
import {distance} from '~/utils';
import ee from '~/utils/event';
import {fetcher} from '~/utils/fetch';
import {format} from 'd3-format';
import minBy from 'lodash/minBy';
......@@ -70,15 +71,23 @@ const Error = styled.div`
align-items: center;
`;
const chartSize = {
width: 430,
height: 337
};
const chartSizeInRem = {
width: rem(chartSize.width),
height: rem(chartSize.height)
};
type HistogramChartProps = {
cid: symbol;
run: Run;
tag: string;
mode: Modes;
running?: boolean;
};
const HistogramChart: FunctionComponent<HistogramChartProps> = ({cid, run, tag, mode, running}) => {
const HistogramChart: FunctionComponent<HistogramChartProps> = ({run, tag, mode, running}) => {
const {t} = useTranslation(['histogram', 'common']);
const echart = useRef<LineChartRef | StackChartRef>(null);
......@@ -93,10 +102,6 @@ const HistogramChart: FunctionComponent<HistogramChartProps> = ({cid, run, tag,
);
const [maximized, setMaximized] = useState<boolean>(false);
const toggleMaximized = useCallback(() => {
ee.emit('toggle-chart-size', cid, !maximized);
setMaximized(m => !m);
}, [cid, maximized]);
const title = useMemo(() => `${tag} (${run.label})`, [tag, run.label]);
......@@ -278,27 +283,40 @@ const HistogramChart: FunctionComponent<HistogramChartProps> = ({cid, run, tag,
}
return (
<Wrapper>
{chart}
<Toolbox
items={[
{
icon: 'maximize',
activeIcon: 'minimize',
tooltip: t('histogram:maximize'),
activeTooltip: t('histogram:minimize'),
toggle: true,
onClick: toggleMaximized
},
{
icon: 'download',
tooltip: t('histogram:download-image'),
onClick: () => echart.current?.saveAsImage()
}
]}
/>
</Wrapper>
<Chart maximized={maximized} {...chartSizeInRem}>
<Wrapper>
{chart}
<Toolbox
items={[
{
icon: 'maximize',
activeIcon: 'minimize',
tooltip: t('histogram:maximize'),
activeTooltip: t('histogram:minimize'),
toggle: true,
onClick: () => setMaximized(m => !m)
},
{
icon: 'download',
tooltip: t('histogram:download-image'),
onClick: () => echart.current?.saveAsImage()
}
]}
/>
</Wrapper>
</Chart>
);
};
export default HistogramChart;
export const Loader: FunctionComponent = () => (
<>
<Chart {...chartSizeInRem}>
<ChartLoader width={chartSize.width - 2} height={chartSize.height - 2} />
</Chart>
<Chart {...chartSizeInRem}>
<ChartLoader width={chartSize.width - 2} height={chartSize.height - 2} />
</Chart>
</>
);
......@@ -18,9 +18,9 @@ import React, {FunctionComponent} from 'react';
import ContentLoader from './ContentLoader';
export const Chart: FunctionComponent = () => {
export const Chart: FunctionComponent<{width: number; height: number}> = ({width, height}) => {
return (
<ContentLoader viewBox="0 0 428 335">
<ContentLoader viewBox={`0 0 ${width} ${height}`}>
<rect x="20" y="20" rx="3" ry="3" width="200" height="16" />
<rect x="20" y="56" rx="3" ry="3" width="390" height="231" />
<rect x="20" y="301" rx="3" ry="3" width="16" height="16" />
......@@ -29,9 +29,9 @@ export const Chart: FunctionComponent = () => {
);
};
export const SampleChart: FunctionComponent<{height: number}> = ({height}) => {
export const SampleChart: FunctionComponent<{width: number; height: number}> = ({width, height}) => {
return (
<ContentLoader viewBox={`0 0 428 ${height}`}>
<ContentLoader viewBox={`0 0 ${width} ${height}`}>
<rect x="20" y="20" rx="3" ry="3" width="200" height="18" />
<rect x="333" y="26.5" rx="2.5" ry="2.5" width="17" height="5" />
<rect x="358" y="22" rx="3" ry="3" width="50" height="14" />
......@@ -48,6 +48,15 @@ export const SampleChart: FunctionComponent<{height: number}> = ({height}) => {
);
};
export const TextChart: FunctionComponent<{width: number}> = ({width}) => {
return (
<ContentLoader viewBox="0 0 1098 38" height={38}>
<rect x="8" y="6" rx="4" ry="4" width="64" height="26" />
<rect x="86" y="11" rx="3" ry="3" width={width} height="16" />
</ContentLoader>
);
};
export const ChartCollapseTitle: FunctionComponent = () => {
return (
<ContentLoader viewBox="0 0 200 18" width={200} height={18}>
......
......@@ -21,7 +21,7 @@ import type {IContentLoaderProps} from 'react-content-loader';
import {themes} from '~/utils/theme';
import useTheme from '~/hooks/useTheme';
const RunList: FunctionComponent<IContentLoaderProps> = ({children, ...props}) => {
const Loader: FunctionComponent<IContentLoaderProps> = ({children, ...props}) => {
const theme = useTheme();
return (
<ContentLoader
......@@ -34,4 +34,4 @@ const RunList: FunctionComponent<IContentLoaderProps> = ({children, ...props}) =
);
};
export default RunList;
export default Loader;
......@@ -18,7 +18,10 @@ import Audio, {AudioProps} from '~/components/Audio';
import React, {FunctionComponent, useCallback, useState} from 'react';
import SampleChart, {SampleChartBaseProps, SampleEntityProps} from '~/components/SamplePage/SampleChart';
import Chart from '~/components/Chart';
import {SampleChart as SampleChartLoader} from '~/components/Loader/ChartPage';
import {format} from 'd3-format';
import {rem} from '~/utils/style';
import styled from 'styled-components';
import {useTranslation} from 'react-i18next';
......@@ -32,6 +35,15 @@ const StyledAudio = styled(Audio)`
const cache = 5 * 60 * 1000;
const chartSize = {
width: 430,
height: 244
};
const chartSizeInRem = {
width: rem(chartSize.width),
height: rem(chartSize.height)
};
type AudioChartProps = {
audioContext?: AudioContext;
} & SampleChartBaseProps;
......@@ -47,7 +59,7 @@ const AudioChart: FunctionComponent<AudioChartProps> = ({audioContext, ...props}
[]
);
const content = useCallback(
const renderContent = useCallback(
(props: SampleEntityProps) => (
<StyledAudio audioContext={audioContext} {...props} onLoading={onLoading} onLoad={onLoad} />
),
......@@ -55,20 +67,33 @@ const AudioChart: FunctionComponent<AudioChartProps> = ({audioContext, ...props}
);
return (
<SampleChart
type="audio"
cache={cache}
footer={
<span>
{t('sample:sample-rate')}
{t('common:colon')}
{sampleRate}
</span>
}
content={content}
{...props}
/>
<Chart {...chartSizeInRem}>
<SampleChart
type="audio"
cache={cache}
footer={
<span>
{t('sample:sample-rate')}
{t('common:colon')}
{sampleRate}
</span>
}
renderContent={renderContent}
{...props}
/>
</Chart>
);
};
export default AudioChart;
export const Loader: FunctionComponent = () => (
<>
<Chart {...chartSizeInRem}>
<SampleChartLoader width={chartSize.width - 2} height={chartSize.height - 2} />
</Chart>
<Chart {...chartSizeInRem}>
<SampleChartLoader width={chartSize.width - 2} height={chartSize.height - 2} />
</Chart>
</>
);
......@@ -20,10 +20,12 @@ import SampleChart, {
SampleEntityProps,
SamplePreviewerProps
} from '~/components/SamplePage/SampleChart';
import {size, transitionProps} from '~/utils/style';
import {rem, size, transitionProps} from '~/utils/style';
import Chart from '~/components/Chart';
import Image from '~/components/Image';
import ImagePreviewer from '~/components/SamplePage/ImagePreviewer';
import {SampleChart as SampleChartLoader} from '~/components/Loader/ChartPage';
import styled from 'styled-components';
const StyledImage = styled(Image)<{brightness?: number; contrast?: number; fit?: boolean}>`
......@@ -36,6 +38,15 @@ const StyledImage = styled(Image)<{brightness?: number; contrast?: number; fit?:
const cache = 5 * 60 * 1000;
const chartSize = {
width: 430,
height: 406
};
const chartSizeInRem = {
width: rem(chartSize.width),
height: rem(chartSize.height)
};
type ImageChartProps = {
brightness?: number;
contrast?: number;
......@@ -43,14 +54,35 @@ type ImageChartProps = {
} & SampleChartBaseProps;
const ImageChart: FunctionComponent<ImageChartProps> = ({brightness, contrast, fit, ...props}) => {
const content = useCallback(
const renderContent = useCallback(
(props: SampleEntityProps) => <StyledImage {...props} brightness={brightness} contrast={contrast} fit={fit} />,
[brightness, contrast, fit]
);
const previewer = useCallback((props: SamplePreviewerProps) => <ImagePreviewer {...props} />, []);
const renderPreviewer = useCallback((props: SamplePreviewerProps) => <ImagePreviewer {...props} />, []);
return <SampleChart type="image" cache={cache} content={content} previewer={previewer} {...props} />;
return (
<Chart {...chartSizeInRem}>
<SampleChart
type="image"
cache={cache}
renderContent={renderContent}
renderPreviewer={renderPreviewer}
{...props}
/>
</Chart>
);
};
export default ImageChart;
export const Loader: FunctionComponent = () => (
<>
<Chart {...chartSizeInRem}>
<SampleChartLoader width={chartSize.width - 2} height={chartSize.height - 2} />
</Chart>
<Chart {...chartSizeInRem}>
<SampleChartLoader width={chartSize.width - 2} height={chartSize.height - 2} />
</Chart>
</>
);
......@@ -16,6 +16,7 @@
import React, {FunctionComponent, useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {ellipsis, em, primaryColor, rem, size, transitionProps} from '~/utils/style';
import useRequest, {useRunningRequest} from '~/hooks/useRequest';
import type {BlobResponse} from '~/utils/fetch';
import ChartToolbox from '~/components/ChartToolbox';
......@@ -29,8 +30,6 @@ import mime from 'mime-types';
import queryString from 'query-string';
import {saveFile} from '~/utils/saveFile';
import styled from 'styled-components';
import useRequest from '~/hooks/useRequest';
import {useRunningRequest} from '~/hooks/useRequest';
import {useTranslation} from 'react-i18next';
const Wrapper = styled.div`
......@@ -114,7 +113,7 @@ const FooterInfo = styled.div`
}
`;
type SampleData = {
export type SampleData = {
step: number;
wallTime: number;
};
......@@ -144,11 +143,11 @@ type SampleChartProps = {
cache: number;
step?: number;
footer?: JSX.Element;
content: (props: SampleEntityProps) => React.ReactNode;
previewer?: (props: SamplePreviewerProps) => React.ReactNode;
renderContent: (props: SampleEntityProps) => React.ReactNode;
renderPreviewer?: (props: SamplePreviewerProps) => React.ReactNode;
} & SampleChartBaseProps;
const getUrl = (type: string, index: number, run: string, tag: string, wallTime: number): string =>
export const getEntityUrl = (type: string, index: number, run: string, tag: string, wallTime: number): string =>
`/${type}/${type}?${queryString.stringify({index, ts: wallTime, run, tag})}`;
const SampleChart: FunctionComponent<SampleChartProps> = ({
......@@ -158,8 +157,8 @@ const SampleChart: FunctionComponent<SampleChartProps> = ({
type,
cache,
footer,
content,
previewer
renderContent,
renderPreviewer
}) => {
const {t, i18n} = useTranslation(['sample', 'common']);
......@@ -208,7 +207,7 @@ const SampleChart: FunctionComponent<SampleChartProps> = ({
if (!data) {
return;
}
const url = getUrl(type, step, run.label, tag, wallTime);
const url = getEntityUrl(type, step, run.label, tag, wallTime);
cached.current[step] = {
src: url,
timer: window.setTimeout(() => {
......@@ -278,7 +277,7 @@ const SampleChart: FunctionComponent<SampleChartProps> = ({
}
}, [src, entityData, entityError, entityLoading]);
const Content = useMemo(() => {
const content = useMemo<React.ReactNode>(() => {
// show loading when deferring
if (loading || !cached.current[step] || !viewed) {
return <GridLoader color={primaryColor} size="10px" />;
......@@ -290,13 +289,13 @@ const SampleChart: FunctionComponent<SampleChartProps> = ({
return <span>{t('common:empty')}</span>;
}
if (entityProps) {
return content(entityProps);
return renderContent(entityProps);
}
return null;
}, [viewed, loading, error, data, step, entityProps, t, content]);
}, [viewed, loading, error, data, step, entityProps, t, renderContent]);
const Previewer = useMemo<React.ReactNode>(() => {
if (!previewer) {
const previewer = useMemo<React.ReactNode>(() => {
if (!renderPreviewer) {
return null;
}
if (!preview) {
......@@ -305,7 +304,7 @@ const SampleChart: FunctionComponent<SampleChartProps> = ({
if (!entityProps) {
return null;
}
return previewer({
return renderPreviewer({
...entityProps,
loading: !cached.current[step] || entityProps.loading,
steps,
......@@ -314,7 +313,7 @@ const SampleChart: FunctionComponent<SampleChartProps> = ({
onChange: setStep,
onChangeComplete: cacheSrc
});
}, [previewer, entityProps, preview, steps, step, cacheSrc]);
}, [renderPreviewer, entityProps, preview, steps, step, cacheSrc]);
return (
<Wrapper ref={wrapperRef}>
......@@ -325,10 +324,10 @@ const SampleChart: FunctionComponent<SampleChartProps> = ({
<StepSlider value={step} steps={steps} onChange={setStep} onChangeComplete={cacheSrc}>
{formatTime(wallTime, i18n.language)}
</StepSlider>
<Container ref={container} preview={!!previewer && !!src} onClick={() => setPreview(true)}>
{Content}
<Container ref={container} preview={!!renderPreviewer && !!src} onClick={() => setPreview(true)}>
{content}
</Container>
{Previewer}
{previewer}
<Footer>
<ChartToolbox
items={[
......
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, {FunctionComponent, useCallback, useEffect, useState} from 'react';
import type {SampleChartBaseProps, SampleData} from './SampleChart';
import {borderRadius, ellipsis, em, rem, sameBorder, size, transitionProps} from '~/utils/style';
import useRequest, {useRunningRequest} from '~/hooks/useRequest';
import ContentLoader from '~/components/Loader/ContentLoader';
import Icon from '~/components/Icon';
import {TextChart as TextChartLoader} from '~/components/Loader/ChartPage';
import {fetcher} from '~/utils/fetch';
import {getEntityUrl} from './SampleChart';
import queryString from 'query-string';
import styled from 'styled-components';
import {useTranslation} from 'react-i18next';
const Wrapper = styled.div`
width: 100%;
`;
const Title = styled.h4<{color: string; opened?: boolean}>`
cursor: pointer;
background-color: var(--text-chart-title-background-color);
display: flex;
justify-content: space-between;
align-items: center;
height: ${rem(40)};
margin: 0;
padding: 0 ${rem(20)} 0 ${rem(12)};
border-radius: ${borderRadius};
font-weight: 400;
font-size: ${em(14)};
${transitionProps('background-color')}
.tag {
flex: auto;
font-weight: 700;
&::before {
content: '';
display: inline-block;
${size(rem(10), rem(3))}
margin-right: ${rem(8)};
border-radius: ${rem(1.5)};
vertical-align: middle;
background-color: var(--text-chart-title-indicator-color);
${transitionProps('background-color')}
}
}
.run {
flex: none;
color: var(--text-lighter-color);
${transitionProps('color')}
${ellipsis()}
max-width: 50%;
&::before {
content: '';
display: inline-block;
${size(rem(9), rem(9))}
margin-right: ${rem(8)};
border-radius: ${rem(4.5)};
vertical-align: middle;
background-color: ${props => props.color};
}
}
.steps {
flex: none;
color: var(--text-lighter-color);
margin-left: ${rem(12)};
}
.icon {
margin-left: ${rem(20)};
font-size: ${rem(10)};
color: var(--text-lighter-color);
transform: rotate(${props => (props.opened ? '180' : '0')}deg);
${transitionProps(['transform', 'color'])};
}
`;
const TextWrapper = styled.div`
height: ${rem(40)};
margin-top: ${rem(12)};
display: flex;
justify-content: flex-start;
align-items: center;
padding: 0;
${sameBorder(true)}
${transitionProps('border-color')}
`;
const TextGrid = styled.div`
margin-top: ${rem(12)};
display: grid;
grid-template-columns: fit-content(25%) auto;
grid-row-gap: ${rem(12)};
justify-items: stretch;
align-items: stretch;
${transitionProps('border-color')}
> span {
height: ${rem(40)};
line-height: 1.857142857;
padding: ${rem(7)} 0;
}
.step {
${sameBorder()}
border-right: none;
border-top-left-radius: ${borderRadius};
border-bottom-left-radius: ${borderRadius};
padding-left: ${rem(8)};
padding-right: ${rem(14)};
> span {
display: block;
width: 100%;
color: var(--text-light-color);
background-color: var(--text-chart-tag-background-color);
padding: 0 ${rem(8)};
border-radius: ${borderRadius};
${transitionProps(['background-color', 'color'])}
}
}
.text {
${sameBorder()}
border-left: none;
border-top-right-radius: ${borderRadius};
border-bottom-right-radius: ${borderRadius};
padding-right: ${rem(20)};
${ellipsis()}
> * {
vertical-align: middle;
}
}
`;
type TextProps = {
index: number;
run: string;
tag: string;
} & SampleData;
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), fetcher, {
dedupingInterval: 5 * 60 * 1000
});
return (
<>
<span className="step">
<span>
{t('sample:step')} {step}
</span>
</span>
<span className="text" title={text ?? ''}>
{loading ? (
<ContentLoader viewBox="0 0 640 16" height="16">
<rect x="0" y="0" rx="3" ry="3" width={((index + 1) * 250) % 640} height="16" />
</ContentLoader>
) : (
error ?? text
)}
</span>
</>
);
};
type TextChartProps = {
opened?: boolean;
} & SampleChartBaseProps;
const TextChart: FunctionComponent<TextChartProps> = ({run, tag, opened, running}) => {
const [isOpened, setIsOpened] = useState(opened ?? false);
useEffect(() => setIsOpened(opened ?? false), [opened]);
const toggleOpened = useCallback(() => setIsOpened(m => !m), []);
const {data, error, loading} = useRunningRequest<SampleData[]>(
`/text/list?${queryString.stringify({run: run.label, tag})}`,
!!running
);
return (
<Wrapper>
<Title color={run.colors[0]} opened={isOpened} onClick={toggleOpened}>
<span className="tag">{tag}</span>
<span className="run">{run.label}</span>
<span className="steps">{data?.length ?? 0}</span>
<Icon className="icon" type="chevron-down" />
</Title>
{isOpened ? (
loading ? (
<>
<TextWrapper>
<TextChartLoader width={270} />
</TextWrapper>
<TextWrapper>
<TextChartLoader width={640} />
</TextWrapper>
</>
) : error ? (
<TextWrapper>{error}</TextWrapper>
) : (
<TextGrid>
{data?.map((item, index) => (
<Text key={index} {...item} run={run.label} tag={tag} index={index} />
))}
</TextGrid>
)
) : null}
</Wrapper>
);
};
export default TextChart;
export const Loader: FunctionComponent = () => (
<>
<Wrapper>
<Title color=""></Title>
<TextWrapper>
<TextChartLoader width={270} />
</TextWrapper>
<TextWrapper>
<TextChartLoader width={640} />
</TextWrapper>
</Wrapper>
<Wrapper>
<Title color=""></Title>
</Wrapper>
</>
);
......@@ -30,12 +30,13 @@ import {
} from '~/resource/scalar';
import {rem, size} from '~/utils/style';
import Chart from '~/components/Chart';
import {Chart as ChartLoader} from '~/components/Loader/ChartPage';
import ChartToolbox from '~/components/ChartToolbox';
import type {EChartOption} from 'echarts';
import type {Run} from '~/types';
import TooltipTable from '~/components/TooltipTable';
import {cycleFetcher} from '~/utils/fetch';
import ee from '~/utils/event';
import {format} from 'd3-format';
import queryString from 'query-string';
import {renderToStaticMarkup} from 'react-dom/server';
......@@ -78,8 +79,16 @@ const Error = styled.div`
align-items: center;
`;
const chartSize = {
width: 430,
height: 337
};
const chartSizeInRem = {
width: rem(chartSize.width),
height: rem(chartSize.height)
};
type ScalarChartProps = {
cid: symbol;
runs: Run[];
tag: string;
smoothing: number;
......@@ -92,7 +101,6 @@ type ScalarChartProps = {
};
const ScalarChart: FunctionComponent<ScalarChartProps> = ({
cid,
runs,
tag,
smoothing,
......@@ -114,10 +122,6 @@ const ScalarChart: FunctionComponent<ScalarChartProps> = ({
);
const [maximized, setMaximized] = useState<boolean>(false);
const toggleMaximized = useCallback(() => {
ee.emit('toggle-chart-size', cid, !maximized);
setMaximized(m => !m);
}, [cid, maximized]);
const xAxisType = useMemo(() => (xAxis === XAxis.WallTime ? XAxisType.time : XAxisType.value), [xAxis]);
......@@ -243,7 +247,7 @@ const ScalarChart: FunctionComponent<ScalarChartProps> = ({
tooltip: t('scalar:maximize'),
activeTooltip: t('scalar:minimize'),
toggle: true,
onClick: toggleMaximized
onClick: () => setMaximized(m => !m)
},
{
icon: 'restore-size',
......@@ -275,7 +279,7 @@ const ScalarChart: FunctionComponent<ScalarChartProps> = ({
]
}
],
[downloadData, t, toggleMaximized, toggleYAxisType]
[downloadData, t, toggleYAxisType]
);
// display error only on first fetch
......@@ -284,11 +288,24 @@ const ScalarChart: FunctionComponent<ScalarChartProps> = ({
}
return (
<Wrapper>
<StyledLineChart ref={echart} title={tag} options={options} data={data} loading={loading} zoom />
<Toolbox items={toolbox} />
</Wrapper>
<Chart maximized={maximized} {...chartSizeInRem}>
<Wrapper>
<StyledLineChart ref={echart} title={tag} options={options} data={data} loading={loading} zoom />
<Toolbox items={toolbox} />
</Wrapper>
</Chart>
);
};
export default ScalarChart;
export const Loader: FunctionComponent = () => (
<>
<Chart {...chartSizeInRem}>
<ChartLoader width={chartSize.width - 2} height={chartSize.height - 2} />
</Chart>
<Chart {...chartSizeInRem}>
<ChartLoader width={chartSize.width - 2} height={chartSize.height - 2} />
</Chart>
</>
);
......@@ -26,6 +26,7 @@ export const navMap = {
histogram: Pages.Histogram,
image: Pages.Image,
audio: Pages.Audio,
text: Pages.Text,
graph: Pages.Graph,
embeddings: Pages.HighDimensional,
pr_curve: Pages.PRCurve,
......
......@@ -14,12 +14,12 @@
* limitations under the License.
*/
import ChartPage, {WithChart} from '~/components/ChartPage';
import ChartPage, {RenderChart} from '~/components/ChartPage';
import CurveChart, {Loader as ChartLoader} from '~/components/CurvesPage/CurveChart';
import React, {FunctionComponent, useCallback, useState} from 'react';
import Content from '~/components/Content';
import CurveAside from '~/components/CurvesPage/CurveAside';
import CurveChart from '~/components/CurvesPage/CurveChart';
import Error from '~/components/Error';
import type {Tag} from '~/resource/curves';
import Title from '~/components/Title';
......@@ -33,8 +33,8 @@ const PRCurve: FunctionComponent = () => {
const [tags, setTags] = useState<Tag[]>([]);
const withChart = useCallback<WithChart<Tag>>(
({label, runs, ...args}) => <CurveChart type="pr" runs={runs} tag={label} {...args} running={running} />,
const renderChart = useCallback<RenderChart<Tag>>(
({label, runs}) => <CurveChart type="pr" runs={runs} tag={label} running={running} />,
[running]
);
......@@ -54,7 +54,7 @@ const PRCurve: FunctionComponent = () => {
{!loading && !tags.length ? (
<Error />
) : (
<ChartPage items={tags} withChart={withChart} loading={loading} />
<ChartPage items={tags} renderChart={renderChart} loader={<ChartLoader />} loading={loading} />
)}
</Content>
</>
......
......@@ -14,12 +14,12 @@
* limitations under the License.
*/
import ChartPage, {WithChart} from '~/components/ChartPage';
import ChartPage, {RenderChart} from '~/components/ChartPage';
import CurveChart, {Loader as ChartLoader} from '~/components/CurvesPage/CurveChart';
import React, {FunctionComponent, useCallback, useState} from 'react';
import Content from '~/components/Content';
import CurveAside from '~/components/CurvesPage/CurveAside';
import CurveChart from '~/components/CurvesPage/CurveChart';
import Error from '~/components/Error';
import type {Tag} from '~/resource/curves';
import Title from '~/components/Title';
......@@ -33,8 +33,8 @@ const ROCCurve: FunctionComponent = () => {
const [tags, setTags] = useState<Tag[]>([]);
const withChart = useCallback<WithChart<Tag>>(
({label, runs, ...args}) => <CurveChart type="roc" runs={runs} tag={label} {...args} running={running} />,
const renderChart = useCallback<RenderChart<Tag>>(
({label, runs}) => <CurveChart type="roc" runs={runs} tag={label} running={running} />,
[running]
);
......@@ -54,7 +54,7 @@ const ROCCurve: FunctionComponent = () => {
{!loading && !tags.length ? (
<Error />
) : (
<ChartPage items={tags} withChart={withChart} loading={loading} />
<ChartPage items={tags} renderChart={renderChart} loader={<ChartLoader />} loading={loading} />
)}
</Content>
</>
......
......@@ -14,7 +14,8 @@
* limitations under the License.
*/
import ChartPage, {WithChart} from '~/components/ChartPage';
import ChartPage, {RenderChart} from '~/components/ChartPage';
import HistogramChart, {Loader as ChartLoader} from '~/components/HistogramPage/HistogramChart';
import {Modes, modes} from '~/resource/histogram';
import React, {FunctionComponent, useCallback, useMemo, useState} from 'react';
......@@ -22,7 +23,6 @@ import {AsideSection} from '~/components/Aside';
import Content from '~/components/Content';
import Error from '~/components/Error';
import Field from '~/components/Field';
import HistogramChart from '~/components/HistogramPage/HistogramChart';
import RadioButton from '~/components/RadioButton';
import RadioGroup from '~/components/RadioGroup';
import RunAside from '~/components/RunAside';
......@@ -66,8 +66,8 @@ const Histogram: FunctionComponent = () => {
[loading, mode, onChangeRuns, running, runs, selectedRuns, t]
);
const withChart = useCallback<WithChart<TagWithSingleRun>>(
({label, run, ...args}) => <HistogramChart run={run} tag={label} {...args} mode={mode} running={running} />,
const renderChart = useCallback<RenderChart<TagWithSingleRun>>(
({label, run}) => <HistogramChart run={run} tag={label} mode={mode} running={running} />,
[running, mode]
);
......@@ -78,7 +78,12 @@ const Histogram: FunctionComponent = () => {
{!loading && !runs.length ? (
<Error />
) : (
<ChartPage items={tagsWithSingleRun} withChart={withChart} loading={loading} />
<ChartPage
items={tagsWithSingleRun}
renderChart={renderChart}
loader={<ChartLoader />}
loading={loading}
/>
)}
</Content>
</>
......
......@@ -16,23 +16,17 @@
// cSpell:words ungrouped
import ChartPage, {WithChart} from '~/components/ChartPage';
import AudioChart, {Loader as ChartLoader} from '~/components/SamplePage/Audio';
import ChartPage, {RenderChart} from '~/components/ChartPage';
import React, {FunctionComponent, useCallback, useEffect, useMemo, useRef, useState} from 'react';
import AudioChart from '~/components/SamplePage/AudioChart';
import Content from '~/components/Content';
import Error from '~/components/Error';
import RunAside from '~/components/RunAside';
import {SampleChart as SampleChartLoader} from '~/components/Loader/ChartPage';
import Title from '~/components/Title';
import {rem} from '~/utils/style';
import useTagFilter from '~/hooks/useTagFilter';
import {useTranslation} from 'react-i18next';
const chartSize = {
height: rem(244)
};
const AudioSample: FunctionComponent = () => {
const {t} = useTranslation(['sample', 'common']);
......@@ -65,7 +59,7 @@ const AudioSample: FunctionComponent = () => {
[loading, onChangeRuns, running, runs, selectedRuns]
);
const withChart = useCallback<WithChart<typeof tagsWithSingleRun[number]>>(
const renderChart = useCallback<RenderChart<typeof tagsWithSingleRun[number]>>(
({run, label}) => <AudioChart audioContext={audioContext.current} run={run} tag={label} running={running} />,
[running]
);
......@@ -81,9 +75,9 @@ const AudioSample: FunctionComponent = () => {
) : (
<ChartPage
items={tagsWithSingleRun}
chartSize={chartSize}
withChart={withChart}
loading={loading && <SampleChartLoader height={242} />}
renderChart={renderChart}
loader={<ChartLoader />}
loading={loading}
/>
)}
</Content>
......
......@@ -16,7 +16,8 @@
// cSpell:words ungrouped
import ChartPage, {WithChart} from '~/components/ChartPage';
import ChartPage, {RenderChart} from '~/components/ChartPage';
import ImageChart, {Loader as ChartLoader} from '~/components/SamplePage/Image';
import React, {FunctionComponent, useCallback, useMemo, useState} from 'react';
import {AsideSection} from '~/components/Aside';
......@@ -24,19 +25,12 @@ import Checkbox from '~/components/Checkbox';
import Content from '~/components/Content';
import Error from '~/components/Error';
import Field from '~/components/Field';
import ImageChart from '~/components/SamplePage/ImageChart';
import RunAside from '~/components/RunAside';
import {SampleChart as SampleChartLoader} from '~/components/Loader/ChartPage';
import Slider from '~/components/Slider';
import Title from '~/components/Title';
import {rem} from '~/utils/style';
import useTagFilter from '~/hooks/useTagFilter';
import {useTranslation} from 'react-i18next';
const chartSize = {
height: rem(406)
};
const ImageSample: FunctionComponent = () => {
const {t} = useTranslation(['sample', 'common']);
......@@ -78,7 +72,7 @@ const ImageSample: FunctionComponent = () => {
[brightness, contrast, loading, onChangeRuns, running, runs, selectedRuns, showActualSize, t]
);
const withChart = useCallback<WithChart<typeof tagsWithSingleRun[number]>>(
const renderChart = useCallback<RenderChart<typeof tagsWithSingleRun[number]>>(
({run, label}) => (
<ImageChart
run={run}
......@@ -103,9 +97,9 @@ const ImageSample: FunctionComponent = () => {
) : (
<ChartPage
items={tagsWithSingleRun}
chartSize={chartSize}
withChart={withChart}
loading={loading && <SampleChartLoader height={404} />}
renderChart={renderChart}
loader={<ChartLoader />}
loading={loading}
/>
)}
</Content>
......
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// cSpell:words ungrouped
import ChartPage, {RenderChart} from '~/components/ChartPage';
import React, {FunctionComponent, useCallback, useMemo, useState} from 'react';
import TextChart, {Loader as ChartLoader} from '~/components/SamplePage/Text';
import Content from '~/components/Content';
import Error from '~/components/Error';
import RunAside from '~/components/RunAside';
import Title from '~/components/Title';
import useTagFilter from '~/hooks/useTagFilter';
import {useTranslation} from 'react-i18next';
const TextSample: FunctionComponent = () => {
const {t} = useTranslation(['sample', 'common']);
const [running, setRunning] = useState(true);
const {runs, tagsWithSingleRun, selectedRuns, onChangeRuns, loading} = useTagFilter('text', running);
const aside = useMemo(
() => (
<RunAside
runs={runs}
selectedRuns={selectedRuns}
onChangeRuns={onChangeRuns}
running={running}
onToggleRunning={setRunning}
loading={loading}
></RunAside>
),
[loading, onChangeRuns, running, runs, selectedRuns]
);
const withChart = useCallback<RenderChart<typeof tagsWithSingleRun[number]>>(
({run, label}, index) => <TextChart run={run} tag={label} opened={index === 0} running={running} />,
[running]
);
return (
<>
<Title>
{t('common:text')} - {t('common:sample')}
</Title>
<Content aside={aside}>
{!loading && !runs.length ? (
<Error />
) : (
<ChartPage
items={tagsWithSingleRun}
renderChart={withChart}
loader={<ChartLoader />}
loading={loading}
/>
)}
</Content>
</>
);
};
export default TextSample;
......@@ -14,8 +14,9 @@
* limitations under the License.
*/
import ChartPage, {WithChart} from '~/components/ChartPage';
import ChartPage, {RenderChart} from '~/components/ChartPage';
import React, {FunctionComponent, useCallback, useEffect, useMemo, useState} from 'react';
import ScalarChart, {Loader as ChartLoader} from '~/components/ScalarPage/ScalarChart';
import {SortingMethod, XAxis, parseSmoothing, sortingMethod as toolTipSortingValues} from '~/resource/scalar';
import {AsideSection} from '~/components/Aside';
......@@ -24,7 +25,6 @@ import Content from '~/components/Content';
import Error from '~/components/Error';
import Field from '~/components/Field';
import RunAside from '~/components/RunAside';
import ScalarChart from '~/components/ScalarPage/ScalarChart';
import Select from '~/components/Select';
import Slider from '~/components/Slider';
import type {Tag} from '~/types';
......@@ -143,12 +143,11 @@ const Scalar: FunctionComponent = () => {
]
);
const withChart = useCallback<WithChart<Tag>>(
({label, runs, ...args}) => (
const renderChart = useCallback<RenderChart<Tag>>(
({label, runs}) => (
<ScalarChart
runs={runs}
tag={label}
{...args}
smoothing={smoothing}
xAxis={xAxis}
sortingMethod={tooltipSorting}
......@@ -168,7 +167,7 @@ const Scalar: FunctionComponent = () => {
{!loading && !runs.length ? (
<Error />
) : (
<ChartPage items={tags} withChart={withChart} loading={loading} />
<ChartPage items={tags} renderChart={renderChart} loader={<ChartLoader />} loading={loading} />
)}
</Content>
</>
......
......@@ -21,6 +21,7 @@ export enum Pages {
Histogram = 'histogram',
Image = 'image',
Audio = 'audio',
Text = 'text',
Graph = 'graph',
HighDimensional = 'high-dimensional',
PRCurve = 'pr-curve',
......@@ -66,6 +67,11 @@ const routes: Route[] = [
id: Pages.Audio,
path: '/sample/audio',
component: React.lazy(() => import('~/pages/sample/audio'))
},
{
id: Pages.Text,
path: '/sample/text',
component: React.lazy(() => import('~/pages/sample/text'))
}
]
},
......
......@@ -23,6 +23,7 @@ const initState: RunsState = {
histogram: [],
image: [],
audio: [],
text: [],
'pr-curve': [],
'roc-curve': []
};
......
......@@ -25,6 +25,7 @@ export interface RunsState {
histogram: Runs;
image: Runs;
audio: Runs;
text: Runs;
'pr-curve': Runs;
'roc-curve': Runs;
}
......
......@@ -87,7 +87,11 @@ export const themes = {
graphUploaderBackgroundColor: '#f9f9f9',
graphUploaderActiveBackgroundColor: '#f2f6ff',
graphCopyrightColor: '#ddd',
graphCopyrightLogoFilter: 'opacity(25%)'
graphCopyrightLogoFilter: 'opacity(25%)',
textChartTitleBackgroundColor: '#f8f8f8',
textChartTitleIndicatorColor: '#000',
textChartTagBackgroundColor: '#f6f6f6'
},
dark: {
textColor: '#cfcfd1',
......@@ -131,7 +135,12 @@ export const themes = {
graphUploaderBackgroundColor: '#262629',
graphUploaderActiveBackgroundColor: '#303033',
graphCopyrightColor: '#565657',
graphCopyrightLogoFilter: 'invert(35%) sepia(5%) saturate(79%) hue-rotate(202deg) brightness(88%) contrast(86%)'
graphCopyrightLogoFilter:
'invert(35%) sepia(5%) saturate(79%) hue-rotate(202deg) brightness(88%) contrast(86%)',
textChartTitleBackgroundColor: '#2a2a2a',
textChartTitleIndicatorColor: '#fff',
textChartTagBackgroundColor: '#222'
}
} as const;
......
......@@ -32,10 +32,10 @@
"test": "echo \"Error: no test specified\" && exit 0"
},
"devDependencies": {
"@types/express": "4.17.9",
"@types/express": "4.17.11",
"@types/mkdirp": "1.0.1",
"@types/node": "14.14.20",
"@types/node-fetch": "2.5.7",
"@types/node": "14.14.22",
"@types/node-fetch": "2.5.8",
"@types/rimraf": "3.0.0",
"cpy-cli": "3.1.1",
"get-port": "5.1.1",
......
......@@ -14,4 +14,4 @@
* limitations under the License.
*/
export default ['embeddings', 'scalar', 'image', 'audio', 'graph', 'histogram', 'pr_curve', 'roc_curve'];
export default ['embeddings', 'scalar', 'image', 'audio', 'text', 'graph', 'histogram', 'pr_curve', 'roc_curve'];
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export default [
{
wallTime: 1512549785061.623,
step: 60
},
{
wallTime: 1512886109672.786,
step: 60
},
{
wallTime: 1512886124266.915,
step: 210
},
{
wallTime: 1512886138898.628,
step: 330
},
{
wallTime: 1512886139883.663,
step: 340
},
{
wallTime: 1512886147195.567,
step: 410
},
{
wallTime: 1512886156478.56,
step: 500
},
{
wallTime: 1512886187827.93,
step: 810
},
{
wallTime: 1512886200386.198,
step: 950
},
{
wallTime: 1512886204224.405,
step: 990
}
];
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// cSpell:disable
export default {
runs: ['train', 'test'],
tags: [
[
'input_reshape/input/text/7',
'input_reshape/input/text/4',
'input_reshape/input/text/5',
'hahaha/input/text/2',
'hahaha/input/text/3',
'hahaha/input/text/0',
'ohehe/input/text/1',
'😼/input/text/8',
'😼/input/text/9'
],
[
'input_reshape/input/text/6',
'input_reshape/input/text/7',
'input_reshape/input/text/4',
'input_reshape/input/text/5',
'hahaha/input/text/2',
'hahaha/input/text/3',
'oheihei/input/text/0',
'oheihei/input/text/1',
'😼/input/text/8',
'😼/input/text/9'
]
]
};
/**
* Copyright 2020 Baidu Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {Request, Response} from 'express';
const texts = [
'不要以为抹消过去,重新来过,即可发生什么改变',
'这只是谁也不会伤害到的,温柔的谎言。虽然听上去不时闪现着希望,实际上却是迂回地饱含着绝望的说法。可能做不到 这件事本身说话人自己也了然于心,而向众人留有回旋的余地。',
'自称理解了能教他人什么的都太狂妄了 自以为理解了是罪与恶 虽然如此 我们不得不自欺欺人地活下去',
'自己的过去会被当做笑话或者捏他的形式,被他人随随便便的共有化。最终只会被他和她们当做方便好用的交流素材, 快乐的使用着',
'怎么办?没怎么办。只想就这件事随便说说而已。就好比,在电视里看到战争和贫困的场景,只能一边说着“真是可怜啊 ”“真是不得了啊”“这是我们无能为力的事情啊”,而同时我们在舒适的屋子里吃着好吃的晚饭的事情也没有改变。 我们无法在此之后着手做些什么,到最后不过只能想到“要对目前为止自己的幸福心怀感激”这种程度的事',
'世上没有像一个模子刻出来样的恶人哦 平时大家都是善人 至少大家都是普通人 但是 一到紧要关头 就会突然变成恶人 所以很 可怕 因为不能大意 人不可轻信',
'人类要是遇到真心害怕的事 完全不会在意别人 就算牺牲周围的人也要获救 只要暴露出这份丑陋的嘴脸 就再也无法好好相处了  不能逃避只是强身的想法 错的并不会总是自己 社会上 人世间 身边 总会有人做错 自己可以改变它 这只是顺应了这个垃圾一 般的冷酷且残酷的世界 承认自己的失败并顺从的行为 只是用漂亮话装饰起来 连自己都要欺骗罢了'
];
export default async (req: Request, res: Response) => {
const index = (+req.query.index ?? 0) % texts.length;
res.setHeader('Content-Type', 'text/plain');
return texts[index];
};
......@@ -40,9 +40,9 @@
"mime-types": "2.1.28"
},
"devDependencies": {
"@types/express": "4.17.9",
"@types/express": "4.17.11",
"@types/faker": "5.1.5",
"@types/node": "14.14.20",
"@types/node": "14.14.22",
"cpy-cli": "3.1.1",
"rimraf": "3.0.2",
"ts-node": "9.1.1",
......
......@@ -40,19 +40,19 @@
"pako": "1.0.11"
},
"devDependencies": {
"autoprefixer": "10.2.0",
"autoprefixer": "10.2.3",
"copy-webpack-plugin": "7.0.0",
"css-loader": "5.0.1",
"html-webpack-plugin": "4.5.1",
"mini-css-extract-plugin": "1.3.3",
"postcss": "8.2.2",
"postcss-loader": "4.1.0",
"mini-css-extract-plugin": "1.3.4",
"postcss": "8.2.4",
"postcss-loader": "4.2.0",
"rimraf": "3.0.2",
"sass": "1.32.2",
"sass-loader": "10.1.0",
"sass": "1.32.5",
"sass-loader": "10.1.1",
"terser": "5.5.1",
"webpack": "5.11.1",
"webpack-cli": "4.3.1"
"webpack": "5.17.0",
"webpack-cli": "4.4.0"
},
"engines": {
"node": ">=12",
......
......@@ -39,15 +39,15 @@
"dependencies": {
"@visualdl/core": "2.1.4",
"dotenv": "8.2.0",
"enhanced-resolve": "5.4.1",
"enhanced-resolve": "5.7.0",
"express": "4.17.1",
"http-proxy-middleware": "1.0.6",
"pm2": "4.5.1"
},
"devDependencies": {
"@types/enhanced-resolve": "3.0.6",
"@types/express": "4.17.9",
"@types/node": "14.14.20",
"@types/express": "4.17.11",
"@types/node": "14.14.22",
"@visualdl/mock": "2.1.4",
"cross-env": "7.0.3",
"nodemon": "2.0.7",
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册