mirror of
				https://github.com/datahub-project/datahub.git
				synced 2025-10-31 18:59:23 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			193 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			193 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import {
 | |
|   ISearchResultClickTrackEventParams,
 | |
|   ICustomEventData,
 | |
|   IBaseTrackingEvent
 | |
| } from '@datahub/shared/types/tracking/event-tracking';
 | |
| import { inject as service } from '@ember/service';
 | |
| import RouterService from '@ember/routing/router-service';
 | |
| import DwellTime from '@datahub/shared/utils/tracking/dwell-time';
 | |
| import { Time } from '@datahub/metadata-types/types/common/time';
 | |
| import { action } from '@ember/object';
 | |
| import { searchTrackingEvent } from '@datahub/shared/constants/tracking/event-tracking/search';
 | |
| import Service from '@ember/service';
 | |
| import { isRouteEntityPageRoute } from '@datahub/data-models/utils/entity-route-name-resolver';
 | |
| import { SuccessfulDwellTimeLength, searchRouteName } from '@datahub/shared/constants/tracking/site-search-tracking';
 | |
| import Transition from '@ember/routing/-private/transition';
 | |
| import UnifiedTracking from '@datahub/shared/services/unified-tracking';
 | |
| import {
 | |
|   PageKey,
 | |
|   CustomTrackingEventName,
 | |
|   SearchActionEventCategory
 | |
| } from '@datahub/shared/constants/tracking/event-tracking';
 | |
| import CurrentUser from '@datahub/shared/services/current-user';
 | |
| import DataModelsService from '@datahub/data-models/services/data-models';
 | |
| import { DataModelName } from '@datahub/data-models/constants/entity';
 | |
| 
 | |
| /**
 | |
|  * Search service is used to maintain the same
 | |
|  * state on different parts of the app. Right now the only thing
 | |
|  * we need to persist is the keywords.
 | |
|  */
 | |
