diff --git a/src/App.tsx b/src/App.tsx
index 8aa1e17cf..fd8836c76 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -7,7 +7,13 @@ import React, { ReactNode, useEffect, useState, useMemo } from "react";
import { IconType } from "react-icons";
import { AiFillHeart } from "react-icons/ai";
import { BsLink, BsToggles } from "react-icons/bs";
-import { FaArchive, FaBell, FaCrosshairs, FaTasks } from "react-icons/fa";
+import {
+ FaArchive,
+ FaBell,
+ FaCrosshairs,
+ FaPlug,
+ FaTasks
+} from "react-icons/fa";
import { HiUser } from "react-icons/hi";
import { ImLifebuoy } from "react-icons/im";
import {
@@ -184,6 +190,12 @@ const ConnectionsPage = dynamic(() =>
)
);
+const PluginsPage = dynamic(() =>
+ import("@flanksource-ui/pages/Settings/PluginsPage").then(
+ (m) => m.PluginsPage
+ )
+);
+
const EventQueueStatusPage = dynamic(() =>
import("@flanksource-ui/pages/Settings/EventQueueStatus").then(
(m) => m.EventQueueStatusPage
@@ -507,6 +519,13 @@ const settingsNav: SettingsNavigationItems = {
featureName: features["settings.integrations"],
resourceName: tables.database
},
+ {
+ name: "Plugins",
+ href: "/settings/plugins",
+ icon: FaPlug,
+ featureName: features["settings.plugins"],
+ resourceName: tables.plugins
+ },
{
name: "Views",
href: "/settings/views",
@@ -938,6 +957,16 @@ export function IncidentManagerRoutes({ sidebar }: { sidebar: ReactNode }) {
+ ,
+ tables.plugins,
+ "read",
+ true
+ )}
+ />
+
("/plugins");
+}
diff --git a/src/context/UserAccessContext/permissions.ts b/src/context/UserAccessContext/permissions.ts
index 67abba003..20f4dd867 100644
--- a/src/context/UserAccessContext/permissions.ts
+++ b/src/context/UserAccessContext/permissions.ts
@@ -17,6 +17,7 @@ export const tables = {
feature_flags: "properties",
logging_backends: "logging_backends",
integrations: "integrations",
+ plugins: "plugins",
notifications: "notifications",
playbooks: "playbooks",
playbook_runs: "playbook_runs",
diff --git a/src/pages/Settings/PluginsPage.tsx b/src/pages/Settings/PluginsPage.tsx
new file mode 100644
index 000000000..28c311da1
--- /dev/null
+++ b/src/pages/Settings/PluginsPage.tsx
@@ -0,0 +1,101 @@
+import {
+ getPlugins,
+ PluginListing
+} from "@flanksource-ui/api/services/plugins";
+import {
+ BreadcrumbNav,
+ BreadcrumbRoot
+} from "@flanksource-ui/ui/BreadcrumbNav";
+import { Head } from "@flanksource-ui/ui/Head";
+import { SearchLayout } from "@flanksource-ui/ui/Layout/SearchLayout";
+import MRTDataTable from "@flanksource-ui/ui/MRTDataTable/MRTDataTable";
+import { useQuery } from "@tanstack/react-query";
+import clsx from "clsx";
+import { MRT_ColumnDef } from "mantine-react-table";
+
+const columns: MRT_ColumnDef[] = [
+ {
+ header: "Name",
+ accessorKey: "name",
+ maxSize: 50,
+ enableResizing: true
+ },
+ {
+ header: "Description",
+ accessorKey: "description",
+ enableResizing: true
+ },
+ {
+ header: "Version",
+ accessorKey: "version",
+ maxSize: 100,
+ enableResizing: true
+ },
+ {
+ header: "Agent",
+ id: "agent",
+ accessorFn: (row) => row.agent?.name ?? "",
+ maxSize: 100,
+ enableResizing: true
+ }
+];
+
+function PluginsList({
+ data,
+ isLoading,
+ className
+}: {
+ data: PluginListing[];
+ isLoading?: boolean;
+ className?: string;
+}) {
+ return (
+
+
+
+ );
+}
+
+export function PluginsPage() {
+ const {
+ isLoading: loading,
+ data: plugins,
+ refetch
+ } = useQuery({
+ queryKey: ["plugins", "all"],
+ queryFn: async () => {
+ const response = await getPlugins();
+ return response.data ?? [];
+ }
+ });
+
+ return (
+ <>
+
+
+ Plugins
+
+ ]}
+ />
+ }
+ onRefresh={() => {
+ refetch();
+ }}
+ contentClass="p-0 h-full"
+ loading={loading}
+ >
+
+
+ >
+ );
+}
diff --git a/src/services/permissions/features.ts b/src/services/permissions/features.ts
index d11c05b36..dc7d628ac 100644
--- a/src/services/permissions/features.ts
+++ b/src/services/permissions/features.ts
@@ -24,6 +24,7 @@ export const features = {
"settings.notifications": "settings.notifications",
"settings.playbooks": "settings.playbooks",
"settings.integrations": "settings.integrations",
+ "settings.plugins": "settings.plugins",
"settings.permissions": "settings.permissions",
"settings.mcp": "settings.mcp",
"settings.artifacts": "settings.artifacts"