diff --git a/public/app/core/actions/index.ts b/public/app/core/actions/index.ts index 3c23dbbbe54..7a965f82dd1 100644 --- a/public/app/core/actions/index.ts +++ b/public/app/core/actions/index.ts @@ -1,3 +1,4 @@ import { initNav } from './navModel'; +import { updateLocation } from './location'; -export { initNav }; +export { initNav, updateLocation }; diff --git a/public/app/core/actions/location.ts b/public/app/core/actions/location.ts new file mode 100644 index 00000000000..6f7ac67363e --- /dev/null +++ b/public/app/core/actions/location.ts @@ -0,0 +1,13 @@ +import { LocationUpdate } from 'app/types'; + +export type Action = UpdateLocationAction; + +export interface UpdateLocationAction { + type: 'UPDATE_LOCATION'; + payload: LocationUpdate; +} + +export const updateLocation = (location: LocationUpdate): UpdateLocationAction => ({ + type: 'UPDATE_LOCATION', + payload: location, +}); diff --git a/public/app/core/reducers/index.ts b/public/app/core/reducers/index.ts index 0779111c16e..98f796981e4 100644 --- a/public/app/core/reducers/index.ts +++ b/public/app/core/reducers/index.ts @@ -1,5 +1,7 @@ import navModel from './navModel'; +import location from './location'; export default { navModel, + location, }; diff --git a/public/app/core/reducers/location.ts b/public/app/core/reducers/location.ts new file mode 100644 index 00000000000..5676c82844a --- /dev/null +++ b/public/app/core/reducers/location.ts @@ -0,0 +1,35 @@ +import { Action } from 'app/core/actions/location'; +import { LocationState, UrlQueryMap } from 'app/types'; +import { toUrlParams } from 'app/core/utils/url'; + +export const initialState: LocationState = { + url: '', + path: '', + query: {}, + routeParams: {}, +}; + +function renderUrl(path: string, query: UrlQueryMap): string { + if (Object.keys(query).length > 0) { + path += '?' + toUrlParams(query); + } + return path; +} + +const routerReducer = (state = initialState, action: Action): LocationState => { + switch (action.type) { + case 'UPDATE_LOCATION': { + const { path, query, routeParams } = action.payload; + return { + url: renderUrl(path || state.path, query), + path: path || state.path, + query: query || state.query, + routeParams: routeParams || state.routeParams, + }; + } + } + + return state; +}; + +export default routerReducer; diff --git a/public/app/core/services/bridge_srv.ts b/public/app/core/services/bridge_srv.ts index bdc2976a94c..29326794ac6 100644 --- a/public/app/core/services/bridge_srv.ts +++ b/public/app/core/services/bridge_srv.ts @@ -1,8 +1,10 @@ import coreModule from 'app/core/core_module'; import appEvents from 'app/core/app_events'; import { store } from 'app/stores/store'; +import { store as reduxStore } from 'app/stores/configureStore'; import { reaction } from 'mobx'; import locationUtil from 'app/core/utils/location_util'; +import { updateLocation } from 'app/core/actions'; // Services that handles angular -> mobx store sync & other react <-> angular sync export class BridgeSrv { @@ -19,12 +21,30 @@ export class BridgeSrv { if (store.view.currentUrl !== angularUrl) { store.view.updatePathAndQuery(this.$location.path(), this.$location.search(), this.$route.current.params); } + const state = reduxStore.getState(); + if (state.location.url !== angularUrl) { + reduxStore.dispatch( + updateLocation({ + path: this.$location.path(), + query: this.$location.search(), + routeParams: this.$route.current.params, + }) + ); + } }); this.$rootScope.$on('$routeChangeSuccess', (evt, data) => { store.view.updatePathAndQuery(this.$location.path(), this.$location.search(), this.$route.current.params); + reduxStore.dispatch( + updateLocation({ + path: this.$location.path(), + query: this.$location.search(), + routeParams: this.$route.current.params, + }) + ); }); + // listen for mobx store changes and update angular reaction( () => store.view.currentUrl, currentUrl => { @@ -39,6 +59,19 @@ export class BridgeSrv { } ); + // Listen for changes in redux location -> update angular location + reduxStore.subscribe(() => { + const state = reduxStore.getState(); + const angularUrl = this.$location.url(); + const url = locationUtil.stripBaseFromUrl(state.location.url); + if (angularUrl !== url) { + this.$timeout(() => { + this.$location.url(url); + }); + console.log('store updating angular $location.url', url); + } + }); + appEvents.on('location-change', payload => { const urlWithoutBase = locationUtil.stripBaseFromUrl(payload.href); if (this.fullPageReloadRoutes.indexOf(urlWithoutBase) > -1) { diff --git a/public/app/features/alerting/containers/AlertRuleList.tsx b/public/app/features/alerting/containers/AlertRuleList.tsx index 665b1508e3e..3c64f490db4 100644 --- a/public/app/features/alerting/containers/AlertRuleList.tsx +++ b/public/app/features/alerting/containers/AlertRuleList.tsx @@ -5,11 +5,13 @@ import classNames from 'classnames'; import PageHeader from 'app/core/components/PageHeader/PageHeader'; import appEvents from 'app/core/app_events'; import Highlighter from 'react-highlight-words'; -import { initNav } from 'app/core/actions'; +import { initNav, updateLocation } from 'app/core/actions'; import { ContainerProps } from 'app/types'; import { getAlertRules, AlertRule } from '../apis'; -interface Props extends ContainerProps {} +interface Props extends ContainerProps { + updateLocation: typeof updateLocation; +} interface State { rules: AlertRule[]; @@ -44,7 +46,9 @@ export class AlertRuleList extends PureComponent { } onStateFilterChanged = evt => { - // this.props.view.updateQuery({ state: evt.target.value }); + this.props.updateLocation({ + query: { state: evt.target.value }, + }); // this.fetchRules(); }; @@ -113,9 +117,7 @@ export class AlertRuleList extends PureComponent {
    - {rules.map(rule => ( - - ))} + {rules.map(rule => )}
@@ -204,6 +206,7 @@ const mapStateToProps = state => ({ const mapDispatchToProps = { initNav, + updateLocation, }; export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(AlertRuleList)); diff --git a/public/app/types/index.ts b/public/app/types/index.ts index 43d921e3964..9cb5ee85c04 100644 --- a/public/app/types/index.ts +++ b/public/app/types/index.ts @@ -1,4 +1,5 @@ import { NavModel, NavModelItem } from './navModel'; import { ContainerProps } from './container'; +import { LocationState, LocationUpdate, UrlQueryMap, UrlQueryValue } from './location'; -export { NavModel, NavModelItem, ContainerProps }; +export { NavModel, NavModelItem, ContainerProps, LocationState, LocationUpdate, UrlQueryValue, UrlQueryMap }; diff --git a/public/app/types/location.ts b/public/app/types/location.ts new file mode 100644 index 00000000000..4a7f51523a7 --- /dev/null +++ b/public/app/types/location.ts @@ -0,0 +1,15 @@ +export interface LocationUpdate { + path?: string; + query?: UrlQueryMap; + routeParams?: UrlQueryMap; +} + +export interface LocationState { + url: string; + path: string; + query: UrlQueryMap; + routeParams: UrlQueryMap; +} + +export type UrlQueryValue = string | number | boolean | string[] | number[] | boolean[]; +export type UrlQueryMap = { [s: string]: UrlQueryValue };