Skip to content

Commit

Permalink
[Maps][ML] Add hyperlink to anomaly explorer for job from anomaly lay…
Browse files Browse the repository at this point in the history
…er in maps (elastic#159268)

## Summary

Related issue: elastic#148665

This PR adds a link to the anomaly explorer for the job corresponding to
the anomalies layer in maps. The link is found under 'Source details'
once the anomalies layer is created.

<img width="1291" alt="image"
src="https://github.com/elastic/kibana/assets/6446462/f109ce21-1aec-40c4-8cf1-fc3dedaef199">

## NOTE

This is dependent on the changes in maps
elastic#159255

### Checklist

Delete any items that are not applicable to this PR.

- [ ] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))

---------

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
alvarezmelissa87 and kibanamachine authored Jun 9, 2023
1 parent 11c761f commit f2da362
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 13 deletions.
1 change: 1 addition & 0 deletions x-pack/plugins/maps/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export {
export type { FieldFormatter } from './constants';

export type {
DataFilters,
EMSFileSourceDescriptor,
ESTermSourceDescriptor,
LayerDescriptor,
Expand Down
23 changes: 21 additions & 2 deletions x-pack/plugins/ml/public/maps/anomaly_source.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import {
} from '@kbn/maps-plugin/common';
import { AbstractSourceDescriptor, MapExtent } from '@kbn/maps-plugin/common/descriptor_types';
import { ITooltipProperty, GEOJSON_FEATURE_ID_PROPERTY_NAME } from '@kbn/maps-plugin/public';
import { DataFilters } from '@kbn/maps-plugin/common';
import type { SerializableRecord } from '@kbn/utility-types';
import type { LocatorPublic } from '@kbn/share-plugin/common';
import type { Adapters } from '@kbn/inspector-plugin/common/adapters';
import type { GeoJsonWithMeta } from '@kbn/maps-plugin/public';
import type { IField } from '@kbn/maps-plugin/public';
Expand All @@ -30,6 +33,7 @@ import {
AnomalySourceTooltipProperty,
ANOMALY_SOURCE_FIELDS,
} from './anomaly_source_field';
import { ML_PAGES } from '../../common/constants/locator';
import { getResultsForJobId, ML_ANOMALY_LAYERS, MlAnomalyLayersType } from './util';
import { UpdateAnomalySourceEditor } from './update_anomaly_source_editor';
import type { MlApiServices } from '../application/services/ml_api_service';
Expand All @@ -43,7 +47,7 @@ export interface AnomalySourceDescriptor extends AbstractSourceDescriptor {

export class AnomalySource implements IVectorSource {
static mlResultsService: MlApiServices['results'];
static canGetJobs: boolean;
static mlLocator?: LocatorPublic<SerializableRecord>;

static createDescriptor(descriptor: Partial<AnomalySourceDescriptor>) {
if (typeof descriptor.jobId !== 'string') {
Expand Down Expand Up @@ -197,13 +201,28 @@ export class AnomalySource implements IVectorSource {
return false;
}

async getImmutableProperties(): Promise<ImmutableSourceProperty[]> {
async getImmutableProperties(dataFilters: DataFilters): Promise<ImmutableSourceProperty[]> {
let explorerLink: string | undefined;

try {
explorerLink = await AnomalySource.mlLocator?.getUrl({
page: ML_PAGES.ANOMALY_EXPLORER,
pageState: {
jobIds: [this._descriptor.jobId],
timeRange: dataFilters.timeFilters,
},
});
} catch (error) {
// ignore error if unable to get link
}

return [
{
label: i18n.translate('xpack.ml.maps.anomalySourcePropLabel', {
defaultMessage: 'Job Id',
}),
value: this._descriptor.jobId,
...(explorerLink ? { link: explorerLink } : {}),
},
];
}
Expand Down
24 changes: 14 additions & 10 deletions x-pack/plugins/ml/public/maps/anomaly_source_factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,39 @@

import type { StartServicesAccessor } from '@kbn/core/public';
import { SOURCE_TYPES } from '@kbn/maps-plugin/common';
import type { LocatorPublic } from '@kbn/share-plugin/common';
import type { SerializableRecord } from '@kbn/utility-types';
import { HttpService } from '../application/services/http_service';
import type { MlPluginStart, MlStartDependencies } from '../plugin';
import { ML_APP_LOCATOR } from '../../common/constants/locator';
import type { MlApiServices } from '../application/services/ml_api_service';

export class AnomalySourceFactory {
public readonly type = SOURCE_TYPES.ES_ML_ANOMALIES;

constructor(
private getStartServices: StartServicesAccessor<MlStartDependencies, MlPluginStart>,
private canGetJobs: boolean
) {
this.canGetJobs = canGetJobs;
}
private getStartServices: StartServicesAccessor<MlStartDependencies, MlPluginStart>
) {}

private async getServices(): Promise<{ mlResultsService: MlApiServices['results'] }> {
const [coreStart] = await this.getStartServices();
private async getServices(): Promise<{
mlResultsService: MlApiServices['results'];
mlLocator?: LocatorPublic<SerializableRecord>;
}> {
const [coreStart, pluginStart] = await this.getStartServices();
const { mlApiServicesProvider } = await import('../application/services/ml_api_service');
const mlLocator = pluginStart.share.url.locators.get(ML_APP_LOCATOR);

const httpService = new HttpService(coreStart.http);
const mlResultsService = mlApiServicesProvider(httpService).results;

return { mlResultsService };
return { mlResultsService, mlLocator };
}

public async create(): Promise<any> {
const { mlResultsService } = await this.getServices();
const { mlResultsService, mlLocator } = await this.getServices();
const { AnomalySource } = await import('./anomaly_source');
AnomalySource.mlResultsService = mlResultsService;
AnomalySource.canGetJobs = this.canGetJobs;
AnomalySource.mlLocator = mlLocator;
return AnomalySource;
}
}
2 changes: 1 addition & 1 deletion x-pack/plugins/ml/public/maps/register_map_extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export async function registerMapExtension(
core: MlCoreSetup,
{ canGetJobs, canCreateJobs }: { canGetJobs: boolean; canCreateJobs: boolean }
) {
const anomalySourceFactory = new AnomalySourceFactory(core.getStartServices, canGetJobs);
const anomalySourceFactory = new AnomalySourceFactory(core.getStartServices);
const anomalyLayerWizardFactory = new AnomalyLayerWizardFactory(
core.getStartServices,
canGetJobs,
Expand Down

0 comments on commit f2da362

Please sign in to comment.