diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index dda56103eb29e74b530d1dabdd4962d1a26675ec..b5ea44af8d9fb837f43261417cdd64da3c8c43a9 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -21,10 +21,9 @@ repos:
hooks:
- id: fe
name: lint-staged
- entry: cd frontend && lint-staged
+ entry: ./frontend/scripts/lint-staged.sh
language: node
files: ^frontend/
- pass_filenames: false
description: lint frontend code by lint-staged
- repo: meta
hooks:
diff --git a/frontend/lerna.json b/frontend/lerna.json
index ff15a09aa08fe75e1523189985107ec8de260337..16b71fcb2e712001b400b57fc8c8f3fdc36e2330 100644
--- a/frontend/lerna.json
+++ b/frontend/lerna.json
@@ -2,7 +2,7 @@
"packages": [
"packages/*"
],
- "version": "2.1.0-1",
+ "version": "2.1.1",
"npmClient": "yarn",
"useWorkspaces": true,
"command": {
diff --git a/frontend/packages/cli/package.json b/frontend/packages/cli/package.json
index cb62d9b8324e78170169ba4a65674b585a1eb775..ac4c57ff6888602e22eb1930d4fec3528fb57ece 100644
--- a/frontend/packages/cli/package.json
+++ b/frontend/packages/cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@visualdl/cli",
- "version": "2.1.0-1",
+ "version": "2.1.1",
"description": "A platform to visualize the deep learning process and result.",
"keywords": [
"visualdl",
@@ -34,7 +34,7 @@
"dist"
],
"dependencies": {
- "@visualdl/server": "2.1.0-1",
+ "@visualdl/server": "2.1.1",
"open": "7.3.0",
"ora": "5.1.0",
"pm2": "4.5.1",
diff --git a/frontend/packages/core/package.json b/frontend/packages/core/package.json
index 68e3e882fd997f96f78a4e9567869d13b97378f6..903ceb2984fe05809aa2e34414eb8ca1f33be4a1 100644
--- a/frontend/packages/core/package.json
+++ b/frontend/packages/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@visualdl/core",
- "version": "2.1.0-1",
+ "version": "2.1.1",
"description": "A platform to visualize the deep learning process and result.",
"keywords": [
"visualdl",
@@ -35,8 +35,8 @@
],
"dependencies": {
"@tippyjs/react": "4.2.0",
- "@visualdl/netron": "2.1.0-1",
- "@visualdl/wasm": "2.1.0-1",
+ "@visualdl/netron": "2.1.1",
+ "@visualdl/wasm": "2.1.1",
"bignumber.js": "9.0.1",
"d3": "6.3.1",
"d3-format": "2.0.0",
@@ -105,7 +105,7 @@
"@types/react-router-dom": "5.1.6",
"@types/snowpack-env": "2.3.3",
"@types/styled-components": "5.1.7",
- "@visualdl/mock": "2.1.0-1",
+ "@visualdl/mock": "2.1.1",
"babel-plugin-styled-components": "1.12.0",
"dotenv": "8.2.0",
"enhanced-resolve": "5.4.1",
diff --git a/frontend/packages/core/public/icons/chevron-left.svg b/frontend/packages/core/public/icons/chevron-left.svg
new file mode 100644
index 0000000000000000000000000000000000000000..eb69902007d84dbe2e7df709e0f7ae5595f2204a
--- /dev/null
+++ b/frontend/packages/core/public/icons/chevron-left.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/packages/core/public/icons/chevron-right.svg b/frontend/packages/core/public/icons/chevron-right.svg
new file mode 100644
index 0000000000000000000000000000000000000000..387397f478365db76a4681d80f10758fb7fe7ee0
--- /dev/null
+++ b/frontend/packages/core/public/icons/chevron-right.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/packages/core/public/locales/en/scalar.json b/frontend/packages/core/public/locales/en/scalar.json
index dd4036835f3b6b3cf0ae80f39ba02ce6e2295e2e..7f805017a7831e09608d8a716a07df3ca1b3de63 100644
--- a/frontend/packages/core/public/locales/en/scalar.json
+++ b/frontend/packages/core/public/locales/en/scalar.json
@@ -1,5 +1,6 @@
{
"download-data": "Download data",
+ "download-data-format": "In {{format}}",
"download-image": "Download image",
"ignore-outliers": "Ignore outliers in chart scaling",
"max": "Max.",
diff --git a/frontend/packages/core/public/locales/zh/scalar.json b/frontend/packages/core/public/locales/zh/scalar.json
index 5ce8ca80db5dcaf7d1e1b247211fea7860f54b4f..5416340e834650cce153f94bd084b40bb5098a05 100644
--- a/frontend/packages/core/public/locales/zh/scalar.json
+++ b/frontend/packages/core/public/locales/zh/scalar.json
@@ -1,5 +1,6 @@
{
"download-data": "下载数据",
+ "download-data-format": "{{format}} 格式",
"download-image": "下载图片",
"ignore-outliers": "图表缩放时忽略极端值",
"max": "最大值",
diff --git a/frontend/packages/core/src/components/ChartToolbox.tsx b/frontend/packages/core/src/components/ChartToolbox.tsx
index 064be38b27894e674073de347085ed375a638c4e..b9e07539aae4d7f9e525114b9ab4f22fb0e11f15 100644
--- a/frontend/packages/core/src/components/ChartToolbox.tsx
+++ b/frontend/packages/core/src/components/ChartToolbox.tsx
@@ -48,7 +48,7 @@ const ToolboxItem = styled.a<{active?: boolean}>`
}
`;
-const ChartToolboxMenu = styled.div`
+const ChartToolboxMenuWrapper = styled.div`
background-color: var(--background-color);
${transitionProps('background-color')};
@@ -65,9 +65,16 @@ const ChartToolboxMenu = styled.div`
}
`;
+const ChartToolboxMenuIcon = styled(Icon)`
+ vertical-align: middle;
+ font-size: 78%;
+ margin-left: 0.6em;
+`;
+
interface ChartToolboxItemChild {
label: string;
onClick?: () => unknown;
+ children?: ChartToolboxItemChild[];
}
type BaseChartToolboxItem = {
@@ -169,17 +176,45 @@ const ToggleChartToolbox: FunctionComponent = ({
);
};
+const ChartToolboxMenu: FunctionComponent = ({label, onClick, children}) => {
+ return children ? (
+
+ {children.map((item, index) => (
+
+ ))}
+
+ }
+ placement="right-start"
+ animation="shift-away-subtle"
+ interactive
+ hideOnClick={false}
+ arrow={false}
+ role="menu"
+ theme="menu"
+ offset={[0, 0]}
+ >
+
+ {label}
+
+
+ ) : (
+
+ onClick?.()}>{label}
+
+ );
+};
+
const MenuChartToolbox: FunctionComponent = ({icon, menuList}) => {
return (
+
{menuList.map((item, index) => (
- item.onClick?.()}>
- {item.label}
-
+
))}
-
+
}
placement="right-start"
animation="shift-away-subtle"
diff --git a/frontend/packages/core/src/components/ScalarPage/ScalarChart.tsx b/frontend/packages/core/src/components/ScalarPage/ScalarChart.tsx
index b1bf41d2d0ac94d2c2cdb2a106bfffa13516a71d..a6ca90b52ab5657f363cb11486ce88135deb5e91 100644
--- a/frontend/packages/core/src/components/ScalarPage/ScalarChart.tsx
+++ b/frontend/packages/core/src/components/ScalarPage/ScalarChart.tsx
@@ -45,6 +45,12 @@ import {useRunningRequest} from '~/hooks/useRequest';
import {useTranslation} from 'react-i18next';
import useWebAssembly from '~/hooks/useWebAssembly';
+const DownloadDataTypes = {
+ csv: 'csv',
+ tsv: 'tsv'
+ // excel: 'xlsx'
+} as const;
+
const labelFormatter = format('.8');
const Wrapper = styled.div`
@@ -211,6 +217,24 @@ const ScalarChart: FunctionComponent = ({
[formatter, ranges, xAxisType, yAxisType]
);
+ const downloadData = useCallback(
+ (type: keyof typeof DownloadDataTypes) => {
+ saveFile(
+ runs.map(
+ run =>
+ `/scalar/data?${queryString.stringify({
+ run: run.label,
+ tag,
+ type
+ })}`
+ ),
+ runs.map(run => `visualdl-scalar-${run.label}-${tag}.${DownloadDataTypes[type]}`),
+ `visualdl-scalar-${tag}.zip`
+ );
+ },
+ [runs, tag]
+ );
+
const toolbox = useMemo(
() => [
{
@@ -241,17 +265,17 @@ const ScalarChart: FunctionComponent = ({
},
{
label: t('scalar:download-data'),
- onClick: () =>
- saveFile(
- runs.map(run => `/scalar/data?${queryString.stringify({run: run.label, tag})}`),
- runs.map(run => `visualdl-scalar-${run.label}-${tag}.tsv`),
- `visualdl-scalar-${tag}.zip`
- )
+ children: Object.keys(DownloadDataTypes)
+ .sort((a, b) => a.localeCompare(b))
+ .map(format => ({
+ label: t('scalar:download-data-format', {format}),
+ onClick: () => downloadData(format as keyof typeof DownloadDataTypes)
+ }))
}
]
}
],
- [runs, t, tag, toggleMaximized, toggleYAxisType]
+ [downloadData, t, toggleMaximized, toggleYAxisType]
);
// display error only on first fetch
diff --git a/frontend/packages/demo/package.json b/frontend/packages/demo/package.json
index f022d0911848ae9cb770232e633124e8880d5d6c..a83452672c1a151896aa28315def87d17faa0d4f 100644
--- a/frontend/packages/demo/package.json
+++ b/frontend/packages/demo/package.json
@@ -1,6 +1,6 @@
{
"name": "@visualdl/demo",
- "version": "2.1.0-1",
+ "version": "2.1.1",
"description": "A platform to visualize the deep learning process and result.",
"keywords": [
"visualdl",
diff --git a/frontend/packages/mock/data/scalar/data.ts b/frontend/packages/mock/data/scalar/data.ts
index 6d6ed37e5f1b014613632a153545a848938e3745..f384b2fb7db7f4cd8375ce29302ace12ef9f2823 100644
--- a/frontend/packages/mock/data/scalar/data.ts
+++ b/frontend/packages/mock/data/scalar/data.ts
@@ -17,7 +17,14 @@
import {Request, Response} from 'express';
export default (req: Request, res: Response) => {
- const {run, tag} = req.query;
- res.setHeader('Content-Type', 'text/tab-separated-values');
- return `scalar\n${run}\n${tag}`;
+ const {run, tag, type} = req.query;
+ switch (type) {
+ case 'tsv':
+ res.setHeader('Content-Type', 'text/tab-separated-values');
+ break;
+ case 'csv':
+ res.setHeader('Content-Type', 'text/comma-separated-values');
+ break;
+ }
+ return `scalar\n${run}\n${tag}\n${type}`;
};
diff --git a/frontend/packages/mock/package.json b/frontend/packages/mock/package.json
index a2c501c8dd92d67fd968864869b7abe9d0443b57..3d376f95da91355e6c9d16af496d50885514c28f 100644
--- a/frontend/packages/mock/package.json
+++ b/frontend/packages/mock/package.json
@@ -1,6 +1,6 @@
{
"name": "@visualdl/mock",
- "version": "2.1.0-1",
+ "version": "2.1.1",
"description": "A platform to visualize the deep learning process and result.",
"keywords": [
"visualdl",
diff --git a/frontend/packages/netron/package.json b/frontend/packages/netron/package.json
index d22bedec13ceb91e667cb9551a11379a14f53d4c..8476cae601d821b0e1f55f788d4ef379db0ae715 100644
--- a/frontend/packages/netron/package.json
+++ b/frontend/packages/netron/package.json
@@ -1,6 +1,6 @@
{
"name": "@visualdl/netron",
- "version": "2.1.0-1",
+ "version": "2.1.1",
"description": "A platform to visualize the deep learning process and result.",
"keywords": [
"visualdl",
diff --git a/frontend/packages/server/package.json b/frontend/packages/server/package.json
index b21e78c3b64fca4bb7296cdae2344169a2c672b9..e86839043b72b7ffcd3715021756bce6c33060e1 100644
--- a/frontend/packages/server/package.json
+++ b/frontend/packages/server/package.json
@@ -1,6 +1,6 @@
{
"name": "@visualdl/server",
- "version": "2.1.0-1",
+ "version": "2.1.1",
"description": "A platform to visualize the deep learning process and result.",
"keywords": [
"visualdl",
@@ -36,7 +36,7 @@
"ecosystem.config.d.ts"
],
"dependencies": {
- "@visualdl/core": "2.1.0-1",
+ "@visualdl/core": "2.1.1",
"dotenv": "8.2.0",
"enhanced-resolve": "5.4.1",
"express": "4.17.1",
@@ -47,14 +47,14 @@
"@types/enhanced-resolve": "3.0.6",
"@types/express": "4.17.9",
"@types/node": "14.14.16",
- "@visualdl/mock": "2.1.0-1",
+ "@visualdl/mock": "2.1.1",
"cross-env": "7.0.3",
"nodemon": "2.0.6",
"ts-node": "9.1.1",
"typescript": "4.0.5"
},
"optionalDependencies": {
- "@visualdl/demo": "2.1.0-1"
+ "@visualdl/demo": "2.1.1"
},
"engines": {
"node": ">=12",
diff --git a/frontend/packages/wasm/package.json b/frontend/packages/wasm/package.json
index 4f9c2c08adbd7f0726841323bbcbe47467f0af4d..c5617d679241fc59c7fe4cd5d00687a2869aa46c 100644
--- a/frontend/packages/wasm/package.json
+++ b/frontend/packages/wasm/package.json
@@ -1,6 +1,6 @@
{
"name": "@visualdl/wasm",
- "version": "2.1.0-1",
+ "version": "2.1.1",
"title": "VisualDL",
"description": "A platform to visualize the deep learning process and result.",
"keywords": [
diff --git a/frontend/scripts/lint-staged.sh b/frontend/scripts/lint-staged.sh
new file mode 100755
index 0000000000000000000000000000000000000000..92a0cc3168883bd46705673f7325144354dcf90c
--- /dev/null
+++ b/frontend/scripts/lint-staged.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -e
+
+echo $0
+
+SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+cd $SCRIPT_DIR/..
+
+./node_modules/.bin/lint-staged --no-stash