diff --git a/CHANGELOG.md b/CHANGELOG.md index b4f25f48f8ac..0447251ea6a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Add `color-scheme` to the root styling ([#4477](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4477)) - [Multiple DataSource] Frontend support for adding sample data ([#4412](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4412)) - Enable plugins to augment visualizations with additional data and context ([#4361](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4361)) +- Dashboard De-Angularization ([#4502](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4502)) ### 🐛 Bug Fixes diff --git a/src/plugins/dashboard/public/application/app.tsx b/src/plugins/dashboard/public/application/app.tsx index 83634d23729e..1d9c6268c1e3 100644 --- a/src/plugins/dashboard/public/application/app.tsx +++ b/src/plugins/dashboard/public/application/app.tsx @@ -10,17 +10,12 @@ */ import './app.scss'; -import { AppMountParameters } from 'opensearch-dashboards/public'; import React from 'react'; import { Route, Switch } from 'react-router-dom'; import { DashboardConstants, createDashboardEditUrl } from '../dashboard_constants'; import { DashboardEditor, DashboardListing, DashboardNoMatch } from './components'; -export interface DashboardAppProps { - onAppLeave: AppMountParameters['onAppLeave']; -} - -export const DashboardApp = ({ onAppLeave }: DashboardAppProps) => { +export const DashboardApp = () => { return ( diff --git a/src/plugins/dashboard/public/application/components/dashboard_editor.tsx b/src/plugins/dashboard/public/application/components/dashboard_editor.tsx index b6a52a9250c6..3a6089470443 100644 --- a/src/plugins/dashboard/public/application/components/dashboard_editor.tsx +++ b/src/plugins/dashboard/public/application/components/dashboard_editor.tsx @@ -23,7 +23,7 @@ export const DashboardEditor = () => { const { id: dashboardIdFromUrl } = useParams<{ id: string }>(); const { services } = useOpenSearchDashboards(); const { chrome } = services; - const isChromeVisible = useChromeVisibility(services.chrome); + const isChromeVisible = useChromeVisibility(chrome); const [eventEmitter] = useState(new EventEmitter()); const { savedDashboard: savedDashboardInstance, dashboard } = useSavedDashboardInstance( @@ -41,8 +41,6 @@ export const DashboardEditor = () => { const { dashboardContainer, indexPatterns } = useDashboardContainer( services, - isChromeVisible, - eventEmitter, dashboard, savedDashboardInstance, appState @@ -58,23 +56,23 @@ export const DashboardEditor = () => { ); useEffect(() => { - if (appState && dashboard) { + if (currentAppState && dashboard) { if (savedDashboardInstance?.id) { chrome.setBreadcrumbs( setBreadcrumbsForExistingDashboard( savedDashboardInstance.title, - appState?.getState().viewMode, + currentAppState.viewMode, dashboard.isDirty ) ); chrome.docTitle.change(savedDashboardInstance.title); } else { chrome.setBreadcrumbs( - setBreadcrumbsForNewDashboard(appState?.getState().viewMode, dashboard.isDirty) + setBreadcrumbsForNewDashboard(currentAppState.viewMode, dashboard.isDirty) ); } } - }, [appState?.getState(), savedDashboardInstance, chrome]); + }, [currentAppState, savedDashboardInstance, chrome, dashboard]); useEffect(() => { // clean up all registered listeners if any is left @@ -83,18 +81,6 @@ export const DashboardEditor = () => { }; }, [eventEmitter]); - console.log('savedDashboardInstance', savedDashboardInstance); - console.log('dashboard', dashboard); - console.log('appState', appState); - console.log('appStateData', appState?.getState()); - console.log('currentAppState', currentAppState); - console.log('isEmbeddableRendered', isEmbeddableRendered); - if (dashboard) { - console.log('isDirty', dashboard.isDirty); - } - console.log('dashboardContainer', dashboardContainer); - console.log('indexPatterns', indexPatterns); - return (
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 2d37676a5c37..d4fb223e6f73 100644 --- a/src/plugins/dashboard/public/application/components/dashboard_top_nav.tsx +++ b/src/plugins/dashboard/public/application/components/dashboard_top_nav.tsx @@ -4,7 +4,7 @@ */ import React, { memo, useState, useEffect } from 'react'; -import { Filter, IndexPattern } from 'src/plugins/data/public'; +import { IndexPattern } from 'src/plugins/data/public'; import { useCallback } from 'react'; import { useLocation } from 'react-router-dom'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; @@ -102,7 +102,7 @@ const TopNav = ({ stateContainer, isEmbeddableRendered, dashboard, - dashboardIdFromUrl + dashboardIdFromUrl, ]); useEffect(() => { diff --git a/src/plugins/dashboard/public/application/embeddable/grid/_dashboard_grid.scss b/src/plugins/dashboard/public/application/embeddable/grid/_dashboard_grid.scss index c7f801102cad..019667bec13f 100644 --- a/src/plugins/dashboard/public/application/embeddable/grid/_dashboard_grid.scss +++ b/src/plugins/dashboard/public/application/embeddable/grid/_dashboard_grid.scss @@ -82,7 +82,7 @@ &:hover, &:focus { // TODO: this is a sass error, $embEditingModeHoverColor is undefined, comment it out for now - //background-color: $embEditingModeHoverColor; + // background-color: $embEditingModeHoverColor; } } diff --git a/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.tsx b/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.tsx index 633c4f7428c2..ea58e82a88c5 100644 --- a/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.tsx +++ b/src/plugins/dashboard/public/application/embeddable/grid/dashboard_grid.tsx @@ -30,7 +30,7 @@ import 'react-grid-layout/css/styles.css'; import 'react-resizable/css/styles.css'; -import './_dashboard_grid.scss' +import './_dashboard_grid.scss'; // @ts-ignore import sizeMe from 'react-sizeme'; diff --git a/src/plugins/dashboard/public/application/top_nav/get_top_nav_config.ts b/src/plugins/dashboard/public/application/top_nav/get_top_nav_config.ts index e325a291c130..aa7c2e2e4255 100644 --- a/src/plugins/dashboard/public/application/top_nav/get_top_nav_config.ts +++ b/src/plugins/dashboard/public/application/top_nav/get_top_nav_config.ts @@ -29,7 +29,6 @@ */ import { i18n } from '@osd/i18n'; -import { AppMountParameters } from 'opensearch-dashboards/public'; import { ViewMode } from '../../embeddable_plugin'; import { TopNavIds } from './top_nav_ids'; import { NavAction } from '../../types'; @@ -43,8 +42,7 @@ import { NavAction } from '../../types'; export function getTopNavConfig( dashboardMode: ViewMode, actions: { [key: string]: NavAction }, - hideWriteControls: boolean, - onAppLeave?: AppMountParameters['onAppLeave'] + hideWriteControls: boolean ) { switch (dashboardMode) { case ViewMode.VIEW: diff --git a/src/plugins/dashboard/public/application/utils/get_dashboard_instance.tsx b/src/plugins/dashboard/public/application/utils/get_dashboard_instance.tsx index 3385aadbe738..d2a1a1a4f3e0 100644 --- a/src/plugins/dashboard/public/application/utils/get_dashboard_instance.tsx +++ b/src/plugins/dashboard/public/application/utils/get_dashboard_instance.tsx @@ -30,10 +30,11 @@ export const getDashboardInstance = async ( // Get the existing dashboard/default new dashboard from saved object loader const savedDashboard: SavedObjectDashboard = await savedDashboards.get(opts); + // Serialized the saved object dashboard const serializedDashboard = convertToSerializedDashboard(savedDashboard); + // Create a Dashboard class using the serialized dashboard - // const dashboard = (await dashboards.createDashboard(serializedDashboard)) as Dashboard; const dashboard = new Dashboard(serializedDashboard); await dashboard.setState(serializedDashboard); 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 e364a0de293a..27d7094784dc 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 @@ -5,7 +5,7 @@ import React, { useState } from 'react'; import { cloneDeep, isEqual, uniqBy } from 'lodash'; -import { EMPTY, Observable, Subscription, merge, of, pipe } from 'rxjs'; +import { EMPTY, Observable, Subscription, merge, pipe } from 'rxjs'; import { catchError, distinctUntilChanged, @@ -16,7 +16,6 @@ import { switchMap, } from 'rxjs/operators'; import deepEqual from 'fast-deep-equal'; -import { EventEmitter } from 'stream'; import { useEffect } from 'react'; import { i18n } from '@osd/i18n'; import _ from 'lodash'; @@ -55,8 +54,6 @@ import { Dashboard } from '../../../dashboard'; export const useDashboardContainer = ( services: DashboardServices, - isChromeVisible: boolean, - eventEmitter: EventEmitter, dashboard?: Dashboard, savedDashboardInstance?: SavedObjectDashboard, appState?: DashboardAppStateContainer @@ -134,7 +131,6 @@ const createDashboardEmbeddable = ( } = dashboardServices; const { query: queryService } = data; const filterManager = queryService.filterManager; - const timefilter = queryService.timefilter.timefilter; const queryStringManager = queryService.queryString; const { visualizeCapabilities, mapsCapabilities } = embeddableCapabilities; const dashboardFactory = embeddable.getEmbeddableFactory< @@ -237,7 +233,7 @@ const createDashboardEmbeddable = ( getShouldShowViewHelp(appStateData) || shouldShowUnauthorizedEmptyState(appStateData), useMargins: appStateData.options.useMargins, - lastReloadRequestTime, // TODO + lastReloadRequestTime, title: appStateData.title, description: appStateData.description, expandedPanelId: appStateData.expandedPanelId, @@ -339,8 +335,6 @@ const createDashboardEmbeddable = ( return Object.values(differences).length === 0 ? undefined : cloneDeep(differences); }; - // TODO: handle dashboard container input and output subsciptions - // issue: outputSubscription = merge( // output of dashboard container itself dashboardContainer.getOutput$(), @@ -381,13 +375,6 @@ const createDashboardEmbeddable = ( ) { // Add filters modifies the object passed to it, hence the clone deep. filterManager.addFilters(cloneDeep(container.getInput().filters)); - - // TODO: investigate if this is needed - /* dashboardStateManager.applyFilters( - $scope.model.query, - container.getInput().filters - );*/ - appState.transitions.set('query', queryStringManager.getQuery()); } // triggered when dashboard embeddable container has changes, and update the appState diff --git a/src/plugins/dashboard/public/application/utils/use/use_saved_dashboard_instance.ts b/src/plugins/dashboard/public/application/utils/use/use_saved_dashboard_instance.ts index d65b022c623f..88edb45f4c27 100644 --- a/src/plugins/dashboard/public/application/utils/use/use_saved_dashboard_instance.ts +++ b/src/plugins/dashboard/public/application/utils/use/use_saved_dashboard_instance.ts @@ -44,10 +44,10 @@ export const useSavedDashboardInstance = ( const getSavedDashboardInstance = async () => { try { - let savedDashboardInstance: any; + let savedDashboardObject: any; if (history.location.pathname === '/create') { try { - savedDashboardInstance = await getDashboardInstance(services); + savedDashboardObject = await getDashboardInstance(services); } catch { redirectWhenMissing({ history, @@ -61,8 +61,8 @@ export const useSavedDashboardInstance = ( } } else if (dashboardIdFromUrl) { try { - savedDashboardInstance = await getDashboardInstance(services, dashboardIdFromUrl); - const { savedDashboard } = savedDashboardInstance; + savedDashboardObject = await getDashboardInstance(services, dashboardIdFromUrl); + const { savedDashboard } = savedDashboardObject; // Update time filter to match the saved dashboard if time restore has been set to true when saving the dashboard // We should only set the time filter according to time restore once when we are loading the dashboard @@ -111,7 +111,7 @@ export const useSavedDashboardInstance = ( } } - setSavedDashboardInstance(savedDashboardInstance); + setSavedDashboardInstance(savedDashboardObject); } catch (error) { toastNotifications.addWarning({ title: i18n.translate('dashboard.createDashboard.failedToLoadErrorMessage', { diff --git a/src/plugins/dashboard/public/dashboard.ts b/src/plugins/dashboard/public/dashboard.ts index 668d3afb09a6..ef54348da768 100644 --- a/src/plugins/dashboard/public/dashboard.ts +++ b/src/plugins/dashboard/public/dashboard.ts @@ -15,14 +15,9 @@ import { cloneDeep } from 'lodash'; import { Filter, ISearchSource, Query, RefreshInterval } from '../../data/public'; -import { DashboardPanelState } from './application'; -import { EmbeddableInput } from './embeddable_plugin'; import { SavedDashboardPanel } from './types'; -// export interface SerializedPanels { -// [panelId: string]: DashboardPanelState; -// } - +// TODO: This class can be revisited and clean up more export interface SerializedDashboard { id?: string; timeRestore: boolean; @@ -35,8 +30,8 @@ export interface SerializedDashboard { useMargins: boolean; }; uiState?: string; - lastSavedTitle: string; // TODO: DO WE STILL NEED THIS? - refreshInterval?: RefreshInterval; // TODO: SHOULD THIS NOT BE OPTIONAL? + lastSavedTitle: string; + refreshInterval?: RefreshInterval; searchSource?: ISearchSource; query: Query; filters: Filter[]; @@ -63,7 +58,6 @@ export class Dashboard { public query: Query; public filters: Filter[]; public title?: string; - // TODO: dashboardNew - pass version to dashboard class public version = '3.0.0'; public isDirty = false; @@ -90,8 +84,6 @@ export class Dashboard { this.description = state.description; } if (state.panels) { - // this panels is only JSON.parse() panels, we should convert them into the same type as app state panels - // app state store only JSON.parse() panels too this.panels = cloneDeep(state.panels); } if (state.options) { @@ -124,52 +116,4 @@ export class Dashboard { private getRefreshInterval(refreshInterval: RefreshInterval) { return cloneDeep(refreshInterval ?? {}); } - - // private getQuery(query: Query): Query { - // return cloneDeep(query ?? ({} as Query)); - // } - - // private getFilters(filters: Filter[]) { - // return cloneDeep(filters ?? ({} as Filter[])); - // } - - // private getPanels(panels?: SerializedPanels) { - // return cloneDeep(panels ?? ({} as SerializedPanels)); - // } - - /* clone() { - const serializedDashboard = this.serialize(); - const dashboard = new Dashboard(serializedDashboard); - dashboard.setState(serializedDashboard); - return dashboard; - }*/ - - /* serialize(): SerializedDashboard { - return { - id: this.id, - timeRestore: this.timeRestore!, - timeTo: this.timeTo, - timeFrom: this.timeFrom, - description: this.description, - panels: this.serializePanels(), - options: cloneDeep(this.options) as any, - uiState: this.uiState, - lastSavedTitle: this.lastSavedTitle, - refreshInterval: this.refreshInterval, - searchSource: this.searchSource, - query: this.query, - filters: this.filters, - title: this.title!, - }; - }*/ - - /* serializePanels(): SerializedPanels { - const embeddablesMap: { - [key: string]: DashboardPanelState; - } = {}; - this.panels.forEach((panel: SavedDashboardPanel) => { - embeddablesMap[panel.panelIndex] = convertSavedDashboardPanelToPanelState(panel); - }); - return embeddablesMap; - }*/ } diff --git a/src/plugins/dashboard/server/saved_objects/migrations_730.test.ts b/src/plugins/dashboard/server/saved_objects/migrations_730.test.ts index 330711c0e687..ae1fb945250e 100644 --- a/src/plugins/dashboard/server/saved_objects/migrations_730.test.ts +++ b/src/plugins/dashboard/server/saved_objects/migrations_730.test.ts @@ -68,6 +68,7 @@ test('dashboard migration 7.3.0 migrates filters to query on search source', () "panelsJSON": "[{\\"id\\":\\"1\\",\\"type\\":\\"visualization\\",\\"foo\\":true},{\\"id\\":\\"2\\",\\"type\\":\\"visualization\\",\\"bar\\":true}]", "timeRestore": false, "title": "hi", + "uiStateJSON": "{}", "useMargins": true, "version": 1, },