From e4c1f9835fd000d07bd4fa06f178d3c761777c44 Mon Sep 17 00:00:00 2001 From: Jon Jackson Date: Wed, 17 Apr 2019 16:12:48 -0400 Subject: [PATCH] Replace plotly line chart with pf-react area chart --- frontend/package.json | 1 + frontend/public/components/app.jsx | 6 + frontend/public/components/build.tsx | 8 +- frontend/public/components/cluster-health.jsx | 26 +- .../public/components/graphs/_graphs.scss | 9 +- .../public/components/graphs/graph-loader.jsx | 1 + frontend/public/components/graphs/index.jsx | 7 +- frontend/public/components/graphs/line.tsx | 40 ++ .../graphs/{line.jsx => plotly-line.jsx} | 6 +- .../components/graphs/prometheus-watch.tsx | 140 ++++++ .../components/graphs/query-browser.jsx | 4 +- .../public/components/graphs/resizable.tsx | 41 ++ frontend/public/components/graphs/themes.tsx | 73 ++++ .../public/components/image-stream-tag.tsx | 4 +- frontend/public/components/namespace.jsx | 8 +- frontend/public/components/node.tsx | 12 +- frontend/public/components/pod.jsx | 10 +- frontend/public/components/utils/datetime.ts | 8 + frontend/public/components/utils/units.js | 4 +- frontend/yarn.lock | 404 +++++++++++++++++- 20 files changed, 766 insertions(+), 46 deletions(-) create mode 100644 frontend/public/components/graphs/line.tsx rename frontend/public/components/graphs/{line.jsx => plotly-line.jsx} (95%) create mode 100644 frontend/public/components/graphs/prometheus-watch.tsx create mode 100644 frontend/public/components/graphs/resizable.tsx create mode 100644 frontend/public/components/graphs/themes.tsx diff --git a/frontend/package.json b/frontend/package.json index 5bbf5355c961..352208dcaa01 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -56,6 +56,7 @@ }, "dependencies": { "@patternfly/patternfly": "1.0.219", + "@patternfly/react-charts": "^3.1.1", "@patternfly/react-core": "2.4.1", "brace": "0.11.x", "classnames": "2.x", diff --git a/frontend/public/components/app.jsx b/frontend/public/components/app.jsx index 1ef7bc75ff34..b05432b2b150 100644 --- a/frontend/public/components/app.jsx +++ b/frontend/public/components/app.jsx @@ -137,6 +137,12 @@ class App extends React.PureComponent { } _onNavToggle() { + + // Some components, like svg charts, need to reflow when nav is toggled + setTimeout(() => { + window.dispatchEvent(new Event('nav_toggle')); + }, 100); + this.setState(prevState => { return { isNavOpen: !prevState.isNavOpen, diff --git a/frontend/public/components/build.tsx b/frontend/public/components/build.tsx index 196d7f41e7eb..c714311502ff 100644 --- a/frontend/public/components/build.tsx +++ b/frontend/public/components/build.tsx @@ -9,7 +9,7 @@ import { K8sResourceKindReference, referenceFor, K8sResourceKind } from '../modu import { cloneBuild, formatBuildDuration, BuildPhase, getBuildNumber } from '../module/k8s/builds'; import { ColHead, DetailsPage, List, ListHeader, ListPage } from './factory'; import { errorModal } from './modals'; -import { BuildHooks, BuildStrategy, Kebab, SectionHeading, history, navFactory, ResourceKebab, ResourceLink, resourceObjPath, ResourceSummary, Timestamp, AsyncComponent, resourcePath, StatusIcon } from './utils'; +import { BuildHooks, BuildStrategy, Kebab, SectionHeading, history, navFactory, ResourceKebab, ResourceLink, resourceObjPath, ResourceSummary, Timestamp, AsyncComponent, resourcePath, StatusIcon, humanizeDecimalBytes, humanizeCpuCores } from './utils'; import { BuildPipeline, BuildPipelineLogLink } from './build-pipeline'; import { breadcrumbsForOwnerRefs } from './utils/breadcrumbs'; import { fromNow } from './utils/datetime'; @@ -92,13 +92,13 @@ const BuildGraphs = requirePrometheus(({build}) => { return
- +
- +
- +
diff --git a/frontend/public/components/cluster-health.jsx b/frontend/public/components/cluster-health.jsx index 9f62dfca244d..323fa88a5209 100644 --- a/frontend/public/components/cluster-health.jsx +++ b/frontend/public/components/cluster-health.jsx @@ -1,9 +1,11 @@ import * as React from 'react'; import { Helmet } from 'react-helmet'; -import { humanizeMem, humanizeNumber, PageHeading } from './utils'; +import { humanizeBinaryBytes, humanizeNumber, PageHeading, humanizeCpuCores, humanizeDecimalBytes } from './utils'; import { Bar, Gauge, Line, Scalar } from './graphs'; +const LINE_CHART_HEIGHT = 200; + const multiLoadQueries = [ { name: '1m', @@ -62,7 +64,7 @@ export const ClusterHealth = () =>
- +
@@ -81,10 +83,10 @@ export const ClusterHealth = () =>
- +
- +
@@ -102,30 +104,30 @@ export const ClusterHealth = () =>
- +
- +
- +
- +
- +
- +
@@ -136,10 +138,10 @@ export const ClusterHealth = () =>
- +
- +
diff --git a/frontend/public/components/graphs/_graphs.scss b/frontend/public/components/graphs/_graphs.scss index 575b27e47876..7ede94c7c707 100644 --- a/frontend/public/components/graphs/_graphs.scss +++ b/frontend/public/components/graphs/_graphs.scss @@ -2,12 +2,15 @@ padding-top: 15px; // So graph title doesn't abut border margin-top: 0; margin-bottom: 16px; - overflow: hidden; + overflow: visible; // Tooltips may overflow +} + +.graph-wrapper svg { + overflow: visible !important; // Tooltips may overflow } .graph-title { - margin: 0; - text-align: center; + margin: 0 0 10px 0; color: black; overflow: hidden; text-overflow: ellipsis; diff --git a/frontend/public/components/graphs/graph-loader.jsx b/frontend/public/components/graphs/graph-loader.jsx index 638e659e0376..e75865195b96 100644 --- a/frontend/public/components/graphs/graph-loader.jsx +++ b/frontend/public/components/graphs/graph-loader.jsx @@ -1,6 +1,7 @@ export { Bar } from './bar'; export { Gauge } from './gauge'; export { Line } from './line'; +export { PlotlyLine } from './plotly-line'; export { QueryBrowser } from './query-browser'; export { Scalar } from './scalar'; export { Donut } from './donut'; diff --git a/frontend/public/components/graphs/index.jsx b/frontend/public/components/graphs/index.jsx index 262e917c3e8b..d320be0f0594 100644 --- a/frontend/public/components/graphs/index.jsx +++ b/frontend/public/components/graphs/index.jsx @@ -5,14 +5,15 @@ import { AsyncComponent } from '../utils/async'; import { FLAGS, connectToFlags } from '../../features'; export { Status, errorStatus } from './status'; -export const prometheusBasePath = window.SERVER_FLAGS.prometheusBaseURL; -export const prometheusTenancyBasePath = window.SERVER_FLAGS.prometheusTenancyBaseURL; -export const alertManagerBasePath = window.SERVER_FLAGS.alertManagerBaseURL; +export const prometheusBasePath = 'https://prometheus-k8s-openshift-monitoring.apps.jonjacks.devcluster.openshift.com'; +export const prometheusTenancyBasePath = 'https://prometheus-k8s-openshift-monitoring.apps.jonjacks.devcluster.openshift.com'; +export const alertManagerBasePath = 'https://prometheus-k8s-openshift-monitoring.apps.jonjacks.devcluster.openshift.com'; export const QueryBrowser = props => import('./graph-loader').then(c => c.QueryBrowser)} {...props} />; export const Bar = props => import('./graph-loader').then(c => c.Bar)} {...props} />; export const Gauge = props => import('./graph-loader').then(c => c.Gauge)} {...props} />; export const Line = props => import('./graph-loader').then(c => c.Line)} {...props} />; +export const PlotlyLine = props => import('./graph-loader').then(c => c.PlotlyLine)} {...props} />; export const Scalar = props => import('./graph-loader').then(c => c.Scalar)} {...props} />; export const Donut = props => import('./graph-loader').then(c => c.Donut)} {...props} />; diff --git a/frontend/public/components/graphs/line.tsx b/frontend/public/components/graphs/line.tsx new file mode 100644 index 000000000000..50d2e41efcc5 --- /dev/null +++ b/frontend/public/components/graphs/line.tsx @@ -0,0 +1,40 @@ +import * as _ from 'lodash-es'; +import * as React from 'react'; +import { Chart, ChartArea, ChartVoronoiContainer, ChartAxis, ChartTheme, ChartGroup } from '@patternfly/react-charts'; + +import { humanizeNumber } from '../utils'; +import { withPrometheusWatch } from './prometheus-watch'; +import { resizable } from './resizable'; +import { twentyFourHourTime } from '../utils/datetime'; +import { areaStyles, cartesianChartStyles } from './themes'; + + + +const LineChart = ({ + data, + humanize = humanizeNumber, + height = 90, + tickCount = 3, + theme = ChartTheme.light.multi, + width +}) => { + // Override theme. Once PF React Charts is released and we update, there should be much less we need to override here. + const _theme = _.merge(theme, cartesianChartStyles, areaStyles); + const getLabel = v => (data.length > 1) ? `${v.name}: ${humanize(v.y)}` : humanize(v.y); + const container = ; + return + twentyFourHourTime(tick)} /> + humanize(tick)} /> + + { _.map(data, (values, i) => ) } + + ; +} + +export const Line = _.flow(withPrometheusWatch,resizable)(LineChart); diff --git a/frontend/public/components/graphs/line.jsx b/frontend/public/components/graphs/plotly-line.jsx similarity index 95% rename from frontend/public/components/graphs/line.jsx rename to frontend/public/components/graphs/plotly-line.jsx index 15632dcbd913..bc26050d71c8 100644 --- a/frontend/public/components/graphs/line.jsx +++ b/frontend/public/components/graphs/plotly-line.jsx @@ -14,7 +14,7 @@ const baseData = { type: 'scatter', }; -export class Line_ extends BaseGraph { +export class PlotlyLine_ extends BaseGraph { constructor(props) { super(props); @@ -126,8 +126,8 @@ export class Line_ extends BaseGraph { }); } } -export const Line = connectToURLs(MonitoringRoutes.Prometheus)(Line_); +export const PlotlyLine = connectToURLs(MonitoringRoutes.Prometheus)(PlotlyLine_); -Line_.contextTypes = { +PlotlyLine_.contextTypes = { urls: PropTypes.object, }; diff --git a/frontend/public/components/graphs/prometheus-watch.tsx b/frontend/public/components/graphs/prometheus-watch.tsx new file mode 100644 index 000000000000..612c1be6c51d --- /dev/null +++ b/frontend/public/components/graphs/prometheus-watch.tsx @@ -0,0 +1,140 @@ +/* eslint-disable no-undef, no-unused-vars */ +import * as _ from 'lodash-es'; +import * as React from 'react'; +import * as classNames from 'classnames'; + +import { coFetchJSON } from '../../co-fetch'; +import { connectToURLs, MonitoringRoutes } from '../../monitoring'; +import { SafetyFirst } from '../safety-first'; +import { prometheusTenancyBasePath, prometheusBasePath } from '.'; + +export const withPrometheusWatch = (Component) => connectToURLs(MonitoringRoutes.Prometheus)( + class extends SafetyFirst { + private interval; + private timeSpan; + private start; + private end; + constructor(props) { + super(props); + this.interval = null; + this.timeSpan = props.timeSpan || 60 * 60 * 1000; // 1 hour + this.start = null; + this.end = null; + this.state = { + error: null, + data: [], + }; + } + + fetch(enablePolling = true) { + const { query, basePath, namespace, numSamples, timeout, title = ''} = this.props; + const timeSpan = this.end - this.start || this.timeSpan; + const end = this.end || Date.now(); + const start = this.start || (end - timeSpan); + const baseUrl = basePath || (namespace ? prometheusTenancyBasePath : prometheusBasePath); + const pollInterval = timeSpan ? Math.max(timeSpan / 120, 3000) : 15000; + const stepSize = (timeSpan && numSamples ? timeSpan / numSamples : pollInterval) / 1000; + const timeoutParam = timeout ? `&timeout=${encodeURIComponent(timeout)}` : ''; + const queries = !_.isArray(query) ? [{query, name: title}] : query; + const promises = queries.map(q => { + const nsParam = namespace ? `&namespace=${encodeURIComponent(namespace)}` : ''; + const url = this.timeSpan + ? `${baseUrl}/api/v1/query_range?query=${encodeURIComponent(q.query)}&start=${start / 1000}&end=${end / 1000}&step=${stepSize}${nsParam}${timeoutParam}` + : `${baseUrl}/api/v1/query?query=${encodeURIComponent(q.query)}${nsParam}${timeoutParam}`; + return coFetchJSON(url).then(result => { + const values = _.get(result, 'data.result[0].values'); + return _.map(values, v => ({ + name: q.name, + x: new Date(v[0] * 1000), + y: parseFloat(v[1]), + })); + }); + }); + Promise.all(promises) + .then(data => this.setState({data})) + .catch(error => this.setState({error})) + .then(() => { + if (enablePolling) { + this.interval = setTimeout(() => { + if (this.isMounted_) { + this.fetch(); + } + }, pollInterval); + } + }); + } + + componentWillMount() { + if (this.props.query) { + this.fetch(); + } + } + + componentWillUnmount() { + super.componentWillUnmount(); + clearInterval(this.interval); + } + + prometheusURL() { + const { urls, query } = this.props; + const base = urls && urls[MonitoringRoutes.Prometheus]; + if (!base) { + return null; + } + + const queries = _.isArray(query) ? query : [{query}]; + const params = new URLSearchParams(); + _.each(queries, (q, i) => { + params.set(`g${i}.range_input`, '1h'); + params.set(`g${i}.expr`, q.query); + params.set(`g${i}.tab`, '0'); + }); + + return `${base}/graph?${params.toString()}`; + } + + render() { + const { title, className, ...rest } = this.props; + const { data } = this.state; + const url = this.props.query ? this.prometheusURL() : null; + + return
+ { title &&
{title}
} + { + url + ? + + + : + } +
; + } + } +); + +type PrometheusQuery = { + name: string; + query: string; +}; + +type CartesianData = { + x: Date; + y: number; +}; + +type PrometheusWatchProps = { + basePath?: string; + className?: string; + humanize?: (v: number) => string; + namespace?: string; + numSamples?: number; + query: PrometheusQuery[] | string; + timeout?: string; + title?: string; + urls?: string[]; +}; + +type PrometheusWatchState = { + data: CartesianData[][]; + error?: string; +}; diff --git a/frontend/public/components/graphs/query-browser.jsx b/frontend/public/components/graphs/query-browser.jsx index 1348505433ca..f1780fba3db4 100644 --- a/frontend/public/components/graphs/query-browser.jsx +++ b/frontend/public/components/graphs/query-browser.jsx @@ -5,12 +5,12 @@ import { addTraces, deleteTraces, relayout, restyle } from 'plotly.js/lib/core'; import { connectToURLs, MonitoringRoutes } from '../../monitoring'; import { Dropdown, ExternalLink, LoadingInline } from '../utils'; import { formatPrometheusDuration, parsePrometheusDuration } from '../utils/datetime'; -import { Line_ } from './line'; +import { PlotlyLine_ } from './plotly-line'; const spans = ['5m', '15m', '30m', '1h', '2h', '6h', '12h', '1d', '2d', '1w', '2w']; const dropdownItems = _.zipObject(spans, spans); -class QueryBrowser_ extends Line_ { +class QueryBrowser_ extends PlotlyLine_ { constructor(props) { super(props); diff --git a/frontend/public/components/graphs/resizable.tsx b/frontend/public/components/graphs/resizable.tsx new file mode 100644 index 000000000000..655d43892cd6 --- /dev/null +++ b/frontend/public/components/graphs/resizable.tsx @@ -0,0 +1,41 @@ +/* eslint-disable no-undef, no-unused-vars */ +import * as React from 'react'; + +export const resizable = (Component) => { + return class Resizable extends React.Component { + private containerRef; + constructor(props) { + super(props); + this.containerRef = React.createRef(); + this.state = { + width: 0, + }; + } + + componentDidMount() { + window.addEventListener('resize', this.handleResize); + window.addEventListener('nav_toggle', this.handleResize); + this.handleResize(); + } + + componentWillUnmount() { + window.removeEventListener('resize', this.handleResize); + window.removeEventListener('nav_toggle', this.handleResize); + } + + handleResize = () => { + this.setState({ + width: this.containerRef.current.clientWidth, + }); + } + + render() { + return
+ +
; + } + }; +}; + +type ResizableProps = {}; +type ResizableState = { width: number; }; diff --git a/frontend/public/components/graphs/themes.tsx b/frontend/public/components/graphs/themes.tsx new file mode 100644 index 000000000000..12b85d2713e8 --- /dev/null +++ b/frontend/public/components/graphs/themes.tsx @@ -0,0 +1,73 @@ +import { global_FontFamily_sans_serif } from "@patternfly/react-tokens"; + +const independentAxisStyles = { + independentAxis: { + style: { + axis: { stroke: '#D1D1D1' }, + tickLabels: { fontFamily: global_FontFamily_sans_serif.value }, + }, + }, +}; + +const dependentAxisStyles = { + dependentAxis: { + style: { + axis: { stroke: '#D1D1D1' }, + grid: { stroke: '#EDEDED' }, + tickLabels: { fontFamily: global_FontFamily_sans_serif.value }, + }, + }, +}; + +const tooltipStyles = { + // General tooltip style + tooltip: { + flyoutStyle: { + fill: '#151515', + }, + style: { + labels: { + fontFamily: global_FontFamily_sans_serif.value, + fill: '#FFF', + }, + }, + }, + + // Voronoi container tooltip theme, overrides general tooltip style + voronoi: { + style: { + flyout: { + fill: '#151515', + }, + labels: { + fontFamily: global_FontFamily_sans_serif.value, + fill: '#FFF', + }, + }, + }, +}; + +export const areaStyles = { + area: { + style: { + data: { + labels: global_FontFamily_sans_serif.value, + fillOpacity: .15, + }, + }, + }, +}; + +export const cartesianChartStyles = { + chart: { + padding: { + bottom: 30, + left: 60, + right: 0, + top: 0, + }, + }, + ...independentAxisStyles, + ...dependentAxisStyles, + ...tooltipStyles, +}; diff --git a/frontend/public/components/image-stream-tag.tsx b/frontend/public/components/image-stream-tag.tsx index ec669682f4e9..640554b452fb 100644 --- a/frontend/public/components/image-stream-tag.tsx +++ b/frontend/public/components/image-stream-tag.tsx @@ -5,7 +5,7 @@ import * as _ from 'lodash-es'; import { K8sResourceKind, K8sResourceKindReference } from '../module/k8s'; import { DetailsPage } from './factory'; import { Kebab, SectionHeading, navFactory, ResourceSummary } from './utils'; -import { humanizeMem } from './utils/units'; +import { humanizeBinaryBytes } from './utils/units'; const ImageStreamTagsReference: K8sResourceKindReference = 'ImageStreamTag'; @@ -39,7 +39,7 @@ export const ImageStreamTagsDetails: React.SFC = ({ const cmd = (config.Cmd || []).join(' '); const exposedPorts = _.keys(config.ExposedPorts).join(', '); const size = _.get(imageStreamTag, 'image.dockerImageMetadata.Size'); - const humanizedSize = _.isFinite(size) && humanizeMem(size); + const humanizedSize = _.isFinite(size) && humanizeBinaryBytes(size); const architecture = _.get(imageStreamTag, 'image.dockerImageMetadata.Architecture'); return
diff --git a/frontend/public/components/namespace.jsx b/frontend/public/components/namespace.jsx index 0d5ed6ef4ac5..223dece00d3c 100644 --- a/frontend/public/components/namespace.jsx +++ b/frontend/public/components/namespace.jsx @@ -10,7 +10,7 @@ import { k8sGet } from '../module/k8s'; import { formatNamespacedRouteForResource, UIActions } from '../ui/ui-actions'; import { ColHead, DetailsPage, List, ListHeader, ListPage, ResourceRow } from './factory'; import { SafetyFirst } from './safety-first'; -import { ActionsMenu, Kebab, Dropdown, Firehose, LabelList, LoadingInline, navFactory, ResourceKebab, SectionHeading, ResourceIcon, ResourceLink, ResourceSummary, humanizeMem, MsgBox, StatusIcon, ExternalLink } from './utils'; +import { ActionsMenu, Kebab, Dropdown, Firehose, LabelList, LoadingInline, navFactory, ResourceKebab, SectionHeading, ResourceIcon, ResourceLink, ResourceSummary, humanizeBinaryBytes, MsgBox, StatusIcon, ExternalLink, humanizeCpuCores, humanizeDecimalBytes } from './utils'; import { createNamespaceModal, createProjectModal, deleteNamespaceModal, configureNamespacePullSecretModal } from './modals'; import { RoleBindingsPage } from './RBAC'; import { Bar, Line, requirePrometheus } from './graphs'; @@ -167,7 +167,7 @@ class PullSecret extends SafetyFirst { export const NamespaceLineCharts = ({ns}) =>
-
]} />
- ( title="Memory Usage by Pod (Top 10)" namespace={ns.metadata.name} query={`sort(topk(10, sum by (pod_name)(container_memory_usage_bytes{pod_name!="", namespace="${ns.metadata.name}"})))`} - humanize={humanizeMem} + humanize={humanizeBinaryBytes} metric="pod_name" /> ); diff --git a/frontend/public/components/node.tsx b/frontend/public/components/node.tsx index f9a1531ad5b2..621815bc92dd 100644 --- a/frontend/public/components/node.tsx +++ b/frontend/public/components/node.tsx @@ -8,7 +8,7 @@ import { ResourceEventStream } from './events'; import { ColHead, DetailsPage, List, ListHeader, ListPage, ResourceRow } from './factory'; import { configureUnschedulableModal } from './modals'; import { PodsPage } from './pod'; -import { Kebab, navFactory, LabelList, ResourceKebab, SectionHeading, ResourceLink, Timestamp, units, cloudProviderNames, cloudProviderID, pluralize, StatusIcon } from './utils'; +import { Kebab, navFactory, LabelList, ResourceKebab, SectionHeading, ResourceLink, Timestamp, units, cloudProviderNames, cloudProviderID, pluralize, StatusIcon, humanizeDecimalBytes, humanizeCpuCores } from './utils'; import { Line, requirePrometheus } from './graphs'; import { MachineModel, NodeModel } from '../models'; import { CamelCaseWrap } from './utils/camel-case-wrap'; @@ -104,22 +104,22 @@ const NodeGraphs = requirePrometheus(({node}) => { return
- +
- +
- +
- +
- +
diff --git a/frontend/public/components/pod.jsx b/frontend/public/components/pod.jsx index a42dcfd9ed77..694393181461 100644 --- a/frontend/public/components/pod.jsx +++ b/frontend/public/components/pod.jsx @@ -22,9 +22,11 @@ import { Timestamp, navFactory, units, + humanizeCpuCores, + humanizeDecimalBytes, } from './utils'; import { PodLogs } from './pod-logs'; -import { Line, requirePrometheus } from './graphs'; +import { requirePrometheus, Line } from './graphs'; import { breadcrumbsForOwnerRefs } from './utils/breadcrumbs'; import { formatDuration } from './utils/datetime'; import { CamelCaseWrap } from './utils/camel-case-wrap'; @@ -130,13 +132,13 @@ export const PodContainerTable = ({heading, containers, pod}) =>
- +
- +
- +
diff --git a/frontend/public/components/utils/datetime.ts b/frontend/public/components/utils/datetime.ts index 5befd3c40452..f25a480dd46d 100644 --- a/frontend/public/components/utils/datetime.ts +++ b/frontend/public/components/utils/datetime.ts @@ -150,3 +150,11 @@ export const parsePrometheusDuration = (duration: string): number => { return 0; } }; + +const zeroPad = (number: number) => number < 10 ? `0${number}` : number; + +export const twentyFourHourTime = (date: Date): string => { + const hours = zeroPad(date.getHours()); + const minutes = zeroPad(date.getMinutes()); + return `${hours}:${minutes}`; +}; diff --git a/frontend/public/components/utils/units.js b/frontend/public/components/utils/units.js index ad38cb66e627..01c2e52a9ae4 100644 --- a/frontend/public/components/utils/units.js +++ b/frontend/public/components/utils/units.js @@ -142,8 +142,10 @@ const humanize = units.humanize = (value, typeName, useRound = false) => { }; }; -export const humanizeMem = v => humanize(v, 'binaryBytes', true).string; +export const humanizeBinaryBytes = v => humanize(v, 'binaryBytes', true).string; +export const humanizeDecimalBytes = v => humanize(v, 'decimalBytes', true).string; export const humanizeNumber = v => humanize(v, 'numeric', true).string; +export const humanizeCpuCores = v => (v < 1 && v > 0) ? `${round(v*1000)}m` : `${round(v)}`; units.dehumanize = (value, typeName) => { const type = getType(typeName); diff --git a/frontend/yarn.lock b/frontend/yarn.lock index c7a41e563c95..2f8394284d83 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -123,6 +123,18 @@ version "1.0.219" resolved "https://registry.yarnpkg.com/@patternfly/patternfly/-/patternfly-1.0.219.tgz#3fb57ca7ec88437d78cd84f6e9563979f1081469" +"@patternfly/react-charts@^3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@patternfly/react-charts/-/react-charts-3.1.1.tgz#acc028d3b498b221a5c87478f7a1e42780450f4c" + integrity sha512-zDmB5e4in5Zc5KNM59rTNCsWie9paZqKfTOTvQyB+uIHdsSW2ax7VqITvL/haBYw2uFniyLftXsQu1W2b0lXSw== + dependencies: + "@patternfly/react-styles" "^3.0.2" + optionalDependencies: + "@types/victory" "^0.9.19" + hoist-non-react-statics "^3.1.0" + victory "^30.1.0" + victory-core "^31.1.0" + "@patternfly/react-core@2.4.1": version "2.4.1" resolved "https://registry.yarnpkg.com/@patternfly/react-core/-/react-core-2.4.1.tgz#3f2fedb160ed9451be5126b906bb8ec493146540" @@ -157,6 +169,24 @@ relative "^3.0.2" resolve-from "^4.0.0" +"@patternfly/react-styles@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@patternfly/react-styles/-/react-styles-3.0.2.tgz#39e453dc895a05062f32187163c831c94f4021a0" + integrity sha512-JiGxDkC4JArQJ13RQOjSUE4jPmwrAq8f5E+qg0tVws1A9BQ2l3uGCRFMVbfa57qqjqk0jXNmIVdFSeCG18qwJQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0-beta.48" + camel-case "^3.0.0" + css "^2.2.3" + cssom "^0.3.4" + cssstyle "^0.3.1" + emotion "^9.2.9" + emotion-server "^9.2.9" + fbjs-scripts "^0.8.3" + fs-extra "^6.0.1" + jsdom "^11.11.0" + relative "^3.0.2" + resolve-from "^4.0.0" + "@patternfly/react-tokens@^2.0.6": version "2.0.6" resolved "https://registry.yarnpkg.com/@patternfly/react-tokens/-/react-tokens-2.0.6.tgz#40f42a1e176541053478e5c462e22f5412bf2356" @@ -503,6 +533,13 @@ dependencies: source-map "^0.6.1" +"@types/victory@^0.9.19": + version "0.9.21" + resolved "https://registry.yarnpkg.com/@types/victory/-/victory-0.9.21.tgz#debf9b816134b36631cec746927cda87b16815e7" + integrity sha512-7A2dDRhPk2O5L4nCYw55I53uNX3G/PoLb41b0XclPFi98Bf8eA7Ov/LpmUlneSQY/3o2qbpPqJ2c8TLi3R8oJg== + dependencies: + "@types/react" "*" + "@types/webpack@^4.1.1": version "4.1.2" resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.1.2.tgz#96b45333201dd1526b85fbe18f1972f828f7e996" @@ -3450,9 +3487,10 @@ d3-array@1: version "1.2.1" resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.1.tgz#d1ca33de2f6ac31efadb8e050a021d7e2396d5dc" -d3-array@^1.2.1: +d3-array@^1.2.0, d3-array@^1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f" + integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw== d3-collection@1: version "1.0.4" @@ -3470,6 +3508,11 @@ d3-dispatch@1: version "1.0.3" resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.3.tgz#46e1491eaa9b58c358fce5be4e8bed626e7871f8" +d3-ease@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.5.tgz#8ce59276d81241b1b72042d6af2d40e76d936ffb" + integrity sha512-Ct1O//ly5y5lFM9YTdu+ygq7LleSgSE4oj7vUt9tPLHUi8VCV7QoizGpdWRWAwCO9LdYzIrQDg97+hGVdsSGPQ== + d3-force@^1.0.6: version "1.1.0" resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-1.1.0.tgz#cebf3c694f1078fcc3d4daf8e567b2fbd70d4ea3" @@ -3479,6 +3522,11 @@ d3-force@^1.0.6: d3-quadtree "1" d3-timer "1" +d3-format@1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.3.2.tgz#6a96b5e31bcb98122a30863f7d92365c00603562" + integrity sha512-Z18Dprj96ExragQ0DeGi+SYPQ7pPfRMtUXtsg/ChVIKNBCzjO8XYJvRTC1usblx52lqge56V5ect+frYTQc8WQ== + d3-hierarchy@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-1.1.8.tgz#7a6317bd3ed24e324641b6f1e76e978836b008cc" @@ -3489,9 +3537,17 @@ d3-interpolate@1: dependencies: d3-color "1" +d3-interpolate@^1.1.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.3.2.tgz#417d3ebdeb4bc4efcc8fd4361c55e4040211fd68" + integrity sha512-NlNKGopqaz9qM1PXh9gBF1KSCVh+jSFErrSlD/4hybwoNX/gt1d8CDbDW+3i+5UOHhjC6s6nMvRxcuoMVNgL2w== + dependencies: + d3-color "1" + d3-path@1: version "1.0.7" resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.7.tgz#8de7cd693a75ac0b5480d3abaccd94793e58aae8" + integrity sha512-q0cW1RpvA5c5ma2rch62mX8AYaiLX0+bdaSM2wxSU9tXjU4DNvkx9qiUvjkuWCj3p22UO/hlPivujqMiR9PDzA== d3-quadtree@1: version "1.0.3" @@ -3506,16 +3562,52 @@ d3-sankey-circular@0.33.0: d3-shape "^1.2.0" elementary-circuits-directed-graph "^1.0.4" -d3-shape@^1.2.0: +d3-scale@^1.0.0: + version "1.0.7" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-1.0.7.tgz#fa90324b3ea8a776422bd0472afab0b252a0945d" + integrity sha512-KvU92czp2/qse5tUfGms6Kjig0AhHOwkzXG0+PqIJB3ke0WUv088AHMZI0OssO9NCkXt4RP8yju9rpH8aGB7Lw== + dependencies: + d3-array "^1.2.0" + d3-collection "1" + d3-color "1" + d3-format "1" + d3-interpolate "1" + d3-time "1" + d3-time-format "2" + +d3-shape@^1.0.0, d3-shape@^1.2.0: version "1.3.5" resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.5.tgz#e81aea5940f59f0a79cfccac012232a8987c6033" + integrity sha512-VKazVR3phgD+MUCldapHD7P9kcrvPcexeX/PkMJmkUov4JM8IxsSg1DvbYoYich9AtdTsa5nNk2++ImPiDiSxg== dependencies: d3-path "1" +d3-time-format@2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.1.3.tgz#ae06f8e0126a9d60d6364eac5b1533ae1bac826b" + integrity sha512-6k0a2rZryzGm5Ihx+aFMuO1GgelgIz+7HhB4PH4OEndD5q2zGn1mDfRdNrulspOfR6JXkb2sThhDK41CSK85QA== + dependencies: + d3-time "1" + +d3-time@1: + version "1.0.11" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.0.11.tgz#1d831a3e25cd189eb256c17770a666368762bbce" + integrity sha512-Z3wpvhPLW4vEScGeIMUckDW7+3hWKOQfAWg/U7PlWBnQmeKQ00gCUsTtWSYulrKNA7ta8hJ+xXc6MHrMuITwEw== + d3-timer@1: version "1.0.7" resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.7.tgz#df9650ca587f6c96607ff4e60cc38229e8dd8531" +d3-timer@^1.0.0: + version "1.0.9" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.9.tgz#f7bb8c0d597d792ff7131e1c24a36dd471a471ba" + integrity sha512-rT34J5HnQUHhcLvhSB9GjCkN0Ddd5Y8nCwDBG2u6wQEeYxT/Lf51fTFFkldeib/sE/J0clIe0pnCfs6g/lRbyg== + +d3-voronoi@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/d3-voronoi/-/d3-voronoi-1.1.4.tgz#dd3c78d7653d2bb359284ae478645d95944c8297" + integrity sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg== + d3@^3.5.12, d3@~3.5.0, d3@~3.5.17: version "3.5.17" resolved "https://registry.yarnpkg.com/d3/-/d3-3.5.17.tgz#bc46748004378b21a360c9fc7cf5231790762fb8" @@ -6075,6 +6167,13 @@ hoist-non-react-statics@^2.1.1, hoist-non-react-statics@^2.3.1: version "2.5.5" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" +hoist-non-react-statics@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b" + integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA== + dependencies: + react-is "^16.7.0" + home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -10169,6 +10268,11 @@ react-dom@16.x: object-assign "^4.1.1" prop-types "^15.6.0" +react-fast-compare@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" + integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== + react-fontawesome@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/react-fontawesome/-/react-fontawesome-1.6.1.tgz#eddce17e7dc731aa09fd4a186688a61793a16c5c" @@ -10188,6 +10292,11 @@ react-is@^16.3.1, react-is@^16.3.2, react-is@^16.5.2: version "16.5.2" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.5.2.tgz#e2a7b7c3f5d48062eb769fcb123505eb928722e3" +react-is@^16.7.0: + version "16.8.6" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" + integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA== + react-jsonschema-form@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/react-jsonschema-form/-/react-jsonschema-form-1.0.4.tgz#e63a3ebffcf3987d0bfe8e05e2fae738fa5f6f19" @@ -13006,6 +13115,297 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +victory-area@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-area/-/victory-area-30.6.1.tgz#03f19be259b1da78f9ab5f7c1297b9ef7eccacad" + integrity sha512-Ksu0dnS2Ssiiuv/OH/1XK/a3M2D7to20JUkzVSyvm3m1HvKyvRCK4fDuBI2mXFWaX5iT2gJmqtVj6R22b+NOtg== + dependencies: + d3-shape "^1.2.0" + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-axis@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-axis/-/victory-axis-30.6.1.tgz#d9eae9b31ec8b78ad9f99383b54ab03f3bf7a0b2" + integrity sha512-SJFdMDYOLG9EfPovskomeXvb4VOJnTF//DvXCIcw6Ysy6sMpkwvWfpJVKgh9JAzELirW8OSU775f5BcwZ+z1xg== + dependencies: + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-bar@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-bar/-/victory-bar-30.6.1.tgz#04793a0c83cc77d695f94a92358a14eec5f1d657" + integrity sha512-P9v6OAz9w71+cTvRuRm43jtXV9Ag41bGn2RXf7nUgp1M0GFvaFQGujSILdSVsE8zEdyQLmwUxJRSz+s5b6CeSQ== + dependencies: + d3-shape "^1.2.0" + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-box-plot@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-box-plot/-/victory-box-plot-30.6.1.tgz#d82e726069d891dd0e54fed04bc75f112a212df4" + integrity sha512-2UVGOG+E4Nm0LLQyj3q13oAaE8vChAkrOZryTFFtDLZHVw5pUxDzZtWlgysna82tkJQA4vjlcq2h2lbZw9G1Rw== + dependencies: + d3-array "^1.2.0" + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-brush-container@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-brush-container/-/victory-brush-container-30.6.1.tgz#2db8c4f3d6e6facfafc69285e8cb6a2f94e2499e" + integrity sha512-V76eHU0Mn92DgOjnYJVHT+4skHkACBn2wQROd0E9ZFNqqyTa76U/ISD+4ihjNSqy0HfGdaHTjxcjL83E/EfONw== + dependencies: + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-brush-line@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-brush-line/-/victory-brush-line-30.6.1.tgz#d0cf8c32f55674fda8c1fcd16d548ea4e1119361" + integrity sha512-wOeIIPm8BDNqqDJQFfHe6txJ8JPWNKzHeQ6WTiwntw/IN8oLk4cwnbbW5yhQQC6rOniRFZH5iqb5V+zdCLUCWg== + dependencies: + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-candlestick@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-candlestick/-/victory-candlestick-30.6.1.tgz#14fa5220ce2ee766c721a71eff0ecab80528e6d1" + integrity sha512-cF0/jRU8LY14vBWHugU/5Ei1a+Lcc6u1k4o03m7ujKSsBffvVDnj4CN+nR9jwMMEMUeViBiVpY8HfhzFXVQ5KQ== + dependencies: + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-chart@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-chart/-/victory-chart-30.6.1.tgz#ee74341b6ec14ef7954161296e8f6e9f4e6c851f" + integrity sha512-JHP51QSJweuOQqMMqVim5u/vLKnvD3hjANpJdPPzthTrrmm1IPHAMLkUQ0m0tPiKsAf/5E49jDx4mDz7r6IK7w== + dependencies: + lodash "^4.17.5" + prop-types "^15.5.8" + react-fast-compare "^2.0.0" + victory-axis "^30.6.1" + victory-core "^30.6.1" + victory-polar-axis "^30.6.1" + victory-shared-events "^30.6.1" + +victory-core@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-core/-/victory-core-30.6.1.tgz#edb3eb6f8d48dc9953273e7f77fafdedeadf1460" + integrity sha512-oP5gHIVnpcp6I8oHPLDlIHqaEJ3lWMQHjwOTKr/ICsbabdtWBd0D8AByrV0qaXm8vgUmvyBhQqH2UCXb1Zh+jA== + dependencies: + d3-ease "^1.0.0" + d3-interpolate "^1.1.1" + d3-scale "^1.0.0" + d3-shape "^1.2.0" + d3-timer "^1.0.0" + lodash "^4.17.5" + prop-types "^15.5.8" + react-fast-compare "^2.0.0" + +victory-core@^31.1.0: + version "31.2.0" + resolved "https://registry.yarnpkg.com/victory-core/-/victory-core-31.2.0.tgz#c526abbeb8003460ac157419c13f9c1935a980f1" + integrity sha512-fKSJ2vKkvk6jc6ofBQ7/MbC2+r3Do7zeKfUnT7l4Z163kPDOWicA+wUdgMPlRtRv4J70z9tIENq8xMI22FMCpA== + dependencies: + d3-ease "^1.0.0" + d3-interpolate "^1.1.1" + d3-scale "^1.0.0" + d3-shape "^1.2.0" + d3-timer "^1.0.0" + lodash "^4.17.5" + prop-types "^15.5.8" + react-fast-compare "^2.0.0" + +victory-create-container@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-create-container/-/victory-create-container-30.6.1.tgz#f24f4f6269e11ef04a5f2d08831a347e5b01ccfc" + integrity sha512-Bm23Yk9xzdO8uCK99G+IFFclWx/vpDLea2vcW2MyHlTT2Iwa1HHW8UAYFfwr6858LYMaOa/Y9UV/YvP+twctoA== + dependencies: + lodash "^4.17.5" + victory-brush-container "^30.6.1" + victory-core "^30.6.1" + victory-cursor-container "^30.6.1" + victory-selection-container "^30.6.1" + victory-voronoi-container "^30.6.1" + victory-zoom-container "^30.6.1" + +victory-cursor-container@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-cursor-container/-/victory-cursor-container-30.6.1.tgz#054ba4a9caf3b32a4b467d77a9c0b0410f54a06e" + integrity sha512-XjmLUdQWEiv8F+AwfpVvi3kETJz7OCWlpkypbiIJjLvYM8lUeT84boOftMfyw+HRjUAxPQFh1D7yBUvAqrwKiA== + dependencies: + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-errorbar@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-errorbar/-/victory-errorbar-30.6.1.tgz#bee14bf0c0853ad841454ec060b290f7588dd7a2" + integrity sha512-SBowNqH5MBh1GoqA3UF5YVsFB0h0o60IkR5Yjhe/uaGhwyZVAu5X9+BE0CXRq0uDLhOX9GDvqDs59hAe0D3xiw== + dependencies: + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-group@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-group/-/victory-group-30.6.1.tgz#59a55858750a3f880860ebe64faf0b21575f3da4" + integrity sha512-fGt6/+GgsBqFiuzVdzQHRc2joYEDL9Bo2wE8rCH5HAUnj/oI6drKi8euooUpBOIhbOQeycCj7r6BXJvp8H9CfQ== + dependencies: + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-legend@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-legend/-/victory-legend-30.6.1.tgz#9f411b07915f058ed17b061e274c622b426e4c08" + integrity sha512-iadVJSaj+mhT9Crx2eYMF39qTyvn03B5p44OjeLqKcvb0MDElVDsXyYHTwsUgnE4i+YPOFz9+buMaw2UWXU0NA== + dependencies: + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-line@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-line/-/victory-line-30.6.1.tgz#ce43f4d68b0faea28025881580b6b3914b427950" + integrity sha512-JmL17SK4bLkhQEelDoj6QK9KLF8o5uW0aNNxdhSqluFxROLtuixUzvffEYlN0weHCkIR6f/o2PqbujLVtoxOOg== + dependencies: + d3-shape "^1.2.0" + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-pie@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-pie/-/victory-pie-30.6.1.tgz#f791286fb9e57b5e575ec51ea5b4275a4aa7d68d" + integrity sha512-03jIWh/+17j7FX21KSNWSglhb50DqJQ9Jy5+nVAEcTlhIiI3bffuDd9IvoCfXMMwDmoRvaRq1xtXSElq4jZYpw== + dependencies: + d3-shape "^1.0.0" + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-polar-axis@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-polar-axis/-/victory-polar-axis-30.6.1.tgz#a8b13e9210627abe70605bf7d8e11d34d66cf632" + integrity sha512-OQIAKURdTdmOk/rXr+DNeE9xoROEOqmAdanTYXdpeazbYiClSbhcbIypK0Z7qyGziIV8D8W4r4at/mAMA9AkXQ== + dependencies: + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-scatter@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-scatter/-/victory-scatter-30.6.1.tgz#96797fefff3d31ede944e95ac51682846705a1a8" + integrity sha512-UsIne7V/LruhkA5r+BqUa4MNuMGSgOgPyklOOyKur1jrYm83kE3t0T7ObiTrFBLsL7SqVnmxARXW66Lv2GWE+g== + dependencies: + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-selection-container@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-selection-container/-/victory-selection-container-30.6.1.tgz#627148c84ae43472682c9f135487035cbdadf6d4" + integrity sha512-ihv1aGOwu3IX/v94IRawMAlWRMlt/BogrU28FXhhVMdqXemPFkq3J9COq0khGhh+wuqtC1tu9Ni7uw4YA3fdZg== + dependencies: + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-shared-events@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-shared-events/-/victory-shared-events-30.6.1.tgz#788e6c45a752c521a3f067675b9b9196fcee552c" + integrity sha512-4zQ6gfkrQVNtx+bUv+kgNNtVX5Mr6T68Hs2xV4H0f3FrToyFrsXtANGFhAzgmi+00Mk06FVIAIY94tZW3Cej1Q== + dependencies: + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-stack@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-stack/-/victory-stack-30.6.1.tgz#873be79c492f0d7ed02ad03bd82e592d6f778ea8" + integrity sha512-WJk9FIe/GuqXaZsB+vZSTbgIyg53I6cwCtyMvh4Jj3iFWHuRmpVaT7vwJ46/I2WOKLvQWyd0EY380kby5PNUVg== + dependencies: + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-tooltip@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-tooltip/-/victory-tooltip-30.6.1.tgz#234e23954c9b4543cee22ac45f9b91325207fe42" + integrity sha512-Mezqycvoxms6ON6ftBKU8TpB8Ggsiy+1gJREeOt83TfvrIp8DKher33kj83ofD853rPcmRJeMNAz57I1mpXtHA== + dependencies: + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-voronoi-container@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-voronoi-container/-/victory-voronoi-container-30.6.1.tgz#58a16af999e0c6ff528905aec812c2fdd5b93dff" + integrity sha512-rHT7rgYLuetgi67CFyM8N3AgomzNi1/tjjUKC2SmD2qq8bBysVXlyzTh2Zx4aTLVX59XNNGAaLxPjUjkZWYY2g== + dependencies: + d3-voronoi "^1.1.2" + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + victory-tooltip "^30.6.1" + +victory-voronoi@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-voronoi/-/victory-voronoi-30.6.1.tgz#d3de9db4997778f2f8acd0427bab14898e137b9e" + integrity sha512-bxzYmGROFYtpP3EmmcKwHMDAvpIVNYK+7LNOuYwu0z/IHBT//K2EplWAV90IYIvTdKVT75lgqiYsFOWY78L2yw== + dependencies: + d3-voronoi "^1.1.2" + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory-zoom-container@^30.6.1: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory-zoom-container/-/victory-zoom-container-30.6.1.tgz#41ee41e4168f311375508d2ed1b8581f2b437bb6" + integrity sha512-F/b2l6LJjkR1OF+ioU49yGDW0rJJusKqrOFtcSDbnyeSwKkQGkgJ0T+Nv/TN5jSBdC3Wb/kKtwqHRYCrxtt3Zg== + dependencies: + lodash "^4.17.5" + prop-types "^15.5.8" + victory-core "^30.6.1" + +victory@^30.1.0: + version "30.6.1" + resolved "https://registry.yarnpkg.com/victory/-/victory-30.6.1.tgz#607a0ca643bf4f4a32a08a4a4e1a84d601611159" + integrity sha512-VJAFvZz4s6qT3KhDKLv9qMKtSwLjbRZiuK917KrfomTLYcjMgrA1FckW/8nIn1URwNdkawe4YvgAE0wdtbDO3A== + dependencies: + victory-area "^30.6.1" + victory-axis "^30.6.1" + victory-bar "^30.6.1" + victory-box-plot "^30.6.1" + victory-brush-container "^30.6.1" + victory-brush-line "^30.6.1" + victory-candlestick "^30.6.1" + victory-chart "^30.6.1" + victory-core "^30.6.1" + victory-create-container "^30.6.1" + victory-cursor-container "^30.6.1" + victory-errorbar "^30.6.1" + victory-group "^30.6.1" + victory-legend "^30.6.1" + victory-line "^30.6.1" + victory-pie "^30.6.1" + victory-polar-axis "^30.6.1" + victory-scatter "^30.6.1" + victory-selection-container "^30.6.1" + victory-shared-events "^30.6.1" + victory-stack "^30.6.1" + victory-tooltip "^30.6.1" + victory-voronoi "^30.6.1" + victory-voronoi-container "^30.6.1" + victory-zoom-container "^30.6.1" + vinyl-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-2.0.0.tgz#a7ebf5ffbefda1b7d18d140fcb07b223efb6751a"