Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[7.x] prep state transfer for passing embeddables by value to editor and back (#69991) #70073

Merged
merged 1 commit into from
Jun 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import {
ViewMode,
SavedObjectEmbeddableInput,
ContainerOutput,
EmbeddableInput,
} from '../../../embeddable/public';
import { NavAction, SavedDashboardPanel } from '../types';

Expand Down Expand Up @@ -430,9 +431,16 @@ export class DashboardAppController {
.getStateTransfer(scopedHistory())
.getIncomingEmbeddablePackage();
if (incomingState) {
container.addNewEmbeddable<SavedObjectEmbeddableInput>(incomingState.type, {
savedObjectId: incomingState.id,
});
if ('id' in incomingState) {
container.addNewEmbeddable<SavedObjectEmbeddableInput>(incomingState.type, {
savedObjectId: incomingState.id,
});
} else if ('input' in incomingState) {
container.addNewEmbeddable<EmbeddableInput>(
incomingState.type,
incomingState.input
);
}
}
}

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 @@ -69,7 +69,7 @@ export {
isRangeSelectTriggerContext,
isValueClickTriggerContext,
EmbeddableStateTransfer,
EmbeddableOriginatingAppState,
EmbeddableEditorState,
EmbeddablePackageState,
EmbeddableRenderer,
EmbeddableRendererProps,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ test('redirects to app using state transfer', async () => {
const embeddable = new EditableEmbeddable({ id: '123', viewMode: ViewMode.EDIT }, true);
embeddable.getOutput = jest.fn(() => ({ editApp: 'ultraVisualize', editPath: '/123' }));
await action.execute({ embeddable });
expect(stateTransferMock.navigateToWithOriginatingApp).toHaveBeenCalledWith('ultraVisualize', {
expect(stateTransferMock.navigateToEditor).toHaveBeenCalledWith('ultraVisualize', {
path: '/123',
state: { originatingApp: 'superCoolCurrentApp' },
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { take } from 'rxjs/operators';
import { ViewMode } from '../types';
import { EmbeddableFactoryNotFoundError } from '../errors';
import { EmbeddableStart } from '../../plugin';
import { IEmbeddable, EmbeddableOriginatingAppState, EmbeddableStateTransfer } from '../..';
import { IEmbeddable, EmbeddableEditorState, EmbeddableStateTransfer } from '../..';

export const ACTION_EDIT_PANEL = 'editPanel';

Expand All @@ -35,7 +35,7 @@ interface ActionContext {
interface NavigationContext {
app: string;
path: string;
state?: EmbeddableOriginatingAppState;
state?: EmbeddableEditorState;
}

export class EditPanelAction implements Action<ActionContext> {
Expand Down Expand Up @@ -88,7 +88,7 @@ export class EditPanelAction implements Action<ActionContext> {
const appTarget = this.getAppTarget(context);
if (appTarget) {
if (this.stateTransfer && appTarget.state) {
await this.stateTransfer.navigateToWithOriginatingApp(appTarget.app, {
await this.stateTransfer.navigateToEditor(appTarget.app, {
path: appTarget.path,
state: appTarget.state,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('embeddable state transfer', () => {
});

it('can send an outgoing originating app state', async () => {
await stateTransfer.navigateToWithOriginatingApp(destinationApp, { state: { originatingApp } });
await stateTransfer.navigateToEditor(destinationApp, { state: { originatingApp } });
expect(application.navigateToApp).toHaveBeenCalledWith('superUltraVisualize', {
state: { originatingApp: 'superUltraTestDashboard' },
});
Expand All @@ -50,7 +50,7 @@ describe('embeddable state transfer', () => {
application.navigateToApp,
(historyMock as unknown) as ScopedHistory
);
await stateTransfer.navigateToWithOriginatingApp(destinationApp, {
await stateTransfer.navigateToEditor(destinationApp, {
state: { originatingApp },
appendToExistingState: true,
});
Expand Down Expand Up @@ -94,7 +94,7 @@ describe('embeddable state transfer', () => {
application.navigateToApp,
(historyMock as unknown) as ScopedHistory
);
const fetchedState = stateTransfer.getIncomingOriginatingApp();
const fetchedState = stateTransfer.getIncomingEditorState();
expect(fetchedState).toEqual({ originatingApp: 'extremeSportsKibana' });
});

Expand All @@ -104,7 +104,7 @@ describe('embeddable state transfer', () => {
application.navigateToApp,
(historyMock as unknown) as ScopedHistory
);
const fetchedState = stateTransfer.getIncomingOriginatingApp();
const fetchedState = stateTransfer.getIncomingEditorState();
expect(fetchedState).toBeUndefined();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
import { cloneDeep } from 'lodash';
import { ScopedHistory, ApplicationStart } from '../../../../../core/public';
import {
EmbeddableOriginatingAppState,
isEmbeddableOriginatingAppState,
EmbeddableEditorState,
isEmbeddableEditorState,
EmbeddablePackageState,
isEmbeddablePackageState,
} from './types';
Expand All @@ -39,16 +39,16 @@ export class EmbeddableStateTransfer {
) {}

/**
* Fetches an {@link EmbeddableOriginatingAppState | originating app} argument from the scoped
* Fetches an {@link EmbeddableEditorState | originating app} argument from the scoped
* history's location state.
*
* @param history - the scoped history to fetch from
* @param options.keysToRemoveAfterFetch - an array of keys to be removed from the state after they are retrieved
*/
public getIncomingOriginatingApp(options?: {
public getIncomingEditorState(options?: {
keysToRemoveAfterFetch?: string[];
}): EmbeddableOriginatingAppState | undefined {
return this.getIncomingState<EmbeddableOriginatingAppState>(isEmbeddableOriginatingAppState, {
}): EmbeddableEditorState | undefined {
return this.getIncomingState<EmbeddableEditorState>(isEmbeddableEditorState, {
keysToRemoveAfterFetch: options?.keysToRemoveAfterFetch,
});
}
Expand All @@ -70,17 +70,17 @@ export class EmbeddableStateTransfer {

/**
* A wrapper around the {@link ApplicationStart.navigateToApp} method which navigates to the specified appId
* with {@link EmbeddableOriginatingAppState | originating app state}
* with {@link EmbeddableEditorState | embeddable editor state}
*/
public async navigateToWithOriginatingApp(
public async navigateToEditor(
appId: string,
options?: {
path?: string;
state: EmbeddableOriginatingAppState;
state: EmbeddableEditorState;
appendToExistingState?: boolean;
}
): Promise<void> {
await this.navigateToWithState<EmbeddableOriginatingAppState>(appId, options);
await this.navigateToWithState<EmbeddableEditorState>(appId, options);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/embeddable/public/lib/state_transfer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@
*/

export { EmbeddableStateTransfer } from './embeddable_state_transfer';
export { EmbeddableOriginatingAppState, EmbeddablePackageState } from './types';
export { EmbeddableEditorState, EmbeddablePackageState } from './types';
32 changes: 24 additions & 8 deletions src/plugins/embeddable/public/lib/state_transfer/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,49 @@
* under the License.
*/

import { EmbeddableInput } from '..';

/**
* Represents a state package that contains the last active app id.
* @public
*/
export interface EmbeddableOriginatingAppState {
export interface EmbeddableEditorState {
originatingApp: string;
byValueMode?: boolean;
valueInput?: EmbeddableInput;
}

export function isEmbeddableOriginatingAppState(
state: unknown
): state is EmbeddableOriginatingAppState {
export function isEmbeddableEditorState(state: unknown): state is EmbeddableEditorState {
return ensureFieldOfTypeExists('originatingApp', state, 'string');
}

/**
* Represents a state package that contains all fields necessary to create an embeddable in a container.
* Represents a state package that contains all fields necessary to create an embeddable by reference in a container.
* @public
*/
export interface EmbeddablePackageState {
export interface EmbeddablePackageByReferenceState {
type: string;
id: string;
}

/**
* Represents a state package that contains all fields necessary to create an embeddable by value in a container.
* @public
*/
export interface EmbeddablePackageByValueState {
type: string;
input: EmbeddableInput;
}

export type EmbeddablePackageState =
| EmbeddablePackageByReferenceState
| EmbeddablePackageByValueState;

export function isEmbeddablePackageState(state: unknown): state is EmbeddablePackageState {
return (
ensureFieldOfTypeExists('type', state, 'string') &&
ensureFieldOfTypeExists('id', state, 'string')
(ensureFieldOfTypeExists('type', state, 'string') &&
ensureFieldOfTypeExists('id', state, 'string')) ||
ensureFieldOfTypeExists('input', state, 'object')
);
}

Expand Down
4 changes: 2 additions & 2 deletions src/plugins/embeddable/public/mocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ export const createEmbeddablePanelMock = ({

export const createEmbeddableStateTransferMock = (): Partial<EmbeddableStateTransfer> => {
return {
getIncomingOriginatingApp: jest.fn(),
getIncomingEditorState: jest.fn(),
getIncomingEmbeddablePackage: jest.fn(),
navigateToWithOriginatingApp: jest.fn(),
navigateToEditor: jest.fn(),
navigateToWithEmbeddablePackage: jest.fn(),
};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ describe('NewVisModal', () => {
);
const visButton = wrapper.find('button[data-test-subj="visType-visWithAliasUrl"]');
visButton.simulate('click');
expect(stateTransfer.navigateToWithOriginatingApp).toBeCalledWith('otherApp', {
expect(stateTransfer.navigateToEditor).toBeCalledWith('otherApp', {
path: '#/aliasUrl',
state: { originatingApp: 'coolJestTestApp' },
});
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/visualizations/public/wizard/new_vis_modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ class NewVisModal extends React.Component<TypeSelectionProps, TypeSelectionState

private navigate(appId: string, params: string) {
if (this.props.stateTransfer && this.props.originatingApp) {
this.props.stateTransfer.navigateToWithOriginatingApp(appId, {
this.props.stateTransfer.navigateToEditor(appId, {
path: params,
state: { originatingApp: this.props.originatingApp },
});
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/visualize/public/application/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ function VisualizeAppController($scope, $route, $injector, $timeout, kbnUrlState
};

const { originatingApp } =
embeddable.getStateTransfer(scopedHistory()).getIncomingOriginatingApp() || {};
embeddable.getStateTransfer(scopedHistory()).getIncomingEditorState() || {};
$scope.getOriginatingApp = () => originatingApp;

const visStateToEditorState = () => {
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/lens/public/app_plugin/mounter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export async function mountApp(

const stateTransfer = embeddable?.getStateTransfer(params.history);
const { originatingApp } =
stateTransfer?.getIncomingOriginatingApp({ keysToRemoveAfterFetch: ['originatingApp'] }) || {};
stateTransfer?.getIncomingEditorState({ keysToRemoveAfterFetch: ['originatingApp'] }) || {};

const instance = await createEditorFrame();

Expand Down