From 27754b002a9df4b71927ce284f1e52e0284ea91e Mon Sep 17 00:00:00 2001 From: sumit_chaturvedi Date: Mon, 31 Mar 2025 08:52:16 +0530 Subject: [PATCH 1/6] feat(ui): Add notification system for rss feeds --- ui/actions/feeds/feeds.tsx | 25 ++++++++ ui/actions/feeds/index.tsx | 1 + ui/components/feeds/feeds-client.tsx | 93 ++++++++++++++++++++++++++++ ui/components/feeds/feeds-server.tsx | 8 +++ ui/components/feeds/index.ts | 2 + ui/components/icons/Icons.tsx | 25 ++++++++ ui/components/ui/nav-bar/navbar.tsx | 2 + ui/package.json | 1 + 8 files changed, 157 insertions(+) create mode 100644 ui/actions/feeds/feeds.tsx create mode 100644 ui/actions/feeds/index.tsx create mode 100644 ui/components/feeds/feeds-client.tsx create mode 100644 ui/components/feeds/feeds-server.tsx create mode 100644 ui/components/feeds/index.ts diff --git a/ui/actions/feeds/feeds.tsx b/ui/actions/feeds/feeds.tsx new file mode 100644 index 0000000000..32dbf69b01 --- /dev/null +++ b/ui/actions/feeds/feeds.tsx @@ -0,0 +1,25 @@ +"use server"; + +import Parser from "rss-parser"; + +// TODO: Need to use the actual feed url +const RSS_FEED_URL = "https://prowler.com/blog/rss"; + +export const fetchFeeds = async (): Promise => { + const parser = new Parser(); + try { + const feed = await parser.parseURL(RSS_FEED_URL); + return [ + { + title: feed.title, + description: feed.description, + link: feed.link, + lastBuildDate: new Date(feed.lastBuildDate).toLocaleString(), + }, + ]; + } catch (error) { + // eslint-disable-next-line no-console + console.error("Error fetching RSS feed:", error); + return []; + } +}; diff --git a/ui/actions/feeds/index.tsx b/ui/actions/feeds/index.tsx new file mode 100644 index 0000000000..2ab8f864d4 --- /dev/null +++ b/ui/actions/feeds/index.tsx @@ -0,0 +1 @@ +export * from "./feeds"; diff --git a/ui/components/feeds/feeds-client.tsx b/ui/components/feeds/feeds-client.tsx new file mode 100644 index 0000000000..573549c2f9 --- /dev/null +++ b/ui/components/feeds/feeds-client.tsx @@ -0,0 +1,93 @@ +"use client"; + +import Link from "next/link"; +import { useState } from "react"; + +import { BellIcon as Icon } from "@/components/icons"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu/dropdown-menu"; +import { cn } from "@/lib/utils"; + +import { Button } from "../ui/button/button"; + +interface Feed { + title: string; + link: string; + description: string; + lastBuildDate: string; +} + +interface FeedsClientProps { + initialFeeds?: Feed[]; // Adjust fields based on your data structure +} + +// TODO: Need to update FeedsClientProps with actual interface when actual RSS data finialized +export const FeedsClient: React.FC = ({ + initialFeeds = [], +}) => { + const [feed] = useState(initialFeeds); + const [isAllowedDomain] = useState( + //process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true", + true, + ); + + return ( + <> + {isAllowedDomain && ( + + + + + +

Feeds

