[APM] Upgrade to react-redux-request (#19338)

This commit is contained in:
Søren Louv-Jansen 2018-05-24 02:45:49 +02:00 committed by GitHub
parent d649f02c07
commit 66739ffdd9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 170 additions and 318 deletions

View file

@ -138,6 +138,7 @@
"react-markdown-renderer": "^1.4.0",
"react-portal": "^3.2.0",
"react-redux": "^5.0.5",
"react-redux-request": "^1.5.5",
"react-router-breadcrumbs-hoc": "1.1.2",
"react-router-dom": "^4.2.2",
"react-select": "^1.2.1",

View file

@ -27,8 +27,8 @@ import {
ERROR_EXC_MESSAGE,
ERROR_EXC_HANDLED
} from '../../../../common/constants';
import { ErrorDistributionRequest } from '../../../store/reduxRequest/errorDistribution';
import { ErrorGroupDetailsRequest } from '../../../store/reduxRequest/errorGroup';
import { ErrorDistributionRequest } from '../../../store/reactReduxRequest/errorDistribution';
import { ErrorGroupDetailsRequest } from '../../../store/reactReduxRequest/errorGroup';
const Titles = styled.div`
margin-bottom: ${px(units.plus)};

View file

@ -73,13 +73,13 @@ function ListItem({ error, serviceName }) {
return (
<KuiTableRow>
<GroupIdCell>
<GroupIdLink path={`${serviceName}/errors/${groupId}`}>
<GroupIdLink path={`/${serviceName}/errors/${groupId}`}>
{groupId.slice(0, 5) || 'N/A'}
</GroupIdLink>
</GroupIdCell>
<MessageAndCulpritCell>
<TooltipOverlay content={message || 'N/A'}>
<MessageLink path={`${serviceName}/errors/${groupId}`}>
<MessageLink path={`/${serviceName}/errors/${groupId}`}>
{message || 'N/A'}
</MessageLink>
</TooltipOverlay>

View file

@ -7,7 +7,7 @@
import { connect } from 'react-redux';
import ErrorGroupOverview from './view';
import { getUrlParams } from '../../../store/urlParams';
import { getLicense } from '../../../store/reduxRequest/license';
import { getLicense } from '../../../store/reactReduxRequest/license';
function mapStateToProps(state = {}) {
return {

View file

@ -11,7 +11,7 @@ import TabNavigation from '../../shared/TabNavigation';
import List from './List';
import WatcherFlyout from './Watcher/WatcherFlyOut';
import OpenWatcherDialogButton from './Watcher/OpenWatcherDialogButton';
import { ErrorGroupDetailsRequest } from '../../../store/reduxRequest/errorGroupList';
import { ErrorGroupDetailsRequest } from '../../../store/reactReduxRequest/errorGroupList';
class ErrorGroupOverview extends Component {
state = {

View file

@ -11,7 +11,7 @@ import { STATUS } from '../../../../constants/index';
function getIsLoading(state) {
return some(
state.reduxRequest,
state.reactReduxRequest,
subState => get(subState, 'status') === STATUS.LOADING
);
}

View file

@ -5,7 +5,7 @@
*/
import React from 'react';
import { STATUS } from '../../../../constants/index';
import { LicenceRequest } from '../../../../store/reduxRequest/license';
import { LicenceRequest } from '../../../../store/reactReduxRequest/license';
function LicenseChecker() {
return (

View file

@ -52,7 +52,7 @@ function ListItem({ service }) {
<KuiTableRow>
<ServiceNameCell>
<TooltipOverlay content={formatString(serviceName)}>
<AppLink path={`${serviceName}/transactions`}>
<AppLink path={`/${serviceName}/transactions`}>
{formatString(serviceName)}
</AppLink>
</TooltipOverlay>

View file

@ -6,7 +6,7 @@
import { connect } from 'react-redux';
import ServiceOverview from './view';
import { getServiceList } from '../../../store/reduxRequest/serviceList';
import { getServiceList } from '../../../store/reactReduxRequest/serviceList';
import { getUrlParams } from '../../../store/urlParams';
import sorting, { changeServiceSorting } from '../../../store/sorting';

View file

@ -13,7 +13,7 @@ import { EuiButton } from '@elastic/eui';
import List from './List';
import { HeaderContainer } from '../../shared/UIComponents';
import { ServiceListRequest } from '../../../store/reduxRequest/serviceList';
import { ServiceListRequest } from '../../../store/reactReduxRequest/serviceList';
class ServiceOverview extends Component {
state = {

View file

@ -17,7 +17,7 @@ import Timeline from '../../../../shared/charts/Timeline';
import EmptyMessage from '../../../../shared/EmptyMessage';
import { getFeatureDocs } from '../../../../../utils/documentation';
import { ExternalLink } from '../../../../../utils/url';
import { SpansRequest } from '../../../../../store/reduxRequest/spans';
import { SpansRequest } from '../../../../../store/reactReduxRequest/spans';
const Container = styled.div`
transition: 0.1s padding ease;

View file

@ -8,10 +8,10 @@ import React from 'react';
import { HeaderLarge } from '../../shared/UIComponents';
import Transaction from './Transaction';
import Distribution from './Distribution';
import { DetailsChartsRequest } from '../../../store/reduxRequest/detailsCharts';
import { DetailsChartsRequest } from '../../../store/reactReduxRequest/detailsCharts';
import Charts from '../../shared/charts/TransactionCharts';
import { TransactionDistributionRequest } from '../../../store/reduxRequest/transactionDistribution';
import { TransactionDetailsRequest } from '../../../store/reduxRequest/transactionDetails';
import { TransactionDistributionRequest } from '../../../store/reactReduxRequest/transactionDistribution';
import { TransactionDetailsRequest } from '../../../store/reactReduxRequest/transactionDetails';
function TransactionDetails({ urlParams }) {
return (

View file

@ -86,7 +86,7 @@ function TransactionListItem({ serviceName, transaction, type, impact }) {
<KuiTableRow>
<TransactionNameCell>
<TooltipOverlay content={transactionName || 'N/A'}>
<TransactionNameLink path={transactionUrl}>
<TransactionNameLink path={`/${transactionUrl}`}>
{transactionName || 'N/A'}
</TransactionNameLink>
</TooltipOverlay>

View file

@ -10,9 +10,9 @@ import { HeaderLarge, HeaderMedium } from '../../shared/UIComponents';
import TabNavigation from '../../shared/TabNavigation';
import Charts from '../../shared/charts/TransactionCharts';
import List from './List';
import { OverviewChartsRequest } from '../../../store/reduxRequest/overviewCharts';
import { TransactionListRequest } from '../../../store/reduxRequest/transactionList';
import { ServiceDetailsRequest } from '../../../store/reduxRequest/serviceDetails';
import { OverviewChartsRequest } from '../../../store/reactReduxRequest/overviewCharts';
import { TransactionListRequest } from '../../../store/reactReduxRequest/transactionList';
import { ServiceDetailsRequest } from '../../../store/reactReduxRequest/serviceDetails';
function ServiceDetailsAndTransactionList({ urlParams, render }) {
return (

View file

@ -1,51 +0,0 @@
/*
* 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.
*/
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { ReduxRequestView } from './view';
import hash from 'object-hash/index';
export { reduxRequestReducer } from './reducer';
const mapStateToProps = (state, ownProps) => {
const { args, id, selector } = ownProps;
const hashedArgs = hash(args);
let result;
try {
result = selector(state, { id });
} catch (e) {
console.error(`The selector for "ReduxRequest#${id}" threw an error:\n`, e);
return {
hashedArgs,
hasError: true
};
}
return {
prevHashedArgs: result.hashedArgs,
hashedArgs,
result
};
};
const mapDispatchToProps = dispatch => ({
dispatch
});
export const ReduxRequest = connect(mapStateToProps, mapDispatchToProps)(
ReduxRequestView
);
ReduxRequest.propTypes = {
args: PropTypes.array,
id: PropTypes.string.isRequired,
selector: PropTypes.func
};
ReduxRequest.defaultProps = {
args: [],
selector: (state, props) => state.reduxRequest[props.id] || {}
};

View file

@ -1,51 +0,0 @@
/*
* 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.
*/
import { get } from 'lodash';
export const ACTION_TYPES = {
LOADING: 'REDUX_REQUEST_LOADING',
SUCCESS: 'REDUX_REQUEST_SUCCESS',
FAILURE: 'REDUX_REQUEST_FAILURE'
};
export const STATUS = {
LOADING: 'LOADING',
SUCCESS: 'SUCCESS',
FAILURE: 'FAILURE'
};
function getStatus(type) {
switch (type) {
case ACTION_TYPES.LOADING:
return STATUS.LOADING;
case ACTION_TYPES.SUCCESS:
return STATUS.SUCCESS;
case ACTION_TYPES.FAILURE:
return STATUS.FAILURE;
}
}
export function reduxRequestReducer(state = {}, action) {
switch (action.type) {
case ACTION_TYPES.LOADING:
case ACTION_TYPES.SUCCESS:
case ACTION_TYPES.FAILURE: {
const { id, data, error, hashedArgs } = action;
return {
...state,
[id]: {
status: getStatus(action.type),
data: data || get(state[id], 'data'),
error: error || get(state[id], 'error'),
hashedArgs
}
};
}
default:
return state;
}
}

View file

@ -1,116 +0,0 @@
/*
* 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.
*/
import React from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import { ACTION_TYPES } from './reducer';
async function maybeFetchData(
{
args,
dispatch,
hasError,
fn,
hashedArgs,
id,
prevHashedArgs,
shouldInvoke
},
ctx = {}
) {
const shouldFetchData =
shouldInvoke && prevHashedArgs !== hashedArgs && !hasError;
if (!shouldFetchData) {
return;
}
dispatch({
id,
hashedArgs,
type: ACTION_TYPES.LOADING
});
const fetchId = (ctx.fetchId = _.uniqueId());
try {
const data = await fn(...args);
if (fetchId === ctx.fetchId) {
dispatch({
data,
hashedArgs,
id,
type: ACTION_TYPES.SUCCESS
});
}
} catch (error) {
if (fetchId === ctx.fetchId) {
console.error(error);
dispatch({
error,
hashedArgs,
id,
type: ACTION_TYPES.FAILURE
});
}
}
}
export class ReduxRequestView extends React.Component {
componentWillMount() {
maybeFetchData(this.props, this);
}
componentWillReceiveProps(nextProps) {
maybeFetchData(nextProps, this);
}
shouldComponentUpdate(nextProps) {
return this.props.result !== nextProps.result;
}
componentWillUnmount() {
this.fetchId = null;
}
render() {
if (this.props.hasError) {
return null;
}
const { status, data, error } = this.props.result;
try {
return this.props.render({ status, data, error });
} catch (e) {
console.error(
`The render method of "ReduxRequest#${
this.props.id
}" threw an error:\n`,
e
);
return null;
}
}
}
ReduxRequestView.propTypes = {
args: PropTypes.array,
dispatch: PropTypes.func.isRequired,
fn: PropTypes.func.isRequired,
hasError: PropTypes.bool,
hashedArgs: PropTypes.string.isRequired,
id: PropTypes.string.isRequired,
prevHashedArgs: PropTypes.string,
render: PropTypes.func,
result: PropTypes.object,
shouldInvoke: PropTypes.bool.isRequired
};
ReduxRequestView.defaultProps = {
args: [],
hasError: false,
render: () => {},
result: {},
shouldInvoke: true
};

View file

@ -19,7 +19,7 @@ import {
import { isEmpty } from 'lodash';
import TooltipOverlay from '../../shared/TooltipOverlay';
import { ServiceDetailsRequest } from '../../../store/reduxRequest/serviceDetails';
import { ServiceDetailsRequest } from '../../../store/reactReduxRequest/serviceDetails';
const Container = styled.div`
display: flex;
@ -87,7 +87,7 @@ function TabNavigation({ urlParams, location }) {
key={type}
>
<NavLink
path={`${serviceName}/transactions/${encodeURIComponent(
path={`/${serviceName}/transactions/${encodeURIComponent(
type
)}`}
selected={transactionType === type && !errorsSelected}
@ -101,7 +101,7 @@ function TabNavigation({ urlParams, location }) {
/>
<Divider />
<TabLink path={`${serviceName}/errors`} selected={errorsSelected}>
<TabLink path={`/${serviceName}/errors`} selected={errorsSelected}>
Errors
</TabLink>
</Container>

View file

@ -10,7 +10,7 @@ describe('root reducer', () => {
it('should return the initial state', () => {
expect(reducer(undefined, {})).toEqual({
location: { hash: '', pathname: '', search: '' },
reduxRequest: {},
reactReduxRequest: {},
sorting: {
service: { descending: false, key: 'serviceName' },
transaction: { descending: true, key: 'impact' }

View file

@ -12,13 +12,13 @@ import { mountWithStore } from '../../../utils/testHelpers';
describe('serviceList', () => {
describe('getServiceList', () => {
it('should return default value when empty', () => {
const state = { reduxRequest: {}, sorting: { service: {} } };
const state = { reactReduxRequest: {}, sorting: { service: {} } };
expect(getServiceList(state)).toEqual({ data: [] });
});
it('should return serviceList when not empty', () => {
const state = {
reduxRequest: { serviceList: { data: [{ foo: 'bar' }] } },
reactReduxRequest: { serviceList: { data: [{ foo: 'bar' }] } },
sorting: { service: {} }
};
expect(getServiceList(state)).toEqual({ data: [{ foo: 'bar' }] });
@ -32,7 +32,7 @@ describe('serviceList', () => {
beforeEach(() => {
const state = {
reduxRequest: {
reactReduxRequest: {
serviceList: { status: 'my-status', data: [{ foo: 'bar' }] }
},
sorting: { service: {} }

View file

@ -9,7 +9,7 @@ import { createSelector } from 'reselect';
import { getCharts } from '../selectors/chartSelectors';
import { getUrlParams } from '../urlParams';
import { withInitialData } from './helpers';
import { ReduxRequest } from '../../components/shared/ReduxRequest';
import { Request } from 'react-redux-request';
import { loadCharts } from '../../services/rest';
const ID = 'detailsCharts';
@ -23,7 +23,7 @@ const INITIAL_DATA = {
export const getDetailsCharts = createSelector(
getUrlParams,
state => withInitialData(state.reduxRequest[ID], INITIAL_DATA),
state => withInitialData(state.reactReduxRequest[ID], INITIAL_DATA),
getCharts
);
@ -37,13 +37,14 @@ export function DetailsChartsRequest({ urlParams, render }) {
kuery
} = urlParams;
if (!(serviceName && start && end && transactionType && transactionName)) {
return null;
}
return (
<ReduxRequest
<Request
id={ID}
fn={loadCharts}
shouldInvoke={Boolean(
serviceName && start && end && transactionType && transactionName
)}
args={[
{ serviceName, start, end, transactionType, transactionName, kuery }
]}

View file

@ -5,7 +5,7 @@
*/
import React from 'react';
import { ReduxRequest } from '../../components/shared/ReduxRequest';
import { Request } from 'react-redux-request';
import { loadErrorDistribution } from '../../services/rest';
import { withInitialData } from './helpers';
@ -13,17 +13,20 @@ const ID = 'errorDistribution';
const INITIAL_DATA = { buckets: [], totalHits: 0 };
export function getErrorDistribution(state) {
return withInitialData(state.reduxRequest[ID], INITIAL_DATA);
return withInitialData(state.reactReduxRequest[ID], INITIAL_DATA);
}
export function ErrorDistributionRequest({ urlParams, render }) {
const { serviceName, start, end, errorGroupId, kuery } = urlParams;
if (!(serviceName, start, end, errorGroupId)) {
return null;
}
return (
<ReduxRequest
<Request
id={ID}
fn={loadErrorDistribution}
shouldInvoke={Boolean(serviceName, start, end, errorGroupId)}
args={[{ serviceName, start, end, errorGroupId, kuery }]}
selector={getErrorDistribution}
render={render}

View file

@ -6,24 +6,27 @@
import React from 'react';
import { withInitialData } from './helpers';
import { ReduxRequest } from '../../components/shared/ReduxRequest';
import { Request } from 'react-redux-request';
import { loadErrorGroupDetails } from '../../services/rest';
const ID = 'errorGroupDetails';
const INITIAL_DATA = {};
export function getErrorGroupDetails(state) {
return withInitialData(state.reduxRequest[ID], INITIAL_DATA);
return withInitialData(state.reactReduxRequest[ID], INITIAL_DATA);
}
export function ErrorGroupDetailsRequest({ urlParams, render }) {
const { serviceName, errorGroupId, start, end, kuery } = urlParams;
if (!(serviceName && start && end && errorGroupId)) {
return null;
}
return (
<ReduxRequest
<Request
id={ID}
fn={loadErrorGroupDetails}
shouldInvoke={Boolean(serviceName && start && end && errorGroupId)}
args={[{ serviceName, start, end, errorGroupId, kuery }]}
selector={getErrorGroupDetails}
render={render}

View file

@ -6,24 +6,27 @@
import React from 'react';
import { withInitialData } from './helpers';
import { ReduxRequest } from '../../components/shared/ReduxRequest';
import { Request } from 'react-redux-request';
import { loadErrorGroupList } from '../../services/rest';
const ID = 'errorGroupList';
const INITIAL_DATA = [];
export function getErrorGroupList(state) {
return withInitialData(state.reduxRequest[ID], INITIAL_DATA);
return withInitialData(state.reactReduxRequest[ID], INITIAL_DATA);
}
export function ErrorGroupDetailsRequest({ urlParams, render }) {
const { serviceName, start, end, q, sortBy, sortOrder, kuery } = urlParams;
if (!(serviceName && start && end)) {
return null;
}
return (
<ReduxRequest
<Request
id={ID}
fn={loadErrorGroupList}
shouldInvoke={Boolean(serviceName && start && end)}
args={[{ serviceName, start, end, q, sortBy, sortOrder, kuery }]}
selector={getErrorGroupList}
render={render}

View file

@ -5,7 +5,7 @@
*/
import React from 'react';
import { withInitialData } from './helpers';
import { ReduxRequest } from '../../components/shared/ReduxRequest';
import { Request } from 'react-redux-request';
import { loadLicense } from '../../services/rest';
const ID = 'license';
@ -15,16 +15,11 @@ const INITIAL_DATA = {
};
export function getLicense(state) {
return withInitialData(state.reduxRequest[ID], INITIAL_DATA);
return withInitialData(state.reactReduxRequest[ID], INITIAL_DATA);
}
export function LicenceRequest({ render }) {
return (
<ReduxRequest
id={ID}
fn={loadLicense}
selector={getLicense}
render={render}
/>
<Request id={ID} fn={loadLicense} selector={getLicense} render={render} />
);
}

View file

@ -9,7 +9,7 @@ import { createSelector } from 'reselect';
import { getCharts } from '../selectors/chartSelectors';
import { getUrlParams } from '../urlParams';
import { withInitialData } from './helpers';
import { ReduxRequest } from '../../components/shared/ReduxRequest';
import { Request } from 'react-redux-request';
import { loadCharts } from '../../services/rest';
const ID = 'overviewCharts';
@ -23,16 +23,20 @@ const INITIAL_DATA = {
export const getOverviewCharts = createSelector(
getUrlParams,
state => withInitialData(state.reduxRequest[ID], INITIAL_DATA),
state => withInitialData(state.reactReduxRequest[ID], INITIAL_DATA),
getCharts
);
export function OverviewChartsRequest({ urlParams, render }) {
const { serviceName, start, end, transactionType, kuery } = urlParams;
if (!(serviceName && start && end && transactionType)) {
return null;
}
return (
<ReduxRequest
<Request
id={ID}
shouldInvoke={Boolean(serviceName && start && end && transactionType)}
fn={loadCharts}
args={[{ serviceName, start, end, transactionType, kuery }]}
selector={getOverviewCharts}

View file

@ -8,27 +8,31 @@ import React from 'react';
import _ from 'lodash';
import PropTypes from 'prop-types';
import { withInitialData } from './helpers';
import { ReduxRequest } from '../../components/shared/ReduxRequest';
import { Request } from 'react-redux-request';
import { loadServiceDetails } from '../../services/rest';
const ID = 'serviceDetails';
const INITIAL_DATA = { types: [] };
export function getServiceDetails(state) {
return withInitialData(state.reduxRequest[ID], INITIAL_DATA);
return withInitialData(state.reactReduxRequest[ID], INITIAL_DATA);
}
export function getDefaultTransactionType(state) {
const types = _.get(state.reduxRequest.serviceDetails, 'data.types');
const types = _.get(state.reactReduxRequest.serviceDetails, 'data.types');
return _.first(types);
}
export function ServiceDetailsRequest({ urlParams, render }) {
const { serviceName, start, end, kuery } = urlParams;
if (!(serviceName && start && end)) {
return null;
}
return (
<ReduxRequest
<Request
id={ID}
shouldInvoke={Boolean(serviceName && start && end)}
fn={loadServiceDetails}
args={[{ serviceName, start, end, kuery }]}
selector={getServiceDetails}

View file

@ -8,14 +8,14 @@ import React from 'react';
import orderBy from 'lodash.orderby';
import { createSelector } from 'reselect';
import { loadServiceList } from '../../services/rest';
import { ReduxRequest } from '../../components/shared/ReduxRequest';
import { Request } from 'react-redux-request';
import { withInitialData } from './helpers';
const ID = 'serviceList';
const INITIAL_DATA = [];
export const getServiceList = createSelector(
state => withInitialData(state.reduxRequest[ID], INITIAL_DATA),
state => withInitialData(state.reactReduxRequest[ID], INITIAL_DATA),
state => state.sorting.service,
(serviceList, serviceSorting) => {
const { key: sortKey, descending } = serviceSorting;
@ -30,7 +30,7 @@ export const getServiceList = createSelector(
export function ServiceListRequest({ urlParams, render }) {
const { start, end, kuery } = urlParams;
return (
<ReduxRequest
<Request
id={ID}
fn={loadServiceList}
args={[{ start, end, kuery }]}

View file

@ -6,22 +6,26 @@
import React from 'react';
import { withInitialData } from './helpers';
import { ReduxRequest } from '../../components/shared/ReduxRequest';
import { Request } from 'react-redux-request';
import { loadSpans } from '../../services/rest';
const ID = 'spans';
const INITIAL_DATA = {};
export function getSpans(state) {
return withInitialData(state.reduxRequest[ID], INITIAL_DATA);
return withInitialData(state.reactReduxRequest[ID], INITIAL_DATA);
}
export function SpansRequest({ urlParams, render }) {
const { serviceName, start, end, transactionId, kuery } = urlParams;
if (!(serviceName && start && end && transactionId)) {
return null;
}
return (
<ReduxRequest
<Request
id={ID}
shouldInvoke={Boolean(serviceName && start && end && transactionId)}
fn={loadSpans}
selector={getSpans}
args={[{ serviceName, start, end, transactionId, kuery }]}

View file

@ -6,22 +6,26 @@
import React from 'react';
import { withInitialData } from './helpers';
import { ReduxRequest } from '../../components/shared/ReduxRequest';
import { Request } from 'react-redux-request';
import { loadTransaction } from '../../services/rest';
const ID = 'transactionDetails';
const INITIAL_DATA = {};
export function getTransactionDetails(state) {
return withInitialData(state.reduxRequest[ID], INITIAL_DATA);
return withInitialData(state.reactReduxRequest[ID], INITIAL_DATA);
}
export function TransactionDetailsRequest({ urlParams, render }) {
const { serviceName, start, end, transactionId, kuery } = urlParams;
if (!(serviceName && start && end && transactionId)) {
return null;
}
return (
<ReduxRequest
<Request
id={ID}
shouldInvoke={Boolean(serviceName && start && end && transactionId)}
fn={loadTransaction}
selector={getTransactionDetails}
args={[{ serviceName, start, end, transactionId, kuery }]}

View file

@ -6,14 +6,14 @@
import React from 'react';
import { withInitialData } from './helpers';
import { ReduxRequest } from '../../components/shared/ReduxRequest';
import { Request } from 'react-redux-request';
import { loadTransactionDistribution } from '../../services/rest';
const INITIAL_DATA = { buckets: [], totalHits: 0 };
export function getTransactionDistribution(state) {
return withInitialData(
state.reduxRequest.transactionDistribution,
state.reactReduxRequest.transactionDistribution,
INITIAL_DATA
);
}
@ -25,10 +25,14 @@ export function getDefaultTransactionId(state) {
export function TransactionDistributionRequest({ urlParams, render }) {
const { serviceName, start, end, transactionName, kuery } = urlParams;
if (!(serviceName && start && end && transactionName)) {
return null;
}
return (
<ReduxRequest
<Request
id="transactionDistribution"
shouldInvoke={Boolean(serviceName && start && end && transactionName)}
fn={loadTransactionDistribution}
args={[{ serviceName, start, end, transactionName, kuery }]}
selector={getTransactionDistribution}

View file

@ -7,14 +7,14 @@
import React from 'react';
import orderBy from 'lodash.orderby';
import { createSelector } from 'reselect';
import { ReduxRequest } from '../../components/shared/ReduxRequest';
import { Request } from 'react-redux-request';
import { loadTransactionList } from '../../services/rest';
const ID = 'transactionList';
const INITIAL_DATA = [];
export const getTransactionList = createSelector(
state => state.reduxRequest[ID],
state => state.reactReduxRequest[ID],
state => state.sorting.transaction,
(transactionList = {}, transactionSorting) => {
const { key: sortKey, descending } = transactionSorting;
@ -32,10 +32,14 @@ export const getTransactionList = createSelector(
export function TransactionListRequest({ urlParams, render }) {
const { serviceName, start, end, transactionType, kuery } = urlParams;
if (!(serviceName && start && end && transactionType)) {
return null;
}
return (
<ReduxRequest
<Request
id={ID}
shouldInvoke={Boolean(serviceName && start && end && transactionType)}
fn={loadTransactionList}
args={[
{

View file

@ -8,13 +8,13 @@ import { combineReducers } from 'redux';
import location from './location';
import sorting from './sorting';
import urlParams from './urlParams';
import { reduxRequestReducer } from '../components/shared/ReduxRequest';
import { reducer } from 'react-redux-request';
const rootReducer = combineReducers({
location,
sorting,
urlParams,
reduxRequest: reduxRequestReducer
reactReduxRequest: reducer
});
export default rootReducer;

View file

@ -8,8 +8,8 @@ import _ from 'lodash';
import { createSelector } from 'reselect';
import { LOCATION_UPDATE } from './location';
import { toQuery, legacyDecodeURIComponent } from '../utils/url';
import { getDefaultTransactionId } from './reduxRequest/transactionDistribution';
import { getDefaultTransactionType } from './reduxRequest/serviceDetails';
import { getDefaultTransactionId } from './reactReduxRequest/transactionDistribution';
import { getDefaultTransactionType } from './reactReduxRequest/serviceDetails';
// ACTION TYPES
export const TIMEPICKER_UPDATE = 'TIMEPICKER_UPDATE';

View file

@ -12,9 +12,9 @@ exports[`KibanaLinkComponent should render correct markup 1`] = `
exports[`RelativeLinkComponent should render correct markup 1`] = `
<a
className="euiLink euiLink--primary "
href="/opbeans-backend/errors?_g=(refreshInterval:(display:Off,pause:!f,value:0),time:(from:now-2y,mode:quick,to:now))"
href="/opbeans-node/errors?foo=bar&foo2=bar2"
onClick={[Function]}
>
Errors
Go to Discover
</a>
`;

View file

@ -5,8 +5,9 @@
*/
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { Router } from 'react-router-dom';
import { mount } from 'enzyme';
import createHistory from 'history/createMemoryHistory';
import {
toQuery,
@ -48,35 +49,58 @@ describe('fromQuery', () => {
});
describe('RelativeLinkComponent', () => {
let history;
let wrapper;
beforeEach(() => {
history = createHistory();
history.location = {
...history.location,
pathname: '/opbeans-node/transactions',
search: '?foo=bar'
};
wrapper = mount(
<MemoryRouter>
<Router history={history}>
<RelativeLinkComponent
location={{
pathname: '/opbeans-backend/transactions',
search:
'?_g=(refreshInterval:(display:Off,pause:!f,value:0),time:(from:now-2y,mode:quick,to:now))'
}}
path={'/opbeans-backend/errors'}
query={{}}
location={history.location}
query={{ foo2: 'bar2' }}
path={'/opbeans-node/errors'}
>
Errors
Go to Discover
</RelativeLinkComponent>
</MemoryRouter>
</Router>
);
});
it('should have correct url', () => {
expect(wrapper.find('a').prop('href')).toBe(
'/opbeans-backend/errors?_g=(refreshInterval:(display:Off,pause:!f,value:0),time:(from:now-2y,mode:quick,to:now))'
'/opbeans-node/errors?foo=bar&foo2=bar2'
);
});
it('should render correct markup', () => {
expect(toJson(wrapper)).toMatchSnapshot();
});
it('should have initial location', () => {
expect(history.location).toEqual(
expect.objectContaining({
pathname: '/opbeans-node/transactions',
search: '?foo=bar'
})
);
});
it('should update location on click', () => {
wrapper.simulate('click', { button: 0 });
expect(history.location).toEqual(
expect.objectContaining({
pathname: '/opbeans-node/errors',
search: '?foo=bar&foo2=bar2'
})
);
});
});
describe('KibanaLinkComponent', () => {

View file

@ -4634,7 +4634,7 @@ lodash.isempty@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e"
lodash.isequal@^4.1.1:
lodash.isequal@^4.1.1, lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
@ -6094,6 +6094,14 @@ react-reconciler@^0.7.0:
object-assign "^4.1.1"
prop-types "^15.6.0"
react-redux-request@^1.5.5:
version "1.5.5"
resolved "https://registry.yarnpkg.com/react-redux-request/-/react-redux-request-1.5.5.tgz#693562b0d85293d9d16b02e13ea13f118950bb1d"
dependencies:
lodash.get "^4.4.2"
lodash.isequal "^4.5.0"
prop-types "^15.6.1"
react-redux@^5.0.5:
version "5.0.6"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.6.tgz#23ed3a4f986359d68b5212eaaa681e60d6574946"

View file

@ -8172,7 +8172,7 @@ lodash.isempty@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e"
lodash.isequal@^4.0.0, lodash.isequal@^4.1.1:
lodash.isequal@^4.0.0, lodash.isequal@^4.1.1, lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
@ -10517,6 +10517,14 @@ react-reconciler@^0.7.0:
object-assign "^4.1.1"
prop-types "^15.6.0"
react-redux-request@^1.5.5:
version "1.5.5"
resolved "https://registry.yarnpkg.com/react-redux-request/-/react-redux-request-1.5.5.tgz#693562b0d85293d9d16b02e13ea13f118950bb1d"
dependencies:
lodash.get "^4.4.2"
lodash.isequal "^4.5.0"
prop-types "^15.6.1"
react-redux@^5.0.5, react-redux@^5.0.6:
version "5.0.7"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.7.tgz#0dc1076d9afb4670f993ffaef44b8f8c1155a4c8"