Skip to content

Commit

Permalink
Merge pull request #4 from ThomThomson/security/edit-mode/appContext
Browse files Browse the repository at this point in the history
Add App Context to security dashboard edit mode
  • Loading branch information
angorayc committed Sep 29, 2023
2 parents 237a1aa + 528600a commit 3b863c1
Show file tree
Hide file tree
Showing 15 changed files with 48 additions and 44 deletions.
6 changes: 5 additions & 1 deletion src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export const Item = React.forwardRef<HTMLDivElement, Props>(
showNotifications={true}
onPanelStatusChange={onPanelStatusChange}
embeddable={() => container.untilEmbeddableLoaded(id)}
containerContext={container.getEmbeddableContainerContext()}
containerContext={container.getAppContext()}
/>
{children}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,13 @@ export class DashboardContainer extends Container<InheritedChildInput, Dashboard
this.select = reduxTools.select;
}

public getEmbeddableContainerContext() {
const embeddableContainerContext = this.creationOptions?.getEmbeddableContainerContext?.(
public getAppContext() {
const embeddableAppContext = this.creationOptions?.getEmbeddableAppContext?.(
this.getDashboardSavedObjectId()
);
return {
...embeddableContainerContext,
currentAppId: embeddableContainerContext?.currentAppId ?? DASHBOARD_APP_ID,
...embeddableAppContext,
currentAppId: embeddableAppContext?.currentAppId ?? DASHBOARD_APP_ID,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
EmbeddableFactory,
EmbeddableFactoryDefinition,
EmbeddablePackageState,
EmbeddableContainerContext,
EmbeddableAppContext,
} from '@kbn/embeddable-plugin/public';
import { SearchSessionInfoProvider } from '@kbn/data-plugin/public';
import { IKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public';
Expand Down Expand Up @@ -60,7 +60,7 @@ export interface DashboardCreationOptions {

isEmbeddedExternally?: boolean;

getEmbeddableContainerContext?: (dashboardId?: string) => EmbeddableContainerContext;
getEmbeddableAppContext?: (dashboardId?: string) => EmbeddableAppContext;
}

export class DashboardContainerFactoryDefinition
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<ReactNode | undefined>();
const embeddableRoot: React.RefObject<HTMLDivElement> = useMemo(() => React.createRef(), []);

Expand All @@ -74,8 +67,7 @@ export const EmbeddablePanel = (panelProps: UnwrappedEmbeddablePanelProps) => {
const editPanel = new EditPanelAction(
embeddableStart.getEmbeddableFactory,
core.application,
stateTransfer,
containerContext?.getCurrentPath
stateTransfer
);

const actions: PanelUniversalActions = {
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ export class EditPanelAction implements Action<ActionContext> {
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$
Expand Down Expand Up @@ -139,7 +138,7 @@ export class EditPanelAction implements Action<ActionContext> {

if (app && path) {
if (this.currentAppId) {
const originatingPath = this.getOriginatingPath?.();
const originatingPath = embeddable.getAppContext()?.getCurrentPath?.();

const state: EmbeddableEditorState = {
originatingApp: this.currentAppId,
Expand Down
3 changes: 1 addition & 2 deletions src/plugins/embeddable/public/embeddable_panel/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}
*/
Expand Down Expand Up @@ -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'];
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/embeddable/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export {
export type {
EmbeddablePhase,
EmbeddablePhaseEvent,
EmbeddableContainerContext,
EmbeddableAppContext,
} from './embeddable_panel/types';

export { AttributeService, ATTRIBUTE_SERVICE_KEY } from './lib/attribute_service';
Expand Down
5 changes: 5 additions & 0 deletions src/plugins/embeddable/public/lib/embeddables/embeddable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 '';
Expand Down Expand Up @@ -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;
}
Expand Down
6 changes: 6 additions & 0 deletions src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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 (
<EmbeddablePanel embeddable={embeddable} containerContext={embeddableContainerContext} />
);
embeddable.getAppContext = () => canvasAppContext;

return <EmbeddablePanel embeddable={embeddable} />;
};

return (embeddableObject: IEmbeddable) => {
Expand Down
12 changes: 5 additions & 7 deletions x-pack/plugins/lens/public/embeddable/embeddable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<Document, 'savedObjectId' | 'type'>;

Expand Down Expand Up @@ -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,
Expand All @@ -818,6 +815,7 @@ export class Embeddable
await transfer.navigateToEditor(APP_ID, {
path: this.output.editPath,
state: transferState,
skipAppLeave: true,
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 3b863c1

Please sign in to comment.