| export default class SearchService extends Service {
 | |
|   /**
 | |
|    * Keyword or query for the current search
 | |
|    */
 | |
|   keyword!: string;
 | |
| 
 | |
|   /**
 | |
|    * Data Models service to fetch unguarded entities
 | |
|    */
 | |
|   @service('data-models')
 | |
|   dataModels!: DataModelsService;
 | |
| 
 | |
|   /**
 | |
|    * Current entity of the search
 | |
|    */
 | |
|   entity?: DataModelName;
 | |
| 
 | |
|   /**
 | |
|    * Optional urn of the clicked search result
 | |
|    * @type {string}
 | |
|    */
 | |
|   private clickedSearchResultUrn?: string;
 | |
| 
 | |
|   /**
 | |
|    * On service instantiation a reference to a DwellTime instance is cached here to track dwell time
 | |
|    * @type {DwellTime}
 | |
|    * @memberof Search
 | |
|    */
 | |
|   dwellTimeTracker!: DwellTime;
 | |
| 
 | |
|   /**
 | |
|    * Injects the application CurrentUser service to provide the actor information on the action event
 | |
|    */
 | |
|   @service('current-user')
 | |
|   sessionUser!: CurrentUser;
 | |
| 
 | |
|   /**
 | |
|    * References the application service to track user events, metrics and interaction
 | |
|    */
 | |
|   @service('unified-tracking')
 | |
|   tracking!: UnifiedTracking;
 | |
| 
 | |
|   /**
 | |
|    * Router service used in tracking dwell time
 | |
|    */
 | |
|   @service
 | |
|   router!: RouterService;
 | |
| 
 | |
|   /**
 | |
|    * Performs a set of operation when a search result is clicked.
 | |
|    *
 | |
|    * Responsible for gathering the required parameters for tracking the click and passes them onto the `trackSearchCategoryEvent` method.
 | |
|    * @param {string} urn The urn associated with the clicked search result
 | |
|    * @param {number} absolutePosition The position of the specific result in regards with all the search-results
 | |
|    */
 | |
|   didClickSearchResult(urn: string, absolutePosition: number): void {
 | |
|     // When a search result is clicked, initiate dwell time tracking
 | |
|     this.dwellTimeTracker.beginTracking();
 | |
|     // Also, track event as a click event
 | |
|     this.clickedSearchResultUrn = urn;
 | |
|     const searchResultEventParams: ISearchResultClickTrackEventParams = {
 | |
|       baseSearchTrackingEvent: searchTrackingEvent.SearchResultClick,
 | |
|       actionCategory: SearchActionEventCategory.SearchClick,
 | |
|       absolutePosition,
 | |
|       facet: null
 | |
|     };
 | |
|     this.trackSearchActionEvent(searchResultEventParams);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the threshold value of the successful amount of dwell time on the component
 | |
|    * @instance
 | |
|    */
 | |
|   successfulDwellTimeLength = SuccessfulDwellTimeLength;
 | |
| 
 | |
|   /**
 | |
|    * Track SAT Click as an event
 | |
|    * 1) Time spent or more specifically dwell time on viewing the entity page (see DwellTime class for differentiation)
 | |
|    * @link {DwellTime}
 | |
|    * 2) navigation sequence i.e. click from a search implied by dwell time, that lands on an entity page
 | |
|    * @param {number} dwellTime
 | |
|    * @returns boolean
 | |
|    */
 | |
|   @action
 | |
|   trackSatClick(dwellTime: number, transition: Transition): boolean {
 | |
|     const isSATClick = this.isSATClick(dwellTime, transition);
 | |
|     if (isSATClick) {
 | |
|       this.trackSearchActionEvent({
 | |
|         baseSearchTrackingEvent: searchTrackingEvent.SearchResultSATClick,
 | |
|         actionCategory: SearchActionEventCategory.SearchSatClick,
 | |
|         absolutePosition: null,
 | |
|         facet: null
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     return isSATClick;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Creates attributes for tracking the search action event and invokes the tracking service.
 | |
|    *
 | |
|    * @param {ISearchResultClickTrackEventParams} searchResultEventParams A map consisting the current user's username, search query keyed in by the user , the positioning of the search result card in the list, the facet filters clicked by the user
 | |
|    */
 | |
|   trackSearchActionEvent(searchActionEventParams: ISearchResultClickTrackEventParams): void {
 | |
|     const { baseSearchTrackingEvent, absolutePosition, actionCategory, facet } = searchActionEventParams;
 | |
|     const userName = this.sessionUser.entity?.username || '';
 | |
| 
 | |
|     const baseEventAttrs: IBaseTrackingEvent = {
 | |
|       ...baseSearchTrackingEvent,
 | |
|       name: this.clickedSearchResultUrn
 | |
|     };
 | |
|     const customEventAttrs: ICustomEventData = {
 | |
|       pageKey: PageKey.searchCategory,
 | |
|       eventName: CustomTrackingEventName.SearchAction,
 | |
|       userName,
 | |
|       target: this.clickedSearchResultUrn,
 | |
|       body: {
 | |
|         requesterUrn: userName,
 | |
|         targetUrn: this.clickedSearchResultUrn,
 | |
|         actionCategory,
 | |
|         query: this.keyword,
 | |
|         absolutePosition,
 | |
|         facet
 | |
|       }
 | |
|     };
 | |
|     this.tracking.trackEvent(baseEventAttrs, customEventAttrs);
 | |
|   }
 | |
| 
 | |
|   init(): void {
 | |
|     super.init();
 | |
| 
 | |
|     // Instantiate a DwellTime instance to track dwell time, which is essentially time spent on a search result page
 | |
|     this.dwellTimeTracker = new DwellTime(searchRouteName, this.router, this.trackSatClick);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Determines if the click can be judged as a satisfied click
 | |
|    * @param {Time} dwellTime the amount of time in milliseconds the user has dwelled on the page
 | |
|    * @param {Transition} { to, from } the current ember transition object containing the RouteInfo object being transitioned to or from
 | |
|    */
 | |
|   isSATClick(dwellTime: Time, { to, from }: Transition): boolean {
 | |
|     const isReturningToSearch = Boolean(to && to.name === searchRouteName);
 | |
|     // If the user is returning to the search page, check if the dwellTime is meets or exceeds what is considered a successful amount of time
 | |
|     const isSufficientDwellTimeOnSearchReturn = isReturningToSearch && dwellTime >= this.successfulDwellTimeLength;
 | |
| 
 | |
|     // If the dwell time is sufficient and the user is returning to search, or the user is navigating away from an entity route
 | |
|     // to a route that is not search this is considered a satisfied click
 | |
|     return (
 | |
|       isSufficientDwellTimeOnSearchReturn ||
 | |
|       (isRouteEntityPageRoute(from, this.dataModels.guards.unGuardedEntitiesDisplayName) && !isReturningToSearch)
 | |
|     );
 | |
|   }
 | |
| }
 | |
| 
 | |
| // DO NOT DELETE: this is how TypeScript knows how to look up your services.
 | |
| declare module '@ember/service' {
 | |
|   // This is a core ember thing
 | |
|   //eslint-disable-next-line @typescript-eslint/interface-name-prefix
 | |
|   interface Registry {
 | |
|     search: SearchService;
 | |
|   }
 | |
| }
 | 
