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