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

[Maps] Switch to SavedObjectClient.resolve #112606

Merged
merged 13 commits into from
Oct 5, 2021
22 changes: 15 additions & 7 deletions x-pack/plugins/lens/public/embeddable/embeddable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import { isEqual, uniqBy } from 'lodash';
import React from 'react';
import { i18n } from '@kbn/i18n';
import { render, unmountComponentAtNode } from 'react-dom';
import type {
ExecutionContextSearch,
Expand Down Expand Up @@ -41,11 +42,7 @@ import {
ReferenceOrValueEmbeddable,
} from '../../../../../src/plugins/embeddable/public';
import { Document, injectFilterReferences } from '../persistence';
import {
ExpressionWrapper,
ExpressionWrapperProps,
savedObjectConflictError,
} from './expression_wrapper';
import { ExpressionWrapper, ExpressionWrapperProps } from './expression_wrapper';
import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public';
import {
isLensBrushEvent,
Expand All @@ -63,6 +60,7 @@ import { LensAttributeService } from '../lens_attribute_service';
import type { ErrorMessage } from '../editor_frame_service/types';
import { getLensInspectorService, LensInspector } from '../lens_inspector_service';
import { SharingSavedObjectProps } from '../types';
import type { SpacesPluginStart } from '../../../spaces/public';

export type LensSavedObjectAttributes = Omit<Document, 'savedObjectId' | 'type'>;
export interface ResolvedLensSavedObjectAttributes extends LensSavedObjectAttributes {
Expand Down Expand Up @@ -108,6 +106,7 @@ export interface LensEmbeddableDeps {
getTriggerCompatibleActions?: UiActionsStart['getTriggerCompatibleActions'];
capabilities: { canSaveVisualizations: boolean; canSaveDashboards: boolean };
usageCollection?: UsageCollectionSetup;
spaces?: SpacesPluginStart;
}

export class Embeddable
Expand Down Expand Up @@ -281,8 +280,17 @@ export class Embeddable
};
const { ast, errors } = await this.deps.documentToExpression(this.savedVis);
this.errors = errors;
if (sharingSavedObjectProps?.outcome === 'conflict') {
const conflictError = savedObjectConflictError(sharingSavedObjectProps.errorJSON!);
if (sharingSavedObjectProps?.outcome === 'conflict' && this.deps.spaces) {
const conflictError = {
shortMessage: i18n.translate('xpack.lens.embeddable.legacyURLConflict.shortMessage', {
defaultMessage: `You've encountered a URL conflict`,
}),
longMessage: (
<this.deps.spaces.ui.components.getSavedObjectConflictMessage
json={sharingSavedObjectProps.errorJSON!}
/>
),
};
this.errors = this.errors ? [...this.errors, conflictError] : [conflictError];
}
this.expression = ast ? toExpression(ast) : null;
Expand Down
4 changes: 4 additions & 0 deletions x-pack/plugins/lens/public/embeddable/embeddable_factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { LensAttributeService } from '../lens_attribute_service';
import { DOC_TYPE } from '../../common/constants';
import { ErrorMessage } from '../editor_frame_service/types';
import { extract, inject } from '../../common/embeddable_factory';
import type { SpacesPluginStart } from '../../../spaces/public';

export interface LensEmbeddableStartServices {
timefilter: TimefilterContract;
Expand All @@ -38,6 +39,7 @@ export interface LensEmbeddableStartServices {
documentToExpression: (
doc: Document
) => Promise<{ ast: Ast | null; errors: ErrorMessage[] | undefined }>;
spaces?: SpacesPluginStart;
}

export class EmbeddableFactory implements EmbeddableFactoryDefinition {
Expand Down Expand Up @@ -90,6 +92,7 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition {
capabilities,
usageCollection,
inspector,
spaces,
} = await this.getStartServices();

const { Embeddable } = await import('../async_services');
Expand All @@ -110,6 +113,7 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition {
canSaveVisualizations: Boolean(capabilities.visualize.save),
},
usageCollection,
spaces,
},
input,
parent
Expand Down
64 changes: 2 additions & 62 deletions x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,10 @@
* 2.0.
*/

import React, { useState } from 'react';
import React from 'react';
import { I18nProvider } from '@kbn/i18n/react';
import { FormattedMessage } from '@kbn/i18n/react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiText,
EuiIcon,
EuiEmptyPrompt,
EuiButtonEmpty,
EuiCallOut,
EuiSpacer,
EuiLink,
} from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiText, EuiIcon, EuiEmptyPrompt } from '@elastic/eui';
import {
ExpressionRendererEvent,
ReactExpressionRendererType,
Expand All @@ -28,7 +18,6 @@ import type { KibanaExecutionContext } from 'src/core/public';
import { ExecutionContextSearch } from 'src/plugins/data/public';
import { DefaultInspectorAdapters, RenderMode } from 'src/plugins/expressions';
import classNames from 'classnames';
import { i18n } from '@kbn/i18n';
import { getOriginalRequestErrorMessages } from '../editor_frame_service/error_helper';
import { ErrorMessage } from '../editor_frame_service/types';
import { LensInspector } from '../lens_inspector_service';
Expand Down Expand Up @@ -172,52 +161,3 @@ export function ExpressionWrapper({
</I18nProvider>
);
}

const SavedObjectConflictMessage = ({ json }: { json: string }) => {
const [expandError, setExpandError] = useState(false);
return (
<>
<FormattedMessage
id="xpack.lens.embeddable.legacyURLConflict.longMessage"
defaultMessage="Disable the {documentationLink} associated with this object."
values={{
documentationLink: (
<EuiLink
external
href="https://www.elastic.co/guide/en/kibana/master/legacy-url-aliases.html"
target="_blank"
>
{i18n.translate('xpack.lens.embeddable.legacyURLConflict.documentationLinkText', {
defaultMessage: 'legacy URL alias',
})}
</EuiLink>
),
}}
/>
<EuiSpacer />
{expandError ? (
<EuiCallOut
title={i18n.translate('xpack.lens.embeddable.legacyURLConflict.expandErrorText', {
defaultMessage: `This object has the same URL as a legacy alias. Disable the alias to resolve this error : {json}`,
values: { json },
})}
color="danger"
iconType="alert"
/>
) : (
<EuiButtonEmpty onClick={() => setExpandError(true)}>
{i18n.translate('xpack.lens.embeddable.legacyURLConflict.expandError', {
defaultMessage: `Show more`,
})}
</EuiButtonEmpty>
)}
</>
);
};

export const savedObjectConflictError = (json: string): ErrorMessage => ({
shortMessage: i18n.translate('xpack.lens.embeddable.legacyURLConflict.shortMessage', {
defaultMessage: `You've encountered a URL conflict`,
}),
longMessage: <SavedObjectConflictMessage json={json} />,
});
1 change: 1 addition & 0 deletions x-pack/plugins/lens/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ export class LensPlugin {
uiActions: plugins.uiActions,
usageCollection,
inspector: plugins.inspector,
spaces: plugins.spaces,
};
};

Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/maps/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"savedObjectsTagging",
"charts",
"security",
"spaces",
"usageCollection"
],
"ui": true,
Expand Down
8 changes: 8 additions & 0 deletions x-pack/plugins/maps/public/embeddable/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,12 @@
flex: 1 1 100%;
z-index: 1;
min-height: 0; // Absolute must for Firefox to scroll contents
}

