Skip to content

Commit b941472

Browse files
Maja Grubicelasticmachine
andcommitted
[Visualize] First version of by-value visualize editor (#72256)
* First version of new by-value editor Fixing broken behavior and applying relevant changes Adding changes to dashboard Removing unnecessary empty line Removing unnecessary deepClone Fixing some stuff in dashboard container Extracting logic into common components Fixing eslint Fix breadcrumbs Fixing error in search interceptor Reintroduce mistakenly removed empty lines Renaming function * Adding missing null check * Making typescript play nicely * Fixing failing tests * Applying PR comments * Fixing eslint errors * Fix save as behavior * Fixing HTMLElement type * Passing in setOriginatingApp parameter * Redirect back to dashboard if input is missing * Fixing i18n error * Unlink saved search * Fix duplicating embeddable by reference Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
1 parent 855b06c commit b941472

28 files changed

Lines changed: 656 additions & 196 deletions

src/plugins/dashboard/public/application/dashboard_app_controller.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,9 +468,14 @@ export class DashboardAppController {
468468
const explicitInput = {
469469
savedVis: input,
470470
};
471+
const embeddableId =
472+
'embeddableId' in incomingEmbeddable
473+
? incomingEmbeddable.embeddableId
474+
: undefined;
471475
container.addOrUpdateEmbeddable<EmbeddableInput>(
472476
incomingEmbeddable.type,
473-
explicitInput
477+
explicitInput,
478+
embeddableId
474479
);
475480
}
476481
}

