From d5ed4562dd56da8b82b7d6fc05a39b15af148a84 Mon Sep 17 00:00:00 2001 From: AbdulTheActivePiecer Date: Sun, 1 Oct 2023 14:30:53 +0300 Subject: [PATCH 1/3] chore: redirect to 404 if piece or pieces list retrieval fails --- app/features/page.tsx | 4 ++ app/find-apps/[id]/page.tsx | 4 ++ app/find-apps/page.tsx | 4 ++ app/page.tsx | 8 ++- app/pieces/[id]/page.tsx | 65 ++++++++++++------- app/pieces/page.tsx | 5 ++ app/sitemap.tsx | 9 ++- .../landing-page/CombinationsMakerSection.tsx | 7 +- components/voting/VotingSectionServer.tsx | 12 +++- utils/piece-helper.tsx | 14 ++-- 10 files changed, 95 insertions(+), 37 deletions(-) diff --git a/app/features/page.tsx b/app/features/page.tsx index 05583be..c60c173 100644 --- a/app/features/page.tsx +++ b/app/features/page.tsx @@ -11,6 +11,7 @@ import CombinationsMakerSection from "../../components/landing-page/Combinations import { VisibilitySection } from "../../components/features-page/VisibilitySection"; import { FeaturesSection } from "../../components/features-page/FeaturesSection"; import { FeaturesCarousel } from "../../components/features-page/FeaturesCarousel"; +import { redirect } from "next/navigation"; export async function generateMetadata(): Promise { @@ -37,6 +38,9 @@ export async function generateMetadata(): Promise { export default async function FindAppsPage() { const pieces = (await GetPieces()) + if (!pieces) { + redirect("/404"); + } return <>
diff --git a/app/find-apps/[id]/page.tsx b/app/find-apps/[id]/page.tsx index 4393604..7cbe707 100644 --- a/app/find-apps/[id]/page.tsx +++ b/app/find-apps/[id]/page.tsx @@ -4,6 +4,7 @@ import Link from "next/link"; import { NavigationProps } from "../../../components/navigationProps"; import { GetPieces } from "../../../utils/piece-helper"; import { allPiecesSort, corePieces } from "../../../components/utils"; +import { redirect } from "next/navigation"; const alphabet = "abcdefghijklmnopqrstuvwxyz".toUpperCase().split(""); export function generateMetadata( @@ -32,6 +33,9 @@ export function generateMetadata( export default async function FindAppsPage({ params }: NavigationProps) { const pieces = (await GetPieces()); + if (!pieces) { + redirect("/404") + } const allPieces = [...pieces, ...corePieces].sort(allPiecesSort); const filteredPieces = allPieces .filter((piece) => params.id ? (typeof piece === "string" ? piece.startsWith(params?.id.toLowerCase()) : piece.displayName.toLowerCase().startsWith(params?.id.toLowerCase())) : true); diff --git a/app/find-apps/page.tsx b/app/find-apps/page.tsx index bf198a4..5e79a43 100644 --- a/app/find-apps/page.tsx +++ b/app/find-apps/page.tsx @@ -2,6 +2,7 @@ import { Metadata } from "next"; import { GetPieces } from "../../utils/piece-helper"; import Link from "next/link"; import { allPiecesSort, corePieces } from "../../components/utils"; +import { redirect } from "next/navigation"; const alphabet = "abcdefghijklmnopqrstuvwxyz".toUpperCase().split(""); export const metadata: Metadata = { title: 'All apps - Connect your apps with Activepieces', @@ -24,6 +25,9 @@ export const metadata: Metadata = { export default async function FindAppsPage() { const pieces = (await GetPieces()); + if (!pieces) { + redirect("/404"); + } const allPieces = [...pieces, ...corePieces].sort(allPiecesSort); return ( diff --git a/app/page.tsx b/app/page.tsx index 258db99..58d8712 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -12,6 +12,8 @@ import { ComparisionSection } from '../components/landing-page/ComparisonSection import { PiecesDictionarySection } from '../components/landing-page/PiecesDictionarySection'; import { DetailedPiece, GetPiece, GetPieces } from '../utils/piece-helper'; import { aiTemplates, generateTemplateFromDependencies, leadsTemplatesDeps, productivityTemplatesDeps } from '../components/flowTemplateGenerator'; +import { redirect } from 'next/navigation'; + export async function generateMetadata(): Promise { @@ -44,8 +46,12 @@ export async function generateMetadata(): Promise { export default async function Home() { const pieces = await GetPieces(); const detailedPieces: DetailedPiece[] = []; + if (!pieces) { redirect("/404"); } for (const p of pieces) { - detailedPieces.push(await GetPiece(p.name)); + const piece = await GetPiece(p.name); + if (piece) { + detailedPieces.push(piece); + } } const leadsTemplates = leadsTemplatesDeps.map((t) => generateTemplateFromDependencies(t.description, detailedPieces, t.trigger, t.action)); const productivityTemplates = productivityTemplatesDeps.map((t) => generateTemplateFromDependencies(t.description, detailedPieces, t.trigger, t.action)); diff --git a/app/pieces/[id]/page.tsx b/app/pieces/[id]/page.tsx index a8fdfe7..a786ee9 100644 --- a/app/pieces/[id]/page.tsx +++ b/app/pieces/[id]/page.tsx @@ -7,38 +7,59 @@ import { Metadata } from "next"; import { NavigationProps } from "../../../components/navigationProps"; import Link from "next/link"; import { AutomateWithActivepieces } from "../../../components/animated-curtains/AutomateWithActivepieces"; +import { redirect } from 'next/navigation' + + export async function generateMetadata( { params }: NavigationProps, ): Promise { - const pieceName = params.id; - const pieceData = await GetPiece(`@activepieces/piece-${pieceName}`); - const title = `${pieceData.displayName} Integrations - Connect your apps with Activepieces` - const description = `Connect ${pieceData.displayName} to hundreds of apps to automate your business. Activepieces is trusted by thousands of users who automate their everyday tasks.` - return { - title: title, - description: description, - openGraph: { - title: title, - description: description, - siteName: "Activepieces", - images: [ - { - url: "https://www.activepieces.com/meta1.png", - width: 1200, - height: 630, - alt: "Activepieces", - } - ], - url: "https://www.activepieces.com/pieces/" + pieceName, - }, - icons: "/favicon.ico", + try { + const pieceName = params.id; + const pieceData = await GetPiece(`@activepieces/piece-${pieceName}`); + if (pieceData) { + const title = `${pieceData.displayName} Integrations - Connect your apps with Activepieces` + const description = `Connect ${pieceData.displayName} to hundreds of apps to automate your business. Activepieces is trusted by thousands of users who automate their everyday tasks.` + return { + title: title, + description: description, + openGraph: { + title: title, + description: description, + siteName: "Activepieces", + images: [ + { + url: "https://www.activepieces.com/meta1.png", + width: 1200, + height: 630, + alt: "Activepieces", + } + ], + url: "https://www.activepieces.com/pieces/" + pieceName, + }, + icons: "/favicon.ico", + } + } + return {} } + catch (ex) { + console.error(JSON.stringify(ex)); + return { + + } + } + + + } export default async function PiecePage({ params }: NavigationProps) { const pieceName = params.id; + const pieceData = await GetPiece(`@activepieces/piece-${pieceName}`); + if (!pieceData) { + redirect('/404') + } const actions: ActionBase[][] = [[], []]; Object.values(pieceData.actions).forEach((action, i) => { if (i % 2 === 0) { diff --git a/app/pieces/page.tsx b/app/pieces/page.tsx index 8b0bb45..83dc866 100644 --- a/app/pieces/page.tsx +++ b/app/pieces/page.tsx @@ -2,6 +2,8 @@ import { Metadata } from "next"; import { GetPieces } from "../../utils/piece-helper"; import PiecesList from "../../components/pieces/List"; +import { redirect } from "next/navigation"; + export async function generateMetadata(): Promise { @@ -31,6 +33,9 @@ export async function generateMetadata(): Promise { export default async function PiecesPage() { const pieces = await GetPieces(); + if (!pieces) { + redirect("/404") + } return (
diff --git a/app/sitemap.tsx b/app/sitemap.tsx index b39888b..5d977ff 100644 --- a/app/sitemap.tsx +++ b/app/sitemap.tsx @@ -18,9 +18,12 @@ export default async function sitemap(): Promise { '/pieces/webhook', ] const pieces = await GetPieces() - pieces.forEach((piece) => { - simpleRoutes.push(`/pieces/${piece.name.replace('@activepieces/piece-', '')}`) - }) + if (pieces) { + pieces.forEach((piece) => { + simpleRoutes.push(`/pieces/${piece.name.replace('@activepieces/piece-', '')}`) + }) + } + const blogs = await getBlogs() blogs.forEach((blog) => { diff --git a/components/landing-page/CombinationsMakerSection.tsx b/components/landing-page/CombinationsMakerSection.tsx index eea3ba8..97cc91d 100644 --- a/components/landing-page/CombinationsMakerSection.tsx +++ b/components/landing-page/CombinationsMakerSection.tsx @@ -6,15 +6,18 @@ import CombinationsCreator from './CombinationsCreator'; const CombinationsMakerSection = async () => { const pieces = await GetPieces(); + if (!pieces) return (<>); const piecesWithTriggers = pieces.filter(piece => piece.triggers > 0); const piecesWithActions = pieces.filter(piece => piece.actions > 0); const triggersPieces: DetailedPiece[] = [] const actionsPieces: DetailedPiece[] = []; for (const p of piecesWithTriggers) { - triggersPieces.push(await GetPiece(p.name)); + const rp = await GetPiece(p.name); + if (rp) { triggersPieces.push(rp); } } for (const p of piecesWithActions) { - actionsPieces.push(await GetPiece(p.name)); + const rp = await GetPiece(p.name); + if (rp) { actionsPieces.push(rp); } } return ( diff --git a/components/voting/VotingSectionServer.tsx b/components/voting/VotingSectionServer.tsx index 7440ee1..28f0372 100644 --- a/components/voting/VotingSectionServer.tsx +++ b/components/voting/VotingSectionServer.tsx @@ -12,10 +12,16 @@ export const VotingSectionServer = async () => { const pieces = await GetPieces(); const detailedPieces: DetailedPiece[] = [] - for (const piece of pieces) { - const detailedPiece = await GetPiece(piece.name); - detailedPieces.push(detailedPiece); + if (pieces) { + for (const piece of pieces) { + const detailedPiece = await GetPiece(piece.name); + if (detailedPiece) { + detailedPieces.push(detailedPiece); + } + + } } + const supabase = createServerComponentClient({ cookies }) const votes = await getSupabaseVotesForIssues(supabase); diff --git a/utils/piece-helper.tsx b/utils/piece-helper.tsx index cdc1ac8..2d029d5 100644 --- a/utils/piece-helper.tsx +++ b/utils/piece-helper.tsx @@ -32,7 +32,7 @@ type PieceMetaData = (PieceBase & { triggers: number; }); -export async function GetPieces(): Promise { +export async function GetPieces(): Promise { const res = await fetch( `https://cloud.activepieces.com/api/v1/pieces`, { @@ -40,26 +40,28 @@ export async function GetPieces(): Promise { } ); if (!res.ok) { - throw new Error("Failed to fetch data"); + console.error("Failed to fetch pieces ") + return null; } const resJson: PieceMetaData[] = await res.json(); return resJson.filter(p => p.name !== "@activepieces/piece-instagram-business" && p.name !== "@activepieces/piece-shopify" && p.name !== "@activepieces/piece-facebook-pages"); } -export async function GetPiece(Name: string): Promise { +export async function GetPiece(pieceName: string): Promise { const res = await fetch( - `https://cloud.activepieces.com/api/v1/pieces/${Name}`, + `https://cloud.activepieces.com/api/v1/pieces/${pieceName}`, { cache: "force-cache" } ); if (!res.ok) { - throw new Error("Failed to fetch data"); + console.error("Failed to fetch piece " + pieceName) + return null; } const data = await res.json(); return { - name: Name, + name: pieceName, version: data.version, displayName: data.displayName, description: data.description, From cd1fafc36b8262c06b474066e4babeb36968c6d5 Mon Sep 17 00:00:00 2001 From: AbdulTheActivePiecer Date: Sun, 1 Oct 2023 14:40:56 +0300 Subject: [PATCH 2/3] chore: redirect to 404 if an error is thrown while retrieving blogs --- app/blog/[id]/page.tsx | 146 +++++++++++++++++++++++------------------ app/blog/page.tsx | 10 ++- app/sitemap.tsx | 13 ++-- 3 files changed, 100 insertions(+), 69 deletions(-) diff --git a/app/blog/[id]/page.tsx b/app/blog/[id]/page.tsx index 66ed2a6..14e6bc4 100644 --- a/app/blog/[id]/page.tsx +++ b/app/blog/[id]/page.tsx @@ -8,6 +8,8 @@ import { NavigationProps } from "../../../components/navigationProps"; import Link from "next/link"; import { formatDate } from "@/utils/date-helper"; import { createClient } from "@supabase/supabase-js"; +import { redirect } from "next/navigation"; + export interface Blog { title: string; @@ -32,7 +34,8 @@ async function readBlogData(blogName: string, userPassword: string | undefined | .select('*') .eq('slug', blogName) if (error) { - throw error + + throw new Error(error.message) } if (!data || data.length === 0) { throw new Error('Blog not found') @@ -74,75 +77,90 @@ export async function generateMetadata({ }: NavigationProps): Promise { const blogName = params.id; const password = searchParams.password; - const { title, description, thumbnail, author } = await readBlogData(blogName, password); - - return { - title: title + ' - Activepieces', - description: description, - openGraph: { + try { + const { title, description, thumbnail, author } = await readBlogData(blogName, password); + return { title: title + ' - Activepieces', description: description, - siteName: "Activepieces", - images: [ - { - url: thumbnail, - width: 1200, - height: 630, - alt: "Activepieces Blog", - }, - ], - url: `www.activepieces.com/blog/${blogName}`, - }, - authors: { - url: `www.activepieces.com/blog/${blogName}`, - name: author, - }, - icons: "/favicon.ico", - }; + openGraph: { + title: title + ' - Activepieces', + description: description, + siteName: "Activepieces", + images: [ + { + url: thumbnail, + width: 1200, + height: 630, + alt: "Activepieces Blog", + }, + ], + url: `www.activepieces.com/blog/${blogName}`, + }, + authors: { + url: `www.activepieces.com/blog/${blogName}`, + name: author, + }, + icons: "/favicon.ico", + }; + } + catch (ex) { + console.error(JSON.stringify(ex)); + return {}; + + } + + + } export default async function BlogPost({ params, searchParams }: NavigationProps) { const blogName = params.id; const password = searchParams.password; - - const { publishedOn, content, title, thumbnail, author } = await readBlogData(blogName, password); - return ( -
-
- -
-

- {title} -

-
- {author} | Published on {publishedOn} + try { + const { publishedOn, content, title, thumbnail, author } = await readBlogData(blogName, password); + return ( +
+
+ +
+

+ {title} +

+
+ {author} | Published on {publishedOn} +
+
+ Blog thumbnail +
+
+
+ {content}
-
- Blog thumbnail -
-
-
- {content} -
-
-
- ); +
+
+ ); + } + catch (ex) { + console.error(JSON.stringify(ex)); + redirect("/404"); + } + } diff --git a/app/blog/page.tsx b/app/blog/page.tsx index fc077ea..84c8f2a 100644 --- a/app/blog/page.tsx +++ b/app/blog/page.tsx @@ -3,6 +3,7 @@ import Link from "next/link"; import { Metadata } from "next"; import { AutomateWithActivepieces } from "../../components/animated-curtains/AutomateWithActivepieces"; import { BlogPost, getBlogs } from "@/utils/blogs-helper"; +import { redirect } from "next/navigation"; export async function generateMetadata(): Promise { @@ -56,8 +57,15 @@ function BlogCard({ post }: { post: BlogPost }) { export default async function BlogIndex() { // Fetch data + let posts: BlogPost[] = []; + try { + posts = await getBlogs(); + } + catch (ex) { + console.error(ex); + redirect("/404"); + } - const posts = await getBlogs(); return ( <>
diff --git a/app/sitemap.tsx b/app/sitemap.tsx index 5d977ff..6cf03a1 100644 --- a/app/sitemap.tsx +++ b/app/sitemap.tsx @@ -24,11 +24,16 @@ export default async function sitemap(): Promise { }) } + try { + const blogs = await getBlogs() + blogs.forEach((blog) => { + simpleRoutes.push(`/blog/${blog.slug}`) + }) + } + catch (ex) { + console.error(JSON.stringify(ex)) + } - const blogs = await getBlogs() - blogs.forEach((blog) => { - simpleRoutes.push(`/blog/${blog.slug}`) - }) return [ ...simpleRoutes.map((path) => ({ From 5899f54ef49ee0ee7c4c47af42596038990e9bc8 Mon Sep 17 00:00:00 2001 From: AbdulTheActivePiecer Date: Sun, 1 Oct 2023 14:45:54 +0300 Subject: [PATCH 3/3] chore: don't stringify errors --- app/blog/[id]/page.tsx | 4 ++-- app/pieces/[id]/page.tsx | 2 +- app/sitemap.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/blog/[id]/page.tsx b/app/blog/[id]/page.tsx index 14e6bc4..a3e2dcf 100644 --- a/app/blog/[id]/page.tsx +++ b/app/blog/[id]/page.tsx @@ -104,7 +104,7 @@ export async function generateMetadata({ }; } catch (ex) { - console.error(JSON.stringify(ex)); + console.error(ex); return {}; } @@ -159,7 +159,7 @@ export default async function BlogPost({ params, searchParams }: NavigationProps ); } catch (ex) { - console.error(JSON.stringify(ex)); + console.error((ex)); redirect("/404"); } diff --git a/app/pieces/[id]/page.tsx b/app/pieces/[id]/page.tsx index a786ee9..3a7f92d 100644 --- a/app/pieces/[id]/page.tsx +++ b/app/pieces/[id]/page.tsx @@ -43,7 +43,7 @@ export async function generateMetadata( return {} } catch (ex) { - console.error(JSON.stringify(ex)); + console.error((ex)); return { } diff --git a/app/sitemap.tsx b/app/sitemap.tsx index 6cf03a1..0c4aec1 100644 --- a/app/sitemap.tsx +++ b/app/sitemap.tsx @@ -31,7 +31,7 @@ export default async function sitemap(): Promise { }) } catch (ex) { - console.error(JSON.stringify(ex)) + console.error(ex) }