"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.VisualizeTopNav = void 0; var _react = _interopRequireWildcard(require("react")); var _i18n = require("@kbn/i18n"); var _useLocalStorage = _interopRequireDefault(require("react-use/lib/useLocalStorage")); var _public = require("@kbn/kibana-react-plugin/public"); var _constants = require("../../../common/constants"); var _utils = require("../utils"); 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 LOCAL_STORAGE_EDIT_IN_LENS_BADGE = 'EDIT_IN_LENS_BADGE_VISIBLE'; const TopNav = ({ currentAppState, isChromeVisible, isEmbeddableRendered, hasUnsavedChanges, setHasUnsavedChanges, hasUnappliedChanges, originatingApp, setOriginatingApp, originatingPath, visInstance, stateContainer, visualizationIdFromUrl, embeddableId, onAppLeave, eventEmitter }) => { var _vis$type$editorConfi; const { services } = (0, _public.useKibana)(); const { TopNavMenu } = services.navigation.ui; const { setHeaderActionMenu, visualizeCapabilities } = services; const { embeddableHandler, vis } = visInstance; const [inspectorSession, setInspectorSession] = (0, _react.useState)(); const [navigateToLens, setNavigateToLens] = (0, _react.useState)(false); const [displayEditInLensItem, setDisplayEditInLensItem] = (0, _react.useState)(false); // If the user has clicked the edit in lens button, we want to hide the badge. // The information is stored in local storage to persist across reloads. const [hideTryInLensBadge, setHideTryInLensBadge] = (0, _useLocalStorage.default)(LOCAL_STORAGE_EDIT_IN_LENS_BADGE, false); const hideLensBadge = (0, _react.useCallback)(() => { setHideTryInLensBadge(true); }, [setHideTryInLensBadge]); const openInspector = (0, _react.useCallback)(() => { const session = embeddableHandler.openInspector(); setInspectorSession(session); }, [embeddableHandler]); const doReload = (0, _react.useCallback)(async () => { // start a new session to make sure all data is up to date services.data.search.session.start(); // embeddable handler is subscribed to session service and will refresh }, [services.data.search.session]); const handleRefresh = (0, _react.useCallback)((_payload, isUpdate) => { if (isUpdate === false) { doReload(); } }, [doReload]); (0, _react.useEffect)(() => { const subscription = embeddableHandler.getExpressionVariables$().subscribe(expressionVariables => { setDisplayEditInLensItem(Boolean(vis.type.navigateToLens && (expressionVariables === null || expressionVariables === void 0 ? void 0 : expressionVariables.canNavigateToLens))); }); return () => { subscription.unsubscribe(); }; }, [embeddableHandler, vis]); const config = (0, _react.useMemo)(() => { if (isEmbeddableRendered) { return (0, _utils.getTopNavConfig)({ hasUnsavedChanges, setHasUnsavedChanges, hasUnappliedChanges, openInspector, originatingApp, setOriginatingApp, originatingPath, visInstance, stateContainer, visualizationIdFromUrl, stateTransfer: services.stateTransferService, embeddableId, displayEditInLensItem, hideLensBadge, setNavigateToLens, showBadge: !hideTryInLensBadge && displayEditInLensItem, eventEmitter }, services); } }, [isEmbeddableRendered, hasUnsavedChanges, setHasUnsavedChanges, hasUnappliedChanges, openInspector, originatingApp, setOriginatingApp, originatingPath, visInstance, stateContainer, visualizationIdFromUrl, services, embeddableId, displayEditInLensItem, hideLensBadge, hideTryInLensBadge, eventEmitter]); const [indexPatterns, setIndexPatterns] = (0, _react.useState)([]); const showDatePicker = () => { // tsvb loads without an indexPattern initially (TODO investigate). // hide timefilter only if timeFieldName is explicitly undefined. const hasTimeField = vis.data.indexPattern ? !!vis.data.indexPattern.timeFieldName : true; return vis.type.options.showTimePicker && hasTimeField; }; const showFilterBar = vis.type.options.showFilterBar; const showQueryInput = vis.type.requiresSearch && vis.type.options.showQueryInput; (0, _react.useEffect)(() => { return () => { if (inspectorSession) { // Close the inspector if this scope is destroyed (e.g. because the user navigates away). inspectorSession.close(); } }; }, [inspectorSession]); (0, _react.useEffect)(() => { onAppLeave(actions => { // Confirm when the user has made any changes to an existing visualizations // or when the user has configured something without saving // the warning won't appear if you navigate from the Viz editor to Lens if (originatingApp && (hasUnappliedChanges || hasUnsavedChanges) && !services.stateTransferService.isTransferInProgress && !navigateToLens) { return actions.confirm(_i18n.i18n.translate('visualizations.confirmModal.confirmTextDescription', { defaultMessage: 'Leave Visualize editor with unsaved changes?' }), _i18n.i18n.translate('visualizations.confirmModal.title', { defaultMessage: 'Unsaved changes' })); } return actions.default(); }); return () => { // reset on app leave handler so leaving from the listing page doesn't trigger a confirmation onAppLeave(actions => actions.default()); }; }, [onAppLeave, originatingApp, hasUnsavedChanges, hasUnappliedChanges, visualizeCapabilities.save, services.stateTransferService.isTransferInProgress, navigateToLens]); (0, _react.useEffect)(() => { const asyncSetIndexPattern = async () => { let indexes; if (vis.data.indexPattern) { indexes = [vis.data.indexPattern]; } else if (vis.type.getUsedIndexPattern) { indexes = await vis.type.getUsedIndexPattern(vis.params); } if (!indexes || !indexes.length) { const defaultIndex = await services.dataViews.getDefault(); if (defaultIndex) { indexes = [defaultIndex]; } } if (indexes) { setIndexPatterns(indexes); } }; asyncSetIndexPattern(); }, [services.dataViews, vis.data.indexPattern, vis.params, vis.type]); /** Synchronizing dataView with state **/ (0, _react.useEffect)(() => { const stateContainerSubscription = stateContainer.state$.subscribe(async ({ dataView }) => { if (dataView && visInstance.vis.data.indexPattern && dataView !== visInstance.vis.data.indexPattern.id) { const dataViewFromState = await services.dataViews.get(dataView); if (dataViewFromState) { setIndexPatterns([dataViewFromState]); } } }); return () => { stateContainerSubscription.unsubscribe(); }; }, [services.dataViews, stateContainer.state$, visInstance.vis.data.indexPattern]); (0, _react.useEffect)(() => { const autoRefreshFetchSub = services.data.query.timefilter.timefilter.getAutoRefreshFetch$().subscribe(async done => { try { await doReload(); } finally { done(); } }); return () => { autoRefreshFetchSub.unsubscribe(); }; }, [services.data.query.timefilter.timefilter, doReload]); const shouldShowDataViewPicker = Boolean(((_vis$type$editorConfi = vis.type.editorConfig) === null || _vis$type$editorConfi === void 0 ? void 0 : _vis$type$editorConfi.enableDataViewChange) && (vis.data.indexPattern && !vis.data.savedSearchId || (0, _utils.isFallbackDataView)(vis.data.indexPattern)) && indexPatterns.length); const onChangeDataView = (0, _react.useCallback)(async selectedDataViewId => { if (selectedDataViewId) { stateContainer.transitions.updateDataView(selectedDataViewId); } }, [stateContainer.transitions]); const isMissingCurrentDataView = (0, _utils.isFallbackDataView)(vis.data.indexPattern); return isChromeVisible ? /*#__PURE__*/ /** * Most visualizations have all search bar components enabled. * Some visualizations have fewer options, but all visualizations have the search bar. * That's is why the showSearchBar prop is set. * All visualizations also have the timepicker\autorefresh component, * it is enabled by default in the TopNavMenu component. */ _react.default.createElement(TopNavMenu, { appName: _constants.VISUALIZE_APP_NAME, config: config, setMenuMountPoint: setHeaderActionMenu, onQuerySubmit: handleRefresh, savedQueryId: currentAppState.savedQuery, onSavedQueryIdChange: stateContainer.transitions.updateSavedQuery, indexPatterns: indexPatterns, screenTitle: vis.title, showAutoRefreshOnly: !showDatePicker(), showDatePicker: showDatePicker(), showFilterBar: showFilterBar, showQueryInput: showQueryInput, showSaveQuery: Boolean(services.visualizeCapabilities.saveQuery), dataViewPickerComponentProps: shouldShowDataViewPicker && vis.data.indexPattern ? { currentDataViewId: vis.data.indexPattern.id, trigger: { label: isMissingCurrentDataView ? _i18n.i18n.translate('visualizations.fallbackDataView.label', { defaultMessage: '{type} not found', values: { type: vis.data.savedSearchId ? _i18n.i18n.translate('visualizations.search.label', { defaultMessage: 'Search' }) : _i18n.i18n.translate('visualizations.dataView.label', { defaultMessage: 'Data view' }) } }) : vis.data.indexPattern.getName() }, isMissingCurrent: isMissingCurrentDataView, onChangeDataView } : undefined, showSearchBar: true, useDefaultBehaviors: true }) : showFilterBar ? /*#__PURE__*/ /** * The top nav is hidden in embed mode, but the filter bar must still be present so * we show the filter bar on its own here if the chrome is not visible. */ _react.default.createElement(TopNavMenu, { appName: _constants.VISUALIZE_APP_NAME, setMenuMountPoint: setHeaderActionMenu, indexPatterns: indexPatterns, showSearchBar: true, showSaveQuery: false, showDatePicker: false, showQueryInput: false }) : null; }; const VisualizeTopNav = /*#__PURE__*/(0, _react.memo)(TopNav); exports.VisualizeTopNav = VisualizeTopNav;