mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 04:11:10 -05:00
Refactor extension state into ExtensionStateContext
This commit is contained in:
@@ -1,38 +0,0 @@
|
|||||||
.App {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.App-logo {
|
|
||||||
height: 40vmin;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
|
||||||
.App-logo {
|
|
||||||
animation: App-logo-spin infinite 20s linear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.App-header {
|
|
||||||
background-color: #282c34;
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: calc(10px + 2vmin);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.App-link {
|
|
||||||
color: #61dafb;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes App-logo-spin {
|
|
||||||
from {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import React from "react"
|
|
||||||
import { render, screen } from "@testing-library/react"
|
|
||||||
import App from "./App"
|
|
||||||
|
|
||||||
test("renders learn react link", () => {
|
|
||||||
render(<App />)
|
|
||||||
const linkElement = screen.getByText(/learn react/i)
|
|
||||||
expect(linkElement).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
@@ -1,51 +1,27 @@
|
|||||||
import React, { useCallback, useEffect, useMemo, useState } from "react"
|
import { useCallback, useMemo, useState } from "react"
|
||||||
import { useEvent } from "react-use"
|
import { useEvent } from "react-use"
|
||||||
import { ApiConfiguration } from "../../src/shared/api"
|
import { ExtensionMessage } from "../../src/shared/ExtensionMessage"
|
||||||
import { ClaudeMessage, ExtensionMessage } from "../../src/shared/ExtensionMessage"
|
|
||||||
import { HistoryItem } from "../../src/shared/HistoryItem"
|
|
||||||
import "./App.css"
|
|
||||||
import { normalizeApiConfiguration } from "./components/ApiOptions"
|
import { normalizeApiConfiguration } from "./components/ApiOptions"
|
||||||
import ChatView from "./components/ChatView"
|
import ChatView from "./components/ChatView"
|
||||||
import HistoryView from "./components/HistoryView"
|
import HistoryView from "./components/HistoryView"
|
||||||
import SettingsView from "./components/SettingsView"
|
import SettingsView from "./components/SettingsView"
|
||||||
import WelcomeView from "./components/WelcomeView"
|
import WelcomeView from "./components/WelcomeView"
|
||||||
|
import { ExtensionStateContextProvider, useExtensionState } from "./context/ExtensionStateContext"
|
||||||
import { vscode } from "./utils/vscode"
|
import { vscode } from "./utils/vscode"
|
||||||
|
|
||||||
/*
|
const AppContent = () => {
|
||||||
The contents of webviews however are created when the webview becomes visible and destroyed when the webview is moved into the background. Any state inside the webview will be lost when the webview is moved to a background tab.
|
const { apiConfiguration } = useExtensionState()
|
||||||
|
|
||||||
The best way to solve this is to make your webview stateless. Use message passing to save off the webview's state and then restore the state when the webview becomes visible again.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const App: React.FC = () => {
|
|
||||||
const [didHydrateState, setDidHydrateState] = useState(false)
|
|
||||||
const [showSettings, setShowSettings] = useState(false)
|
const [showSettings, setShowSettings] = useState(false)
|
||||||
const [showHistory, setShowHistory] = useState(false)
|
const [showHistory, setShowHistory] = useState(false)
|
||||||
const [showWelcome, setShowWelcome] = useState<boolean>(false)
|
const [showWelcome, setShowWelcome] = useState<boolean>(false)
|
||||||
const [version, setVersion] = useState<string>("")
|
|
||||||
const [apiConfiguration, setApiConfiguration] = useState<ApiConfiguration | undefined>(undefined)
|
|
||||||
const [maxRequestsPerTask, setMaxRequestsPerTask] = useState<string>("")
|
|
||||||
const [customInstructions, setCustomInstructions] = useState<string>("")
|
|
||||||
const [alwaysAllowReadOnly, setAlwaysAllowReadOnly] = useState<boolean>(false)
|
|
||||||
const [vscodeThemeName, setVscodeThemeName] = useState<string | undefined>(undefined)
|
|
||||||
const [vscodeUriScheme, setVscodeUriScheme] = useState<string | undefined>(undefined)
|
|
||||||
const [claudeMessages, setClaudeMessages] = useState<ClaudeMessage[]>([])
|
|
||||||
const [taskHistory, setTaskHistory] = useState<HistoryItem[]>([])
|
|
||||||
const [showAnnouncement, setShowAnnouncement] = useState(false)
|
const [showAnnouncement, setShowAnnouncement] = useState(false)
|
||||||
const [koduCredits, setKoduCredits] = useState<number | undefined>(undefined)
|
|
||||||
const [shouldShowKoduPromo, setShouldShowKoduPromo] = useState(true)
|
|
||||||
const [didAuthKoduFromWelcome, setDidAuthKoduFromWelcome] = useState<boolean>(false)
|
const [didAuthKoduFromWelcome, setDidAuthKoduFromWelcome] = useState<boolean>(false)
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
vscode.postMessage({ type: "webviewDidLaunch" })
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const handleMessage = useCallback(
|
const handleMessage = useCallback(
|
||||||
(e: MessageEvent) => {
|
(e: MessageEvent) => {
|
||||||
const message: ExtensionMessage = e.data
|
const message: ExtensionMessage = e.data
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
case "state":
|
case "state":
|
||||||
setVersion(message.state!.version)
|
|
||||||
const hasKey =
|
const hasKey =
|
||||||
message.state!.apiConfiguration?.apiKey !== undefined ||
|
message.state!.apiConfiguration?.apiKey !== undefined ||
|
||||||
message.state!.apiConfiguration?.openRouterApiKey !== undefined ||
|
message.state!.apiConfiguration?.openRouterApiKey !== undefined ||
|
||||||
@@ -55,25 +31,10 @@ const App: React.FC = () => {
|
|||||||
if (!hasKey) {
|
if (!hasKey) {
|
||||||
setDidAuthKoduFromWelcome(false)
|
setDidAuthKoduFromWelcome(false)
|
||||||
}
|
}
|
||||||
setApiConfiguration(message.state!.apiConfiguration)
|
|
||||||
setMaxRequestsPerTask(
|
|
||||||
message.state!.maxRequestsPerTask !== undefined
|
|
||||||
? message.state!.maxRequestsPerTask.toString()
|
|
||||||
: ""
|
|
||||||
)
|
|
||||||
setCustomInstructions(message.state!.customInstructions || "")
|
|
||||||
setAlwaysAllowReadOnly(message.state!.alwaysAllowReadOnly || false)
|
|
||||||
setVscodeThemeName(message.state!.themeName)
|
|
||||||
setVscodeUriScheme(message.state!.uriScheme)
|
|
||||||
setClaudeMessages(message.state!.claudeMessages)
|
|
||||||
setTaskHistory(message.state!.taskHistory)
|
|
||||||
setKoduCredits(message.state!.koduCredits)
|
|
||||||
// don't update showAnnouncement to false if shouldShowAnnouncement is false
|
// don't update showAnnouncement to false if shouldShowAnnouncement is false
|
||||||
if (message.state!.shouldShowAnnouncement) {
|
if (message.state!.shouldShowAnnouncement) {
|
||||||
setShowAnnouncement(true)
|
setShowAnnouncement(true)
|
||||||
}
|
}
|
||||||
setShouldShowKoduPromo(message.state!.shouldShowKoduPromo)
|
|
||||||
setDidHydrateState(true)
|
|
||||||
break
|
break
|
||||||
case "action":
|
case "action":
|
||||||
switch (message.action!) {
|
switch (message.action!) {
|
||||||
@@ -89,9 +50,6 @@ const App: React.FC = () => {
|
|||||||
setShowSettings(false)
|
setShowSettings(false)
|
||||||
setShowHistory(false)
|
setShowHistory(false)
|
||||||
break
|
break
|
||||||
case "koduCreditsFetched":
|
|
||||||
setKoduCredits(message.state!.koduCredits)
|
|
||||||
break
|
|
||||||
case "koduAuthenticated":
|
case "koduAuthenticated":
|
||||||
if (!didAuthKoduFromWelcome) {
|
if (!didAuthKoduFromWelcome) {
|
||||||
setShowSettings(true)
|
setShowSettings(true)
|
||||||
@@ -112,49 +70,21 @@ const App: React.FC = () => {
|
|||||||
return normalizeApiConfiguration(apiConfiguration)
|
return normalizeApiConfiguration(apiConfiguration)
|
||||||
}, [apiConfiguration])
|
}, [apiConfiguration])
|
||||||
|
|
||||||
if (!didHydrateState) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{showWelcome ? (
|
{showWelcome ? (
|
||||||
<WelcomeView
|
<WelcomeView setDidAuthKoduFromWelcome={setDidAuthKoduFromWelcome} />
|
||||||
apiConfiguration={apiConfiguration}
|
|
||||||
setApiConfiguration={setApiConfiguration}
|
|
||||||
vscodeUriScheme={vscodeUriScheme}
|
|
||||||
setDidAuthKoduFromWelcome={setDidAuthKoduFromWelcome}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{showSettings && (
|
{showSettings && <SettingsView onDone={() => setShowSettings(false)} />}
|
||||||
<SettingsView
|
{showHistory && <HistoryView onDone={() => setShowHistory(false)} />}
|
||||||
version={version}
|
|
||||||
apiConfiguration={apiConfiguration}
|
|
||||||
setApiConfiguration={setApiConfiguration}
|
|
||||||
koduCredits={koduCredits}
|
|
||||||
maxRequestsPerTask={maxRequestsPerTask}
|
|
||||||
setMaxRequestsPerTask={setMaxRequestsPerTask}
|
|
||||||
customInstructions={customInstructions}
|
|
||||||
setCustomInstructions={setCustomInstructions}
|
|
||||||
alwaysAllowReadOnly={alwaysAllowReadOnly}
|
|
||||||
setAlwaysAllowReadOnly={setAlwaysAllowReadOnly}
|
|
||||||
onDone={() => setShowSettings(false)}
|
|
||||||
vscodeUriScheme={vscodeUriScheme}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{showHistory && <HistoryView taskHistory={taskHistory} onDone={() => setShowHistory(false)} />}
|
|
||||||
{/* Do not conditionally load ChatView, it's expensive and there's state we don't want to lose (user input, disableInput, askResponse promise, etc.) */}
|
{/* Do not conditionally load ChatView, it's expensive and there's state we don't want to lose (user input, disableInput, askResponse promise, etc.) */}
|
||||||
<ChatView
|
<ChatView
|
||||||
version={version}
|
|
||||||
messages={claudeMessages}
|
|
||||||
taskHistory={taskHistory}
|
|
||||||
showHistoryView={() => {
|
showHistoryView={() => {
|
||||||
setShowSettings(false)
|
setShowSettings(false)
|
||||||
setShowHistory(true)
|
setShowHistory(true)
|
||||||
}}
|
}}
|
||||||
isHidden={showSettings || showHistory}
|
isHidden={showSettings || showHistory}
|
||||||
vscodeThemeName={vscodeThemeName}
|
|
||||||
showAnnouncement={showAnnouncement}
|
showAnnouncement={showAnnouncement}
|
||||||
selectedModelSupportsImages={selectedModelInfo.supportsImages}
|
selectedModelSupportsImages={selectedModelInfo.supportsImages}
|
||||||
selectedModelSupportsPromptCache={selectedModelInfo.supportsPromptCache}
|
selectedModelSupportsPromptCache={selectedModelInfo.supportsPromptCache}
|
||||||
@@ -162,10 +92,6 @@ const App: React.FC = () => {
|
|||||||
vscode.postMessage({ type: "didCloseAnnouncement" })
|
vscode.postMessage({ type: "didCloseAnnouncement" })
|
||||||
setShowAnnouncement(false)
|
setShowAnnouncement(false)
|
||||||
}}
|
}}
|
||||||
apiConfiguration={apiConfiguration}
|
|
||||||
vscodeUriScheme={vscodeUriScheme}
|
|
||||||
shouldShowKoduPromo={shouldShowKoduPromo}
|
|
||||||
koduCredits={koduCredits}
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -173,4 +99,12 @@ const App: React.FC = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const App = () => {
|
||||||
|
return (
|
||||||
|
<ExtensionStateContextProvider>
|
||||||
|
<AppContent />
|
||||||
|
</ExtensionStateContextProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default App
|
export default App
|
||||||
|
|||||||
@@ -18,29 +18,19 @@ import { ExtensionMessage } from "../../../src/shared/ExtensionMessage"
|
|||||||
import { getKoduAddCreditsUrl, getKoduHomepageUrl, getKoduSignInUrl } from "../../../src/shared/kodu"
|
import { getKoduAddCreditsUrl, getKoduHomepageUrl, getKoduSignInUrl } from "../../../src/shared/kodu"
|
||||||
import { vscode } from "../utils/vscode"
|
import { vscode } from "../utils/vscode"
|
||||||
import VSCodeButtonLink from "./VSCodeButtonLink"
|
import VSCodeButtonLink from "./VSCodeButtonLink"
|
||||||
|
import { useExtensionState } from "../context/ExtensionStateContext"
|
||||||
|
|
||||||
interface ApiOptionsProps {
|
interface ApiOptionsProps {
|
||||||
showModelOptions: boolean
|
showModelOptions: boolean
|
||||||
apiConfiguration?: ApiConfiguration
|
|
||||||
setApiConfiguration: React.Dispatch<React.SetStateAction<ApiConfiguration | undefined>>
|
|
||||||
koduCredits?: number
|
|
||||||
apiErrorMessage?: string
|
apiErrorMessage?: string
|
||||||
vscodeUriScheme?: string
|
|
||||||
setDidAuthKodu?: React.Dispatch<React.SetStateAction<boolean>>
|
setDidAuthKodu?: React.Dispatch<React.SetStateAction<boolean>>
|
||||||
}
|
}
|
||||||
|
|
||||||
const ApiOptions: React.FC<ApiOptionsProps> = ({
|
const ApiOptions: React.FC<ApiOptionsProps> = ({ showModelOptions, apiErrorMessage, setDidAuthKodu }) => {
|
||||||
showModelOptions,
|
const { apiConfiguration, setApiConfiguration, koduCredits, uriScheme } = useExtensionState()
|
||||||
apiConfiguration,
|
|
||||||
setApiConfiguration,
|
|
||||||
koduCredits,
|
|
||||||
apiErrorMessage,
|
|
||||||
vscodeUriScheme,
|
|
||||||
setDidAuthKodu,
|
|
||||||
}) => {
|
|
||||||
const [, setDidFetchKoduCredits] = useState(false)
|
const [, setDidFetchKoduCredits] = useState(false)
|
||||||
const handleInputChange = (field: keyof ApiConfiguration) => (event: any) => {
|
const handleInputChange = (field: keyof ApiConfiguration) => (event: any) => {
|
||||||
setApiConfiguration((prev) => ({ ...prev, [field]: event.target.value }))
|
setApiConfiguration({ ...apiConfiguration, [field]: event.target.value })
|
||||||
}
|
}
|
||||||
|
|
||||||
const { selectedProvider, selectedModelId, selectedModelInfo } = useMemo(() => {
|
const { selectedProvider, selectedModelId, selectedModelInfo } = useMemo(() => {
|
||||||
@@ -185,7 +175,7 @@ const ApiOptions: React.FC<ApiOptionsProps> = ({
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<VSCodeButtonLink
|
<VSCodeButtonLink
|
||||||
href={getKoduAddCreditsUrl(vscodeUriScheme)}
|
href={getKoduAddCreditsUrl(uriScheme)}
|
||||||
style={{
|
style={{
|
||||||
width: "fit-content",
|
width: "fit-content",
|
||||||
}}>
|
}}>
|
||||||
@@ -194,9 +184,7 @@ const ApiOptions: React.FC<ApiOptionsProps> = ({
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ margin: "4px 0px" }}>
|
<div style={{ margin: "4px 0px" }}>
|
||||||
<VSCodeButtonLink
|
<VSCodeButtonLink href={getKoduSignInUrl(uriScheme)} onClick={() => setDidAuthKodu?.(true)}>
|
||||||
href={getKoduSignInUrl(vscodeUriScheme)}
|
|
||||||
onClick={() => setDidAuthKodu?.(true)}>
|
|
||||||
Sign in to Kodu
|
Sign in to Kodu
|
||||||
</VSCodeButtonLink>
|
</VSCodeButtonLink>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
|
|||||||
import { ClaudeAsk, ClaudeMessage, ClaudeSay, ClaudeSayTool } from "../../../src/shared/ExtensionMessage"
|
import { ClaudeAsk, ClaudeMessage, ClaudeSay, ClaudeSayTool } from "../../../src/shared/ExtensionMessage"
|
||||||
import { COMMAND_OUTPUT_STRING } from "../../../src/shared/combineCommandSequences"
|
import { COMMAND_OUTPUT_STRING } from "../../../src/shared/combineCommandSequences"
|
||||||
import { SyntaxHighlighterStyle } from "../utils/getSyntaxHighlighterStyleFromTheme"
|
import { SyntaxHighlighterStyle } from "../utils/getSyntaxHighlighterStyleFromTheme"
|
||||||
import CodeBlock from "./CodeBlock/CodeBlock"
|
import CodeBlock from "./CodeBlock"
|
||||||
import Thumbnails from "./Thumbnails"
|
import Thumbnails from "./Thumbnails"
|
||||||
import { ApiProvider } from "../../../src/shared/api"
|
import { ApiProvider } from "../../../src/shared/api"
|
||||||
|
|
||||||
|
|||||||
@@ -4,56 +4,50 @@ import vsDarkPlus from "react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-
|
|||||||
import DynamicTextArea from "react-textarea-autosize"
|
import DynamicTextArea from "react-textarea-autosize"
|
||||||
import { useEvent, useMount } from "react-use"
|
import { useEvent, useMount } from "react-use"
|
||||||
import { Virtuoso, type VirtuosoHandle } from "react-virtuoso"
|
import { Virtuoso, type VirtuosoHandle } from "react-virtuoso"
|
||||||
import { ClaudeAsk, ClaudeMessage, ExtensionMessage } from "../../../src/shared/ExtensionMessage"
|
import { ClaudeAsk, ExtensionMessage } from "../../../src/shared/ExtensionMessage"
|
||||||
import { getApiMetrics } from "../../../src/shared/getApiMetrics"
|
|
||||||
import { combineApiRequests } from "../../../src/shared/combineApiRequests"
|
import { combineApiRequests } from "../../../src/shared/combineApiRequests"
|
||||||
import { combineCommandSequences } from "../../../src/shared/combineCommandSequences"
|
import { combineCommandSequences } from "../../../src/shared/combineCommandSequences"
|
||||||
|
import { getApiMetrics } from "../../../src/shared/getApiMetrics"
|
||||||
|
import { useExtensionState } from "../context/ExtensionStateContext"
|
||||||
import { getSyntaxHighlighterStyleFromTheme } from "../utils/getSyntaxHighlighterStyleFromTheme"
|
import { getSyntaxHighlighterStyleFromTheme } from "../utils/getSyntaxHighlighterStyleFromTheme"
|
||||||
import { vscode } from "../utils/vscode"
|
import { vscode } from "../utils/vscode"
|
||||||
import Announcement from "./Announcement"
|
import Announcement from "./Announcement"
|
||||||
import ChatRow from "./ChatRow"
|
import ChatRow from "./ChatRow"
|
||||||
import HistoryPreview from "./HistoryPreview"
|
import HistoryPreview from "./HistoryPreview"
|
||||||
|
import KoduPromo from "./KoduPromo"
|
||||||
import TaskHeader from "./TaskHeader"
|
import TaskHeader from "./TaskHeader"
|
||||||
import Thumbnails from "./Thumbnails"
|
import Thumbnails from "./Thumbnails"
|
||||||
import { HistoryItem } from "../../../src/shared/HistoryItem"
|
|
||||||
import { ApiConfiguration } from "../../../src/shared/api"
|
|
||||||
import KoduPromo from "./KoduPromo"
|
|
||||||
|
|
||||||
interface ChatViewProps {
|
interface ChatViewProps {
|
||||||
version: string
|
|
||||||
messages: ClaudeMessage[]
|
|
||||||
taskHistory: HistoryItem[]
|
|
||||||
isHidden: boolean
|
isHidden: boolean
|
||||||
vscodeThemeName?: string
|
|
||||||
showAnnouncement: boolean
|
showAnnouncement: boolean
|
||||||
selectedModelSupportsImages: boolean
|
selectedModelSupportsImages: boolean
|
||||||
selectedModelSupportsPromptCache: boolean
|
selectedModelSupportsPromptCache: boolean
|
||||||
hideAnnouncement: () => void
|
hideAnnouncement: () => void
|
||||||
showHistoryView: () => void
|
showHistoryView: () => void
|
||||||
apiConfiguration?: ApiConfiguration
|
|
||||||
vscodeUriScheme?: string
|
|
||||||
shouldShowKoduPromo: boolean
|
|
||||||
koduCredits?: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_IMAGES_PER_MESSAGE = 20 // Anthropic limits to 20 images
|
const MAX_IMAGES_PER_MESSAGE = 20 // Anthropic limits to 20 images
|
||||||
|
|
||||||
const ChatView = ({
|
const ChatView = ({
|
||||||
version,
|
|
||||||
messages,
|
|
||||||
taskHistory,
|
|
||||||
isHidden,
|
isHidden,
|
||||||
vscodeThemeName,
|
|
||||||
showAnnouncement,
|
showAnnouncement,
|
||||||
selectedModelSupportsImages,
|
selectedModelSupportsImages,
|
||||||
selectedModelSupportsPromptCache,
|
selectedModelSupportsPromptCache,
|
||||||
hideAnnouncement,
|
hideAnnouncement,
|
||||||
showHistoryView,
|
showHistoryView,
|
||||||
apiConfiguration,
|
|
||||||
vscodeUriScheme,
|
|
||||||
shouldShowKoduPromo,
|
|
||||||
koduCredits,
|
|
||||||
}: ChatViewProps) => {
|
}: ChatViewProps) => {
|
||||||
|
const {
|
||||||
|
version,
|
||||||
|
claudeMessages: messages,
|
||||||
|
taskHistory,
|
||||||
|
themeName: vscodeThemeName,
|
||||||
|
apiConfiguration,
|
||||||
|
uriScheme,
|
||||||
|
shouldShowKoduPromo,
|
||||||
|
koduCredits,
|
||||||
|
} = useExtensionState()
|
||||||
|
|
||||||
//const task = messages.length > 0 ? (messages[0].say === "task" ? messages[0] : undefined) : undefined) : undefined
|
//const task = messages.length > 0 ? (messages[0].say === "task" ? messages[0] : undefined) : undefined) : undefined
|
||||||
const task = messages.length > 0 ? messages[0] : undefined // leaving this less safe version here since if the first message is not a task, then the extension is in a bad state and needs to be debugged (see ClaudeDev.abort)
|
const task = messages.length > 0 ? messages[0] : undefined // leaving this less safe version here since if the first message is not a task, then the extension is in a bad state and needs to be debugged (see ClaudeDev.abort)
|
||||||
const modifiedMessages = useMemo(() => combineApiRequests(combineCommandSequences(messages.slice(1))), [messages])
|
const modifiedMessages = useMemo(() => combineApiRequests(combineCommandSequences(messages.slice(1))), [messages])
|
||||||
@@ -490,7 +484,7 @@ const ChatView = ({
|
|||||||
onClose={handleTaskCloseButtonClick}
|
onClose={handleTaskCloseButtonClick}
|
||||||
isHidden={isHidden}
|
isHidden={isHidden}
|
||||||
koduCredits={koduCredits}
|
koduCredits={koduCredits}
|
||||||
vscodeUriScheme={vscodeUriScheme}
|
vscodeUriScheme={uriScheme}
|
||||||
apiProvider={apiConfiguration?.apiProvider}
|
apiProvider={apiConfiguration?.apiProvider}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
@@ -500,11 +494,11 @@ const ChatView = ({
|
|||||||
version={version}
|
version={version}
|
||||||
hideAnnouncement={hideAnnouncement}
|
hideAnnouncement={hideAnnouncement}
|
||||||
apiConfiguration={apiConfiguration}
|
apiConfiguration={apiConfiguration}
|
||||||
vscodeUriScheme={vscodeUriScheme}
|
vscodeUriScheme={uriScheme}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{apiConfiguration?.koduApiKey === undefined && !showAnnouncement && shouldShowKoduPromo && (
|
{apiConfiguration?.koduApiKey === undefined && !showAnnouncement && shouldShowKoduPromo && (
|
||||||
<KoduPromo vscodeUriScheme={vscodeUriScheme} style={{ margin: "10px 15px -10px 15px" }} />
|
<KoduPromo style={{ margin: "10px 15px -10px 15px" }} />
|
||||||
)}
|
)}
|
||||||
<div style={{ padding: "0 20px", flexGrow: taskHistory.length > 0 ? undefined : 1 }}>
|
<div style={{ padding: "0 20px", flexGrow: taskHistory.length > 0 ? undefined : 1 }}>
|
||||||
<h2>What can I do for you?</h2>
|
<h2>What can I do for you?</h2>
|
||||||
@@ -520,9 +514,7 @@ const ChatView = ({
|
|||||||
permission), I can assist you in ways that go beyond simple code completion or tech support.
|
permission), I can assist you in ways that go beyond simple code completion or tech support.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{taskHistory.length > 0 && (
|
{taskHistory.length > 0 && <HistoryPreview showHistoryView={showHistoryView} />}
|
||||||
<HistoryPreview taskHistory={taskHistory} showHistoryView={showHistoryView} />
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{task && (
|
{task && (
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useMemo } from "react"
|
import { useMemo } from "react"
|
||||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
|
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
|
||||||
import { getLanguageFromPath } from "../../utils/getLanguageFromPath"
|
import { getLanguageFromPath } from "../utils/getLanguageFromPath"
|
||||||
import { SyntaxHighlighterStyle } from "../../utils/getSyntaxHighlighterStyleFromTheme"
|
import { SyntaxHighlighterStyle } from "../utils/getSyntaxHighlighterStyleFromTheme"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
const vscodeSyntaxStyle: React.CSSProperties = {
|
const vscodeSyntaxStyle: React.CSSProperties = {
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
|
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
|
||||||
|
import { useExtensionState } from "../context/ExtensionStateContext"
|
||||||
import { vscode } from "../utils/vscode"
|
import { vscode } from "../utils/vscode"
|
||||||
import { HistoryItem } from "../../../src/shared/HistoryItem"
|
|
||||||
|
|
||||||
type HistoryPreviewProps = {
|
type HistoryPreviewProps = {
|
||||||
taskHistory: HistoryItem[]
|
|
||||||
showHistoryView: () => void
|
showHistoryView: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const HistoryPreview = ({ taskHistory, showHistoryView }: HistoryPreviewProps) => {
|
const HistoryPreview = ({ showHistoryView }: HistoryPreviewProps) => {
|
||||||
|
const { taskHistory } = useExtensionState()
|
||||||
const handleHistorySelect = (id: string) => {
|
const handleHistorySelect = (id: string) => {
|
||||||
vscode.postMessage({ type: "showTaskWithId", text: id })
|
vscode.postMessage({ type: "showTaskWithId", text: id })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
|
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
|
||||||
|
import { useExtensionState } from "../context/ExtensionStateContext"
|
||||||
import { vscode } from "../utils/vscode"
|
import { vscode } from "../utils/vscode"
|
||||||
import { HistoryItem } from "../../../src/shared/HistoryItem"
|
|
||||||
|
|
||||||
type HistoryViewProps = {
|
type HistoryViewProps = {
|
||||||
taskHistory: HistoryItem[]
|
|
||||||
onDone: () => void
|
onDone: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const HistoryView = ({ taskHistory, onDone }: HistoryViewProps) => {
|
const HistoryView = ({ onDone }: HistoryViewProps) => {
|
||||||
|
const { taskHistory } = useExtensionState()
|
||||||
const handleHistorySelect = (id: string) => {
|
const handleHistorySelect = (id: string) => {
|
||||||
vscode.postMessage({ type: "showTaskWithId", text: id })
|
vscode.postMessage({ type: "showTaskWithId", text: id })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import { getKoduSignInUrl } from "../../../src/shared/kodu"
|
import { getKoduSignInUrl } from "../../../src/shared/kodu"
|
||||||
import { vscode } from "../utils/vscode"
|
import { vscode } from "../utils/vscode"
|
||||||
|
import { useExtensionState } from "../context/ExtensionStateContext"
|
||||||
|
|
||||||
interface KoduPromoProps {
|
interface KoduPromoProps {
|
||||||
vscodeUriScheme?: string
|
|
||||||
style?: React.CSSProperties
|
style?: React.CSSProperties
|
||||||
}
|
}
|
||||||
|
|
||||||
const KoduPromo: React.FC<KoduPromoProps> = ({ vscodeUriScheme, style }) => {
|
const KoduPromo: React.FC<KoduPromoProps> = ({ style }) => {
|
||||||
|
const { uriScheme } = useExtensionState()
|
||||||
|
|
||||||
function onClose() {
|
function onClose() {
|
||||||
vscode.postMessage({ type: "didDismissKoduPromo" })
|
vscode.postMessage({ type: "didDismissKoduPromo" })
|
||||||
}
|
}
|
||||||
@@ -28,7 +30,7 @@ const KoduPromo: React.FC<KoduPromoProps> = ({ vscodeUriScheme, style }) => {
|
|||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
}}>
|
}}>
|
||||||
<a
|
<a
|
||||||
href={getKoduSignInUrl(vscodeUriScheme)}
|
href={getKoduSignInUrl(uriScheme)}
|
||||||
style={{
|
style={{
|
||||||
textDecoration: "none",
|
textDecoration: "none",
|
||||||
color: "inherit",
|
color: "inherit",
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import {
|
|||||||
VSCodeTextArea,
|
VSCodeTextArea,
|
||||||
VSCodeTextField,
|
VSCodeTextField,
|
||||||
} from "@vscode/webview-ui-toolkit/react"
|
} from "@vscode/webview-ui-toolkit/react"
|
||||||
import React, { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
import { ApiConfiguration } from "../../../src/shared/api"
|
import { useExtensionState } from "../context/ExtensionStateContext"
|
||||||
import { validateApiConfiguration, validateMaxRequestsPerTask } from "../utils/validate"
|
import { validateApiConfiguration, validateMaxRequestsPerTask } from "../utils/validate"
|
||||||
import { vscode } from "../utils/vscode"
|
import { vscode } from "../utils/vscode"
|
||||||
import ApiOptions from "./ApiOptions"
|
import ApiOptions from "./ApiOptions"
|
||||||
@@ -14,47 +14,35 @@ import ApiOptions from "./ApiOptions"
|
|||||||
const IS_DEV = false // FIXME: use flags when packaging
|
const IS_DEV = false // FIXME: use flags when packaging
|
||||||
|
|
||||||
type SettingsViewProps = {
|
type SettingsViewProps = {
|
||||||
version: string
|
|
||||||
apiConfiguration?: ApiConfiguration
|
|
||||||
setApiConfiguration: React.Dispatch<React.SetStateAction<ApiConfiguration | undefined>>
|
|
||||||
koduCredits?: number
|
|
||||||
maxRequestsPerTask: string
|
|
||||||
setMaxRequestsPerTask: React.Dispatch<React.SetStateAction<string>>
|
|
||||||
customInstructions: string
|
|
||||||
setCustomInstructions: React.Dispatch<React.SetStateAction<string>>
|
|
||||||
onDone: () => void
|
onDone: () => void
|
||||||
alwaysAllowReadOnly: boolean
|
|
||||||
setAlwaysAllowReadOnly: React.Dispatch<React.SetStateAction<boolean>>
|
|
||||||
vscodeUriScheme?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const SettingsView = ({
|
const SettingsView = ({ onDone }: SettingsViewProps) => {
|
||||||
version,
|
const {
|
||||||
apiConfiguration,
|
apiConfiguration,
|
||||||
setApiConfiguration,
|
version,
|
||||||
koduCredits,
|
maxRequestsPerTask,
|
||||||
maxRequestsPerTask,
|
customInstructions,
|
||||||
setMaxRequestsPerTask,
|
setCustomInstructions,
|
||||||
customInstructions,
|
alwaysAllowReadOnly,
|
||||||
setCustomInstructions,
|
setAlwaysAllowReadOnly,
|
||||||
onDone,
|
} = useExtensionState()
|
||||||
alwaysAllowReadOnly,
|
|
||||||
setAlwaysAllowReadOnly,
|
|
||||||
vscodeUriScheme,
|
|
||||||
}: SettingsViewProps) => {
|
|
||||||
const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined)
|
const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined)
|
||||||
const [maxRequestsErrorMessage, setMaxRequestsErrorMessage] = useState<string | undefined>(undefined)
|
const [maxRequestsErrorMessage, setMaxRequestsErrorMessage] = useState<string | undefined>(undefined)
|
||||||
|
const [maxRequestsPerTaskString, setMaxRequestsPerTaskString] = useState<string>(
|
||||||
|
maxRequestsPerTask?.toString() || ""
|
||||||
|
)
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
const apiValidationResult = validateApiConfiguration(apiConfiguration)
|
const apiValidationResult = validateApiConfiguration(apiConfiguration)
|
||||||
const maxRequestsValidationResult = validateMaxRequestsPerTask(maxRequestsPerTask)
|
const maxRequestsValidationResult = validateMaxRequestsPerTask(maxRequestsPerTaskString)
|
||||||
|
|
||||||
setApiErrorMessage(apiValidationResult)
|
setApiErrorMessage(apiValidationResult)
|
||||||
setMaxRequestsErrorMessage(maxRequestsValidationResult)
|
setMaxRequestsErrorMessage(maxRequestsValidationResult)
|
||||||
|
|
||||||
if (!apiValidationResult && !maxRequestsValidationResult) {
|
if (!apiValidationResult && !maxRequestsValidationResult) {
|
||||||
vscode.postMessage({ type: "apiConfiguration", apiConfiguration })
|
vscode.postMessage({ type: "apiConfiguration", apiConfiguration })
|
||||||
vscode.postMessage({ type: "maxRequestsPerTask", text: maxRequestsPerTask })
|
vscode.postMessage({ type: "maxRequestsPerTask", text: maxRequestsPerTaskString })
|
||||||
vscode.postMessage({ type: "customInstructions", text: customInstructions })
|
vscode.postMessage({ type: "customInstructions", text: customInstructions })
|
||||||
vscode.postMessage({ type: "alwaysAllowReadOnly", bool: alwaysAllowReadOnly })
|
vscode.postMessage({ type: "alwaysAllowReadOnly", bool: alwaysAllowReadOnly })
|
||||||
onDone()
|
onDone()
|
||||||
@@ -112,14 +100,7 @@ const SettingsView = ({
|
|||||||
<div
|
<div
|
||||||
style={{ flexGrow: 1, overflowY: "scroll", paddingRight: 8, display: "flex", flexDirection: "column" }}>
|
style={{ flexGrow: 1, overflowY: "scroll", paddingRight: 8, display: "flex", flexDirection: "column" }}>
|
||||||
<div style={{ marginBottom: 5 }}>
|
<div style={{ marginBottom: 5 }}>
|
||||||
<ApiOptions
|
<ApiOptions showModelOptions={true} apiErrorMessage={apiErrorMessage} />
|
||||||
apiConfiguration={apiConfiguration}
|
|
||||||
setApiConfiguration={setApiConfiguration}
|
|
||||||
showModelOptions={true}
|
|
||||||
koduCredits={koduCredits}
|
|
||||||
apiErrorMessage={apiErrorMessage}
|
|
||||||
vscodeUriScheme={vscodeUriScheme}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ marginBottom: 5 }}>
|
<div style={{ marginBottom: 5 }}>
|
||||||
@@ -141,13 +122,13 @@ const SettingsView = ({
|
|||||||
|
|
||||||
<div style={{ marginBottom: 5 }}>
|
<div style={{ marginBottom: 5 }}>
|
||||||
<VSCodeTextArea
|
<VSCodeTextArea
|
||||||
value={customInstructions}
|
value={customInstructions ?? ""}
|
||||||
style={{ width: "100%" }}
|
style={{ width: "100%" }}
|
||||||
rows={4}
|
rows={4}
|
||||||
placeholder={
|
placeholder={
|
||||||
'e.g. "Run unit tests at the end", "Use TypeScript with async/await", "Speak in Spanish"'
|
'e.g. "Run unit tests at the end", "Use TypeScript with async/await", "Speak in Spanish"'
|
||||||
}
|
}
|
||||||
onInput={(e: any) => setCustomInstructions(e.target?.value || "")}>
|
onInput={(e: any) => setCustomInstructions(e.target?.value ?? "")}>
|
||||||
<span style={{ fontWeight: "500" }}>Custom Instructions</span>
|
<span style={{ fontWeight: "500" }}>Custom Instructions</span>
|
||||||
</VSCodeTextArea>
|
</VSCodeTextArea>
|
||||||
<p
|
<p
|
||||||
@@ -162,10 +143,10 @@ const SettingsView = ({
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<VSCodeTextField
|
<VSCodeTextField
|
||||||
value={maxRequestsPerTask}
|
value={maxRequestsPerTaskString}
|
||||||
style={{ width: "100%" }}
|
style={{ width: "100%" }}
|
||||||
placeholder="20"
|
placeholder="20"
|
||||||
onInput={(e: any) => setMaxRequestsPerTask(e.target?.value)}>
|
onInput={(e: any) => setMaxRequestsPerTaskString(e.target?.value ?? "")}>
|
||||||
<span style={{ fontWeight: "500" }}>Maximum # Requests Per Task</span>
|
<span style={{ fontWeight: "500" }}>Maximum # Requests Per Task</span>
|
||||||
</VSCodeTextField>
|
</VSCodeTextField>
|
||||||
<p
|
<p
|
||||||
|
|||||||
@@ -1,24 +1,18 @@
|
|||||||
import { VSCodeButton, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
|
import { VSCodeButton, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
|
||||||
import React, { useEffect, useState } from "react"
|
import React, { useEffect, useState } from "react"
|
||||||
import { ApiConfiguration } from "../../../src/shared/api"
|
import { getKoduSignInUrl } from "../../../src/shared/kodu"
|
||||||
|
import { useExtensionState } from "../context/ExtensionStateContext"
|
||||||
import { validateApiConfiguration } from "../utils/validate"
|
import { validateApiConfiguration } from "../utils/validate"
|
||||||
import { vscode } from "../utils/vscode"
|
import { vscode } from "../utils/vscode"
|
||||||
import ApiOptions from "./ApiOptions"
|
import ApiOptions from "./ApiOptions"
|
||||||
import { getKoduSignInUrl } from "../../../src/shared/kodu"
|
|
||||||
|
|
||||||
interface WelcomeViewProps {
|
interface WelcomeViewProps {
|
||||||
apiConfiguration?: ApiConfiguration
|
|
||||||
setApiConfiguration: React.Dispatch<React.SetStateAction<ApiConfiguration | undefined>>
|
|
||||||
vscodeUriScheme?: string
|
|
||||||
setDidAuthKoduFromWelcome: React.Dispatch<React.SetStateAction<boolean>>
|
setDidAuthKoduFromWelcome: React.Dispatch<React.SetStateAction<boolean>>
|
||||||
}
|
}
|
||||||
|
|
||||||
const WelcomeView: React.FC<WelcomeViewProps> = ({
|
const WelcomeView: React.FC<WelcomeViewProps> = ({ setDidAuthKoduFromWelcome }) => {
|
||||||
apiConfiguration,
|
const { apiConfiguration, uriScheme } = useExtensionState()
|
||||||
setApiConfiguration,
|
|
||||||
vscodeUriScheme,
|
|
||||||
setDidAuthKoduFromWelcome,
|
|
||||||
}) => {
|
|
||||||
const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined)
|
const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined)
|
||||||
|
|
||||||
const disableLetsGoButton = apiErrorMessage != null
|
const disableLetsGoButton = apiErrorMessage != null
|
||||||
@@ -67,20 +61,14 @@ const WelcomeView: React.FC<WelcomeViewProps> = ({
|
|||||||
}}></i>
|
}}></i>
|
||||||
<span>
|
<span>
|
||||||
Explore Claude's capabilities with $20 free credits from{" "}
|
Explore Claude's capabilities with $20 free credits from{" "}
|
||||||
<VSCodeLink href={getKoduSignInUrl(vscodeUriScheme)} style={{ display: "inline" }}>
|
<VSCodeLink href={getKoduSignInUrl(uriScheme)} style={{ display: "inline" }}>
|
||||||
Kodu
|
Kodu
|
||||||
</VSCodeLink>
|
</VSCodeLink>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ marginTop: "10px" }}>
|
<div style={{ marginTop: "10px" }}>
|
||||||
<ApiOptions
|
<ApiOptions showModelOptions={false} setDidAuthKodu={setDidAuthKoduFromWelcome} />
|
||||||
apiConfiguration={apiConfiguration}
|
|
||||||
setApiConfiguration={setApiConfiguration}
|
|
||||||
showModelOptions={false}
|
|
||||||
vscodeUriScheme={vscodeUriScheme}
|
|
||||||
setDidAuthKodu={setDidAuthKoduFromWelcome}
|
|
||||||
/>
|
|
||||||
{apiConfiguration?.apiProvider !== "kodu" && (
|
{apiConfiguration?.apiProvider !== "kodu" && (
|
||||||
<VSCodeButton onClick={handleSubmit} disabled={disableLetsGoButton} style={{ marginTop: "3px" }}>
|
<VSCodeButton onClick={handleSubmit} disabled={disableLetsGoButton} style={{ marginTop: "3px" }}>
|
||||||
Let's go!
|
Let's go!
|
||||||
|
|||||||
71
webview-ui/src/context/ExtensionStateContext.tsx
Normal file
71
webview-ui/src/context/ExtensionStateContext.tsx
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import React, { createContext, useCallback, useContext, useEffect, useState } from "react"
|
||||||
|
import { useEvent } from "react-use"
|
||||||
|
import { ExtensionMessage, ExtensionState } from "../../../src/shared/ExtensionMessage"
|
||||||
|
import { ApiConfiguration } from "../../../src/shared/api"
|
||||||
|
import { vscode } from "../utils/vscode"
|
||||||
|
|
||||||
|
interface ExtensionStateContextType extends ExtensionState {
|
||||||
|
setApiConfiguration: (config: ApiConfiguration) => void
|
||||||
|
setMaxRequestsPerTask: (value?: number) => void
|
||||||
|
setCustomInstructions: (value?: string) => void
|
||||||
|
setAlwaysAllowReadOnly: (value: boolean) => void
|
||||||
|
setShowAnnouncement: (value: boolean) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const ExtensionStateContext = createContext<ExtensionStateContextType | undefined>(undefined)
|
||||||
|
|
||||||
|
export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||||
|
const [state, setState] = useState<ExtensionState>({
|
||||||
|
version: "",
|
||||||
|
claudeMessages: [],
|
||||||
|
taskHistory: [],
|
||||||
|
shouldShowAnnouncement: false,
|
||||||
|
shouldShowKoduPromo: false,
|
||||||
|
})
|
||||||
|
const [didHydrateState, setDidHydrateState] = useState(false)
|
||||||
|
|
||||||
|
const handleMessage = useCallback((event: MessageEvent) => {
|
||||||
|
const message: ExtensionMessage = event.data
|
||||||
|
if (message.type === "state" && message.state) {
|
||||||
|
setState(message.state)
|
||||||
|
setDidHydrateState(true)
|
||||||
|
}
|
||||||
|
if (message.type === "action" && message.action) {
|
||||||
|
switch (message.action) {
|
||||||
|
case "koduCreditsFetched":
|
||||||
|
// special case where we only want to update one part of state in case user is in the middle of modifying settings
|
||||||
|
setState((prevState) => ({ ...prevState, koduCredits: message.state?.koduCredits }))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEvent("message", handleMessage)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
vscode.postMessage({ type: "webviewDidLaunch" })
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const contextValue: ExtensionStateContextType = {
|
||||||
|
...state,
|
||||||
|
setApiConfiguration: (value) => setState((prevState) => ({ ...prevState, apiConfiguration: value })),
|
||||||
|
setMaxRequestsPerTask: (value) => setState((prevState) => ({ ...prevState, maxRequestsPerTask: value })),
|
||||||
|
setCustomInstructions: (value) => setState((prevState) => ({ ...prevState, customInstructions: value })),
|
||||||
|
setAlwaysAllowReadOnly: (value) => setState((prevState) => ({ ...prevState, alwaysAllowReadOnly: value })),
|
||||||
|
setShowAnnouncement: (value) => setState((prevState) => ({ ...prevState, shouldShowAnnouncement: value })),
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!didHydrateState) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useExtensionState = () => {
|
||||||
|
const context = useContext(ExtensionStateContext)
|
||||||
|
if (context === undefined) {
|
||||||
|
throw new Error("useExtensionState must be used within an ExtensionStateContextProvider")
|
||||||
|
}
|
||||||
|
return context
|
||||||
|
}
|
||||||
@@ -1,15 +1,3 @@
|
|||||||
/* body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans",
|
|
||||||
"Droid Sans", "Helvetica Neue", sans-serif;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
|
|
||||||
} */
|
|
||||||
|
|
||||||
textarea:focus {
|
textarea:focus {
|
||||||
outline: 1.5px solid var(--vscode-focusBorder, #007fd4);
|
outline: 1.5px solid var(--vscode-focusBorder, #007fd4);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user