Skip to content
This repository was archived by the owner on Jul 8, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

# NPM
.npmrc

node_modules
dist
dist-ssr
Expand Down
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
legacy-peer-deps=true
132 changes: 34 additions & 98 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
},
"dependencies": {
"@hey-api/client-fetch": "^0.6.0",
"@monaco-editor/react": "^4.6.0",
"@radix-ui/react-dialog": "^1.1.4",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
Expand Down
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
BreadcrumbPage,
} from "./components/ui/breadcrumb";
import { useBreadcrumb } from "./hooks/useBreadcrumb";
import { RouteWorkspace } from "./routes/route-workspace";

function App() {
const { data: prompts, isLoading } = usePromptsData();
Expand Down Expand Up @@ -57,6 +58,7 @@ function App() {
<Route path="/prompt/:id" element={<Chat />} />
<Route path="/help/:section" element={<Help />} />
<Route path="/certificates" element={<Certificates />} />
<Route path="/workspace/:id" element={<RouteWorkspace />} />
<Route
path="/certificates/security"
element={<CertificateSecurity />}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import Editor, { type Theme } from "@monaco-editor/react";
import {
Button,
Card,
CardBody,
CardFooter,
DarkModeContext,
LinkButton,
Text,
} from "@stacklok/ui-kit";
import {
Dispatch,
SetStateAction,
useContext,
useEffect,
useState,
} from "react";
import { usePostSystemPrompt } from "../hooks/use-post-system-prompt";
import { Check } from "lucide-react";

type DarkModeContextValue = {
preference: "dark" | "light" | null;
override: "dark" | "light" | null;
};

const DEFAULT_VALUE = `You are a security expert conducting a thorough code review.\nIdentify potential security vulnerabilities, suggest improvements, and explain security best practices.`;

function inferDarkMode(
contextValue:
| null
| [DarkModeContextValue, Dispatch<SetStateAction<DarkModeContextValue>>],
): Theme {
if (contextValue === null) return "light";

// Handle override
if (contextValue[0].override === "dark") return "vs-dark";
if (contextValue[0].override === "light") return "light";

// Handle preference
if (contextValue[0].preference === "dark") return "vs-dark";
return "light";
}

function useSavedStatus() {
const [saved, setSaved] = useState<boolean>(false);

useEffect(() => {
const id = setTimeout(() => setSaved(false), 2000);
return () => clearTimeout(id);
}, [saved]);

return { saved, setSaved };
}

export function SystemPromptEditor({ className }: { className?: string }) {
const context = useContext(DarkModeContext);
const theme: Theme = inferDarkMode(context);

const [value, setValue] = useState<string>(() => DEFAULT_VALUE);

const { mutate, isPending } = usePostSystemPrompt();

const { saved, setSaved } = useSavedStatus();

return (
<Card className={className}>
<CardBody>
<Text className="text-primary">Custom prompt</Text>
<Text className="text-secondary mb-4">
Pass custom instructions to your LLM to augment it's behavior, and
save time & tokens.
</Text>
<div className="border border-gray-200 rounded overflow-hidden">
<Editor
options={{
minimap: { enabled: false },
}}
value={value}
onChange={(v) => setValue(v ?? "")}
height="20rem"
defaultLanguage="Markdown"
theme={theme}
className="bg-base"
defaultValue="<!-- Add any additional prompts you would like to pass to your LLM here. -->"
/>
</div>
</CardBody>
<CardFooter className="justify-end gap-2">
<LinkButton variant="secondary">Cancel</LinkButton>
<Button
isPending={isPending}
isDisabled={saved}
onPress={() => {
mutate(value, {
onSuccess: () => setSaved(true),
});
}}
>
{saved ? (
<>
<span>Saved</span> <Check />
</>
) : (
"Save changes"
)}
</Button>
</CardFooter>
</Card>
);
}
Loading
Loading