import * as React from 'react' ; import { BehaviorSubject } from 'rxjs' ; import { filter , map } from 'rxjs/operators' ; import { i18n } from '@osd/i18n' ; import { App , AppMountParameters , AppUpdater , CoreSetup , CoreStart , Plugin , PluginInitializerContext , SavedObjectsClientContract , ScopedHistory , } from 'src/core/public' ; import { UrlForwardingSetup , UrlForwardingStart } from 'src/plugins/url_forwarding/public' ; import { UsageCollectionSetup } from '../../usage_collection/public' ; import { CONTEXT_MENU_TRIGGER , EmbeddableSetup , EmbeddableStart , SavedObjectEmbeddableInput , EmbeddableInput , PANEL_NOTIFICATION_TRIGGER , } from '../../embeddable/public' ; import { DataPublicPluginSetup , DataPublicPluginStart , opensearchFilters } from '../../data/public' ; import { SharePluginSetup , SharePluginStart , UrlGeneratorContract } from '../../share/public' ; import { UiActionsSetup , UiActionsStart } from '../../ui_actions/public' ; import { Start as InspectorStartContract } from '../../inspector/public' ; import { NavigationPublicPluginStart as NavigationStart } from '../../navigation/public' ; import { getSavedObjectFinder , SavedObjectLoader , SavedObjectsStart , showSaveModal , } from '../../saved_objects/public' ; import { ExitFullScreenButton as ExitFullScreenButtonUi , ExitFullScreenButtonProps , } from '../../opensearch_dashboards_react/public' ; import { createOsdUrlTracker , Storage } from '../../opensearch_dashboards_utils/public' ; import { initAngularBootstrap , OpenSearchDashboardsLegacySetup , OpenSearchDashboardsLegacyStart , } from '../../opensearch_dashboards_legacy/public' ; import { FeatureCatalogueCategory , HomePublicPluginSetup } from '../../../plugins/home/public' ; import { DEFAULT_APP_CATEGORIES } from '../../../core/public' ; import { ACTION_CLONE_PANEL , ACTION_EXPAND_PANEL , ACTION_REPLACE_PANEL , ClonePanelAction , ClonePanelActionContext , createDashboardContainerByValueRenderer , DASHBOARD_CONTAINER_TYPE , DashboardContainerFactory , DashboardContainerFactoryDefinition , ExpandPanelAction , ExpandPanelActionContext , RenderDeps , ReplacePanelAction , ReplacePanelActionContext , ACTION_UNLINK_FROM_LIBRARY , UnlinkFromLibraryActionContext , UnlinkFromLibraryAction , ACTION_ADD_TO_LIBRARY , AddToLibraryActionContext , AddToLibraryAction , ACTION_LIBRARY_NOTIFICATION , LibraryNotificationActionContext , LibraryNotificationAction , } from './application' ; import { createDashboardUrlGenerator , DASHBOARD_APP_URL_GENERATOR , DashboardUrlGeneratorState , } from './url_generator' ; import { createSavedDashboardLoader } from './saved_dashboards' ; import { DashboardConstants } from './dashboard_constants' ; import { addEmbeddableToDashboardUrl } from './url_utils/url_helper' ; import { PlaceholderEmbeddableFactory } from './application/embeddable/placeholder' ; import { UrlGeneratorState } from '../../share/public' ; import { AttributeService } from '.' ; import { AttributeServiceOptions , ATTRIBUTE_SERVICE_KEY , } from './attribute_service/attribute_service' ; declare module '../../share/public' { export interface UrlGeneratorStateMapping { [ DASHBOARD_APP_URL_GENERATOR ] : UrlGeneratorState < DashboardUrlGeneratorState > ; } } export type DashboardUrlGenerator = UrlGeneratorContract < typeof DASHBOARD_APP_URL_GENERATOR > ; export interface DashboardFeatureFlagConfig { allowByValueEmbeddables : boolean ; } interface SetupDependencies { data : DataPublicPluginSetup ; embeddable : EmbeddableSetup ; home ? : HomePublicPluginSetup ; opensearchDashboardsLegacy : OpenSearchDashboardsLegacySetup ; urlForwarding : UrlForwardingSetup ; share ? : SharePluginSetup ; uiActions : UiActionsSetup ; usageCollection ? : UsageCollectionSetup ; } interface StartDependencies { data : DataPublicPluginStart ; opensearchDashboardsLegacy : OpenSearchDashboardsLegacyStart ; urlForwarding : UrlForwardingStart ; embeddable : EmbeddableStart ; inspector : InspectorStartContract ; navigation : NavigationStart ; savedObjectsClient : SavedObjectsClientContract ; share ? : SharePluginStart ; uiActions : UiActionsStart ; savedObjects : SavedObjectsStart ; } export type DashboardSetup = void ; export interface DashboardStart { getSavedDashboardLoader : ( ) => SavedObjectLoader ; addEmbeddableToDashboard : ( options : { embeddableId : string ; embeddableType : string ; } ) => void | undefined ; dashboardUrlGenerator ? : DashboardUrlGenerator ; dashboardFeatureFlagConfig : DashboardFeatureFlagConfig ; DashboardContainerByValueRenderer : ReturnType < typeof createDashboardContainerByValueRenderer > ; getAttributeService : < A extends { title : string ; } , V extends EmbeddableInput & { [ ATTRIBUTE_SERVICE_KEY ] : A ; } = EmbeddableInput & { [ ATTRIBUTE_SERVICE_KEY ] : A ; } , R extends SavedObjectEmbeddableInput = SavedObjectEmbeddableInput > ( type : string , options : AttributeServiceOptions < A > ) => AttributeService < A , V , R > ; } declare module '../../../plugins/ui_actions/public' { export interface ActionContextMapping { [ ACTION_EXPAND_PANEL ] : ExpandPanelActionContext ; [ ACTION_REPLACE_PANEL ] : ReplacePanelActionContext ; [ ACTION_CLONE_PANEL ] : ClonePanelActionContext ; [ ACTION_ADD_TO_LIBRARY ] : AddToLibraryActionContext ; [ ACTION_UNLINK_FROM_LIBRARY ] : UnlinkFromLibraryActionContext ; [ ACTION_LIBRARY_NOTIFICATION ] : LibraryNotificationActionContext ; } } export class DashboardPlugin implements Plugin < DashboardSetup , DashboardStart , SetupDependencies , StartDependencies > { constructor ( private initializerContext ) { } private appStateUpdater = new BehaviorSubject < AppUpdater > ( ( ) => ( { } ) ) ; private stopUrlTracking : ( ( ) => void ) | undefined = undefined ; private getActiveUrl : ( ( ) => string ) | undefined = undefined ; private currentHistory : ScopedHistory | undefined = undefined ; private dashboardFeatureFlagConfig ? : DashboardFeatureFlagConfig ; private dashboardUrlGenerator ? : DashboardUrlGenerator ; public setup ( core , { share , uiActions , embeddable , home , urlForwarding , data , usageCollection } ) { this . dashboardFeatureFlagConfig = this . initializerContext . config . get < DashboardFeatureFlagConfig > ( ) ; const expandPanelAction = new ExpandPanelAction ( ) ; uiActions . registerAction ( expandPanelAction ) ; uiActions . attachAction ( CONTEXT_MENU_TRIGGER , expandPanelAction . id ) ; const startServices = core . getStartServices ( ) ; if ( share ) { this . dashboardUrlGenerator = share . urlGenerators . registerUrlGenerator ( createDashboardUrlGenerator ( async ( ) => { const [ coreStart , , selfStart ] = await startServices ; return { appBasePath : coreStart . application . getUrlForApp ( 'dashboards' ) , useHashedUrl : coreStart . uiSettings . get ( 'state:storeInSessionStorage' ) , savedDashboardLoader : selfStart . getSavedDashboardLoader ( ) , } ; } ) ) ; } const getStartServices = async ( ) => { const [ coreStart , deps ] = await core . getStartServices ( ) ; const useHideChrome = ( { toggleChrome } = { toggleChrome : true } ) => { React . useEffect ( ( ) => { if ( toggleChrome ) { coreStart . chrome . setIsVisible ( false ) ; } return ( ) => { if ( toggleChrome ) { coreStart . chrome . setIsVisible ( true ) ; } } ; } , [ toggleChrome ] ) ; } ; const ExitFullScreenButton = ( { toggleChrome , ... props } ) => { useHideChrome ( { toggleChrome } ) ; return < ExitFullScreenButtonUi { ... props } / > ; } ; return { capabilities : coreStart . application . capabilities , application : coreStart . application , notifications : coreStart . notifications , overlays : coreStart . overlays , embeddable : deps . embeddable , inspector : deps . inspector , SavedObjectFinder : getSavedObjectFinder ( coreStart . savedObjects , coreStart . uiSettings ) , ExitFullScreenButton , uiActions : deps . uiActions , } ; } ; const factory = new DashboardContainerFactoryDefinition ( getStartServices , ( ) => this . currentHistory ! ) ; embeddable . registerEmbeddableFactory ( factory . type , factory ) ; const placeholderFactory = new PlaceholderEmbeddableFactory ( ) ; embeddable . registerEmbeddableFactory ( placeholderFactory . type , placeholderFactory ) ; const { appMounted , appUnMounted , stop : stopUrlTracker , getActiveUrl , restorePreviousUrl , } = createOsdUrlTracker ( { baseUrl : core . http . basePath . prepend ( '/app/dashboards' ) , defaultSubUrl : `#${ DashboardConstants . LANDING_PAGE_PATH }` , storageKey : `lastUrl:${ core . http . basePath . get ( ) }:dashboard` , navLinkUpdater$ : this . appStateUpdater , toastNotifications : core . notifications . toasts , stateParams : [ { osdUrlKey : '_g' , stateUpdate$ : data . query . state$ . pipe ( filter ( ( { changes } ) => ! ! ( changes . globalFilters || changes . time || changes . refreshInterval ) ) , map ( ( { state } ) => ( { ... state , filters : state . filters ?. filter ( opensearchFilters . isFilterPinned ) , } ) ) ) , } , ] , getHistory : ( ) => this . currentHistory ! , } ) ; this . getActiveUrl = getActiveUrl ; this . stopUrlTracking = ( ) => { stopUrlTracker ( ) ; } ; const app = { id : DashboardConstants . DASHBOARDS_ID , title : 'Dashboard' , order : 2500 , euiIconType : 'inputOutput' , defaultPath : `#${ DashboardConstants . LANDING_PAGE_PATH }` , updater$ : this . appStateUpdater , category : DEFAULT_APP_CATEGORIES . opensearchDashboards , mount : async ( params ) => { const [ coreStart , pluginsStart , dashboardStart ] = await core . getStartServices ( ) ; this . currentHistory = params . history ; appMounted ( ) ; const { embeddable : embeddableStart , navigation , share : shareStart , data : dataStart , opensearchDashboardsLegacy : { dashboardConfig } , urlForwarding : { navigateToDefaultApp , navigateToLegacyOpenSearchDashboardsUrl } , savedObjects , } = pluginsStart ; const deps = { pluginInitializerContext : this . initializerContext , core : coreStart , dashboardConfig , navigateToDefaultApp , navigateToLegacyOpenSearchDashboardsUrl , navigation , share : shareStart , data : dataStart , savedObjectsClient : coreStart . savedObjects . client , savedDashboards : dashboardStart . getSavedDashboardLoader ( ) , chrome : coreStart . chrome , addBasePath : coreStart . http . basePath . prepend , uiSettings : coreStart . uiSettings , savedQueryService : dataStart . query . savedQueries , embeddable : embeddableStart , dashboardCapabilities : coreStart . application . capabilities . dashboard , embeddableCapabilities : { visualizeCapabilities : coreStart . application . capabilities . visualize , mapsCapabilities : coreStart . application . capabilities . maps , } , localStorage : new Storage ( localStorage ) , usageCollection , scopedHistory : ( ) => this . currentHistory ! , setHeaderActionMenu : params . setHeaderActionMenu , savedObjects , restorePreviousUrl , } ; await dataStart . indexPatterns . clearCache ( ) ; const { renderApp } = await import ( './application/application' ) ; params . element . classList . add ( 'dshAppContainer' ) ; const unmount = renderApp ( params . element , params . appBasePath , deps ) ; return ( ) => { unmount ( ) ; appUnMounted ( ) ; } ; } , } ; initAngularBootstrap ( ) ; core . application . register ( app ) ; urlForwarding . forwardApp ( DashboardConstants . DASHBOARDS_ID , DashboardConstants . DASHBOARDS_ID , ( path ) => { const [ , tail ] = /(\?.*)/ . exec ( path ) || [ ] ; return `#/list${ tail || '' }` ; } ) ; urlForwarding . forwardApp ( DashboardConstants . DASHBOARD_ID , DashboardConstants . DASHBOARDS_ID , ( path ) => { const [ , id , tail ] = /dashboard\/?(.*?)($|\?.*)/ . exec ( path ) || [ ] ; if ( ! id && ! tail ) { return '#/list' ; } if ( ! id && tail ) { return `#/create${ tail || '' }` ; } return `#/view/${ id }${ tail || '' }` ; } ) ; if ( home ) { home . featureCatalogue . register ( { id : DashboardConstants . DASHBOARD_ID , title : i18n . translate ( 'dashboard.featureCatalogue.dashboardTitle' , { defaultMessage : 'Dashboard' , } ) , subtitle : i18n . translate ( 'dashboard.featureCatalogue.dashboardSubtitle' , { defaultMessage : 'Analyze data in dashboards.' , } ) , description : i18n . translate ( 'dashboard.featureCatalogue.dashboardDescription' , { defaultMessage : 'Display and share a collection of visualizations and saved searches.' , } ) , icon : 'dashboardApp' , path : `/app/dashboards#${ DashboardConstants . LANDING_PAGE_PATH }` , showOnHomePage : false , category : FeatureCatalogueCategory . DATA , solutionId : 'opensearchDashboards' , order : 100 , } ) ; } } private addEmbeddableToDashboard ( core , { embeddableId , embeddableType } ) { if ( ! this . getActiveUrl ) { throw new Error ( 'dashboard is not ready yet.' ) ; } const lastDashboardUrl = this . getActiveUrl ( ) ; const dashboardUrl = addEmbeddableToDashboardUrl ( lastDashboardUrl , embeddableId , embeddableType ) ; core . application . navigateToApp ( 'dashboards' , { path : dashboardUrl } ) ; } public start ( core , plugins ) { const { notifications } = core ; const { uiActions , data : { indexPatterns , search } , embeddable , } = plugins ; const SavedObjectFinder = getSavedObjectFinder ( core . savedObjects , core . uiSettings ) ; const changeViewAction = new ReplacePanelAction ( core , SavedObjectFinder , notifications , plugins . embeddable . getEmbeddableFactories ) ; uiActions . registerAction ( changeViewAction ) ; uiActions . attachAction ( CONTEXT_MENU_TRIGGER , changeViewAction . id ) ; const clonePanelAction = new ClonePanelAction ( core ) ; uiActions . registerAction ( clonePanelAction ) ; uiActions . attachAction ( CONTEXT_MENU_TRIGGER , clonePanelAction . id ) ; if ( this . dashboardFeatureFlagConfig ?. allowByValueEmbeddables ) { const addToLibraryAction = new AddToLibraryAction ( ) ; uiActions . registerAction ( addToLibraryAction ) ; uiActions . attachAction ( CONTEXT_MENU_TRIGGER , addToLibraryAction . id ) ; const unlinkFromLibraryAction = new UnlinkFromLibraryAction ( ) ; uiActions . registerAction ( unlinkFromLibraryAction ) ; uiActions . attachAction ( CONTEXT_MENU_TRIGGER , unlinkFromLibraryAction . id ) ; const libraryNotificationAction = new LibraryNotificationAction ( ) ; uiActions . registerAction ( libraryNotificationAction ) ; uiActions . attachAction ( PANEL_NOTIFICATION_TRIGGER , libraryNotificationAction . id ) ; } const savedDashboardLoader = createSavedDashboardLoader ( { savedObjectsClient : core . savedObjects . client , indexPatterns , search , chrome : core . chrome , overlays : core . overlays , } ) ; const dashboardContainerFactory = plugins . embeddable . getEmbeddableFactory ( DASHBOARD_CONTAINER_TYPE ) ! as DashboardContainerFactory ; return { getSavedDashboardLoader : ( ) => savedDashboardLoader , addEmbeddableToDashboard : this . addEmbeddableToDashboard . bind ( this , core ) , dashboardUrlGenerator : this . dashboardUrlGenerator , dashboardFeatureFlagConfig : this . dashboardFeatureFlagConfig ! , DashboardContainerByValueRenderer : createDashboardContainerByValueRenderer ( { factory : dashboardContainerFactory , } ) , getAttributeService : ( type , options ) => new AttributeService ( type , showSaveModal , core . i18n . Context , core . notifications . toasts , options , embeddable . getEmbeddableFactory ) , } ; } public stop ( ) { if ( this . stopUrlTracking ) { this . stopUrlTracking ( ) ; } } }