From bce557cc2dc767628bed6aac87301a1be7c5431b Mon Sep 17 00:00:00 2001 From: rxliuli Date: Tue, 4 Nov 2025 05:03:50 +0800 Subject: init commit --- .../search/guided-search/guided-search-metrics.js | 132 +++++++++++++++++++++ .../common/search/guided-search/guided-search.js | 105 ++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 node_modules/@jet-app/app-store/tmp/src/common/search/guided-search/guided-search-metrics.js create mode 100644 node_modules/@jet-app/app-store/tmp/src/common/search/guided-search/guided-search.js (limited to 'node_modules/@jet-app/app-store/tmp/src/common/search/guided-search') diff --git a/node_modules/@jet-app/app-store/tmp/src/common/search/guided-search/guided-search-metrics.js b/node_modules/@jet-app/app-store/tmp/src/common/search/guided-search/guided-search-metrics.js new file mode 100644 index 0000000..83cdf90 --- /dev/null +++ b/node_modules/@jet-app/app-store/tmp/src/common/search/guided-search/guided-search-metrics.js @@ -0,0 +1,132 @@ +/** + * Builds metrics entities for Guided Search + */ +import { ImpressionMetrics, } from "../../../api/models"; +import { isDefinedNonNullNonEmpty, isNullOrEmpty } from "../../../foundation/json-parsing/server-data"; +import { createMetricsClickData, createMetricsSearchData } from "../../metrics/builder"; +import { createBasicLocation, currentPosition } from "../../metrics/helpers/location"; +// region Action Metrics +/** + * Add click + search metrics data to guided search token action + * @param objectGraph The dependency graph for the App Store. + * @param action Action to instrument, e.g. toggle or rewrite. + * @param targetToken The token display label, which may be toggleable. + * @param searchTerm The search term for which this token action was returned for. + * @param metricsOptions The metrics option use for adding instrumentation to token toggle. + */ +export function addEventsToGuidedSearchTokenAction(objectGraph, action, targetToken, searchTerm, metricsOptions) { + // Click Fields + const actionType = "guidedSearch"; + const targetType = "guidedLabel"; + const clickFields = { + actionType: actionType, + location: createBasicLocation(objectGraph, { + pageInformation: null, + locationTracker: metricsOptions.locationTracker, + targetType: targetType, + }, targetToken), + searchTerm: searchTerm, + }; + // Search Fields + const searchFields = { + targetId: targetToken, + }; + // SSS: Clicks must be before Search + const clickData = createMetricsClickData(objectGraph, targetToken, targetType, clickFields, ["guidedSearch"]); + action.actionMetrics.addMetricsData(clickData); + const searchData = createMetricsSearchData(objectGraph, searchTerm, targetType, actionType, null, searchFields, [ + "guidedSearch", + ]); + action.actionMetrics.addMetricsData(searchData); +} +export function addEventsToGuidedSearchTokenEntityChangeAction(objectGraph, action, searchTerm, targetEntity, metricsOptions) { + // Click Fields + const actionType = "hint"; + const targetType = "hintsEntity"; + const clickFields = { + actionType: actionType, + location: createBasicLocation(objectGraph, { + pageInformation: null, + locationTracker: metricsOptions.locationTracker, + targetType: targetType, + }, targetEntity), + searchTerm: searchTerm, + }; + // Search Fields + const searchFields = { + targetId: targetEntity, + }; + // SSS: Clicks must be before Search + const clickData = createMetricsClickData(objectGraph, targetEntity, targetType, clickFields); + action.actionMetrics.addMetricsData(clickData); + const searchData = createMetricsSearchData(objectGraph, searchTerm, targetType, actionType, null, searchFields); + action.actionMetrics.addMetricsData(searchData); +} +// endregion +// region Page Metrics +/** + * Build a `MetricsFields` for guided search fields used for page and impression events. + * This is attached onto `MetricsPageInformation` for consumption during page and impression field generation. + */ +export function guidedSearchPageInformationFields(objectGraph, request, guidedSearchData) { + const fields = {}; + // field for what tokens were selected on page. + if (isDefinedNonNullNonEmpty(request.guidedSearchTokens)) { + fields["searchSelectedGuidedFacets"] = request.guidedSearchTokens; + } + // field for what the server computed final query was + if (guidedSearchData && guidedSearchData.finalTerm) { + fields["searchGuidedFinalQuery"] = guidedSearchData.finalTerm; + } + if (isNullOrEmpty(fields)) { + return undefined; + } + return fields; +} +// endregion +// region Impression Metrics +export function addImpressionMetricsToGuidedSearchToken(objectGraph, token, type, metricsOptions) { + const tokenIndex = currentPosition(metricsOptions.locationTracker); + /** + * ID for parent is index. This should be explicit but is not in how we do metrics in JS today (sequential IDs are added later) + */ + const impressionFields = { + impressionIndex: tokenIndex, + id: tokenIndex.toString(), + idType: "sequential", + name: token.displayName, + impressionType: type, + parentId: "search-revisions", + }; + token.impressionMetrics = new ImpressionMetrics(impressionFields); +} +/** + * Add imaginary parent container for search results + * Guided Search: Tech Debt: Trim parent impression tech debt off SearchResults (JS Compatibility Breaking) + */ +export function addSearchResultParentImpressionMetrics(objectGraph, searchResultsPage, metricsOptions) { + const parentIndex = currentPosition(metricsOptions.locationTracker); + searchResultsPage.resultsParentImpressionMetrics = new ImpressionMetrics({ + impressionIndex: parentIndex, + impressionType: "SearchResults", + idType: "relationship", + id: "search-results", + name: "Search Results", + }); +} +/** + * Add an imaginary parent container for guided search tokens + * Guided Search: Tech Debt: Trim parent impression tech debt off SearchResults (JS Compatibility Breaking) + */ +export function addGuidedSearchParentImpressionMetrics(objectGraph, searchResultsPage, metricsOptions) { + const parentIndex = currentPosition(metricsOptions.locationTracker); + searchResultsPage.guidedSearchTokensParentImpressionMetrics = new ImpressionMetrics({ + impressionIndex: parentIndex, + impressionType: "SearchRevisions", + idType: "relationship", + id: "search-revisions", + name: "Search Revisions", + }); +} +// endregion +//# sourceMappingURL=guided-search-metrics.js.map \ No newline at end of file diff --git a/node_modules/@jet-app/app-store/tmp/src/common/search/guided-search/guided-search.js b/node_modules/@jet-app/app-store/tmp/src/common/search/guided-search/guided-search.js new file mode 100644 index 0000000..3be4ae9 --- /dev/null +++ b/node_modules/@jet-app/app-store/tmp/src/common/search/guided-search/guided-search.js @@ -0,0 +1,105 @@ +/** + * Model Builder for Guided Search (STUB) + */ +import { GuidedSearchQuery, GuidedSearchToken, SearchAction, searchEntitySystemImage, } from "../../../api/models"; +import { GuidedSearchTokenToggleAction, SearchEntityChangeAction, } from "../../../api/models/search/guided-search-actions"; +import { isNullOrEmpty } from "../../../foundation/json-parsing/server-data"; +import { unreachable } from "../../../foundation/util/errors"; +import { addEventsToGuidedSearchTokenEntityChangeAction, addEventsToGuidedSearchTokenAction, addImpressionMetricsToGuidedSearchToken, } from "./guided-search-metrics"; +// region exports +/** + * Create a Guided search token from facet data. + * @param objectGraph The App Store object graph. + * @param selectionBehavior The behavior for click action, e.g. query rewrite versus toggling tokens. + * @param requestDescriptor The request descriptor for search request that returned this data. + * @param facetData The facet data to build with. + * @param metricsOptions The metrics options. + */ +export function createGuidedSearchToken(objectGraph, selectionBehavior, requestDescriptor, facetData, metricsOptions) { + if (isNullOrEmpty(facetData)) { + return null; + } + // Create click and search metrics for token action. + const origin = "guidedToken"; + const searchTerm = requestDescriptor.term; + const targetToken = facetData.displayLabel; + const clickAction = selectionBehavior === "rewrite" + ? new SearchAction(targetToken, facetData.finalTerm, null, origin) + : new GuidedSearchTokenToggleAction(targetToken, origin); + addEventsToGuidedSearchTokenAction(objectGraph, clickAction, targetToken, searchTerm, metricsOptions); + // Create the token with associated click action and metrics.. + const token = new GuidedSearchToken(targetToken, facetData.isSelected, undefined, targetToken, clickAction); + addImpressionMetricsToGuidedSearchToken(objectGraph, token, "guidedLabel", metricsOptions); + return token; +} +/** + * Create the guided search queries from facet data. + * These are stored across a guided search session so client can send down precomputed combinations of search term and guided search facets as an optimization. + * @param requestDescriptor The request descriptor for search request that returned this data. + * @param facetData The data to generate `GuidedSearchQuery` for. + */ +export function createGuidedSearchQueries(objectGraph, requestDescriptor, facetData) { + var _a; + if (isNullOrEmpty(facetData)) { + return null; + } + // request parameters that returned this `facetData` + const requestTerm = requestDescriptor.term; + const requestFacets = (_a = requestDescriptor.guidedSearchTokens) !== null && _a !== void 0 ? _a : []; + const queries = []; + for (const data of facetData) { + /** + * For each facet data, project the facet selection if that facet was selected / deselected w.r.t. request's facets + */ + const facetValue = data.displayLabel; + const lookaheadFacets = Array.from(requestFacets); + if (data.isSelected) { + const facetIndex = lookaheadFacets.indexOf(facetValue); + if (facetIndex !== -1) { + lookaheadFacets.splice(facetIndex, 1); + } + } + else { + lookaheadFacets.push(facetValue); + } + const query = new GuidedSearchQuery(requestTerm, lookaheadFacets, data.finalTerm); + queries.push(query); + } + return queries; +} +/** + * Create an action for **reversing** a selected entity hint. This is so user can reverse an selected entity filter for search. + * e.g. If user tapped "Search for Games in Apple Watch Apps", user can deselect the "Apple Watch Apps" entity filter from the Guided Search UI + */ +export function createGuidedSearchTokenClearingEntityFilter(objectGraph, requestDescriptor, metricsOptions) { + var _a; + const selectedEntityFilter = requestDescriptor.searchEntity; + if (!selectedEntityFilter) { + return null; + } + const deselectEntityAction = new SearchEntityChangeAction(null, "guidedToken"); + addEventsToGuidedSearchTokenEntityChangeAction(objectGraph, deselectEntityAction, requestDescriptor.term, selectedEntityFilter, metricsOptions); + let displayText; + switch (selectedEntityFilter) { + case "arcade": + displayText = objectGraph.loc.string("GUIDED_SEARCH_TOKEN_ENTITY_ARCADE"); + break; + case "developer": + displayText = objectGraph.loc.string("GUIDED_SEARCH_TOKEN_ENTITY_DEVELOPERS"); + break; + case "story": + displayText = objectGraph.loc.string("GUIDED_SEARCH_TOKEN_ENTITY_STORIES"); + break; + case "watch": + displayText = objectGraph.loc.string("GUIDED_SEARCH_TOKEN_ENTITY_APPLEWATCH"); + break; + default: + unreachable(selectedEntityFilter); + break; + } + const token = new GuidedSearchToken(displayText, true, (_a = searchEntitySystemImage(selectedEntityFilter)) !== null && _a !== void 0 ? _a : "magnifyingglass", displayText, deselectEntityAction); + addImpressionMetricsToGuidedSearchToken(objectGraph, token, "hintsEntity", metricsOptions); + return token; +} +// endregion +//# sourceMappingURL=guided-search.js.map \ No newline at end of file -- cgit v1.2.3