From 6670ecdfda383f001748d0e5ab7cbe4ec240e514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Thu, 29 Feb 2024 17:48:11 +0100 Subject: [PATCH] Expose releases as an api (#4247) --- .../src/app/_components/releases/Release.tsx | 2 +- .../twenty-website/src/app/get-releases.tsx | 49 -------------- .../src/app/releases/api/route.tsx | 67 +++++++++++++++++++ .../twenty-website/src/app/releases/page.tsx | 2 +- .../shared-utils/compareSemanticVersions.ts | 16 +++++ 5 files changed, 85 insertions(+), 51 deletions(-) delete mode 100644 packages/twenty-website/src/app/get-releases.tsx create mode 100644 packages/twenty-website/src/app/releases/api/route.tsx create mode 100644 packages/twenty-website/src/shared-utils/compareSemanticVersions.ts diff --git a/packages/twenty-website/src/app/_components/releases/Release.tsx b/packages/twenty-website/src/app/_components/releases/Release.tsx index d6a33e2a0..c12bc3d52 100644 --- a/packages/twenty-website/src/app/_components/releases/Release.tsx +++ b/packages/twenty-website/src/app/_components/releases/Release.tsx @@ -6,7 +6,7 @@ import { compileMDX } from 'next-mdx-remote/rsc'; import remarkBehead from 'remark-behead'; import gfm from 'remark-gfm'; -import { ReleaseNote } from '@/app/get-releases'; +import { ReleaseNote } from '@/app/releases/api/route'; const StyledContainer = styled.div` width: 810px; diff --git a/packages/twenty-website/src/app/get-releases.tsx b/packages/twenty-website/src/app/get-releases.tsx deleted file mode 100644 index c9691b786..000000000 --- a/packages/twenty-website/src/app/get-releases.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import fs from 'fs'; -import matter from 'gray-matter'; - -export interface ReleaseNote { - slug: string; - date: string; - release: string; - content: string; -} - -function compareSemanticVersions(a: string, b: string) { - const a1 = a.split('.'); - const b1 = b.split('.'); - - const len = Math.min(a1.length, b1.length); - - for (let i = 0; i < len; i++) { - const a2 = +a1[i] || 0; - const b2 = +b1[i] || 0; - - if (a2 !== b2) { - return a2 > b2 ? 1 : -1; - } - } - return b1.length - a1.length; -} - -export async function getReleases(): Promise { - const files = fs.readdirSync('src/content/releases'); - const releasenotes: ReleaseNote[] = []; - - for (const fileName of files) { - if (!fileName.endsWith('.md') && !fileName.endsWith('.mdx')) { - continue; - } - const file = fs.readFileSync(`src/content/releases/${fileName}`, 'utf-8'); - const { data: frontmatter, content } = matter(file); - releasenotes.push({ - slug: fileName.slice(0, -4), - date: frontmatter.Date, - release: frontmatter.release, - content: content, - }); - } - - releasenotes.sort((a, b) => compareSemanticVersions(b.release, a.release)); - - return releasenotes; -} diff --git a/packages/twenty-website/src/app/releases/api/route.tsx b/packages/twenty-website/src/app/releases/api/route.tsx new file mode 100644 index 000000000..7b3e8ceeb --- /dev/null +++ b/packages/twenty-website/src/app/releases/api/route.tsx @@ -0,0 +1,67 @@ +import { compareSemanticVersions } from '@/shared-utils/compareSemanticVersions'; +import fs from 'fs'; +import matter from 'gray-matter'; + +import { NextRequest, NextResponse } from 'next/server' + + +export interface ReleaseNote { + slug: string; + date: string; + release: string; + content: string; +} + + +const BASE_URL = 'https://twenty.com/'; + +// WARNING: This API is used by twenty-front, not just by twenty-website +// Make sure you don't change it without updating twenty-front at the same time +export async function getReleases(baseUrl?: string): Promise { + const files = fs.readdirSync('src/content/releases'); + const releasenotes: ReleaseNote[] = []; + + for (const fileName of files) { + if (!fileName.endsWith('.md') && !fileName.endsWith('.mdx')) { + continue; + } + const file = fs.readFileSync(`src/content/releases/${fileName}`, 'utf-8'); + const { data: frontmatter, content } = matter(file); + + let updatedContent; + if(baseUrl) { + updatedContent = content.replace(/!\[(.*?)\]\((?!http)(.*?)\)/g, (match, alt, src) => { + // Check if src is a relative path (not starting with http:// or https://) + if (!src.startsWith('/')) { + src = `${baseUrl}/${src}`; + } else { + src = `${baseUrl}${src}`; + } + return `![${alt}](${src})`; + }); + } + + releasenotes.push({ + slug: fileName.slice(0, -4), + date: frontmatter.Date, + release: frontmatter.release, + content: updatedContent ?? content, + }); + } + + releasenotes.sort((a, b) => compareSemanticVersions(b.release, a.release)); + + return releasenotes; +} + + +export async function GET(request: NextRequest) { + + const host = request.nextUrl.hostname; + const protocol = request.nextUrl.protocol; + const baseUrl = `${protocol}//${host}`; + + console.log(baseUrl); + + return NextResponse.json(await getReleases(baseUrl), { status: 200 }) +} diff --git a/packages/twenty-website/src/app/releases/page.tsx b/packages/twenty-website/src/app/releases/page.tsx index fa820f3ae..330235d85 100644 --- a/packages/twenty-website/src/app/releases/page.tsx +++ b/packages/twenty-website/src/app/releases/page.tsx @@ -5,7 +5,7 @@ import { Line } from '@/app/_components/releases/Line'; import { Release } from '@/app/_components/releases/Release'; import { Title } from '@/app/_components/releases/StyledTitle'; import { ContentContainer } from '@/app/_components/ui/layout/ContentContainer'; -import { getReleases } from '@/app/get-releases'; +import { getReleases } from '@/app/releases/api/route'; export const metadata: Metadata = { title: 'Twenty - Releases', diff --git a/packages/twenty-website/src/shared-utils/compareSemanticVersions.ts b/packages/twenty-website/src/shared-utils/compareSemanticVersions.ts new file mode 100644 index 000000000..0fbec4b9f --- /dev/null +++ b/packages/twenty-website/src/shared-utils/compareSemanticVersions.ts @@ -0,0 +1,16 @@ +export function compareSemanticVersions(a: string, b: string) { + const a1 = a.split('.'); + const b1 = b.split('.'); + + const len = Math.min(a1.length, b1.length); + + for (let i = 0; i < len; i++) { + const a2 = +a1[i] || 0; + const b2 = +b1[i] || 0; + + if (a2 !== b2) { + return a2 > b2 ? 1 : -1; + } + } + return b1.length - a1.length; + } \ No newline at end of file