From 4f3588240c2aaeae98852bbd0cc02b4944ec3aa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samy=20Pess=C3=A9?= Date: Fri, 29 Aug 2025 16:10:28 +0200 Subject: [PATCH] Unify layout and fix tracking of ask_question (#3610) --- .changeset/ten-files-talk.md | 5 + .../[siteData]/~gitbook/embed/layout.tsx | 15 +- .../[siteData]/~gitbook/embed/layout.tsx | 14 +- packages/gitbook/src/components/AI/index.ts | 1 + .../Embeddable/EmbeddableRootLayout.tsx | 21 +- .../components/Insights/InsightsProvider.tsx | 4 +- .../src/components/SiteLayout/SiteLayout.tsx | 18 +- .../components/SpaceLayout/SpaceLayout.tsx | 222 ++++++++++-------- 8 files changed, 179 insertions(+), 121 deletions(-) create mode 100644 .changeset/ten-files-talk.md diff --git a/.changeset/ten-files-talk.md b/.changeset/ten-files-talk.md new file mode 100644 index 000000000..f7c4057bc --- /dev/null +++ b/.changeset/ten-files-talk.md @@ -0,0 +1,5 @@ +--- +"gitbook": patch +--- + +Fix event ask_question not being tracked diff --git a/packages/gitbook/src/app/sites/dynamic/[mode]/[siteURL]/[siteData]/~gitbook/embed/layout.tsx b/packages/gitbook/src/app/sites/dynamic/[mode]/[siteURL]/[siteData]/~gitbook/embed/layout.tsx index ba7774691..36a75310a 100644 --- a/packages/gitbook/src/app/sites/dynamic/[mode]/[siteURL]/[siteData]/~gitbook/embed/layout.tsx +++ b/packages/gitbook/src/app/sites/dynamic/[mode]/[siteURL]/[siteData]/~gitbook/embed/layout.tsx @@ -5,6 +5,8 @@ import { generateEmbeddableViewport, } from '@/components/Embeddable'; import { getEmbeddableStaticContext } from '@/lib/embeddable'; +import { shouldTrackEvents } from '@/lib/tracking'; +import { headers } from 'next/headers'; interface SiteStaticLayoutProps { params: Promise; @@ -14,9 +16,18 @@ export default async function RootLayout({ params, children, }: React.PropsWithChildren) { - const { context } = await getEmbeddableStaticContext(await params); + const { context, visitorAuthClaims } = await getEmbeddableStaticContext(await params); + const withTracking = shouldTrackEvents(await headers()); - return {children}; + return ( + + {children} + + ); } export async function generateViewport({ params }: SiteStaticLayoutProps) { diff --git a/packages/gitbook/src/app/sites/static/[mode]/[siteURL]/[siteData]/~gitbook/embed/layout.tsx b/packages/gitbook/src/app/sites/static/[mode]/[siteURL]/[siteData]/~gitbook/embed/layout.tsx index ba7774691..01a28af48 100644 --- a/packages/gitbook/src/app/sites/static/[mode]/[siteURL]/[siteData]/~gitbook/embed/layout.tsx +++ b/packages/gitbook/src/app/sites/static/[mode]/[siteURL]/[siteData]/~gitbook/embed/layout.tsx @@ -5,6 +5,7 @@ import { generateEmbeddableViewport, } from '@/components/Embeddable'; import { getEmbeddableStaticContext } from '@/lib/embeddable'; +import { shouldTrackEvents } from '@/lib/tracking'; interface SiteStaticLayoutProps { params: Promise; @@ -14,9 +15,18 @@ export default async function RootLayout({ params, children, }: React.PropsWithChildren) { - const { context } = await getEmbeddableStaticContext(await params); + const { context, visitorAuthClaims } = await getEmbeddableStaticContext(await params); + const withTracking = shouldTrackEvents(); - return {children}; + return ( + + {children} + + ); } export async function generateViewport({ params }: SiteStaticLayoutProps) { diff --git a/packages/gitbook/src/components/AI/index.ts b/packages/gitbook/src/components/AI/index.ts index 915c4f875..c7e0827a2 100644 --- a/packages/gitbook/src/components/AI/index.ts +++ b/packages/gitbook/src/components/AI/index.ts @@ -1,2 +1,3 @@ export * from './useAI'; export * from './useAIChat'; +export type { RenderAIMessageOptions } from './server-actions'; diff --git a/packages/gitbook/src/components/Embeddable/EmbeddableRootLayout.tsx b/packages/gitbook/src/components/Embeddable/EmbeddableRootLayout.tsx index fec1269d4..104d50a3a 100644 --- a/packages/gitbook/src/components/Embeddable/EmbeddableRootLayout.tsx +++ b/packages/gitbook/src/components/Embeddable/EmbeddableRootLayout.tsx @@ -1,16 +1,20 @@ -import { AIChatProvider, AIContextProvider } from '@/components/AI'; +import { AIContextProvider } from '@/components/AI'; import { CustomizationRootLayout } from '@/components/RootLayout'; import { SiteLayoutClientContexts, generateSiteLayoutMetadata, generateSiteLayoutViewport, } from '@/components/SiteLayout'; +import type { VisitorAuthClaims } from '@/lib/adaptive'; import type { GitBookSiteContext } from '@/lib/context'; import { CustomizationAIMode } from '@gitbook/api'; +import { SpaceLayoutServerContext } from '../SpaceLayout'; import { EmbeddableIframeAPI } from './EmbeddableIframeAPI'; type EmbeddableRootLayoutProps = { context: GitBookSiteContext; + withTracking: boolean; + visitorAuthClaims: VisitorAuthClaims; }; /** @@ -18,6 +22,8 @@ type EmbeddableRootLayoutProps = { */ export async function EmbeddableRootLayout({ context, + withTracking, + visitorAuthClaims, children, }: React.PropsWithChildren) { return ( @@ -31,8 +37,11 @@ export async function EmbeddableRootLayout({ aiMode={CustomizationAIMode.Assistant} trademark={context.customization.trademark.enabled} > - - + ); } -export async function generateEmbeddableViewport({ context }: EmbeddableRootLayoutProps) { +export async function generateEmbeddableViewport({ context }: { context: GitBookSiteContext }) { return generateSiteLayoutViewport(context); } -export async function generateEmbeddableMetadata({ context }: EmbeddableRootLayoutProps) { +export async function generateEmbeddableMetadata({ context }: { context: GitBookSiteContext }) { return generateSiteLayoutMetadata(context); } diff --git a/packages/gitbook/src/components/Insights/InsightsProvider.tsx b/packages/gitbook/src/components/Insights/InsightsProvider.tsx index 82892567d..b36bccc7f 100644 --- a/packages/gitbook/src/components/Insights/InsightsProvider.tsx +++ b/packages/gitbook/src/components/Insights/InsightsProvider.tsx @@ -46,7 +46,9 @@ type TrackEventCallback = ( options?: InsightsEventOptions ) => void; -const InsightsContext = React.createContext(() => {}); +const InsightsContext = React.createContext(() => { + console.error('useTrackEvent must be used within an InsightsProvider'); +}); interface InsightsProviderProps { /** If true, the events will be sent to the server. */ diff --git a/packages/gitbook/src/components/SiteLayout/SiteLayout.tsx b/packages/gitbook/src/components/SiteLayout/SiteLayout.tsx index 329fd7b37..0e1460d44 100644 --- a/packages/gitbook/src/components/SiteLayout/SiteLayout.tsx +++ b/packages/gitbook/src/components/SiteLayout/SiteLayout.tsx @@ -13,7 +13,7 @@ import { buildVersion } from '@/lib/build'; import { GITBOOK_API_PUBLIC_URL, GITBOOK_ASSETS_URL, GITBOOK_ICONS_URL } from '@/lib/env'; import { getResizedImageURL } from '@/lib/images'; import { isSiteIndexable } from '@/lib/seo'; -import { AIChatProvider, AIContextProvider } from '../AI'; +import { AIContextProvider } from '../AI'; import { RocketLoaderDetector } from './RocketLoaderDetector'; import { SiteLayoutClientContexts } from './SiteLayoutClientContexts'; @@ -58,15 +58,13 @@ export async function SiteLayout(props: { aiMode={customization.ai?.mode} trademark={customization.trademark.enabled} > - - - {children} - - + + {children} + {scripts.length > 0 ? ( diff --git a/packages/gitbook/src/components/SpaceLayout/SpaceLayout.tsx b/packages/gitbook/src/components/SpaceLayout/SpaceLayout.tsx index 1b2ca9709..ee369afbe 100644 --- a/packages/gitbook/src/components/SpaceLayout/SpaceLayout.tsx +++ b/packages/gitbook/src/components/SpaceLayout/SpaceLayout.tsx @@ -14,6 +14,8 @@ import { tcls } from '@/lib/tailwind'; import type { VisitorAuthClaims } from '@/lib/adaptive'; import { GITBOOK_APP_URL } from '@/lib/env'; +import { AIChatProvider } from '../AI'; +import type { RenderAIMessageOptions } from '../AI'; import { AIChat } from '../AIChat'; import { Announcement } from '../Announcement'; import { SpacesDropdown } from '../Header/SpacesDropdown'; @@ -23,10 +25,7 @@ import { SiteSectionList, encodeClientSiteSections } from '../SiteSections'; import { CurrentContentProvider } from '../hooks'; import { SpaceLayoutContextProvider } from './SpaceLayoutContext'; -/** - * Render the entire layout of the space (header, table of contents, footer). - */ -export function SpaceLayout(props: { +type SpaceLayoutProps = { context: GitBookSiteContext; /** Whether to enable tracking of events into site insights. */ @@ -35,22 +34,21 @@ export function SpaceLayout(props: { /** The visitor auth claims. */ visitorAuthClaims: VisitorAuthClaims; + /** The options for rendering AI messages. */ + aiChatRenderMessageOptions?: RenderAIMessageOptions; + /** The children of the layout. */ children: React.ReactNode; -}) { - const { context, withTracking, visitorAuthClaims, children } = props; - const { siteSpace, customization, sections, siteSpaces } = context; +}; - const withTopHeader = customization.header.preset !== CustomizationHeaderPreset.None; +/** + * Provide all contexts for a space. + */ +export function SpaceLayoutServerContext(props: SpaceLayoutProps) { + const { context, withTracking, visitorAuthClaims, aiChatRenderMessageOptions, children } = + props; - const withSections = Boolean(sections && sections.list.length > 1); - const isMultiVariants = Boolean(siteSpaces.length > 1); - - const withFooter = - customization.themes.toggeable || - customization.footer.copyright || - customization.footer.logo || - customization.footer.groups?.length; + const { customization } = context; const eventUrl = new URL( context.linker.toAbsoluteURL(context.linker.toPathInSite('/~gitbook/__evt')) @@ -76,92 +74,116 @@ export function SpaceLayout(props: { eventUrl={eventUrl.toString()} visitorCookieTrackingEnabled={customization.insights?.trackingCookie} > - -
- {customization.ai?.mode === CustomizationAIMode.Assistant ? ( - - ) : null} - -
-
- - -
- ) - } - innerHeader={ - // displays the search button and/or the space dropdown in the ToC according to the header/variant settings. E.g if there is no header, the search button will be displayed in the ToC. - <> - {!withTopHeader && ( - 1} - spaceTitle={siteSpace.title} - siteSpaceId={siteSpace.id} - className="max-lg:hidden" - viewport="desktop" - /> - )} - {!withTopHeader && withSections && sections && ( - - )} - {isMultiVariants && !sections && ( - - )} - - } - /> -
{children}
-
- - - {withFooter ?