From 3edb140eec07e7c3306c8b1440e81e6a8caa5302 Mon Sep 17 00:00:00 2001 From: Giuseppe Scuglia Date: Mon, 16 Dec 2024 10:48:13 +0100 Subject: [PATCH 1/9] fix certificate overflow scroll --- src/components/CertificateSecurity.tsx | 6 +++--- src/components/Certificates.tsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/CertificateSecurity.tsx b/src/components/CertificateSecurity.tsx index ac5eb748..e1cdd481 100644 --- a/src/components/CertificateSecurity.tsx +++ b/src/components/CertificateSecurity.tsx @@ -67,7 +67,7 @@ const OpenSourceIcon = () => ( export function CertificateSecurity() { return ( - <> +
@@ -83,7 +83,7 @@ export function CertificateSecurity() {
-
+

Certificate Security

@@ -209,6 +209,6 @@ export function CertificateSecurity() {
- +
); } diff --git a/src/components/Certificates.tsx b/src/components/Certificates.tsx index 95f7db62..58c81465 100644 --- a/src/components/Certificates.tsx +++ b/src/components/Certificates.tsx @@ -150,7 +150,7 @@ export function Certificates() { const currentSteps = steps[activeOS][activeAction]; return ( - <> +
@@ -167,7 +167,7 @@ export function Certificates() {
-
+

Certificates

@@ -307,6 +307,6 @@ export function Certificates() {
- +
); } From 3c2b78b8942f44f271798ccd2447e75292bf1bb4 Mon Sep 17 00:00:00 2001 From: Giuseppe Scuglia Date: Mon, 16 Dec 2024 14:08:39 +0100 Subject: [PATCH 2/9] fix breadcrumb and overlflow app --- public/help/copilot-setup.md | 2 +- src/App.tsx | 69 ++++-- src/components/CertificateSecurity.tsx | 27 +-- src/components/Certificates.tsx | 280 +++++++++++-------------- src/components/Chat.tsx | 30 +-- src/components/Dashboard.tsx | 2 +- src/components/Help.tsx | 55 +---- src/components/Sidebar.tsx | 1 - src/hooks/useBreadcrumb.ts | 30 +++ 9 files changed, 220 insertions(+), 276 deletions(-) create mode 100644 src/hooks/useBreadcrumb.ts diff --git a/public/help/copilot-setup.md b/public/help/copilot-setup.md index 9979303c..e88e142e 100644 --- a/public/help/copilot-setup.md +++ b/public/help/copilot-setup.md @@ -37,6 +37,7 @@ settings (Ctrl+Shift+P) + "Preferences: Open User Settings (JSON)": "debug.testOverrideProxyUrl": "https://localhost:8990", "debug.overrideProxyUrl": "https://localhost:8990", } +} ``` > **_NOTE:_** CoPilot may need a refresh after creating the proxy config. Restart VS-Code or open the command palate (Ctrl+Shift+P) and select "Developer: Reload Window". @@ -54,4 +55,3 @@ If there is any sort of failure, you will see the following: If you experience a failure, click on the CoPilot avatar and select "Show Diagnostics" , copy the text and post it to the CoPilot [CodeGate Discussions](https://github.com/stacklok/codegate/discussions/categories/copilot) - diff --git a/src/App.tsx b/src/App.tsx index 9b7822f8..69e213b5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,7 +2,7 @@ import { Header } from "./components/Header"; import { PromptList } from "./components/PromptList"; import { useEffect } from "react"; import { Dashboard } from "./components/Dashboard"; -import { Routes, Route } from "react-router-dom"; +import { Routes, Route, Link } from "react-router-dom"; import { Chat } from "./components/Chat"; import { usePromptsStore } from "./hooks/usePromptsStore"; import { Sidebar } from "./components/Sidebar"; @@ -10,37 +10,66 @@ import { useSse } from "./hooks/useSse"; import { Help } from "./components/Help"; import { Certificates } from "./components/Certificates"; import { CertificateSecurity } from "./components/CertificateSecurity"; +import { + Breadcrumb, + BreadcrumbList, + BreadcrumbItem, + BreadcrumbSeparator, + BreadcrumbPage, +} from "./components/ui/breadcrumb"; +import { useBreadcrumb } from "./hooks/useBreadcrumb"; function App() { const { prompts, loading, fetchPrompts } = usePromptsStore(); useSse(); + const breadcrumb = useBreadcrumb(prompts); useEffect(() => { fetchPrompts(); }, [fetchPrompts]); return ( - <> -
-
- - - -
-
-
- - } /> - } /> - } /> - } /> - } /> - -
-
+
+ + + +
+
+ +
+ + + + Dashboard + + {breadcrumb && ( + <> + + + + {breadcrumb} + + + + )} + + +
+ +
+ + } /> + } /> + } /> + } /> + } + /> +
- +
); } diff --git a/src/components/CertificateSecurity.tsx b/src/components/CertificateSecurity.tsx index e1cdd481..0468a3c0 100644 --- a/src/components/CertificateSecurity.tsx +++ b/src/components/CertificateSecurity.tsx @@ -1,11 +1,3 @@ -import { Link } from "react-router-dom"; -import { - Breadcrumb, - BreadcrumbList, - BreadcrumbItem, - BreadcrumbSeparator, - BreadcrumbPage, -} from "./ui/breadcrumb"; import { Card } from "./ui/card"; const SecurityShieldIcon = () => ( @@ -67,23 +59,8 @@ const OpenSourceIcon = () => ( export function CertificateSecurity() { return ( -
-
- - - - Dashboard - - - - - Certificate Security - - - - -
-
+
+

Certificate Security

diff --git a/src/components/Certificates.tsx b/src/components/Certificates.tsx index 58c81465..782bcdfb 100644 --- a/src/components/Certificates.tsx +++ b/src/components/Certificates.tsx @@ -2,13 +2,6 @@ import { Button } from "./ui/button"; import { Card } from "./ui/card"; import { Link } from "react-router-dom"; import { useState, ReactNode } from "react"; -import { - Breadcrumb, - BreadcrumbList, - BreadcrumbItem, - BreadcrumbSeparator, - BreadcrumbPage, -} from "./ui/breadcrumb"; type OS = "macos" | "windows" | "linux"; type Action = "install" | "remove"; @@ -150,163 +143,144 @@ export function Certificates() { const currentSteps = steps[activeOS][activeAction]; return ( -
-
- - - - Dashboard - - - - - Certificate Download - - - - -
- -
-

Certificates

+
+

Certificates

- -
-
- -
-
-

- CodeGate SSL Certificate -

-

- This certificate allows CodeGate to act as a proxy for certain - software such as CoPilot. -

- -
+ +
+
+
- - - -

- Is this certificate safe to install on my machine? -

-
-
- -

- Local Only: CodeGate runs entirely on your - machine within an isolated container, ensuring all data - processing stays local without any external transmissions. -

-
- -
- -

- Secure Certificate Handling: This custom CA is - locally generated and managed, the developers of CodeGate have - no access to it. -

-
- -
- -

- No External Communications: CodeGate is - designed with no capability to call home or communicate with - external servers, outside of those requested by the IDE or - Agent. -

-
-
-
- +

+ CodeGate SSL Certificate +

+

+ This certificate allows CodeGate to act as a proxy for certain + software such as CoPilot. +

+
-
+
+
- -

Certificate Management

+ +

+ Is this certificate safe to install on my machine? +

+
+
+ +

+ Local Only: CodeGate runs entirely on your + machine within an isolated container, ensuring all data processing + stays local without any external transmissions. +

+
- {/* OS Selection Tabs */} -
- - - +
+ +

+ Secure Certificate Handling: This custom CA is + locally generated and managed, the developers of CodeGate have no + access to it. +

- {/* Action Selection Tabs */} -
- - +
+ +

+ No External Communications: CodeGate is designed + with no capability to call home or communicate with external + servers, outside of those requested by the IDE or Agent. +

+
+
+ + Learn More + + +
+ + + +

Certificate Management

-
-
- {currentSteps.map((step, index) => ( - - ))} -
+ {/* OS Selection Tabs */} +
+ + + +
+ + {/* Action Selection Tabs */} +
+ + +
+ +
+
+ {currentSteps.map((step, index) => ( + + ))}
- -
+
+
); } diff --git a/src/components/Chat.tsx b/src/components/Chat.tsx index b02aace2..ae2f04b7 100644 --- a/src/components/Chat.tsx +++ b/src/components/Chat.tsx @@ -4,43 +4,19 @@ import { ChatBubbleMessage, } from "./ui/chat/chat-bubble"; import { ChatMessageList } from "./ui/chat/chat-message-list"; -import { Link, useParams } from "react-router-dom"; -import { - Breadcrumb, - BreadcrumbList, - BreadcrumbItem, - BreadcrumbSeparator, - BreadcrumbPage, -} from "./ui/breadcrumb"; +import { useParams } from "react-router-dom"; import { usePromptsStore } from "@/hooks/usePromptsStore"; import { Markdown } from "./Markdown"; -import { extractTitleFromMessage } from "@/lib/utils"; export function Chat() { const { id } = useParams(); const chat = usePromptsStore((state) => state.prompts.find((prompt) => prompt.chat_id === id) ); - const title = chat?.question_answers?.[0].question.message ?? ""; return ( -
-
- - - - Dashboard - - - - - {extractTitleFromMessage(title)} - - - - -
- +
+ {(chat?.question_answers ?? []).map(({ question, answer }, index) => (
diff --git a/src/components/Dashboard.tsx b/src/components/Dashboard.tsx index 60e6c97e..fa71c07a 100644 --- a/src/components/Dashboard.tsx +++ b/src/components/Dashboard.tsx @@ -136,7 +136,7 @@ export function Dashboard() { }, []); return ( -
+
diff --git a/src/components/Help.tsx b/src/components/Help.tsx index c5fbca05..3a4a87c5 100644 --- a/src/components/Help.tsx +++ b/src/components/Help.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { Link, useParams } from "react-router-dom"; +import { useParams } from "react-router-dom"; import { Markdown } from "./Markdown"; import Prism from "prismjs"; import "prismjs/themes/prism-tomorrow.css"; @@ -8,13 +8,6 @@ import "prismjs/components/prism-javascript"; import "prismjs/components/prism-python"; import "prismjs/components/prism-json"; import "prismjs/components/prism-yaml"; -import { - Breadcrumb, - BreadcrumbList, - BreadcrumbItem, - BreadcrumbSeparator, - BreadcrumbPage, -} from "./ui/breadcrumb"; export function Help() { const { section } = useParams(); @@ -46,42 +39,9 @@ export function Help() { }, [section]); return ( -
-
- - - - Dashboard - - - - - {section === "copilot-setup" - ? "CoPilot Setup" - : "Continue Setup"} - - - - -
- -
- + - {content} - -
+ > + {content} +
); } diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index c79f0e38..cf6ac142 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -44,7 +44,6 @@ export function Sidebar({ {children} - ); } diff --git a/src/hooks/useBreadcrumb.ts b/src/hooks/useBreadcrumb.ts new file mode 100644 index 00000000..abee9d2e --- /dev/null +++ b/src/hooks/useBreadcrumb.ts @@ -0,0 +1,30 @@ +import { extractTitleFromMessage } from "@/lib/utils"; +import { Prompt } from "@/types"; +import { useLocation } from "react-router-dom"; + +const routes = [ + { path: "/certificates/security", breadcrumb: "Certificate Security" }, + { path: "/certificates", breadcrumb: "Certificate Download" }, + { path: "/help/continue-setup", breadcrumb: "Continue Setup" }, + { path: "/help/copilot-setup", breadcrumb: "CoPilot Setup" }, + { path: "/prompt/", breadcrumb: "Dashboard" }, + { path: "/", breadcrumb: "" }, +]; + +export function useBreadcrumb(prompts: Prompt[]) { + const { pathname } = useLocation(); + + const match = routes.find((route) => pathname.startsWith(route.path)); + if (match?.path === "/prompt/") { + try { + const promptId = pathname.split("/").pop(); + const chat = prompts.find((prompt) => prompt.chat_id === promptId); + const title = chat?.question_answers?.[0].question.message ?? ""; + return extractTitleFromMessage(title) ?? ""; + } catch { + return ""; + } + } + + return match ? match.breadcrumb : ""; +} From bb4bf09c2be914849c525b28eea6b908dbb43c0d Mon Sep 17 00:00:00 2001 From: Giuseppe Scuglia Date: Mon, 16 Dec 2024 14:21:59 +0100 Subject: [PATCH 3/9] fix react hook deps --- src/components/Dashboard.tsx | 31 +++++++++++++++++-------------- src/hooks/useSse.ts | 2 +- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/components/Dashboard.tsx b/src/components/Dashboard.tsx index fa71c07a..bab0e96d 100644 --- a/src/components/Dashboard.tsx +++ b/src/components/Dashboard.tsx @@ -103,7 +103,7 @@ export function Dashboard() { if (searchFilterParam && alerts.length > 0) { setSearch(searchFilterParam); } - }, [searchParams, alerts]); + }, [searchParams, toggleMaliciousFilter, setSearch, alerts]); const maliciousPackages = getMaliciousPackagesChart(); @@ -119,21 +119,24 @@ export function Dashboard() { setSearchParams(searchParams); toggleMaliciousFilter(isChecked); }, - [setSearchParams, searchParams, toggleMaliciousFilter] + [setSearchParams, setSearch, searchParams, toggleMaliciousFilter] ); - const handleSearch = useCallback((value: string) => { - if (value) { - searchParams.set("search", value); - searchParams.delete("maliciousPkg"); - setSearch(value); - toggleMaliciousFilter(false); - } else { - searchParams.delete("search"); - setSearch(""); - } - setSearchParams(searchParams); - }, []); + const handleSearch = useCallback( + (value: string) => { + if (value) { + searchParams.set("search", value); + searchParams.delete("maliciousPkg"); + setSearch(value); + toggleMaliciousFilter(false); + } else { + searchParams.delete("search"); + setSearch(""); + } + setSearchParams(searchParams); + }, + [searchParams, setSearch, setSearchParams, toggleMaliciousFilter] + ); return (
diff --git a/src/hooks/useSse.ts b/src/hooks/useSse.ts index 9d6e1517..5ad53891 100644 --- a/src/hooks/useSse.ts +++ b/src/hooks/useSse.ts @@ -30,5 +30,5 @@ export function useSse() { eventSource.close(); } }; - }, [BASE_URL]); + }, [location.pathname, sendNotification]); } From 4e6f713b7a678920e2366c4078d92b7b9509074a Mon Sep 17 00:00:00 2001 From: Giuseppe Scuglia Date: Mon, 16 Dec 2024 14:50:40 +0100 Subject: [PATCH 4/9] add tsc script --- .gitignore | 4 ++++ package.json | 5 +++-- tsconfig.app.json | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index a547bf36..ffae558d 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,10 @@ dist dist-ssr *.local +# typescript +*.tsbuildinfo +next-env.d.ts + # Editor directories and files .vscode/* !.vscode/extensions.json diff --git a/package.json b/package.json index 40fb28bc..4818e0be 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "dev": "vite", "build": "tsc -b && vite build", "lint": "eslint .", - "preview": "vite preview" + "preview": "vite preview", + "type-check": "tsc --noEmit -p ./tsconfig.app.json" }, "dependencies": { "@radix-ui/react-avatar": "^1.1.1", @@ -55,4 +56,4 @@ "typescript-eslint": "^8.15.0", "vite": "^6.0.1" } -} +} \ No newline at end of file diff --git a/tsconfig.app.json b/tsconfig.app.json index caf4270b..231a4ec9 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -13,6 +13,7 @@ "moduleDetection": "force", "noEmit": true, "jsx": "react-jsx", + "incremental": true, /* Linting */ "strict": true, From b2600bdc4ae027a6935bc5b326d6462bfa415a95 Mon Sep 17 00:00:00 2001 From: Giuseppe Scuglia Date: Mon, 16 Dec 2024 14:54:19 +0100 Subject: [PATCH 5/9] fine tune charts width --- src/components/Dashboard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Dashboard.tsx b/src/components/Dashboard.tsx index bab0e96d..622b1ca8 100644 --- a/src/components/Dashboard.tsx +++ b/src/components/Dashboard.tsx @@ -141,7 +141,7 @@ export function Dashboard() { return (
-
+
From fd3039468f06b052a424d2b5322b78f14360f4d7 Mon Sep 17 00:00:00 2001 From: Giuseppe Scuglia Date: Mon, 16 Dec 2024 16:53:26 +0100 Subject: [PATCH 6/9] fix hook unmount --- src/hooks/useSse.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/hooks/useSse.ts b/src/hooks/useSse.ts index 5ad53891..6de6bd53 100644 --- a/src/hooks/useSse.ts +++ b/src/hooks/useSse.ts @@ -26,9 +26,7 @@ export function useSse() { }; return () => { - if (location.pathname.includes("/prompt")) { - eventSource.close(); - } + eventSource.close(); }; }, [location.pathname, sendNotification]); } From 5b06c692910aed8c401c486f6c7a5f4e910f14d8 Mon Sep 17 00:00:00 2001 From: Giuseppe Scuglia Date: Mon, 16 Dec 2024 17:15:52 +0100 Subject: [PATCH 7/9] add documentation link --- src/components/Header.tsx | 40 +++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 759f5da0..d97da9ae 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -18,20 +18,20 @@ export function Header() {
-
+
Certificates
- Download - Certificate Security @@ -39,26 +39,38 @@ export function Header() {
-
+
Help
- Continue Setup - CoPilot Setup
+ +
); From d0990a5bcd6c27de4fa1459db5e9823a11c6d602 Mon Sep 17 00:00:00 2001 From: Giuseppe Scuglia Date: Mon, 16 Dec 2024 17:16:27 +0100 Subject: [PATCH 8/9] fix overflow chat --- src/components/Chat.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Chat.tsx b/src/components/Chat.tsx index ae2f04b7..b78093e4 100644 --- a/src/components/Chat.tsx +++ b/src/components/Chat.tsx @@ -15,7 +15,7 @@ export function Chat() { ); return ( -
+
{(chat?.question_answers ?? []).map(({ question, answer }, index) => (
From 69751470aa8da5030c9a41022c721b28113e2e6b Mon Sep 17 00:00:00 2001 From: Giuseppe Scuglia Date: Mon, 16 Dec 2024 17:43:13 +0100 Subject: [PATCH 9/9] add bold on selected prompt --- src/App.tsx | 2 +- src/components/Chat.tsx | 14 +++++++++++--- src/components/PromptList.tsx | 10 +++++++++- src/hooks/useBreadcrumb.ts | 8 ++++---- src/hooks/usePromptsStore.ts | 2 ++ src/types.ts | 2 ++ 6 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 69e213b5..fafa5bf0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -22,7 +22,7 @@ import { useBreadcrumb } from "./hooks/useBreadcrumb"; function App() { const { prompts, loading, fetchPrompts } = usePromptsStore(); useSse(); - const breadcrumb = useBreadcrumb(prompts); + const breadcrumb = useBreadcrumb(); useEffect(() => { fetchPrompts(); diff --git a/src/components/Chat.tsx b/src/components/Chat.tsx index b78093e4..bde08b9e 100644 --- a/src/components/Chat.tsx +++ b/src/components/Chat.tsx @@ -7,12 +7,20 @@ import { ChatMessageList } from "./ui/chat/chat-message-list"; import { useParams } from "react-router-dom"; import { usePromptsStore } from "@/hooks/usePromptsStore"; import { Markdown } from "./Markdown"; +import { useEffect } from "react"; export function Chat() { const { id } = useParams(); - const chat = usePromptsStore((state) => - state.prompts.find((prompt) => prompt.chat_id === id) - ); + const { prompts, setCurrentPromptId } = usePromptsStore(); + const chat = prompts.find((prompt) => prompt.chat_id === id); + + useEffect(() => { + if (id) { + setCurrentPromptId(id); + } + + return () => setCurrentPromptId(""); + }, [prompts, id, setCurrentPromptId]); return (
diff --git a/src/components/PromptList.tsx b/src/components/PromptList.tsx index 8bbf67c9..224a662f 100644 --- a/src/components/PromptList.tsx +++ b/src/components/PromptList.tsx @@ -4,8 +4,12 @@ import { extractTitleFromMessage, groupPromptsByRelativeDate, } from "@/lib/utils"; +import { usePromptsStore } from "@/hooks/usePromptsStore"; +import clsx from "clsx"; export function PromptList({ prompts }: { prompts: Prompt[] }) { + const { currentPromptId, setCurrentPromptId } = usePromptsStore(); + const groupedPrompts = groupPromptsByRelativeDate(prompts); return (
@@ -16,8 +20,12 @@ export function PromptList({ prompts }: { prompts: Prompt[] }) { {prompts.map((prompt) => (
  • setCurrentPromptId(prompt.chat_id)} to={`/prompt/${prompt.chat_id}`} - className="text-gray-800 text-sm truncate hover:text-gray-500" + className={clsx( + `text-gray-800 text-sm truncate hover:text-gray-500`, + { "font-bold": currentPromptId === prompt.chat_id } + )} > {extractTitleFromMessage( prompt.question_answers?.[0].question.message ?? diff --git a/src/hooks/useBreadcrumb.ts b/src/hooks/useBreadcrumb.ts index abee9d2e..720a1f41 100644 --- a/src/hooks/useBreadcrumb.ts +++ b/src/hooks/useBreadcrumb.ts @@ -1,6 +1,6 @@ import { extractTitleFromMessage } from "@/lib/utils"; -import { Prompt } from "@/types"; import { useLocation } from "react-router-dom"; +import { usePromptsStore } from "./usePromptsStore"; const routes = [ { path: "/certificates/security", breadcrumb: "Certificate Security" }, @@ -11,14 +11,14 @@ const routes = [ { path: "/", breadcrumb: "" }, ]; -export function useBreadcrumb(prompts: Prompt[]) { +export function useBreadcrumb() { const { pathname } = useLocation(); + const { currentPromptId, prompts } = usePromptsStore(); const match = routes.find((route) => pathname.startsWith(route.path)); if (match?.path === "/prompt/") { try { - const promptId = pathname.split("/").pop(); - const chat = prompts.find((prompt) => prompt.chat_id === promptId); + const chat = prompts.find((prompt) => prompt.chat_id === currentPromptId); const title = chat?.question_answers?.[0].question.message ?? ""; return extractTitleFromMessage(title) ?? ""; } catch { diff --git a/src/hooks/usePromptsStore.ts b/src/hooks/usePromptsStore.ts index 72564c94..ab3e9fd4 100644 --- a/src/hooks/usePromptsStore.ts +++ b/src/hooks/usePromptsStore.ts @@ -5,6 +5,8 @@ import { getPrompts } from "@/service"; export const usePromptsStore = create((set) => ({ prompts: [], loading: false, + currentPromptId: "", + setCurrentPromptId: (id: string) => set({ currentPromptId: id }), fetchPrompts: async () => { set({ loading: true }); const prompts = await getPrompts(); diff --git a/src/types.ts b/src/types.ts index ebf7d481..ce7eaa87 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,6 +1,8 @@ export type PromptState = { prompts: Prompt[]; loading: boolean; + currentPromptId: string; + setCurrentPromptId: (id: string) => void; fetchPrompts: () => void; };