[Uptime] Added date range filter into expanded list query (#52609) (#54453)

* added filters into expanded list query

* update filters

* update query

* update snap

* update tests

* update filters

* update test

* remove side effect

* ignore typcehck

* update to remove location filter from query

* update filter groups

* remove code

* update test
This commit is contained in:
Shahzad 2020-01-10 19:17:50 +01:00 committed by GitHub
parent decf467d4c
commit 921e9332b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 205 additions and 161 deletions

View file

@ -239,7 +239,7 @@
"react-use": "^13.13.0",
"reactcss": "1.2.3",
"redux": "4.0.0",
"redux-actions": "2.2.1",
"redux-actions": "2.6.5",
"redux-thunk": "2.3.0",
"regenerator-runtime": "^0.13.3",
"regression": "2.0.1",
@ -351,7 +351,7 @@
"@types/react-router-dom": "^5.1.3",
"@types/react-virtualized": "^9.18.7",
"@types/redux": "^3.6.31",
"@types/redux-actions": "^2.2.1",
"@types/redux-actions": "^2.6.1",
"@types/request": "^2.48.2",
"@types/selenium-webdriver": "^4.0.5",
"@types/semver": "^5.5.0",

View file

@ -8,11 +8,12 @@ import { MonitorSummary, Check } from '../../../../../../common/graphql/types';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import React from 'react';
import { MonitorListDrawerComponent } from '../monitor_list_drawer';
import { MonitorDetails } from '../../../../../../common/runtime_types';
describe('MonitorListDrawer component', () => {
let summary: MonitorSummary;
let loadMonitorDetails: any;
let monitorDetails: any;
let monitorDetails: MonitorDetails;
beforeEach(() => {
summary = {

View file

@ -6,7 +6,6 @@
import React, { useEffect } from 'react';
import { EuiLink, EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiText } from '@elastic/eui';
import { get } from 'lodash';
import styled from 'styled-components';
import { connect } from 'react-redux';
import { MonitorSummary } from '../../../../../common/graphql/types';
@ -16,6 +15,8 @@ import { MostRecentError } from './most_recent_error';
import { getMonitorDetails } from '../../../../state/selectors';
import { MonitorStatusList } from './monitor_status_list';
import { MonitorDetails } from '../../../../../common/runtime_types';
import { useUrlParams } from '../../../../hooks';
import { MonitorDetailsActionPayload } from '../../../../state/actions/types';
import { MonitorListActionsPopover } from '../monitor_list_actions_popover';
const ContainerDiv = styled.div`
@ -50,19 +51,20 @@ export function MonitorListDrawerComponent({
monitorDetails,
}: MonitorListDrawerProps) {
const monitorId = summary?.monitor_id;
const [getUrlParams] = useUrlParams();
const { dateRangeStart: dateStart, dateRangeEnd: dateEnd } = getUrlParams();
useEffect(() => {
if (monitorId) {
loadMonitorDetails(monitorId);
}
}, [loadMonitorDetails, monitorId]);
loadMonitorDetails({
dateStart,
dateEnd,
monitorId,
});
}, [dateStart, dateEnd, monitorId, loadMonitorDetails]);
if (!summary || !summary.state.checks) {
return null;
}
const monitorUrl = summary?.state?.url?.full || '';
const monitorUrl: string | undefined = get(summary.state.url, 'full', undefined);
return (
return summary && summary.state.checks ? (
<ContainerDiv>
<EuiFlexGroup>
<EuiFlexItem grow={true}>
@ -87,7 +89,7 @@ export function MonitorListDrawerComponent({
/>
)}
</ContainerDiv>
);
) : null;
}
const mapStateToProps = (state: AppState, { summary }: any) => ({
@ -95,7 +97,8 @@ const mapStateToProps = (state: AppState, { summary }: any) => ({
});
const mapDispatchToProps = (dispatch: any) => ({
loadMonitorDetails: (monitorId: string) => dispatch(fetchMonitorDetails(monitorId)),
loadMonitorDetails: (actionPayload: MonitorDetailsActionPayload) =>
dispatch(fetchMonitorDetails(actionPayload)),
});
export const MonitorListDrawer = connect(

View file

@ -4,6 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { MonitorDetailsActionPayload } from './types';
import { MonitorError } from '../../../common/runtime_types';
import { MonitorLocations } from '../../../common/runtime_types';
import { QueryParams } from './types';
@ -17,12 +19,12 @@ export const FETCH_MONITOR_LOCATIONS_FAIL = 'FETCH_MONITOR_LOCATIONS_FAIL';
export interface MonitorDetailsState {
monitorId: string;
error: Error;
error: MonitorError;
}
interface GetMonitorDetailsAction {
type: typeof FETCH_MONITOR_DETAILS;
payload: string;
payload: MonitorDetailsActionPayload;
}
interface GetMonitorDetailsSuccessAction {
@ -54,10 +56,10 @@ interface GetMonitorLocationsFailAction {
payload: any;
}
export function fetchMonitorDetails(monitorId: string): GetMonitorDetailsAction {
export function fetchMonitorDetails(payload: MonitorDetailsActionPayload): GetMonitorDetailsAction {
return {
type: FETCH_MONITOR_DETAILS,
payload: monitorId,
payload,
};
}

View file

@ -10,3 +10,10 @@ export interface QueryParams {
filters?: string;
statusFilter?: string;
}
export interface MonitorDetailsActionPayload {
monitorId: string;
dateStart: string;
dateEnd: string;
location?: string;
}

View file

@ -3,53 +3,19 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
export const SET_INTEGRATION_POPOVER_STATE = 'SET_INTEGRATION_POPOVER_STATE';
export const SET_BASE_PATH = 'SET_BASE_PATH';
export const REFRESH_APP = 'REFRESH_APP';
import { createAction } from 'redux-actions';
export interface PopoverState {
id: string;
open: boolean;
}
interface SetBasePathAction {
type: typeof SET_BASE_PATH;
payload: string;
}
export type UiPayload = PopoverState & string & number & Map<string, string[]>;
interface SetIntegrationPopoverAction {
type: typeof SET_INTEGRATION_POPOVER_STATE;
payload: PopoverState;
}
export const setBasePath = createAction<string>('SET BASE PATH');
interface TriggerAppRefreshAction {
type: typeof REFRESH_APP;
payload: number;
}
export const triggerAppRefresh = createAction<number>('REFRESH APP');
export type UiActionTypes =
| SetIntegrationPopoverAction
| SetBasePathAction
| TriggerAppRefreshAction;
export function toggleIntegrationsPopover(popoverState: PopoverState): SetIntegrationPopoverAction {
return {
type: SET_INTEGRATION_POPOVER_STATE,
payload: popoverState,
};
}
export function setBasePath(basePath: string): SetBasePathAction {
return {
type: SET_BASE_PATH,
payload: basePath,
};
}
export function triggerAppRefresh(refreshTime: number): TriggerAppRefreshAction {
return {
type: REFRESH_APP,
payload: refreshTime,
};
}
export const toggleIntegrationsPopover = createAction<PopoverState>(
'TOGGLE INTEGRATION POPOVER STATE'
);

View file

@ -6,6 +6,7 @@
import { ThrowReporter } from 'io-ts/lib/ThrowReporter';
import { getApiPath } from '../../lib/helper';
import { BaseParams } from './types';
import {
MonitorDetailsType,
MonitorDetails,
@ -19,12 +20,23 @@ interface ApiRequest {
basePath: string;
}
export type MonitorQueryParams = BaseParams & ApiRequest;
export const fetchMonitorDetails = async ({
monitorId,
basePath,
}: ApiRequest): Promise<MonitorDetails> => {
const url = getApiPath(`/api/uptime/monitor/details?monitorId=${monitorId}`, basePath);
const response = await fetch(url);
dateStart,
dateEnd,
}: MonitorQueryParams): Promise<MonitorDetails> => {
const url = getApiPath(`/api/uptime/monitor/details`, basePath);
const params = {
monitorId,
dateStart,
dateEnd,
};
const urlParams = new URLSearchParams(params).toString();
const response = await fetch(`${url}?${urlParams}`);
if (!response.ok) {
throw new Error(response.statusText);
}

View file

@ -0,0 +1,14 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
export interface BaseParams {
basePath: string;
dateStart: string;
dateEnd: string;
filters?: string;
statusFilter?: string;
location?: string;
}

View file

@ -16,12 +16,18 @@ import {
} from '../actions/monitor';
import { fetchMonitorDetails, fetchMonitorLocations } from '../api';
import { getBasePath } from '../selectors';
import { MonitorDetailsActionPayload } from '../actions/types';
function* monitorDetailsEffect(action: Action<any>) {
const monitorId: string = action.payload;
const { monitorId, dateStart, dateEnd }: MonitorDetailsActionPayload = action.payload;
try {
const basePath = yield select(getBasePath);
const response = yield call(fetchMonitorDetails, { monitorId, basePath });
const response = yield call(fetchMonitorDetails, {
monitorId,
basePath,
dateStart,
dateEnd,
});
yield put({ type: FETCH_MONITOR_DETAILS_SUCCESS, payload: response });
} catch (error) {
yield put({ type: FETCH_MONITOR_DETAILS_FAIL, payload: error.message });

View file

@ -21,7 +21,7 @@ Object {
exports[`ui reducer updates the refresh value 1`] = `
Object {
"basePath": "",
"basePath": "abc",
"integrationsPopoverOpen": null,
"lastRefresh": 125,
}

View file

@ -4,15 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { UiActionTypes } from '../../actions';
import { setBasePath, toggleIntegrationsPopover, triggerAppRefresh } from '../../actions';
import { uiReducer } from '../ui';
import { Action } from 'redux-actions';
describe('ui reducer', () => {
it(`sets the application's base path`, () => {
const action: UiActionTypes = {
type: 'SET_BASE_PATH',
payload: 'yyz',
};
const action = setBasePath('yyz') as Action<never>;
expect(
uiReducer(
{
@ -26,13 +24,10 @@ describe('ui reducer', () => {
});
it('adds integration popover status to state', () => {
const action: UiActionTypes = {
type: 'SET_INTEGRATION_POPOVER_STATE',
payload: {
id: 'popover-2',
open: true,
},
};
const action = toggleIntegrationsPopover({
id: 'popover-2',
open: true,
}) as Action<never>;
expect(
uiReducer(
{
@ -46,10 +41,16 @@ describe('ui reducer', () => {
});
it('updates the refresh value', () => {
const action: UiActionTypes = {
type: 'REFRESH_APP',
payload: 125,
};
expect(uiReducer(undefined, action)).toMatchSnapshot();
const action = triggerAppRefresh(125) as Action<never>;
expect(
uiReducer(
{
basePath: 'abc',
integrationsPopoverOpen: null,
lastRefresh: 125,
},
action
)
).toMatchSnapshot();
});
});

View file

@ -12,5 +12,6 @@ import { uiReducer } from './ui';
export const rootReducer = combineReducers({
monitor: monitorReducer,
snapshot: snapshotReducer,
// @ts-ignore for now TODO: refactor to use redux-action
ui: uiReducer,
});

View file

@ -4,12 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { handleActions, Action } from 'redux-actions';
import {
UiActionTypes,
PopoverState,
SET_INTEGRATION_POPOVER_STATE,
SET_BASE_PATH,
REFRESH_APP,
toggleIntegrationsPopover,
setBasePath,
triggerAppRefresh,
UiPayload,
} from '../actions/ui';
export interface UiState {
@ -24,29 +25,22 @@ const initialState: UiState = {
lastRefresh: Date.now(),
};
export function uiReducer(state = initialState, action: UiActionTypes): UiState {
switch (action.type) {
case REFRESH_APP:
return {
...state,
lastRefresh: action.payload,
};
case SET_INTEGRATION_POPOVER_STATE:
const popoverState = action.payload;
return {
...state,
integrationsPopoverOpen: {
id: popoverState.id,
open: popoverState.open,
},
};
case SET_BASE_PATH:
const basePath = action.payload;
return {
...state,
basePath,
};
default:
return state;
}
}
export const uiReducer = handleActions<UiState, UiPayload>(
{
[String(toggleIntegrationsPopover)]: (state, action: Action<PopoverState>) => ({
...state,
integrationsPopoverOpen: action.payload as PopoverState,
}),
[String(setBasePath)]: (state, action: Action<string>) => ({
...state,
basePath: action.payload as string,
}),
[String(triggerAppRefresh)]: (state, action: Action<number>) => ({
...state,
lastRefresh: action.payload as number,
}),
},
initialState
);

View file

@ -24,7 +24,11 @@ describe('state selectors', () => {
errors: [],
loading: false,
},
ui: { basePath: 'yyz', integrationsPopoverOpen: null, lastRefresh: 125 },
ui: {
basePath: 'yyz',
integrationsPopoverOpen: null,
lastRefresh: 125,
},
};
it('selects base path from state', () => {

View file

@ -6,11 +6,13 @@
import { AppState } from '../../state';
// UI Selectors
export const getBasePath = ({ ui: { basePath } }: AppState) => basePath;
export const isIntegrationsPopupOpen = ({ ui: { integrationsPopoverOpen } }: AppState) =>
integrationsPopoverOpen;
// Monitor Selectors
export const getMonitorDetails = (state: AppState, summary: any) => {
return state.monitor.monitorDetailsList[summary.monitor_id];
};

View file

@ -27,6 +27,8 @@ export interface GetFilterBarParams {
export interface GetMonitorDetailsParams {
monitorId: string;
dateStart: string;
dateEnd: string;
}
export interface GetMonitorPageTitleParams {

View file

@ -231,7 +231,23 @@ export const elasticsearchMonitorsAdapter: UMMonitorsAdapter = {
};
},
getMonitorDetails: async ({ callES, monitorId }) => {
getMonitorDetails: async ({ callES, monitorId, dateStart, dateEnd }) => {
const queryFilters: any = [
{
range: {
'@timestamp': {
gte: dateStart,
lte: dateEnd,
},
},
},
{
term: {
'monitor.id': monitorId,
},
},
];
const params = {
index: INDEX_NAMES.HEARTBEAT,
body: {
@ -246,13 +262,7 @@ export const elasticsearchMonitorsAdapter: UMMonitorsAdapter = {
},
},
],
filter: [
{
term: {
'monitor.id': monitorId,
},
},
],
filter: queryFilters,
},
},
sort: [

View file

@ -157,14 +157,14 @@ export const elasticsearchPingsAdapter: UMPingsAdapter = {
statusFilter,
}) => {
const boolFilters = parseFilterQuery(filters);
const additionaFilters = [];
const additionalFilters = [];
if (monitorId) {
additionaFilters.push({ match: { 'monitor.id': monitorId } });
additionalFilters.push({ match: { 'monitor.id': monitorId } });
}
if (boolFilters) {
additionaFilters.push(boolFilters);
additionalFilters.push(boolFilters);
}
const filter = getFilterClause(dateRangeStart, dateRangeEnd, additionaFilters);
const filter = getFilterClause(dateRangeStart, dateRangeEnd, additionalFilters);
const interval = getHistogramInterval(dateRangeStart, dateRangeEnd);
const intervalFormatted = getHistogramIntervalFormatted(dateRangeStart, dateRangeEnd);

View file

@ -4,14 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
const getRange = (dateRangeStart: string, dateRangeEnd: string) => ({
range: {
'@timestamp': {
gte: dateRangeStart,
lte: dateRangeEnd,
},
},
});
import { makeDateRangeFilter } from './make_date_rate_filter';
export const getFilterClause = (
dateRangeStart: string,
@ -19,5 +12,5 @@ export const getFilterClause = (
additionalKeys?: Array<{ [key: string]: any }>
) =>
additionalKeys && additionalKeys.length > 0
? [getRange(dateRangeStart, dateRangeEnd), ...additionalKeys]
: [getRange(dateRangeStart, dateRangeEnd)];
? [makeDateRangeFilter(dateRangeStart, dateRangeEnd), ...additionalKeys]
: [makeDateRangeFilter(dateRangeStart, dateRangeEnd)];

View file

@ -13,18 +13,24 @@ export const createGetMonitorDetailsRoute: UMRestApiRouteFactory = (libs: UMServ
path: '/api/uptime/monitor/details',
validate: {
query: schema.object({
monitorId: schema.maybe(schema.string()),
monitorId: schema.string(),
dateStart: schema.maybe(schema.string()),
dateEnd: schema.maybe(schema.string()),
}),
},
options: {
tags: ['access:uptime'],
},
handler: async ({ callES }, _context, request, response): Promise<any> => {
const { monitorId } = request.query;
const { monitorId, dateStart, dateEnd } = request.query;
return response.ok({
body: {
...(await libs.monitors.getMonitorDetails({ callES, monitorId })),
...(await libs.monitors.getMonitorDetails({
callES,
monitorId,
dateStart,
dateEnd,
})),
},
});
},

View file

@ -95,7 +95,7 @@
"@types/react-test-renderer": "^16.9.1",
"@types/recompose": "^0.30.6",
"@types/reduce-reducers": "^0.3.0",
"@types/redux-actions": "^2.2.1",
"@types/redux-actions": "^2.6.1",
"@types/sinon": "^7.0.13",
"@types/styled-components": "^4.4.1",
"@types/supertest": "^2.0.5",
@ -310,7 +310,7 @@
"recompose": "^0.26.0",
"reduce-reducers": "^0.4.3",
"redux": "4.0.0",
"redux-actions": "2.2.1",
"redux-actions": "2.6.5",
"redux-observable": "^1.0.0",
"redux-saga": "^0.16.0",
"redux-thunk": "2.3.0",

View file

@ -4650,10 +4650,10 @@
dependencies:
redux "^4.0.0"
"@types/redux-actions@^2.2.1":
version "2.3.0"
resolved "https://registry.yarnpkg.com/@types/redux-actions/-/redux-actions-2.3.0.tgz#d28d7913ec86ee9e20ecb33a1fed887ecb538149"
integrity sha512-N5gZT7Tg5HGRbQH56D6umLhv1R4koEFjfz5+2TFo/tjAz3Y3Aj+hjQBum3UUO4D53hYO439UlWP5Q+S63vujrQ==
"@types/redux-actions@^2.6.1":
version "2.6.1"
resolved "https://registry.yarnpkg.com/@types/redux-actions/-/redux-actions-2.6.1.tgz#0940e97fa35ad3004316bddb391d8e01d2efa605"
integrity sha512-zKgK+ATp3sswXs6sOYo1tk8xdXTy4CTaeeYrVQlClCjeOpag5vzPo0ASWiiBJ7vsiQRAdb3VkuFLnDoBimF67g==
"@types/redux@^3.6.31":
version "3.6.31"
@ -18113,6 +18113,11 @@ jszip@^3.1.5:
readable-stream "~2.3.6"
set-immediate-shim "~1.0.1"
just-curry-it@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/just-curry-it/-/just-curry-it-3.1.0.tgz#ab59daed308a58b847ada166edd0a2d40766fbc5"
integrity sha512-mjzgSOFzlrurlURaHVjnQodyPNvrHrf1TbQP2XU9NSqBtHQPuHZ+Eb6TAJP7ASeJN9h9K0KXoRTs8u6ouHBKvg==
just-debounce@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea"
@ -18830,7 +18835,7 @@ locutus@^2.0.5:
resolved "https://registry.yarnpkg.com/locutus/-/locutus-2.0.10.tgz#f903619466a98a4ab76e8b87a5854b55a743b917"
integrity sha512-AZg2kCqrquMJ5FehDsBidV0qHl98NrsYtseUClzjAQ3HFnsDBJTCwGVplSQ82t9/QfgahqvTjaKcZqZkHmS0wQ==
lodash-es@^4.17.11, lodash-es@^4.17.4, lodash-es@^4.17.5, lodash-es@^4.2.1:
lodash-es@^4.17.11, lodash-es@^4.17.5, lodash-es@^4.2.1:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78"
integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==
@ -24615,25 +24620,21 @@ redeyed@~2.1.0:
dependencies:
esprima "~4.0.0"
reduce-reducers@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/reduce-reducers/-/reduce-reducers-0.1.2.tgz#fa1b4718bc5292a71ddd1e5d839c9bea9770f14b"
integrity sha1-+htHGLxSkqcd3R5dg5yb6pdw8Us=
reduce-reducers@^0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/reduce-reducers/-/reduce-reducers-0.4.3.tgz#8e052618801cd8fc2714b4915adaa8937eb6d66c"
integrity sha512-+CNMnI8QhgVMtAt54uQs3kUxC3Sybpa7Y63HR14uGLgI9/QR5ggHvpxwhGGe3wmx5V91YwqQIblN9k5lspAmGw==
redux-actions@2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/redux-actions/-/redux-actions-2.2.1.tgz#d64186b25649a13c05478547d7cd7537b892410d"
integrity sha1-1kGGslZJoTwFR4VH1811N7iSQQ0=
redux-actions@2.6.5:
version "2.6.5"
resolved "https://registry.yarnpkg.com/redux-actions/-/redux-actions-2.6.5.tgz#bdca548768ee99832a63910c276def85e821a27e"
integrity sha512-pFhEcWFTYNk7DhQgxMGnbsB1H2glqhQJRQrtPb96kD3hWiZRzXHwwmFPswg6V2MjraXRXWNmuP9P84tvdLAJmw==
dependencies:
invariant "^2.2.1"
lodash "^4.13.1"
lodash-es "^4.17.4"
reduce-reducers "^0.1.0"
invariant "^2.2.4"
just-curry-it "^3.1.0"
loose-envify "^1.4.0"
reduce-reducers "^0.4.3"
to-camel-case "^1.0.0"
redux-observable@^1.0.0:
version "1.0.0"
@ -28205,6 +28206,13 @@ to-arraybuffer@^1.0.0:
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
to-camel-case@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/to-camel-case/-/to-camel-case-1.0.0.tgz#1a56054b2f9d696298ce66a60897322b6f423e46"
integrity sha1-GlYFSy+daWKYzmamCJcyK29CPkY=
dependencies:
to-space-case "^1.0.0"
to-fast-properties@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
@ -28215,6 +28223,11 @@ to-fast-properties@^2.0.0:
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
to-no-case@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/to-no-case/-/to-no-case-1.0.2.tgz#c722907164ef6b178132c8e69930212d1b4aa16a"
integrity sha1-xyKQcWTvaxeBMsjmmTAhLRtKoWo=
to-object-path@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
@ -28263,6 +28276,13 @@ to-source-code@^1.0.0:
dependencies:
is-nil "^1.0.0"
to-space-case@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/to-space-case/-/to-space-case-1.0.0.tgz#b052daafb1b2b29dc770cea0163e5ec0ebc9fc17"
integrity sha1-sFLar7Gysp3HcM6gFj5ewOvJ/Bc=
dependencies:
to-no-case "^1.0.0"
to-through@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/to-through/-/to-through-2.0.0.tgz#fc92adaba072647bc0b67d6b03664aa195093af6"