Skip to content

Commit

Permalink
Fix error when accessing a change request not found (#2723)
Browse files Browse the repository at this point in the history
  • Loading branch information
gregberge authored Jan 14, 2025
1 parent e000f23 commit 65cc4af
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 85 deletions.
5 changes: 5 additions & 0 deletions .changeset/rich-impalas-applaud.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'gitbook': patch
---

Fix error when accessing a change request not found
151 changes: 78 additions & 73 deletions packages/gitbook/src/components/AdminToolbar/AdminToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,7 @@ interface AdminToolbarProps {
space: Space;
}

/**
* Toolbar with information for the content admin when previewing a revision or change-request.
*/
export function AdminToolbar(props: AdminToolbarProps) {
const { content } = props;

const toolbar = (() => {
if (content.changeRequestId) {
return (
<ChangeRequestToolbar
spaceId={content.spaceId}
changeRequestId={content.changeRequestId}
/>
);
}

if (content.revisionId) {
return <RevisionToolbar spaceId={content.spaceId} revisionId={content.revisionId} />;
}

return null;
})();

if (!toolbar) {
return null;
}

function ToolbarLayout(props: { children: React.ReactNode }) {
return (
<div
className={tcls(
Expand All @@ -61,41 +35,68 @@ export function AdminToolbar(props: AdminToolbarProps) {
'backdrop-blur-sm',
)}
>
<React.Suspense fallback={null}>{toolbar}</React.Suspense>
<React.Suspense fallback={null}>{props.children}</React.Suspense>
</div>
);
}

/**
* Toolbar with information for the content admin when previewing a revision or change-request.
*/
export function AdminToolbar(props: AdminToolbarProps) {
const { content } = props;
if (content.changeRequestId) {
return (
<ChangeRequestToolbar
spaceId={content.spaceId}
changeRequestId={content.changeRequestId}
/>
);
}

if (content.revisionId) {
return <RevisionToolbar spaceId={content.spaceId} revisionId={content.revisionId} />;
}

return null;
}

async function ChangeRequestToolbar(props: { spaceId: string; changeRequestId: string }) {
const { spaceId, changeRequestId } = props;

const changeRequest = await getChangeRequest(spaceId, changeRequestId);

if (!changeRequest) {
return null;
}

return (
<Toolbar>
<ToolbarButton title="Open in application" href={changeRequest.urls.app}>
<Icon icon="code-branch" className="size-4" />
</ToolbarButton>
<ToolbarBody>
<p>
#{changeRequest.number}: {changeRequest.subject ?? 'No subject'}
</p>
<p className="text-xs text-light/8 dark:text-light/8">
Change request updated <DateRelative value={changeRequest.updatedAt} />
</p>
</ToolbarBody>
<ToolbarButtonGroups>
<ToolbarLayout>
<Toolbar>
<ToolbarButton title="Open in application" href={changeRequest.urls.app}>
<Icon icon="arrow-up-right-from-square" className="size-4" />
<Icon icon="code-branch" className="size-4" />
</ToolbarButton>
<RefreshChangeRequestButton
spaceId={spaceId}
changeRequestId={changeRequestId}
revisionId={changeRequest.revision}
updatedAt={new Date(changeRequest.updatedAt).getTime()}
/>
</ToolbarButtonGroups>
</Toolbar>
<ToolbarBody>
<p>
#{changeRequest.number}: {changeRequest.subject ?? 'No subject'}
</p>
<p className="text-xs text-light/8 dark:text-light/8">
Change request updated <DateRelative value={changeRequest.updatedAt} />
</p>
</ToolbarBody>
<ToolbarButtonGroups>
<ToolbarButton title="Open in application" href={changeRequest.urls.app}>
<Icon icon="arrow-up-right-from-square" className="size-4" />
</ToolbarButton>
<RefreshChangeRequestButton
spaceId={spaceId}
changeRequestId={changeRequestId}
revisionId={changeRequest.revision}
updatedAt={new Date(changeRequest.updatedAt).getTime()}
/>
</ToolbarButtonGroups>
</Toolbar>
</ToolbarLayout>
);
}

Expand All @@ -107,31 +108,35 @@ async function RevisionToolbar(props: { spaceId: string; revisionId: string }) {
});

return (
<Toolbar>
<ToolbarButton title="Open in application" href={revision.urls.app}>
<Icon icon="code-commit" className="size-4" />
</ToolbarButton>
<ToolbarBody>
<p>
Revision created <DateRelative value={revision.createdAt} />
</p>
{revision.git ? (
<p className="text-xs text-light/8 dark:text-light/8">{revision.git.message}</p>
) : null}
</ToolbarBody>
<ToolbarButtonGroups>
<ToolbarLayout>
<Toolbar>
<ToolbarButton title="Open in application" href={revision.urls.app}>
<Icon icon="arrow-up-right-from-square" className="size-4" />
<Icon icon="code-commit" className="size-4" />
</ToolbarButton>
{revision.git?.url ? (
<ToolbarButton title="Open git commit" href={revision.git.url}>
<Icon
icon={revision.git.url.includes('github.com') ? 'github' : 'gitlab'}
className="size-4"
/>
<ToolbarBody>
<p>
Revision created <DateRelative value={revision.createdAt} />
</p>
{revision.git ? (
<p className="text-xs text-light/8 dark:text-light/8">
{revision.git.message}
</p>
) : null}
</ToolbarBody>
<ToolbarButtonGroups>
<ToolbarButton title="Open in application" href={revision.urls.app}>
<Icon icon="arrow-up-right-from-square" className="size-4" />
</ToolbarButton>
) : null}
</ToolbarButtonGroups>
</Toolbar>
{revision.git?.url ? (
<ToolbarButton title="Open git commit" href={revision.git.url}>
<Icon
icon={revision.git.url.includes('github.com') ? 'github' : 'gitlab'}
className="size-4"
/>
</ToolbarButton>
) : null}
</ToolbarButtonGroups>
</Toolbar>
</ToolbarLayout>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@ export async function hasContentBeenUpdated(props: {
revisionId: string;
}) {
const changeRequest = await getChangeRequest.revalidate(props.spaceId, props.changeRequestId);
if (!changeRequest) {
return false;
}
return changeRequest.revision !== props.revisionId;
}
42 changes: 30 additions & 12 deletions packages/gitbook/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ export const getUserById = cache({
revalidateBefore: 60 * 60,
});
} catch (error) {
if ((error as GitBookAPIError).code === 404) {
if (checkHasErrorCode(error, 404)) {
return {
revalidateBefore: 60 * 60,
data: null,
Expand Down Expand Up @@ -291,6 +291,10 @@ export const getSpace = cache({
},
});

function checkHasErrorCode(error: unknown, code: number) {
return error instanceof Error && 'code' in error && error.code === code;
}

/**
* Get a change request by its ID.
*/
Expand All @@ -300,14 +304,28 @@ export const getChangeRequest = cache({
getAPICacheTag({ tag: 'change-request', space: spaceId, changeRequest: changeRequestId }),
get: async (spaceId: string, changeRequestId: string, options: CacheFunctionOptions) => {
const apiCtx = await api();
const response = await apiCtx.client.spaces.getChangeRequestById(spaceId, changeRequestId, {
...noCacheFetchOptions,
signal: options.signal,
});
return cacheResponse(response, {
ttl: 60 * 60,
revalidateBefore: 10 * 60,
});
try {
const response = await apiCtx.client.spaces.getChangeRequestById(
spaceId,
changeRequestId,
{
...noCacheFetchOptions,
signal: options.signal,
},
);

return cacheResponse(response, {
ttl: 60 * 60,
revalidateBefore: 10 * 60,
});
} catch (error) {
if (checkHasErrorCode(error, 404)) {
return {
data: null,
};
}
throw error;
}
},
});

Expand Down Expand Up @@ -426,7 +444,7 @@ export const getRevisionPageByPath = cache({

return cacheResponse(response, cacheTtl_7days);
} catch (error) {
if ((error as GitBookAPIError).code === 404) {
if (checkHasErrorCode(error, 404)) {
return {
data: null,
...cacheTtl_7days,
Expand Down Expand Up @@ -711,14 +729,14 @@ export const getSiteRedirectBySource = cache({
} catch (error) {
// 422 is returned when the source is invalid
// we don't want to throw but just return null
if ((error as GitBookAPIError).code === 422) {
if (checkHasErrorCode(error, 422)) {
return {
data: null,
...cacheTtl_1day,
};
}

if ((error as GitBookAPIError).code === 404) {
if (checkHasErrorCode(error, 404)) {
return {
data: null,
...cacheTtl_1day,
Expand Down

0 comments on commit 65cc4af

Please sign in to comment.