diff --git a/src/plugins/dashboard/public/application/components/dashboard_editor.tsx b/src/plugins/dashboard/public/application/components/dashboard_editor.tsx
index c5681aa3f197..76ffa0479e7a 100644
--- a/src/plugins/dashboard/public/application/components/dashboard_editor.tsx
+++ b/src/plugins/dashboard/public/application/components/dashboard_editor.tsx
@@ -39,7 +39,7 @@ export const DashboardEditor = () => {
savedDashboardInstance
);
- const { dashboardContainer } = useDashboardContainer(
+ const { dashboardContainer, indexPatterns } = useDashboardContainer(
services,
isChromeVisible,
eventEmitter,
@@ -93,6 +93,7 @@ export const DashboardEditor = () => {
console.log('isDirty', dashboard.isDirty);
}
console.log('dashboardContainer', dashboardContainer);
+ console.log('indexPatterns', indexPatterns);
return (
@@ -109,6 +110,7 @@ export const DashboardEditor = () => {
dashboard={dashboard}
currentAppState={currentAppState}
isEmbeddableRendered={isEmbeddableRendered}
+ indexPatterns={indexPatterns}
dashboardContainer={dashboardContainer}
/>
)}
diff --git a/src/plugins/dashboard/public/application/components/dashboard_top_nav.tsx b/src/plugins/dashboard/public/application/components/dashboard_top_nav.tsx
index 7675b733fef0..3282dad1f3cf 100644
--- a/src/plugins/dashboard/public/application/components/dashboard_top_nav.tsx
+++ b/src/plugins/dashboard/public/application/components/dashboard_top_nav.tsx
@@ -3,7 +3,6 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import { uniqBy } from 'lodash';
import React, { memo, useState, useEffect } from 'react';
import { Filter, IndexPattern } from 'src/plugins/data/public';
import { useCallback } from 'react';
@@ -13,7 +12,6 @@ import { getTopNavConfig } from '../top_nav/get_top_nav_config';
import { DashboardAppStateContainer, DashboardAppState, DashboardServices } from '../../types';
import { getNavActions } from '../utils/get_nav_actions';
import { DashboardContainer } from '../embeddable';
-import { isErrorEmbeddable } from '../../embeddable_plugin';
import { Dashboard } from '../../dashboard';
interface DashboardTopNavProps {
@@ -23,6 +21,7 @@ interface DashboardTopNavProps {
dashboard: Dashboard;
currentAppState: DashboardAppState;
isEmbeddableRendered: boolean;
+ indexPatterns: IndexPattern[];
dashboardContainer?: DashboardContainer;
}
@@ -42,16 +41,14 @@ const TopNav = ({
currentAppState,
isEmbeddableRendered,
dashboardContainer,
+ indexPatterns,
}: DashboardTopNavProps) => {
- const [filters, setFilters] = useState
([]);
const [topNavMenu, setTopNavMenu] = useState();
const [isFullScreenMode, setIsFullScreenMode] = useState();
- const [indexPatterns, setIndexPatterns] = useState();
const { services } = useOpenSearchDashboards();
const { TopNavMenu } = services.navigation.ui;
- const { data, dashboardConfig, setHeaderActionMenu } = services;
- const { query: queryService } = data;
+ const { dashboardConfig, setHeaderActionMenu } = services;
const location = useLocation();
const queryParameters = new URLSearchParams(location.search);
@@ -76,10 +73,6 @@ const TopNav = ({
const shouldShowNavBarComponent = (forceShow: boolean): boolean =>
(forceShow || isChromeVisible) && !currentAppState?.fullScreenMode;
- useEffect(() => {
- setFilters(queryService.filterManager.getFilters());
- }, [services, queryService]);
-
useEffect(() => {
if (isEmbeddableRendered) {
const navActions = getNavActions(
@@ -112,33 +105,6 @@ const TopNav = ({
setIsFullScreenMode(currentAppState?.fullScreenMode);
}, [currentAppState, services]);
- useEffect(() => {
- const asyncSetIndexPattern = async () => {
- if (dashboardContainer) {
- let panelIndexPatterns: IndexPattern[] = [];
- dashboardContainer.getChildIds().forEach((id) => {
- const embeddableInstance = dashboardContainer.getChild(id);
- if (isErrorEmbeddable(embeddableInstance)) return;
- const embeddableIndexPatterns = (embeddableInstance.getOutput() as any).indexPatterns;
- if (!embeddableIndexPatterns) return;
- panelIndexPatterns.push(...embeddableIndexPatterns);
- });
- panelIndexPatterns = uniqBy(panelIndexPatterns, 'id');
-
- if (panelIndexPatterns.length > 0) {
- setIndexPatterns(panelIndexPatterns);
- } else {
- const defaultIndex = await services.data.indexPatterns.getDefault();
- if (defaultIndex) {
- setIndexPatterns([defaultIndex]);
- }
- }
- }
- };
-
- asyncSetIndexPattern();
- }, [dashboardContainer, stateContainer, currentAppState, services.data.indexPatterns]);
-
const shouldShowFilterBar = (forceHide: boolean): boolean =>
!forceHide && (currentAppState.filters!.length > 0 || !currentAppState?.fullScreenMode);
@@ -156,7 +122,6 @@ const TopNav = ({
return (
{}}
+ onSavedQueryIdChange={(savedQueryId?: string) => {
+ stateContainer.transitions.set('savedQuery', savedQueryId);
+ }}
+ savedQueryId={currentAppState?.savedQuery}
onQuerySubmit={handleRefresh}
setMenuMountPoint={isEmbeddedExternally ? undefined : setHeaderActionMenu}
/>
diff --git a/src/plugins/dashboard/public/application/lib/save_dashboard.ts b/src/plugins/dashboard/public/application/lib/save_dashboard.ts
index 2b48d862af34..871c8d62b286 100644
--- a/src/plugins/dashboard/public/application/lib/save_dashboard.ts
+++ b/src/plugins/dashboard/public/application/lib/save_dashboard.ts
@@ -33,6 +33,7 @@ import { SavedObjectSaveOpts } from 'src/plugins/saved_objects/public';
import { updateSavedDashboard } from './update_saved_dashboard';
import { DashboardAppStateContainer } from '../../types';
+import { Dashboard } from '../../dashboard';
/**
* Saves the dashboard.
@@ -43,11 +44,12 @@ export function saveDashboard(
timeFilter: TimefilterContract,
stateContainer: DashboardAppStateContainer,
savedDashboard: any,
- saveOptions: SavedObjectSaveOpts
+ saveOptions: SavedObjectSaveOpts,
+ dashboard: Dashboard
): Promise {
const appState = stateContainer.getState();
- updateSavedDashboard(savedDashboard, appState, timeFilter);
+ updateSavedDashboard(savedDashboard, appState, timeFilter, dashboard);
return savedDashboard.save(saveOptions).then((id: string) => {
if (id) {
diff --git a/src/plugins/dashboard/public/application/lib/update_saved_dashboard.ts b/src/plugins/dashboard/public/application/lib/update_saved_dashboard.ts
index 0baebc0bc3d5..bfbb29865794 100644
--- a/src/plugins/dashboard/public/application/lib/update_saved_dashboard.ts
+++ b/src/plugins/dashboard/public/application/lib/update_saved_dashboard.ts
@@ -34,11 +34,13 @@ import { FilterUtils } from './filter_utils';
import { SavedObjectDashboard } from '../../saved_dashboards';
import { DashboardAppState } from '../../types';
import { opensearchFilters } from '../../../../data/public';
+import { Dashboard } from '../../dashboard';
export function updateSavedDashboard(
savedDashboard: SavedObjectDashboard,
appState: DashboardAppState,
- timeFilter: TimefilterContract
+ timeFilter: TimefilterContract,
+ dashboard: Dashboard
) {
savedDashboard.title = appState.title;
savedDashboard.description = appState.description;
@@ -46,19 +48,23 @@ export function updateSavedDashboard(
savedDashboard.panelsJSON = JSON.stringify(appState.panels);
savedDashboard.optionsJSON = JSON.stringify(appState.options);
- savedDashboard.timeFrom = savedDashboard.timeRestore
+ const timeFrom = savedDashboard.timeRestore
? FilterUtils.convertTimeToUTCString(timeFilter.getTime().from)
: undefined;
- savedDashboard.timeTo = savedDashboard.timeRestore
+ const timeTo = savedDashboard.timeRestore
? FilterUtils.convertTimeToUTCString(timeFilter.getTime().to)
: undefined;
+
const timeRestoreObj: RefreshInterval = _.pick(timeFilter.getRefreshInterval(), [
'display',
'pause',
'section',
'value',
]) as RefreshInterval;
- savedDashboard.refreshInterval = savedDashboard.timeRestore ? timeRestoreObj : undefined;
+ const refreshInterval = savedDashboard.timeRestore ? timeRestoreObj : undefined;
+ savedDashboard.timeFrom = timeFrom;
+ savedDashboard.timeTo = timeTo;
+ savedDashboard.refreshInterval = refreshInterval;
// save only unpinned filters
const unpinnedFilters = appState.filters.filter(
@@ -68,4 +74,17 @@ export function updateSavedDashboard(
// save the queries
savedDashboard.searchSource.setField('query', appState.query as Query);
+
+ dashboard.setState({
+ title: appState.title,
+ description: appState.description,
+ timeRestore: appState.timeRestore,
+ panels: appState.panels,
+ options: appState.options,
+ timeFrom,
+ timeTo,
+ refreshInterval,
+ query: appState.query as Query,
+ filters: unpinnedFilters,
+ });
}
diff --git a/src/plugins/dashboard/public/application/utils/get_nav_actions.tsx b/src/plugins/dashboard/public/application/utils/get_nav_actions.tsx
index 9c7abab68682..da0b7da7a8c5 100644
--- a/src/plugins/dashboard/public/application/utils/get_nav_actions.tsx
+++ b/src/plugins/dashboard/public/application/utils/get_nav_actions.tsx
@@ -373,7 +373,13 @@ export const getNavActions = (
async function save(saveOptions: SavedObjectSaveOpts) {
const timefilter = queryService.timefilter.timefilter;
try {
- const id = await saveDashboard(timefilter, stateContainer, savedDashboard, saveOptions);
+ const id = await saveDashboard(
+ timefilter,
+ stateContainer,
+ savedDashboard,
+ saveOptions,
+ dashboard
+ );
if (id) {
notifications.toasts.addSuccess({
diff --git a/src/plugins/dashboard/public/application/utils/use/use_dashboard_container.tsx b/src/plugins/dashboard/public/application/utils/use/use_dashboard_container.tsx
index df777460018a..e364a0de293a 100644
--- a/src/plugins/dashboard/public/application/utils/use/use_dashboard_container.tsx
+++ b/src/plugins/dashboard/public/application/utils/use/use_dashboard_container.tsx
@@ -4,7 +4,7 @@
*/
import React, { useState } from 'react';
-import { cloneDeep, isEqual } from 'lodash';
+import { cloneDeep, isEqual, uniqBy } from 'lodash';
import { EMPTY, Observable, Subscription, merge, of, pipe } from 'rxjs';
import {
catchError,
@@ -62,6 +62,7 @@ export const useDashboardContainer = (
appState?: DashboardAppStateContainer
) => {
const [dashboardContainer, setDashboardContainer] = useState();
+ const [indexPatterns, setIndexPatterns] = useState([]);
useEffect(() => {
const getDashboardContainer = async () => {
@@ -71,7 +72,8 @@ export const useDashboardContainer = (
savedDashboardInstance,
services,
appState,
- dashboard
+ dashboard,
+ setIndexPatterns
);
setDashboardContainer(dashboardContainerEmbeddable);
@@ -105,14 +107,15 @@ export const useDashboardContainer = (
}
}, [dashboardContainer, services]);
- return { dashboardContainer };
+ return { dashboardContainer, indexPatterns };
};
const createDashboardEmbeddable = (
savedDash: any,
dashboardServices: DashboardServices,
appState: DashboardAppStateContainer,
- dashboard: Dashboard
+ dashboard: Dashboard,
+ setIndexPatterns: React.Dispatch>
) => {
let dashboardContainer: DashboardContainer;
let inputSubscription: Subscription | undefined;
@@ -240,6 +243,45 @@ const createDashboardEmbeddable = (
expandedPanelId: appStateData.expandedPanelId,
};
};
+ const setCurrentIndexPatterns = () => {
+ let panelIndexPatterns: IndexPattern[] = [];
+ dashboardContainer.getChildIds().forEach((id) => {
+ const embeddableInstance = dashboardContainer.getChild(id);
+ if (isErrorEmbeddable(embeddableInstance)) return;
+ const embeddableIndexPatterns = (embeddableInstance.getOutput() as any).indexPatterns;
+ if (!embeddableIndexPatterns) return;
+ panelIndexPatterns.push(...embeddableIndexPatterns);
+ });
+ panelIndexPatterns = uniqBy(panelIndexPatterns, 'id');
+ return panelIndexPatterns;
+ };
+
+ const updateIndexPatternsOperator = pipe(
+ filter((container: DashboardContainer) => !!container && !isErrorEmbeddable(container)),
+ map(setCurrentIndexPatterns),
+ distinctUntilChanged((a, b) =>
+ deepEqual(
+ a.map((ip) => ip.id),
+ b.map((ip) => ip.id)
+ )
+ ),
+ // using switchMap for previous task cancellation
+ switchMap((panelIndexPatterns: IndexPattern[]) => {
+ return new Observable((observer) => {
+ if (panelIndexPatterns && panelIndexPatterns.length > 0) {
+ if (observer.closed) return;
+ setIndexPatterns(panelIndexPatterns);
+ observer.complete();
+ } else {
+ data.indexPatterns.getDefault().then((defaultIndexPattern) => {
+ if (observer.closed) return;
+ setIndexPatterns([defaultIndexPattern as IndexPattern]);
+ observer.complete();
+ });
+ }
+ });
+ })
+ );
if (dashboardFactory) {
return dashboardFactory
@@ -321,7 +363,8 @@ const createDashboardEmbeddable = (
)
.pipe(
mapTo(dashboardContainer),
- startWith(dashboardContainer) // to trigger initial index pattern update
+ startWith(dashboardContainer), // to trigger initial index pattern update
+ updateIndexPatternsOperator
)
.subscribe();
diff --git a/src/plugins/dashboard/public/application/utils/use/use_editor_updates.ts b/src/plugins/dashboard/public/application/utils/use/use_editor_updates.ts
index bb3b4fe09b1a..31feef28e607 100644
--- a/src/plugins/dashboard/public/application/utils/use/use_editor_updates.ts
+++ b/src/plugins/dashboard/public/application/utils/use/use_editor_updates.ts
@@ -43,7 +43,13 @@ export const useEditorUpdates = (
if (changes) {
dashboardContainer.updateInput(changes);
- if (changes.filters || changes.query || changes.timeRange || changes.refreshConfig) {
+ if (changes.timeRange || changes.refreshConfig) {
+ if (dashboardInstance.timeRestore) {
+ dashboard.isDirty = true;
+ }
+ }
+
+ if (changes.filters || changes.query) {
dashboard.isDirty = true;
}
}
diff --git a/src/plugins/dashboard/public/dashboard.ts b/src/plugins/dashboard/public/dashboard.ts
index 4dc192c4d875..668d3afb09a6 100644
--- a/src/plugins/dashboard/public/dashboard.ts
+++ b/src/plugins/dashboard/public/dashboard.ts
@@ -73,7 +73,7 @@ export class Dashboard {
this.filters = cloneDeep(dashboardState.filters);
}
- async setState(state: PartialDashboardState) {
+ setState(state: PartialDashboardState) {
if (state.id) {
this.id = state.id;
}
@@ -109,12 +109,12 @@ export class Dashboard {
if (state.searchSource) {
this.searchSource = state.searchSource;
}
- // if (state.query) {
- // this.query = this.getQuery(state.query);
- // }
- // if (state.filters) {
- // this.filters = this.getFilters(state.filters);
- // }
+ if (state.query) {
+ this.query = state.query;
+ }
+ if (state.filters) {
+ this.filters = state.filters;
+ }
}
public setIsDirty(value: boolean) {
diff --git a/src/plugins/dashboard/public/saved_dashboards/_saved_dashboard.ts b/src/plugins/dashboard/public/saved_dashboards/_saved_dashboard.ts
index 98923f5aa0db..741c9871f51f 100644
--- a/src/plugins/dashboard/public/saved_dashboards/_saved_dashboard.ts
+++ b/src/plugins/dashboard/public/saved_dashboards/_saved_dashboard.ts
@@ -39,114 +39,3 @@ export const convertToSerializedDashboard = (
filters: savedDashboard.getFilters(),
};
};
-
-/* export const convertFromSerializedDashboard = (
- serializedDashboard: SerializedDashboard
- ): ISavedDashboard => {
- const {
- id,
- timeRestore,
- timeTo,
- timeFrom,
- refreshInterval,
- description,
- panels,
- options,
- uiState,
- lastSavedTitle,
- searchSource,
- query,
- filters,
- } = serializedDashboard;
-
- return {
- id,
- timeRestore,
- timeTo,
- timeFrom,
- description,
- panelsJSON: JSON.stringify(panels),
- optionsJSON: JSON.stringify(options),
- uiStateJSON: JSON.stringify(uiState),
- lastSavedTitle,
- refreshInterval,
- searchSource,
- getQuery: () => query,
- getFilters: () => filters,
- };
- };
-
- export function createSavedDashboardClass(
- services: SavedObjectOpenSearchDashboardsServices
- ): new (id: string) => SavedObjectDashboard {
- const SavedObjectClass = createSavedObjectClass(services);
- class SavedDashboard extends SavedObjectClass {
- public static type = 'dashboard';
- public static mapping: Record = {
- title: 'text',
- hits: 'integer',
- description: 'text',
- panelsJSON: 'text',
- optionsJSON: 'text',
- version: 'integer',
- timeRestore: 'boolean',
- timeTo: 'keyword',
- timeFrom: 'keyword',
- refreshInterval: {
- type: 'object',
- properties: {
- display: { type: 'keyword' },
- pause: { type: 'boolean' },
- section: { type: 'integer' },
- value: { type: 'integer' },
- },
- },
- };
- // Order these fields to the top, the rest are alphabetical
- public static fieldOrder = ['title', 'description'];
- public static searchSource = true;
- public showInRecentlyAccessed = true;
-
- constructor(id: string) {
- super({
- type: SavedDashboard.type,
- mapping: SavedDashboard.mapping,
- searchSource: SavedDashboard.searchSource,
- extractReferences,
- injectReferences,
-
- // if this is null/undefined then the SavedObject will be assigned the defaults
- id,
-
- // default values that will get assigned if the doc is new
- defaults: {
- title: '',
- hits: 0,
- description: '',
- panelsJSON: '[]',
- optionsJSON: JSON.stringify({
- // for BWC reasons we can't default dashboards that already exist without this setting to true.
- useMargins: !id,
- hidePanelTitles: false,
- }),
- version: 1,
- timeRestore: false,
- timeTo: undefined,
- timeFrom: undefined,
- refreshInterval: undefined,
- },
- });
- this.getFullPath = () => `/app/dashboardsNew#${createDashboardEditUrl(String(this.id))}`;
- }
-
- getQuery() {
- return this.searchSource!.getOwnField('query') || { query: '', language: 'kuery' };
- }
-
- getFilters() {
- return this.searchSource!.getOwnField('filter') || [];
- }
- }
-
- return (SavedDashboard as unknown) as new (id: string) => SavedObjectDashboard;
- }*/