From f209c40d3124fb5a52fde7b081684aec4f7fc76f Mon Sep 17 00:00:00 2001 From: Riya <69919272+riysaxen-amzn@users.noreply.github.com> Date: Tue, 3 Sep 2024 16:54:35 -0700 Subject: [PATCH] Persist dataSourceId across applications under new Nav change (#244) * Persist dataSourceId across applications under new Nav change Signed-off-by: Riya Saxena * fixes with mds Signed-off-by: Riya Saxena * fixes with mds Signed-off-by: Riya Saxena * fix UTs Signed-off-by: Riya Saxena * moved to constants Signed-off-by: Riya Saxena * revert changes in snapshot files Signed-off-by: Riya Saxena --------- Signed-off-by: Riya Saxena Co-authored-by: Amardeepsingh Siglani --- .../MDSEnabledComponent.tsx | 23 +++++++++++++++++-- public/components/PageHeader/PageHeader.tsx | 2 ++ public/pages/Emails/EmailSenders.tsx | 5 +++- public/pages/Main/Main.tsx | 15 +++++++++--- public/plugin.ts | 23 +++++++++++++++++-- public/utils/constants.ts | 12 ++++++++++ 6 files changed, 72 insertions(+), 8 deletions(-) diff --git a/public/components/MDSEnabledComponent/MDSEnabledComponent.tsx b/public/components/MDSEnabledComponent/MDSEnabledComponent.tsx index 565e1af5..ef90e38f 100644 --- a/public/components/MDSEnabledComponent/MDSEnabledComponent.tsx +++ b/public/components/MDSEnabledComponent/MDSEnabledComponent.tsx @@ -1,6 +1,8 @@ -import React from "react"; +import React, { useContext, useEffect } from "react"; import { DataSourceMenuContext, DataSourceMenuProperties } from "../../services/DataSourceMenuContext"; import _ from 'lodash' +import { useHistory } from "react-router-dom"; +import queryString from "query-string"; export default class MDSEnabledComponent< Props extends DataSourceMenuProperties, @@ -29,8 +31,25 @@ export function isDataSourceChanged(prevProps, currentProps) { return false; } -export function isDataSourceError(error) { +export function isDataSourceError(error: { body: { message: string | string[]; }; }) { return (error.body && error.body.message && error.body.message.includes("Data Source Error")); } +export function useUpdateUrlWithDataSourceProperties() { + const dataSourceMenuProps = useContext(DataSourceMenuContext); + const { dataSourceId, multiDataSourceEnabled } = dataSourceMenuProps; + const history = useHistory(); + const currentSearch = history?.location?.search; + const currentQuery = queryString.parse(currentSearch); + useEffect(() => { + if (multiDataSourceEnabled) { + history.replace({ + search: queryString.stringify({ + ...currentQuery, + dataSourceId, + }), + }); + } + }, [dataSourceId, multiDataSourceEnabled]); +} diff --git a/public/components/PageHeader/PageHeader.tsx b/public/components/PageHeader/PageHeader.tsx index e36c9c68..dabae611 100644 --- a/public/components/PageHeader/PageHeader.tsx +++ b/public/components/PageHeader/PageHeader.tsx @@ -10,6 +10,7 @@ import { TopNavControlLinkData, } from '../../../../../src/plugins/navigation/public'; import { getApplication, getNavigationUI, getUseUpdatedUx } from '../../services/utils/constants'; +import { useUpdateUrlWithDataSourceProperties } from '../MDSEnabledComponent/MDSEnabledComponent'; export interface PageHeaderProps { appRightControls?: TopNavControlData[]; @@ -27,6 +28,7 @@ const PageHeader: React.FC = ({ }) => { const { HeaderControl } = getNavigationUI(); const { setAppBadgeControls, setAppRightControls, setAppDescriptionControls, setAppLeftControls } = getApplication(); + useUpdateUrlWithDataSourceProperties(); return getUseUpdatedUx() ? ( <> diff --git a/public/pages/Emails/EmailSenders.tsx b/public/pages/Emails/EmailSenders.tsx index b7da4ddd..1c50387a 100644 --- a/public/pages/Emails/EmailSenders.tsx +++ b/public/pages/Emails/EmailSenders.tsx @@ -13,6 +13,7 @@ import { SendersTable } from './components/tables/SendersTable'; import { SESSendersTable } from './components/tables/SESSendersTable'; import { NotificationService } from '../../services'; import { getUseUpdatedUx } from '../../services/utils/constants'; +import { useUpdateUrlWithDataSourceProperties } from '../../components/MDSEnabledComponent/MDSEnabledComponent'; interface EmailSendersProps extends RouteComponentProps { notificationService: NotificationService; @@ -22,7 +23,9 @@ export function EmailSenders(props: EmailSendersProps) { const coreContext = useContext(CoreServicesContext)!; const mainStateContext = useContext(MainContext)!; - + // Call the hook to manage URL updates + useUpdateUrlWithDataSourceProperties(); + useEffect(() => { setBreadcrumbs([ BREADCRUMBS.NOTIFICATIONS, diff --git a/public/pages/Main/Main.tsx b/public/pages/Main/Main.tsx index 768b86c2..c88a4036 100644 --- a/public/pages/Main/Main.tsx +++ b/public/pages/Main/Main.tsx @@ -11,7 +11,7 @@ import { CoreServicesConsumer, CoreServicesContext } from '../../components/core import { ModalProvider, ModalRoot } from '../../components/Modal'; import { BrowserServices } from '../../models/interfaces'; import { ServicesConsumer, ServicesContext } from '../../services/services'; -import { ROUTES } from '../../utils/constants'; +import { ROUTES, dataSourceObservable } from '../../utils/constants'; import { CHANNEL_TYPE } from '../../../common/constants'; import { Channels } from '../Channels/Channels'; import { ChannelDetails } from '../Channels/components/details/ChannelDetails'; @@ -85,12 +85,20 @@ export default class Main extends Component { dataSourceLabel?: string; }; + if (dataSourceId) { + dataSourceObservable.next({ id: dataSourceId, label: dataSourceLabel }); + } this.state = { ...initialState, dataSourceId: dataSourceId, dataSourceLabel: dataSourceLabel, dataSourceReadOnly: false, - dataSourceLoading: props.multiDataSourceEnabled, + /** + * undefined: need data source picker to help to determine which data source to use. + * empty string: using the local cluster. + * string: using the selected data source. + */ + dataSourceLoading: dataSourceId === undefined ? props.multiDataSourceEnabled : false, }; } else { this.state = initialState; @@ -124,7 +132,7 @@ export default class Main extends Component { ]; let newState = { - dataSourceId: this.state.dataSourceId || '', + dataSourceId: this.state.dataSourceId, dataSourceLabel: this.state.dataSourceLabel || '', dataSourceReadOnly: false, dataSourceLoading: this.state.dataSourceLoading, @@ -153,6 +161,7 @@ export default class Main extends Component { dataSourceId: id, dataSourceLabel: label, }); + dataSourceObservable.next({ id, label }); } if (this.state.dataSourceLoading) { this.setState({ diff --git a/public/plugin.ts b/public/plugin.ts index cfc225bf..f180e64f 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -6,6 +6,7 @@ import { i18n } from '@osd/i18n'; import { AppMountParameters, + AppUpdater, CoreSetup, CoreStart, DEFAULT_APP_CATEGORIES, @@ -20,8 +21,9 @@ import { NotificationsDashboardsSetupDeps, } from './types'; import { PLUGIN_NAME } from '../common'; -import { ROUTES } from './utils/constants'; +import { ROUTES, dataSourceObservable } from './utils/constants'; import { setApplication, setBreadCrumbsSetter, setNavigationUI, setUISettings } from './services/utils/constants'; +import { BehaviorSubject } from "rxjs"; export class notificationsDashboardsPlugin implements @@ -33,6 +35,15 @@ export class notificationsDashboardsPlugin defaultMessage: 'Notifications', }); + private updateDefaultRouteOfManagementApplications: AppUpdater = () => { + const hash = `#/?dataSourceId=${dataSourceObservable.value?.id || ""}`; + return { + defaultPath: hash, + }; + }; + + private appStateUpdater = new BehaviorSubject(this.updateDefaultRouteOfManagementApplications); + public setup( core: CoreSetup, { managementOverview, dataSourceManagement }: NotificationsDashboardsSetupDeps, @@ -91,6 +102,7 @@ export class notificationsDashboardsPlugin title: 'Channels', order: 9070, workspaceAvailability: WorkspaceAvailability.outsideWorkspace, + updater$: this.appStateUpdater, mount: async (params: AppMountParameters) => { return mountWrapper(params, ROUTES.CHANNELS); }, @@ -101,6 +113,7 @@ export class notificationsDashboardsPlugin title: 'Email senders', order: 9080, workspaceAvailability: WorkspaceAvailability.outsideWorkspace, + updater$: this.appStateUpdater, mount: async (params: AppMountParameters) => { return mountWrapper(params, ROUTES.EMAIL_SENDERS); }, @@ -111,11 +124,18 @@ export class notificationsDashboardsPlugin title: 'Email recepient groups', order: 9090, workspaceAvailability: WorkspaceAvailability.outsideWorkspace, + updater$: this.appStateUpdater, mount: async (params: AppMountParameters) => { return mountWrapper(params, ROUTES.EMAIL_GROUPS); }, }); + dataSourceObservable.subscribe((dataSourceOption) => { + if (dataSourceOption) { + this.appStateUpdater.next(this.updateDefaultRouteOfManagementApplications); + } + }); + const navlinks = [ { id: 'channels', parent: PLUGIN_NAME }, { id: 'email_senders', parent: PLUGIN_NAME }, @@ -132,7 +152,6 @@ export class notificationsDashboardsPlugin navLinks ); } - // Return methods that should be available to other plugins return {}; } diff --git a/public/utils/constants.ts b/public/utils/constants.ts index e934f4d6..b640822a 100644 --- a/public/utils/constants.ts +++ b/public/utils/constants.ts @@ -5,6 +5,9 @@ import { ChromeBreadcrumb } from 'opensearch-dashboards/public'; import { getBreadCrumbsSetter, getUseUpdatedUx } from '../services/utils/constants'; +import { DataSourceOption } from 'src/plugins/data_source_management/public'; +import { i18n } from "@osd/i18n"; +import { BehaviorSubject } from 'rxjs'; export const DOCUMENTATION_LINK = ''; export const ALERTING_DOCUMENTATION_LINK = @@ -72,3 +75,12 @@ export const CUSTOM_WEBHOOK_ENDPOINT_TYPE = Object.freeze({ export function setBreadcrumbs(crumbs: ChromeBreadcrumb[]) { getBreadCrumbsSetter()(getUseUpdatedUx() ? crumbs : [BREADCRUMBS.NOTIFICATIONS, ...crumbs]); } + +const LocalCluster: DataSourceOption = { + label: i18n.translate("dataSource.localCluster", { + defaultMessage: "Local cluster", + }), + id: "", +}; + +export const dataSourceObservable = new BehaviorSubject(LocalCluster);