src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ export class DashboardContainer extends Container<InheritedChildInput, Dashboard
171171
// TODO: In the current infrastructure, embeddables in a container do not react properly to
172172
// changes. Removing the existing embeddable, and adding a new one is a temporary workaround
173173
// until the container logic is fixed.
174+
174175
const finalPanels = { ...this.input.panels };
175176
delete finalPanels[previousPanelState.explicitInput.id];
176177
const newPanelId = newPanelState.explicitInput?.id ? newPanelState.explicitInput.id : uuid.v4();
@@ -196,9 +197,10 @@ export class DashboardContainer extends Container<InheritedChildInput, Dashboard
196197
EEI extends EmbeddableInput = EmbeddableInput,
197198
EEO extends EmbeddableOutput = EmbeddableOutput,
198199
E extends IEmbeddable<EEI, EEO> = IEmbeddable<EEI, EEO>
199-
>(type: string, explicitInput: Partial<EEI>) {
200-
if (explicitInput.id && this.input.panels[explicitInput.id]) {
201-
this.replacePanel(this.input.panels[explicitInput.id], {
200+
>(type: string, explicitInput: Partial<EEI>, embeddableId?: string) {
201+
const idToReplace = embeddableId || explicitInput.id;
202+
if (idToReplace && this.input.panels[idToReplace]) {
203+
this.replacePanel(this.input.panels[idToReplace], {
202204
type,
203205
explicitInput: {
204206
...explicitInput,

src/plugins/embeddable/public/lib/actions/edit_panel_action.test.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,18 @@ test('is compatible when edit url is available, in edit mode and editable', asyn
5656
test('redirects to app using state transfer', async () => {
5757
applicationMock.currentAppId$ = of('superCoolCurrentApp');
5858
const action = new EditPanelAction(getFactory, applicationMock, stateTransferMock);
59-
const embeddable = new EditableEmbeddable({ id: '123', viewMode: ViewMode.EDIT }, true);
59+
const input = { id: '123', viewMode: ViewMode.EDIT };
60+
const embeddable = new EditableEmbeddable(input, true);
6061
embeddable.getOutput = jest.fn(() => ({ editApp: 'ultraVisualize', editPath: '/123' }));
6162
await action.execute({ embeddable });
6263
expect(stateTransferMock.navigateToEditor).toHaveBeenCalledWith('ultraVisualize', {
6364
path: '/123',
64-
state: { originatingApp: 'superCoolCurrentApp' },
65+
state: {
66+
originatingApp: 'superCoolCurrentApp',
67+
byValueMode: true,
68+
embeddableId: '123',
69+
valueInput: input,
70+
},
6571
});
6672
});
6773

src/plugins/embeddable/public/lib/actions/edit_panel_action.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ import { take } from 'rxjs/operators';
2424
import { ViewMode } from '../types';
2525
import { EmbeddableFactoryNotFoundError } from '../errors';
2626
import { EmbeddableStart } from '../../plugin';
27-
import { IEmbeddable, EmbeddableEditorState, EmbeddableStateTransfer } from '../..';
27+
import {
28+
IEmbeddable,
29+
EmbeddableEditorState,
30+
EmbeddableStateTransfer,
31+
SavedObjectEmbeddableInput,
32+
} from '../..';
2833

2934
export const ACTION_EDIT_PANEL = 'editPanel';
3035

@@ -109,8 +114,17 @@ export class EditPanelAction implements Action<ActionContext> {
109114
const app = embeddable ? embeddable.getOutput().editApp : undefined;
110115
const path = embeddable ? embeddable.getOutput().editPath : undefined;
111116
if (app && path) {
112-
const state = this.currentAppId ? { originatingApp: this.currentAppId } : undefined;
113-
return { app, path, state };
117+
if (this.currentAppId) {
118+
const byValueMode = !(embeddable.getInput() as SavedObjectEmbeddableInput).savedObjectId;
119+
const state: EmbeddableEditorState = {
120+
originatingApp: this.currentAppId,
121+
byValueMode,
122+
valueInput: byValueMode ? embeddable.getInput() : undefined,
123+
embeddableId: embeddable.id,
124+
};
125+
return { app, path, state };
126+
}
127+
return { app, path };
114128
}
115129
}
116130

src/plugins/embeddable/public/lib/state_transfer/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export interface EmbeddableEditorState {
2727
originatingApp: string;
2828
byValueMode?: boolean;
2929
valueInput?: EmbeddableInput;
30+
embeddableId?: string;
3031
}
3132

3233
export function isEmbeddableEditorState(state: unknown): state is EmbeddableEditorState {
@@ -49,6 +50,7 @@ export interface EmbeddablePackageByReferenceState {
4950
export interface EmbeddablePackageByValueState {
5051
type: string;
5152
input: EmbeddableInput;
53+
embeddableId?: string;
5254
}
5355

5456
export type EmbeddablePackageState =

src/plugins/navigation/public/top_nav_menu/top_nav_menu_item.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export function TopNavMenuItem(props: TopNavMenuData) {
4646
iconType: props.iconType,
4747
iconSide: props.iconSide,
4848
'data-test-subj': props.testId,
49+
className: props.className,
4950
};
5051

5152
const btn = props.emphasize ? (

src/plugins/vis_default_editor/public/default_editor_controller.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ class DefaultEditorController {
6969
]
7070
: visType.editorConfig.optionTabs),
7171
];
72-
7372
this.state = {
7473
vis,
7574
optionTabs,

src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ export const createVisEmbeddableFromObject = (deps: VisualizeEmbeddableFactoryDe
4141
try {
4242
const visId = vis.id as string;
4343

44-
const editPath = visId ? savedVisualizations.urlFor(visId) : '';
44+
const editPath = visId ? savedVisualizations.urlFor(visId) : '#/edit_by_value';
45+
4546
const editUrl = visId
4647
? getHttp().basePath.prepend(`/app/visualize${savedVisualizations.urlFor(visId)}`)
4748
: '';

src/plugins/visualize/public/application/app.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ import { Route, Switch, useLocation } from 'react-router-dom';
2424
import { syncQueryStateWithUrl } from '../../../data/public';
2525
import { useKibana } from '../../../kibana_react/public';
2626
import { VisualizeServices } from './types';
27-
import { VisualizeEditor, VisualizeListing, VisualizeNoMatch } from './components';
27+
import {
28+
VisualizeEditor,
29+
VisualizeListing,
30+
VisualizeNoMatch,
31+
VisualizeByValueEditor,
32+
} from './components';
2833
import { VisualizeConstants } from './visualize_constants';
2934

3035
export const VisualizeApp = () => {
@@ -48,6 +53,9 @@ export const VisualizeApp = () => {
4853

4954
return (
5055
<Switch>
56+
<Route exact path={`${VisualizeConstants.EDIT_BY_VALUE_PATH}`}>
57+
<VisualizeByValueEditor />
58+
</Route>
5159
<Route path={[VisualizeConstants.CREATE_PATH, `${VisualizeConstants.EDIT_PATH}/:id`]}>
5260
<VisualizeEditor />
5361
</Route>

src/plugins/visualize/public/application/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@
2020
export { VisualizeListing } from './visualize_listing';
2121
export { VisualizeEditor } from './visualize_editor';
2222
export { VisualizeNoMatch } from './visualize_no_match';
23+
export { VisualizeByValueEditor } from './visualize_byvalue_editor';

0 commit comments

Comments
 (0)