Fix links to other spaces in a section (#3409)

Co-authored-by: Steven H <steven@gitbook.io>
This commit is contained in:
Samy Pessé
2025-06-30 17:47:23 +02:00
committed by GitHub
parent 8fe9c9afea
commit b60039b7d5
4 changed files with 84 additions and 37 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"gitbook": patch
---
Fix links to other spaces within a section.
@@ -3,7 +3,7 @@
import type { GitBookBaseContext, GitBookSiteContext } from '@/lib/context';
import { resolvePageId } from '@/lib/pages';
import { fetchServerActionSiteContext, getServerActionBaseContext } from '@/lib/server-actions';
import { findSiteSpaceById, getSiteStructureSections } from '@/lib/sites';
import { findSiteSpaceBy } from '@/lib/sites';
import { filterOutNullable } from '@/lib/typescript';
import type {
Revision,
@@ -256,24 +256,20 @@ async function searchSiteContent(
return (
await Promise.all(
searchResults.map(async (spaceItem) => {
const sections = getSiteStructureSections(structure).flatMap((item) =>
item.object === 'site-section-group' ? [item, ...item.sections] : item
const found = findSiteSpaceBy(
structure,
(siteSpace) => siteSpace.space.id === spaceItem.id
);
const siteSpace = findSiteSpaceById(structure, spaceItem.id);
const siteSection = sections.find(
(section) => section.id === siteSpace?.section
) as SiteSection;
const siteSectionGroup = siteSection?.sectionGroup
? sections.find((sectionGroup) => sectionGroup.id === siteSection.sectionGroup)
: null;
const siteSection = found?.siteSection;
const siteSectionGroup = found?.siteSectionGroup;
return Promise.all(
spaceItem.pages.map((pageItem) =>
transformSitePageResult(context, {
pageItem,
spaceItem,
space: siteSpace?.space,
spaceURL: siteSpace?.urls.published,
space: found?.siteSpace.space,
spaceURL: found?.siteSpace.urls.published,
siteSection: siteSection ?? undefined,
siteSectionGroup: (siteSectionGroup as SiteSectionGroup) ?? undefined,
})
@@ -313,8 +309,11 @@ async function transformAnswer(
}
// Find the siteSpace in case it is nested in a site section so we can resolve the URL appropriately
const siteSpace = findSiteSpaceById(context.structure, source.space);
const spaceURL = siteSpace?.urls.published;
const found = findSiteSpaceBy(
context.structure,
(siteSpace) => siteSpace.space.id === source.space
);
const spaceURL = found?.siteSpace.urls.published;
const href = spaceURL
? joinPathWithBaseURL(spaceURL, page.page.path)
+7 -4
View File
@@ -33,7 +33,7 @@ import { PageIcon } from '@/components/PageIcon';
import { getGitBookAppHref } from './app';
import { getBlockById, getBlockTitle } from './document';
import { resolvePageId } from './pages';
import { findSiteSpaceById, getFallbackSiteSpacePath } from './sites';
import { findSiteSpaceBy, getFallbackSiteSpacePath } from './sites';
import type { ClassValue } from './tailwind';
import { filterOutNullable } from './typescript';
@@ -315,9 +315,12 @@ async function getBestTargetSpace(
// In the context of sites, we try to find our target space in the site structure.
// because the url of this space will be in the same site.
if ('site' in context) {
const siteSpace = findSiteSpaceById(context.structure, spaceId);
if (siteSpace) {
return { space: siteSpace.space, siteSpace };
const found = findSiteSpaceBy(
context.structure,
(siteSpace) => siteSpace.space.id === spaceId
);
if (found) {
return { space: found.siteSpace.space, siteSpace: found.siteSpace };
}
}
+59 -19
View File
@@ -48,18 +48,46 @@ export function listAllSiteSpaces(siteStructure: SiteStructure) {
/**
* Find a site space by its spaceId in a site structure.
*/
export function findSiteSpaceById(siteStructure: SiteStructure, spaceId: string): SiteSpace | null {
export function findSiteSpaceBy(
siteStructure: SiteStructure,
predicate: (siteSpace: SiteSpace) => boolean
): {
siteSpace: SiteSpace;
siteSection: SiteSection | null;
siteSectionGroup: SiteSectionGroup | null;
} | null {
if (siteStructure.type === 'siteSpaces') {
return siteStructure.structure.find((siteSpace) => siteSpace.space.id === spaceId) ?? null;
const siteSpace = siteStructure.structure.find(predicate) ?? null;
if (siteSpace) {
return {
siteSpace,
siteSection: null,
siteSectionGroup: null,
};
}
return null;
}
for (const section of siteStructure.structure) {
const siteSpace =
section.object === 'site-section'
? findSiteSpaceByIdInSiteSpaces(section.siteSpaces, spaceId)
: findSiteSpaceByIdInSections(section.sections, spaceId);
if (siteSpace) {
return siteSpace;
for (const sectionOrGroup of siteStructure.structure) {
if (sectionOrGroup.object === 'site-section') {
const siteSpace = findSiteSpaceByIdInSiteSpaces(sectionOrGroup.siteSpaces, predicate);
if (siteSpace) {
return {
siteSpace,
siteSection: sectionOrGroup,
siteSectionGroup: null,
};
}
} else {
const found = findSiteSpaceByIdInSections(sectionOrGroup.sections, predicate);
if (found) {
return {
siteSpace: found.siteSpace,
siteSection: found.siteSection,
siteSectionGroup: sectionOrGroup,
};
}
}
}
@@ -94,25 +122,37 @@ export function getSiteSpaceURL(context: GitBookSiteContext, siteSpace: SiteSpac
/**
* Get the path of a site space in the current site.
* This doesn't return the most optimized path, as it doesn't take into account which one is the default one.
*/
export function getFallbackSiteSpacePath(context: GitBookSiteContext, siteSpace: SiteSpace) {
const { sections } = context;
return sections?.current ? joinPath(sections.current.path, siteSpace.path) : siteSpace.path;
const found = findSiteSpaceBy(context.structure, (entry) => entry.id === siteSpace.id);
// don't include the path for the default site space
const siteSpacePath = siteSpace.default ? '' : siteSpace.path;
// for non-default site sections, include the section path.
if (found?.siteSection && !found?.siteSection.default) {
return joinPath(found.siteSection.path, siteSpacePath);
}
return siteSpacePath;
}
function findSiteSpaceByIdInSections(sections: SiteSection[], spaceId: string): SiteSpace | null {
for (const section of sections) {
const siteSpace =
section.siteSpaces.find((siteSpace) => siteSpace.space.id === spaceId) ?? null;
function findSiteSpaceByIdInSections(
sections: SiteSection[],
predicate: (siteSpace: SiteSpace) => boolean
): { siteSpace: SiteSpace; siteSection: SiteSection } | null {
for (const siteSection of sections) {
const siteSpace = siteSection.siteSpaces.find(predicate) ?? null;
if (siteSpace) {
return siteSpace;
return { siteSpace, siteSection };
}
}
return null;
}
function findSiteSpaceByIdInSiteSpaces(siteSpaces: SiteSpace[], spaceId: string): SiteSpace | null {
return siteSpaces.find((siteSpace) => siteSpace.space.id === spaceId) ?? null;
function findSiteSpaceByIdInSiteSpaces(
siteSpaces: SiteSpace[],
predicate: (siteSpace: SiteSpace) => boolean
): SiteSpace | null {
return siteSpaces.find(predicate) ?? null;
}