From c3a40a0f6edda4429c530c769359d2e4ffac0b25 Mon Sep 17 00:00:00 2001 From: Ahtesham Quraish Date: Tue, 24 Feb 2026 22:10:28 +0500 Subject: [PATCH 1/2] fix: remove the articles route and its relevant code (#2974) Co-authored-by: Ahtesham Quraish --- frontends/main/next.config.js | 12 +++ .../Articles/ArticleDraftListingPage.tsx | 14 ++- .../main/src/app/articles/[slugOrId]/page.tsx | 95 ------------------- frontends/main/src/app/articles/new/page.tsx | 15 --- .../[slugOrId]/draft/page.tsx | 4 +- .../src/app/{articles => news}/draft/page.tsx | 2 +- frontends/main/src/common/urls.ts | 2 +- .../TiptapEditor/ArticleEditor.tsx | 2 +- .../ArticleByLineInfoBar.tsx | 2 +- 9 files changed, 23 insertions(+), 125 deletions(-) delete mode 100644 frontends/main/src/app/articles/[slugOrId]/page.tsx delete mode 100644 frontends/main/src/app/articles/new/page.tsx rename frontends/main/src/app/{articles => news}/[slugOrId]/draft/page.tsx (89%) rename frontends/main/src/app/{articles => news}/draft/page.tsx (85%) diff --git a/frontends/main/next.config.js b/frontends/main/next.config.js index 7fd9b59a84..1f0b85bb55 100644 --- a/frontends/main/next.config.js +++ b/frontends/main/next.config.js @@ -47,6 +47,18 @@ const nextConfig = { destination: "/enrollmentcode/:code", permanent: true, }, + { + // can be removed once fastly redirect is in place + source: "/articles/:slug*", + destination: "/news/:slug*", + permanent: true, + }, + { + // can be removed once fastly redirect is in place + source: "/articles", + destination: "/news", + permanent: true, + }, ] }, diff --git a/frontends/main/src/app-pages/Articles/ArticleDraftListingPage.tsx b/frontends/main/src/app-pages/Articles/ArticleDraftListingPage.tsx index 0f3fff4e1a..5411b021ea 100644 --- a/frontends/main/src/app-pages/Articles/ArticleDraftListingPage.tsx +++ b/frontends/main/src/app-pages/Articles/ArticleDraftListingPage.tsx @@ -12,15 +12,15 @@ import { LoadingSpinner, Typography, } from "ol-components" -import { Permission, useUserHasPermission } from "api/hooks/user" +import { Permission } from "api/hooks/user" import { useArticleList } from "api/hooks/articles" import type { RichTextArticle } from "api/v1" import { LocalDate } from "ol-utilities" import { RiArrowLeftLine, RiArrowRightLine } from "@remixicon/react" import { ArticleBanner, DEFAULT_BACKGROUND_IMAGE_URL } from "./ArticleBanner" import { extractFirstImageFromArticle } from "@/common/articleUtils" -import { notFound } from "next/navigation" import { articlesDraftView, articlesView } from "@/common/urls" +import RestrictedRoute from "@/components/RestrictedRoute/RestrictedRoute" const PAGE_SIZE = 20 @@ -109,8 +109,6 @@ const ArticleDraftPage: React.FC = () => { draft: true, // Filter for drafts only on the backend }) - const isArticleEditor = useUserHasPermission(Permission.ArticleEditor) - useEffect(() => { if (page > 1 && scrollRef.current) { scrollRef.current.scrollIntoView({ behavior: "smooth", block: "start" }) @@ -120,11 +118,11 @@ const ArticleDraftPage: React.FC = () => { const draftArticles = articles?.results const totalPages = articles?.count ? Math.ceil(articles.count / PAGE_SIZE) : 0 - if (!isLoadingArticles && !isArticleEditor) { - return notFound() + if (isLoadingArticles) { + return } return ( - <> + { )} - + ) } diff --git a/frontends/main/src/app/articles/[slugOrId]/page.tsx b/frontends/main/src/app/articles/[slugOrId]/page.tsx deleted file mode 100644 index 68ebf8a394..0000000000 --- a/frontends/main/src/app/articles/[slugOrId]/page.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import React from "react" -import { HydrationBoundary, dehydrate } from "@tanstack/react-query" -import { articleQueries } from "api/hooks/articles/queries" -import { ArticleDetailPage } from "@/app-pages/Articles/ArticleDetailPage" -import { getQueryClient } from "@/app/getQueryClient" -import { learningResourceQueries } from "api/hooks/learningResources" -import { extractLearningResourceIds } from "@/page-components/TiptapEditor/extensions/utils" -import { safeGenerateMetadata, standardizeMetadata } from "@/common/metadata" -import type { RichTextArticle } from "api/v1" -import type { JSONContent } from "@tiptap/react" - -// Extracts the banner subheading paragraph at known location -const extractArticleDescription = ( - article: RichTextArticle, -): string | undefined => { - const banner = article.content?.content?.[0] - const subheading = banner?.content?.[1] - const textNode = subheading?.content?.[0] - return textNode?.text -} - -const extractImageMetadata = ( - article: RichTextArticle, -): { src: string; alt: string } | null => { - const imageWithCaption = article.content?.content?.find( - (node: JSONContent) => node.type === "imageWithCaption", - ) - if (!imageWithCaption) { - return null - } - return { - src: imageWithCaption.attrs.src, - alt: imageWithCaption.attrs.caption || imageWithCaption.attrs.alt, - } -} - -export const generateMetadata = async ( - props: PageProps<"/articles/[slugOrId]">, -) => { - const params = await props.params - - const { slugOrId } = await params - - const queryClient = getQueryClient() - - return safeGenerateMetadata(async () => { - const article = await queryClient.fetchQuery( - articleQueries.articlesDetailRetrieve(slugOrId), - ) - - const description = extractArticleDescription(article) - const leadImage = extractImageMetadata(article) - - return standardizeMetadata({ - title: article.title, - description, - image: leadImage?.src, - imageAlt: leadImage?.alt, - }) - }) -} - -const Page: React.FC> = async (props) => { - const { slugOrId } = await props.params - - const queryClient = getQueryClient() - - await queryClient.fetchQueryOr404( - articleQueries.articlesDetailRetrieve(slugOrId), - ) - - const queryKey = articleQueries.articlesDetailRetrieve(slugOrId).queryKey - const cacheData = queryClient.getQueryData(queryKey) - - const learningResourceIds = cacheData?.content - ? extractLearningResourceIds(cacheData.content) - : [] - - if (learningResourceIds.length > 0) { - const bulkQuery = learningResourceQueries.list({ - resource_id: learningResourceIds, - }) - await queryClient.prefetchQuery(bulkQuery) - } - - return ( - - - - ) -} -export default Page diff --git a/frontends/main/src/app/articles/new/page.tsx b/frontends/main/src/app/articles/new/page.tsx deleted file mode 100644 index 52acf8ab88..0000000000 --- a/frontends/main/src/app/articles/new/page.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from "react" -import { Metadata } from "next" -import { standardizeMetadata } from "@/common/metadata" -import { ArticleNewPage } from "@/app-pages/Articles/ArticleNewPage" - -export const metadata: Metadata = standardizeMetadata({ - title: "New Article", - robots: "noindex, nofollow", -}) - -const Page: React.FC> = () => { - return -} - -export default Page diff --git a/frontends/main/src/app/articles/[slugOrId]/draft/page.tsx b/frontends/main/src/app/news/[slugOrId]/draft/page.tsx similarity index 89% rename from frontends/main/src/app/articles/[slugOrId]/draft/page.tsx rename to frontends/main/src/app/news/[slugOrId]/draft/page.tsx index 9967751c83..1f4dc0b464 100644 --- a/frontends/main/src/app/articles/[slugOrId]/draft/page.tsx +++ b/frontends/main/src/app/news/[slugOrId]/draft/page.tsx @@ -10,9 +10,7 @@ export const generateMetadata = async () => { }) } -const Page: React.FC> = async ( - props, -) => { +const Page: React.FC> = async (props) => { const { slugOrId } = await props.params // No prefetching for draft articles - the client-side component diff --git a/frontends/main/src/app/articles/draft/page.tsx b/frontends/main/src/app/news/draft/page.tsx similarity index 85% rename from frontends/main/src/app/articles/draft/page.tsx rename to frontends/main/src/app/news/draft/page.tsx index a0cd289b6e..56ad03090b 100644 --- a/frontends/main/src/app/articles/draft/page.tsx +++ b/frontends/main/src/app/news/draft/page.tsx @@ -8,7 +8,7 @@ export const metadata: Metadata = standardizeMetadata({ robots: "noindex, nofollow", }) -const Page: React.FC> = () => { +const Page: React.FC> = () => { return } diff --git a/frontends/main/src/common/urls.ts b/frontends/main/src/common/urls.ts index 0421332b8f..082564af73 100644 --- a/frontends/main/src/common/urls.ts +++ b/frontends/main/src/common/urls.ts @@ -25,7 +25,7 @@ export const programLetterView = (id: string) => generatePath(PROGRAMLETTER_VIEW, { id: String(id) }) export const ARTICLES_LISTING = "/news/" export const ARTICLES_VIEW = "/news/[id]" -export const ARTICLES_DRAFT_VIEW = "/articles/[id]/draft" +export const ARTICLES_DRAFT_VIEW = "/news/[id]/draft" export const ARTICLES_EDIT = "/news/[id]/edit" export const ARTICLES_CREATE = "/news/new" export const articlesView = (id: string) => diff --git a/frontends/main/src/page-components/TiptapEditor/ArticleEditor.tsx b/frontends/main/src/page-components/TiptapEditor/ArticleEditor.tsx index 7362fa0852..6c59c6bfb5 100644 --- a/frontends/main/src/page-components/TiptapEditor/ArticleEditor.tsx +++ b/frontends/main/src/page-components/TiptapEditor/ArticleEditor.tsx @@ -282,7 +282,7 @@ const ArticleEditor = ({ onSave, readOnly, article }: ArticleEditorProps) => { Drafts diff --git a/frontends/main/src/page-components/TiptapEditor/extensions/node/ArticleByLineInfoBar/ArticleByLineInfoBar.tsx b/frontends/main/src/page-components/TiptapEditor/extensions/node/ArticleByLineInfoBar/ArticleByLineInfoBar.tsx index d7ef06f890..92d32c516e 100644 --- a/frontends/main/src/page-components/TiptapEditor/extensions/node/ArticleByLineInfoBar/ArticleByLineInfoBar.tsx +++ b/frontends/main/src/page-components/TiptapEditor/extensions/node/ArticleByLineInfoBar/ArticleByLineInfoBar.tsx @@ -117,7 +117,7 @@ export const ArticleByLineInfoBarContent = ({ title={article?.title ?? ""} anchorEl={shareButtonRef.current} onClose={() => setShareOpen(false)} - pageUrl={`${NEXT_PUBLIC_ORIGIN}/articles/${article?.slug}`} + pageUrl={`${NEXT_PUBLIC_ORIGIN}/news/${article?.slug}`} /> {(displayAuthorName || isEditable) && ( From eb58f03ed160e7bea8f7683540193ebeac223324 Mon Sep 17 00:00:00 2001 From: Doof Date: Tue, 24 Feb 2026 17:30:00 +0000 Subject: [PATCH 2/2] Release 0.55.2 --- RELEASE.rst | 5 +++++ main/settings.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/RELEASE.rst b/RELEASE.rst index 0e2689d709..71ad1754e4 100644 --- a/RELEASE.rst +++ b/RELEASE.rst @@ -1,6 +1,11 @@ Release Notes ============= +Version 0.55.2 +-------------- + +- fix: remove the articles route and its relevant code (#2974) + Version 0.55.1 (Released February 24, 2026) -------------- diff --git a/main/settings.py b/main/settings.py index e279435ce3..ded787529b 100644 --- a/main/settings.py +++ b/main/settings.py @@ -34,7 +34,7 @@ from main.settings_pluggy import * # noqa: F403 from openapi.settings_spectacular import open_spectacular_settings -VERSION = "0.55.1" +VERSION = "0.55.2" log = logging.getLogger()