diff --git a/frontend/README.md b/frontend/README.md index ba5c5ddf1d4e37bcd893266580a43f12d5282a8d..57b2b08eea9020a7794df6806cc5eee3ac09db23 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -18,7 +18,7 @@ English | [简体中文](https://github.com/PaddlePaddle/VisualDL/blob/develop/frontend/README_cn.md) -**🚧UNDER CONSTRUCTION🚧** +**🚧UNDER DEVELOPMENT🚧** **🚧SOME FEATURE MAY NOT WORK PROPERLY🚧** diff --git a/frontend/README_cn.md b/frontend/README_cn.md index c00d016e3724a1d86d80c5b28678fc991a0d41e6..e666d76ebbdd22aef349d5d4dc9e51062788756b 100644 --- a/frontend/README_cn.md +++ b/frontend/README_cn.md @@ -18,7 +18,7 @@ [English](https://github.com/PaddlePaddle/VisualDL/blob/develop/frontend/README.md) | 简体中文 -**🚧仍在建设中🚧** +**🚧开发中🚧** **🚧某些功能可能不能正常工作🚧** diff --git a/frontend/babel.config.js b/frontend/babel.config.js index dd6805651c353c41b5a3d627cb28c0222a9df0a1..1c11280dec8f7e9e72d7943711e40662ba052c4c 100644 --- a/frontend/babel.config.js +++ b/frontend/babel.config.js @@ -9,6 +9,7 @@ module.exports = { preprocess: false } ], - ...(process.env.NODE_ENV !== 'production' ? ['babel-plugin-typescript-to-proptypes'] : []) + ['emotion'], + ...(process.env.NODE_ENV !== 'production' ? ['typescript-to-proptypes'] : []) ] }; diff --git a/frontend/components/ChartPage.tsx b/frontend/components/ChartPage.tsx index 3ddc0313c4fbe72535063d416a214a6ddc39b592..c41ac4465e69604069fb000766dca74efb2e28a7 100644 --- a/frontend/components/ChartPage.tsx +++ b/frontend/components/ChartPage.tsx @@ -1,6 +1,7 @@ import React, {FunctionComponent, useState} from 'react'; import styled from 'styled-components'; -import {WithStyled, rem} from '~/utils/style'; +import {WithStyled, rem, primaryColor} from '~/utils/style'; +import BarLoader from 'react-spinners/BarLoader'; import Chart from '~/components/Chart'; import Pagination from '~/components/Pagination'; @@ -18,14 +19,23 @@ const Wrapper = styled.div` } `; +const Loading = styled.div` + display: flex; + justify-content: center; + align-items: center; + min-height: ${rem(200)}; + padding: ${rem(40)} 0; +`; + // TODO: add types // eslint-disable-next-line type ChartPageProps = { items?: T[]; + loading?: boolean; withChart?: (item: T) => React.ReactNode; }; -const ChartPage: FunctionComponent = ({items, withChart, className}) => { +const ChartPage: FunctionComponent = ({items, loading, withChart, className}) => { const pageSize = 12; const total = Math.ceil((items?.length ?? 0) / pageSize); @@ -35,11 +45,17 @@ const ChartPage: FunctionComponent = ({items, withC return (
- - {pageItems.map((item, index) => ( - {withChart?.(item)} - ))} - + {loading ? ( + + + + ) : ( + + {pageItems.map((item, index) => ( + {withChart?.(item)} + ))} + + )}
); diff --git a/frontend/components/Checkbox.tsx b/frontend/components/Checkbox.tsx index d2f85fe9eee279ab284b0edc346facbdf6088e5e..65986fb67ae285510675e01fa541d3c5f12c5fef 100644 --- a/frontend/components/Checkbox.tsx +++ b/frontend/components/Checkbox.tsx @@ -81,6 +81,7 @@ type CheckboxProps = { value?: boolean; onChange?: (value: boolean) => unknown; size?: 'small'; + title?: string; disabled?: boolean; }; @@ -90,6 +91,7 @@ const Checkbox: FunctionComponent = ({ size, disabled, className, + title, onChange }) => { const [checked, setChecked] = useState(!!value); @@ -103,7 +105,7 @@ const Checkbox: FunctionComponent = ({ }; return ( - + {children} diff --git a/frontend/components/Content.tsx b/frontend/components/Content.tsx index 08db0170f7ab07b74bd19bb369b96b46f6119673..ff9d5829cbc10509117923bd340f3dbe7aa3a823 100644 --- a/frontend/components/Content.tsx +++ b/frontend/components/Content.tsx @@ -1,6 +1,7 @@ import React, {FunctionComponent} from 'react'; import styled from 'styled-components'; -import {rem, math, headerHeight, asideWidth, backgroundColor} from '~/utils/style'; +import HashLoader from 'react-spinners/HashLoader'; +import {rem, math, headerHeight, asideWidth, backgroundColor, primaryColor} from '~/utils/style'; const margin = rem(20); const padding = rem(20); @@ -30,14 +31,36 @@ const Aside = styled.aside` overflow-y: auto; `; +const Loading = styled.div` + width: 100vw; + height: 100vh; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(255, 255, 255, 0.8); + display: flex; + justify-content: center; + align-items: center; + overscroll-behavior: none; + cursor: progress; +`; + type ContentProps = { aside?: React.ReactNode; + loading?: boolean; }; -const Content: FunctionComponent = ({children, aside}) => ( +const Content: FunctionComponent = ({children, aside, loading}) => (
{children}
{aside && } + {loading && ( + + + + )}
); diff --git a/frontend/components/Image.tsx b/frontend/components/Image.tsx index 46ee287f723a61d613b27f65ddb5ef7284028f94..48a300cd87b0204bbcfc63f5ef7d30ca8c32ad52 100644 --- a/frontend/components/Image.tsx +++ b/frontend/components/Image.tsx @@ -1,44 +1,31 @@ -import React, {FunctionComponent, useEffect, useState, useRef} from 'react'; -import fetch from 'isomorphic-unfetch'; -import {useTranslation} from '~/utils/i18n'; +import React, {FunctionComponent, useLayoutEffect, useState} from 'react'; +import useSWR from 'swr'; +import {primaryColor} from '~/utils/style'; +import {blobFetcher} from '~/utils/fetch'; +import GridLoader from 'react-spinners/GridLoader'; type ImageProps = { src?: string; }; const Image: FunctionComponent = ({src}) => { - const {t} = useTranslation('common'); - const [url, setUrl] = useState(''); - const [loading, setLoading] = useState(false); - const controller = useRef(null as AbortController | null); + const {data} = useSWR(src ?? null, blobFetcher); - useEffect(() => { - if (process.browser) { + // use useLayoutEffect hook to prevent image render after url revoked + useLayoutEffect(() => { + if (process.browser && data) { let objectUrl: string | null = null; - (async () => { - setLoading(true); - controller.current?.abort(); - controller.current = new AbortController(); - try { - const result = await fetch(src ?? '', {signal: controller.current.signal}); - const blob = await result.blob(); - objectUrl = URL.createObjectURL(blob); - setUrl(objectUrl); - } catch { - // ignore abort error - } finally { - setLoading(false); - } - })(); + objectUrl = URL.createObjectURL(data); + setUrl(objectUrl); return () => { objectUrl && URL.revokeObjectURL(objectUrl); }; } - }, [src]); + }, [data]); - return loading ? {t('loading')} : ; + return !data ? : ; }; export default Image; diff --git a/frontend/components/LineChart.tsx b/frontend/components/LineChart.tsx index 3f4436dc0c4cffedaab7b341162a76b7dbcc8fd7..5e16b3905f9835803350001d59d8eab520565689 100644 --- a/frontend/components/LineChart.tsx +++ b/frontend/components/LineChart.tsx @@ -1,8 +1,10 @@ import React, {FunctionComponent, useEffect, useCallback} from 'react'; import {EChartOption} from 'echarts'; import {WithStyled} from '~/utils/style'; +import {useTranslation} from '~/utils/i18n'; import useECharts from '~/hooks/useECharts'; import * as chart from '~/utils/chart'; +import {formatTime} from '~/utils/scalars'; type LineChartProps = { title?: string; @@ -29,18 +31,21 @@ const LineChart: FunctionComponent = ({ loading, className }) => { - const [ref, echart] = useECharts({ - loading: !!loading + const {i18n} = useTranslation(); + + const {ref, echart} = useECharts({ + loading: !!loading, + zoom: true }); const xAxisFormatter = useCallback( - (value: number) => (type === 'time' ? new Date(value).toLocaleTimeString() : value), - [type] + (value: number) => (type === 'time' ? formatTime(value, i18n.language, 'LTS') : value), + [type, i18n.language] ); useEffect(() => { if (process.browser) { - echart.current?.setOption( + echart?.current?.setOption( { color: chart.color, title: { @@ -84,18 +89,6 @@ const LineChart: FunctionComponent = ({ } }, [data, title, legend, xAxis, type, xAxisFormatter, yRange, tooltip, echart]); - useEffect(() => { - if (process.browser) { - setTimeout(() => { - echart.current?.dispatchAction({ - type: 'takeGlobalCursor', - key: 'dataZoomSelect', - dataZoomSelectActive: true - }); - }, 0); - } - }, [echart]); - return
; }; diff --git a/frontend/components/Preloader.tsx b/frontend/components/Preloader.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3ccfffe45814b0bc5c984d61f4dd3e80aa7c1142 --- /dev/null +++ b/frontend/components/Preloader.tsx @@ -0,0 +1,14 @@ +import React, {FunctionComponent} from 'react'; +import Head from 'next/head'; + +type PreloaderProps = { + url: string; +}; + +const Preloader: FunctionComponent = ({url}) => ( + + + +); + +export default Preloader; diff --git a/frontend/components/SampleChart.tsx b/frontend/components/SampleChart.tsx index 1026779413b2d964d37041a3c5b82db3aefc5b78..86f5af17591da83b552d975713dca046c707d147 100644 --- a/frontend/components/SampleChart.tsx +++ b/frontend/components/SampleChart.tsx @@ -2,8 +2,8 @@ import React, {FunctionComponent, useState} from 'react'; import styled from 'styled-components'; import useSWR from 'swr'; import queryString from 'query-string'; -import {useTranslation} from '~/utils/i18n'; -import {em, size, ellipsis, textLightColor} from '~/utils/style'; +import {em, size, ellipsis, primaryColor, textLightColor} from '~/utils/style'; +import GridLoader from 'react-spinners/GridLoader'; import StepSlider from '~/components/StepSlider'; import Image from '~/components/Image'; @@ -78,11 +78,9 @@ type SampleChartProps = { }; const getImageUrl = (index: number, run: string, tag: string, wallTime: number): string => - `${process.env.API_URL}/images/image?${queryString.stringify({index, ts: wallTime, run, tag})}`; + `/images/image?${queryString.stringify({index, ts: wallTime, run, tag})}`; const SampleChart: FunctionComponent = ({run, tag, fit, running}) => { - const {t} = useTranslation('common'); - const {data, error} = useSWR(`/images/list?${queryString.stringify({run, tag})}`, { refreshInterval: running ? 15 * 1000 : 0 }); @@ -97,7 +95,7 @@ const SampleChart: FunctionComponent = ({run, tag, fit, runnin item.step) ?? []} onChange={setStep} /> - {!data && !error && {t('loading')}} + {!data && !error && } {data && !error && }
diff --git a/frontend/components/ScalarChart.tsx b/frontend/components/ScalarChart.tsx index de6bb5be7912ce5542b90fedbe6d28063049d5fa..e548c10051a1569f30f745d2ee26771ce96895e4 100644 --- a/frontend/components/ScalarChart.tsx +++ b/frontend/components/ScalarChart.tsx @@ -56,7 +56,7 @@ const ScalarChart: FunctionComponent = ({ outlier, running }) => { - const {t} = useTranslation('scalars'); + const {t, i18n} = useTranslation(['scalars', 'common']); // TODO: maybe we can create a custom hook here const {data: datasets, error} = useSWR( @@ -161,9 +161,9 @@ const ScalarChart: FunctionComponent = ({ }; }) ?? []; const sort = sortingMethodMap[sortingMethod]; - return tooltip(sort ? sort(points, data) : points); + return tooltip(sort ? sort(points, data) : points, i18n); }, - [smoothedDatasets, runs, sortingMethod] + [smoothedDatasets, runs, sortingMethod, i18n] ); return ( diff --git a/frontend/components/ScatterChart.tsx b/frontend/components/ScatterChart.tsx index 3cf4c0603a2756256ba3bca95f89748e73834985..f35ca5a1e6ed1b898cce0475437e147c96f6b660 100644 --- a/frontend/components/ScatterChart.tsx +++ b/frontend/components/ScatterChart.tsx @@ -112,9 +112,9 @@ const ScatterChart: FunctionComponent = ({ dimension, className }) => { - const [ref, echart] = useECharts({ + const {ref, echart} = useECharts({ loading, - gl: true + gl: dimension === '3d' }); const [highlighted, others] = useMemo(() => dividePoints(points, keyword), [points, keyword]); const chartOptions = useMemo( @@ -130,14 +130,9 @@ const ScatterChart: FunctionComponent = ({ ); useEffect(() => { - if (!process.browser) { - return; + if (process.browser) { + echart?.current?.setOption(chartOptions, {notMerge: true}); } - - echart.current?.setOption( - chartOptions, - true // not merged - ); }, [chartOptions, echart]); return
; diff --git a/frontend/components/Select.tsx b/frontend/components/Select.tsx index 10dc495efd4ffc26050122a737d4b55017952131..f503879fc8cd159818d91b1921cc55158d4224d2 100644 --- a/frontend/components/Select.tsx +++ b/frontend/components/Select.tsx @@ -31,6 +31,7 @@ const Wrapper = styled.div<{opened?: boolean}>` height: ${height}; line-height: calc(${height} - 2px); min-width: ${minWidth}; + max-width: 100%; display: inline-block; position: relative; border: 1px solid ${borderColor}; @@ -67,6 +68,8 @@ const TriggerIcon = styled(Icon)<{opened?: boolean}>` const Label = styled.span` flex-grow: 1; + padding-right: ${em(10)}; + ${ellipsis()} `; const List = styled.div<{opened?: boolean; empty?: boolean}>` @@ -204,6 +207,7 @@ const Select: FunctionComponent & WithStyled> = ({ changeValue(item.value, checked)} > @@ -215,6 +219,7 @@ const Select: FunctionComponent & WithStyled> = ({ changeValue(item.value)} > {item.label} diff --git a/frontend/components/StepSlider.tsx b/frontend/components/StepSlider.tsx index d0286a6f6d992491defff3d7b4425202bdb2a531..a8dbf18de05120e532665aa1425233d852d491df 100644 --- a/frontend/components/StepSlider.tsx +++ b/frontend/components/StepSlider.tsx @@ -27,7 +27,7 @@ const StepSlider: FunctionComponent = ({onChange, value, steps} return ( <> - + (value: T, delay: number): T => { + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const handler = setTimeout(() => { + setDebouncedValue(value); + }, delay); + return () => clearTimeout(handler); + }, [value, delay]); + + return debouncedValue; +}; + +export default useDebounce; diff --git a/frontend/hooks/useECharts.ts b/frontend/hooks/useECharts.ts index 02ac90bca905fd831db81a5b185fd1c12c4c4f6e..8ee2c8036cd73c8220eeaf94f57af1db7a3a77f7 100644 --- a/frontend/hooks/useECharts.ts +++ b/frontend/hooks/useECharts.ts @@ -1,24 +1,41 @@ -import {useRef, useEffect, useCallback, MutableRefObject} from 'react'; +import {useRef, useEffect, useCallback, useState, MutableRefObject} from 'react'; import echarts, {ECharts} from 'echarts'; -import {useTranslation} from '~/utils/i18n'; +import {primaryColor, textColor, maskColor} from '~/utils/style'; const useECharts = (options: { - loading: boolean; + loading?: boolean; gl?: boolean; -}): [MutableRefObject, MutableRefObject] => { - const {t} = useTranslation('common'); - const ref = useRef(null); - const echart = useRef(null as ECharts | null); + zoom?: boolean; +}): { + ref: MutableRefObject; + echart: MutableRefObject | null; +} => { + const ref = useRef(null as T | null); + const echartInstance = useRef(null as ECharts | null); + const [echart, setEchart] = useState(null as typeof echartInstance | null); const createChart = useCallback(() => { - const loadExtension = options.gl ? import('echarts-gl') : Promise.resolve(); - loadExtension.then(() => { - echart.current = echarts.init((ref.current as unknown) as HTMLDivElement); - }); - }, [options.gl]); + (async () => { + if (options.gl) { + await import('echarts-gl'); + } + echartInstance.current = echarts.init((ref.current as unknown) as HTMLDivElement); + if (options.zoom) { + setTimeout(() => { + echartInstance.current?.dispatchAction({ + type: 'takeGlobalCursor', + key: 'dataZoomSelect', + dataZoomSelectActive: true + }); + }, 0); + } + setEchart(echartInstance); + })(); + }, [options.gl, options.zoom]); const destroyChart = useCallback(() => { - echart.current?.dispose(); + echartInstance.current?.dispose(); + setEchart(null); }, []); useEffect(() => { @@ -29,22 +46,22 @@ const useECharts = (options: { }, [createChart, destroyChart]); useEffect(() => { - if (process.browser) { + if (process.browser && echart) { if (options.loading) { - echart.current?.showLoading('default', { - text: t('loading'), - color: '#c23531', - textColor: '#000', - maskColor: 'rgba(255, 255, 255, 0.8)', + echartInstance.current?.showLoading('default', { + text: '', + color: primaryColor, + textColor, + maskColor, zlevel: 0 }); } else { - echart.current?.hideLoading(); + echartInstance.current?.hideLoading(); } } - }, [t, options.loading]); + }, [options.loading, echart]); - return [ref, echart]; + return {ref, echart}; }; export default useECharts; diff --git a/frontend/hooks/useSearchValue.ts b/frontend/hooks/useSearchValue.ts new file mode 100644 index 0000000000000000000000000000000000000000..73f463113898d1e9f1de60e71df797cdaa118731 --- /dev/null +++ b/frontend/hooks/useSearchValue.ts @@ -0,0 +1,19 @@ +import useDebounce from '~/hooks/useDebounce'; + +const isEmptyValue = (value: unknown): boolean => + (Array.isArray(value) && !value.length) || ('string' === typeof value && value === ''); + +const useSearchValue = (value: T, delay = 275): T => { + const debounced = useDebounce(value, delay); + // return empty value immediately + if (isEmptyValue(value)) { + return value; + } + // if debounced value is empty, return non-empty value immediately + if (isEmptyValue(debounced)) { + return value; + } + return debounced; +}; + +export default useSearchValue; diff --git a/frontend/hooks/useTagFilter.ts b/frontend/hooks/useTagFilter.ts index aaaabf8258688ed2bec0bf98cdb4e2b2671e5681..032ec8d3796a1f831f8e18c1230bbec771134597 100644 --- a/frontend/hooks/useTagFilter.ts +++ b/frontend/hooks/useTagFilter.ts @@ -1,10 +1,10 @@ import {useReducer, useEffect, useCallback, useMemo} from 'react'; +import {useRouter} from 'next/router'; import useSWR from 'swr'; import groupBy from 'lodash/groupBy'; import uniq from 'lodash/uniq'; import intersection from 'lodash/intersection'; import {Tag} from '~/types'; -import {useRouter} from 'next/router'; type Runs = string[]; type Tags = Record; @@ -143,7 +143,9 @@ const useTagFilters = (type: string) => { selectedRuns: state.runs, selectedTags: state.filteredTags, onChangeRuns, - onFilterTags + onFilterTags, + loadingRuns: !runs, + loadingTags: !tags }; }; diff --git a/frontend/mock/embeddings/embedding.ts b/frontend/mock/embeddings/embedding.ts index 38391c45d84ae5c8cbc70d41d12592636bd48979..9a2b1e567e0ca6dd0e261d52224d897eb7d38ae2 100644 --- a/frontend/mock/embeddings/embedding.ts +++ b/frontend/mock/embeddings/embedding.ts @@ -1,7 +1,8 @@ import {Request} from 'express'; export default (req: Request) => { - if (req.query.dimension === '3') { + const {dimension, run} = req.query; + if (dimension === '3') { return { embedding: [ [10.0, 8.04, 3], @@ -16,7 +17,7 @@ export default (req: Request) => { [7.0, 4.8, 3], [5.0, 5.68, 3] ], - labels: ['yellow', 'blue', 'red', 'king', 'queen', 'man', 'women', 'kid', 'adult', 'light', 'dark'] + labels: [`${run}-yellow`, 'blue', 'red', 'king', 'queen', 'man', 'women', 'kid', 'adult', 'light', 'dark'] }; } return { @@ -33,6 +34,6 @@ export default (req: Request) => { [7.0, 4.8], [5.0, 5.68] ], - labels: ['yellow', 'blue', 'red', 'king', 'queen', 'man', 'women', 'kid', 'adult', 'light', 'dark'] + labels: [`${run}-yellow`, 'blue', 'red', 'king', 'queen', 'man', 'women', 'kid', 'adult', 'light', 'dark'] }; }; diff --git a/frontend/next.config.js b/frontend/next.config.js index 1b68281209086213abc84ef24c9ad8a8aff401fe..764ff4ba3a1da3871e21672199c1a9d877a0db1d 100644 --- a/frontend/next.config.js +++ b/frontend/next.config.js @@ -27,6 +27,7 @@ module.exports = { poweredByHeader: false, env: { ...APP, + BUILD_ID: '', DEFAULT_LANGUAGE, LOCALE_PATH, LANGUAGES, diff --git a/frontend/package.json b/frontend/package.json index df8b84bb2f365691acf5240c8a4c9ac73822710a..85e4d0215f4b23c69b83e86e08e7880199c7b96d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -61,10 +61,12 @@ "react-i18next": "11.3.3", "react-input-range": "1.3.0", "react-is": "16.13.0", + "react-spinners": "0.8.0", "save-svg-as-png": "1.4.17", "styled-components": "5.0.1", "swr": "0.1.18", - "url": "0.11.0" + "url": "0.11.0", + "yargs": "15.1.0" }, "devDependencies": { "@babel/core": "7.8.7", @@ -80,11 +82,13 @@ "@types/react-dom": "16.9.5", "@types/styled-components": "5.0.1", "@types/webpack": "4.41.7", + "@types/yargs": "15.0.4", "@typescript-eslint/eslint-plugin": "2.22.0", "@typescript-eslint/parser": "2.22.0", + "babel-plugin-emotion": "10.0.29", "babel-plugin-styled-components": "1.10.7", "babel-plugin-typescript-to-proptypes": "1.3.0", - "cross-env": "7.0.1", + "cross-env": "7.0.2", "eslint": "6.8.0", "eslint-config-prettier": "6.10.0", "eslint-plugin-prettier": "3.1.2", diff --git a/frontend/pages/graphs.tsx b/frontend/pages/graphs.tsx index c4246b8d6224656bd9faf6cee78db4eb608b7994..662c902cdef699f07df2adec2fe2ea1a1ae92d38 100644 --- a/frontend/pages/graphs.tsx +++ b/frontend/pages/graphs.tsx @@ -1,16 +1,17 @@ import React, {useState, useEffect, useMemo} from 'react'; import useSWR from 'swr'; import styled from 'styled-components'; +import {saveSvgAsPng} from 'save-svg-as-png'; +import {rem} from '~/utils/style'; import RawButton from '~/components/Button'; import RawRangeSlider from '~/components/RangeSlider'; import Content from '~/components/Content'; import Title from '~/components/Title'; import Field from '~/components/Field'; import {useTranslation, NextI18NextPage} from '~/utils/i18n'; -import {rem} from '~/utils/style'; import NodeInfo, {NodeInfoProps} from '~/components/GraphPage/NodeInfo'; +import Preloader from '~/components/Preloader'; import {Graph, collectDagFacts} from '~/resource/graph'; -import {saveSvgAsPng} from 'save-svg-as-png'; // eslint-disable-next-line @typescript-eslint/no-empty-function const dumbFn = () => {}; @@ -269,9 +270,10 @@ const Graphs: NextI18NextPage = () => { return ( <> + {t('common:graphs')} - + diff --git a/frontend/pages/high-dimensional.tsx b/frontend/pages/high-dimensional.tsx index f26a63691fbe7845556a75f662ee8c903d272a11..78bab725a15dc16e48e50fb90182e2b3a663ee9e 100644 --- a/frontend/pages/high-dimensional.tsx +++ b/frontend/pages/high-dimensional.tsx @@ -3,6 +3,7 @@ import styled from 'styled-components'; import useSWR from 'swr'; import queryString from 'query-string'; import {useRouter} from 'next/router'; +import useSearchValue from '~/hooks/useSearchValue'; import {rem, em} from '~/utils/style'; import {useTranslation, NextI18NextPage} from '~/utils/i18n'; import Title from '~/components/Title'; @@ -17,6 +18,7 @@ import RunningToggle from '~/components/RunningToggle'; import ScatterChart from '~/components/ScatterChart'; import Select, {SelectValueType} from '~/components/Select'; import AsideDivider from '~/components/AsideDivider'; +import Preloader from '~/components/Preloader'; import {Dimension} from '~/types'; const dimensions = ['2d', '3d']; @@ -55,6 +57,7 @@ const HighDimensional: NextI18NextPage = () => { useEffect(() => setRun(selectedRun), [setRun, selectedRun]); const [search, setSearch] = useState(''); + const debouncedSearch = useSearchValue(search); const [dimension, setDimension] = useState(dimensions[0] as Dimension); const [reduction, setReduction] = useState(reductions[0]); const [running, setRunning] = useState(true); @@ -137,9 +140,15 @@ const HighDimensional: NextI18NextPage = () => { return ( <> + {t('common:high-dimensional')} - - + + ); diff --git a/frontend/pages/samples.tsx b/frontend/pages/samples.tsx index c88cb6948e0f534d028f6a6a0443bf527eae3ccb..e9a46d4ef65609b4e504c24811d0f532f46dffc8 100644 --- a/frontend/pages/samples.tsx +++ b/frontend/pages/samples.tsx @@ -14,6 +14,7 @@ import RunningToggle from '~/components/RunningToggle'; import AsideDivider from '~/components/AsideDivider'; import ChartPage from '~/components/ChartPage'; import SampleChart from '~/components/SampleChart'; +import Preloader from '~/components/Preloader'; const StyledIcon = styled(Icon)` font-size: ${rem(16)}; @@ -40,7 +41,9 @@ type Item = { const Samples: NextI18NextPage = () => { const {t} = useTranslation(['samples', 'common']); - const {runs, tags, selectedRuns, selectedTags, onChangeRuns, onFilterTags} = useTagFilter('images'); + const {runs, tags, selectedRuns, selectedTags, onChangeRuns, onFilterTags, loadingRuns, loadingTags} = useTagFilter( + 'images' + ); const ungroupedSelectedTags = useMemo( () => selectedTags.reduce((prev, {runs, ...item}) => { @@ -103,10 +106,12 @@ const Samples: NextI18NextPage = () => { return ( <> + + {t('common:samples')} - + - + ); diff --git a/frontend/pages/scalars.tsx b/frontend/pages/scalars.tsx index e5fcf90b66e1b98e1b907897a7b426cb181e57e5..bbc4cd603eedd507135df3aa191657dfa13c68cd 100644 --- a/frontend/pages/scalars.tsx +++ b/frontend/pages/scalars.tsx @@ -1,6 +1,7 @@ import React, {useState, useCallback} from 'react'; import {useTranslation, NextI18NextPage} from '~/utils/i18n'; import useTagFilter from '~/hooks/useTagFilter'; +import useSearchValue from '~/hooks/useSearchValue'; import Title from '~/components/Title'; import Content from '~/components/Content'; import RunSelect from '~/components/RunSelect'; @@ -13,6 +14,7 @@ import RunningToggle from '~/components/RunningToggle'; import AsideDivider from '~/components/AsideDivider'; import ChartPage from '~/components/ChartPage'; import ScalarChart, {xAxisMap, sortingMethodMap} from '~/components/ScalarChart'; +import Preloader from '~/components/Preloader'; import {Tag} from '~/types'; type XAxis = keyof typeof xAxisMap; @@ -23,7 +25,11 @@ const toolTipSortingValues = ['default', 'descending', 'ascending', 'nearest']; const Scalars: NextI18NextPage = () => { const {t} = useTranslation(['scalars', 'common']); - const {runs, tags, selectedRuns, selectedTags, onChangeRuns, onFilterTags} = useTagFilter('scalars'); + const {runs, tags, selectedRuns, selectedTags, onChangeRuns, onFilterTags, loadingRuns, loadingTags} = useTagFilter( + 'scalars' + ); + + const debouncedTags = useSearchValue(selectedTags); const [smoothing, setSmoothing] = useState(0.6); @@ -83,10 +89,12 @@ const Scalars: NextI18NextPage = () => { return ( <> + + {t('common:scalars')} - + - + ); diff --git a/frontend/public/locales/en/moment.json b/frontend/public/locales/en/moment.json new file mode 100644 index 0000000000000000000000000000000000000000..a29bacdbab00fa2e5593e32b3a8f4290db7b6fc5 --- /dev/null +++ b/frontend/public/locales/en/moment.json @@ -0,0 +1,10 @@ +{ + "longDateFormat": { + "LT": "h:mm A", + "LTS": "h:mm:ss A", + "L": "MM/DD/YYYY", + "LL": "MMMM Do YYYY", + "LLL": "MMMM Do YYYY LT", + "LLLL": "dddd, MMMM Do YYYY LT" + } +} diff --git a/frontend/public/locales/en/scalars.json b/frontend/public/locales/en/scalars.json index e542148f049b38aa162c8b601b21942bc588f35c..0b671fee56c2d9636c3750fac9238d1ebbc2d632 100644 --- a/frontend/public/locales/en/scalars.json +++ b/frontend/public/locales/en/scalars.json @@ -1,5 +1,7 @@ { "smoothing": "Smoothing", + "value": "Value", + "smoothed": "Smoothed", "x-axis": "X-Axis", "x-axis-value": { "step": "Step", diff --git a/frontend/public/locales/zh/moment.json b/frontend/public/locales/zh/moment.json new file mode 100644 index 0000000000000000000000000000000000000000..7089e056e49137250d95b4f2a58aeed74ce383ce --- /dev/null +++ b/frontend/public/locales/zh/moment.json @@ -0,0 +1,10 @@ +{ + "longDateFormat": { + "LT": "HH:mm", + "LTS": "HH:mm:ss", + "L": "YYYY-MM-DD", + "LL": "YYYY MM Do", + "LLL": "YYYY MMMM Do LT", + "LLLL": "YYYY MMMM Do dddd LT" + } +} diff --git a/frontend/public/locales/zh/scalars.json b/frontend/public/locales/zh/scalars.json index 1c6bc6d0ab727ad820de469fd683df6eac776a6a..d748fc3659f22d4b41cb329ab0959fcc6cfd33b8 100644 --- a/frontend/public/locales/zh/scalars.json +++ b/frontend/public/locales/zh/scalars.json @@ -1,5 +1,7 @@ { "smoothing": "平滑度", + "value": "值", + "smoothed": "平滑值", "x-axis": "X轴", "x-axis-value": { "step": "步", diff --git a/frontend/server/index.ts b/frontend/server/index.ts index f257ef5599d14ffd194d6f49db3ef8908cc29f1f..cbb6a692ed4af0542e522fea4f5d9c6c815e1520 100644 --- a/frontend/server/index.ts +++ b/frontend/server/index.ts @@ -2,6 +2,7 @@ import path from 'path'; import express from 'express'; import next from 'next'; import {setConfig} from 'next/config'; +import {argv} from 'yargs'; import {nextI18NextMiddleware} from '../utils/i18next/middlewares'; import nextI18next from '../utils/i18n'; import config from '../next.config'; @@ -10,9 +11,11 @@ const isDev = process.env.NODE_ENV !== 'production'; setConfig(config); -const host = process.env.HOST || 'localhost'; -const port = process.env.PORT || 8999; -const proxy = process.env.PROXY; +const host = (argv.host as string) || process.env.HOST || 'localhost'; +const port: string | number = Number.parseInt(argv.port as string, 10) || process.env.PORT || 8999; +const proxy = (argv.proxy as string) || process.env.PROXY; +const delay = Number.parseInt(argv.delay as string, 10); + const app = next({dev: isDev, conf: config}); const handle = app.getRequestHandler(); @@ -25,7 +28,10 @@ const handle = app.getRequestHandler(); server.use(config.env.API_URL, createProxyMiddleware({target: proxy, changeOrigin: true})); } else if (isDev) { const {default: mock} = await import('../utils/mock'); - server.use(config.env.API_URL, mock({path: path.resolve(__dirname, '../mock')})); + server.use( + config.env.API_URL, + mock({path: path.resolve(__dirname, '../mock'), delay: delay ? () => Math.random() * delay : 0}) + ); } await nextI18next.initPromise; diff --git a/frontend/types/i18n.d.ts b/frontend/types/i18n.d.ts index daef4d20300f80bc8f0f1a0373a9a5a32adf1f58..5e56fccb0154f6b7875cbc1fc11f58a2aff3aee1 100644 --- a/frontend/types/i18n.d.ts +++ b/frontend/types/i18n.d.ts @@ -1,2 +1,2 @@ -declare module 'path-match'; declare module 'detect-node'; +declare module 'path-match'; diff --git a/frontend/utils/fetch.ts b/frontend/utils/fetch.ts index 543fe0dd271494b42f1c4d2bf48d4e933cdf7880..ec33851b49733b14460e36dbb0d0daf606b0c76c 100644 --- a/frontend/utils/fetch.ts +++ b/frontend/utils/fetch.ts @@ -3,13 +3,19 @@ import fetch from 'isomorphic-unfetch'; /* eslint-disable @typescript-eslint/no-explicit-any */ -export const fetcher = async (url: string, options?: any, baseUrl = ''): Promise => { - const res = await fetch(baseUrl + process.env.API_URL + url, options); + +export const fetcher = async (url: string, options?: any): Promise => { + const res = await fetch(process.env.API_URL + url, options); const response = await res.json(); return response && 'data' in response ? response.data : response; }; -export const cycleFetcher = async (urls: string[], options?: any, baseUrl = ''): Promise => { - return await Promise.all(urls.map(url => fetcher(url, options, baseUrl))); +export const blobFetcher = async (url: string, options?: any): Promise => { + const res = await fetch(process.env.API_URL + url, options); + return await res.blob(); +}; + +export const cycleFetcher = async (urls: string[], options?: any): Promise => { + return await Promise.all(urls.map(url => fetcher(url, options))); }; diff --git a/frontend/utils/i18n.ts b/frontend/utils/i18n.ts index 67fbcd56447e345883037466e99cc191da986e4e..52cd823d483cc4caa8df28bd479cc26281c21acc 100644 --- a/frontend/utils/i18n.ts +++ b/frontend/utils/i18n.ts @@ -1,4 +1,5 @@ import {NextComponentType, NextPageContext} from 'next'; +import moment from 'moment'; import NextI18Next from './i18next'; import {env} from '../next.config'; @@ -8,6 +9,10 @@ const otherLanguages = allLanguages.filter(lang => lang !== defaultLanguage); const isDev = process.env.NODE_ENV === 'development'; +allLanguages.forEach(async (lang: string) => { + moment.updateLocale(lang, await import(`../public/locales/${lang}/moment.json`)); +}); + const nextI18Next = new NextI18Next({ localePath: env.LOCALE_PATH, browserLanguageDetection: !isDev, diff --git a/frontend/utils/i18next/components/Link.tsx b/frontend/utils/i18next/components/Link.tsx index 3fb56e73cbbc21d12b20188fb9f3f2b2a40b5b0e..28bbe5736b96449f26a99cd5e7dafb30dc47d9cb 100644 --- a/frontend/utils/i18next/components/Link.tsx +++ b/frontend/utils/i18next/components/Link.tsx @@ -17,6 +17,7 @@ */ /* eslint-disable @typescript-eslint/no-explicit-any */ + import React from 'react'; import PropTypes from 'prop-types'; import NextLink, {LinkProps} from 'next/link'; diff --git a/frontend/utils/i18next/config/create-config.ts b/frontend/utils/i18next/config/create-config.ts index 03b39d41339d16da91904490be1064af8a3e0192..b241c4a5d18b9ed7736eb23e98af4287aa48ab7b 100644 --- a/frontend/utils/i18next/config/create-config.ts +++ b/frontend/utils/i18next/config/create-config.ts @@ -1,6 +1,8 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import {defaultConfig} from './default-config'; import {consoleMessage, isServer} from '../utils'; -import {InitConfig, Config} from '../types'; +import {Config} from '../types'; const deepMergeObjects = ['backend', 'detection']; const dedupe = (names: string[]) => names.filter((v, i) => names.indexOf(v) === i); @@ -12,16 +14,16 @@ export const createConfig = (userConfig: Config): Config => { } /* - Initial merge of default and user-provided config - */ + Initial merge of default and user-provided config + */ const combinedConfig = { ...defaultConfig, ...userConfig }; /* - Sensible defaults to prevent user duplication - */ + Sensible defaults to prevent user duplication + */ combinedConfig.allLanguages = dedupe(combinedConfig.otherLanguages.concat([combinedConfig.defaultLanguage])); combinedConfig.whitelist = combinedConfig.allLanguages; @@ -29,22 +31,22 @@ export const createConfig = (userConfig: Config): Config => { if (isServer()) { const fs = eval("require('fs')"); - const path = require('path'); + const path = require('path'); // eslint-disable-line @typescript-eslint/no-var-requires let serverLocalePath = localePath; /* - Validate defaultNS - https://github.com/isaachinman/next-i18next/issues/358 - */ + Validate defaultNS + https://github.com/isaachinman/next-i18next/issues/358 + */ if (typeof combinedConfig.defaultNS === 'string') { const defaultFile = `/${defaultLanguage}/${combinedConfig.defaultNS}.${localeExtension}`; const defaultNSPath = path.join(process.cwd(), localePath, defaultFile); const defaultNSExists = fs.existsSync(defaultNSPath); if (!defaultNSExists) { /* - If defaultNS doesn't exist, try to fall back to the deprecated static folder - https://github.com/isaachinman/next-i18next/issues/523 - */ + If defaultNS doesn't exist, try to fall back to the deprecated static folder + https://github.com/isaachinman/next-i18next/issues/523 + */ const staticDirPath = path.join(process.cwd(), STATIC_LOCALE_PATH, defaultFile); const staticDirExists = fs.existsSync(staticDirPath); @@ -62,16 +64,16 @@ export const createConfig = (userConfig: Config): Config => { } /* - Set server side backend - */ + Set server side backend + */ combinedConfig.backend = { loadPath: path.join(process.cwd(), `${serverLocalePath}/${localeStructure}.${localeExtension}`), addPath: path.join(process.cwd(), `${serverLocalePath}/${localeStructure}.missing.${localeExtension}`) }; /* - Set server side preload (languages and namespaces) - */ + Set server side preload (languages and namespaces) + */ combinedConfig.preload = allLanguages; if (!combinedConfig.ns) { const getAllNamespaces = (p: string) => @@ -82,15 +84,15 @@ export const createConfig = (userConfig: Config): Config => { let clientLocalePath = localePath; /* - Remove public prefix from client site config - */ + Remove public prefix from client site config + */ if (localePath.startsWith('public/')) { clientLocalePath = localePath.replace(/^public\//, ''); } /* - Set client side backend - */ + Set client side backend + */ combinedConfig.backend = { loadPath: `${process.env.PUBLIC_PATH}/${clientLocalePath}/${localeStructure}.${localeExtension}`, addPath: `${process.env.PUBLIC_PATH}/${clientLocalePath}/${localeStructure}.missing.${localeExtension}` @@ -100,16 +102,16 @@ export const createConfig = (userConfig: Config): Config => { } /* - Set fallback language to defaultLanguage in production - */ + Set fallback language to defaultLanguage in production + */ if (!userConfig.fallbackLng) { (combinedConfig as any).fallbackLng = process.env.NODE_ENV === 'production' ? combinedConfig.defaultLanguage : false; } /* - Deep merge with overwrite - goes last - */ + Deep merge with overwrite - goes last + */ deepMergeObjects.forEach(obj => { if ((userConfig as any)[obj]) { (combinedConfig as any)[obj] = { diff --git a/frontend/utils/i18next/index.ts b/frontend/utils/i18next/index.ts index 5707df7d5f7a8702b3981f56cc421799434badf8..575b660a8be71c90755827ae9c389b0f4fb19147 100644 --- a/frontend/utils/i18next/index.ts +++ b/frontend/utils/i18next/index.ts @@ -1,14 +1,11 @@ import {withTranslation, useTranslation, Trans} from 'react-i18next'; import hoistNonReactStatics from 'hoist-non-react-statics'; - import {createConfig} from './config/create-config'; import createI18NextClient from './create-i18next-client'; - import {appWithTranslation, withInternals} from './hocs'; import {consoleMessage} from './utils'; import {Link} from './components'; import {wrapRouter} from './router'; - import { AppWithTranslation, Config, diff --git a/frontend/utils/i18next/middlewares/next-i18next-middleware.ts b/frontend/utils/i18next/middlewares/next-i18next-middleware.ts index 69adca9be1f14189457ad74e40694ea1af07efc3..d0b0291981adcd95e456806b87b9b3dbb3a553ee 100644 --- a/frontend/utils/i18next/middlewares/next-i18next-middleware.ts +++ b/frontend/utils/i18next/middlewares/next-i18next-middleware.ts @@ -25,10 +25,10 @@ export default function(nexti18next: NextI18Next) { const middleware = []; /* - If not using server side language detection, - we need to manually set the language for - each request - */ + If not using server side language detection, + we need to manually set the language for + each request + */ if (!config.serverLanguageDetection) { middleware.push((req: Request, _res: Response, next: NextFunction) => { if (isI18nRoute(req)) { @@ -39,13 +39,13 @@ export default function(nexti18next: NextI18Next) { } /* - This does the bulk of the i18next work - */ + This does the bulk of the i18next work + */ middleware.push(i18nextMiddleware.handle(i18n)); /* - This does the locale subpath work - */ + This does the locale subpath work + */ middleware.push((req: Request, res: Response, next: NextFunction) => { if (isI18nRoute(req) && req.i18n) { let currentLng = lngFromReq(req); @@ -59,25 +59,25 @@ export default function(nexti18next: NextI18Next) { if (lngFromCurrentSubpath !== undefined && lngFromCurrentSubpath !== currentLng) { /* - If a user has hit a subpath which does not - match their language, give preference to - the path, and change user language. - */ + If a user has hit a subpath which does not + match their language, give preference to + the path, and change user language. + */ req.i18n.changeLanguage(lngFromCurrentSubpath); currentLng = lngFromCurrentSubpath; } else if (currentLngRequiresSubpath && !currentLngSubpathIsPresent) { /* - If a language subpath is required and - not present, prepend correct subpath - */ + If a language subpath is required and + not present, prepend correct subpath + */ return redirectWithoutCache(res, addSubpath(req.url, currentLngSubpath)); } /* - If a locale subpath is present in the URL, - modify req.url in place so that NextJs will - render the correct route - */ + If a locale subpath is present in the URL, + modify req.url in place so that NextJs will + render the correct route + */ if (typeof lngFromCurrentSubpath === 'string') { const params = localeSubpathRoute(req.url); if (params !== false) { diff --git a/frontend/utils/i18next/router/wrap-router.ts b/frontend/utils/i18next/router/wrap-router.ts index e89e718f75df0e83c6a13be9cb3580b789a55c59..e625bc198a45b43650e18d873eb77b11b604e1c8 100644 --- a/frontend/utils/i18next/router/wrap-router.ts +++ b/frontend/utils/i18next/router/wrap-router.ts @@ -9,6 +9,9 @@ Very important: if you import `Router` from NextJs directly, and not this file, your lang subpath routing will break. */ + +/* eslint-disable @typescript-eslint/no-explicit-any */ + import NextRouter, {SingletonRouter} from 'next/router'; import {lngPathCorrector, subpathIsRequired} from '../utils'; diff --git a/frontend/utils/i18next/types.ts b/frontend/utils/i18next/types.ts index 1146b87001e5a2b873fed278c408b8f6f3a8b5ee..bf3ecb67e2398c4809cf20f4348874bc12e0b952 100644 --- a/frontend/utils/i18next/types.ts +++ b/frontend/utils/i18next/types.ts @@ -1,4 +1,4 @@ -/* tslint:disable no-explicit-any */ +/* eslint-disable @typescript-eslint/no-explicit-any */ import * as React from 'react'; import { @@ -64,6 +64,7 @@ declare class NextI18Next { } declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace namespace Express { interface Request { lng?: string; diff --git a/frontend/utils/i18next/utils/lng-path-corrector.ts b/frontend/utils/i18next/utils/lng-path-corrector.ts index d494506a3f9d20917b3c2c59ebe75c23cd0b3f05..91aea8e58ea1038047a823d596d1aa754d3e5db9 100644 --- a/frontend/utils/i18next/utils/lng-path-corrector.ts +++ b/frontend/utils/i18next/utils/lng-path-corrector.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import {format as formatUrl, parse as parseUrl} from 'url'; import {Config} from '../types'; @@ -42,7 +44,7 @@ export const lngPathCorrector = (config: Config, currentRoute: any, currentLangu throw new Error('Invalid configuration: Current language is not included in all languages array'); } - let href = parseHref(originalHref); + const href = parseHref(originalHref); let as = parseAs(originalAs, href); /* @@ -56,8 +58,8 @@ export const lngPathCorrector = (config: Config, currentRoute: any, currentLangu Strip any/all subpaths from the `as` value */ Object.values(localeSubpaths || {}).forEach((subpath: string) => { - if (subpathIsPresent(as, subpath)) { - as = removeSubpath(as, subpath); + if (subpathIsPresent(as as string, subpath)) { + as = removeSubpath(as as string, subpath); } }); diff --git a/frontend/utils/i18next/utils/lngs-to-load.ts b/frontend/utils/i18next/utils/lngs-to-load.ts index cfb27efc41cd40d8c87710bc9af2c66a212f0a64..484887b913d9b17c21760296771586a60fc1a351 100644 --- a/frontend/utils/i18next/utils/lngs-to-load.ts +++ b/frontend/utils/i18next/utils/lngs-to-load.ts @@ -1,4 +1,5 @@ import {FallbackLng} from 'i18next'; + export const lngsToLoad = (initialLng: string | null, fallbackLng: FallbackLng | false, otherLanguages?: string[]) => { const languages = []; diff --git a/frontend/utils/mock.ts b/frontend/utils/mock.ts index 7892709c7b33b2383ea558b0377f251da5882c49..1d4484519e0610fb4f28c1aba7d8524e2253986c 100644 --- a/frontend/utils/mock.ts +++ b/frontend/utils/mock.ts @@ -27,14 +27,16 @@ export default (options: Options) => { mock = await mock(req, res); } - // sleep let delay = 0; if ('function' === typeof options.delay) { delay = options.delay(method); } else if (options.delay) { delay = options.delay; } - await sleep(delay); + + if (delay) { + await sleep(delay); + } if (mock instanceof ArrayBuffer) { res.send(Buffer.from(mock)); diff --git a/frontend/utils/scalars.ts b/frontend/utils/scalars.ts index bea3e0b152ba9dc58b52b9ec8b310b1268c999a0..e6659144809be353e03836c8cd24784fbe1ba7ef 100644 --- a/frontend/utils/scalars.ts +++ b/frontend/utils/scalars.ts @@ -3,6 +3,7 @@ import minBy from 'lodash/minBy'; import maxBy from 'lodash/maxBy'; import sortBy from 'lodash/sortBy'; import moment from 'moment'; +import {I18n} from '~/utils/i18next/types'; // https://en.wikipedia.org/wiki/Moving_average export const transform = (seriesData: number[][], smoothingWeight: number) => { @@ -79,8 +80,13 @@ export type TooltipData = { item: number[]; }; +export const formatTime = (value: number, language: string, formatter = 'L LTS') => + moment(Math.floor(value), 'x') + .locale(language) + .format(formatter); + // TODO: make it better, don't concat html -export const tooltip = (data: TooltipData[]) => { +export const tooltip = (data: TooltipData[], i18n: I18n) => { const indexPropMap = { Time: 0, Step: 1, @@ -96,6 +102,14 @@ export const tooltip = (data: TooltipData[]) => { Smoothed: 60, Relative: 60 }; + const translatePropMap = { + Run: 'common:runs', + Time: 'scalars:x-axis-value.wall', + Step: 'scalars:x-axis-value.step', + Value: 'scalars:value', + Smoothed: 'scalars:smoothed', + Relative: 'scalars:x-axis-value.relative' + }; const transformedData = data.map(item => { const data = item.item; return { @@ -104,7 +118,7 @@ export const tooltip = (data: TooltipData[]) => { Smoothed: data[indexPropMap.Smoothed].toString().slice(0, 6), Value: data[indexPropMap.Value].toString().slice(0, 6), Step: data[indexPropMap.Step], - Time: moment(Math.floor(data[indexPropMap.Time]), 'x').format('YYYY-MM-DD HH:mm:ss'), + Time: formatTime(data[indexPropMap.Time], i18n.language), // Relative display value should take easy-read into consideration. // Better to tranform data to 'day:hour', 'hour:minutes', 'minute: seconds' and second only. Relative: Math.floor(data[indexPropMap.Relative] * 60 * 60) + 's' @@ -112,11 +126,11 @@ export const tooltip = (data: TooltipData[]) => { }); let headerHtml = ''; - headerHtml += Object.keys(transformedData[0]) + headerHtml += (Object.keys(transformedData[0]) as (keyof typeof transformedData[0])[]) .map(key => { - return `${key}`; + return `${i18n.t( + translatePropMap[key] + )}`; }) .join(''); headerHtml += ''; diff --git a/frontend/utils/style.ts b/frontend/utils/style.ts index f82fac9cdf4f97a381f4629bdb57345d60504b40..08c6101fa7e7ce84ec62d54ce9011eb4ca02051f 100644 --- a/frontend/utils/style.ts +++ b/frontend/utils/style.ts @@ -35,6 +35,7 @@ export const backgroundFocusedColor = '#F6F6F6'; export const borderColor = '#DDD'; export const borderFocusedColor = darken(0.15, borderColor); export const progressBarColor = '#FFF'; +export const maskColor = 'rgba(255, 255, 255, 0.8)'; // transitions export const duration = '75ms'; diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 72d6833328d5ea773275ae6d218113ee203b2d6f..f676fa1450fad7757bfaa27dd850a13461c408de 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -883,7 +883,7 @@ dependencies: regenerator-runtime "^0.13.2" -"@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.8.4": +"@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": version "7.8.7" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.7.tgz#8fefce9802db54881ba59f90bb28719b4996324d" integrity sha512-+AATMUFppJDw6aiR5NVPHqIQBlV/Pj8wY/EZH+lmvRdUo9xBaz/rF3alAwFJQavvKfeOlPE7oaaDHVbcySbCsg== @@ -928,6 +928,42 @@ resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== +"@emotion/cache@^10.0.27": + version "10.0.29" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0" + integrity sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ== + dependencies: + "@emotion/sheet" "0.9.4" + "@emotion/stylis" "0.8.5" + "@emotion/utils" "0.11.3" + "@emotion/weak-memoize" "0.2.5" + +"@emotion/core@^10.0.15": + version "10.0.28" + resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.0.28.tgz#bb65af7262a234593a9e952c041d0f1c9b9bef3d" + integrity sha512-pH8UueKYO5jgg0Iq+AmCLxBsvuGtvlmiDCOuv8fGNYn3cowFpLN98L8zO56U0H1PjDIyAlXymgL3Wu7u7v6hbA== + dependencies: + "@babel/runtime" "^7.5.5" + "@emotion/cache" "^10.0.27" + "@emotion/css" "^10.0.27" + "@emotion/serialize" "^0.11.15" + "@emotion/sheet" "0.9.4" + "@emotion/utils" "0.11.3" + +"@emotion/css@^10.0.27": + version "10.0.27" + resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.27.tgz#3a7458198fbbebb53b01b2b87f64e5e21241e14c" + integrity sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw== + dependencies: + "@emotion/serialize" "^0.11.15" + "@emotion/utils" "0.11.3" + babel-plugin-emotion "^10.0.27" + +"@emotion/hash@0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" + integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== + "@emotion/is-prop-valid@^0.8.3": version "0.8.7" resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.7.tgz#803449993f436f9a6c67752251ea3fc492a1044c" @@ -940,16 +976,42 @@ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== -"@emotion/stylis@^0.8.4": +"@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16": + version "0.11.16" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad" + integrity sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg== + dependencies: + "@emotion/hash" "0.8.0" + "@emotion/memoize" "0.7.4" + "@emotion/unitless" "0.7.5" + "@emotion/utils" "0.11.3" + csstype "^2.5.7" + +"@emotion/sheet@0.9.4": + version "0.9.4" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5" + integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA== + +"@emotion/stylis@0.8.5", "@emotion/stylis@^0.8.4": version "0.8.5" resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== -"@emotion/unitless@^0.7.4": +"@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.4": version "0.7.5" resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== +"@emotion/utils@0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.11.3.tgz#a759863867befa7e583400d322652a3f44820924" + integrity sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw== + +"@emotion/weak-memoize@0.2.5": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" + integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== + "@next/polyfill-nomodule@9.2.2": version "9.2.2" resolved "https://registry.yarnpkg.com/@next/polyfill-nomodule/-/polyfill-nomodule-9.2.2.tgz#2687d5b64ba053b247700f057f083dfd392ee52e" @@ -1118,9 +1180,9 @@ integrity sha512-Ny3rLbV5tnmqgW7w/poCcef4kXP8mHPo/p8EjTS5d9OUk8MlqAeRaM8eF7Vyv7QMLiIXNE94Pa1cMLSPkXQBoQ== "@types/d3-scale@*": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-2.1.1.tgz#405e58771ec6ae7b8f7b4178ee1887620759e8f7" - integrity sha512-kNTkbZQ+N/Ip8oX9PByXfDLoCSaZYm+VUOasbmsa6KD850/ziMdYepg/8kLg2plHzoLANdMqPoYQbvExevLUHg== + version "2.2.0" + resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-2.2.0.tgz#e5987a2857365823eb26ed5eb21bc566c4dcf1c0" + integrity sha512-oQFanN0/PiR2oySHfj+zAAkK1/p4LD32Nt1TMVmzk+bYHk7vgIg/iTXQWitp1cIkDw4LMdcgvO63wL+mNs47YA== dependencies: "@types/d3-time" "*" @@ -1385,6 +1447,18 @@ "@types/webpack-sources" "*" source-map "^0.6.0" +"@types/yargs-parser@*": + version "15.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" + integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== + +"@types/yargs@15.0.4": + version "15.0.4" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.4.tgz#7e5d0f8ca25e9d5849f2ea443cf7c402decd8299" + integrity sha512-9T1auFmbPZoxHz0enUFlUuKRy3it01R+hlggyVUMtnCTQRunsQYifnSGb8hET4Xo8yiC0o0r1paW3ud5+rbURg== + dependencies: + "@types/yargs-parser" "*" + "@types/zrender@*": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/zrender/-/zrender-4.0.0.tgz#a6806f12ec4eccaaebd9b0d816f049aca6188fbd" @@ -1718,7 +1792,7 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.1.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== @@ -1747,11 +1821,19 @@ anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" -aproba@^1.1.1: +aproba@^1.0.3, aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -1946,6 +2028,31 @@ babel-plugin-dynamic-import-node@^2.3.0: dependencies: object.assign "^4.1.0" +babel-plugin-emotion@10.0.29, babel-plugin-emotion@^10.0.27: + version "10.0.29" + resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.29.tgz#89d8e497091fcd3d10331f097f1471e4cc3f35b4" + integrity sha512-7Jpi1OCxjyz0k163lKtqP+LHMg5z3S6A7vMBfHnF06l2unmtsOmFDzZBpGf0CWo1G4m8UACfVcDJiSiRuu/cSw== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@emotion/hash" "0.8.0" + "@emotion/memoize" "0.7.4" + "@emotion/serialize" "^0.11.16" + babel-plugin-macros "^2.0.0" + babel-plugin-syntax-jsx "^6.18.0" + convert-source-map "^1.5.0" + escape-string-regexp "^1.0.5" + find-root "^1.1.0" + source-map "^0.5.7" + +babel-plugin-macros@^2.0.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" + integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== + dependencies: + "@babel/runtime" "^7.7.2" + cosmiconfig "^6.0.0" + resolve "^1.12.0" + babel-plugin-styled-components@1.10.7, "babel-plugin-styled-components@>= 1": version "1.10.7" resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.10.7.tgz#3494e77914e9989b33cc2d7b3b29527a949d635c" @@ -2319,7 +2426,7 @@ camelcase@5.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== -camelcase@5.3.1, camelcase@^5.3.1: +camelcase@5.3.1, camelcase@^5.0.0, camelcase@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== @@ -2493,6 +2600,15 @@ cli-width@^2.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" @@ -2653,6 +2769,11 @@ console-browserify@^1.1.0: resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" @@ -2670,7 +2791,7 @@ content-type@1.0.4, content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== -convert-source-map@1.7.0, convert-source-map@^1.7.0: +convert-source-map@1.7.0, convert-source-map@^1.5.0, convert-source-map@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== @@ -2794,10 +2915,10 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" -cross-env@7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.1.tgz#c8e03412ea0e1370fe3f0066929a70b8e1e90c39" - integrity sha512-1+DmLosu38kC4s1H4HzNkcolwdANifu9+5bE6uKQCV4L6jvVdV9qdRAk8vV3GoWRe0x4z+K2fFhgoDMqwNsPqQ== +cross-env@7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.2.tgz#bd5ed31339a93a3418ac4f3ca9ca3403082ae5f9" + integrity sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw== dependencies: cross-spawn "^7.0.1" @@ -2954,7 +3075,7 @@ cssnano-simple@1.0.0: cssnano-preset-simple "^1.0.0" postcss "^7.0.18" -csstype@^2.2.0: +csstype@^2.2.0, csstype@^2.5.7: version "2.6.9" resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.9.tgz#05141d0cd557a56b8891394c1911c40c8a98d098" integrity sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q== @@ -3264,6 +3385,11 @@ debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: dependencies: ms "^2.1.1" +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" @@ -3332,6 +3458,11 @@ del@^3.0.0: pify "^3.0.0" rimraf "^2.2.8" +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + depd@~1.1.1, depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -3350,6 +3481,11 @@ destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + detect-node@2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" @@ -3484,9 +3620,9 @@ ee-first@1.1.1: integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= electron-to-chromium@^1.3.322, electron-to-chromium@^1.3.363: - version "1.3.368" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.368.tgz#d7597e04339f7ca70762031ec473d38eb2df6acb" - integrity sha512-fqzDipW3p+uDkHUHFPrdW3wINRKcJsbnJwBD7hgaQEQwcuLSvNLw6SeUp5gKDpTbmTl7zri7IZfhsdTUTnygJg== + version "1.3.370" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.370.tgz#420fba483d30ba3f7965b30ecf850fdb5f08a0bc" + integrity sha512-399cXDE9C7qoVF2CUgCA/MLflfvxbo1F0kB/pkB94426freL/JgZ0HNaloomsOfnE+VC/qgTFZqzmivSdaNfPQ== elegant-spinner@^1.0.1: version "1.0.1" @@ -4067,6 +4203,11 @@ find-cache-dir@^3.0.0: make-dir "^3.0.2" pkg-dir "^4.1.0" +find-root@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + find-up@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.0.0.tgz#c367f8024de92efb75f2d4906536d24682065c3a" @@ -4088,7 +4229,7 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" -find-up@^4.0.0: +find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== @@ -4181,6 +4322,13 @@ from2@^2.1.0: inherits "^2.0.1" readable-stream "^2.0.0" +fs-minipass@^1.2.5: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== + dependencies: + minipass "^2.6.0" + fs-write-stream-atomic@^1.0.8: version "1.0.10" resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" @@ -4219,11 +4367,30 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + gensync@^1.0.0-beta.1: version "1.0.0-beta.1" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-own-enumerable-property-symbols@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" @@ -4377,6 +4544,11 @@ has-symbols@^1.0.0, has-symbols@^1.0.1: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" @@ -4586,7 +4758,7 @@ i18next@19.3.2: dependencies: "@babel/runtime" "^7.3.1" -iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.24: +iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -4620,6 +4792,13 @@ ignore-loader@0.1.2: resolved "https://registry.yarnpkg.com/ignore-loader/-/ignore-loader-0.1.2.tgz#d81f240376d0ba4f0d778972c3ad25874117a463" integrity sha1-2B8kA3bQuk8Nd4lyw60lh0EXpGM= +ignore-walk@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" + integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== + dependencies: + minimatch "^3.0.4" + ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" @@ -5689,6 +5868,21 @@ minimist@^1.2.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= +minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.2.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== + dependencies: + minipass "^2.9.0" + mississippi@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" @@ -5713,7 +5907,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5.1, mkdirp@^0.5.1: +mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -5784,6 +5978,15 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +needle@^2.2.1: + version "2.3.3" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.3.tgz#a041ad1d04a871b0ebb666f40baaf1fb47867117" + integrity sha512-EkY0GeSq87rWp1hoq/sH/wnTWgFVhYlnIkbJ0YJFfRgEFlz2RraCjBpFQ+vrEgEdp0ThfyHADmkChEhcb7PKyw== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + negotiator@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" @@ -5936,6 +6139,22 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" +node-pre-gyp@*: + version "0.14.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83" + integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4.4.2" + node-releases@^1.1.44, node-releases@^1.1.50: version "1.1.50" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.50.tgz#803c40d2c45db172d0410e4efec83aa8c6ad0592" @@ -5959,6 +6178,14 @@ nodemon@2.0.2: undefsafe "^2.0.2" update-notifier "^2.5.0" +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= + dependencies: + abbrev "1" + osenv "^0.1.4" + nopt@~1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" @@ -6008,6 +6235,27 @@ normalize-url@1.9.1: query-string "^4.1.0" sort-keys "^1.0.0" +npm-bundled@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" + integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== + dependencies: + npm-normalize-package-bin "^1.0.1" + +npm-normalize-package-bin@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" + integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== + +npm-packlist@^1.1.6: + version "1.4.8" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" + integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + npm-normalize-package-bin "^1.0.1" + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -6022,6 +6270,16 @@ npm-run-path@^4.0.0: dependencies: path-key "^3.0.0" +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + nprogress@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1" @@ -6187,11 +6445,24 @@ os-browserify@^0.3.0: resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= -os-tmpdir@~1.0.2: +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -7098,7 +7369,7 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -rc@^1.0.1, rc@^1.1.6: +rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -7149,6 +7420,13 @@ react-is@16.8.6: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA== +react-spinners@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/react-spinners/-/react-spinners-0.8.0.tgz#a64f5bc4c301f463841cf75ed67d6f64a365997c" + integrity sha512-xeoRNn4YlsqKaqBm0SgCrRt3sI99CGFraZbw9noD9RLKwumEJ55e9dkXjdEbZgJUmPymQCDrsazQe79DoFd9IQ== + dependencies: + "@emotion/core" "^10.0.15" + react@16.13.0: version "16.13.0" resolved "https://registry.yarnpkg.com/react/-/react-16.13.0.tgz#d046eabcdf64e457bbeed1e792e235e1b9934cf7" @@ -7167,7 +7445,7 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -7331,6 +7609,16 @@ repeat-string@^1.6.1: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -7367,7 +7655,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.10.0, resolve@^1.14.2, resolve@^1.3.2, resolve@^1.8.1: +resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.3.2, resolve@^1.8.1: version "1.15.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== @@ -7420,7 +7708,7 @@ rimraf@2.6.3: dependencies: glob "^7.1.3" -rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.3: +rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -7499,6 +7787,11 @@ save-svg-as-png@1.4.17: resolved "https://registry.yarnpkg.com/save-svg-as-png/-/save-svg-as-png-1.4.17.tgz#294442002772a24f1db1bf8a2aaf7df4ab0cdc55" integrity sha512-7QDaqJsVhdFPwviCxkgHiGm9omeaMBe1VKbHySWU6oFB2LtnGCcYS13eVoslUgq6VZC6Tjq/HddBd1K6p2PGpA== +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + scheduler@^0.19.0: version "0.19.0" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.0.tgz#a715d56302de403df742f4a9be11975b32f5698d" @@ -7541,7 +7834,7 @@ semver-regex@^2.0.0: resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-2.0.0.tgz#a93c2c5844539a770233379107b38c7b4ac9d338" integrity sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw== -"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.1: +"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -7590,6 +7883,11 @@ serve-static@1.14.1: parseurl "~1.3.3" send "0.17.1" +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" @@ -7767,7 +8065,7 @@ source-map@0.7.3: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== -source-map@^0.5.0, source-map@^0.5.6: +source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -7896,7 +8194,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.0.0, string-width@^2.1.1: +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -7913,7 +8211,7 @@ string-width@^3.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0: +string-width@^4.1.0, string-width@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== @@ -8127,6 +8425,19 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== +tar@^4.4.2: + version "4.4.13" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" + integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.8.6" + minizlib "^1.2.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.3" + term-size@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" @@ -8682,6 +8993,11 @@ whatwg-fetch@3.0.0: resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + which-pm-runs@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" @@ -8701,6 +9017,13 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + widest-line@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc" @@ -8735,6 +9058,15 @@ wrap-ansi@^3.0.1: string-width "^2.1.1" strip-ansi "^4.0.0" +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -8786,7 +9118,7 @@ yallist@^2.1.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= -yallist@^3.0.2: +yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== @@ -8798,6 +9130,31 @@ yaml@^1.7.2: dependencies: "@babel/runtime" "^7.6.3" +yargs-parser@^16.1.0: + version "16.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-16.1.0.tgz#73747d53ae187e7b8dbe333f95714c76ea00ecf1" + integrity sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs@15.1.0: + version "15.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.1.0.tgz#e111381f5830e863a89550bd4b136bb6a5f37219" + integrity sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^16.1.0" + yarn@1.22.0: version "1.22.0" resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.22.0.tgz#acf82906e36bcccd1ccab1cfb73b87509667c881"