Skip to content

Commit 77fd393

Browse files
authored
Fix click on search items when embedded in an iframe and track announcement links (#3061)
1 parent 8701b5e commit 77fd393

File tree

13 files changed

+141
-76
lines changed

13 files changed

+141
-76
lines changed

.changeset/flat-pigs-greet.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"gitbook": minor
3+
---
4+
5+
Track event when visitor is opening a search result.

.changeset/lovely-countries-smoke.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"gitbook": patch
3+
---
4+
5+
Fix clicking search results when the site is embedded in an iframe.

.changeset/rude-crabs-enjoy.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"gitbook": minor
3+
---
4+
5+
Track event when clicking announcement banner link.

bun.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@
262262
},
263263
"overrides": {
264264
"@codemirror/state": "6.4.1",
265-
"@gitbook/api": "0.104.0",
265+
"@gitbook/api": "0.105.0",
266266
"react": "18.3.1",
267267
"react-dom": "18.3.1",
268268
},
@@ -623,7 +623,7 @@
623623

624624
"@fortawesome/fontawesome-svg-core": ["@fortawesome/[email protected]", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "6.6.0" } }, "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg=="],
625625

626-
"@gitbook/api": ["@gitbook/api@0.104.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-Y+Z2K5uFZCUOFiaFzvkZQaiTFCttrNc+yRjf0uAtQVBYKn245FzVTi55q/DqdFipJ83D5dY4sknclQs9qwi+Mg=="],
626+
"@gitbook/api": ["@gitbook/api@0.105.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-asM2NzFf+8jG/7FtdxYRE5XiOqPMPZX5hy6egKal/ZcXkjtwWqVEY99Ys+evjg3BJXdb7E1lJoN2QA6PBTKZBQ=="],
627627

