From c49b3a8e901fb5c330b20f9ffda40de94aa06bca Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Wed, 18 Jun 2025 12:27:58 +0200 Subject: [PATCH] fix typing --- .../src/components/Ads/AdClassicRendering.tsx | 5 +- .../src/components/Ads/AdCoverRendering.tsx | 5 +- .../Announcement/AnnouncementBanner.tsx | 5 +- .../src/components/DocumentView/File.tsx | 5 +- .../DocumentView/Table/RecordColumnValue.tsx | 8 +- .../src/components/Header/HeaderLink.tsx | 13 +- .../src/components/Header/HeaderLinkMore.tsx | 5 +- .../src/components/Insights/slimTrackEvent.ts | 175 ++++++++++++------ .../PageBody/PageFooterNavigation.tsx | 9 +- .../TableOfContents/PageDocumentItem.tsx | 5 +- .../TableOfContents/PageLinkItem.tsx | 5 +- .../components/TableOfContents/Trademark.tsx | 5 +- 12 files changed, 158 insertions(+), 87 deletions(-) diff --git a/packages/gitbook/src/components/Ads/AdClassicRendering.tsx b/packages/gitbook/src/components/Ads/AdClassicRendering.tsx index 82613af49..490749fbb 100644 --- a/packages/gitbook/src/components/Ads/AdClassicRendering.tsx +++ b/packages/gitbook/src/components/Ads/AdClassicRendering.tsx @@ -4,6 +4,7 @@ import { getResizedImageURL } from '@v2/lib/images'; import { tcls } from '@/lib/tailwind'; +import { toSlimTrackEvent } from '../Insights'; import { Link } from '../primitives'; import type { AdItem } from './types'; @@ -33,10 +34,10 @@ export async function AdClassicRendering({ target="_blank" insights={ insightsAd - ? { + ? toSlimTrackEvent({ type: 'ad_click', ad: insightsAd, - } + }) : undefined } className={tcls( diff --git a/packages/gitbook/src/components/Ads/AdCoverRendering.tsx b/packages/gitbook/src/components/Ads/AdCoverRendering.tsx index 4b073e867..e897fd1a0 100644 --- a/packages/gitbook/src/components/Ads/AdCoverRendering.tsx +++ b/packages/gitbook/src/components/Ads/AdCoverRendering.tsx @@ -5,6 +5,7 @@ import { getResizedImageURL } from '@v2/lib/images'; import { tcls } from '@/lib/tailwind'; +import { toSlimTrackEvent } from '../Insights'; import { Link } from '../primitives'; import type { AdCover } from './types'; @@ -31,10 +32,10 @@ export async function AdCoverRendering({ target="_blank" insights={ insightsAd - ? { + ? toSlimTrackEvent({ type: 'ad_click', ad: insightsAd, - } + }) : undefined } className={tcls( diff --git a/packages/gitbook/src/components/Announcement/AnnouncementBanner.tsx b/packages/gitbook/src/components/Announcement/AnnouncementBanner.tsx index 2b07504f3..a7df1f8cd 100644 --- a/packages/gitbook/src/components/Announcement/AnnouncementBanner.tsx +++ b/packages/gitbook/src/components/Announcement/AnnouncementBanner.tsx @@ -6,6 +6,7 @@ import type { ResolvedContentRef } from '@/lib/references'; import { tcls } from '@/lib/tailwind'; import { type CustomizationAnnouncement, SiteInsightsLinkPosition } from '@gitbook/api'; import { Icon, type IconName } from '@gitbook/icons'; +import { toSlimTrackEvent } from '../Insights'; import { CONTAINER_STYLE } from '../layout'; import { Link, linkStyles } from '../primitives'; import { ANNOUNCEMENT_CSS_CLASS, ANNOUNCEMENT_STORAGE_KEY } from './constants'; @@ -41,13 +42,13 @@ export function AnnouncementBanner(props: { )} insights={ announcement.link - ? { + ? toSlimTrackEvent({ type: 'link_click', link: { target: announcement.link.to, position: SiteInsightsLinkPosition.Announcement, }, - } + }) : undefined } > diff --git a/packages/gitbook/src/components/DocumentView/File.tsx b/packages/gitbook/src/components/DocumentView/File.tsx index fe72164fc..4b7577280 100644 --- a/packages/gitbook/src/components/DocumentView/File.tsx +++ b/packages/gitbook/src/components/DocumentView/File.tsx @@ -4,6 +4,7 @@ import { getSimplifiedContentType } from '@/lib/files'; import { resolveContentRef } from '@/lib/references'; import { tcls } from '@/lib/tailwind'; +import { toSlimTrackEvent } from '../Insights'; import { Link } from '../primitives'; import type { BlockProps } from './Block'; import { Caption } from './Caption'; @@ -28,13 +29,13 @@ export async function File(props: BlockProps) {
( className="flex flex-row items-center gap-2" insights={ ref.file - ? { + ? toSlimTrackEvent({ type: 'link_click', link: { target: { @@ -182,7 +182,7 @@ export async function RecordColumnValue( }, position: SiteInsightsLinkPosition.Content, }, - } + }) : undefined } > @@ -236,13 +236,13 @@ export async function RecordColumnValue( href={resolved.href} insights={ contentRef - ? { + ? toSlimTrackEvent({ type: 'link_click', link: { target: contentRef, position: SiteInsightsLinkPosition.Content, }, - } + }) : undefined } > diff --git a/packages/gitbook/src/components/Header/HeaderLink.tsx b/packages/gitbook/src/components/Header/HeaderLink.tsx index 6b13fef71..38387434e 100644 --- a/packages/gitbook/src/components/Header/HeaderLink.tsx +++ b/packages/gitbook/src/components/Header/HeaderLink.tsx @@ -11,6 +11,7 @@ import assertNever from 'assert-never'; import { resolveContentRef } from '@/lib/references'; import { tcls } from '@/lib/tailwind'; +import { toSlimTrackEvent } from '../Insights'; import { Button, Link } from '../primitives'; import { type DropdownButtonProps, @@ -125,13 +126,13 @@ function HeaderItemButton( ), }[linkStyle] )} - insights={{ + insights={toSlimTrackEvent({ type: 'link_click', link: { target: linkTarget, position: SiteInsightsLinkPosition.Header, }, - }} + })} label={title} {...rest} /> @@ -169,13 +170,13 @@ function HeaderItemLink(props: Omit) { {title} @@ -217,13 +218,13 @@ async function SubHeaderLink(props: { return ( {link.title} diff --git a/packages/gitbook/src/components/Header/HeaderLinkMore.tsx b/packages/gitbook/src/components/Header/HeaderLinkMore.tsx index 7954b80ec..63abdea90 100644 --- a/packages/gitbook/src/components/Header/HeaderLinkMore.tsx +++ b/packages/gitbook/src/components/Header/HeaderLinkMore.tsx @@ -10,6 +10,7 @@ import type React from 'react'; import { resolveContentRef } from '@/lib/references'; import { tcls } from '@/lib/tailwind'; +import { toSlimTrackEvent } from '../Insights'; import { DropdownChevron, DropdownMenu, DropdownMenuItem, DropdownSubMenu } from './DropdownMenu'; import styles from './headerLinks.module.css'; @@ -80,13 +81,13 @@ async function MoreMenuLink(props: { href={target?.href ?? null} insights={ link.to - ? { + ? toSlimTrackEvent({ type: 'link_click', link: { target: link.to, position: SiteInsightsLinkPosition.Header, }, - } + }) : undefined } > diff --git a/packages/gitbook/src/components/Insights/slimTrackEvent.ts b/packages/gitbook/src/components/Insights/slimTrackEvent.ts index 731f3ff59..4483a8ea2 100644 --- a/packages/gitbook/src/components/Insights/slimTrackEvent.ts +++ b/packages/gitbook/src/components/Insights/slimTrackEvent.ts @@ -1,98 +1,159 @@ import type * as api from '@gitbook/api'; import type { InsightsEventName, TrackEventInput } from './InsightsProvider'; -export type SlimTrackEventInput = - | { t: 'pv' } - | { t: 'so' } - | { t: 'stq'; q: string } - | { t: 'sor'; q: string; r: { s: string; p: string } } - | { t: 'ppf'; f: { r: api.PageFeedbackRating } } - | { t: 'ppfc'; f: { r: api.PageFeedbackRating; c: string } } - | { t: 'aq'; q: string } - | { t: 'lc'; l: { t: api.ContentRef; p: api.SiteInsightsLinkPosition } } - | { t: 'aco'; o: api.OpenAPIOperationPointer } - | { t: 'acr'; o: api.OpenAPIOperationPointer } - | { t: 'tc'; p: api.SiteInsightsTrademarkPlacement } - | { t: 'ac'; a: api.SiteInsightsAd } - | { t: 'ad'; a: api.SiteInsightsAd }; +type SlimTrackEventName = + | 'pv' // page_view + | 'so' // search_open + | 'stq' // search_type_query + | 'sor' // search_open_result + | 'ppf' // page_post_feedback + | 'ppfc' // page_post_feedback_comment + | 'aq' // ask_question + | 'lc' // link_click + | 'aco' // api_client_open + | 'acr' // api_client_request + | 'tc' // trademark_click + | 'ac' // ad_click + | 'ad'; // ad_display -export function expandSlimTrackEvent( - input: SlimTrackEventInput -): TrackEventInput { +type BaseSlimTrackEvent = { + t: T; // type +}; + +export type SlimTrackEventInput = T extends 'pv' + ? BaseSlimTrackEvent<'pv'> + : T extends 'so' + ? BaseSlimTrackEvent<'so'> + : T extends 'stq' + ? BaseSlimTrackEvent<'stq'> & { q: string } + : T extends 'sor' + ? BaseSlimTrackEvent<'sor'> & { q: string; r: { s: string; p: string } } + : T extends 'ppf' + ? BaseSlimTrackEvent<'ppf'> & { f: { r: api.PageFeedbackRating } } + : T extends 'ppfc' + ? BaseSlimTrackEvent<'ppfc'> & { f: { r: api.PageFeedbackRating; c: string } } + : T extends 'aq' + ? BaseSlimTrackEvent<'aq'> & { q: string } + : T extends 'lc' + ? BaseSlimTrackEvent<'lc'> & { + l: { t: api.ContentRef; p: api.SiteInsightsLinkPosition }; + } + : T extends 'aco' + ? BaseSlimTrackEvent<'aco'> & { o: api.OpenAPIOperationPointer } + : T extends 'acr' + ? BaseSlimTrackEvent<'acr'> & { o: api.OpenAPIOperationPointer } + : T extends 'tc' + ? BaseSlimTrackEvent<'tc'> & { p: api.SiteInsightsTrademarkPlacement } + : T extends 'ac' + ? BaseSlimTrackEvent<'ac'> & { a: api.SiteInsightsAd } + : T extends 'ad' + ? BaseSlimTrackEvent<'ad'> & { a: api.SiteInsightsAd } + : never; + +export function expandSlimTrackEvent( + input: SlimTrackEventInput +) { switch (input.t) { case 'pv': - return { type: 'page_view' }; + return { type: 'page_view' as const }; case 'so': - return { type: 'search_open' }; + return { type: 'search_open' as const }; case 'stq': - return { type: 'search_type_query', query: input.q }; + return { type: 'search_type_query' as const, query: input.q }; case 'sor': return { - type: 'search_open_result', + type: 'search_open_result' as const, query: input.q, result: { spaceId: input.r.s, pageId: input.r.p }, }; case 'ppf': - return { type: 'page_post_feedback', feedback: { rating: input.f.r } }; + return { type: 'page_post_feedback' as const, feedback: { rating: input.f.r } }; case 'ppfc': return { - type: 'page_post_feedback_comment', + type: 'page_post_feedback_comment' as const, feedback: { rating: input.f.r, comment: input.f.c }, }; case 'aq': - return { type: 'ask_question', query: input.q }; + return { type: 'ask_question' as const, query: input.q }; case 'lc': return { - type: 'link_click', + type: 'link_click' as const, link: { target: input.l.t, position: input.l.p }, }; case 'aco': - return { type: 'api_client_open', operation: input.o }; + return { type: 'api_client_open' as const, operation: input.o }; case 'acr': - return { type: 'api_client_request', operation: input.o }; + return { type: 'api_client_request' as const, operation: input.o }; case 'tc': - return { type: 'trademark_click', placement: input.p }; + return { type: 'trademark_click' as const, placement: input.p }; case 'ac': - return { type: 'ad_click', ad: input.a }; + return { type: 'ad_click' as const, ad: input.a }; case 'ad': - return { type: 'ad_display', ad: input.a }; + return { type: 'ad_display' as const, ad: input.a }; default: throw new Error('Unknown slim event'); } } -export function toSlimTrackEvent(event: TrackEventInput): SlimTrackEventInput { +export function toSlimTrackEvent( + event: TrackEventInput +) { switch (event.type) { case 'page_view': - return { t: 'pv' }; + return { t: 'pv' as const }; case 'search_open': - return { t: 'so' }; - case 'search_type_query': - return { t: 'stq', q: event.query }; - case 'search_open_result': + return { t: 'so' as const }; + case 'search_type_query': { + const _event = event as unknown as TrackEventInput<'search_type_query'>; + return { t: 'stq' as const, q: _event.query }; + } + case 'search_open_result': { + const _event = event as unknown as TrackEventInput<'search_open_result'>; return { - t: 'sor', - q: event.query, - r: { s: event.result.spaceId, p: event.result.pageId }, + t: 'sor' as const, + q: _event.query, + r: { s: _event.result.spaceId, p: _event.result.pageId }, }; - case 'page_post_feedback': - return { t: 'ppf', f: { r: event.feedback.rating } }; - case 'page_post_feedback_comment': - return { t: 'ppfc', f: { r: event.feedback.rating, c: event.feedback.comment } }; - case 'ask_question': - return { t: 'aq', q: event.query }; - case 'link_click': - return { t: 'lc', l: { t: event.link.target, p: event.link.position } }; - case 'api_client_open': - return { t: 'aco', o: event.operation }; - case 'api_client_request': - return { t: 'acr', o: event.operation }; - case 'trademark_click': - return { t: 'tc', p: event.placement }; - case 'ad_click': - return { t: 'ac', a: event.ad }; - case 'ad_display': - return { t: 'ad', a: event.ad }; + } + case 'page_post_feedback': { + const _event = event as unknown as TrackEventInput<'page_post_feedback'>; + return { t: 'ppf' as const, f: { r: _event.feedback.rating } }; + } + case 'page_post_feedback_comment': { + const _event = event as unknown as TrackEventInput<'page_post_feedback_comment'>; + return { + t: 'ppfc' as const, + f: { r: _event.feedback.rating, c: _event.feedback.comment }, + }; + } + case 'ask_question': { + const _event = event as unknown as TrackEventInput<'ask_question'>; + return { t: 'aq' as const, q: _event.query }; + } + case 'link_click': { + const _event = event as unknown as TrackEventInput<'link_click'>; + return { t: 'lc' as const, l: { t: _event.link.target, p: _event.link.position } }; + } + case 'api_client_open': { + const _event = event as unknown as TrackEventInput<'api_client_open'>; + return { t: 'aco' as const, o: _event.operation }; + } + case 'api_client_request': { + const _event = event as unknown as TrackEventInput<'api_client_request'>; + return { t: 'acr' as const, o: _event.operation }; + } + case 'trademark_click': { + const _event = event as unknown as TrackEventInput<'trademark_click'>; + return { t: 'tc' as const, p: _event.placement }; + } + case 'ad_click': { + const _event = event as unknown as TrackEventInput<'ad_click'>; + return { t: 'ac' as const, a: _event.ad }; + } + case 'ad_display': { + const _event = event as unknown as TrackEventInput<'ad_display'>; + return { t: 'ad' as const, a: _event.ad }; + } default: throw new Error('Unknown event type'); } diff --git a/packages/gitbook/src/components/PageBody/PageFooterNavigation.tsx b/packages/gitbook/src/components/PageBody/PageFooterNavigation.tsx index a6be37d41..1c9ce1b2b 100644 --- a/packages/gitbook/src/components/PageBody/PageFooterNavigation.tsx +++ b/packages/gitbook/src/components/PageBody/PageFooterNavigation.tsx @@ -7,6 +7,7 @@ import { resolvePrevNextPages } from '@/lib/pages'; import { tcls } from '@/lib/tailwind'; import type { GitBookSiteContext } from '@v2/lib/context'; +import { toSlimTrackEvent } from '../Insights'; import { Link, type LinkInsightsProps } from '../primitives'; /** @@ -43,7 +44,7 @@ export async function PageFooterNavigation(props: { label={t(language, 'previous_page')} title={previous.title} href={previousHref} - insights={{ + insights={toSlimTrackEvent({ type: 'link_click', link: { target: { @@ -52,7 +53,7 @@ export async function PageFooterNavigation(props: { }, position: SiteInsightsLinkPosition.Content, }, - }} + })} reversed /> ) : null} @@ -62,7 +63,7 @@ export async function PageFooterNavigation(props: { label={t(language, 'next_page')} title={next.title} href={nextHref} - insights={{ + insights={toSlimTrackEvent({ type: 'link_click', link: { target: { @@ -71,7 +72,7 @@ export async function PageFooterNavigation(props: { }, position: SiteInsightsLinkPosition.Content, }, - }} + })} /> ) : null}
diff --git a/packages/gitbook/src/components/TableOfContents/PageDocumentItem.tsx b/packages/gitbook/src/components/TableOfContents/PageDocumentItem.tsx index 4875633ac..4181625fc 100644 --- a/packages/gitbook/src/components/TableOfContents/PageDocumentItem.tsx +++ b/packages/gitbook/src/components/TableOfContents/PageDocumentItem.tsx @@ -7,6 +7,7 @@ import { } from '@gitbook/api'; import type { GitBookSiteContext } from '@v2/lib/context'; +import { toSlimTrackEvent } from '../Insights'; import { PagesList } from './PagesList'; import { TOCPageIcon } from './TOCPageIcon'; import { ToggleableLinkItem } from './ToggleableLinkItem'; @@ -28,7 +29,7 @@ export async function PageDocumentItem(props: { {page.title} diff --git a/packages/gitbook/src/components/TableOfContents/Trademark.tsx b/packages/gitbook/src/components/TableOfContents/Trademark.tsx index aa2d37c0a..e51d5ccea 100644 --- a/packages/gitbook/src/components/TableOfContents/Trademark.tsx +++ b/packages/gitbook/src/components/TableOfContents/Trademark.tsx @@ -8,6 +8,7 @@ import { Icon } from '@gitbook/icons'; import { getSpaceLanguage, t } from '@/intl/server'; import { tcls } from '@/lib/tailwind'; +import { toSlimTrackEvent } from '../Insights'; import { Link } from '../primitives'; /** @@ -115,10 +116,10 @@ export function TrademarkLink(props: { 'transition-colors', 'pointer-events-auto' )} - insights={{ + insights={toSlimTrackEvent({ type: 'trademark_click', placement, - }} + })} >