Typescriptify dashboard redux code (#19857)

* Typescriptify dashboard redux code

* Address code review comments

* minor fixes

* move all type dependencies to dev
This commit is contained in:
Stacey Gammon 2018-06-19 09:41:12 -04:00 committed by GitHub
parent fbbd5c111e
commit 26da49e129
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 1325 additions and 879 deletions

View file

@ -86,7 +86,6 @@
"@kbn/pm": "link:packages/kbn-pm",
"@kbn/test-subj-selector": "link:packages/kbn-test-subj-selector",
"@kbn/ui-framework": "link:packages/kbn-ui-framework",
"@types/prop-types": "^15.5.3",
"JSONStream": "1.1.1",
"accept-language-parser": "1.2.0",
"angular": "1.6.9",
@ -231,10 +230,15 @@
"@types/execa": "^0.9.0",
"@types/getopts": "^2.0.0",
"@types/glob": "^5.0.35",
"@types/jest": "^22.2.3",
"@types/listr": "^0.13.0",
"@types/lodash": "^3.10.1",
"@types/minimatch": "^2.0.29",
"@types/prop-types": "^15.5.3",
"@types/react": "^16.3.14",
"@types/react-dom": "^16.0.5",
"@types/redux": "^3.6.31",
"@types/redux-actions": "^2.2.1",
"angular-mocks": "1.4.7",
"babel-eslint": "8.1.2",
"babel-jest": "^22.4.3",

View file

@ -1,60 +0,0 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { createAction } from 'redux-actions';
import _ from 'lodash';
import {
updatePanel
} from './panels';
import {
getPanel,
getEmbeddableCustomization,
} from '../../selectors/dashboard_selectors';
export const embeddableIsInitializing = createAction('EMBEDDABLE_IS_INITIALIZING');
export const embeddableIsInitialized = createAction('EMBEDDABLE_INITIALIZED');
export const setStagedFilter = createAction('SET_STAGED_FILTER');
export const clearStagedFilters = createAction('CLEAR_STAGED_FILTERS');
export const embeddableError = createAction('EMBEDDABLE_ERROR');
/**
* The main point of communication from the embeddable to the dashboard. Any time state in the embeddable
* changes, this function will be called. The data is then extracted from EmbeddableState and stored in
* redux so the appropriate actions are taken and UI updated.
* @param {string} panelId - the id of the panel whose state has changed.
* @param {EmbeddableState} embeddableState - the new state of the embeddable.
*/
export function embeddableStateChanged({ panelId, embeddableState }) {
return (dispatch, getState) => {
// Translate embeddableState to things redux cares about.
const customization = getEmbeddableCustomization(getState(), panelId);
if (!_.isEqual(embeddableState.customization, customization)) {
const panel = getPanel(getState(), panelId);
dispatch(updatePanel({ ...panel, embeddableConfig: _.cloneDeep(embeddableState.customization) }));
}
if (embeddableState.stagedFilter) {
dispatch(setStagedFilter({ stagedFilter: embeddableState.stagedFilter, panelId }));
}
};
}

View file

@ -20,14 +20,12 @@
import { store } from '../../store';
import {
clearStagedFilters,
setStagedFilter,
embeddableIsInitialized,
embeddableIsInitializing,
setStagedFilter,
} from '../actions';
import {
getStagedFilters,
} from '../../selectors';
import { getStagedFilters } from '../../selectors';
beforeAll(() => {
store.dispatch(embeddableIsInitializing('foo1'));
@ -43,13 +41,17 @@ describe('staged filters', () => {
});
test('can set a staged filter', () => {
store.dispatch(setStagedFilter({ stagedFilter: ['imafilter'], panelId: 'foo1' }));
store.dispatch(
setStagedFilter({ stagedFilter: ['imafilter'], panelId: 'foo1' })
);
const stagedFilters = getStagedFilters(store.getState());
expect(stagedFilters.length).toBe(1);
});
test('getStagedFilters returns filters for all embeddables', () => {
store.dispatch(setStagedFilter({ stagedFilter: ['imafilter'], panelId: 'foo2' }));
store.dispatch(
setStagedFilter({ stagedFilter: ['imafilter'], panelId: 'foo2' })
);
const stagedFilters = getStagedFilters(store.getState());
expect(stagedFilters.length).toBe(2);
});
@ -60,4 +62,3 @@ describe('staged filters', () => {
expect(stagedFilters.length).toBe(0);
});
});

View file

@ -0,0 +1,144 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import _ from 'lodash';
import { Dispatch } from 'redux';
import { createAction } from 'redux-actions';
import {
CoreKibanaState,
getEmbeddableCustomization,
getPanel,
} from '../../selectors';
import { PanelId, PanelState } from '../selectors';
import { updatePanel } from './panels';
import { EmbeddableMetadata, EmbeddableState } from 'ui/embeddable';
import { KibanaAction } from '../../selectors/types';
export enum EmbeddableActionTypeKeys {
EMBEDDABLE_IS_INITIALIZING = 'EMBEDDABLE_IS_INITIALIZING',
EMBEDDABLE_IS_INITIALIZED = 'EMBEDDABLE_IS_INITIALIZED',
SET_STAGED_FILTER = 'SET_STAGED_FILTER',
CLEAR_STAGED_FILTERS = 'CLEAR_STAGED_FILTERS',
EMBEDDABLE_ERROR = 'EMBEDDABLE_ERROR',
}
export interface EmbeddableIsInitializingAction
extends KibanaAction<
EmbeddableActionTypeKeys.EMBEDDABLE_IS_INITIALIZING,
PanelId
> {}
export interface EmbeddableIsInitializedActionPayload {
panelId: PanelId;
metadata: EmbeddableMetadata;
}
export interface EmbeddableIsInitializedAction
extends KibanaAction<
EmbeddableActionTypeKeys.EMBEDDABLE_IS_INITIALIZED,
EmbeddableIsInitializedActionPayload
> {}
export interface SetStagedFilterActionPayload {
panelId: PanelId;
stagedFilter: object;
}
export interface SetStagedFilterAction
extends KibanaAction<
EmbeddableActionTypeKeys.SET_STAGED_FILTER,
SetStagedFilterActionPayload
> {}
export interface ClearStagedFiltersAction
extends KibanaAction<
EmbeddableActionTypeKeys.CLEAR_STAGED_FILTERS,
undefined
> {}
export interface EmbeddableErrorActionPayload {
error: string | object;
panelId: PanelId;
}
export interface EmbeddableErrorAction
extends KibanaAction<
EmbeddableActionTypeKeys.EMBEDDABLE_ERROR,
EmbeddableErrorActionPayload
> {}
export type EmbeddableActions =
| EmbeddableIsInitializingAction
| EmbeddableIsInitializedAction
| ClearStagedFiltersAction
| SetStagedFilterAction
| EmbeddableErrorAction;
export const embeddableIsInitializing = createAction<PanelId>(
EmbeddableActionTypeKeys.EMBEDDABLE_IS_INITIALIZING
);
export const embeddableIsInitialized = createAction<
EmbeddableIsInitializedActionPayload
>(EmbeddableActionTypeKeys.EMBEDDABLE_IS_INITIALIZED);
export const setStagedFilter = createAction<SetStagedFilterActionPayload>(
EmbeddableActionTypeKeys.SET_STAGED_FILTER
);
export const clearStagedFilters = createAction(
EmbeddableActionTypeKeys.CLEAR_STAGED_FILTERS
);
export const embeddableError = createAction<EmbeddableErrorActionPayload>(
EmbeddableActionTypeKeys.EMBEDDABLE_ERROR
);
/**
* The main point of communication from the embeddable to the dashboard. Any time state in the embeddable
* changes, this function will be called. The data is then extracted from EmbeddableState and stored in
* redux so the appropriate actions are taken and UI updated.
*
* @param changeData.panelId - the id of the panel whose state has changed.
* @param changeData.embeddableState - the new state of the embeddable.
*/
export function embeddableStateChanged(changeData: {
panelId: PanelId;
embeddableState: EmbeddableState;
}) {
const { panelId, embeddableState } = changeData;
return (
dispatch: Dispatch<CoreKibanaState>,
getState: () => CoreKibanaState
) => {
// Translate embeddableState to things redux cares about.
const customization = getEmbeddableCustomization(getState(), panelId);
if (!_.isEqual(embeddableState.customization, customization)) {
const originalPanelState = getPanel(getState(), panelId);
const newPanelState: PanelState = {
...originalPanelState,
embeddableConfig: _.cloneDeep(embeddableState.customization),
};
dispatch(updatePanel(newPanelState));
}
if (embeddableState.stagedFilter) {
dispatch(
setStagedFilter({ stagedFilter: embeddableState.stagedFilter, panelId })
);
}
};
}

View file

@ -20,8 +20,4 @@
export * from './view';
export * from './panels';
export * from './embeddables';
export {
updateDescription,
updateTitle,
} from './metadata';
export * from './metadata';

View file

@ -0,0 +1,51 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { createAction } from 'redux-actions';
import { KibanaAction } from '../../selectors/types';
export enum MetadataActionTypeKeys {
UPDATE_DESCRIPTION = 'UPDATE_DESCRIPTION',
UPDATE_TITLE = 'UPDATE_TITLE',
}
export type UpdateTitleActionPayload = string;
export interface UpdateTitleAction
extends KibanaAction<
MetadataActionTypeKeys.UPDATE_TITLE,
UpdateTitleActionPayload
> {}
export type UpdateDescriptionActionPayload = string;
export interface UpdateDescriptionAction
extends KibanaAction<
MetadataActionTypeKeys.UPDATE_DESCRIPTION,
UpdateDescriptionActionPayload
> {}
export type MetadataActions = UpdateDescriptionAction | UpdateTitleAction;
export const updateDescription = createAction<UpdateDescriptionAction>(
MetadataActionTypeKeys.UPDATE_DESCRIPTION
);
export const updateTitle = createAction<UpdateTitleAction>(
MetadataActionTypeKeys.UPDATE_TITLE
);

View file

@ -1,43 +0,0 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { createAction } from 'redux-actions';
export const deletePanel = createAction('DELETE_PANEL');
export const updatePanel = createAction('UPDATE_PANEL');
export const resetPanelTitle = createAction('RESET_PANEl_TITLE');
export const setPanelTitle = createAction('SET_PANEl_TITLE',
/**
* @param title {string}
* @param panelIndex {string}
*/
(title, panelIndex) => ({ title, panelIndex })
);
/**
* @param panels {Array<PanelState>}
* @return {Object}
*/
export const updatePanels = createAction('UPDATE_PANELS');
/**
* @param panels {Array<PanelState>}
* @return {Object}
*/
export const setPanels = createAction('SET_PANELS');

View file

@ -0,0 +1,84 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { createAction } from 'redux-actions';
import { KibanaAction } from '../../selectors/types';
import { PanelId, PanelsMap, PanelState } from '../selectors';
export enum PanelActionTypeKeys {
DELETE_PANEL = 'DELETE_PANEL',
UPDATE_PANEL = 'UPDATE_PANEL',
RESET_PANEl_TITLE = 'RESET_PANEl_TITLE',
SET_PANEl_TITLE = 'SET_PANEl_TITLE',
UPDATE_PANELS = 'UPDATE_PANELS',
SET_PANELS = 'SET_PANELS',
}
export interface DeletePanelAction
extends KibanaAction<PanelActionTypeKeys.DELETE_PANEL, PanelId> {}
export interface UpdatePanelAction
extends KibanaAction<PanelActionTypeKeys.UPDATE_PANEL, PanelState> {}
export interface UpdatePanelsAction
extends KibanaAction<PanelActionTypeKeys.UPDATE_PANELS, PanelsMap> {}
export interface ResetPanelTitleAction
extends KibanaAction<PanelActionTypeKeys.RESET_PANEl_TITLE, PanelId> {}
export interface SetPanelTitleActionPayload {
panelId: PanelId;
title: string;
}
export interface SetPanelTitleAction
extends KibanaAction<
PanelActionTypeKeys.SET_PANEl_TITLE,
SetPanelTitleActionPayload
> {}
export interface SetPanelsAction
extends KibanaAction<PanelActionTypeKeys.SET_PANELS, PanelsMap> {}
export type PanelActions =
| DeletePanelAction
| UpdatePanelAction
| ResetPanelTitleAction
| UpdatePanelsAction
| SetPanelTitleAction
| SetPanelsAction;
export const deletePanel = createAction<PanelId>(
PanelActionTypeKeys.DELETE_PANEL
);
export const updatePanel = createAction<PanelState>(
PanelActionTypeKeys.UPDATE_PANEL
);
export const resetPanelTitle = createAction<PanelId>(
PanelActionTypeKeys.RESET_PANEl_TITLE
);
export const setPanelTitle = createAction<SetPanelTitleActionPayload>(
PanelActionTypeKeys.SET_PANEl_TITLE
);
export const updatePanels = createAction<PanelsMap>(
PanelActionTypeKeys.UPDATE_PANELS
);
export const setPanels = createAction<PanelsMap>(
PanelActionTypeKeys.SET_PANELS
);

View file

@ -1,31 +0,0 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { createAction } from 'redux-actions';
export const updateViewMode = createAction('UPDATE_VIEW_MODE');
export const setVisibleContextMenuPanelId = createAction('SET_VISIBLE_CONTEXT_MENU_PANEL_ID');
export const maximizePanel = createAction('MAXIMIZE_PANEl');
export const minimizePanel = createAction('MINIMIZE_PANEL');
export const updateIsFullScreenMode = createAction('UPDATE_IS_FULL_SCREEN_MODE');
export const updateUseMargins = createAction('UPDATE_USE_MARGINS');
export const updateHidePanelTitles = createAction('HIDE_PANEL_TITLES');
export const updateTimeRange = createAction('UPDATE_TIME_RANGE');
export const updateFilters = createAction('UPDATE_FILTERS');
export const updateQuery = createAction('UPDATE_QUERY');

View file

@ -0,0 +1,115 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { createAction } from 'redux-actions';
import { Filters, Query, TimeRange } from 'ui/embeddable';
import { KibanaAction } from '../../selectors/types';
import { DashboardViewMode } from '../dashboard_view_mode';
import { PanelId } from '../selectors';
export enum ViewActionTypeKeys {
UPDATE_VIEW_MODE = 'UPDATE_VIEW_MODE',
SET_VISIBLE_CONTEXT_MENU_PANEL_ID = 'SET_VISIBLE_CONTEXT_MENU_PANEL_ID',
MAXIMIZE_PANEl = 'MAXIMIZE_PANEl',
MINIMIZE_PANEL = 'MINIMIZE_PANEL',
UPDATE_IS_FULL_SCREEN_MODE = 'UPDATE_IS_FULL_SCREEN_MODE',
UPDATE_USE_MARGINS = 'UPDATE_USE_MARGINS',
UPDATE_HIDE_PANEL_TITLES = 'UPDATE_HIDE_PANEL_TITLES',
UPDATE_TIME_RANGE = 'UPDATE_TIME_RANGE',
UPDATE_FILTERS = 'UPDATE_FILTERS',
UPDATE_QUERY = 'UPDATE_QUERY',
}
export interface UpdateViewModeAction
extends KibanaAction<
ViewActionTypeKeys.UPDATE_VIEW_MODE,
DashboardViewMode
> {}
export interface SetVisibleContextMenuPanelIdAction
extends KibanaAction<
ViewActionTypeKeys.SET_VISIBLE_CONTEXT_MENU_PANEL_ID,
PanelId
> {}
export interface MaximizePanelAction
extends KibanaAction<ViewActionTypeKeys.MAXIMIZE_PANEl, PanelId> {}
export interface MinimizePanelAction
extends KibanaAction<ViewActionTypeKeys.MINIMIZE_PANEL, undefined> {}
export interface UpdateIsFullScreenModeAction
extends KibanaAction<
ViewActionTypeKeys.UPDATE_IS_FULL_SCREEN_MODE,
boolean
> {}
export interface UpdateUseMarginsAction
extends KibanaAction<ViewActionTypeKeys.UPDATE_USE_MARGINS, boolean> {}
export interface UpdateHidePanelTitlesAction
extends KibanaAction<ViewActionTypeKeys.UPDATE_HIDE_PANEL_TITLES, boolean> {}
export interface UpdateTimeRangeAction
extends KibanaAction<ViewActionTypeKeys.UPDATE_TIME_RANGE, TimeRange> {}
export interface UpdateFiltersAction
extends KibanaAction<ViewActionTypeKeys.UPDATE_FILTERS, Filters> {}
export interface UpdateQueryAction
extends KibanaAction<ViewActionTypeKeys.UPDATE_QUERY, Query> {}
export type ViewActions =
| UpdateViewModeAction
| SetVisibleContextMenuPanelIdAction
| MaximizePanelAction
| MinimizePanelAction
| UpdateIsFullScreenModeAction
| UpdateUseMarginsAction
| UpdateHidePanelTitlesAction
| UpdateTimeRangeAction
| UpdateFiltersAction
| UpdateQueryAction;
export const updateViewMode = createAction<string>(
ViewActionTypeKeys.UPDATE_VIEW_MODE
);
export const setVisibleContextMenuPanelId = createAction<PanelId>(
ViewActionTypeKeys.SET_VISIBLE_CONTEXT_MENU_PANEL_ID
);
export const maximizePanel = createAction<PanelId>(
ViewActionTypeKeys.MAXIMIZE_PANEl
);
export const minimizePanel = createAction(ViewActionTypeKeys.MINIMIZE_PANEL);
export const updateIsFullScreenMode = createAction<boolean>(
ViewActionTypeKeys.UPDATE_IS_FULL_SCREEN_MODE
);
export const updateUseMargins = createAction<boolean>(
ViewActionTypeKeys.UPDATE_USE_MARGINS
);
export const updateHidePanelTitles = createAction<boolean>(
ViewActionTypeKeys.UPDATE_HIDE_PANEL_TITLES
);
export const updateTimeRange = createAction<TimeRange>(
ViewActionTypeKeys.UPDATE_TIME_RANGE
);
export const updateFilters = createAction<Filters>(
ViewActionTypeKeys.UPDATE_FILTERS
);
export const updateQuery = createAction<Query>(ViewActionTypeKeys.UPDATE_QUERY);

View file

@ -70,4 +70,4 @@
>
</dashboard-viewport-provider>
</dashboard-app>
</dashboard-app>

View file

@ -29,30 +29,30 @@ export function dashboardContextProvider(Private, getAppState) {
const appState = getAppState();
const queryFilter = Private(FilterBarQueryFilterProvider);
const bool = { must: [], must_not: [] };
if (!appState) return { bool: bool };
if (!appState) { return { bool: bool }; }
const filterBarFilters = queryFilter.getFilters();
const queryBarQuery = appState.query;
if (queryBarQuery.language === 'lucene') {
// Add the query bar filter, its handled differently.
const query = luceneStringToDsl(queryBarQuery.query);
if (query) bool.must.push(query);
if (query) { bool.must.push(query); }
}
// Add each of the filter bar filters
_.each(filterBarFilters, function (filter) {
const esFilter = _.omit(filter, function (val, key) {
if (key === 'meta' || key[0] === '$') return true;
if (key === 'meta' || key[0] === '$') { return true; }
return false;
});
if (filter.meta.disabled) return;
if (filter.meta.disabled) { return; }
if (filter.meta.negate) {
bool.must_not = bool.must_not || [];
if (esFilter.query || esFilter) bool.must_not.push(migrateFilter(esFilter.query || esFilter));
if (esFilter.query || esFilter) { bool.must_not.push(migrateFilter(esFilter.query || esFilter)); }
} else {
bool.must = bool.must || [];
if (esFilter.query || esFilter) bool.must.push(migrateFilter(esFilter.query || esFilter));
if (esFilter.query || esFilter) { bool.must.push(migrateFilter(esFilter.query || esFilter)); }
}
});

View file

@ -17,16 +17,7 @@
* under the License.
*/
/**
* A dashboard mode.
* @typedef {string} DashboardMode
*/
/**
* Dashboard view modes.
* @type {{EDIT: DashboardViewMode, VIEW: DashboardViewMode}}
*/
export const DashboardViewMode = {
EDIT: 'edit',
VIEW: 'view'
};
export enum DashboardViewMode {
EDIT = 'edit',
VIEW = 'view',
}

View file

@ -62,12 +62,12 @@ test('Panel header shows embeddable title when nothing is set on the panel', ()
});
test('Panel header shows panel title when it is set on the panel', () => {
store.dispatch(setPanelTitle('my custom panel title', 'foo1'));
store.dispatch(setPanelTitle({ title: 'my custom panel title', panelId: 'foo1' }));
expect(findTestSubject(component, 'dashboardPanelTitle').text()).toBe('my custom panel title');
});
test('Panel header shows no panel title when it is set to an empty string on the panel', () => {
store.dispatch(setPanelTitle('', 'foo1'));
store.dispatch(setPanelTitle({ title: '', panelId: 'foo1' }));
expect(findTestSubject(component, 'dashboardPanelTitle').text()).toBe('');
});

View file

@ -83,7 +83,7 @@ const mapDispatchToProps = (dispatch, { panelId }) => ({
onMaximizePanel: () => dispatch(maximizePanel(panelId)),
onMinimizePanel: () => dispatch(minimizePanel()),
onResetPanelTitle: () => dispatch(resetPanelTitle(panelId)),
onUpdatePanelTitle: (newTitle) => dispatch(setPanelTitle(newTitle, panelId)),
onUpdatePanelTitle: (newTitle) => dispatch(setPanelTitle({ title: newTitle, panelId: panelId })),
});
const mergeProps = (stateProps, dispatchProps, ownProps) => {

View file

@ -1,121 +0,0 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { handleActions } from 'redux-actions';
import _ from 'lodash';
import {
embeddableIsInitializing,
embeddableError,
embeddableIsInitialized,
setStagedFilter,
clearStagedFilters,
deletePanel,
} from '../actions';
export const embeddables = handleActions({
[clearStagedFilters]:
(embeddables) => {
return _.mapValues(embeddables, (embeddable) => _.omit({ ...embeddable }, ['stagedFilter']));
},
[embeddableIsInitialized]:
/**
*
* @param embeddables {Object.<string, EmbeddableState>}
* @param payload {Object}
* @param payload.panelId {string} Panel id of embeddable that was initialized
* @param payload.metadata {object} Metadata for the embeddable that was initialized
* @return {Object.<string, EmbeddableState>}
*/
(embeddables, { payload }) => {
return {
...embeddables,
[payload.panelId]: {
...embeddables[payload.panelId],
initialized: true,
metadata: { ...payload.metadata },
}
};
},
// TODO: Currently only saved search uses this to apply a filter. When visualize uses it too, we will need to
// support multiple staged filters.
[setStagedFilter]:
(embeddables, { payload }) => {
return {
...embeddables,
[payload.panelId]: {
...embeddables[payload.panelId],
stagedFilter: payload.stagedFilter,
}
};
},
[deletePanel]:
/**
*
* @param embeddables {Object.<string, EmbeddableState>}
* @param payload {String} The id of the panel to delete
* @return {Object.<string, EmbeddableState>}
*/
(embeddables, { payload }) => {
const embeddablesCopy = { ...embeddables };
delete embeddablesCopy[payload];
return embeddablesCopy;
},
[embeddableIsInitializing]:
/**
*
* @param embeddables {Object.<string, EmbeddableState>}
* @param payload {Object}
* @param payload.panelId {String}
* @param payload.embeddable {Embeddable}
* @return {Object.<string, EmbeddableState>}
*/
(embeddables, { payload }) => {
return {
...embeddables,
[payload]: {
initialized: false,
error: undefined,
}
};
},
[embeddableError]:
/**
*
* @param embeddables {Object.<string, EmbeddableState>}
* @param payload {Object}
* @param payload.panelId {String}
* @param payload.error {String|Object}
* @return {Object.<string, EmbeddableState>}
*/
(embeddables, { payload }) => {
return {
...embeddables,
[payload.panelId]: {
...embeddables[payload.panelId],
error: payload.error,
}
};
}
}, {});

View file

@ -17,17 +17,26 @@
* under the License.
*/
import { getEmbeddableError, getEmbeddableInitialized } from '../../selectors';
import { store } from '../../store';
import {
embeddableIsInitializing, setPanels,
} from '../actions';
import {
getEmbeddableError,
getEmbeddableInitialized,
} from '../../selectors';
import { embeddableIsInitializing, setPanels } from '../actions';
beforeAll(() => {
store.dispatch(setPanels({ 'foo1': { panelIndex: 'foo1' } }));
const panelData = {
embeddableConfig: {},
gridData: {
h: 0,
id: '0',
w: 0,
x: 0,
y: 0,
},
id: '123',
panelIndex: 'foo1',
type: 'mySpecialType',
version: '123',
};
store.dispatch(setPanels({ foo1: panelData }));
});
describe('embeddableIsInitializing', () => {
@ -42,4 +51,3 @@ describe('embeddableIsInitializing', () => {
expect(error).toBe(undefined);
});
});

View file

@ -0,0 +1,121 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import _ from 'lodash';
import { Reducer } from 'redux';
import {
EmbeddableActionTypeKeys,
EmbeddableErrorActionPayload,
EmbeddableIsInitializedActionPayload,
PanelActionTypeKeys,
SetStagedFilterActionPayload,
} from '../actions';
import {
EmbeddableReduxState,
EmbeddablesMap,
PanelId,
} from '../selectors/types';
const embeddableIsInitializing = (
embeddables: EmbeddablesMap,
panelId: PanelId
): EmbeddablesMap => ({
...embeddables,
[panelId]: {
error: undefined,
initialized: false,
metadata: {},
stagedFilter: undefined,
},
});
const embeddableIsInitialized = (
embeddables: EmbeddablesMap,
{ panelId, metadata }: EmbeddableIsInitializedActionPayload
): EmbeddablesMap => ({
...embeddables,
[panelId]: {
...embeddables[panelId],
initialized: true,
metadata: { ...metadata },
},
});
const setStagedFilter = (
embeddables: EmbeddablesMap,
{ panelId, stagedFilter }: SetStagedFilterActionPayload
): EmbeddablesMap => ({
...embeddables,
[panelId]: {
...embeddables[panelId],
stagedFilter,
},
});
const embeddableError = (
embeddables: EmbeddablesMap,
payload: EmbeddableErrorActionPayload
): EmbeddablesMap => ({
...embeddables,
[payload.panelId]: {
...embeddables[payload.panelId],
error: payload.error,
},
});
const clearStagedFilters = (embeddables: EmbeddablesMap): EmbeddablesMap => {
const omitStagedFilters = (
embeddable: EmbeddableReduxState
): EmbeddablesMap => _.omit({ ...embeddable }, ['stagedFilter']);
return _.mapValues<EmbeddablesMap>(embeddables, omitStagedFilters);
};
const deleteEmbeddable = (
embeddables: EmbeddablesMap,
panelId: PanelId
): EmbeddablesMap => {
const embeddablesCopy = { ...embeddables };
delete embeddablesCopy[panelId];
return embeddablesCopy;
};
export const embeddablesReducer: Reducer<EmbeddablesMap> = (
embeddables = {},
action
): EmbeddablesMap => {
switch (
action.type as EmbeddableActionTypeKeys | PanelActionTypeKeys.DELETE_PANEL
) {
case EmbeddableActionTypeKeys.EMBEDDABLE_IS_INITIALIZING:
return embeddableIsInitializing(embeddables, action.payload);
case EmbeddableActionTypeKeys.EMBEDDABLE_IS_INITIALIZED:
return embeddableIsInitialized(embeddables, action.payload);
case EmbeddableActionTypeKeys.SET_STAGED_FILTER:
return setStagedFilter(embeddables, action.payload);
case EmbeddableActionTypeKeys.CLEAR_STAGED_FILTERS:
return clearStagedFilters(embeddables);
case EmbeddableActionTypeKeys.EMBEDDABLE_ERROR:
return embeddableError(embeddables, action.payload);
case PanelActionTypeKeys.DELETE_PANEL:
return deleteEmbeddable(embeddables, action.payload);
default:
return embeddables;
}
};

View file

@ -18,25 +18,17 @@
*/
import { combineReducers } from 'redux';
import {
embeddables,
} from './embeddables';
import { embeddablesReducer } from './embeddables';
import {
panels,
} from './panels';
import { panelsReducer } from './panels';
import {
view,
} from './view';
import { viewReducer } from './view';
import {
metadata,
} from './metadata';
import { metadataReducer } from './metadata';
export const dashboard = combineReducers({
view,
panels,
embeddables,
metadata,
embeddables: embeddablesReducer,
metadata: metadataReducer,
panels: panelsReducer,
view: viewReducer,
});

View file

@ -1,37 +0,0 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { handleActions } from 'redux-actions';
import { updateTitle, updateDescription } from '../actions';
export const metadata = handleActions({
[updateTitle]: (state, { payload }) => ({
...state,
title: payload
}),
[updateDescription]: (state, { payload }) => ({
...state,
description: payload
}),
}, {
title: '',
description: '',
});

View file

@ -0,0 +1,60 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { Reducer } from 'redux';
import {
MetadataActions,
MetadataActionTypeKeys,
UpdateDescriptionActionPayload,
UpdateTitleActionPayload,
} from '../actions';
import { DashboardMetadata } from '../selectors';
const updateTitle = (
metadata: DashboardMetadata,
title: UpdateTitleActionPayload
) => ({
...metadata,
title,
});
const updateDescription = (
metadata: DashboardMetadata,
description: UpdateDescriptionActionPayload
) => ({
...metadata,
description,
});
export const metadataReducer: Reducer<DashboardMetadata> = (
metadata = {
description: '',
title: '',
},
action
): DashboardMetadata => {
switch ((action as MetadataActions).type) {
case MetadataActionTypeKeys.UPDATE_TITLE:
return updateTitle(metadata, action.payload);
case MetadataActionTypeKeys.UPDATE_DESCRIPTION:
return updateDescription(metadata, action.payload);
default:
return metadata;
}
};

View file

@ -1,120 +0,0 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import _ from 'lodash';
import { handleActions } from 'redux-actions';
import {
deletePanel,
updatePanel,
updatePanels,
setPanels,
resetPanelTitle,
setPanelTitle,
} from '../actions';
/**
*
* @param panel {PanelState} - new panel data (can be partial data) to merge with possibly existing panel data in
* the panels mapping.
* @param panel.panelIndex {String} The new panel data must specify the panelIndex so we know which panel to merge with.
* @param panels {Object.<string, PanelState>}
* @return {PanelState} - a new PanelState which has the merged data.
*/
function mergePanelData(panel, panels) {
return _.defaultsDeep(panel, panels[panel.panelIndex]);
}
export const panels = handleActions({
[setPanels]:
/**
*
* @param panels {Object.<string, PanelState>}
* @param payload {Object.<string, PanelState>}
* @return {Object.<string, PanelState>}
*/
(panels, { payload }) => _.cloneDeep(payload),
[updatePanels]:
/**
*
* @param panels {Object.<string, PanelState>}
* @param payload {Object.<string, PanelState>}
* @return {Object.<string, PanelState>}
*/
(panels, { payload }) => {
const panelsCopy = { ...panels };
Object.values(payload).forEach(panel => {
panelsCopy[panel.panelIndex] = mergePanelData(panel, panels);
});
return panelsCopy;
},
[deletePanel]:
/**
*
* @param panels {Object.<string, PanelState>}
* @param payload {string} The panelIndex of the panel to delete
* @return {Object.<string, PanelState>}
*/
(panels, { payload }) => {
const panelsCopy = { ...panels };
delete panelsCopy[payload];
return panelsCopy;
},
[updatePanel]:
/**
* @param panels {Object.<string, PanelState>}
* @param payload {PanelState} The new panel state (is merged with existing).
* @param payload.panelIndex {string} The id of the panel to update.
* @return {Object.<string, PanelState>}
*/
(panels, { payload }) => ({
...panels,
[payload.panelIndex]: mergePanelData(payload, panels),
}),
[resetPanelTitle]:
/**
* @param panels {Object.<string, PanelState>}
* @param payload {String} The id of the panel to reset it's title.
* @return {Object.<string, PanelState>}
*/
(panels, { payload }) => ({
...panels,
[payload]: {
...panels[payload],
title: undefined,
}
}),
[setPanelTitle]:
/**
* @param panels {Object.<string, PanelState>}
* @param payload {PanelState} The new panel state (is merged with existing).
* @param payload.panelIndex {String} The id of the panel to reset it's title.
* @param payload.title {String} The new title to use.
* @return {Object.<string, PanelState>}
*/
(panels, { payload }) => ({
...panels,
[payload.panelIndex]: mergePanelData(payload, panels),
}),
}, {});

View file

@ -17,27 +17,37 @@
* under the License.
*/
import { getPanel, getPanelType } from '../../selectors';
import { store } from '../../store';
import { updatePanel, updatePanels } from '../actions';
import {
getPanel,
getPanelType,
} from '../../selectors';
test('UpdatePanel updates a panel', () => {
store.dispatch(updatePanels([{ panelIndex: '1', gridData: {} }]));
store.dispatch(updatePanel({
const panelData = {
embeddableConfig: {},
gridData: {
h: 0,
id: '0',
w: 0,
x: 0,
y: 0,
},
id: '123',
panelIndex: '1',
type: 'mySpecialType',
version: '123',
};
store.dispatch(updatePanels({ '1': panelData }));
const newPanelData = {
...panelData,
gridData: {
h: 1,
id: '1',
w: 10,
x: 1,
y: 5,
w: 10,
h: 1,
id: '1'
}
}));
},
};
store.dispatch(updatePanel(newPanelData));
const panel = getPanel(store.getState(), '1');
expect(panel.gridData.x).toBe(1);

View file

@ -0,0 +1,103 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import _ from 'lodash';
import { Reducer } from 'redux';
import {
PanelActions,
PanelActionTypeKeys,
SetPanelTitleActionPayload,
} from '../actions';
import { PanelId, PanelsMap, PanelState } from '../selectors';
/**
* @param panel - New panel data (can be partial data) to merge with possibly existing panel data in
* the panels mapping.
* @param panels
* @return a new PanelState which has the merged data.
*/
function mergePanelData(panel: PanelState, panels: PanelsMap): PanelState {
return _.defaultsDeep(panel, panels[panel.panelIndex]);
}
const deletePanel = (panels: PanelsMap, panelId: PanelId): PanelsMap => {
const panelsCopy = { ...panels };
delete panelsCopy[panelId];
return panelsCopy;
};
const updatePanel = (panels: PanelsMap, panelState: PanelState): PanelsMap => ({
...panels,
[panelState.panelIndex]: mergePanelData(panelState, panels),
});
const updatePanels = (
panels: PanelsMap,
updatedPanels: PanelsMap
): PanelsMap => {
const panelsCopy = { ...panels };
Object.values(updatedPanels).forEach(panel => {
panelsCopy[panel.panelIndex] = mergePanelData(panel, panels);
});
return panelsCopy;
};
const resetPanelTitle = (panels: PanelsMap, panelId: PanelId) => ({
...panels,
[panelId]: {
...panels[panelId],
title: undefined,
},
});
const setPanelTitle = (
panels: PanelsMap,
payload: SetPanelTitleActionPayload
) => ({
...panels,
[payload.panelId]: {
...panels[payload.panelId],
title: payload.title,
},
});
const setPanels = (panels: PanelsMap, newPanels: PanelsMap) =>
_.cloneDeep(newPanels);
export const panelsReducer: Reducer<PanelsMap> = (
panels = {},
action
): PanelsMap => {
switch ((action as PanelActions).type) {
case PanelActionTypeKeys.DELETE_PANEL:
return deletePanel(panels, action.payload);
case PanelActionTypeKeys.UPDATE_PANEL:
return updatePanel(panels, action.payload);
case PanelActionTypeKeys.UPDATE_PANELS:
return updatePanels(panels, action.payload);
case PanelActionTypeKeys.RESET_PANEl_TITLE:
return resetPanelTitle(panels, action.payload);
case PanelActionTypeKeys.SET_PANEl_TITLE:
return setPanelTitle(panels, action.payload);
case PanelActionTypeKeys.SET_PANELS:
return setPanels(panels, action.payload);
default:
return panels;
}
};

View file

@ -1,87 +0,0 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { handleActions, combineActions } from 'redux-actions';
import {
updateViewMode,
maximizePanel,
minimizePanel,
updateUseMargins,
updateHidePanelTitles,
updateIsFullScreenMode,
updateTimeRange,
updateFilters,
updateQuery,
setVisibleContextMenuPanelId,
} from '../actions';
import { DashboardViewMode } from '../dashboard_view_mode';
export const view = handleActions({
[setVisibleContextMenuPanelId]: (state, { payload }) => ({
...state,
visibleContextMenuPanelId: payload
}),
[updateViewMode]: (state, { payload }) => ({
...state,
viewMode: payload
}),
[updateTimeRange]: (state, { payload }) => ({
...state,
timeRange: payload
}),
[updateFilters]: (state, { payload }) => ({
...state,
filters: payload
}),
[updateQuery]: (state, { payload }) => ({
...state,
query: payload
}),
[updateUseMargins]: (state, { payload }) => ({
...state,
useMargins: payload
}),
[updateHidePanelTitles]: (state, { payload }) => ({
...state,
hidePanelTitles: payload
}),
[combineActions(maximizePanel, minimizePanel)]: (state, { payload }) => ({
...state,
maximizedPanelId: payload
}),
[updateIsFullScreenMode]: (state, { payload }) => ({
...state,
isFullScreenMode: payload
}),
}, {
isFullScreenMode: false,
viewMode: DashboardViewMode.VIEW,
maximizedPanelId: undefined,
useMargins: true,
hidePanelTitles: false,
});

View file

@ -19,16 +19,16 @@
import { store } from '../../store';
import {
updateIsFullScreenMode,
updateViewMode,
maximizePanel,
minimizePanel,
updateIsFullScreenMode,
updateViewMode,
} from '../actions';
import {
getFullScreenMode,
getViewMode,
getMaximizedPanelId,
getViewMode,
} from '../../selectors';
import { DashboardViewMode } from '../dashboard_view_mode';

View file

@ -0,0 +1,117 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { Reducer } from 'redux';
import { ViewActions, ViewActionTypeKeys } from '../actions';
import { Filters, Query, TimeRange } from 'ui/embeddable';
import { QueryLanguageType } from 'ui/embeddable/types';
import { DashboardViewMode } from '../dashboard_view_mode';
import { PanelId, ViewState } from '../selectors';
const setVisibleContextMenuPanelId = (view: ViewState, panelId: PanelId) => ({
...view,
visibleContextMenuPanelId: panelId,
});
const updateHidePanelTitles = (view: ViewState, hidePanelTitles: boolean) => ({
...view,
hidePanelTitles,
});
const minimizePanel = (view: ViewState) => ({
...view,
maximizedPanelId: undefined,
});
const maximizePanel = (view: ViewState, panelId: PanelId) => ({
...view,
maximizedPanelId: panelId,
});
const updateIsFullScreenMode = (
view: ViewState,
isFullScreenMode: boolean
) => ({
...view,
isFullScreenMode,
});
const updateTimeRange = (view: ViewState, timeRange: TimeRange) => ({
...view,
timeRange,
});
const updateFilters = (view: ViewState, filters: Filters) => ({
...view,
filters,
});
const updateQuery = (view: ViewState, query: Query) => ({
...view,
query,
});
const updateUseMargins = (view: ViewState, useMargins: boolean) => ({
...view,
useMargins,
});
const updateViewMode = (view: ViewState, viewMode: DashboardViewMode) => ({
...view,
viewMode,
});
export const viewReducer: Reducer<ViewState> = (
view = {
filters: [],
hidePanelTitles: false,
isFullScreenMode: false,
query: { language: QueryLanguageType.LUCENE, query: '' },
timeRange: { to: 'now', from: 'now-15m' },
useMargins: true,
viewMode: DashboardViewMode.VIEW,
},
action
): ViewState => {
switch ((action as ViewActions).type) {
case ViewActionTypeKeys.MINIMIZE_PANEL:
return minimizePanel(view);
case ViewActionTypeKeys.MAXIMIZE_PANEl:
return maximizePanel(view, action.payload);
case ViewActionTypeKeys.SET_VISIBLE_CONTEXT_MENU_PANEL_ID:
return setVisibleContextMenuPanelId(view, action.payload);
case ViewActionTypeKeys.UPDATE_HIDE_PANEL_TITLES:
return updateHidePanelTitles(view, action.payload);
case ViewActionTypeKeys.UPDATE_TIME_RANGE:
return updateTimeRange(view, action.payload);
case ViewActionTypeKeys.UPDATE_USE_MARGINS:
return updateUseMargins(view, action.payload);
case ViewActionTypeKeys.UPDATE_VIEW_MODE:
return updateViewMode(view, action.payload);
case ViewActionTypeKeys.UPDATE_IS_FULL_SCREEN_MODE:
return updateIsFullScreenMode(view, action.payload);
case ViewActionTypeKeys.UPDATE_FILTERS:
return updateFilters(view, action.payload);
case ViewActionTypeKeys.UPDATE_QUERY:
return updateQuery(view, action.payload);
default:
return view;
}
};

View file

@ -0,0 +1,171 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import _ from 'lodash';
import {
ContainerState,
EmbeddableMetadata,
Filters,
Query,
TimeRange,
} from 'ui/embeddable';
import { DashboardViewMode } from '../dashboard_view_mode';
import {
DashboardMetadata,
DashboardState,
EmbeddableReduxState,
EmbeddablesMap,
PanelId,
PanelsMap,
PanelState,
} from './types';
export const getPanels = (dashboard: DashboardState): PanelsMap =>
dashboard.panels;
export const getPanel = (
dashboard: DashboardState,
panelId: PanelId
): PanelState => getPanels(dashboard)[panelId];
export const getPanelType = (
dashboard: DashboardState,
panelId: PanelId
): string => getPanel(dashboard, panelId).type;
export const getEmbeddables = (dashboard: DashboardState): EmbeddablesMap =>
dashboard.embeddables;
// TODO: rename panel.embeddableConfig to embeddableCustomization. Because it's on the panel that's stored on a
// dashboard, renaming this will require a migration step.
export const getEmbeddableCustomization = (
dashboard: DashboardState,
panelId: PanelId
): object => getPanel(dashboard, panelId).embeddableConfig;
export const getEmbeddable = (
dashboard: DashboardState,
panelId: PanelId
): EmbeddableReduxState => dashboard.embeddables[panelId];
export const getEmbeddableError = (
dashboard: DashboardState,
panelId: PanelId
): string | object | undefined => getEmbeddable(dashboard, panelId).error;
export const getEmbeddableTitle = (
dashboard: DashboardState,
panelId: PanelId
): string | undefined => {
const embeddable = getEmbeddable(dashboard, panelId);
return embeddable && embeddable.initialized && embeddable.metadata
? embeddable.metadata.title
: '';
};
export const getEmbeddableInitialized = (
dashboard: DashboardState,
panelId: PanelId
): boolean => getEmbeddable(dashboard, panelId).initialized;
export const getEmbeddableStagedFilter = (
dashboard: DashboardState,
panelId: PanelId
): object | undefined => getEmbeddable(dashboard, panelId).stagedFilter;
export const getEmbeddableMetadata = (
dashboard: DashboardState,
panelId: PanelId
): EmbeddableMetadata | undefined => getEmbeddable(dashboard, panelId).metadata;
export const getEmbeddableEditUrl = (
dashboard: DashboardState,
panelId: PanelId
): string | undefined => {
const embeddable = getEmbeddable(dashboard, panelId);
return embeddable && embeddable.initialized && embeddable.metadata
? embeddable.metadata.editUrl
: '';
};
export const getVisibleContextMenuPanelId = (
dashboard: DashboardState
): PanelId | undefined => dashboard.view.visibleContextMenuPanelId;
export const getUseMargins = (dashboard: DashboardState): boolean =>
dashboard.view.useMargins;
export const getViewMode = (dashboard: DashboardState): DashboardViewMode =>
dashboard.view.viewMode;
export const getFullScreenMode = (dashboard: DashboardState): boolean =>
dashboard.view.isFullScreenMode;
export const getHidePanelTitles = (dashboard: DashboardState): boolean =>
dashboard.view.hidePanelTitles;
export const getMaximizedPanelId = (
dashboard: DashboardState
): PanelId | undefined => dashboard.view.maximizedPanelId;
export const getTimeRange = (dashboard: DashboardState): TimeRange =>
dashboard.view.timeRange;
export const getFilters = (dashboard: DashboardState): Filters =>
dashboard.view.filters;
export const getQuery = (dashboard: DashboardState): Query =>
dashboard.view.query;
export const getMetadata = (dashboard: DashboardState): DashboardMetadata =>
dashboard.metadata;
export const getTitle = (dashboard: DashboardState): string =>
dashboard.metadata.title;
export const getDescription = (dashboard: DashboardState): string | undefined =>
dashboard.metadata.description;
export const getContainerState = (
dashboard: DashboardState,
panelId: PanelId
): ContainerState => {
const time = getTimeRange(dashboard);
return {
customTitle: getPanel(dashboard, panelId).title,
embeddableCustomization: _.cloneDeep(
getEmbeddableCustomization(dashboard, panelId) || {}
),
filters: getFilters(dashboard),
hidePanelTitles: getHidePanelTitles(dashboard),
isPanelExpanded: getMaximizedPanelId(dashboard) === panelId,
query: getQuery(dashboard),
timeRange: {
from: time.from,
to: time.to,
},
viewMode: getViewMode(dashboard),
};
};
/**
* @return an array of filters any embeddables wish dashboard to apply
*/
export const getStagedFilters = (dashboard: DashboardState): Filters =>
_.compact(_.map(dashboard.embeddables, 'stagedFilter'));

View file

@ -1,228 +0,0 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import _ from 'lodash';
/**
* @typedef {Object} ViewState
* @property {DashboardViewMode} viewMode
* @property {boolean} isFullScreenMode
* @property {string|undefined} maximizedPanelId
* @property {string|undefined} getVisibleContextMenuPanelId
*/
/**
* @typedef {Object} EmbeddableReduxState
* @property {string} title
* @property {string} editUrl
* @property {string|object} error
*/
/**
* @typedef {Object} DashboardState
* @property {Object.<string, PanelState>} panels
* @property {Object.<string, EmbeddableReduxState>} embeddables
* @property {ViewState} view
*/
/**
* @param dashboard {DashboardState}
* @return {Object.<string, PanelState>}
*/
export const getPanels = dashboard => dashboard.panels;
/**
* @param dashboard {DashboardState}
* @param panelId {string}
* @return {PanelState}
*/
export const getPanel = (dashboard, panelId) => getPanels(dashboard)[panelId];
/**
* @param dashboard {DashboardState}
* @param panelId {string}
* @return {string}
*/
export const getPanelType = (dashboard, panelId) => getPanel(dashboard, panelId).type;
export const getEmbeddables = (dashboard) => dashboard.embeddables;
// TODO: rename panel.embeddableConfig to embeddableCustomization. Because it's on the panel that's stored on a
// dashboard, renaming this will require a migration step.
export const getEmbeddableCustomization = (dashboard, panelId) => getPanel(dashboard, panelId).embeddableConfig;
/**
* @param dashboard {DashboardState}
* @param panelId {string}
* @return {EmbeddableReduxState}
*/
export const getEmbeddable = (dashboard, panelId) => dashboard.embeddables[panelId];
/**
* @param dashboard {DashboardState}
* @param panelId {string}
* @return {string|Object}
*/
export const getEmbeddableError = (dashboard, panelId) => getEmbeddable(dashboard, panelId).error;
/**
* @param dashboard {DashboardState}
* @param panelId {string}
* @return {string}
*/
export const getEmbeddableTitle = (dashboard, panelId) => {
const embeddable = getEmbeddable(dashboard, panelId);
return embeddable && embeddable.initialized ? embeddable.metadata.title : '';
};
/**
* @param dashboard {DashboardState}
* @param panelId {string}
* @return {boolean}
*/
export const getEmbeddableRenderComplete = (dashboard, panelId) => getEmbeddable(dashboard, panelId).renderComplete;
/**
* @param dashboard {DashboardState}
* @param panelId {string}
* @return {boolean}
*/
export const getEmbeddableInitialized = (dashboard, panelId) => getEmbeddable(dashboard, panelId).initialized;
export const getEmbeddableStagedFilter = (dashboard, panelId) => getEmbeddable(dashboard, panelId).stagedFilter;
/**
*
* @param dashboard {DashboardState}
* @param panelId {string}
* @return {EmbeddableMetadata}
*/
export const getEmbeddableMetadata = (dashboard, panelId) => getEmbeddable(dashboard, panelId).metadata;
/**
* @param dashboard {DashboardState}
* @param panelId {string}
* @return {string}
*/
export const getEmbeddableEditUrl = (dashboard, panelId) => {
const embeddable = getEmbeddable(dashboard, panelId);
return embeddable && embeddable.initialized ? embeddable.metadata.editUrl : '';
};
export const getVisibleContextMenuPanelId = dashboard => dashboard.view.visibleContextMenuPanelId;
/**
* @param dashboard {DashboardState}
* @return {boolean}
*/
export const getUseMargins = dashboard => dashboard.view.useMargins;
/**
* @param dashboard {DashboardState}
* @return {DashboardViewMode}
*/
export const getViewMode = dashboard => dashboard.view.viewMode;
/**
* @param dashboard {DashboardState}
* @return {boolean}
*/
export const getFullScreenMode = dashboard => dashboard.view.isFullScreenMode;
/**
* @param dashboard {DashboardState}
* @return {boolean}
*/
export const getHidePanelTitles = dashboard => dashboard.view.hidePanelTitles;
/**
* @param dashboard {DashboardState}
* @return {string|undefined}
*/
export const getMaximizedPanelId = dashboard => dashboard.view.maximizedPanelId;
/**
* @param dashboard {DashboardState}
* @return {{ from: {string}, to: {string}, mode: {string} }}
*/
export const getTimeRange = dashboard => dashboard.view.timeRange;
export const getFilters = dashboard => dashboard.view.filters;
export const getQuery = dashboard => dashboard.view.query;
/**
* @typedef {Object} DashboardMetadata
* @property {string} title
* @property {string} description
*/
/**
* @param dashboard {DashboardState}
* @return {DashboardMetadata}
*/
export const getMetadata = dashboard => dashboard.metadata;
/**
* @param dashboard {DashboardState}
* @return {string}
*/
export const getTitle = dashboard => dashboard.metadata.title;
/**
* @param dashboard {DashboardState}
* @return {string}
*/
export const getDescription = dashboard => dashboard.metadata.description;
/**
* This state object is specifically for communicating to embeddables and it's structure is not tied to
* the redux tree structure.
* @typedef {Object} ContainerState
* @property {DashboardViewMode} viewMode - edit or view mode.
* @property {String} timeRange.to - either an absolute time range in utc format or a relative one (e.g. now-15m)
* @property {String} timeRange.from - either an absolute time range in utc format or a relative one (e.g. now-15m)
* @property {Object} embeddableCustomization
* @property {boolean} hidePanelTitles
* @property {boolean} isPanelExpanded
*/
/**
*
* @param dashboard {DashboardState}
* @param panelId {string}
* @return {ContainerState}
*/
export const getContainerState = (dashboard, panelId) => {
const time = getTimeRange(dashboard);
return {
timeRange: {
to: time.to,
from: time.from,
},
filters: getFilters(dashboard),
query: getQuery(dashboard),
embeddableCustomization: _.cloneDeep(getEmbeddableCustomization(dashboard, panelId) || {}),
hidePanelTitles: getHidePanelTitles(dashboard),
customTitle: getPanel(dashboard, panelId).title,
viewMode: getViewMode(dashboard),
isPanelExpanded: getMaximizedPanelId(dashboard) === panelId,
};
};
/**
*
* @param embeddables {Array.<EmbeddableState>}
* @return {Array.<{ field, value, operator, index }>} Array of filters any embeddables wish dashboard to apply
*/
export const getStagedFilters = ({ embeddables }) => _.compact(_.map(embeddables, 'stagedFilter'));

View file

@ -17,7 +17,6 @@
* under the License.
*/
import { createAction } from 'redux-actions';
export * from './types';
export const updateDescription = createAction('UPDATE_DESCRIPTION');
export const updateTitle = createAction('UPDATE_TITLE');
export * from './dashboard';

View file

@ -0,0 +1,81 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { EmbeddableMetadata, Filters, Query, TimeRange } from 'ui/embeddable';
import { DashboardViewMode } from '../dashboard_view_mode';
export interface ViewState {
readonly viewMode: DashboardViewMode;
readonly isFullScreenMode: boolean;
readonly maximizedPanelId?: string;
readonly visibleContextMenuPanelId?: string;
readonly timeRange: TimeRange;
readonly hidePanelTitles: boolean;
readonly useMargins: boolean;
readonly query: Query;
readonly filters: Filters;
}
export interface GridData {
readonly w: number;
readonly h: number;
readonly x: number;
readonly y: number;
readonly id: string;
}
export type PanelId = string;
export type SavedObjectId = string;
export interface PanelState {
readonly id: SavedObjectId;
readonly version: string;
readonly type: string;
readonly panelIndex: PanelId;
readonly embeddableConfig: object;
readonly gridData: GridData;
readonly title?: string;
}
export interface EmbeddableReduxState {
readonly metadata?: EmbeddableMetadata;
readonly error?: string | object;
readonly initialized: boolean;
readonly stagedFilter?: object;
}
export interface PanelsMap {
readonly [panelId: string]: PanelState;
}
export interface EmbeddablesMap {
readonly [panelId: string]: EmbeddableReduxState;
}
export interface DashboardMetadata {
readonly title: string;
readonly description?: string;
}
export interface DashboardState {
readonly view: ViewState;
readonly panels: PanelsMap;
readonly embeddables: EmbeddablesMap;
readonly metadata: DashboardMetadata;
}

View file

@ -19,11 +19,12 @@
import { combineReducers } from 'redux';
import { dashboard } from './dashboard/reducers';
import { CoreKibanaState } from './selectors';
/**
* Only a single reducer now, but eventually there should be one for each sub app that is part of the
* core kibana plugins.
*/
export const reducers = combineReducers({
dashboard
export const reducers = combineReducers<CoreKibanaState>({
dashboard,
});

View file

@ -1,59 +0,0 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import * as DashboardSelectors from '../dashboard/selectors';
/**
* @typedef {Object} KibanaCoreAppState
* @property {Object} DashboardState
*/
/**
* @param {KibanaCoreAppState} state
* @return {DashboardState}
*/
export const getDashboard = state => state.dashboard;
export const getPanels = state => DashboardSelectors.getPanels(getDashboard(state));
export const getPanel = (state, panelId) => DashboardSelectors.getPanel(getDashboard(state), panelId);
export const getPanelType = (state, panelId) => DashboardSelectors.getPanelType(getDashboard(state), panelId);
export const getEmbeddables = state => DashboardSelectors.getEmbeddables(getDashboard(state));
export const getEmbeddableError = (state, panelId) =>
DashboardSelectors.getEmbeddableError((getDashboard(state)), panelId);
export const getEmbeddableInitialized = (state, panelId) => DashboardSelectors.getEmbeddableInitialized(getDashboard(state), panelId);
export const getEmbeddableCustomization =
(state, panelId) => DashboardSelectors.getEmbeddableCustomization(getDashboard(state), panelId);
export const getEmbeddableStagedFilter =
(state, panelId) => DashboardSelectors.getEmbeddableStagedFilter(getDashboard(state), panelId);
export const getEmbeddableMetadata =
(state, panelId) => DashboardSelectors.getEmbeddableMetadata(getDashboard(state), panelId);
export const getStagedFilters = state => DashboardSelectors.getStagedFilters(getDashboard(state));
export const getViewMode = state => DashboardSelectors.getViewMode(getDashboard(state));
export const getFullScreenMode = state => DashboardSelectors.getFullScreenMode(getDashboard(state));
export const getMaximizedPanelId = state => DashboardSelectors.getMaximizedPanelId(getDashboard(state));
export const getUseMargins = state => DashboardSelectors.getUseMargins(getDashboard(state));
export const getHidePanelTitles = state => DashboardSelectors.getHidePanelTitles(getDashboard(state));
export const getTimeRange = state => DashboardSelectors.getTimeRange(getDashboard(state));
export const getFilters = state => DashboardSelectors.getFilters(getDashboard(state));
export const getQuery = state => DashboardSelectors.getQuery(getDashboard(state));
export const getTitle = state => DashboardSelectors.getTitle(getDashboard(state));
export const getDescription = state => DashboardSelectors.getDescription(getDashboard(state));

View file

@ -0,0 +1,83 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { Filters, Query, TimeRange } from 'ui/embeddable';
import { DashboardViewMode } from '../dashboard/dashboard_view_mode';
import * as DashboardSelectors from '../dashboard/selectors';
import { PanelId } from '../dashboard/selectors/types';
import { CoreKibanaState } from './types';
export const getDashboard = (
state: CoreKibanaState
): DashboardSelectors.DashboardState => state.dashboard;
export const getPanels = (state: CoreKibanaState) =>
DashboardSelectors.getPanels(getDashboard(state));
export const getPanel = (state: CoreKibanaState, panelId: PanelId) =>
DashboardSelectors.getPanel(getDashboard(state), panelId);
export const getPanelType = (state: CoreKibanaState, panelId: PanelId) =>
DashboardSelectors.getPanelType(getDashboard(state), panelId);
export const getEmbeddables = (state: CoreKibanaState) =>
DashboardSelectors.getEmbeddables(getDashboard(state));
export const getEmbeddableError = (state: CoreKibanaState, panelId: PanelId) =>
DashboardSelectors.getEmbeddableError(getDashboard(state), panelId);
export const getEmbeddableInitialized = (
state: CoreKibanaState,
panelId: PanelId
) => DashboardSelectors.getEmbeddableInitialized(getDashboard(state), panelId);
export const getEmbeddableCustomization = (
state: CoreKibanaState,
panelId: PanelId
) =>
DashboardSelectors.getEmbeddableCustomization(getDashboard(state), panelId);
export const getEmbeddableStagedFilter = (
state: CoreKibanaState,
panelId: PanelId
) => DashboardSelectors.getEmbeddableStagedFilter(getDashboard(state), panelId);
export const getEmbeddableMetadata = (
state: CoreKibanaState,
panelId: PanelId
) => DashboardSelectors.getEmbeddableMetadata(getDashboard(state), panelId);
export const getStagedFilters = (state: CoreKibanaState): Filters =>
DashboardSelectors.getStagedFilters(getDashboard(state));
export const getViewMode = (state: CoreKibanaState): DashboardViewMode =>
DashboardSelectors.getViewMode(getDashboard(state));
export const getFullScreenMode = (state: CoreKibanaState): boolean =>
DashboardSelectors.getFullScreenMode(getDashboard(state));
export const getMaximizedPanelId = (
state: CoreKibanaState
): PanelId | undefined =>
DashboardSelectors.getMaximizedPanelId(getDashboard(state));
export const getUseMargins = (state: CoreKibanaState): boolean =>
DashboardSelectors.getUseMargins(getDashboard(state));
export const getHidePanelTitles = (state: CoreKibanaState): boolean =>
DashboardSelectors.getHidePanelTitles(getDashboard(state));
export const getTimeRange = (state: CoreKibanaState): TimeRange =>
DashboardSelectors.getTimeRange(getDashboard(state));
export const getFilters = (state: CoreKibanaState): Filters =>
DashboardSelectors.getFilters(getDashboard(state));
export const getQuery = (state: CoreKibanaState): Query =>
DashboardSelectors.getQuery(getDashboard(state));
export const getTitle = (state: CoreKibanaState): string =>
DashboardSelectors.getTitle(getDashboard(state));
export const getDescription = (state: CoreKibanaState): string | undefined =>
DashboardSelectors.getDescription(getDashboard(state));

View file

@ -18,3 +18,4 @@
*/
export * from './dashboard_selectors';
export { CoreKibanaState } from './types';

View file

@ -0,0 +1,30 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { Action } from 'redux';
import { DashboardState } from '../dashboard/selectors';
export interface CoreKibanaState {
readonly dashboard: DashboardState;
}
export interface KibanaAction<T, P> extends Action {
readonly type: T;
readonly payload: P;
}

View file

@ -17,16 +17,35 @@
* under the License.
*/
import { createStore, applyMiddleware, compose } from 'redux';
import { applyMiddleware, compose, createStore } from 'redux';
import thunk from 'redux-thunk';
import { QueryLanguageType } from 'ui/embeddable/types';
import { DashboardViewMode } from './dashboard/dashboard_view_mode';
import { reducers } from './reducers';
import { CoreKibanaState } from './selectors';
const enhancers = [ applyMiddleware(thunk) ];
window.__REDUX_DEVTOOLS_EXTENSION__ && enhancers.push(window.__REDUX_DEVTOOLS_EXTENSION__());
const enhancers = [applyMiddleware(thunk)];
export const store = createStore(
export const store = createStore<CoreKibanaState>(
reducers,
{},
{
dashboard: {
embeddables: {},
metadata: {
title: 'New Dashboard',
},
panels: {},
view: {
filters: [],
hidePanelTitles: false,
isFullScreenMode: false,
query: { language: QueryLanguageType.LUCENE, query: '' },
timeRange: { from: 'now-15m', to: 'now' },
useMargins: true,
viewMode: DashboardViewMode.VIEW,
},
},
},
compose(...enhancers)
);

View file

@ -28,7 +28,7 @@ export const embeddableShape = PropTypes.shape({
render: PropTypes.func.isRequired,
});
interface EmbeddableMetadata {
export interface EmbeddableMetadata {
// TODO: change to an array, embeddables should be able to specify multiple index patterns they use. Also
// see https://github.com/elastic/kibana/issues/19408 - this needs to be generalized to support embeddables that
// use dynamic index patterns (vega, TSVB) instead of saved object index patterns (most other visualizations).

View file

@ -22,4 +22,10 @@ export * from './embeddable';
export {
EmbeddableFactoriesRegistryProvider,
} from './embeddable_factories_registry';
export { ContainerState } from './types';
export {
ContainerState,
EmbeddableState,
Query,
Filters,
TimeRange,
} from './types';

View file

@ -17,15 +17,38 @@
* under the License.
*/
export interface TimeRange {
to: string;
from: string;
}
// TODO: Filter object representation needs to be fleshed out.
export interface Filter {
meta: object;
query: object;
}
export type Filters = Filter[];
export enum QueryLanguageType {
KUERY = 'kuery',
LUCENE = 'lucene',
}
export interface Query {
language: QueryLanguageType;
query: string;
}
export interface ContainerState {
// 'view' or 'edit'. Should probably be an enum but I'm undecided where to define it, here or in dashboard code.
viewMode: string;
timeRange: {
// To and From should be either an absolute time range in utc format or a relative one (e.g. now-15m)
to: string;
from: string;
};
timeRange: TimeRange;
filters: Filters;
query: Query;
// The shape will be up to the embeddable type.
embeddableCustomization?: object;
@ -42,6 +65,11 @@ export interface ContainerState {
* Is the current panel in expanded mode
*/
isPanelExpanded: boolean;
/**
* A way to override the underlying embeddable title and supply a title at the panel level.
*/
customTitle: string | undefined;
}
export interface EmbeddableState {

View file

@ -275,6 +275,10 @@
dependencies:
"@types/node" "*"
"@types/jest@^22.2.3":
version "22.2.3"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-22.2.3.tgz#0157c0316dc3722c43a7b71de3fdf3acbccef10d"
"@types/json-schema@*":
version "6.0.1"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-6.0.1.tgz#a761975746f1c1b2579c62e3a4b5e88f986f7e2e"
@ -289,6 +293,10 @@
dependencies:
"@types/node" "*"
"@types/lodash@^3.10.1":
version "3.10.2"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-3.10.2.tgz#c1fbda1562ef5603c8192fe1fe65b017849d5873"
"@types/loglevel@^1.5.3":
version "1.5.3"
resolved "https://registry.yarnpkg.com/@types/loglevel/-/loglevel-1.5.3.tgz#adfce55383edc5998a2170ad581b3e23d6adb5b8"
@ -340,6 +348,14 @@
dependencies:
csstype "^2.2.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"
"@types/redux@^3.6.31":
version "3.6.31"
resolved "https://registry.yarnpkg.com/@types/redux/-/redux-3.6.31.tgz#40eafa7575db36b912ce0059b85de98c205b0708"
"@types/retry@*", "@types/retry@^0.10.2":
version "0.10.2"
resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.10.2.tgz#bd1740c4ad51966609b058803ee6874577848b37"