diff --git a/ui/actions/lighthouse/lighthouse.ts b/ui/actions/lighthouse/lighthouse.ts index 686dc179cd..38cca0ee7c 100644 --- a/ui/actions/lighthouse/lighthouse.ts +++ b/ui/actions/lighthouse/lighthouse.ts @@ -2,11 +2,12 @@ import { apiBaseUrl, getAuthHeaders } from "@/lib/helper"; -const getLighthouseConfigId = async (): Promise => { +export const getAIKey = async (): Promise => { const headers = await getAuthHeaders({ contentType: false }); const url = new URL( - `${apiBaseUrl}/lighthouse-configurations?filter[name]=OpenAI`, + `${apiBaseUrl}/lighthouse-configurations?fields[lighthouse-config]=api_key`, ); + try { const response = await fetch(url.toString(), { method: "GET", @@ -17,35 +18,35 @@ const getLighthouseConfigId = async (): Promise => { // Check if data array exists and has at least one item if (data?.data && data.data.length > 0) { - return data.data[0].id; + return data.data[0].attributes.api_key || ""; } // Return empty string if no configuration found return ""; } catch (error) { - console.error("[Server] Error in getOpenAIConfigurationId:", error); + console.error("[Server] Error in getAIKey:", error); return ""; } }; -export const getAIKey = async (): Promise => { +export const checkLighthouseConnection = async (configId: string) => { const headers = await getAuthHeaders({ contentType: false }); - const configId = await getLighthouseConfigId(); - - if (!configId) { - return ""; - } - const url = new URL( - `${apiBaseUrl}/lighthouse-configurations/${configId}?fields[lighthouse-config]=api_key`, + `${apiBaseUrl}/lighthouse-configurations/${configId}/connection`, ); - const response = await fetch(url.toString(), { - method: "GET", - headers, - }); - const data = await response.json(); - return data.data.attributes.api_key; + try { + const response = await fetch(url.toString(), { + method: "POST", + headers, + }); + + const data = await response.json(); + return data; + } catch (error) { + console.error("[Server] Error in checkLighthouseConnection:", error); + return undefined; + } }; export const createLighthouseConfig = async (config: { @@ -74,29 +75,36 @@ export const createLighthouseConfig = async (config: { body: JSON.stringify(payload), }); const data = await response.json(); + + // Trigger connection check in background + if (data?.data?.id) { + checkLighthouseConnection(data.data.id); + } + return data; } catch (error) { - console.error("[Server] Error in createAIConfiguration:", error); + console.error("[Server] Error in createLighthouseConfig:", error); return undefined; } }; export const getLighthouseConfig = async () => { const headers = await getAuthHeaders({ contentType: false }); - const configId = await getLighthouseConfigId(); + const url = new URL(`${apiBaseUrl}/lighthouse-configurations`); - if (!configId) { - return undefined; - } - - const url = new URL(`${apiBaseUrl}/lighthouse-configurations/${configId}`); try { const response = await fetch(url.toString(), { method: "GET", headers, }); const data = await response.json(); - return data; + + // Check if data array exists and has at least one item + if (data?.data && data.data.length > 0) { + return data.data[0]; + } + + return undefined; } catch (error) { console.error("[Server] Error in getLighthouseConfig:", error); return undefined; @@ -109,14 +117,26 @@ export const updateLighthouseConfig = async (config: { businessContext: string; }) => { const headers = await getAuthHeaders({ contentType: true }); - const configId = await getLighthouseConfigId(); - - if (!configId) { - return undefined; - } + // Get the config ID from the list endpoint + const url = new URL(`${apiBaseUrl}/lighthouse-configurations`); try { - const url = new URL(`${apiBaseUrl}/lighthouse-configurations/${configId}`); + const response = await fetch(url.toString(), { + method: "GET", + headers: await getAuthHeaders({ contentType: false }), + }); + + const data = await response.json(); + + // Check if data array exists and has at least one item + if (!data?.data || data.data.length === 0) { + return undefined; + } + + const configId = data.data[0].id; + const updateUrl = new URL( + `${apiBaseUrl}/lighthouse-configurations/${configId}`, + ); // Prepare the request payload following the JSONAPI format const payload = { @@ -131,16 +151,22 @@ export const updateLighthouseConfig = async (config: { }, }; - const response = await fetch(url.toString(), { + const updateResponse = await fetch(updateUrl.toString(), { method: "PATCH", headers, body: JSON.stringify(payload), }); - const data = await response.json(); - return data; + const updateData = await updateResponse.json(); + + // Trigger connection check in background + if (updateData?.data?.id || configId) { + checkLighthouseConnection(configId); + } + + return updateData; } catch (error) { - console.error("[Server] Error in updateAIConfiguration:", error); + console.error("[Server] Error in updateLighthouseConfig:", error); return undefined; } }; diff --git a/ui/app/(prowler)/lighthouse/config/page.tsx b/ui/app/(prowler)/lighthouse/config/page.tsx index 5872f92d12..ce7b2017e7 100644 --- a/ui/app/(prowler)/lighthouse/config/page.tsx +++ b/ui/app/(prowler)/lighthouse/config/page.tsx @@ -6,12 +6,11 @@ export const dynamic = "force-dynamic"; export default async function ChatbotConfigPage() { const response = await getLighthouseConfig(); - - const initialValues = response?.data?.attributes + const initialValues = response?.attributes ? { - model: response.data.attributes.model, - apiKey: response.data.attributes.api_key || "", - businessContext: response.data.attributes.business_context || "", + model: response.attributes.model, + apiKey: response.attributes.api_key || "", + businessContext: response.attributes.business_context || "", } : { model: "gpt-4o", diff --git a/ui/app/(prowler)/lighthouse/page.tsx b/ui/app/(prowler)/lighthouse/page.tsx index 469303ed44..089504a78d 100644 --- a/ui/app/(prowler)/lighthouse/page.tsx +++ b/ui/app/(prowler)/lighthouse/page.tsx @@ -1,13 +1,16 @@ -import { getAIKey } from "@/actions/lighthouse/lighthouse"; +import { getLighthouseConfig } from "@/actions/lighthouse/lighthouse"; import { Chat } from "@/components/lighthouse"; import { ContentLayout } from "@/components/ui"; export default async function AIChatbot() { - const apiKey = await getAIKey(); + const config = await getLighthouseConfig(); + + const hasConfig = !!config; + const isActive = config?.attributes?.is_active ?? false; return ( - + ); } diff --git a/ui/components/lighthouse/chat.tsx b/ui/components/lighthouse/chat.tsx index 4ed1aefd1b..1018607f17 100644 --- a/ui/components/lighthouse/chat.tsx +++ b/ui/components/lighthouse/chat.tsx @@ -16,14 +16,15 @@ interface SuggestedAction { } interface ChatProps { - hasApiKey: boolean; + hasConfig: boolean; + isActive: boolean; } interface ChatFormData { message: string; } -export const Chat = ({ hasApiKey }: ChatProps) => { +export const Chat = ({ hasConfig, isActive }: ChatProps) => { const { messages, handleSubmit, handleInputChange, append, status } = useChat( { api: "/api/lighthouse/analyst", @@ -119,17 +120,23 @@ export const Chat = ({ hasApiKey }: ChatProps) => { }, ]; + // Determine if chat should be disabled + const shouldDisableChat = !hasConfig || !isActive; + return (
- {!hasApiKey && ( + {shouldDisableChat && (

- OpenAI API Key Required + {!hasConfig + ? "OpenAI API Key Required" + : "OpenAI API Key Invalid"}

- Please configure your OpenAI API key to use the Lighthouse Cloud - Security Analyst. + {!hasConfig + ? "Please configure your OpenAI API key to use the Lighthouse Cloud Security Analyst." + : "OpenAI API key is invalid. Please update your key to use Lighthouse Cloud Security Analyst."}

{ { href: "/manage-groups", label: "Provider Groups", icon: Group }, { href: "/scans", label: "Scan Jobs", icon: Timer }, { href: "/roles", label: "Roles", icon: UserCog }, - // { href: "/lighthouse/config", label: "Lighthouse", icon: Cog }, + { href: "/lighthouse/config", label: "Lighthouse", icon: Cog }, ], defaultOpen: true, }, @@ -156,16 +156,16 @@ export const getMenuList = (pathname: string): GroupProps[] => { }, ], }, - // { - // groupLabel: "Prowler Lighthouse", - // menus: [ - // { - // href: "/lighthouse", - // label: "Lighthouse", - // icon: Bot, - // }, - // ], - // }, + { + groupLabel: "Prowler Lighthouse", + menus: [ + { + href: "/lighthouse", + label: "Lighthouse", + icon: Bot, + }, + ], + }, { groupLabel: "", menus: [