Skip to content

Commit

Permalink
Add Changelog (#9063)
Browse files Browse the repository at this point in the history
* Add DB Changelog

* fix build errors

* Create/publish/unpublish

* Edit

* Login with Google

* Login

* Protect actions

* GCS bucket upload

* Last change before killing seed data

* Remove seed data

* fix build errors

* fix: Build error

* fix: Env names

* build prisma first

* enable tracing

* Add file upload for hero image

* remove mdxcomponents and pray vercel error is gone

* try to split stuff in functions

* fix

* Remove load mdx for notFound

* remove navbar since it also loads the world

* More nextjs style

* Revert "More nextjs style"

This reverts commit 780b988.

* fix picture height

* urlencode filename

* Fix errors

* Fix build error
  • Loading branch information
HazAT authored Feb 13, 2024
1 parent d286236 commit 0f07d27
Show file tree
Hide file tree
Showing 198 changed files with 3,805 additions and 11,995 deletions.
3 changes: 0 additions & 3 deletions .envrc

This file was deleted.

20 changes: 20 additions & 0 deletions app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {PrismaAdapter} from '@auth/prisma-adapter';
import NextAuth from 'next-auth';
import GoogleProvider from 'next-auth/providers/google';

import {prisma} from 'sentry-docs/prisma';

const handler = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID || '',
clientSecret: process.env.GOOGLE_CLIENT_SECRET || '',
}),
],
session: {
strategy: 'jwt',
},
});

export {handler as GET, handler as POST};
92 changes: 92 additions & 0 deletions app/changelog/%5Fadmin/[id]/edit/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import {Fragment, Suspense} from 'react';
import Link from 'next/link';

import {editChangelog} from 'sentry-docs/actions/changelog';
import {FileUpload} from 'sentry-docs/components/changelog/fileUpload';
import {ForwardRefEditor} from 'sentry-docs/components/changelog/forwardRefEditor';
import {TitleSlug} from 'sentry-docs/components/changelog/titleSlug';
import {Button} from 'sentry-docs/components/changelog/ui/Button';
import {Select} from 'sentry-docs/components/changelog/ui/Select';
import {prisma} from 'sentry-docs/prisma';

export default async function ChangelogCreatePage({params}) {
const categories = await prisma.category.findMany();
const changelog = await prisma.changelog.findUnique({
where: {id: params.id},
include: {
author: true,
categories: true,
},
});

if (!changelog) {
return (
<Fragment>
<header>
<h2>Changelog not found</h2>
</header>
<footer>
<Link href="/changelogs">Return to Changelogs list</Link>
</footer>
</Fragment>
);
}

return (
<section className="overflow-x-auto col-start-3 col-span-8">
<form action={editChangelog} className="px-2 w-full">
<input type="hidden" name="id" value={changelog.id} />
<TitleSlug defaultSlug={changelog.slug} defaultTitle={changelog.title} />
<FileUpload defaultFile={changelog.image || ''} />
<div className="my-6">
<label htmlFor="summary" className="block text-xs font-medium text-gray-700">
Summary
<Fragment>
&nbsp;<span className="font-bold text-secondary">*</span>
</Fragment>
</label>
<textarea name="summary" className="w-full" required>
{changelog.summary}
</textarea>
<span className="text-xs text-gray-500 italic">
This will be shown in the list
</span>
</div>
<div>
<Select
name="categories"
className="mt-1 mb-6"
label="Category"
placeholder="Select Category"
defaultValue={changelog.categories.map(category => ({
label: category.name,
value: category.name,
}))}
options={categories.map(category => ({
label: category.name,
value: category.name,
}))}
isMulti
/>
</div>

<Suspense fallback={null}>
<ForwardRefEditor
name="content"
defaultValue={changelog.content || ''}
className="w-full"
/>
</Suspense>

<footer className="flex items-center justify-between mt-2 mb-8">
<Link href="/changelog/_admin" className="underline text-gray-500">
Return to Changelogs list
</Link>
<div>
<Button type="submit">Update</Button>
</div>
</footer>
</form>
</section>
);
}
25 changes: 25 additions & 0 deletions app/changelog/%5Fadmin/confirm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use client';

export default function Confirm({changelog, action, children}) {
return (
<form
action={action}
className="inline-block"
onSubmit={e => {
e.preventDefault();
// eslint-disable-next-line no-alert
if (confirm('Are you sure?')) {
action(new FormData(e.currentTarget));
}
}}
>
<input type="hidden" name="id" value={changelog.id} />
<button
type="submit"
className="text-indigo-600 hover:bg-indigo-100 rounded-md px-1 py-2 text-xs whitespace-nowrap"
>
{children}
</button>
</form>
);
}
61 changes: 61 additions & 0 deletions app/changelog/%5Fadmin/create/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {Fragment} from 'react';
import Link from 'next/link';

import {createChangelog} from 'sentry-docs/actions/changelog';
import {FileUpload} from 'sentry-docs/components/changelog/fileUpload';
import {ForwardRefEditor} from 'sentry-docs/components/changelog/forwardRefEditor';
import {TitleSlug} from 'sentry-docs/components/changelog/titleSlug';
import {Button} from 'sentry-docs/components/changelog/ui/Button';
import {Select} from 'sentry-docs/components/changelog/ui/Select';
import {prisma} from 'sentry-docs/prisma';

