diff --git a/src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx b/src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx index 7e75f27cac166..00b68c2abc547 100644 --- a/src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx +++ b/src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx @@ -31,11 +31,11 @@ import { } from './url/search_sessions_integration'; import { DashboardAPI, DashboardRenderer } from '..'; import { type DashboardEmbedSettings } from './types'; -import { DASHBOARD_APP_ID } from '../dashboard_constants'; import { pluginServices } from '../services/plugin_services'; import { AwaitingDashboardAPI } from '../dashboard_container'; import { DashboardRedirect } from '../dashboard_container/types'; import { useDashboardMountContext } from './hooks/dashboard_mount_context'; +import { createDashboardEditUrl, DASHBOARD_APP_ID } from '../dashboard_constants'; import { useDashboardOutcomeValidation } from './hooks/use_dashboard_outcome_validation'; import { loadDashboardHistoryLocationState } from './locator/load_dashboard_history_location_state'; import type { DashboardCreationOptions } from '../dashboard_container/embeddable/dashboard_container_factory'; @@ -160,6 +160,10 @@ export function DashboardApp({ getInitialInput, validateLoadedSavedObject: validateOutcome, isEmbeddedExternally: Boolean(embedSettings), // embed settings are only sent if the dashboard URL has `embed=true` + getEmbeddableAppContext: (dashboardId) => ({ + currentAppId: DASHBOARD_APP_ID, + getCurrentPath: () => `#${createDashboardEditUrl(dashboardId)}`, + }), }); }, [ history, diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_editing_toolbar.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_editing_toolbar.tsx index f7d2ed112f8c2..0190bbaefa00b 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_editing_toolbar.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_editing_toolbar.tsx @@ -69,8 +69,8 @@ export function DashboardEditingToolbar({ isDisabled }: { isDisabled?: boolean } stateTransferService.navigateToEditor(appId, { path, state: { - originatingApp: dashboard.getEmbeddableContainerContext()?.currentAppId, - originatingPath: dashboard.getEmbeddableContainerContext()?.getCurrentPath?.(), + originatingApp: dashboard.getAppContext()?.currentAppId, + originatingPath: dashboard.getAppContext()?.getCurrentPath?.(), searchSessionId: search.session.getSessionId(), }, }); diff --git a/src/plugins/dashboard/public/dashboard_container/component/empty_screen/dashboard_empty_screen.tsx b/src/plugins/dashboard/public/dashboard_container/component/empty_screen/dashboard_empty_screen.tsx index 4aa1e0616b23e..8767b5abe3567 100644 --- a/src/plugins/dashboard/public/dashboard_container/component/empty_screen/dashboard_empty_screen.tsx +++ b/src/plugins/dashboard/public/dashboard_container/component/empty_screen/dashboard_empty_screen.tsx @@ -48,9 +48,9 @@ export function DashboardEmptyScreen() { const isDarkTheme = useObservable(theme$)?.darkMode; const isEditMode = dashboardContainer.select((state) => state.explicitInput.viewMode) === ViewMode.EDIT; - const embeddableContainerContext = dashboardContainer.getEmbeddableContainerContext(); - const originatingPath = embeddableContainerContext?.getCurrentPath?.() ?? ''; - const originatingApp = embeddableContainerContext?.currentAppId; + const embeddableAppContext = dashboardContainer.getAppContext(); + const originatingPath = embeddableAppContext?.getCurrentPath?.() ?? ''; + const originatingApp = embeddableAppContext?.currentAppId; const goToLens = useCallback(() => { if (!lensAlias || !lensAlias.aliasPath) return; diff --git a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx index d6e9e97203348..f965ff3360aab 100644 --- a/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx +++ b/src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx @@ -111,7 +111,7 @@ export const Item = React.forwardRef( showNotifications={true} onPanelStatusChange={onPanelStatusChange} embeddable={() => container.untilEmbeddableLoaded(id)} - containerContext={container.getEmbeddableContainerContext()} + containerContext={container.getAppContext()} /> {children} diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx index 7768e4743fe61..32c43fddd8c41 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx @@ -184,13 +184,13 @@ export class DashboardContainer extends Container EmbeddableContainerContext; + getEmbeddableAppContext?: (dashboardId?: string) => EmbeddableAppContext; } export class DashboardContainerFactoryDefinition diff --git a/src/plugins/embeddable/public/embeddable_panel/embeddable_panel.tsx b/src/plugins/embeddable/public/embeddable_panel/embeddable_panel.tsx index 3d823c215498b..93279e311b065 100644 --- a/src/plugins/embeddable/public/embeddable_panel/embeddable_panel.tsx +++ b/src/plugins/embeddable/public/embeddable_panel/embeddable_panel.tsx @@ -49,14 +49,7 @@ const getEventStatus = (output: EmbeddableOutput): EmbeddablePhase => { }; export const EmbeddablePanel = (panelProps: UnwrappedEmbeddablePanelProps) => { - const { - hideHeader, - showShadow, - embeddable, - hideInspector, - containerContext, - onPanelStatusChange, - } = panelProps; + const { hideHeader, showShadow, embeddable, hideInspector, onPanelStatusChange } = panelProps; const [node, setNode] = useState(); const embeddableRoot: React.RefObject = useMemo(() => React.createRef(), []); @@ -74,8 +67,7 @@ export const EmbeddablePanel = (panelProps: UnwrappedEmbeddablePanelProps) => { const editPanel = new EditPanelAction( embeddableStart.getEmbeddableFactory, core.application, - stateTransfer, - containerContext?.getCurrentPath + stateTransfer ); const actions: PanelUniversalActions = { @@ -91,7 +83,7 @@ export const EmbeddablePanel = (panelProps: UnwrappedEmbeddablePanelProps) => { }; if (!hideInspector) actions.inspectPanel = new InspectPanelAction(inspector); return actions; - }, [containerContext?.getCurrentPath, hideInspector]); + }, [hideInspector]); /** * Track panel status changes diff --git a/src/plugins/embeddable/public/embeddable_panel/panel_actions/edit_panel_action/edit_panel_action.ts b/src/plugins/embeddable/public/embeddable_panel/panel_actions/edit_panel_action/edit_panel_action.ts index fe55b9a39158b..32e9fbac493aa 100644 --- a/src/plugins/embeddable/public/embeddable_panel/panel_actions/edit_panel_action/edit_panel_action.ts +++ b/src/plugins/embeddable/public/embeddable_panel/panel_actions/edit_panel_action/edit_panel_action.ts @@ -45,8 +45,7 @@ export class EditPanelAction implements Action { constructor( private readonly getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory'], private readonly application: ApplicationStart, - private readonly stateTransfer?: EmbeddableStateTransfer, - private readonly getOriginatingPath?: () => string + private readonly stateTransfer?: EmbeddableStateTransfer ) { if (this.application?.currentAppId$) { this.application.currentAppId$ @@ -139,7 +138,7 @@ export class EditPanelAction implements Action { if (app && path) { if (this.currentAppId) { - const originatingPath = this.getOriginatingPath?.(); + const originatingPath = embeddable.getAppContext()?.getCurrentPath?.(); const state: EmbeddableEditorState = { originatingApp: this.currentAppId, diff --git a/src/plugins/embeddable/public/embeddable_panel/types.ts b/src/plugins/embeddable/public/embeddable_panel/types.ts index ceb6916d6cd19..03e29810d4056 100644 --- a/src/plugins/embeddable/public/embeddable_panel/types.ts +++ b/src/plugins/embeddable/public/embeddable_panel/types.ts @@ -19,7 +19,7 @@ import { import { EmbeddableError } from '../lib/embeddables/i_embeddable'; import { EmbeddableContext, EmbeddableInput, EmbeddableOutput, IEmbeddable } from '..'; -export interface EmbeddableContainerContext { +export interface EmbeddableAppContext { /** * Current app's path including query and hash starting from {appId} */ @@ -54,7 +54,6 @@ export interface EmbeddablePanelProps { hideHeader?: boolean; hideInspector?: boolean; showNotifications?: boolean; - containerContext?: EmbeddableContainerContext; actionPredicate?: (actionId: string) => boolean; onPanelStatusChange?: (info: EmbeddablePhaseEvent) => void; getActions?: UiActionsService['getTriggerCompatibleActions']; diff --git a/src/plugins/embeddable/public/index.ts b/src/plugins/embeddable/public/index.ts index 0e3650ea8a8a4..ebe3b1a11af03 100644 --- a/src/plugins/embeddable/public/index.ts +++ b/src/plugins/embeddable/public/index.ts @@ -100,7 +100,7 @@ export { export type { EmbeddablePhase, EmbeddablePhaseEvent, - EmbeddableContainerContext, + EmbeddableAppContext, } from './embeddable_panel/types'; export { AttributeService, ATTRIBUTE_SERVICE_KEY } from './lib/attribute_service'; diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx b/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx index d145bfb3c1ae0..ac1c8462b5bf3 100644 --- a/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx +++ b/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx @@ -17,6 +17,7 @@ import { IContainer } from '../containers'; import { EmbeddableError, EmbeddableOutput, IEmbeddable } from './i_embeddable'; import { EmbeddableInput, ViewMode } from '../../../common/types'; import { genericEmbeddableInputIsEqual, omitGenericEmbeddableInput } from './diff_embeddable_input'; +import { EmbeddableAppContext } from '../../embeddable_panel/types'; function getPanelTitle(input: EmbeddableInput, output: EmbeddableOutput) { if (input.hidePanelTitles) return ''; @@ -102,6 +103,10 @@ export abstract class Embeddable< .subscribe((title) => this.renderComplete.setTitle(title)); } + public getAppContext(): EmbeddableAppContext | undefined { + return this.parent?.getAppContext(); + } + public reportsEmbeddableLoad() { return false; } diff --git a/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts b/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts index f371208271623..92d0309688e76 100644 --- a/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts +++ b/src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts @@ -11,6 +11,7 @@ import { ErrorLike } from '@kbn/expressions-plugin/common'; import { Adapters } from '../types'; import { IContainer } from '../containers/i_container'; import { EmbeddableInput } from '../../../common/types'; +import { EmbeddableAppContext } from '../../embeddable_panel/types'; export type EmbeddableError = ErrorLike; export type { EmbeddableInput }; @@ -181,6 +182,11 @@ export interface IEmbeddable< */ getRoot(): IEmbeddable | IContainer; + /** + * Returns the context of this embeddable's container, or undefined. + */ + getAppContext(): EmbeddableAppContext | undefined; + /** * Renders the embeddable at the given node. * @param domNode diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx index 51c6cdc54131d..ec602510fd9f0 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.tsx @@ -17,13 +17,13 @@ import { isErrorEmbeddable, EmbeddablePanel, } from '@kbn/embeddable-plugin/public'; -import type { EmbeddableContainerContext } from '@kbn/embeddable-plugin/public'; +import type { EmbeddableAppContext } from '@kbn/embeddable-plugin/public'; import { StartDeps } from '../../plugin'; import { EmbeddableExpression } from '../../expression_types/embeddable'; import { RendererStrings } from '../../../i18n'; import { embeddableInputToExpression } from './embeddable_input_to_expression'; import { RendererFactory, EmbeddableInput } from '../../../types'; -import { CANVAS_EMBEDDABLE_CLASSNAME } from '../../../common/lib'; +import { CANVAS_APP, CANVAS_EMBEDDABLE_CLASSNAME } from '../../../common/lib'; const { embeddable: strings } = RendererStrings; @@ -41,18 +41,19 @@ const renderEmbeddableFactory = (core: CoreStart, plugins: StartDeps) => { return null; } - const embeddableContainerContext: EmbeddableContainerContext = { + const canvasAppContext: EmbeddableAppContext = { getCurrentPath: () => { const urlToApp = core.application.getUrlForApp(currentAppId); const inAppPath = window.location.pathname.replace(urlToApp, ''); return inAppPath + window.location.search + window.location.hash; }, + currentAppId: CANVAS_APP, }; - return ( - - ); + embeddable.getAppContext = () => canvasAppContext; + + return ; }; return (embeddableObject: IEmbeddable) => { diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.tsx index 0150d922c481f..45a6bbc95e8c4 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable.tsx @@ -136,6 +136,7 @@ import type { LensPluginStartDependencies } from '../plugin'; import { EmbeddableFeatureBadge } from './embeddable_info_badges'; import { getDatasourceLayers } from '../state_management/utils'; import type { EditLensConfigurationProps } from '../app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration'; +import type { DashboardContainer } from '@kbn/dashboard-plugin/public/dashboard_container'; export type LensSavedObjectAttributes = Omit; @@ -794,18 +795,14 @@ export class Embeddable * Used for the Edit in Lens link inside the inline editing flyout. */ private async navigateToLensEditor() { - const executionContext = this.getExecutionContext(); + const appContext = this.getAppContext(); /** * The origininating app variable is very important for the Save and Return button * of the editor to work properly. - * The best way to get it dynamically is from the execution context but for the dashboard - * it needs to be pluralized */ const transferState = { - originatingApp: - executionContext?.type === 'dashboard' - ? 'dashboards' - : executionContext?.type ?? 'dashboards', + originatingApp: appContext?.currentAppId ?? 'dashboards', + originatingPath: appContext?.getCurrentPath?.(), valueInput: this.getExplicitInput(), embeddableId: this.id, searchSessionId: this.getInput().searchSessionId, @@ -818,6 +815,7 @@ export class Embeddable await transfer.navigateToEditor(APP_ID, { path: this.output.editPath, state: transferState, + skipAppLeave: true, }); } } diff --git a/x-pack/plugins/security_solution/public/dashboards/components/dashboard_renderer.tsx b/x-pack/plugins/security_solution/public/dashboards/components/dashboard_renderer.tsx index 74391c95fae25..7fd8f52e52e87 100644 --- a/x-pack/plugins/security_solution/public/dashboards/components/dashboard_renderer.tsx +++ b/x-pack/plugins/security_solution/public/dashboards/components/dashboard_renderer.tsx @@ -67,7 +67,7 @@ const DashboardRendererComponent = ({ }), getIncomingEmbeddable: () => embeddable.getStateTransfer().getIncomingEmbeddablePackage(APP_UI_ID, true), - getEmbeddableContainerContext: (dashboardId?: string) => ({ + getEmbeddableAppContext: (dashboardId?: string) => ({ getCurrentPath: () => dashboardId ? `${DASHBOARDS_PATH}/${dashboardId}/edit` : `${DASHBOARDS_PATH}/create`, currentAppId: APP_UI_ID,