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

Update tracker params #963

Merged
merged 10 commits into from
May 4, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/sandbox/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"dependencies": {
"@elastic/apm-rum": "^5.12.0",
"@elastic/apm-rum-react": "^1.4.2",
"@elastic/behavioral-analytics-javascript-tracker": "^2.1.3",
"@elastic/datemath": "^5.0.3",
"@elastic/eui": "^49.0.0",
"@elastic/react-search-ui": "1.19.1",
Expand Down
10 changes: 10 additions & 0 deletions examples/sandbox/src/pages/app-search/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ import {
SingleSelectFacet
} from "@elastic/react-search-ui-views";
import "@elastic/react-search-ui-views/lib/styles/styles.css";
import AnalyticsPlugin from "@elastic/search-ui-analytics-plugin";
import {
createTracker,
getTracker
} from "@elastic/behavioral-analytics-javascript-tracker";

const connector = new AppSearchAPIConnector({
searchKey:
Expand All @@ -33,12 +38,17 @@ const connector = new AppSearchAPIConnector({
process.env.REACT_APP_SEARCH_ENDPOINT_BASE ||
"https://search-ui-sandbox.ent.us-central1.gcp.cloud.es.io"
});
createTracker({
collectionName: "search-ui",
endpoint: "http://localhost:9200"
});

const config = {
debug: true,
alwaysSearchOnInitialLoad: true,
apiConnector: connector,
hasA11yNotifications: true,
plugins: [AnalyticsPlugin({ client: getTracker() })],
searchQuery: {
result_fields: {
visitors: { raw: {} },
Expand Down
3 changes: 3 additions & 0 deletions packages/search-ui-analytics-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,8 @@
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
},
"dependencies": {
"@elastic/behavioral-analytics-tracker-core": "^2.0.5"
}
}
22 changes: 17 additions & 5 deletions packages/search-ui-analytics-plugin/src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ describe("analytics plugin", () => {
eaPlugin.subscribe({
type: "SearchQuery",
query: "test",
totalResults: 0
totalResults: 0,
filters: []
});
expect(window["elasticAnalytics"].trackEvent).not.toBeCalled();
expect(internalClient.trackEvent).toBeCalled();
Expand All @@ -36,12 +37,23 @@ describe("analytics plugin", () => {
eaPlugin.subscribe({
type: "SearchQuery",
query: "test",
totalResults: 0
totalResults: 0,
filters: []
});
expect(window["elasticAnalytics"].trackEvent).toBeCalledWith("search", {
type: "SearchQuery",
query: "test",
totalResults: 0
search: {
filters: {},
page: {
current: undefined,
size: undefined
},
results: {
items: [],
total_results: 0
},
sort: undefined,
query: "test"
}
});
});
});
125 changes: 107 additions & 18 deletions packages/search-ui-analytics-plugin/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,107 @@
import type { Event } from "@elastic/search-ui";
import {
Event,
BaseEvent,
ResultSelectedEvent,
SearchQueryEvent,
FilterValueRange,
FilterValue
} from "@elastic/search-ui";
import type {
Tracker,
TrackerEventType,
EventInputProperties,
SearchEventInputProperties,
SearchClickEventInputProperties
} from "@elastic/behavioral-analytics-tracker-core";

export type EventType = "search" | "click" | "pageview";
export interface AnalyticsPluginOptions {
client?: Pick<Tracker, "trackEvent">;
}

export type AnalyticsClient = {
trackEvent: (eventType: EventType, payload: Record<string, any>) => void;
const transformFilterValues = (values: FilterValue[]): string[] => {
const transformBasicValue = (value: string | boolean | number) =>
value.toString();
const transformRangeValue = (value: FilterValueRange) =>
`${value.from || "*"}-${value.to || "*"}`;

return values.reduce<string[]>((res, value) => {
if (Array.isArray(value)) {
return [...res, ...value.map(transformBasicValue)];
}

return [
...res,
typeof value === "object"
? transformRangeValue(value)
: transformBasicValue(value)
];
}, []);
};

export interface AnalyticsPluginOptions {
client?: AnalyticsClient;
}
type TrackerParams<
T extends TrackerEventType,
K extends EventInputProperties
> = [T, K];

export default function AnalyticsPlugin(options = { client: undefined }) {
const client: AnalyticsClient =
const mapEventToTrackerParams: Record<
ResultSelectedEvent["type"] | SearchQueryEvent["type"],
(
event: BaseEvent
) =>
| TrackerParams<"search_click", SearchClickEventInputProperties>
| TrackerParams<"search", SearchEventInputProperties>
> = {
ResultSelected: (event: ResultSelectedEvent) => [
"search_click",
{
document: { id: event.documentId, index: event.origin },
search: {
query: event.query,
results: {
items: [],
total_results: event.totalResults
},
search_application: "search-ui"
Copy link
Member

@joemcelroy joemcelroy May 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exclude search_application from the event. This is reserved for the name of the search application, not the client name. This can added later on once we clarify the status of search_application

}
}
],
SearchQuery: (event: SearchQueryEvent) => [
"search",
{
search: {
query: event.query,
filters: event.filters.reduce(
(res, filter) => ({
...res,
[filter.field]: transformFilterValues(filter.values)
}),
{}
),
page: {
current: event.currentPage,
size: event.resultsPerPage
},
results: {
items: [],
total_results: event.totalResults
},
sort: event.sort
?.filter(
(sort) => sort.direction === "desc" || sort.direction === "asc"
)
.map((sort) => ({
name: sort.field,
direction: sort.direction as "asc" | "desc"
}))
}
}
]
};

export default function AnalyticsPlugin(
options: AnalyticsPluginOptions = { client: undefined }
) {
const client: Tracker =
options.client ||
(typeof window !== "undefined" && window["elasticAnalytics"]);
if (!client) {
Expand All @@ -22,15 +112,14 @@ export default function AnalyticsPlugin(options = { client: undefined }) {

return {
subscribe: (event: Event) => {
const eventTypeMap: Record<Event["type"], EventType> = {
AutocompleteSuggestionSelected: "click",
FacetFilterRemoved: "click",
FacetFilterSelected: "click",
ResultSelected: "click",
SearchQuery: "search"
};

client.trackEvent(eventTypeMap[event.type], event);
const [eventType, payload] =
mapEventToTrackerParams[event.type](event) || [];

if (!eventType || !payload) {
return;
}

client.trackEvent(eventType, payload);
}
};
}
4 changes: 4 additions & 0 deletions packages/search-ui/src/SearchDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,11 @@ class SearchDriver {

this.events.emit({
type: "SearchQuery",
filters: this.state.filters,
query: this.state.searchTerm,
sort: requestState.sort,
currentPage: requestState.current,
resultsPerPage: requestState.resultsPerPage,
totalResults: totalResults
});

Expand Down
4 changes: 4 additions & 0 deletions packages/search-ui/src/__tests__/SearchDriver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -521,8 +521,12 @@ describe("_updateSearchResults", () => {
expect(stateAfterCreation.pagingStart).toEqual(21);
expect(stateAfterCreation.pagingEnd).toEqual(40);
expect(mockPlugin.subscribe).toBeCalledWith({
currentPage: 1,
query: "test",
resultsPerPage: 20,
sort: undefined,
totalResults: 1000,
filters: [],
type: "SearchQuery"
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ describe("#trackClickThrough", () => {
position: 0,
query: "search terms",
tags: ["test"],
type: "ResultSelected"
type: "ResultSelected",
totalResults: 1000
});
});
});
10 changes: 6 additions & 4 deletions packages/search-ui/src/actions/trackClickThrough.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SearchState } from "..";
import { Event, SearchResult, SearchState } from "..";
import Events from "../Events";

/**
Expand All @@ -23,7 +23,8 @@ export default function trackClickThrough(
searchTerm,
results,
current,
resultsPerPage
resultsPerPage,
totalResults
}: SearchState = this.state;

const resultIndexOnPage = results.findIndex(
Expand All @@ -47,8 +48,9 @@ export default function trackClickThrough(
type: "ResultSelected",
documentId,
query: searchTerm,
position: resultIndexOnPage,
origin: "results",
tags
position: resultIndexOnPage,
tags,
totalResults
});
}
9 changes: 7 additions & 2 deletions packages/search-ui/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,14 @@ export interface BaseEvent {
tags?: string[];
}

interface SearchQueryEvent extends BaseEvent {
export interface SearchQueryEvent extends BaseEvent {
type: "SearchQuery";
filters: Filter[];
query: string;
totalResults: number;
sort?: SortOption[];
currentPage?: number;
resultsPerPage?: number;
}

interface AutocompleteSuggestionSelectedEvent extends BaseEvent {
Expand All @@ -250,12 +254,13 @@ interface AutocompleteSuggestionSelectedEvent extends BaseEvent {
position: number;
}

interface ResultSelectedEvent extends BaseEvent {
export interface ResultSelectedEvent extends BaseEvent {
type: "ResultSelected";
query: string;
documentId: string;
position: number;
origin: "autocomplete" | "results";
totalResults?: number;
}

interface FacetFilterSelectedEvent extends BaseEvent {
Expand Down
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1621,6 +1621,18 @@
dependencies:
object-hash "^1.3.0"

"@elastic/behavioral-analytics-javascript-tracker@^2.1.3":
version "2.1.3"
resolved "https://registry.yarnpkg.com/@elastic/behavioral-analytics-javascript-tracker/-/behavioral-analytics-javascript-tracker-2.1.3.tgz#53942a286c84ecc357dea0263f18882898a416e4"
integrity sha512-imProiNHyD04SLk8CqELv1E5quHnttoP7TWRzc94m0c8SxhU5vDn/5Af6JrRQ6QlGjc1+8ENckogcS1L9qGqaw==
dependencies:
"@elastic/behavioral-analytics-tracker-core" "2.0.5"

"@elastic/behavioral-analytics-tracker-core@2.0.5", "@elastic/behavioral-analytics-tracker-core@^2.0.5":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@elastic/behavioral-analytics-tracker-core/-/behavioral-analytics-tracker-core-2.0.5.tgz#831dfa87b01ba8808cd843c60fd49f909b915ad2"
integrity sha512-SEtxpTnnWz/Etve2cdwMyVEv1C67lrVX38wv1hvg6L6Vu7bbSQdjs4b2KruswTA1CtJq8fngWSdACkIZn0scwQ==

"@elastic/datemath@^5.0.3":
version "5.0.3"
resolved "https://registry.yarnpkg.com/@elastic/datemath/-/datemath-5.0.3.tgz#7baccdab672b9a3ecb7fe8387580670936b58573"
Expand Down