| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- import { VSCodeButton, VSCodeCheckbox, VSCodeLink, VSCodeTextArea } from "@vscode/webview-ui-toolkit/react"
- import { memo, useEffect, useState } from "react"
- import { useExtensionState } from "../../context/ExtensionStateContext"
- import { validateApiConfiguration, validateModelId } from "../../utils/validate"
- import { vscode } from "../../utils/vscode"
- import ApiOptions from "./ApiOptions"
- const IS_DEV = false // FIXME: use flags when packaging
- type SettingsViewProps = {
- onDone: () => void
- }
- const SettingsView = ({ onDone }: SettingsViewProps) => {
- const {
- apiConfiguration,
- version,
- customInstructions,
- setCustomInstructions,
- alwaysAllowReadOnly,
- setAlwaysAllowReadOnly,
- openRouterModels,
- } = useExtensionState()
- const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined)
- const [modelIdErrorMessage, setModelIdErrorMessage] = useState<string | undefined>(undefined)
- const handleSubmit = () => {
- const apiValidationResult = validateApiConfiguration(apiConfiguration)
- const modelIdValidationResult = validateModelId(apiConfiguration, openRouterModels)
- setApiErrorMessage(apiValidationResult)
- setModelIdErrorMessage(modelIdValidationResult)
- if (!apiValidationResult && !modelIdValidationResult) {
- vscode.postMessage({ type: "apiConfiguration", apiConfiguration })
- vscode.postMessage({ type: "customInstructions", text: customInstructions })
- vscode.postMessage({ type: "alwaysAllowReadOnly", bool: alwaysAllowReadOnly })
- onDone()
- }
- }
- useEffect(() => {
- setApiErrorMessage(undefined)
- setModelIdErrorMessage(undefined)
- }, [apiConfiguration])
- // validate as soon as the component is mounted
- /*
- useEffect will use stale values of variables if they are not included in the dependency array. so trying to use useEffect with a dependency array of only one value for example will use any other variables' old values. In most cases you don't want this, and should opt to use react-use hooks.
-
- useEffect(() => {
- // uses someVar and anotherVar
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [someVar])
- If we only want to run code once on mount we can use react-use's useEffectOnce or useMount
- */
- const handleResetState = () => {
- vscode.postMessage({ type: "resetState" })
- }
- return (
- <div
- style={{
- position: "fixed",
- top: 0,
- left: 0,
- right: 0,
- bottom: 0,
- padding: "10px 0px 0px 20px",
- display: "flex",
- flexDirection: "column",
- overflow: "hidden",
- }}>
- <div
- style={{
- display: "flex",
- justifyContent: "space-between",
- alignItems: "center",
- marginBottom: "17px",
- paddingRight: 17,
- }}>
- <h3 style={{ color: "var(--vscode-foreground)", margin: 0 }}>Settings</h3>
- <VSCodeButton onClick={handleSubmit}>Done</VSCodeButton>
- </div>
- <div
- style={{ flexGrow: 1, overflowY: "scroll", paddingRight: 8, display: "flex", flexDirection: "column" }}>
- <div style={{ marginBottom: 5 }}>
- <ApiOptions
- showModelOptions={true}
- apiErrorMessage={apiErrorMessage}
- modelIdErrorMessage={modelIdErrorMessage}
- />
- </div>
- <div style={{ marginBottom: 5 }}>
- <VSCodeTextArea
- value={customInstructions ?? ""}
- style={{ width: "100%" }}
- rows={4}
- placeholder={
- 'e.g. "Run unit tests at the end", "Use TypeScript with async/await", "Speak in Spanish"'
- }
- onInput={(e: any) => setCustomInstructions(e.target?.value ?? "")}>
- <span style={{ fontWeight: "500" }}>Custom Instructions</span>
- </VSCodeTextArea>
- <p
- style={{
- fontSize: "12px",
- marginTop: "5px",
- color: "var(--vscode-descriptionForeground)",
- }}>
- These instructions are added to the end of the system prompt sent with every request.
- </p>
- </div>
- <div style={{ marginBottom: 5 }}>
- <VSCodeCheckbox
- checked={alwaysAllowReadOnly}
- onChange={(e: any) => setAlwaysAllowReadOnly(e.target.checked)}>
- <span style={{ fontWeight: "500" }}>Always allow read-only operations</span>
- </VSCodeCheckbox>
- <p
- style={{
- fontSize: "12px",
- marginTop: "5px",
- color: "var(--vscode-descriptionForeground)",
- }}>
- When enabled, Cline will automatically read files, view directories, and inspect sites without
- requiring you to click the Allow button.
- </p>
- </div>
- {IS_DEV && (
- <>
- <div style={{ marginTop: "10px", marginBottom: "4px" }}>Debug</div>
- <VSCodeButton onClick={handleResetState} style={{ marginTop: "5px", width: "auto" }}>
- Reset State
- </VSCodeButton>
- <p
- style={{
- fontSize: "12px",
- marginTop: "5px",
- color: "var(--vscode-descriptionForeground)",
- }}>
- This will reset all global state and secret storage in the extension.
- </p>
- </>
- )}
- <div
- style={{
- textAlign: "center",
- color: "var(--vscode-descriptionForeground)",
- fontSize: "12px",
- lineHeight: "1.2",
- marginTop: "auto",
- padding: "10px 8px 15px 0px",
- }}>
- <p style={{ wordWrap: "break-word", margin: 0, padding: 0 }}>
- If you have any questions or feedback, feel free to open an issue at{" "}
- <VSCodeLink href="https://github.com/saoudrizwan/claude-dev" style={{ display: "inline" }}>
- https://github.com/saoudrizwan/claude-dev
- </VSCodeLink>
- </p>
- <p style={{ fontStyle: "italic", margin: "10px 0 0 0", padding: 0 }}>v{version}</p>
- </div>
- </div>
- </div>
- )
- }
- export default memo(SettingsView)
|