"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.useDashboardContainer = exports.DashboardContainerContext = exports.DashboardContainer = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _reactDom = _interopRequireDefault(require("react-dom")); var _reactRedux = require("react-redux"); var _rxjs = require("rxjs"); var _react = _interopRequireWildcard(require("react")); var _public = require("@kbn/embeddable-plugin/public"); var _i18nReact = require("@kbn/i18n-react"); var _ebtTools = require("@kbn/ebt-tools"); var _public2 = require("@kbn/kibana-react-plugin/public"); var _common = require("@kbn/controls-plugin/common"); var _sharedUxButtonExitFullScreen = require("@kbn/shared-ux-button-exit-full-screen"); var _api = require("./api"); var _ = require("../.."); var _panel = require("../component/panel"); var _plugin_services = require("../../services/plugin_services"); var _create_dashboard = require("./create/create_dashboard"); var _dashboard_viewport = require("../component/viewport/dashboard_viewport"); var _dashboard_container_reducers = require("../state/dashboard_container_reducers"); var _dashboard_diffing_integration = require("../state/diffing/dashboard_diffing_integration"); var _dashboard_constants = require("../../dashboard_constants"); var _dashboard_control_group_integration = require("./create/controls/dashboard_control_group_integration"); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the Server Side Public License, v 1; you may not use this file except * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ const DashboardContainerContext = /*#__PURE__*/(0, _react.createContext)(null); exports.DashboardContainerContext = DashboardContainerContext; const useDashboardContainer = () => { const dashboard = (0, _react.useContext)(DashboardContainerContext); if (dashboard == null) { throw new Error('useDashboardContainer must be used inside DashboardContainerContext.'); } return dashboard; }; exports.useDashboardContainer = useDashboardContainer; class DashboardContainer extends _public.Container { // state management // cleanup // performance monitoring // Services that are used in the Dashboard container code constructor(initialInput, reduxToolsPackage, initialSessionId, initialLastSavedInput, dashboardCreationStartTime, parent, creationOptions, savedObjectId) { const { embeddable: { getEmbeddableFactory } } = _plugin_services.pluginServices.getServices(); super({ ...initialInput }, { embeddableLoaded: {} }, getEmbeddableFactory, parent); (0, _defineProperty2.default)(this, "type", _.DASHBOARD_CONTAINER_TYPE); (0, _defineProperty2.default)(this, "select", void 0); (0, _defineProperty2.default)(this, "getState", void 0); (0, _defineProperty2.default)(this, "dispatch", void 0); (0, _defineProperty2.default)(this, "onStateChange", void 0); (0, _defineProperty2.default)(this, "integrationSubscriptions", new _rxjs.Subscription()); (0, _defineProperty2.default)(this, "diffingSubscription", new _rxjs.Subscription()); (0, _defineProperty2.default)(this, "controlGroup", void 0); (0, _defineProperty2.default)(this, "searchSessionId", void 0); (0, _defineProperty2.default)(this, "stopSyncingWithUnifiedSearch", void 0); (0, _defineProperty2.default)(this, "cleanupStateTools", void 0); (0, _defineProperty2.default)(this, "dashboardCreationStartTime", void 0); (0, _defineProperty2.default)(this, "savedObjectLoadTime", void 0); (0, _defineProperty2.default)(this, "domNode", void 0); (0, _defineProperty2.default)(this, "overlayRef", void 0); (0, _defineProperty2.default)(this, "allDataViews", []); (0, _defineProperty2.default)(this, "creationOptions", void 0); (0, _defineProperty2.default)(this, "analyticsService", void 0); (0, _defineProperty2.default)(this, "theme$", void 0); (0, _defineProperty2.default)(this, "chrome", void 0); (0, _defineProperty2.default)(this, "customBranding", void 0); // ------------------------------------------------------------------------------------------------------ // Dashboard API // ------------------------------------------------------------------------------------------------------ (0, _defineProperty2.default)(this, "runClone", _api.runClone); (0, _defineProperty2.default)(this, "runSaveAs", _api.runSaveAs); (0, _defineProperty2.default)(this, "runQuickSave", _api.runQuickSave); (0, _defineProperty2.default)(this, "showSettings", _api.showSettings); (0, _defineProperty2.default)(this, "addFromLibrary", _api.addFromLibrary); (0, _defineProperty2.default)(this, "replacePanel", _api.replacePanel); (0, _defineProperty2.default)(this, "showPlaceholderUntil", _api.showPlaceholderUntil); (0, _defineProperty2.default)(this, "addOrUpdateEmbeddable", _api.addOrUpdateEmbeddable); (0, _defineProperty2.default)(this, "onDataViewsUpdate$", new _rxjs.Subject()); (0, _defineProperty2.default)(this, "navigateToDashboard", async (newSavedObjectId, newCreationOptions) => { var _this$stopSyncingWith; this.integrationSubscriptions.unsubscribe(); this.integrationSubscriptions = new _rxjs.Subscription(); (_this$stopSyncingWith = this.stopSyncingWithUnifiedSearch) === null || _this$stopSyncingWith === void 0 ? void 0 : _this$stopSyncingWith.call(this); const { dashboardContentManagement: { loadDashboardState } } = _plugin_services.pluginServices.getServices(); if (newCreationOptions) { this.creationOptions = { ...this.creationOptions, ...newCreationOptions }; } const loadDashboardReturn = await loadDashboardState({ id: newSavedObjectId }); const dashboardContainerReady$ = new _rxjs.Subject(); const untilDashboardReady = () => new Promise(resolve => { const subscription = dashboardContainerReady$.subscribe(container => { subscription.unsubscribe(); resolve(container); }); }); const initializeResult = await (0, _create_dashboard.initializeDashboard)({ creationOptions: this.creationOptions, controlGroup: this.controlGroup, untilDashboardReady, loadDashboardReturn }); if (!initializeResult) return; const { input: newInput, searchSessionId } = initializeResult; this.searchSessionId = searchSessionId; this.updateInput(newInput); (0, _reactRedux.batch)(() => { this.dispatch.setLastSavedInput(loadDashboardReturn === null || loadDashboardReturn === void 0 ? void 0 : loadDashboardReturn.dashboardInput); this.dispatch.setAnimatePanelTransforms(false); // prevents panels from animating on navigate. this.dispatch.setLastSavedId(newSavedObjectId); }); dashboardContainerReady$.next(this); }); /** * Gets all the dataviews that are actively being used in the dashboard * @returns An array of dataviews */ (0, _defineProperty2.default)(this, "getAllDataViews", () => { return this.allDataViews; }); /** * Use this to set the dataviews that are used in the dashboard when they change/update * @param newDataViews The new array of dataviews that will overwrite the old dataviews array */ (0, _defineProperty2.default)(this, "setAllDataViews", newDataViews => { this.allDataViews = newDataViews; this.onDataViewsUpdate$.next(newDataViews); }); (0, _defineProperty2.default)(this, "getExpandedPanelId", () => { return this.getState().componentState.expandedPanelId; }); (0, _defineProperty2.default)(this, "setExpandedPanelId", newId => { this.dispatch.setExpandedPanelId(newId); }); (0, _defineProperty2.default)(this, "openOverlay", ref => { this.clearOverlays(); this.dispatch.setHasOverlays(true); this.overlayRef = ref; }); (0, _defineProperty2.default)(this, "clearOverlays", () => { var _this$controlGroup, _this$overlayRef; this.dispatch.setHasOverlays(false); (_this$controlGroup = this.controlGroup) === null || _this$controlGroup === void 0 ? void 0 : _this$controlGroup.closeAllFlyouts(); (_this$overlayRef = this.overlayRef) === null || _this$overlayRef === void 0 ? void 0 : _this$overlayRef.close(); }); (0, _defineProperty2.default)(this, "getPanelCount", () => { return Object.keys(this.getInput().panels).length; }); (0, _defineProperty2.default)(this, "setScrollToPanelId", id => { this.dispatch.setScrollToPanelId(id); }); (0, _defineProperty2.default)(this, "scrollToPanel", async panelRef => { const id = this.getState().componentState.scrollToPanelId; if (!id) return; this.untilEmbeddableLoaded(id).then(() => { this.setScrollToPanelId(undefined); panelRef.scrollIntoView({ block: 'center' }); }); }); (0, _defineProperty2.default)(this, "scrollToTop", () => { window.scroll(0, 0); }); (0, _defineProperty2.default)(this, "setHighlightPanelId", id => { this.dispatch.setHighlightPanelId(id); }); (0, _defineProperty2.default)(this, "highlightPanel", panelRef => { const id = this.getState().componentState.highlightPanelId; if (id && panelRef) { this.untilEmbeddableLoaded(id).then(() => { panelRef.classList.add('dshDashboardGrid__item--highlighted'); // Removes the class after the highlight animation finishes setTimeout(() => { panelRef.classList.remove('dshDashboardGrid__item--highlighted'); }, 5000); }); } this.setHighlightPanelId(undefined); }); ({ analytics: this.analyticsService, settings: { theme: { theme$: this.theme$ } }, chrome: this.chrome, customBranding: this.customBranding } = _plugin_services.pluginServices.getServices()); this.creationOptions = creationOptions; this.searchSessionId = initialSessionId; this.dashboardCreationStartTime = dashboardCreationStartTime; // start diffing dashboard state const diffingMiddleware = _dashboard_diffing_integration.startDiffingDashboardState.bind(this)(creationOptions); // build redux embeddable tools const reduxTools = reduxToolsPackage.createReduxEmbeddableTools({ embeddable: this, reducers: _dashboard_container_reducers.dashboardContainerReducers, additionalMiddleware: [diffingMiddleware], initialComponentState: { lastSavedInput: initialLastSavedInput !== null && initialLastSavedInput !== void 0 ? initialLastSavedInput : { ..._dashboard_constants.DEFAULT_DASHBOARD_INPUT, id: initialInput.id }, isEmbeddedExternally: creationOptions === null || creationOptions === void 0 ? void 0 : creationOptions.isEmbeddedExternally, animatePanelTransforms: false, // set panel transforms to false initially to avoid panels animating on initial render. hasUnsavedChanges: false, // if there is initial unsaved changes, the initial diff will catch them. lastSavedId: savedObjectId } }); this.onStateChange = reduxTools.onStateChange; this.cleanupStateTools = reduxTools.cleanup; this.getState = reduxTools.getState; this.dispatch = reduxTools.dispatch; this.select = reduxTools.select; } getDashboardSavedObjectId() { return this.getState().componentState.lastSavedId; } reportPerformanceMetrics(stats) { if (this.analyticsService && this.dashboardCreationStartTime) { const panelCount = Object.keys(this.getState().explicitInput.panels).length; const totalDuration = stats.panelsRenderDoneTime - this.dashboardCreationStartTime; (0, _ebtTools.reportPerformanceMetricEvent)(this.analyticsService, { eventName: _dashboard_constants.DASHBOARD_LOADED_EVENT, duration: totalDuration, key1: 'time_to_data', value1: (stats.lastTimeToData || stats.panelsRenderDoneTime) - stats.panelsRenderStartTime, key2: 'num_of_panels', value2: panelCount, key3: 'total_load_time', value3: totalDuration, key4: 'saved_object_load_time', value4: this.savedObjectLoadTime }); } } createNewPanelState(factory, partial = {}) { const panelState = super.createNewPanelState(factory, partial); const { newPanel } = (0, _panel.createPanelState)(panelState, this.input.panels); return newPanel; } render(dom) { if (this.domNode) { _reactDom.default.unmountComponentAtNode(this.domNode); } this.domNode = dom; this.domNode.className = 'dashboardContainer'; _reactDom.default.render( /*#__PURE__*/_react.default.createElement(_i18nReact.I18nProvider, null, /*#__PURE__*/_react.default.createElement(_sharedUxButtonExitFullScreen.ExitFullScreenButtonKibanaProvider, { coreStart: { chrome: this.chrome, customBranding: this.customBranding } }, /*#__PURE__*/_react.default.createElement(_public2.KibanaThemeProvider, { theme$: this.theme$ }, /*#__PURE__*/_react.default.createElement(DashboardContainerContext.Provider, { value: this }, /*#__PURE__*/_react.default.createElement(_dashboard_viewport.DashboardViewport, null))))), dom); } getInheritedInput(id) { var _panels$id, _panels$id$explicitIn; const { query, filters, viewMode, timeRange, timeslice, syncColors, syncTooltips, hidePanelTitles, refreshInterval, executionContext, panels } = this.input; let combinedFilters = filters; if (this.controlGroup) { combinedFilters = (0, _dashboard_control_group_integration.combineDashboardFiltersWithControlGroupFilters)(filters, this.controlGroup); } const hasCustomTimeRange = Boolean((_panels$id = panels[id]) === null || _panels$id === void 0 ? void 0 : (_panels$id$explicitIn = _panels$id.explicitInput) === null || _panels$id$explicitIn === void 0 ? void 0 : _panels$id$explicitIn.timeRange); return { searchSessionId: this.searchSessionId, refreshConfig: refreshInterval, filters: combinedFilters, hidePanelTitles, executionContext, syncTooltips, syncColors, viewMode, query, id, // do not pass any time information from dashboard to panel when panel has custom time range // to avoid confusing panel which timeRange should be used timeRange: hasCustomTimeRange ? undefined : timeRange, timeslice: hasCustomTimeRange ? undefined : timeslice }; } // ------------------------------------------------------------------------------------------------------ // Cleanup // ------------------------------------------------------------------------------------------------------ destroy() { var _this$controlGroup2, _this$stopSyncingWith2; super.destroy(); this.cleanupStateTools(); (_this$controlGroup2 = this.controlGroup) === null || _this$controlGroup2 === void 0 ? void 0 : _this$controlGroup2.destroy(); this.diffingSubscription.unsubscribe(); this.integrationSubscriptions.unsubscribe(); (_this$stopSyncingWith2 = this.stopSyncingWithUnifiedSearch) === null || _this$stopSyncingWith2 === void 0 ? void 0 : _this$stopSyncingWith2.call(this); if (this.domNode) _reactDom.default.unmountComponentAtNode(this.domNode); } forceRefresh(refreshControlGroup = true) { var _this$controlGroup3; this.dispatch.setLastReloadRequestTimeToNow({}); if (refreshControlGroup) (_this$controlGroup3 = this.controlGroup) === null || _this$controlGroup3 === void 0 ? void 0 : _this$controlGroup3.reload(); } resetToLastSavedState() { var _this$creationOptions; this.dispatch.resetToLastSavedInput({}); const { explicitInput: { timeRange, refreshInterval }, componentState: { lastSavedInput: { controlGroupInput: lastSavedControlGroupInput, timeRestore: lastSavedTimeRestore } } } = this.getState(); if (this.controlGroup && !(0, _common.persistableControlGroupInputIsEqual)(this.controlGroup.getInput(), lastSavedControlGroupInput)) { this.controlGroup.updateInput(lastSavedControlGroupInput !== null && lastSavedControlGroupInput !== void 0 ? lastSavedControlGroupInput : (0, _common.getDefaultControlGroupInput)()); } // if we are using the unified search integration, we need to force reset the time picker. if ((_this$creationOptions = this.creationOptions) !== null && _this$creationOptions !== void 0 && _this$creationOptions.useUnifiedSearchIntegration && lastSavedTimeRestore) { const { data: { query: { timefilter: { timefilter: timeFilterService } } } } = _plugin_services.pluginServices.getServices(); if (timeRange) timeFilterService.setTime(timeRange); if (refreshInterval) timeFilterService.setRefreshInterval(refreshInterval); } } async getPanelTitles() { const titles = []; const ids = Object.keys(this.getInput().panels); for (const panelId of ids) { await this.untilEmbeddableLoaded(panelId); const child = this.getChild(panelId); const title = child.getTitle(); if (title) { titles.push(title); } } return titles; } } exports.DashboardContainer = DashboardContainer;