+
+ {feed.length === 0 ? ( +

+ No feeds available +

+ ) : ( + feed.map((item, index) => ( + + +

+ {item.title} +

+

+ {item.description} +

+ + {item.lastBuildDate} + + +
+ )) + )} +
+
+
+ )} + + ); +}; diff --git a/ui/components/feeds/feeds-server.tsx b/ui/components/feeds/feeds-server.tsx new file mode 100644 index 0000000000..78658ad868 --- /dev/null +++ b/ui/components/feeds/feeds-server.tsx @@ -0,0 +1,8 @@ +import { fetchFeeds } from "@/actions/feeds"; +import { FeedsClient } from "@/components/feeds"; + +export const FeedsServer = async () => { + const feeds = await fetchFeeds(); + + return ; +}; diff --git a/ui/components/feeds/index.ts b/ui/components/feeds/index.ts new file mode 100644 index 0000000000..3af78ca16a --- /dev/null +++ b/ui/components/feeds/index.ts @@ -0,0 +1,2 @@ +export * from "./feeds-client"; +export * from "./feeds-server"; diff --git a/ui/components/icons/Icons.tsx b/ui/components/icons/Icons.tsx index 4cf36bc6c7..293fb8d793 100644 --- a/ui/components/icons/Icons.tsx +++ b/ui/components/icons/Icons.tsx @@ -1025,3 +1025,28 @@ export const GCPIcon: React.FC = ({ ); }; + +export const BellIcon: React.FC = ({ + size = 24, + width, + height, + ...props +}) => { + return ( + + + + + ); +}; diff --git a/ui/components/ui/nav-bar/navbar.tsx b/ui/components/ui/nav-bar/navbar.tsx index 5cebc9586f..2873b2f408 100644 --- a/ui/components/ui/nav-bar/navbar.tsx +++ b/ui/components/ui/nav-bar/navbar.tsx @@ -1,5 +1,6 @@ import { Icon } from "@iconify/react"; +import { FeedsServer } from "@/components/feeds"; import { ThemeSwitch } from "@/components/ThemeSwitch"; import { UserProfileProps } from "@/types"; @@ -26,6 +27,7 @@ export function Navbar({ title, icon, user }: NavbarProps) {

{title}

+
diff --git a/ui/package.json b/ui/package.json index 4a08e910a9..f52e7b48a4 100644 --- a/ui/package.json +++ b/ui/package.json @@ -36,6 +36,7 @@ "react-dom": "^18.3.1", "react-hook-form": "^7.52.2", "recharts": "^2.13.0-alpha.4", + "rss-parser": "^3.13.0", "server-only": "^0.0.1", "shadcn-ui": "^0.2.3", "sharp": "^0.33.5", From c3cfab310d2a9475ea0fe1a59a9ad58eb2568d2f Mon Sep 17 00:00:00 2001 From: sumit_chaturvedi Date: Mon, 31 Mar 2025 09:28:06 +0530 Subject: [PATCH 2/6] srn Updated the logic to show the notification icon --- ui/actions/compliances/compliances.ts | 4 +- ui/components/feeds/feeds-client.tsx | 94 +++++++++++---------------- ui/components/ui/nav-bar/navbar.tsx | 2 +- 3 files changed, 43 insertions(+), 57 deletions(-) diff --git a/ui/actions/compliances/compliances.ts b/ui/actions/compliances/compliances.ts index 77b7e76696..66eae74004 100644 --- a/ui/actions/compliances/compliances.ts +++ b/ui/actions/compliances/compliances.ts @@ -72,7 +72,9 @@ export const getComplianceOverviewMetadataInfo = async ({ }); if (!response.ok) { - throw new Error(`Failed to fetch compliance overview metadata info: ${response.statusText}`); + throw new Error( + `Failed to fetch compliance overview metadata info: ${response.statusText}`, + ); } const parsedData = parseStringify(await response.json()); diff --git a/ui/components/feeds/feeds-client.tsx b/ui/components/feeds/feeds-client.tsx index 573549c2f9..0b2b9c7650 100644 --- a/ui/components/feeds/feeds-client.tsx +++ b/ui/components/feeds/feeds-client.tsx @@ -22,7 +22,7 @@ interface Feed { } interface FeedsClientProps { - initialFeeds?: Feed[]; // Adjust fields based on your data structure + initialFeeds?: Feed[]; } // TODO: Need to update FeedsClientProps with actual interface when actual RSS data finialized @@ -30,64 +30,48 @@ export const FeedsClient: React.FC = ({ initialFeeds = [], }) => { const [feed] = useState(initialFeeds); - const [isAllowedDomain] = useState( - //process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true", - true, - ); return ( <> - {isAllowedDomain && ( - - - - - -

Feeds

-
- {feed.length === 0 ? ( -

- No feeds available -

- ) : ( - feed.map((item, index) => ( - + + + + +

Feeds

+
+ {feed.length === 0 ? ( +

+ No feeds available +

+ ) : ( + feed.map((item, index) => ( + + - -

- {item.title} -

-

- {item.description} -

- - {item.lastBuildDate} - - -
- )) - )} -
-
- - )} +

+ {item.title} +

+

{item.description}

+ + {item.lastBuildDate} + + +
+ )) + )} +
+
+
); }; diff --git a/ui/components/ui/nav-bar/navbar.tsx b/ui/components/ui/nav-bar/navbar.tsx index 2873b2f408..99e6c158ae 100644 --- a/ui/components/ui/nav-bar/navbar.tsx +++ b/ui/components/ui/nav-bar/navbar.tsx @@ -27,7 +27,7 @@ export function Navbar({ title, icon, user }: NavbarProps) {

{title}

- + {process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true" && }
From 5803cdf297da52889013daeaca712a78c1c3c115 Mon Sep 17 00:00:00 2001 From: sumit_chaturvedi Date: Mon, 31 Mar 2025 09:31:39 +0530 Subject: [PATCH 3/6] srn Fixed lint issue --- ui/components/ui/nav-bar/navbar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/components/ui/nav-bar/navbar.tsx b/ui/components/ui/nav-bar/navbar.tsx index 99e6c158ae..1ad3c5cfc0 100644 --- a/ui/components/ui/nav-bar/navbar.tsx +++ b/ui/components/ui/nav-bar/navbar.tsx @@ -27,7 +27,7 @@ export function Navbar({ title, icon, user }: NavbarProps) {

{title}

- {process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true" && } + {process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true" && }
From 921cc62ed7d87d911ac4fc720f81357b58a1cbe7 Mon Sep 17 00:00:00 2001 From: sumit_chaturvedi Date: Fri, 11 Apr 2025 14:01:17 +0530 Subject: [PATCH 4/6] srn Lint fixes --- ui/components/feeds/feeds-client.tsx | 9 ++++++++- ui/components/icons/Icons.tsx | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ui/components/feeds/feeds-client.tsx b/ui/components/feeds/feeds-client.tsx index fa76ed8032..edfc715a5b 100644 --- a/ui/components/feeds/feeds-client.tsx +++ b/ui/components/feeds/feeds-client.tsx @@ -37,7 +37,14 @@ export const FeedsClient: React.FC = ({ From 407c80a7a78110de00b1f7bef1c37762cf219f77 Mon Sep 17 00:00:00 2001 From: sumit_chaturvedi Date: Wed, 14 May 2025 10:17:16 +0530 Subject: [PATCH 6/6] srn Added missing nullable --- ui/actions/feeds/feeds.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/actions/feeds/feeds.tsx b/ui/actions/feeds/feeds.tsx index 08f060490b..76466f9f69 100644 --- a/ui/actions/feeds/feeds.tsx +++ b/ui/actions/feeds/feeds.tsx @@ -5,7 +5,7 @@ import Parser from "rss-parser"; const RSS_FEED_URL = process.env.RSS_FEED_URL || ""; export const fetchFeeds = async (): Promise => { - if (RSS_FEED_URL.trim()?.length > 0) { + if (RSS_FEED_URL?.trim()?.length > 0) { const parser = new Parser(); try { // TODO: Need to update return logic when actual URL is updated for RSS FEED