Skip to content

Commit a9a923d

Browse files
[Maps] Switch to SavedObjectClient.resolve (#112606)
* [Maps] Switch to SavedObjectClient.resolve * spaces tslint * aliasMatch * maps eslint * update lens to use spaces.ui.components.getSavedObjectConflictMessage * lens eslint * spaces eslint * review feedback Co-authored-by: Kibana Machine <[email protected]>
1 parent 31515e9 commit a9a923d

File tree

23 files changed

+243
-95
lines changed

23 files changed

+243
-95
lines changed

x-pack/plugins/lens/public/embeddable/embeddable.tsx

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import { isEqual, uniqBy } from 'lodash';
99
import React from 'react';
10+
import { i18n } from '@kbn/i18n';
1011
import { render, unmountComponentAtNode } from 'react-dom';
1112
import type {
1213
ExecutionContextSearch,
@@ -41,11 +42,7 @@ import {
4142
ReferenceOrValueEmbeddable,
4243
} from '../../../../../src/plugins/embeddable/public';
4344
import { Document, injectFilterReferences } from '../persistence';
44-
import {
45-
ExpressionWrapper,
46-
ExpressionWrapperProps,
47-
savedObjectConflictError,
48-
} from './expression_wrapper';
45+
import { ExpressionWrapper, ExpressionWrapperProps } from './expression_wrapper';
4946
import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public';
5047
import {
5148
isLensBrushEvent,
@@ -63,6 +60,7 @@ import { LensAttributeService } from '../lens_attribute_service';
6360
import type { ErrorMessage } from '../editor_frame_service/types';
6461
import { getLensInspectorService, LensInspector } from '../lens_inspector_service';
6562
import { SharingSavedObjectProps } from '../types';
63+
import type { SpacesPluginStart } from '../../../spaces/public';
6664

6765
export type LensSavedObjectAttributes = Omit<Document, 'savedObjectId' | 'type'>;
6866
export interface ResolvedLensSavedObjectAttributes extends LensSavedObjectAttributes {
@@ -108,6 +106,7 @@ export interface LensEmbeddableDeps {
108106
getTriggerCompatibleActions?: UiActionsStart['getTriggerCompatibleActions'];
109107
capabilities: { canSaveVisualizations: boolean; canSaveDashboards: boolean };
110108
usageCollection?: UsageCollectionSetup;
109+
spaces?: SpacesPluginStart;
111110
}
112111

113112
export class Embeddable
@@ -281,8 +280,17 @@ export class Embeddable
281280
};
282281
const { ast, errors } = await this.deps.documentToExpression(this.savedVis);
283282
this.errors = errors;
284-
if (sharingSavedObjectProps?.outcome === 'conflict') {
285-
const conflictError = savedObjectConflictError(sharingSavedObjectProps.errorJSON!);
283+
if (sharingSavedObjectProps?.outcome === 'conflict' && this.deps.spaces) {
284+
const conflictError = {
285+
shortMessage: i18n.translate('xpack.lens.embeddable.legacyURLConflict.shortMessage', {
286+
defaultMessage: `You've encountered a URL conflict`,
287+
}),
288+
longMessage: (
289+
<this.deps.spaces.ui.components.getSavedObjectConflictMessage
290+
json={sharingSavedObjectProps.errorJSON!}
291+
/>
292+
),
293+
};
286294
this.errors = this.errors ? [...this.errors, conflictError] : [conflictError];
287295
}
288296
this.expression = ast ? toExpression(ast) : null;

x-pack/plugins/lens/public/embeddable/embeddable_factory.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { LensAttributeService } from '../lens_attribute_service';
2424
import { DOC_TYPE } from '../../common/constants';
2525
import { ErrorMessage } from '../editor_frame_service/types';
2626
import { extract, inject } from '../../common/embeddable_factory';
27+
import type { SpacesPluginStart } from '../../../spaces/public';
2728

2829
export interface LensEmbeddableStartServices {
2930
timefilter: TimefilterContract;
@@ -38,6 +39,7 @@ export interface LensEmbeddableStartServices {
3839
documentToExpression: (
3940
doc: Document
4041
) => Promise<{ ast: Ast | null; errors: ErrorMessage[] | undefined }>;
42+
spaces?: SpacesPluginStart;
4143
}
4244

4345
export class EmbeddableFactory implements EmbeddableFactoryDefinition {
@@ -90,6 +92,7 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition {
9092
capabilities,
9193
usageCollection,
9294
inspector,
95+
spaces,
9396
} = await this.getStartServices();
9497

9598
const { Embeddable } = await import('../async_services');
@@ -110,6 +113,7 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition {
110113
canSaveVisualizations: Boolean(capabilities.visualize.save),
111114
},
112115
usageCollection,
116+
spaces,
113117
},
114118
input,
115119
parent

x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx

Lines changed: 2 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,10 @@
55
* 2.0.
66
*/
77

8-
import React, { useState } from 'react';
8+
import React from 'react';
99
import { I18nProvider } from '@kbn/i18n/react';
1010
import { FormattedMessage } from '@kbn/i18n/react';
11-
import {
12-
EuiFlexGroup,
13-
EuiFlexItem,
14-
EuiText,
15-
EuiIcon,
16-
EuiEmptyPrompt,
17-
EuiButtonEmpty,
18-
EuiCallOut,
19-
EuiSpacer,
20-
EuiLink,
21-
} from '@elastic/eui';
11+
import { EuiFlexGroup, EuiFlexItem, EuiText, EuiIcon, EuiEmptyPrompt } from '@elastic/eui';
2212
import {
2313
ExpressionRendererEvent,
2414
ReactExpressionRendererType,
@@ -28,7 +18,6 @@ import type { KibanaExecutionContext } from 'src/core/public';
2818
import { ExecutionContextSearch } from 'src/plugins/data/public';
2919
import { DefaultInspectorAdapters, RenderMode } from 'src/plugins/expressions';
3020
import classNames from 'classnames';
31-
import { i18n } from '@kbn/i18n';
3221
import { getOriginalRequestErrorMessages } from '../editor_frame_service/error_helper';
3322
import { ErrorMessage } from '../editor_frame_service/types';
3423
import { LensInspector } from '../lens_inspector_service';
@@ -172,52 +161,3 @@ export function ExpressionWrapper({
172161
</I18nProvider>
173162
);
174163
}
175-
176-
const SavedObjectConflictMessage = ({ json }: { json: string }) => {
177-
const [expandError, setExpandError] = useState(false);
178-
return (
179-
<>
180-
<FormattedMessage
181-
id="xpack.lens.embeddable.legacyURLConflict.longMessage"
182-
defaultMessage="Disable the {documentationLink} associated with this object."
183-
values={{
184-
documentationLink: (
185-
<EuiLink
186-
external
187-
href="https://www.elastic.co/guide/en/kibana/master/legacy-url-aliases.html"
188-
target="_blank"
189-
>
190-
{i18n.translate('xpack.lens.embeddable.legacyURLConflict.documentationLinkText', {
191-
defaultMessage: 'legacy URL alias',
192-
})}
193-
</EuiLink>
194-
),
195-
}}
196-
/>
197-
<EuiSpacer />
198-
{expandError ? (
199-
<EuiCallOut
200-
title={i18n.translate('xpack.lens.embeddable.legacyURLConflict.expandErrorText', {
201-
defaultMessage: `This object has the same URL as a legacy alias. Disable the alias to resolve this error : {json}`,
202-
values: { json },
203-
})}
204-
color="danger"
205-
iconType="alert"
206-
/>
207-
) : (
208-
<EuiButtonEmpty onClick={() => setExpandError(true)}>
209-
{i18n.translate('xpack.lens.embeddable.legacyURLConflict.expandError', {
210-
defaultMessage: `Show more`,
211-
})}
212-
</EuiButtonEmpty>
213-
)}
214-
</>
215-
);
216-
};
217-
218-
export const savedObjectConflictError = (json: string): ErrorMessage => ({
219-
shortMessage: i18n.translate('xpack.lens.embeddable.legacyURLConflict.shortMessage', {
220-
defaultMessage: `You've encountered a URL conflict`,
221-
}),
222-
longMessage: <SavedObjectConflictMessage json={json} />,
223-
});

x-pack/plugins/lens/public/plugin.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ export class LensPlugin {
212212
uiActions: plugins.uiActions,
213213
usageCollection,
214214
inspector: plugins.inspector,
215+
spaces: plugins.spaces,
215216
};
216217
};
217218

x-pack/plugins/maps/kibana.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"savedObjectsTagging",
3030
"charts",
3131
"security",
32+
"spaces",
3233
"usageCollection"
3334
],
3435
"ui": true,

x-pack/plugins/maps/public/embeddable/_index.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,12 @@
55
flex: 1 1 100%;
66
z-index: 1;
77
min-height: 0; // Absolute must for Firefox to scroll contents
8+
}
9+
10+
.mapEmbeddedError {
11+
flex-grow: 1;
12+
display: flex;
13+
align-items: center;
14+
justify-content: center;
15+
overflow: auto;
816
}

x-pack/plugins/maps/public/embeddable/map_embeddable.tsx

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { Provider } from 'react-redux';
1212
import { render, unmountComponentAtNode } from 'react-dom';
1313
import { Subscription } from 'rxjs';
1414
import { Unsubscribe } from 'redux';
15+
import { EuiEmptyPrompt } from '@elastic/eui';
1516
import {
1617
Embeddable,
1718
IContainer,
@@ -66,6 +67,7 @@ import {
6667
getCoreI18n,
6768
getHttp,
6869
getChartsPaletteServiceGetColor,
70+
getSpacesApi,
6971
getSearchService,
7072
} from '../kibana_services';
7173
import { LayerDescriptor, MapExtent } from '../../common/descriptor_types';
@@ -353,23 +355,38 @@ export class MapEmbeddable
353355
return;
354356
}
355357

356-
const I18nContext = getCoreI18n().Context;
358+
const sharingSavedObjectProps = this._savedMap.getSharingSavedObjectProps();
359+
const spaces = getSpacesApi();
360+
const content =
361+
sharingSavedObjectProps && spaces && sharingSavedObjectProps?.outcome === 'conflict' ? (
362+
<div className="mapEmbeddedError">
363+
<EuiEmptyPrompt
364+
iconType="alert"
365+
iconColor="danger"
366+
data-test-subj="embeddable-maps-failure"
367+
body={spaces.ui.components.getSavedObjectConflictMessage({
368+
json: sharingSavedObjectProps.errorJSON!,
369+
})}
370+
/>
371+
</div>
372+
) : (
373+
<MapContainer
374+
onSingleValueTrigger={this.onSingleValueTrigger}
375+
addFilters={this.input.hideFilterActions ? null : this.addFilters}
376+
getFilterActions={this.getFilterActions}
377+
getActionContext={this.getActionContext}
378+
renderTooltipContent={this._renderTooltipContent}
379+
title={this.getTitle()}
380+
description={this.getDescription()}
381+
waitUntilTimeLayersLoad$={waitUntilTimeLayersLoad$(this._savedMap.getStore())}
382+
isSharable={this._isSharable}
383+
/>
384+
);
357385

386+
const I18nContext = getCoreI18n().Context;
358387
render(
359388
<Provider store={this._savedMap.getStore()}>
360-
<I18nContext>
361-
<MapContainer
362-
onSingleValueTrigger={this.onSingleValueTrigger}
363-
addFilters={this.input.hideFilterActions ? null : this.addFilters}
364-
getFilterActions={this.getFilterActions}
365-
getActionContext={this.getActionContext}
366-
renderTooltipContent={this._renderTooltipContent}
367-
title={this.getTitle()}
368-
description={this.getDescription()}
369-
waitUntilTimeLayersLoad$={waitUntilTimeLayersLoad$(this._savedMap.getStore())}
370-
isSharable={this._isSharable}
371-
/>
372-
</I18nContext>
389+
<I18nContext>{content}</I18nContext>
373390
</Provider>,
374391
this._domNode
375392
);

x-pack/plugins/maps/public/kibana_services.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export const getNavigateToApp = () => coreStart.application.navigateToApp;
5353
export const getSavedObjectsTagging = () => pluginsStart.savedObjectsTagging;
5454
export const getPresentationUtilContext = () => pluginsStart.presentationUtil.ContextProvider;
5555
export const getSecurityService = () => pluginsStart.security;
56+
export const getSpacesApi = () => pluginsStart.spaces;
5657

5758
// xpack.maps.* kibana.yml settings from this plugin
5859
let mapAppConfig: MapsConfigType;

x-pack/plugins/maps/public/map_attribute_service.ts

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,18 @@ import { checkForDuplicateTitle, OnSaveProps } from '../../../../src/plugins/sav
1414
import { getCoreOverlays, getEmbeddableService, getSavedObjectsClient } from './kibana_services';
1515
import { extractReferences, injectReferences } from '../common/migrations/references';
1616
import { MapByValueInput, MapByReferenceInput } from './embeddable/types';
17+
import { getSpacesApi } from './kibana_services';
1718

18-
type MapDoc = MapSavedObjectAttributes & { references?: SavedObjectReference[] };
19+
export interface SharingSavedObjectProps {
20+
outcome?: 'aliasMatch' | 'exactMatch' | 'conflict';
21+
aliasTargetId?: string;
22+
errorJSON?: string;
23+
}
24+
25+
type MapDoc = MapSavedObjectAttributes & {
26+
sharingSavedObjectProps?: SharingSavedObjectProps;
27+
references?: SavedObjectReference[];
28+
};
1929

2030
export type MapAttributeService = AttributeService<MapDoc, MapByValueInput, MapByReferenceInput>;
2131

@@ -58,7 +68,11 @@ export function getMapAttributeService(): MapAttributeService {
5868
return { id: savedObject.id };
5969
},
6070
unwrapMethod: async (savedObjectId: string): Promise<MapDoc> => {
61-
const savedObject = await getSavedObjectsClient().get<MapSavedObjectAttributes>(
71+
const {
72+
saved_object: savedObject,
73+
outcome,
74+
alias_target_id: aliasTargetId,
75+
} = await getSavedObjectsClient().resolve<MapSavedObjectAttributes>(
6276
MAP_SAVED_OBJECT_TYPE,
6377
savedObjectId
6478
);
@@ -68,7 +82,22 @@ export function getMapAttributeService(): MapAttributeService {
6882
}
6983

7084
const { attributes } = injectReferences(savedObject);
71-
return { ...attributes, references: savedObject.references };
85+
return {
86+
...attributes,
87+
references: savedObject.references,
88+
sharingSavedObjectProps: {
89+
aliasTargetId,
90+
outcome,
91+
errorJSON:
92+
outcome === 'conflict' && getSpacesApi()
93+
? JSON.stringify({
94+
targetType: MAP_SAVED_OBJECT_TYPE,
95+
sourceId: savedObjectId,
96+
targetSpace: (await getSpacesApi()!.getActiveSpace()).id,
97+
})
98+
: undefined,
99+
},
100+
};
72101
},
73102
checkForDuplicateTitle: (props: OnSaveProps) => {
74103
return checkForDuplicateTitle(

x-pack/plugins/maps/public/plugin.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ import {
8282
tileMapRenderer,
8383
tileMapVisType,
8484
} from './legacy_visualizations';
85-
import { SecurityPluginStart } from '../../security/public';
85+
import type { SecurityPluginStart } from '../../security/public';
86+
import type { SpacesPluginStart } from '../../spaces/public';
8687

8788
export interface MapsPluginSetupDependencies {
8889
expressions: ReturnType<ExpressionsPublicPlugin['setup']>;
@@ -112,6 +113,7 @@ export interface MapsPluginStartDependencies {
112113
savedObjectsTagging?: SavedObjectTaggingPluginStart;
113114
presentationUtil: PresentationUtilPluginStart;
114115
security: SecurityPluginStart;
116+
spaces?: SpacesPluginStart;
115117
}
116118

117119
/**

x-pack/plugins/maps/public/render_app.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import React from 'react';
99
import { render, unmountComponentAtNode } from 'react-dom';
1010
import { Router, Switch, Route, Redirect, RouteComponentProps } from 'react-router-dom';
1111
import { i18n } from '@kbn/i18n';
12-
import { AppMountParameters } from 'kibana/public';
12+
import type { AppMountParameters } from 'kibana/public';
1313
import {
1414
getCoreChrome,
1515
getCoreI18n,
@@ -98,6 +98,7 @@ export async function renderApp(
9898
setHeaderActionMenu={setHeaderActionMenu}
9999
stateTransfer={stateTransfer}
100100
originatingApp={originatingApp}
101+
history={history}
101102
key={routeProps.match.params.savedMapId ? routeProps.match.params.savedMapId : 'new'}
102103
/>
103104
);

0 commit comments

Comments
 (0)