diff --git a/docs/changelog.mdx b/docs/changelog.mdx new file mode 100644 index 00000000000000..0e511c1aa26add --- /dev/null +++ b/docs/changelog.mdx @@ -0,0 +1,23 @@ +--- +title: Documentation Changelog +sidebar_order: 100 +description: Track recent updates to Sentry docs +--- + +import {DocsChangelog} from 'sentry-docs/components/changelog/docsChangelog'; + + +## Recent Updates + + + +## Alternative Views + +- [Full Content Dashboard](https://sentry-content-dashboard.sentry.dev/) - View all Sentry content (blog, videos, docs, changelog) +- [RSS Feed](https://sentry-content-dashboard.sentry.dev/api/docs/feed) - Subscribe to doc updates in your RSS reader +- [JSON API](https://sentry-content-dashboard.sentry.dev/api/docs) - Programmatically access changelog data + + + The changelog updates automatically throughout the day. Summaries are generated by AI to provide quick, user-friendly insights into each update from the [getsentry/sentry-docs](https://github.com/getsentry/sentry-docs) repository. + + diff --git a/src/components/changelog/docsChangelog.tsx b/src/components/changelog/docsChangelog.tsx new file mode 100644 index 00000000000000..6c8f3c6a2a9b0f --- /dev/null +++ b/src/components/changelog/docsChangelog.tsx @@ -0,0 +1,175 @@ +interface ChangelogEntry { + author: string; + description: string; + id: string; + publishedAt: string; + title: string; + url: string; + filesChanged?: { + added: string[]; + modified: string[]; + removed: string[]; + }; +} + +async function getChangelogEntries(): Promise { + try { + const res = await fetch('https://sentry-content-dashboard.sentry.dev/api/docs', { + next: {revalidate: 3600}, // Cache for 1 hour + }); + + if (!res.ok) { + throw new Error(`Failed to fetch changelog: ${res.status} ${res.statusText}`); + } + + return res.json(); + } catch (error) { + // eslint-disable-next-line no-console + console.error('Error fetching changelog:', error); + // Error fetching changelog - return empty array + return []; + } +} + +export async function DocsChangelog() { + const entries = await getChangelogEntries(); + + if (entries.length === 0) { + return ( +
+

No changelog entries available

+

Check back later for updates.

+
+ ); + } + + // Show only the 20 most recent entries + const recentEntries = entries.slice(0, 20); + + return ( +
+ {recentEntries.map(entry => { + const date = new Date(entry.publishedAt); + const totalFiles = + (entry.filesChanged?.added?.length || 0) + + (entry.filesChanged?.modified?.length || 0) + + (entry.filesChanged?.removed?.length || 0); + + return ( +
+
+

+ + {entry.title.replace('Docs Update: ', '')} + +

+
+ + {totalFiles > 0 && } + {totalFiles > 0 && ( + + {totalFiles} file{totalFiles !== 1 ? 's' : ''} changed + + )} +
+
+ +

+ {entry.description} +

+ + {entry.filesChanged && totalFiles > 0 && ( +
+ + View changed files + +
+ {entry.filesChanged.added && entry.filesChanged.added.length > 0 && ( +
+ + Added: + +
    + {entry.filesChanged.added.map(file => ( +
  • + {file} +
  • + ))} +
+
+ )} + {entry.filesChanged.modified && + entry.filesChanged.modified.length > 0 && ( +
+ + Modified: + +
    + {entry.filesChanged.modified.map(file => ( +
  • + {file} +
  • + ))} +
+
+ )} + {entry.filesChanged.removed && + entry.filesChanged.removed.length > 0 && ( +
+ + Removed: + +
    + {entry.filesChanged.removed.map(file => ( +
  • + {file} +
  • + ))} +
+
+ )} +
+
+ )} +
+ ); + })} + {entries.length > 20 && ( +
+

+ Showing the 20 most recent updates. View the{' '} + + full content dashboard + {' '} + or subscribe to the{' '} + + RSS feed + + . +

+
+ )} +
+ ); +} diff --git a/src/components/sidebar/sidebarNavigation.tsx b/src/components/sidebar/sidebarNavigation.tsx index fb2502e3de077b..88de1485506fc7 100644 --- a/src/components/sidebar/sidebarNavigation.tsx +++ b/src/components/sidebar/sidebarNavigation.tsx @@ -44,6 +44,10 @@ const productSidebarItems = [ title: 'Concepts & Reference', root: 'concepts', }, + { + title: 'Documentation Changelog', + root: 'changelog', + }, ]; export async function SidebarNavigation({path}: {path: string[]}) {