.mapEmbeddedError {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: center;
overflow: auto;
}
45 changes: 31 additions & 14 deletions x-pack/plugins/maps/public/embeddable/map_embeddable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Provider } from 'react-redux';
import { render, unmountComponentAtNode } from 'react-dom';
import { Subscription } from 'rxjs';
import { Unsubscribe } from 'redux';
import { EuiEmptyPrompt } from '@elastic/eui';
import {
Embeddable,
IContainer,
Expand Down Expand Up @@ -66,6 +67,7 @@ import {
getCoreI18n,
getHttp,
getChartsPaletteServiceGetColor,
getSpacesApi,
getSearchService,
} from '../kibana_services';
import { LayerDescriptor, MapExtent } from '../../common/descriptor_types';
Expand Down Expand Up @@ -353,23 +355,38 @@ export class MapEmbeddable
return;
}

const I18nContext = getCoreI18n().Context;
const sharingSavedObjectProps = this._savedMap.getSharingSavedObjectProps();
const spaces = getSpacesApi();
const content =
sharingSavedObjectProps && spaces && sharingSavedObjectProps?.outcome === 'conflict' ? (
<div className="mapEmbeddedError">
<EuiEmptyPrompt
iconType="alert"
iconColor="danger"
data-test-subj="embeddable-maps-failure"
body={spaces.ui.components.getSavedObjectConflictMessage({
json: sharingSavedObjectProps.errorJSON!,
})}
/>
</div>
) : (
<MapContainer
onSingleValueTrigger={this.onSingleValueTrigger}
addFilters={this.input.hideFilterActions ? null : this.addFilters}
getFilterActions={this.getFilterActions}
getActionContext={this.getActionContext}
renderTooltipContent={this._renderTooltipContent}
title={this.getTitle()}
description={this.getDescription()}
waitUntilTimeLayersLoad$={waitUntilTimeLayersLoad$(this._savedMap.getStore())}
isSharable={this._isSharable}
/>
);