export default async function ChangelogCreatePage() {
const categories = await prisma.category.findMany();

return (
<section className="overflow-x-auto col-start-3 col-span-8">
<form action={createChangelog} className="px-2 w-full">
<TitleSlug />
<FileUpload />
<div className="my-6">
<label htmlFor="summary" className="block text-xs font-medium text-gray-700">
Summary
<Fragment>
&nbsp;<span className="font-bold text-secondary">*</span>
</Fragment>
</label>
<textarea name="summary" className="w-full" required />
<span className="text-xs text-gray-500 italic">
This will be shown in the list
</span>
</div>
<div>
<Select
name="categories"
className="mt-1 mb-6"
label="Category"
placeholder="Select Category"
options={categories.map(category => ({
label: category.name,
value: category.name,
}))}
isMulti
/>
</div>

<ForwardRefEditor name="content" className="w-full" />

<footer className="flex items-center justify-between mt-2">
<Link href="/changelog/_admin" className="underline text-gray-500">
Return to Changelogs list
</Link>
<div>
<Button type="submit">Create (not published yet)</Button>
<br />
<span className="text-xs text-gray-500 italic">You can publish it later</span>
</div>
</footer>
</form>
</section>
);
}
28 changes: 28 additions & 0 deletions app/changelog/%5Fadmin/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {type ReactNode, Suspense} from 'react';
import {GET} from 'app/api/auth/[...nextauth]/route';
import {getServerSession} from 'next-auth/next';

import LoginButton from 'sentry-docs/components/changelog/loginButton';
import NextAuthSessionProvider from 'sentry-docs/components/nextAuthSessionProvider';

export default async function Layout({children}: {children: ReactNode}) {
const session = await getServerSession(GET);
let content = (
<div className="relative min-h-[calc(100vh-8rem)] w-full mx-auto bg-gray-200 pt-16 grid grid-cols-12">
{children}
<div className="fixed top-3 right-4 z-50">
<Suspense fallback={null}>
<LoginButton />
</Suspense>
</div>
</div>
);
if (!session) {
content = (
<div className="relative min-h-[calc(100vh-8rem)] w-full mx-auto bg-gray-200 pt-16 flex items-center justify-center">
<LoginButton />
</div>
);
}
return <NextAuthSessionProvider>{content}</NextAuthSessionProvider>;
}
121 changes: 121 additions & 0 deletions app/changelog/%5Fadmin/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import {Fragment} from 'react';
import {PlusIcon} from '@radix-ui/react-icons';
import {Button, Text} from '@radix-ui/themes';
import Link from 'next/link';

import {
deleteChangelog,
publishChangelog,
unpublishChangelog,
} from 'sentry-docs/actions/changelog';
import {prisma} from 'sentry-docs/prisma';

import Confirm from './confirm';

export default async function ChangelogsListPage() {
const changelogs = await prisma.changelog.findMany({
include: {
categories: true,
author: true,
},
orderBy: {
createdAt: 'desc',
},
});

return (
<Fragment>
<header className="mb-4 col-start-3 col-span-2 text-left">
<Button>
<PlusIcon />
<Link href="/changelog/_admin/create">New Changelog</Link>
</Button>
</header>
<section className="overflow-x-auto col-start-3 col-span-8 shadow-md rounded-lg">
<table className="w-full text-sm text-left text-gray-500">
<thead className="text-xs text-gray-700 uppercase bg-gray-50">
<tr>
<th className="whitespace-nowrap px-4 py-2">Title</th>
<th className="whitespace-nowrap px-4 py-2">Categories</th>
<th className="whitespace-nowrap px-4 py-2">Published by</th>
<th className="px-4 py-2" />
</tr>
</thead>
<tbody className="divide-y divide-gray-200 bg-white border-b hover:bg-gray-50 dark:hover:bg-gray-600">
{changelogs.length === 0 && (
<tr>
<td
colSpan={10}
className="text-center font-medium text-gray-900 whitespace-nowrap"
>
No changelogs found
</td>
</tr>
)}

{changelogs.map(changelog => (
<tr key={changelog.id} className="bg-white border-b hover:bg-gray-50">
<td className="px-6 py-4 font-medium text-gray-900">{changelog.title}</td>

<td className="px-4 py-2">
{changelog.categories.map(category => (
<div
key={category.id}
className="inline whitespace-nowrap p-2 uppercase shadow-sm no-underline rounded-full text-red text-xs mr-1 bg-gray-100"
>
{category.name}
</div>
))}
</td>
<td className="px-4 py-2 text-center">
{changelog.published && (
<span className="text-gray-500">
<Text size="1">
{' '}
{new Date(changelog.publishedAt || '').toLocaleDateString(
undefined,
{month: 'long', day: 'numeric'}
)}
</Text>
<br />
</span>
)}
<Text size="1">{changelog.author?.name}</Text>
</td>

<td className="px-4 py-2">
<div className="flex h-full justify-end">
<Link
href={`/changelog/${changelog.slug}`}
className="text-indigo-600 hover:bg-indigo-100 rounded-md px-1 py-2 text-xs whitespace-nowrap"
>
👀 Show
</Link>
<Link
href={`/changelog/_admin/${changelog.id}/edit`}
className="text-indigo-600 hover:bg-indigo-100 rounded-md px-1 py-2 text-xs whitespace-nowrap"
>
📝 Edit
</Link>
{changelog.published ? (
<Confirm action={unpublishChangelog} changelog={changelog}>
⛔️ Unpublish?
</Confirm>
) : (
<Confirm action={publishChangelog} changelog={changelog}>
✅ Publish?
</Confirm>
)}
<Confirm action={deleteChangelog} changelog={changelog}>
💀 Delete?
</Confirm>
</div>
</td>
</tr>
))}
</tbody>
</table>
</section>
</Fragment>
);
}
Loading

0 comments on commit 0f07d27

Please sign in to comment.