Skip to content

Commit 314201d

Browse files
sfanahataShannon Anahatagetsantry[bot]a-hariti
authored
Fixing JS framework formatting for redirect pages (#14914)
## DESCRIBE YOUR PR **Summary** Enhanced the platform redirect system to show individual JavaScript frameworks (React, Vue, Angular, etc.) as separate, nested options under the main JavaScript platform. This provides users with a more customized and framework-specific experience when selecting their platform. Also added better logic to check for guide paths because Dart also wasn't showing up due to being nested. **Problem** When users clicked platform-redirect links (like /platform-redirect/?next=/session-replay/privacy/), they only saw top-level platforms (JavaScript, Android, React Native). This didn't reflect that many JavaScript frameworks have different support levels for specific features, and users couldn't easily select their specific framework for a more tailored experience. They also did not see Dart, which was nested under a Dart/Flutter guide. **Solution** - Automatic Framework Detection: The system now reads the `notSupported` frontmatter from JavaScript documentation pages to determine which frameworks support each feature. Added more robust logic to search for guides under each platform if main platform paths are empty. - Visual Nesting: JavaScript frameworks are indented under the main JavaScript platform for clear hierarchy Smart Positioning: JavaScript and its frameworks appear at the end of the platform list Framework-Specific URLs: Each framework links to the main JavaScript documentation for that feature Example pages: https://sentry-docs-git-platform-redirect-privacy-fix.sentry.dev/platform-redirect/?next=/session-replay/configuration/#network-details https://sentry-docs-git-platform-redirect-privacy-fix.sentry.dev/platform-redirect/?next=/session-replay/privacy/ ## IS YOUR CHANGE URGENT? Help us prioritize incoming PRs by letting us know when the change needs to go live. - [ ] Urgent deadline (GA date, etc.): <!-- ENTER DATE HERE --> - [ ] Other deadline: <!-- ENTER DATE HERE --> - [x] None: Not urgent, can wait up to 1 week+ ## SLA - Teamwork makes the dream work, so please add a reviewer to your PRs. - Please give the docs team up to 1 week to review your PR unless you've added an urgent due date to it. Thanks in advance for your help! ## PRE-MERGE CHECKLIST *Make sure you've checked the following before merging your changes:* - [ ] Checked Vercel preview for correctness, including links - [ ] PR was reviewed and approved by any necessary SMEs (subject matter experts) - [ ] PR was reviewed and approved by a member of the [Sentry docs team](https://github.com/orgs/getsentry/teams/docs) --------- Co-authored-by: Shannon Anahata <[email protected]> Co-authored-by: getsantry[bot] <66042841+getsantry[bot]@users.noreply.github.com> Co-authored-by: Abdellah Hariti <[email protected]>
1 parent 42a2ce5 commit 314201d

File tree

1 file changed

+87
-18
lines changed

1 file changed

+87
-18
lines changed

app/platform-redirect/page.tsx

Lines changed: 87 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,35 +37,104 @@ export default async function Page(props: {
3737
"The page you are looking for is customized for each platform. Select your platform below and we'll direct you to the most specific documentation on it.";
3838
let title = defaultTitle;
3939

40-
// get rid of irrelevant platforms for the `next` path
41-
const platformList = extractPlatforms(rootNode).filter(platform_ => {
42-
const node = nodeForPath(rootNode, [
40+
// Build a list of platforms or guides that have the content for the `next` path
41+
type PlatformOrGuide = {
42+
icon: string;
43+
key: string;
44+
title: string;
45+
url: string;
46+
parentPlatform?: string;
47+
shouldBeNested?: boolean;
48+
};
49+
50+
const platformOrGuideList: PlatformOrGuide[] = [];
51+
52+
for (const platformEntry of extractPlatforms(rootNode)) {
53+
// Check if the main platform path has the content
54+
const mainPlatformNode = nodeForPath(rootNode, [
4355
'platforms',
44-
platform_.key,
56+
platformEntry.key,
4557
...pathname.split('/').filter(Boolean),
4658
]);
4759

48-
// extract title and description for displaying it on page
49-
if (node && title === defaultTitle && pathname.length > 0) {
50-
title = node.frontmatter.title ?? title;
51-
description = node.frontmatter.description || '';
60+
// Extract title and description from the first valid node we find
61+
if (mainPlatformNode && title === defaultTitle && pathname.length > 0) {
62+
title = mainPlatformNode.frontmatter.title ?? title;
63+
description = mainPlatformNode.frontmatter.description || '';
64+
}
65+
66+
// Check which guides have the content
67+
const supportedGuides: typeof platformEntry.guides = [];
68+
if (platformEntry.guides) {
69+
for (const guide of platformEntry.guides) {
70+
const guideNode = nodeForPath(rootNode, [
71+
'platforms',
72+
platformEntry.key,
73+
'guides',
74+
guide.name,
75+
...pathname.split('/').filter(Boolean),
76+
]);
77+
78+
if (guideNode) {
79+
supportedGuides.push(guide);
80+
81+
// Extract title and description if we haven't yet
82+
if (title === defaultTitle && pathname.length > 0) {
83+
title = guideNode.frontmatter.title ?? title;
84+
description = guideNode.frontmatter.description || '';
85+
}
86+
}
87+
}
5288
}
5389

54-
return !!node;
55-
});
90+
// Check notSupported list to filter out unsupported guides (for platforms like JavaScript)
91+
let filteredGuides = supportedGuides;
92+
if (mainPlatformNode?.frontmatter.notSupported && supportedGuides.length > 0) {
93+
const notSupported = mainPlatformNode.frontmatter.notSupported;
94+
filteredGuides = supportedGuides.filter(
95+
guide => !notSupported.includes(`${platformEntry.key}.${guide.name}`)
96+
);
97+
}
98+
99+
// Include platform if main path exists OR if any guides exist
100+
if (mainPlatformNode || filteredGuides.length > 0) {
101+
// Add the main platform entry only if it has content
102+
if (mainPlatformNode) {
103+
platformOrGuideList.push({
104+
key: platformEntry.key,
105+
title: platformEntry.title ?? platformEntry.key ?? '',
106+
url: platformEntry.url ?? '',
107+
icon: platformEntry.icon ?? platformEntry.key,
108+
});
109+
}
110+
111+
// Add guide entries as nested items (only if main platform exists)
112+
// or as top-level items (if only guides have content)
113+
for (const guide of filteredGuides) {
114+
platformOrGuideList.push({
115+
key: `${platformEntry.key}.${guide.name}`,
116+
title: guide.title ?? guide.name ?? '',
117+
url: guide.url ?? '', // Always use the guide-specific URL
118+
icon: `${platformEntry.key}-${guide.name}`,
119+
shouldBeNested: mainPlatformNode ? true : false, // Only nest if parent exists
120+
parentPlatform: platformEntry.key,
121+
});
122+
}
123+
}
124+
}
56125

57-
if (platformList.length === 0) {
126+
if (platformOrGuideList.length === 0) {
58127
// try to redirect the user to the page directly, might result in 404
59128
return redirect(next);
60129
}
61130

62131
const requestedPlatform = Array.isArray(platform) ? platform[0] : platform;
63132
if (requestedPlatform) {
64-
const isValidPlatform = platformList.some(
133+
const validPlatform = platformOrGuideList.find(
65134
p => p.key === requestedPlatform?.toLowerCase()
66135
);
67-
if (isValidPlatform) {
68-
return redirect(`/platforms/${requestedPlatform}${pathname}`);
136+
if (validPlatform) {
137+
return redirect(`${validPlatform.url}${pathname}`);
69138
}
70139
}
71140

@@ -82,12 +151,12 @@ export default async function Page(props: {
82151
<Alert>{platformInfo}</Alert>
83152

84153
<ul>
85-
{platformList.map(p => (
86-
<li key={p.key}>
87-
<SmartLink to={`/platforms/${p.key}${pathname}`}>
154+
{platformOrGuideList.map(p => (
155+
<li key={p.key} style={{marginLeft: p.shouldBeNested ? '20px' : '0'}}>
156+
<SmartLink to={`${p.url}${pathname}`}>
88157
<PlatformIcon
89158
size={16}
90-
platform={p.icon ?? p.key}
159+
platform={p.icon}
91160
style={{marginRight: '0.5rem'}}
92161
format="sm"
93162
/>

0 commit comments

Comments
 (0)