fix typing

This commit is contained in:
Nicolas Dorseuil
2025-06-18 12:27:58 +02:00
parent 0004d0228d
commit c49b3a8e90
12 changed files with 158 additions and 87 deletions
@@ -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(
@@ -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(
@@ -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
}
>
@@ -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<DocumentBlockFile>) {
<Link
href={file.downloadURL}
download={file.name}
insights={{
insights={toSlimTrackEvent({
type: 'link_click',
link: {
target: block.data.ref,
position: SiteInsightsLinkPosition.Content,
},
}}
})}
className={tcls('group/file', 'flex', 'flex-row', 'items-center', 'px-5', 'py-3')}
>
<div
@@ -173,7 +173,7 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
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<Tag extends React.ElementType = 'div'>(
},
position: SiteInsightsLinkPosition.Content,
},
}
})
: undefined
}
>
@@ -236,13 +236,13 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
href={resolved.href}
insights={
contentRef
? {
? toSlimTrackEvent({
type: 'link_click',
link: {
target: contentRef,
position: SiteInsightsLinkPosition.Content,
},
}
})
: undefined
}
>
@@ -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<HeaderLinkNavItemProps, 'linkStyle'>) {
<Link
href={href}
className={getHeaderLinkClassName({ headerPreset })}
insights={{
insights={toSlimTrackEvent({
type: 'link_click',
link: {
target: linkTarget,
position: SiteInsightsLinkPosition.Header,
},
}}
})}
{...rest}
>
{title}
@@ -217,13 +218,13 @@ async function SubHeaderLink(props: {
return (
<DropdownMenuItem
href={target.href}
insights={{
insights={toSlimTrackEvent({
type: 'link_click',
link: {
target: link.to,
position: SiteInsightsLinkPosition.Header,
},
}}
})}
>
{link.title}
</DropdownMenuItem>
@@ -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
}
>
@@ -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<InsightsEventName> {
type BaseSlimTrackEvent<T extends SlimTrackEventName> = {
t: T; // type
};
export type SlimTrackEventInput<T extends SlimTrackEventName = SlimTrackEventName> = 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<EventName extends SlimTrackEventName = SlimTrackEventName>(
input: SlimTrackEventInput<EventName>
) {
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<InsightsEventName>): SlimTrackEventInput {
export function toSlimTrackEvent<EventName extends InsightsEventName>(
event: TrackEventInput<EventName>
) {
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');
}
@@ -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}
</div>
@@ -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: {
<ToggleableLinkItem
href={href}
pathname={getPagePath(rootPages, page)}
insights={{
insights={toSlimTrackEvent({
type: 'link_click',
link: {
target: {
@@ -37,7 +38,7 @@ export async function PageDocumentItem(props: {
},
position: SiteInsightsLinkPosition.Sidebar,
},
}}
})}
descendants={
hasPageVisibleDescendant(page) ? (
<PagesList
@@ -6,6 +6,7 @@ import { Link } from '@/components/primitives';
import { resolveContentRef } from '@/lib/references';
import { tcls } from '@/lib/tailwind';
import { toSlimTrackEvent } from '../Insights';
import { TOCPageIcon } from './TOCPageIcon';
export async function PageLinkItem(props: { page: RevisionPageLink; context: GitBookSiteContext }) {
@@ -36,13 +37,13 @@ export async function PageLinkItem(props: { page: RevisionPageLink; context: Git
'hover:bg-tint',
'hover:text-tint-strong'
)}
insights={{
insights={toSlimTrackEvent({
type: 'link_click',
link: {
target: page.target,
position: SiteInsightsLinkPosition.Sidebar,
},
}}
})}
>
<TOCPageIcon page={page} />
{page.title}
@@ -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,
}}
})}
>
<Icon
icon="gitbook"