Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions docs/changelog.mdx
Original file line number Diff line number Diff line change
@@ -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

<DocsChangelog />

## 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

<Alert level="info">
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.
</Alert>

139 changes: 139 additions & 0 deletions src/components/changelog/docsChangelog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
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<ChangelogEntry[]> {
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');
}

return res.json();
} catch (error) {
// Error fetching changelog - return empty array
return [];
}
}

export async function DocsChangelog() {
const entries = await getChangelogEntries();

if (entries.length === 0) {
return (
<div className="rounded-lg border border-yellow-200 bg-yellow-50 p-4 text-yellow-800">
<p className="font-semibold">No changelog entries available</p>
<p className="text-sm">Check back later for updates.</p>
</div>
);
}

return (
<div className="space-y-8">
{entries.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 (
<article key={entry.id} className="border-b border-gray-200 pb-8 last:border-0">
<header className="mb-3">
<h3 className="mb-2 text-xl font-semibold">
<a
href={entry.url}
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
{entry.title.replace('Docs Update: ', '')}
</a>
</h3>
<div className="flex flex-wrap items-center gap-3 text-sm text-gray-600">
<time dateTime={entry.publishedAt}>
{date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
})}
</time>
<span>•</span>
<span>by {entry.author}</span>
{totalFiles > 0 && <span>•</span>}
{totalFiles > 0 && (
<span>
{totalFiles} file{totalFiles !== 1 ? 's' : ''} changed
</span>
)}
</div>
</header>

<p className="mb-4 text-gray-700">{entry.description}</p>

{entry.filesChanged && totalFiles > 0 && (
<details className="text-sm">
<summary className="cursor-pointer text-gray-600 hover:text-gray-800">
View changed files
</summary>
<div className="mt-2 space-y-2 rounded-md bg-gray-50 p-3">
{entry.filesChanged.added && entry.filesChanged.added.length > 0 && (
<div>
<span className="font-semibold text-green-700">Added:</span>
<ul className="ml-4 mt-1 list-inside list-disc">
{entry.filesChanged.added.map(file => (
<li key={file} className="text-gray-700">
{file}
</li>
))}
</ul>
</div>
)}
{entry.filesChanged.modified &&
entry.filesChanged.modified.length > 0 && (
<div>
<span className="font-semibold text-blue-700">Modified:</span>
<ul className="ml-4 mt-1 list-inside list-disc">
{entry.filesChanged.modified.map(file => (
<li key={file} className="text-gray-700">
{file}
</li>
))}
</ul>
</div>
)}
{entry.filesChanged.removed &&
entry.filesChanged.removed.length > 0 && (
<div>
<span className="font-semibold text-red-700">Removed:</span>
<ul className="ml-4 mt-1 list-inside list-disc">
{entry.filesChanged.removed.map(file => (
<li key={file} className="text-gray-700">
{file}
</li>
))}
</ul>
</div>
)}
</div>
</details>
)}
</article>
);
})}
</div>
);
}
4 changes: 4 additions & 0 deletions src/components/sidebar/sidebarNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ const productSidebarItems = [
title: 'Concepts & Reference',
root: 'concepts',
},
{
title: 'Documentation Changelog',
root: 'changelog',
},
];

export async function SidebarNavigation({path}: {path: string[]}) {
Expand Down
Loading