const I18nContext = getCoreI18n().Context;
render(
<Provider store={this._savedMap.getStore()}>
<I18nContext>
<MapContainer
onSingleValueTrigger={this.onSingleValueTrigger}
addFilters={this.input.hideFilterActions ? null : this.addFilters}
getFilterActions={this.getFilterActions}
getActionContext={this.getActionContext}
renderTooltipContent={this._renderTooltipContent}
title={this.getTitle()}
description={this.getDescription()}
waitUntilTimeLayersLoad$={waitUntilTimeLayersLoad$(this._savedMap.getStore())}
isSharable={this._isSharable}
/>
</I18nContext>
<I18nContext>{content}</I18nContext>
</Provider>,
this._domNode
);
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/maps/public/kibana_services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export const getNavigateToApp = () => coreStart.application.navigateToApp;
export const getSavedObjectsTagging = () => pluginsStart.savedObjectsTagging;
export const getPresentationUtilContext = () => pluginsStart.presentationUtil.ContextProvider;
export const getSecurityService = () => pluginsStart.security;
export const getSpacesApi = () => pluginsStart.spaces;

// xpack.maps.* kibana.yml settings from this plugin
let mapAppConfig: MapsConfigType;
Expand Down
35 changes: 32 additions & 3 deletions x-pack/plugins/maps/public/map_attribute_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,18 @@ import { checkForDuplicateTitle, OnSaveProps } from '../../../../src/plugins/sav
import { getCoreOverlays, getEmbeddableService, getSavedObjectsClient } from './kibana_services';
import { extractReferences, injectReferences } from '../common/migrations/references';
import { MapByValueInput, MapByReferenceInput } from './embeddable/types';
import { getSpacesApi } from './kibana_services';

type MapDoc = MapSavedObjectAttributes & { references?: SavedObjectReference[] };
export interface SharingSavedObjectProps {
outcome?: 'aliasMatch' | 'exactMatch' | 'conflict';
aliasTargetId?: string;
errorJSON?: string;
}

type MapDoc = MapSavedObjectAttributes & {
sharingSavedObjectProps?: SharingSavedObjectProps;
references?: SavedObjectReference[];
};

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

Expand Down Expand Up @@ -58,7 +68,11 @@ export function getMapAttributeService(): MapAttributeService {
return { id: savedObject.id };
},
unwrapMethod: async (savedObjectId: string): Promise<MapDoc> => {
const savedObject = await getSavedObjectsClient().get<MapSavedObjectAttributes>(
const {
saved_object: savedObject,
outcome,
alias_target_id: aliasTargetId,
} = await getSavedObjectsClient().resolve<MapSavedObjectAttributes>(
MAP_SAVED_OBJECT_TYPE,
savedObjectId
);
Expand All @@ -68,7 +82,22 @@ export function getMapAttributeService(): MapAttributeService {
}

const { attributes } = injectReferences(savedObject);
return { ...attributes, references: savedObject.references };
return {
...attributes,
references: savedObject.references,
sharingSavedObjectProps: {
aliasTargetId,
outcome,
errorJSON:
outcome === 'conflict' && getSpacesApi()
? JSON.stringify({
targetType: MAP_SAVED_OBJECT_TYPE,
sourceId: savedObjectId,
targetSpace: (await getSpacesApi()!.getActiveSpace()).id,
})
: undefined,
},
};
},
checkForDuplicateTitle: (props: OnSaveProps) => {
return checkForDuplicateTitle(
Expand Down
4 changes: 3 additions & 1 deletion x-pack/plugins/maps/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ import {
tileMapRenderer,
tileMapVisType,
} from './legacy_visualizations';
import { SecurityPluginStart } from '../../security/public';
import type { SecurityPluginStart } from '../../security/public';
import type { SpacesPluginStart } from '../../spaces/public';

export interface MapsPluginSetupDependencies {
expressions: ReturnType<ExpressionsPublicPlugin['setup']>;
Expand Down Expand Up @@ -113,6 +114,7 @@ export interface MapsPluginStartDependencies {
savedObjectsTagging?: SavedObjectTaggingPluginStart;
presentationUtil: PresentationUtilPluginStart;
security: SecurityPluginStart;
spaces?: SpacesPluginStart;
}

/**
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/maps/public/render_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { Router, Switch, Route, Redirect, RouteComponentProps } from 'react-router-dom';
import { i18n } from '@kbn/i18n';
import { AppMountParameters } from 'kibana/public';
import type { AppMountParameters } from 'kibana/public';
import {
getCoreChrome,
getCoreI18n,
Expand Down Expand Up @@ -98,6 +98,7 @@ export async function renderApp(
setHeaderActionMenu={setHeaderActionMenu}
stateTransfer={stateTransfer}
originatingApp={originatingApp}
history={history}
key={routeProps.match.params.savedMapId ? routeProps.match.params.savedMapId : 'new'}
/>
);
Expand Down
Loading