Skip to content

Commit

Permalink
[8.x] [OneDiscover] Add EBT event to track field usage (#193996) (#19…
Browse files Browse the repository at this point in the history
…4457)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[OneDiscover] Add EBT event to track field usage
(#193996)](#193996)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Julia
Rechkunova","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-09-30T16:20:21Z","message":"[OneDiscover]
Add EBT event to track field usage (#193996)\n\n- Closes
https://github.com/elastic/kibana/issues/186156\r\n- Closes
https://github.com/elastic/kibana/issues/189454\r\n\r\n##
Summary\r\n\r\nThis PR adds new EBT event type `discover_field_usage`
which we use for\r\ntracking adding and removing grid columns and adding
filters via\r\n+/-/exists buttons. Properties of the added events
consist of:\r\n\r\n`eventType`: `dataTableSelection`,
`dataTableRemoval`, or\r\n`filterAddition`\r\n`fieldName`: name of the
field if it's from ECS schema\r\n`filterOperation`: `+`, `-`, or
`_exists_`\r\n\r\n\r\n<img width=\"1002\" alt=\"Screenshot 2024-09-25 at
17 51
27\"\r\nsrc=\"https://github.com/user-attachments/assets/b3f3fb69-55e1-43b2-9683-a6d8884f56fe\">\r\n\r\n##
Testing\r\n\r\nEnable \"Usage collection\" global
setting.\r\n\r\nNavigate to Discover and observe `kibana-browser`
requests in Network\r\ntab.\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios","sha":"7aa64b6ed59488ab10a5136199b69de0c86668af","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:DataDiscovery","backport:prev-minor","Project:OneDiscover"],"title":"[OneDiscover]
Add EBT event to track field
usage","number":193996,"url":"https://github.com/elastic/kibana/pull/193996","mergeCommit":{"message":"[OneDiscover]
Add EBT event to track field usage (#193996)\n\n- Closes
https://github.com/elastic/kibana/issues/186156\r\n- Closes
https://github.com/elastic/kibana/issues/189454\r\n\r\n##
Summary\r\n\r\nThis PR adds new EBT event type `discover_field_usage`
which we use for\r\ntracking adding and removing grid columns and adding
filters via\r\n+/-/exists buttons. Properties of the added events
consist of:\r\n\r\n`eventType`: `dataTableSelection`,
`dataTableRemoval`, or\r\n`filterAddition`\r\n`fieldName`: name of the
field if it's from ECS schema\r\n`filterOperation`: `+`, `-`, or
`_exists_`\r\n\r\n\r\n<img width=\"1002\" alt=\"Screenshot 2024-09-25 at
17 51
27\"\r\nsrc=\"https://github.com/user-attachments/assets/b3f3fb69-55e1-43b2-9683-a6d8884f56fe\">\r\n\r\n##
Testing\r\n\r\nEnable \"Usage collection\" global
setting.\r\n\r\nNavigate to Discover and observe `kibana-browser`
requests in Network\r\ntab.\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios","sha":"7aa64b6ed59488ab10a5136199b69de0c86668af"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/193996","number":193996,"mergeCommit":{"message":"[OneDiscover]
Add EBT event to track field usage (#193996)\n\n- Closes
https://github.com/elastic/kibana/issues/186156\r\n- Closes
https://github.com/elastic/kibana/issues/189454\r\n\r\n##
Summary\r\n\r\nThis PR adds new EBT event type `discover_field_usage`
which we use for\r\ntracking adding and removing grid columns and adding
filters via\r\n+/-/exists buttons. Properties of the added events
consist of:\r\n\r\n`eventType`: `dataTableSelection`,
`dataTableRemoval`, or\r\n`filterAddition`\r\n`fieldName`: name of the
field if it's from ECS schema\r\n`filterOperation`: `+`, `-`, or
`_exists_`\r\n\r\n\r\n<img width=\"1002\" alt=\"Screenshot 2024-09-25 at
17 51
27\"\r\nsrc=\"https://github.com/user-attachments/assets/b3f3fb69-55e1-43b2-9683-a6d8884f56fe\">\r\n\r\n##
Testing\r\n\r\nEnable \"Usage collection\" global
setting.\r\n\r\nNavigate to Discover and observe `kibana-browser`
requests in Network\r\ntab.\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios","sha":"7aa64b6ed59488ab10a5136199b69de0c86668af"}}]}]
BACKPORT-->

Co-authored-by: Julia Rechkunova <[email protected]>
  • Loading branch information
kibanamachine and jughosta authored Sep 30, 2024
1 parent e6593a0 commit ec90e85
Show file tree
Hide file tree
Showing 17 changed files with 946 additions and 337 deletions.
2 changes: 2 additions & 0 deletions src/plugins/discover/public/__mocks__/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import { SearchResponse } from '@elastic/elasticsearch/lib/api/types';
import { urlTrackerMock } from './url_tracker.mock';
import { createElement } from 'react';
import { createContextAwarenessMocks } from '../context_awareness/__mocks__';
import { DiscoverEBTManager } from '../services/discover_ebt_manager';

export function createDiscoverServicesMock(): DiscoverServices {
const dataPlugin = dataPluginMock.createStartContract();
Expand Down Expand Up @@ -245,6 +246,7 @@ export function createDiscoverServicesMock(): DiscoverServices {
singleDocLocator: { getRedirectUrl: jest.fn(() => '') },
urlTracker: urlTrackerMock,
profilesManager: profilesManagerMock,
ebtManager: new DiscoverEBTManager(),
setHeaderActionMenu: jest.fn(),
} as unknown as DiscoverServices;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ describe('ContextApp test', () => {
contextLocator: { getRedirectUrl: jest.fn(() => '') },
singleDocLocator: { getRedirectUrl: jest.fn(() => '') },
profilesManager: discoverServices.profilesManager,
ebtManager: discoverServices.ebtManager,
timefilter: discoverServices.timefilter,
uiActions: discoverServices.uiActions,
} as unknown as DiscoverServices;
Expand Down
31 changes: 27 additions & 4 deletions src/plugins/discover/public/application/context/context_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export const ContextApp = ({ dataView, anchorId, referrer }: ContextAppProps) =>
navigation,
filterManager,
core,
ebtManager,
fieldsMetadata,
} = services;

const isLegacy = useMemo(() => uiSettings.get(DOC_TABLE_LEGACY), [uiSettings]);
Expand Down Expand Up @@ -199,15 +201,36 @@ export const ContextApp = ({ dataView, anchorId, referrer }: ContextAppProps) =>
);

const addFilter = useCallback(
async (field: DataViewField | string, values: unknown, operation: string) => {
async (field: DataViewField | string, values: unknown, operation: '+' | '-') => {
const newFilters = generateFilters(filterManager, field, values, operation, dataView);
filterManager.addFilters(newFilters);
if (dataViews) {
const fieldName = typeof field === 'string' ? field : field.name;
await popularizeField(dataView, fieldName, dataViews, capabilities);
void ebtManager.trackFilterAddition({
fieldName: fieldName === '_exists_' ? String(values) : fieldName,
filterOperation: fieldName === '_exists_' ? '_exists_' : operation,
fieldsMetadata,
});
}
},
[filterManager, dataViews, dataView, capabilities]
[filterManager, dataViews, dataView, capabilities, ebtManager, fieldsMetadata]
);

const onAddColumnWithTracking = useCallback(
(columnName: string) => {
onAddColumn(columnName);
void ebtManager.trackDataTableSelection({ fieldName: columnName, fieldsMetadata });
},
[onAddColumn, ebtManager, fieldsMetadata]
);

const onRemoveColumnWithTracking = useCallback(
(columnName: string) => {
onRemoveColumn(columnName);
void ebtManager.trackDataTableRemoval({ fieldName: columnName, fieldsMetadata });
},
[onRemoveColumn, ebtManager, fieldsMetadata]
);

const TopNavMenu = navigation.ui.AggregateQueryTopNavMenu;
Expand Down Expand Up @@ -271,8 +294,8 @@ export const ContextApp = ({ dataView, anchorId, referrer }: ContextAppProps) =>
isLegacy={isLegacy}
columns={columns}
grid={appState.grid}
onAddColumn={onAddColumn}
onRemoveColumn={onRemoveColumn}
onAddColumn={onAddColumnWithTracking}
onRemoveColumn={onRemoveColumnWithTracking}
onSetColumns={onSetColumns}
predecessorCount={appState.predecessorCount}
successorCount={appState.successorCount}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ function DiscoverDocumentsComponent({
const services = useDiscoverServices();
const documents$ = stateContainer.dataState.data$.documents$;
const savedSearch = useSavedSearchInitial();
const { dataViews, capabilities, uiSettings, uiActions } = services;
const { dataViews, capabilities, uiSettings, uiActions, ebtManager, fieldsMetadata } = services;
const [
dataSource,
query,
Expand Down Expand Up @@ -200,6 +200,22 @@ function DiscoverDocumentsComponent({
settings: grid,
});

const onAddColumnWithTracking = useCallback(
(columnName: string) => {
onAddColumn(columnName);
void ebtManager.trackDataTableSelection({ fieldName: columnName, fieldsMetadata });
},
[onAddColumn, ebtManager, fieldsMetadata]
);

const onRemoveColumnWithTracking = useCallback(
(columnName: string) => {
onRemoveColumn(columnName);
void ebtManager.trackDataTableRemoval({ fieldName: columnName, fieldsMetadata });
},
[onRemoveColumn, ebtManager, fieldsMetadata]
);

const setExpandedDoc = useCallback(
(doc: DataTableRecord | undefined) => {
stateContainer.internalState.transitions.setExpandedDoc(doc);
Expand Down Expand Up @@ -299,14 +315,22 @@ function DiscoverDocumentsComponent({
columnsMeta={customColumnsMeta}
savedSearchId={savedSearch.id}
onFilter={onAddFilter}
onRemoveColumn={onRemoveColumn}
onAddColumn={onAddColumn}
onRemoveColumn={onRemoveColumnWithTracking}
onAddColumn={onAddColumnWithTracking}
onClose={() => setExpandedDoc(undefined)}
setExpandedDoc={setExpandedDoc}
query={query}
/>
),
[dataView, onAddColumn, onAddFilter, onRemoveColumn, query, savedSearch.id, setExpandedDoc]
[
dataView,
onAddColumnWithTracking,
onAddFilter,
onRemoveColumnWithTracking,
query,
savedSearch.id,
setExpandedDoc,
]
);

const configRowHeight = uiSettings.get(ROW_HEIGHT_OPTION);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) {
spaces,
observabilityAIAssistant,
dataVisualizer: dataVisualizerService,
ebtManager,
fieldsMetadata,
} = useDiscoverServices();
const pageBackgroundColor = useEuiBackgroundColor('plain');
const globalQueryState = data.query.getState();
Expand Down Expand Up @@ -154,6 +156,22 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) {
settings: grid,
});

const onAddColumnWithTracking = useCallback(
(columnName: string) => {
onAddColumn(columnName);
void ebtManager.trackDataTableSelection({ fieldName: columnName, fieldsMetadata });
},
[onAddColumn, ebtManager, fieldsMetadata]
);

const onRemoveColumnWithTracking = useCallback(
(columnName: string) => {
onRemoveColumn(columnName);
void ebtManager.trackDataTableRemoval({ fieldName: columnName, fieldsMetadata });
},
[onRemoveColumn, ebtManager, fieldsMetadata]
);

// The assistant is getting the state from the url correctly
// expect from the index pattern where we have only the dataview id
useEffect(() => {
Expand All @@ -175,9 +193,14 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) {
if (trackUiMetric) {
trackUiMetric(METRIC_TYPE.CLICK, 'filter_added');
}
void ebtManager.trackFilterAddition({
fieldName: fieldName === '_exists_' ? String(values) : fieldName,
filterOperation: fieldName === '_exists_' ? '_exists_' : operation,
fieldsMetadata,
});
return filterManager.addFilters(newFilters);
},
[filterManager, dataView, dataViews, trackUiMetric, capabilities]
[filterManager, dataView, dataViews, trackUiMetric, capabilities, ebtManager, fieldsMetadata]
);

const getOperator = (fieldName: string, values: unknown, operation: '+' | '-') => {
Expand Down Expand Up @@ -222,8 +245,13 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) {
if (trackUiMetric) {
trackUiMetric(METRIC_TYPE.CLICK, 'esql_filter_added');
}
void ebtManager.trackFilterAddition({
fieldName: fieldName === '_exists_' ? String(values) : fieldName,
filterOperation: fieldName === '_exists_' ? '_exists_' : operation,
fieldsMetadata,
});
},
[data.query.queryString, query, trackUiMetric]
[data.query.queryString, query, trackUiMetric, ebtManager, fieldsMetadata]
);

const onFilter = isEsqlMode ? onPopulateWhereClause : onAddFilter;
Expand Down Expand Up @@ -274,8 +302,8 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) {
return undefined;
}

return () => onAddColumn(draggingFieldName);
}, [onAddColumn, draggingFieldName, currentColumns]);
return () => onAddColumnWithTracking(draggingFieldName);
}, [onAddColumnWithTracking, draggingFieldName, currentColumns]);

const [sidebarToggleState$] = useState<BehaviorSubject<SidebarToggleState>>(
() => new BehaviorSubject<SidebarToggleState>({ isCollapsed: false, toggle: () => {} })
Expand Down Expand Up @@ -396,10 +424,10 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) {
sidebarPanel={
<SidebarMemoized
documents$={stateContainer.dataState.data$.documents$}
onAddField={onAddColumn}
onAddField={onAddColumnWithTracking}
onRemoveField={onRemoveColumnWithTracking}
columns={currentColumns}
onAddFilter={onFilter}
onRemoveField={onRemoveColumn}
onChangeDataView={stateContainer.actions.onChangeDataView}
selectedDataView={dataView}
trackUiMetric={trackUiMetric}
Expand Down
10 changes: 5 additions & 5 deletions src/plugins/discover/public/build_services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ import type { DiscoverContextAppLocator } from './application/context/services/l
import type { DiscoverSingleDocLocator } from './application/doc/locator';
import type { DiscoverAppLocator } from '../common';
import type { ProfilesManager } from './context_awareness';
import type { DiscoverEBTContextManager } from './services/discover_ebt_context_manager';
import type { DiscoverEBTManager } from './services/discover_ebt_manager';

/**
* Location state of internal Discover history instance
Expand Down Expand Up @@ -132,7 +132,7 @@ export interface DiscoverServices {
noDataPage?: NoDataPagePluginStart;
observabilityAIAssistant?: ObservabilityAIAssistantPublicStart;
profilesManager: ProfilesManager;
ebtContextManager: DiscoverEBTContextManager;
ebtManager: DiscoverEBTManager;
fieldsMetadata?: FieldsMetadataPublicStart;
logsDataAccess?: LogsDataAccessPluginStart;
}
Expand All @@ -149,7 +149,7 @@ export const buildServices = memoize(
scopedHistory,
urlTracker,
profilesManager,
ebtContextManager,
ebtManager,
setHeaderActionMenu = noop,
}: {
core: CoreStart;
Expand All @@ -162,7 +162,7 @@ export const buildServices = memoize(
scopedHistory?: ScopedHistory;
urlTracker: UrlTracker;
profilesManager: ProfilesManager;
ebtContextManager: DiscoverEBTContextManager;
ebtManager: DiscoverEBTManager;
setHeaderActionMenu?: AppMountParameters['setHeaderActionMenu'];
}): DiscoverServices => {
const { usageCollection } = plugins;
Expand Down Expand Up @@ -223,7 +223,7 @@ export const buildServices = memoize(
noDataPage: plugins.noDataPage,
observabilityAIAssistant: plugins.observabilityAIAssistant,
profilesManager,
ebtContextManager,
ebtManager,
fieldsMetadata: plugins.fieldsMetadata,
logsDataAccess: plugins.logsDataAccess,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
} from '../profiles';
import { ProfileProviderServices } from '../profile_providers/profile_provider_services';
import { ProfilesManager } from '../profiles_manager';
import { DiscoverEBTContextManager } from '../../services/discover_ebt_context_manager';
import { DiscoverEBTManager } from '../../services/discover_ebt_manager';
import { createLogsContextServiceMock } from '@kbn/discover-utils/src/__mocks__';

export const createContextAwarenessMocks = ({
Expand Down Expand Up @@ -152,12 +152,12 @@ export const createContextAwarenessMocks = ({
documentProfileServiceMock.registerProvider(documentProfileProviderMock);
}

const ebtContextManagerMock = new DiscoverEBTContextManager();
const ebtManagerMock = new DiscoverEBTManager();
const profilesManagerMock = new ProfilesManager(
rootProfileServiceMock,
dataSourceProfileServiceMock,
documentProfileServiceMock,
ebtContextManagerMock
ebtManagerMock
);

const profileProviderServices = createProfileProviderServicesMock();
Expand All @@ -173,7 +173,7 @@ export const createContextAwarenessMocks = ({
contextRecordMock2,
profilesManagerMock,
profileProviderServices,
ebtContextManagerMock,
ebtManagerMock,
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('ProfilesManager', () => {
beforeEach(() => {
jest.clearAllMocks();
mocks = createContextAwarenessMocks();
jest.spyOn(mocks.ebtContextManagerMock, 'updateProfilesContextWith');
jest.spyOn(mocks.ebtManagerMock, 'updateProfilesContextWith');
});

it('should return default profiles', () => {
Expand Down Expand Up @@ -62,7 +62,7 @@ describe('ProfilesManager', () => {
mocks.documentProfileProviderMock.profile,
]);

expect(mocks.ebtContextManagerMock.updateProfilesContextWith).toHaveBeenCalledWith([
expect(mocks.ebtManagerMock.updateProfilesContextWith).toHaveBeenCalledWith([
'root-profile',
'data-source-profile',
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import type {
DocumentContext,
} from './profiles';
import type { ContextWithProfileId } from './profile_service';
import { DiscoverEBTContextManager } from '../services/discover_ebt_context_manager';
import { DiscoverEBTManager } from '../services/discover_ebt_manager';

interface SerializedRootProfileParams {
solutionNavId: RootProfileProviderParams['solutionNavId'];
Expand Down Expand Up @@ -53,7 +53,7 @@ export interface GetProfilesOptions {
export class ProfilesManager {
private readonly rootContext$: BehaviorSubject<ContextWithProfileId<RootContext>>;
private readonly dataSourceContext$: BehaviorSubject<ContextWithProfileId<DataSourceContext>>;
private readonly ebtContextManager: DiscoverEBTContextManager;
private readonly ebtManager: DiscoverEBTManager;

private prevRootProfileParams?: SerializedRootProfileParams;
private prevDataSourceProfileParams?: SerializedDataSourceProfileParams;
Expand All @@ -64,11 +64,11 @@ export class ProfilesManager {
private readonly rootProfileService: RootProfileService,
private readonly dataSourceProfileService: DataSourceProfileService,
private readonly documentProfileService: DocumentProfileService,
ebtContextManager: DiscoverEBTContextManager
ebtManager: DiscoverEBTManager
) {
this.rootContext$ = new BehaviorSubject(rootProfileService.defaultContext);
this.dataSourceContext$ = new BehaviorSubject(dataSourceProfileService.defaultContext);
this.ebtContextManager = ebtContextManager;
this.ebtManager = ebtManager;
}

/**
Expand Down Expand Up @@ -206,7 +206,7 @@ export class ProfilesManager {
private trackActiveProfiles(rootContextProfileId: string, dataSourceContextProfileId: string) {
const dscProfiles = [rootContextProfileId, dataSourceContextProfileId];

this.ebtContextManager.updateProfilesContextWith(dscProfiles);
this.ebtManager.updateProfilesContextWith(dscProfiles);
}
}

Expand Down
Loading

0 comments on commit ec90e85

Please sign in to comment.