[Uptime] Fix/issue 48 integration popup closes after refresh (#45759)

* integrate redux into uptime app

* update integrations popup handling

* keep popover open after page refresh

* updated unit test snaps

* update unit tests

* fixed types
This commit is contained in:
Shahzad 2019-09-17 22:15:39 +05:00 committed by GitHub
parent 4e6cf7998f
commit a204a4347f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 208 additions and 69 deletions

View file

@ -218,7 +218,7 @@ export const MonitorListComponent = (props: Props) => {
{
defaultMessage: 'Integrations',
description:
'The heading column of some action buttons that will take users to other Obsevability apps',
'The heading column of some action buttons that will take users to other Observability apps',
}
),
render: (state: any, summary: MonitorSummary) => (

View file

@ -5,20 +5,29 @@
*/
import { EuiButtonIcon, EuiPopover } from '@elastic/eui';
import React, { useState, useContext } from 'react';
import React, { useContext } from 'react';
import { i18n } from '@kbn/i18n';
import { get } from 'lodash';
import { connect } from 'react-redux';
import { MonitorSummary } from '../../../../common/graphql/types';
import { IntegrationGroup } from '../integration_group';
import { UptimeSettingsContext } from '../../../contexts';
import { isIntegrationsPopupOpen } from '../../../state/selectors';
import { AppState } from '../../../state';
import { toggleIntegrationsPopover, PopoverState } from '../../../state/actions';
interface MonitorListActionsPopoverProps {
summary: MonitorSummary;
popoverState: PopoverState | null;
togglePopoverIsVisible: typeof toggleIntegrationsPopover;
}
export const MonitorListActionsPopover = ({ summary }: MonitorListActionsPopoverProps) => {
const MonitorListActionsPopoverComponent = ({
summary,
popoverState,
togglePopoverIsVisible,
}: MonitorListActionsPopoverProps) => {
const popoverId = `${summary.monitor_id}_popover`;
const [popoverIsVisible, setPopoverIsVisible] = useState<boolean>(false);
const {
basePath,
dateRangeStart,
@ -28,8 +37,9 @@ export const MonitorListActionsPopover = ({ summary }: MonitorListActionsPopover
isLogsAvailable,
} = useContext(UptimeSettingsContext);
const monitorUrl = get(summary, 'state.url.full', undefined);
const monitorUrl: string | undefined = get(summary, 'state.url.full', undefined);
const isPopoverOpen: boolean =
!!popoverState && popoverState.open && popoverState.id === popoverId;
return (
<EuiPopover
button={
@ -45,12 +55,12 @@ export const MonitorListActionsPopover = ({ summary }: MonitorListActionsPopover
)}
color="subdued"
iconType="boxesHorizontal"
onClick={() => setPopoverIsVisible(true)}
onClick={() => togglePopoverIsVisible({ id: popoverId, open: true })}
/>
}
closePopover={() => setPopoverIsVisible(false)}
closePopover={() => togglePopoverIsVisible({ id: popoverId, open: false })}
id={popoverId}
isOpen={popoverIsVisible}
isOpen={isPopoverOpen}
>
<IntegrationGroup
basePath={basePath}
@ -64,3 +74,18 @@ export const MonitorListActionsPopover = ({ summary }: MonitorListActionsPopover
</EuiPopover>
);
};
const mapStateToProps = (state: AppState) => ({
popoverState: isIntegrationsPopupOpen(state),
});
const mapDispatchToProps = (dispatch: any) => ({
togglePopoverIsVisible: (popoverState: PopoverState) => {
return dispatch(toggleIntegrationsPopover(popoverState));
},
});
export const MonitorListActionsPopover = connect(
mapStateToProps,
mapDispatchToProps
)(MonitorListActionsPopoverComponent);

View file

@ -0,0 +1,7 @@
/*
* 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 * from './ui';

View file

@ -0,0 +1,26 @@
/*
* 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 const SET_INTEGRATION_POPOVER_STATE = 'SET_INTEGRATION_POPOVER_STATE';
export interface PopoverState {
id: string;
open: boolean;
}
interface SetIntegrationPopoverAction {
type: typeof SET_INTEGRATION_POPOVER_STATE;
payload: PopoverState;
}
export function toggleIntegrationsPopover(popoverState: PopoverState): SetIntegrationPopoverAction {
return {
type: SET_INTEGRATION_POPOVER_STATE,
payload: popoverState,
};
}
export type UiActionTypes = SetIntegrationPopoverAction;

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.
*/
import { compose, createStore } from 'redux';
import { rootReducer } from './reducers';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
export const store = createStore(rootReducer, composeEnhancers());
export type AppState = ReturnType<typeof rootReducer>;

View file

@ -0,0 +1,13 @@
/*
* 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 { combineReducers } from 'redux';
import { uiReducer } from './ui';
export const rootReducer = combineReducers({
ui: uiReducer,
});

View file

@ -0,0 +1,31 @@
/*
* 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 { UiActionTypes, PopoverState, SET_INTEGRATION_POPOVER_STATE } from '../actions/ui';
export interface UiState {
integrationsPopoverOpen: PopoverState | null;
}
const initialState: UiState = {
integrationsPopoverOpen: null,
};
export function uiReducer(state = initialState, action: UiActionTypes): UiState {
switch (action.type) {
case SET_INTEGRATION_POPOVER_STATE:
const popoverState = action.payload;
return {
...state,
integrationsPopoverOpen: {
id: popoverState.id,
open: popoverState.open,
},
};
default:
return state;
}
}

View file

@ -0,0 +1,11 @@
/*
* 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 { fork } from 'redux-saga/effects';
// export function* rootSaga() {
// yield fork();
// }

View file

@ -0,0 +1,8 @@
/*
* 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 { AppState } from '../../state';
export const isIntegrationsPopupOpen = (state: AppState) => state.ui.integrationsPopoverOpen;

View file

@ -11,6 +11,7 @@ import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
import { i18n } from '@kbn/i18n';
import React, { useEffect, useState } from 'react';
import { ApolloProvider } from 'react-apollo';
import { Provider as ReduxProvider } from 'react-redux';
import { BrowserRouter as Router, Route, RouteComponentProps, Switch } from 'react-router-dom';
import { capabilities } from 'ui/capabilities';
import { I18nContext } from 'ui/i18n';
@ -20,6 +21,7 @@ import { UptimeRefreshContext, UptimeSettingsContext, UMSettingsContextValues }
import { UptimeDatePicker } from './components/functional/uptime_date_picker';
import { useUrlParams } from './hooks';
import { getTitle } from './lib/helper/get_title';
import { store } from './state';
export interface UptimeAppColors {
danger: string;
@ -136,66 +138,68 @@ const Application = (props: UptimeAppProps) => {
return (
<I18nContext>
<Router basename={routerBasename}>
<Route
path="/"
render={(rootRouteProps: RouteComponentProps) => {
return (
<ApolloProvider client={client}>
<UptimeRefreshContext.Provider value={{ lastRefresh, ...rootRouteProps }}>
<UptimeSettingsContext.Provider value={initializeSettingsContextValues()}>
<EuiPage className="app-wrapper-panel " data-test-subj="uptimeApp">
<div>
<EuiFlexGroup
alignItems="center"
justifyContent="spaceBetween"
gutterSize="s"
>
<EuiFlexItem grow={false}>
<EuiTitle>
<h1>{headingText}</h1>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<UptimeDatePicker refreshApp={refreshApp} {...rootRouteProps} />
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<Switch>
<Route
exact
path="/"
render={routerProps => (
<OverviewPage
basePath={basePath}
logOverviewPageLoad={logOverviewPageLoad}
setBreadcrumbs={setBreadcrumbs}
{...routerProps}
/>
)}
/>
<Route
path="/monitor/:monitorId/:location?"
render={routerProps => (
<MonitorPage
logMonitorPageLoad={logMonitorPageLoad}
query={client.query}
setBreadcrumbs={setBreadcrumbs}
{...routerProps}
/>
)}
/>
<Route component={NotFoundPage} />
</Switch>
</div>
</EuiPage>
</UptimeSettingsContext.Provider>
</UptimeRefreshContext.Provider>
</ApolloProvider>
);
}}
/>
</Router>
<ReduxProvider store={store}>
<Router basename={routerBasename}>
<Route
path="/"
render={(rootRouteProps: RouteComponentProps) => {
return (
<ApolloProvider client={client}>
<UptimeRefreshContext.Provider value={{ lastRefresh, ...rootRouteProps }}>
<UptimeSettingsContext.Provider value={initializeSettingsContextValues()}>
<EuiPage className="app-wrapper-panel " data-test-subj="uptimeApp">
<div>
<EuiFlexGroup
alignItems="center"
justifyContent="spaceBetween"
gutterSize="s"
>
<EuiFlexItem grow={false}>
<EuiTitle>
<h1>{headingText}</h1>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<UptimeDatePicker refreshApp={refreshApp} {...rootRouteProps} />
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<Switch>
<Route
exact
path="/"
render={routerProps => (
<OverviewPage
basePath={basePath}
logOverviewPageLoad={logOverviewPageLoad}
setBreadcrumbs={setBreadcrumbs}
{...routerProps}
/>
)}
/>
<Route
path="/monitor/:monitorId/:location?"
render={routerProps => (
<MonitorPage
logMonitorPageLoad={logMonitorPageLoad}
query={client.query}
setBreadcrumbs={setBreadcrumbs}
{...routerProps}
/>
)}
/>
<Route component={NotFoundPage} />
</Switch>
</div>
</EuiPage>
</UptimeSettingsContext.Provider>
</UptimeRefreshContext.Provider>
</ApolloProvider>
);
}}
/>
</Router>
</ReduxProvider>
</I18nContext>
);
};