From 642374de25c539366d139c4aa2ec686fd60dde20 Mon Sep 17 00:00:00 2001 From: David Kaltschmidt Date: Sun, 5 Aug 2018 23:07:05 +0200 Subject: [PATCH] Explore: Metrics chooser for prometheus - load all histogrammable metrics on start, based on `{le!=''}` series query - select dropdown shows all those metrics as well as histograms in a special group - select a metric will write fill the metric in the query box - if a histogram is chosen, it will write a complete `histogram_quantile` query - added new dependency: rc-cascader --- package.json | 3 +- public/app/containers/Explore/Explore.tsx | 2 +- .../app/containers/Explore/PromQueryField.tsx | 118 +++++++++++-- public/app/containers/Explore/QueryRows.tsx | 33 ++-- public/sass/_grafana.scss | 1 + public/sass/pages/_explore.scss | 13 ++ public/vendor/css/rc-cascader.css | 158 ++++++++++++++++++ yarn.lock | 123 +++++++++++++- 8 files changed, 411 insertions(+), 40 deletions(-) create mode 100644 public/vendor/css/rc-cascader.css diff --git a/package.json b/package.json index c0581c1de43..200285d7a1e 100644 --- a/package.json +++ b/package.json @@ -166,6 +166,7 @@ "mousetrap-global-bind": "^1.1.0", "prismjs": "^1.6.0", "prop-types": "^15.6.0", + "rc-cascader": "^0.14.0", "react": "^16.2.0", "react-dom": "^16.2.0", "react-grid-layout": "0.16.6", @@ -187,4 +188,4 @@ "resolutions": { "caniuse-db": "1.0.30000772" } -} \ No newline at end of file +} diff --git a/public/app/containers/Explore/Explore.tsx b/public/app/containers/Explore/Explore.tsx index b21a78ed8ab..3ee5bceae8b 100644 --- a/public/app/containers/Explore/Explore.tsx +++ b/public/app/containers/Explore/Explore.tsx @@ -208,7 +208,7 @@ export class Explore extends React.Component { }; const nextQueries = [...queries]; nextQueries[index] = nextQuery; - this.setState({ queries: nextQueries }); + this.setState({ queries: nextQueries }, override ? () => this.onSubmit() : undefined); }; onChangeTime = nextRange => { diff --git a/public/app/containers/Explore/PromQueryField.tsx b/public/app/containers/Explore/PromQueryField.tsx index 68f31d8ffd6..aab31584fd5 100644 --- a/public/app/containers/Explore/PromQueryField.tsx +++ b/public/app/containers/Explore/PromQueryField.tsx @@ -2,6 +2,7 @@ import _ from 'lodash'; import moment from 'moment'; import React from 'react'; import { Value } from 'slate'; +import Cascader from 'rc-cascader'; // dom also includes Element polyfills import { getNextCharacter, getPreviousCousin } from './utils/dom'; @@ -21,12 +22,14 @@ import TypeaheadField, { const DEFAULT_KEYS = ['job', 'instance']; const EMPTY_SELECTOR = '{}'; +const HISTOGRAM_GROUP = '__histograms__'; +const HISTOGRAM_SELECTOR = '{le!=""}'; // Returns all timeseries for histograms const HISTORY_ITEM_COUNT = 5; const HISTORY_COUNT_CUTOFF = 1000 * 60 * 60 * 24; // 24h const METRIC_MARK = 'metric'; const PRISM_LANGUAGE = 'promql'; -export const wrapLabel = label => ({ label }); +export const wrapLabel = (label: string) => ({ label }); export const setFunctionMove = (suggestion: Suggestion): Suggestion => { suggestion.move = -1; return suggestion; @@ -48,6 +51,22 @@ export function addHistoryMetadata(item: Suggestion, history: any[]): Suggestion }; } +export function groupMetricsByPrefix(metrics: string[], delimiter = '_'): CascaderOption[] { + return _.chain(metrics) + .groupBy(metric => metric.split(delimiter)[0]) + .map((metricsForPrefix: string[], prefix: string): CascaderOption => { + const prefixIsMetric = metricsForPrefix.length === 1 && metricsForPrefix[0] === prefix; + const children = prefixIsMetric ? [] : metricsForPrefix.sort().map(m => ({ label: m, value: m })); + return { + children, + label: prefix, + value: prefix, + }; + }) + .sortBy('label') + .value(); +} + export function willApplySuggestion( suggestion: string, { typeaheadContext, typeaheadText }: TypeaheadFieldState @@ -78,22 +97,33 @@ export function willApplySuggestion( return suggestion; } +interface CascaderOption { + label: string; + value: string; + children?: CascaderOption[]; + disabled?: boolean; +} + interface PromQueryFieldProps { history?: any[]; + histogramMetrics?: string[]; initialQuery?: string | null; labelKeys?: { [index: string]: string[] }; // metric -> [labelKey,...] labelValues?: { [index: string]: { [index: string]: string[] } }; // metric -> labelKey -> [labelValue,...] metrics?: string[]; + metricsByPrefix?: CascaderOption[]; onPressEnter?: () => void; - onQueryChange?: (value: string) => void; + onQueryChange?: (value: string, override?: boolean) => void; portalPrefix?: string; request?: (url: string) => any; } interface PromQueryFieldState { + histogramMetrics: string[]; labelKeys: { [index: string]: string[] }; // metric -> [labelKey,...] labelValues: { [index: string]: { [index: string]: string[] } }; // metric -> labelKey -> [labelValue,...] metrics: string[]; + metricsByPrefix: CascaderOption[]; } interface PromTypeaheadInput { @@ -107,7 +137,7 @@ interface PromTypeaheadInput { class PromQueryField extends React.Component { plugins: any[]; - constructor(props, context) { + constructor(props: PromQueryFieldProps, context) { super(props, context); this.plugins = [ @@ -117,21 +147,45 @@ class PromQueryField extends React.Component { + onChangeMetrics = (values: string[], selectedOptions: CascaderOption[]) => { + let query; + if (selectedOptions.length === 1) { + if (selectedOptions[0].children.length === 0) { + query = selectedOptions[0].value; + } else { + // Ignore click on group + return; + } + } else { + const prefix = selectedOptions[0].value; + const metric = selectedOptions[1].value; + if (prefix === HISTOGRAM_GROUP) { + query = `histogram_quantile(0.95, sum(rate(${metric}[5m])) by (le))`; + } else { + query = metric; + } + } + this.onChangeQuery(query, true); + }; + + onChangeQuery = (value: string, override?: boolean) => { // Send text change to parent const { onQueryChange } = this.props; if (onQueryChange) { - onQueryChange(value); + onQueryChange(value, override); } }; @@ -317,7 +371,17 @@ class PromQueryField extends React.Component { + const histogramSeries = this.state.labelValues[HISTOGRAM_SELECTOR]; + if (histogramSeries && histogramSeries['__name__']) { + const histogramMetrics = histogramSeries['__name__'].slice().sort(); + this.setState({ histogramMetrics }); + } + }); + } + + async fetchLabelValues(key: string) { const url = `/api/v1/label/${key}/values`; try { const res = await this.request(url); @@ -337,7 +401,7 @@ class PromQueryField extends React.Component void) { const url = `/api/v1/series?match[]=${name}`; try { const res = await this.request(url); @@ -351,7 +415,7 @@ class PromQueryField extends React.Component ({ label: hm, value: hm })); + const metricsOptions = [ + { label: 'Histograms', value: HISTOGRAM_GROUP, children: histogramOptions }, + ...metricsByPrefix, + ]; + return ( - +
+
+ + + +
+
+ +
+
); } } diff --git a/public/app/containers/Explore/QueryRows.tsx b/public/app/containers/Explore/QueryRows.tsx index d076d3fd057..cd3cf23a927 100644 --- a/public/app/containers/Explore/QueryRows.tsx +++ b/public/app/containers/Explore/QueryRows.tsx @@ -3,10 +3,10 @@ import React, { PureComponent } from 'react'; import QueryField from './PromQueryField'; class QueryRow extends PureComponent { - onChangeQuery = value => { + onChangeQuery = (value, override?: boolean) => { const { index, onChangeQuery } = this.props; if (onChangeQuery) { - onChangeQuery(value, index); + onChangeQuery(value, index, override); } }; @@ -18,10 +18,7 @@ class QueryRow extends PureComponent { }; onClickClearButton = () => { - const { index, onChangeQuery } = this.props; - if (onChangeQuery) { - onChangeQuery('', index, true); - } + this.onChangeQuery('', true); }; onClickRemoveButton = () => { @@ -42,18 +39,7 @@ class QueryRow extends PureComponent { const { edited, history, query, request } = this.props; return (
-
- - - -
-
+
{ request={request} />
+
+ + + +
); } diff --git a/public/sass/_grafana.scss b/public/sass/_grafana.scss index 3a72bd45a1a..ec7103cba95 100644 --- a/public/sass/_grafana.scss +++ b/public/sass/_grafana.scss @@ -1,6 +1,7 @@ // vendor @import '../vendor/css/timepicker.css'; @import '../vendor/css/spectrum.css'; +@import '../vendor/css/rc-cascader.css'; // MIXINS @import 'mixins/mixins'; diff --git a/public/sass/pages/_explore.scss b/public/sass/pages/_explore.scss index b08b0db42c8..6d7ce5a6b61 100644 --- a/public/sass/pages/_explore.scss +++ b/public/sass/pages/_explore.scss @@ -110,6 +110,11 @@ width: 6rem; } +.query-row-field { + margin-right: 3px; + width: 100%; +} + .explore { .logs { .logs-entries { @@ -146,3 +151,11 @@ } } } + +// Prometheus-specifics, to be extracted to datasource soon + +.explore { + .prom-query-field { + display: flex; + } +} diff --git a/public/vendor/css/rc-cascader.css b/public/vendor/css/rc-cascader.css new file mode 100644 index 00000000000..968c1fc770f --- /dev/null +++ b/public/vendor/css/rc-cascader.css @@ -0,0 +1,158 @@ +.rc-cascader { + font-size: 12px; +} +.rc-cascader-menus { + font-size: 12px; + overflow: hidden; + background: #fff; + position: absolute; + border: 1px solid #d9d9d9; + border-radius: 6px; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.17); + white-space: nowrap; +} +.rc-cascader-menus-hidden { + display: none; +} +.rc-cascader-menus.slide-up-enter, +.rc-cascader-menus.slide-up-appear { + animation-duration: .3s; + animation-fill-mode: both; + transform-origin: 0 0; + opacity: 0; + animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1); + animation-play-state: paused; +} +.rc-cascader-menus.slide-up-leave { + animation-duration: .3s; + animation-fill-mode: both; + transform-origin: 0 0; + opacity: 1; + animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34); + animation-play-state: paused; +} +.rc-cascader-menus.slide-up-enter.slide-up-enter-active.rc-cascader-menus-placement-bottomLeft, +.rc-cascader-menus.slide-up-appear.slide-up-appear-active.rc-cascader-menus-placement-bottomLeft { + animation-name: SlideUpIn; + animation-play-state: running; +} +.rc-cascader-menus.slide-up-enter.slide-up-enter-active.rc-cascader-menus-placement-topLeft, +.rc-cascader-menus.slide-up-appear.slide-up-appear-active.rc-cascader-menus-placement-topLeft { + animation-name: SlideDownIn; + animation-play-state: running; +} +.rc-cascader-menus.slide-up-leave.slide-up-leave-active.rc-cascader-menus-placement-bottomLeft { + animation-name: SlideUpOut; + animation-play-state: running; +} +.rc-cascader-menus.slide-up-leave.slide-up-leave-active.rc-cascader-menus-placement-topLeft { + animation-name: SlideDownOut; + animation-play-state: running; +} +.rc-cascader-menu { + display: inline-block; + /* width: 100px; */ + max-width: 50vw; + height: 192px; + list-style: none; + margin: 0; + padding: 0; + border-right: 1px solid #e9e9e9; + overflow: auto; +} +.rc-cascader-menu:last-child { + border-right: 0; +} +.rc-cascader-menu-item { + height: 32px; + line-height: 32px; + padding: 0 16px; + cursor: pointer; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + transition: all 0.3s ease; + position: relative; +} +.rc-cascader-menu-item:hover { + background: #eaf8fe; +} +.rc-cascader-menu-item-disabled { + cursor: not-allowed; + color: #ccc; +} +.rc-cascader-menu-item-disabled:hover { + background: transparent; +} +.rc-cascader-menu-item-loading:after { + position: absolute; + right: 12px; + content: 'loading'; + color: #aaa; + font-style: italic; +} +.rc-cascader-menu-item-active { + background: #d5f1fd; +} +.rc-cascader-menu-item-active:hover { + background: #d5f1fd; +} +.rc-cascader-menu-item-expand { + position: relative; +} +.rc-cascader-menu-item-expand:after { + content: '>'; + font-size: 12px; + color: #999; + position: absolute; + right: 16px; + line-height: 32px; +} +@keyframes SlideUpIn { + 0% { + opacity: 0; + transform-origin: 0% 0%; + transform: scaleY(0.8); + } + 100% { + opacity: 1; + transform-origin: 0% 0%; + transform: scaleY(1); + } +} +@keyframes SlideUpOut { + 0% { + opacity: 1; + transform-origin: 0% 0%; + transform: scaleY(1); + } + 100% { + opacity: 0; + transform-origin: 0% 0%; + transform: scaleY(0.8); + } +} +@keyframes SlideDownIn { + 0% { + opacity: 0; + transform-origin: 0% 100%; + transform: scaleY(0.8); + } + 100% { + opacity: 1; + transform-origin: 0% 100%; + transform: scaleY(1); + } +} +@keyframes SlideDownOut { + 0% { + opacity: 1; + transform-origin: 0% 100%; + transform: scaleY(1); + } + 100% { + opacity: 0; + transform-origin: 0% 100%; + transform: scaleY(0.8); + } +} diff --git a/yarn.lock b/yarn.lock index 6e737e33348..ed8a1eabec3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -478,6 +478,12 @@ acorn@~2.6.4: version "2.6.4" resolved "https://registry.yarnpkg.com/acorn/-/acorn-2.6.4.tgz#eb1f45b4a43fa31d03701a5ec46f3b52673e90ee" +add-dom-event-listener@1.x: + version "1.0.2" + resolved "https://registry.yarnpkg.com/add-dom-event-listener/-/add-dom-event-listener-1.0.2.tgz#8faed2c41008721cf111da1d30d995b85be42bed" + dependencies: + object-assign "4.x" + after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" @@ -771,6 +777,10 @@ array-slice@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" +array-tree-filter@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-tree-filter/-/array-tree-filter-1.0.1.tgz#0a8ad1eefd38ce88858632f9cc0423d7634e4d5d" + array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -1514,7 +1524,7 @@ babel-register@^6.26.0, babel-register@^6.9.0: mkdirp "^0.5.1" source-map-support "^0.4.15" -babel-runtime@^6.0.0, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0, babel-runtime@^6.9.2: +babel-runtime@6.x, babel-runtime@^6.0.0, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0, babel-runtime@^6.9.2: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: @@ -2246,6 +2256,10 @@ classnames@2.x, classnames@^2.2.4, classnames@^2.2.5: version "2.2.5" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" +classnames@^2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" + clean-css@3.4.x, clean-css@~3.4.2: version "3.4.28" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.28.tgz#bf1945e82fc808f55695e6ddeaec01400efd03ff" @@ -2553,6 +2567,12 @@ component-bind@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" +component-classes@^1.2.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/component-classes/-/component-classes-1.2.6.tgz#c642394c3618a4d8b0b8919efccbbd930e5cd691" + dependencies: + component-indexof "0.0.3" + component-emitter@1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" @@ -2561,6 +2581,10 @@ component-emitter@1.2.1, component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" +component-indexof@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/component-indexof/-/component-indexof-0.0.3.tgz#11d091312239eb8f32c8f25ae9cb002ffe8d3c24" + component-inherit@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" @@ -2841,6 +2865,13 @@ crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" +css-animation@^1.3.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/css-animation/-/css-animation-1.4.1.tgz#5b8813125de0fbbbb0bbe1b472ae84221469b7a8" + dependencies: + babel-runtime "6.x" + component-classes "^1.2.5" + css-color-names@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" @@ -3515,6 +3546,10 @@ doctrine@^1.2.2: esutils "^2.0.2" isarray "^1.0.0" +dom-align@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/dom-align/-/dom-align-1.8.0.tgz#c0e89b5b674c6e836cd248c52c2992135f093654" + dom-converter@~0.1: version "0.1.4" resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.1.4.tgz#a45ef5727b890c9bffe6d7c876e7b19cb0e17f3b" @@ -7354,6 +7389,10 @@ lodash._createset@~4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + lodash._root@~3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" @@ -7386,6 +7425,14 @@ lodash.flattendeep@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + lodash.isequal@^4.0.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" @@ -7406,6 +7453,14 @@ lodash.kebabcase@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" +lodash.keys@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -8651,7 +8706,7 @@ object-assign@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@4.x, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -9981,6 +10036,54 @@ raw-body@2.3.3: iconv-lite "0.4.23" unpipe "1.0.0" +rc-align@^2.4.0: + version "2.4.3" + resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-2.4.3.tgz#b9b3c2a6d68adae71a8e1d041cd5e3b2a655f99a" + dependencies: + babel-runtime "^6.26.0" + dom-align "^1.7.0" + prop-types "^15.5.8" + rc-util "^4.0.4" + +rc-animate@2.x: + version "2.4.4" + resolved "https://registry.yarnpkg.com/rc-animate/-/rc-animate-2.4.4.tgz#a05a784c747beef140d99ff52b6117711bef4b1e" + dependencies: + babel-runtime "6.x" + css-animation "^1.3.2" + prop-types "15.x" + +rc-cascader@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/rc-cascader/-/rc-cascader-0.14.0.tgz#a956c99896f10883bf63d46fb894d0cb326842a4" + dependencies: + array-tree-filter "^1.0.0" + prop-types "^15.5.8" + rc-trigger "^2.2.0" + rc-util "^4.0.4" + shallow-equal "^1.0.0" + warning "^4.0.1" + +rc-trigger@^2.2.0: + version "2.5.4" + resolved "https://registry.yarnpkg.com/rc-trigger/-/rc-trigger-2.5.4.tgz#9088a24ba5a811b254f742f004e38a9e2f8843fb" + dependencies: + babel-runtime "6.x" + classnames "^2.2.6" + prop-types "15.x" + rc-align "^2.4.0" + rc-animate "2.x" + rc-util "^4.4.0" + +rc-util@^4.0.4, rc-util@^4.4.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-4.5.1.tgz#0e435057174c024901c7600ba8903dd03da3ab39" + dependencies: + add-dom-event-listener "1.x" + babel-runtime "6.x" + prop-types "^15.5.10" + shallowequal "^0.2.2" + rc@^1.0.1, rc@^1.1.6, rc@^1.1.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -10980,6 +11083,16 @@ shallow-clone@^1.0.0: kind-of "^5.0.0" mixin-object "^2.0.1" +shallow-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.0.0.tgz#508d1838b3de590ab8757b011b25e430900945f7" + +shallowequal@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-0.2.2.tgz#1e32fd5bcab6ad688a4812cb0cc04efc75c7014e" + dependencies: + lodash.keys "^3.1.2" + shallowequal@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.0.2.tgz#1561dbdefb8c01408100319085764da3fcf83f8f" @@ -12555,6 +12668,12 @@ walker@~1.0.5: dependencies: makeerror "1.0.x" +warning@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.1.tgz#66ce376b7fbfe8a887c22bdf0e7349d73d397745" + dependencies: + loose-envify "^1.0.0" + watch@~0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986"