628628
"@gitbook/cache-do": ["@gitbook/cache-do@workspace:packages/cache-do"],
629629

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"@codemirror/state": "6.4.1",
1313
"react": "18.3.1",
1414
"react-dom": "18.3.1",
15-
"@gitbook/api": "0.104.0"
15+
"@gitbook/api": "0.105.0"
1616
},
1717
"private": true,
1818
"scripts": {

packages/gitbook-v2/src/lib/data/lookup.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { race, tryCatch } from '@/lib/async';
2-
import { joinPath } from '@/lib/paths';
2+
import { joinPath, joinPathWithBaseURL } from '@/lib/paths';
33
import { trace } from '@/lib/tracing';
44
import type { PublishedSiteContentLookup } from '@gitbook/api';
55
import { apiClient } from './api';
@@ -36,6 +36,13 @@ export async function getPublishedContentByURL(input: {
3636
url: alternative.url,
3737
visitorAuthToken: input.visitorAuthToken ?? undefined,
3838
redirectOnError: input.redirectOnError,
39+
40+
// As this endpoint is cached by our API, we version the request
41+
// to void getting stale data with missing properties.
42+
// this could be improved by ensuring our API cache layer is versioned
43+
// or invalidated when needed
44+
// @ts-expect-error - cacheVersion is not a real query param
45+
cacheVersion: 'v2',
3946
},
4047
{
4148
signal,
@@ -100,6 +107,7 @@ export async function getPublishedContentByURL(input: {
100107

101108
const siteResult: PublishedSiteContentLookup = {
102109
...data,
110+
canonicalUrl: joinPathWithBaseURL(data.canonicalUrl, alternative.extraPath),
103111
basePath: joinPath(data.basePath, lookup.basePath ?? ''),
104112
pathname: joinPath(data.pathname, alternative.extraPath),
105113
...(changeRequest ? { changeRequest } : {}),

packages/gitbook-v2/src/middleware.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) {
6363
return null;
6464
}
6565

66-
const { url: siteURL, mode } = match;
66+
const { url: siteRequestURL, mode } = match;
6767

6868
/**
6969
* Serve image resizing requests (all requests containing `/~gitbook/image`).
@@ -73,9 +73,9 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) {
7373
* In GitBook v1: image resizing was done at the root of the hostname (docs.company.com/~gitbook/image)
7474
* In GitBook v2: image resizing is done at the content level (docs.company.com/section/variant/~gitbook/image)
7575
*/
76-
if (siteURL.pathname.endsWith('/~gitbook/image')) {
76+
if (siteRequestURL.pathname.endsWith('/~gitbook/image')) {
7777
return await serveResizedImage(request, {
78-
host: siteURL.host,
78+
host: siteRequestURL.host,
7979
});
8080
}
8181

@@ -85,13 +85,13 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) {
8585
// @ts-ignore - request typing
8686
const visitorToken = getVisitorToken({
8787
cookies: request.cookies.getAll(),
88-
url: siteURL,
88+
url: siteRequestURL,
8989
});
9090

9191
const withAPIToken = async (apiToken: string | null) => {
9292
const siteURLData = await throwIfDataError(
9393
getPublishedContentByURL({
94-
url: siteURL.toString(),
94+
url: siteRequestURL.toString(),
9595
visitorAuthToken: visitorToken?.token ?? null,
9696
// When the visitor auth token is pulled from the cookie, set redirectOnError when calling getPublishedContentByUrl to allow
9797
// redirecting when the token is invalid as we could be dealing with stale token stored in the cookie.
@@ -136,11 +136,15 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) {
136136

137137
cookies.push(...getResponseCookiesForVisitorAuth(siteURLData.siteBasePath, visitorToken));
138138

139+
// We use the host/origin from the canonical URL to ensure the links are
140+
// correctly generated when the site is proxied. e.g. https://proxy.gitbook.com/site/siteId/...
141+
const siteCanonicalURL = new URL(siteURLData.canonicalUrl);
142+
139143
//
140144
// Make sure the URL is clean of any va token after a successful lookup
141145
// The token is stored in a cookie that is set on the redirect response
142146
//
143-
const incomingURL = mode === 'url' ? requestURL : siteURL;
147+
const incomingURL = mode === 'url' ? requestURL : siteCanonicalURL;
144148
const requestURLWithoutToken = normalizeVisitorAuthURL(incomingURL);
145149
if (
146150
requestURLWithoutToken !== incomingURL &&
@@ -152,10 +156,6 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) {
152156
);
153157
}
154158

155-
// We use the host/origin from the canonical URL to ensure the links are
156-
// correctly generated when the site is proxied. e.g. https://proxy.gitbook.com/site/siteId/...
157-
const siteCanonicalURL = new URL(siteURLData.canonicalUrl);
158-
159159
//
160160
// Render and serve the content
161161
//
@@ -174,12 +174,12 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) {
174174
requestHeaders.set(MiddlewareHeaders.SiteURLData, JSON.stringify(siteURLData));
175175

176176
// Preview of customization/theme
177-
const customization = siteURL.searchParams.get('customization');
177+
const customization = siteRequestURL.searchParams.get('customization');
178178
if (customization && validateSerializedCustomization(customization)) {
179179
routeType = 'dynamic';
180180
requestHeaders.set(MiddlewareHeaders.Customization, customization);
181181
}
182-
const theme = siteURL.searchParams.get('theme');
182+
const theme = siteRequestURL.searchParams.get('theme');
183183
if (theme === CustomizationThemeMode.Dark || theme === CustomizationThemeMode.Light) {
184184
routeType = 'dynamic';
185185
requestHeaders.set(MiddlewareHeaders.Theme, theme);
@@ -260,10 +260,10 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) {
260260
};
261261

262262
// For https://preview/<siteURL> requests,
263-
if (siteURL.hostname === 'preview') {
263+
if (siteRequestURL.hostname === 'preview') {
264264
return serveWithQueryAPIToken(
265265
// We scope the API token to the site ID.
266-
`${siteURL.hostname}/${requestURL.pathname.slice(1).split('/')[0]}`,
266+
`${siteRequestURL.hostname}/${requestURL.pathname.slice(1).split('/')[0]}`,
267267
request,
268268
withAPIToken
269269
);

packages/gitbook/src/components/Announcement/AnnouncementBanner.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
import * as storage from '@/lib/local-storage';
44
import type { ResolvedContentRef } from '@/lib/references';
55
import { tcls } from '@/lib/tailwind';
6-
import type { CustomizationAnnouncement } from '@gitbook/api';
6+
import { type CustomizationAnnouncement, SiteInsightsLinkPosition } from '@gitbook/api';
77
import { Icon, type IconName } from '@gitbook/icons';
8-
import Link from 'next/link';
98
import { CONTAINER_STYLE } from '../layout';
10-
import { linkStyles } from '../primitives';
9+
import { Link, linkStyles } from '../primitives';
1110
import { ANNOUNCEMENT_CSS_CLASS, ANNOUNCEMENT_STORAGE_KEY } from './constants';
1211

1312
/**
@@ -37,6 +36,17 @@ export function AnnouncementBanner(props: {
3736
closeable && 'pr-12',
3837
hasLink && style.hover
3938
)}
39+
insights={
40+
announcement.link
41+
? {
42+
type: 'link_click',
43+
link: {
44+
target: announcement.link.to,
45+
position: SiteInsightsLinkPosition.Announcement,
46+
},
47+
}
48+
: undefined
49+
}
4050
>
4151
<Icon
4252
icon={style.icon as IconName}

packages/gitbook/src/components/Search/SearchPageResultItem.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { Icon } from '@gitbook/icons';
22
import React from 'react';
33

44
import { tcls } from '@/lib/tailwind';
5-
65
import { Link } from '../primitives';
76
import { HighlightQuery } from './HighlightQuery';
87
import type { ComputedPageResult } from './server-actions';
@@ -38,6 +37,14 @@ export const SearchPageResultItem = React.forwardRef(function SearchPageResultIt
3837
? ['is-active', 'bg-primary', 'text-contrast-primary', 'hover:bg-primary-hover']
3938
: null
4039
)}
40+
insights={{
41+
type: 'search_open_result',
42+
query,
43+
result: {
44+
pageId: item.pageId,
45+
spaceId: item.spaceId,
46+
},
47+
}}
4148
>
4249
<div className="size-4">
4350
<Icon

packages/gitbook/src/components/Search/SearchSectionResultItem.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ export const SearchSectionResultItem = React.forwardRef(function SearchSectionRe
4040
'hover:bg-primary-hover',
4141
]
4242
)}
43+
insights={{
44+
type: 'search_open_result',
45+
query,
46+
result: {
47+
pageId: item.pageId,
48+
spaceId: item.spaceId,
49+
},
50+
}}
4351
>
4452
<div
4553
className={tcls(

0 commit comments

Comments
 (0)