mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-21 12:51:17 -05:00
Prettier backfill
This commit is contained in:
@@ -8,9 +8,9 @@ type PromptsViewProps = {
|
||||
onDone: () => void
|
||||
}
|
||||
|
||||
const AGENT_MODES = modes.map(mode => ({
|
||||
const AGENT_MODES = modes.map((mode) => ({
|
||||
id: mode.slug,
|
||||
label: mode.name
|
||||
label: mode.name,
|
||||
}))
|
||||
|
||||
const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
@@ -21,24 +21,24 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
setEnhancementApiConfigId,
|
||||
mode,
|
||||
customInstructions,
|
||||
setCustomInstructions
|
||||
setCustomInstructions,
|
||||
} = useExtensionState()
|
||||
const [testPrompt, setTestPrompt] = useState('')
|
||||
const [testPrompt, setTestPrompt] = useState("")
|
||||
const [isEnhancing, setIsEnhancing] = useState(false)
|
||||
const [activeTab, setActiveTab] = useState<Mode>(mode)
|
||||
const [isDialogOpen, setIsDialogOpen] = useState(false)
|
||||
const [selectedPromptContent, setSelectedPromptContent] = useState('')
|
||||
const [selectedPromptTitle, setSelectedPromptTitle] = useState('')
|
||||
const [selectedPromptContent, setSelectedPromptContent] = useState("")
|
||||
const [selectedPromptTitle, setSelectedPromptTitle] = useState("")
|
||||
|
||||
useEffect(() => {
|
||||
const handler = (event: MessageEvent) => {
|
||||
const message = event.data
|
||||
if (message.type === 'enhancedPrompt') {
|
||||
if (message.type === "enhancedPrompt") {
|
||||
if (message.text) {
|
||||
setTestPrompt(message.text)
|
||||
}
|
||||
setIsEnhancing(false)
|
||||
} else if (message.type === 'systemPrompt') {
|
||||
} else if (message.type === "systemPrompt") {
|
||||
if (message.text) {
|
||||
setSelectedPromptContent(message.text)
|
||||
setSelectedPromptTitle(`System Prompt (${message.mode} mode)`)
|
||||
@@ -47,17 +47,15 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('message', handler)
|
||||
return () => window.removeEventListener('message', handler)
|
||||
window.addEventListener("message", handler)
|
||||
return () => window.removeEventListener("message", handler)
|
||||
}, [])
|
||||
|
||||
type AgentMode = string;
|
||||
type AgentMode = string
|
||||
|
||||
const updateAgentPrompt = (mode: Mode, promptData: PromptComponent) => {
|
||||
const existingPrompt = customPrompts?.[mode]
|
||||
const updatedPrompt = typeof existingPrompt === 'object'
|
||||
? { ...existingPrompt, ...promptData }
|
||||
: promptData
|
||||
const updatedPrompt = typeof existingPrompt === "object" ? { ...existingPrompt, ...promptData } : promptData
|
||||
|
||||
// Only include properties that differ from defaults
|
||||
if (updatedPrompt.roleDefinition === getRoleDefinition(mode)) {
|
||||
@@ -67,14 +65,14 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
vscode.postMessage({
|
||||
type: "updatePrompt",
|
||||
promptMode: mode,
|
||||
customPrompt: updatedPrompt
|
||||
customPrompt: updatedPrompt,
|
||||
})
|
||||
}
|
||||
|
||||
const updateEnhancePrompt = (value: string | undefined) => {
|
||||
vscode.postMessage({
|
||||
type: "updateEnhancedPrompt",
|
||||
text: value
|
||||
text: value,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -94,8 +92,8 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
const handleAgentReset = (mode: AgentMode) => {
|
||||
const existingPrompt = customPrompts?.[mode]
|
||||
updateAgentPrompt(mode, {
|
||||
...(typeof existingPrompt === 'object' ? existingPrompt : {}),
|
||||
roleDefinition: undefined
|
||||
...(typeof existingPrompt === "object" ? existingPrompt : {}),
|
||||
roleDefinition: undefined,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -105,22 +103,22 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
|
||||
const getAgentPromptValue = (mode: Mode): string => {
|
||||
const prompt = customPrompts?.[mode]
|
||||
return typeof prompt === 'object' ? prompt.roleDefinition ?? getRoleDefinition(mode) : getRoleDefinition(mode);
|
||||
return typeof prompt === "object" ? (prompt.roleDefinition ?? getRoleDefinition(mode)) : getRoleDefinition(mode)
|
||||
}
|
||||
|
||||
const getEnhancePromptValue = (): string => {
|
||||
const enhance = customPrompts?.enhance
|
||||
const defaultEnhance = typeof defaultPrompts.enhance === 'string' ? defaultPrompts.enhance : ''
|
||||
return typeof enhance === 'string' ? enhance : defaultEnhance
|
||||
const defaultEnhance = typeof defaultPrompts.enhance === "string" ? defaultPrompts.enhance : ""
|
||||
return typeof enhance === "string" ? enhance : defaultEnhance
|
||||
}
|
||||
|
||||
const handleTestEnhancement = () => {
|
||||
if (!testPrompt.trim()) return
|
||||
|
||||
|
||||
setIsEnhancing(true)
|
||||
vscode.postMessage({
|
||||
type: "enhancePrompt",
|
||||
text: testPrompt
|
||||
text: testPrompt,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -147,19 +145,23 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
</div>
|
||||
|
||||
<div style={{ flex: 1, overflow: "auto", padding: "0 20px" }}>
|
||||
<div style={{ marginBottom: '20px' }}>
|
||||
<div style={{ marginBottom: "20px" }}>
|
||||
<div style={{ fontWeight: "bold", marginBottom: "4px" }}>Custom Instructions for All Modes</div>
|
||||
<div style={{ fontSize: "13px", color: "var(--vscode-descriptionForeground)", marginBottom: "8px" }}>
|
||||
These instructions apply to all modes. They provide a base set of behaviors that can be enhanced by mode-specific instructions below.
|
||||
<div
|
||||
style={{ fontSize: "13px", color: "var(--vscode-descriptionForeground)", marginBottom: "8px" }}>
|
||||
These instructions apply to all modes. They provide a base set of behaviors that can be enhanced
|
||||
by mode-specific instructions below.
|
||||
</div>
|
||||
<VSCodeTextArea
|
||||
value={customInstructions ?? ''}
|
||||
value={customInstructions ?? ""}
|
||||
onChange={(e) => {
|
||||
const value = (e as CustomEvent)?.detail?.target?.value || ((e as any).target as HTMLTextAreaElement).value
|
||||
const value =
|
||||
(e as CustomEvent)?.detail?.target?.value ||
|
||||
((e as any).target as HTMLTextAreaElement).value
|
||||
setCustomInstructions(value || undefined)
|
||||
vscode.postMessage({
|
||||
type: "customInstructions",
|
||||
text: value.trim() || undefined
|
||||
text: value.trim() || undefined,
|
||||
})
|
||||
}}
|
||||
rows={4}
|
||||
@@ -168,32 +170,38 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
data-testid="global-custom-instructions-textarea"
|
||||
/>
|
||||
<div style={{ fontSize: "12px", color: "var(--vscode-descriptionForeground)", marginTop: "5px" }}>
|
||||
Instructions can also be loaded from <span
|
||||
Instructions can also be loaded from{" "}
|
||||
<span
|
||||
style={{
|
||||
color: 'var(--vscode-textLink-foreground)',
|
||||
cursor: 'pointer',
|
||||
textDecoration: 'underline'
|
||||
color: "var(--vscode-textLink-foreground)",
|
||||
cursor: "pointer",
|
||||
textDecoration: "underline",
|
||||
}}
|
||||
onClick={() => vscode.postMessage({
|
||||
type: "openFile",
|
||||
text: "./.clinerules",
|
||||
values: {
|
||||
create: true,
|
||||
content: "",
|
||||
}
|
||||
})}
|
||||
>.clinerules</span> in your workspace.
|
||||
onClick={() =>
|
||||
vscode.postMessage({
|
||||
type: "openFile",
|
||||
text: "./.clinerules",
|
||||
values: {
|
||||
create: true,
|
||||
content: "",
|
||||
},
|
||||
})
|
||||
}>
|
||||
.clinerules
|
||||
</span>{" "}
|
||||
in your workspace.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 style={{ color: "var(--vscode-foreground)", margin: "0 0 20px 0" }}>Mode-Specific Prompts</h3>
|
||||
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
gap: '16px',
|
||||
alignItems: 'center',
|
||||
marginBottom: '12px'
|
||||
}}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: "16px",
|
||||
alignItems: "center",
|
||||
marginBottom: "12px",
|
||||
}}>
|
||||
{AGENT_MODES.map((tab) => (
|
||||
<button
|
||||
key={tab.id}
|
||||
@@ -201,42 +209,50 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
data-active={activeTab === tab.id ? "true" : "false"}
|
||||
onClick={() => setActiveTab(tab.id)}
|
||||
style={{
|
||||
padding: '4px 8px',
|
||||
border: 'none',
|
||||
background: activeTab === tab.id ? 'var(--vscode-button-background)' : 'none',
|
||||
color: activeTab === tab.id ? 'var(--vscode-button-foreground)' : 'var(--vscode-foreground)',
|
||||
cursor: 'pointer',
|
||||
padding: "4px 8px",
|
||||
border: "none",
|
||||
background: activeTab === tab.id ? "var(--vscode-button-background)" : "none",
|
||||
color:
|
||||
activeTab === tab.id
|
||||
? "var(--vscode-button-foreground)"
|
||||
: "var(--vscode-foreground)",
|
||||
cursor: "pointer",
|
||||
opacity: activeTab === tab.id ? 1 : 0.8,
|
||||
borderRadius: '3px',
|
||||
fontWeight: 'bold'
|
||||
}}
|
||||
>
|
||||
borderRadius: "3px",
|
||||
fontWeight: "bold",
|
||||
}}>
|
||||
{tab.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '20px' }}>
|
||||
<div style={{ marginBottom: '8px' }}>
|
||||
<div style={{ marginBottom: "20px" }}>
|
||||
<div style={{ marginBottom: "8px" }}>
|
||||
<div>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: "4px"
|
||||
}}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: "4px",
|
||||
}}>
|
||||
<div style={{ fontWeight: "bold" }}>Role Definition</div>
|
||||
<VSCodeButton
|
||||
appearance="icon"
|
||||
onClick={() => handleAgentReset(activeTab)}
|
||||
data-testid="reset-prompt-button"
|
||||
title="Revert to default"
|
||||
>
|
||||
title="Revert to default">
|
||||
<span className="codicon codicon-discard"></span>
|
||||
</VSCodeButton>
|
||||
</div>
|
||||
<div style={{ fontSize: "13px", color: "var(--vscode-descriptionForeground)", marginBottom: "8px" }}>
|
||||
Define Cline's expertise and personality for this mode. This description shapes how Cline presents itself and approaches tasks.
|
||||
<div
|
||||
style={{
|
||||
fontSize: "13px",
|
||||
color: "var(--vscode-descriptionForeground)",
|
||||
marginBottom: "8px",
|
||||
}}>
|
||||
Define Cline's expertise and personality for this mode. This description shapes how
|
||||
Cline presents itself and approaches tasks.
|
||||
</div>
|
||||
</div>
|
||||
<VSCodeTextArea
|
||||
@@ -248,22 +264,30 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
data-testid={`${activeTab}-prompt-textarea`}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ marginBottom: '8px' }}>
|
||||
<div style={{ marginBottom: "8px" }}>
|
||||
<div style={{ fontWeight: "bold", marginBottom: "4px" }}>Mode-specific Custom Instructions</div>
|
||||
<div style={{ fontSize: "13px", color: "var(--vscode-descriptionForeground)", marginBottom: "8px" }}>
|
||||
Add behavioral guidelines specific to {activeTab} mode. These instructions enhance the base behaviors defined above.
|
||||
<div
|
||||
style={{
|
||||
fontSize: "13px",
|
||||
color: "var(--vscode-descriptionForeground)",
|
||||
marginBottom: "8px",
|
||||
}}>
|
||||
Add behavioral guidelines specific to {activeTab} mode. These instructions enhance the base
|
||||
behaviors defined above.
|
||||
</div>
|
||||
<VSCodeTextArea
|
||||
value={(() => {
|
||||
const prompt = customPrompts?.[activeTab]
|
||||
return typeof prompt === 'object' ? prompt.customInstructions ?? '' : ''
|
||||
return typeof prompt === "object" ? (prompt.customInstructions ?? "") : ""
|
||||
})()}
|
||||
onChange={(e) => {
|
||||
const value = (e as CustomEvent)?.detail?.target?.value || ((e as any).target as HTMLTextAreaElement).value
|
||||
const value =
|
||||
(e as CustomEvent)?.detail?.target?.value ||
|
||||
((e as any).target as HTMLTextAreaElement).value
|
||||
const existingPrompt = customPrompts?.[activeTab]
|
||||
updateAgentPrompt(activeTab, {
|
||||
...(typeof existingPrompt === 'object' ? existingPrompt : {}),
|
||||
customInstructions: value.trim() || undefined
|
||||
...(typeof existingPrompt === "object" ? existingPrompt : {}),
|
||||
customInstructions: value.trim() || undefined,
|
||||
})
|
||||
}}
|
||||
rows={4}
|
||||
@@ -271,25 +295,34 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
style={{ width: "100%" }}
|
||||
data-testid={`${activeTab}-custom-instructions-textarea`}
|
||||
/>
|
||||
<div style={{ fontSize: "12px", color: "var(--vscode-descriptionForeground)", marginTop: "5px" }}>
|
||||
Custom instructions specific to {activeTab} mode can also be loaded from <span
|
||||
<div
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
color: "var(--vscode-descriptionForeground)",
|
||||
marginTop: "5px",
|
||||
}}>
|
||||
Custom instructions specific to {activeTab} mode can also be loaded from{" "}
|
||||
<span
|
||||
style={{
|
||||
color: 'var(--vscode-textLink-foreground)',
|
||||
cursor: 'pointer',
|
||||
textDecoration: 'underline'
|
||||
color: "var(--vscode-textLink-foreground)",
|
||||
cursor: "pointer",
|
||||
textDecoration: "underline",
|
||||
}}
|
||||
onClick={() => {
|
||||
// First create/update the file with current custom instructions
|
||||
const defaultContent = `# ${activeTab} Mode Rules\n\nAdd mode-specific rules and guidelines here.`
|
||||
const existingPrompt = customPrompts?.[activeTab]
|
||||
const existingInstructions = typeof existingPrompt === 'object' ? existingPrompt.customInstructions : undefined
|
||||
const existingInstructions =
|
||||
typeof existingPrompt === "object"
|
||||
? existingPrompt.customInstructions
|
||||
: undefined
|
||||
vscode.postMessage({
|
||||
type: "updatePrompt",
|
||||
promptMode: activeTab,
|
||||
customPrompt: {
|
||||
...(typeof existingPrompt === 'object' ? existingPrompt : {}),
|
||||
customInstructions: existingInstructions || defaultContent
|
||||
}
|
||||
...(typeof existingPrompt === "object" ? existingPrompt : {}),
|
||||
customInstructions: existingInstructions || defaultContent,
|
||||
},
|
||||
})
|
||||
// Then open the file
|
||||
vscode.postMessage({
|
||||
@@ -298,37 +331,40 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
values: {
|
||||
create: true,
|
||||
content: "",
|
||||
}
|
||||
},
|
||||
})
|
||||
}}
|
||||
>.clinerules-{activeTab}</span> in your workspace.
|
||||
}}>
|
||||
.clinerules-{activeTab}
|
||||
</span>{" "}
|
||||
in your workspace.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ marginBottom: '20px', display: 'flex', justifyContent: 'flex-start' }}>
|
||||
<div style={{ marginBottom: "20px", display: "flex", justifyContent: "flex-start" }}>
|
||||
<VSCodeButton
|
||||
appearance="primary"
|
||||
onClick={() => {
|
||||
vscode.postMessage({
|
||||
type: "getSystemPrompt",
|
||||
mode: activeTab
|
||||
mode: activeTab,
|
||||
})
|
||||
}}
|
||||
data-testid="preview-prompt-button"
|
||||
>
|
||||
data-testid="preview-prompt-button">
|
||||
Preview System Prompt
|
||||
</VSCodeButton>
|
||||
</div>
|
||||
|
||||
<h3 style={{ color: "var(--vscode-foreground)", margin: "40px 0 20px 0" }}>Prompt Enhancement</h3>
|
||||
|
||||
<div style={{
|
||||
color: "var(--vscode-foreground)",
|
||||
fontSize: "13px",
|
||||
marginBottom: "20px",
|
||||
marginTop: "5px",
|
||||
}}>
|
||||
Use prompt enhancement to get tailored suggestions or improvements for your inputs. This ensures Cline understands your intent and provides the best possible responses.
|
||||
<div
|
||||
style={{
|
||||
color: "var(--vscode-foreground)",
|
||||
fontSize: "13px",
|
||||
marginBottom: "20px",
|
||||
marginTop: "5px",
|
||||
}}>
|
||||
Use prompt enhancement to get tailored suggestions or improvements for your inputs. This ensures
|
||||
Cline understands your intent and provides the best possible responses.
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: "20px" }}>
|
||||
@@ -337,22 +373,22 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
<div style={{ marginBottom: "8px" }}>
|
||||
<div style={{ fontWeight: "bold", marginBottom: "4px" }}>API Configuration</div>
|
||||
<div style={{ fontSize: "13px", color: "var(--vscode-descriptionForeground)" }}>
|
||||
You can select an API configuration to always use for enhancing prompts, or just use whatever is currently selected
|
||||
You can select an API configuration to always use for enhancing prompts, or just use
|
||||
whatever is currently selected
|
||||
</div>
|
||||
</div>
|
||||
<VSCodeDropdown
|
||||
value={enhancementApiConfigId || ''}
|
||||
value={enhancementApiConfigId || ""}
|
||||
data-testid="api-config-dropdown"
|
||||
onChange={(e: any) => {
|
||||
const value = e.detail?.target?.value || e.target?.value
|
||||
setEnhancementApiConfigId(value)
|
||||
vscode.postMessage({
|
||||
type: "enhancementApiConfigId",
|
||||
text: value
|
||||
text: value,
|
||||
})
|
||||
}}
|
||||
style={{ width: "300px" }}
|
||||
>
|
||||
style={{ width: "300px" }}>
|
||||
<VSCodeOption value="">Use currently selected API configuration</VSCodeOption>
|
||||
{(listApiConfigMeta || []).map((config) => (
|
||||
<VSCodeOption key={config.id} value={config.id}>
|
||||
@@ -363,15 +399,29 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: "8px" }}>
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "4px" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: "4px",
|
||||
}}>
|
||||
<div style={{ fontWeight: "bold" }}>Enhancement Prompt</div>
|
||||
<div style={{ display: "flex", gap: "8px" }}>
|
||||
<VSCodeButton appearance="icon" onClick={handleEnhanceReset} title="Revert to default">
|
||||
<VSCodeButton
|
||||
appearance="icon"
|
||||
onClick={handleEnhanceReset}
|
||||
title="Revert to default">
|
||||
<span className="codicon codicon-discard"></span>
|
||||
</VSCodeButton>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ fontSize: "13px", color: "var(--vscode-descriptionForeground)", marginBottom: "8px" }}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "13px",
|
||||
color: "var(--vscode-descriptionForeground)",
|
||||
marginBottom: "8px",
|
||||
}}>
|
||||
This prompt will be used to refine your input when you hit the sparkle icon in chat.
|
||||
</div>
|
||||
</div>
|
||||
@@ -382,7 +432,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
resize="vertical"
|
||||
style={{ width: "100%" }}
|
||||
/>
|
||||
|
||||
|
||||
<div style={{ marginTop: "12px" }}>
|
||||
<VSCodeTextArea
|
||||
value={testPrompt}
|
||||
@@ -393,18 +443,18 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
style={{ width: "100%" }}
|
||||
data-testid="test-prompt-textarea"
|
||||
/>
|
||||
<div style={{
|
||||
marginTop: "8px",
|
||||
display: "flex",
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "center",
|
||||
gap: 8
|
||||
}}>
|
||||
<div
|
||||
style={{
|
||||
marginTop: "8px",
|
||||
display: "flex",
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "center",
|
||||
gap: 8,
|
||||
}}>
|
||||
<VSCodeButton
|
||||
onClick={handleTestEnhancement}
|
||||
disabled={isEnhancing}
|
||||
appearance="primary"
|
||||
>
|
||||
appearance="primary">
|
||||
Preview Prompt Enhancement
|
||||
</VSCodeButton>
|
||||
</div>
|
||||
@@ -417,66 +467,68 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
</div>
|
||||
|
||||
{isDialogOpen && (
|
||||
<div style={{
|
||||
position: 'fixed',
|
||||
inset: 0,
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||
zIndex: 1000
|
||||
}}>
|
||||
<div style={{
|
||||
width: 'calc(100vw - 100px)',
|
||||
height: '100%',
|
||||
backgroundColor: 'var(--vscode-editor-background)',
|
||||
boxShadow: '-2px 0 5px rgba(0, 0, 0, 0.2)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
position: 'relative'
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
inset: 0,
|
||||
display: "flex",
|
||||
justifyContent: "flex-end",
|
||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
zIndex: 1000,
|
||||
}}>
|
||||
<div style={{
|
||||
flex: 1,
|
||||
padding: '20px',
|
||||
overflowY: 'auto',
|
||||
minHeight: 0
|
||||
<div
|
||||
style={{
|
||||
width: "calc(100vw - 100px)",
|
||||
height: "100%",
|
||||
backgroundColor: "var(--vscode-editor-background)",
|
||||
boxShadow: "-2px 0 5px rgba(0, 0, 0, 0.2)",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
position: "relative",
|
||||
}}>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
padding: "20px",
|
||||
overflowY: "auto",
|
||||
minHeight: 0,
|
||||
}}>
|
||||
<VSCodeButton
|
||||
appearance="icon"
|
||||
onClick={() => setIsDialogOpen(false)}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: '20px',
|
||||
right: '20px'
|
||||
}}
|
||||
>
|
||||
position: "absolute",
|
||||
top: "20px",
|
||||
right: "20px",
|
||||
}}>
|
||||
<span className="codicon codicon-close"></span>
|
||||
</VSCodeButton>
|
||||
<h2 style={{ margin: '0 0 16px' }}>{selectedPromptTitle}</h2>
|
||||
<pre style={{
|
||||
padding: '8px',
|
||||
whiteSpace: 'pre-wrap',
|
||||
wordBreak: 'break-word',
|
||||
fontFamily: 'var(--vscode-editor-font-family)',
|
||||
fontSize: 'var(--vscode-editor-font-size)',
|
||||
color: 'var(--vscode-editor-foreground)',
|
||||
backgroundColor: 'var(--vscode-editor-background)',
|
||||
border: '1px solid var(--vscode-editor-lineHighlightBorder)',
|
||||
borderRadius: '4px',
|
||||
overflowY: 'auto'
|
||||
}}>
|
||||
<h2 style={{ margin: "0 0 16px" }}>{selectedPromptTitle}</h2>
|
||||
<pre
|
||||
style={{
|
||||
padding: "8px",
|
||||
whiteSpace: "pre-wrap",
|
||||
wordBreak: "break-word",
|
||||
fontFamily: "var(--vscode-editor-font-family)",
|
||||
fontSize: "var(--vscode-editor-font-size)",
|
||||
color: "var(--vscode-editor-foreground)",
|
||||
backgroundColor: "var(--vscode-editor-background)",
|
||||
border: "1px solid var(--vscode-editor-lineHighlightBorder)",
|
||||
borderRadius: "4px",
|
||||
overflowY: "auto",
|
||||
}}>
|
||||
{selectedPromptContent}
|
||||
</pre>
|
||||
</div>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
padding: '12px 20px',
|
||||
borderTop: '1px solid var(--vscode-editor-lineHighlightBorder)',
|
||||
backgroundColor: 'var(--vscode-editor-background)'
|
||||
}}>
|
||||
<VSCodeButton onClick={() => setIsDialogOpen(false)}>
|
||||
Close
|
||||
</VSCodeButton>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "flex-end",
|
||||
padding: "12px 20px",
|
||||
borderTop: "1px solid var(--vscode-editor-lineHighlightBorder)",
|
||||
backgroundColor: "var(--vscode-editor-background)",
|
||||
}}>
|
||||
<VSCodeButton onClick={() => setIsDialogOpen(false)}>Close</VSCodeButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -485,4 +537,4 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
|
||||
)
|
||||
}
|
||||
|
||||
export default PromptsView
|
||||
export default PromptsView
|
||||
|
||||
@@ -1,160 +1,166 @@
|
||||
import { render, screen, fireEvent } from '@testing-library/react'
|
||||
import '@testing-library/jest-dom'
|
||||
import PromptsView from '../PromptsView'
|
||||
import { ExtensionStateContext } from '../../../context/ExtensionStateContext'
|
||||
import { vscode } from '../../../utils/vscode'
|
||||
import { render, screen, fireEvent } from "@testing-library/react"
|
||||
import "@testing-library/jest-dom"
|
||||
import PromptsView from "../PromptsView"
|
||||
import { ExtensionStateContext } from "../../../context/ExtensionStateContext"
|
||||
import { vscode } from "../../../utils/vscode"
|
||||
|
||||
// Mock vscode API
|
||||
jest.mock('../../../utils/vscode', () => ({
|
||||
vscode: {
|
||||
postMessage: jest.fn()
|
||||
}
|
||||
jest.mock("../../../utils/vscode", () => ({
|
||||
vscode: {
|
||||
postMessage: jest.fn(),
|
||||
},
|
||||
}))
|
||||
|
||||
const mockExtensionState = {
|
||||
customPrompts: {},
|
||||
listApiConfigMeta: [
|
||||
{ id: 'config1', name: 'Config 1' },
|
||||
{ id: 'config2', name: 'Config 2' }
|
||||
],
|
||||
enhancementApiConfigId: '',
|
||||
setEnhancementApiConfigId: jest.fn(),
|
||||
mode: 'code',
|
||||
customInstructions: 'Initial instructions',
|
||||
setCustomInstructions: jest.fn()
|
||||
customPrompts: {},
|
||||
listApiConfigMeta: [
|
||||
{ id: "config1", name: "Config 1" },
|
||||
{ id: "config2", name: "Config 2" },
|
||||
],
|
||||
enhancementApiConfigId: "",
|
||||
setEnhancementApiConfigId: jest.fn(),
|
||||
mode: "code",
|
||||
customInstructions: "Initial instructions",
|
||||
setCustomInstructions: jest.fn(),
|
||||
}
|
||||
|
||||
const renderPromptsView = (props = {}) => {
|
||||
const mockOnDone = jest.fn()
|
||||
return render(
|
||||
<ExtensionStateContext.Provider value={{ ...mockExtensionState, ...props } as any}>
|
||||
<PromptsView onDone={mockOnDone} />
|
||||
</ExtensionStateContext.Provider>
|
||||
)
|
||||
const mockOnDone = jest.fn()
|
||||
return render(
|
||||
<ExtensionStateContext.Provider value={{ ...mockExtensionState, ...props } as any}>
|
||||
<PromptsView onDone={mockOnDone} />
|
||||
</ExtensionStateContext.Provider>,
|
||||
)
|
||||
}
|
||||
|
||||
describe('PromptsView', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
describe("PromptsView", () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it('renders all mode tabs', () => {
|
||||
renderPromptsView()
|
||||
expect(screen.getByTestId('code-tab')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('ask-tab')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('architect-tab')).toBeInTheDocument()
|
||||
})
|
||||
it("renders all mode tabs", () => {
|
||||
renderPromptsView()
|
||||
expect(screen.getByTestId("code-tab")).toBeInTheDocument()
|
||||
expect(screen.getByTestId("ask-tab")).toBeInTheDocument()
|
||||
expect(screen.getByTestId("architect-tab")).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('defaults to current mode as active tab', () => {
|
||||
renderPromptsView({ mode: 'ask' })
|
||||
|
||||
const codeTab = screen.getByTestId('code-tab')
|
||||
const askTab = screen.getByTestId('ask-tab')
|
||||
const architectTab = screen.getByTestId('architect-tab')
|
||||
|
||||
expect(askTab).toHaveAttribute('data-active', 'true')
|
||||
expect(codeTab).toHaveAttribute('data-active', 'false')
|
||||
expect(architectTab).toHaveAttribute('data-active', 'false')
|
||||
})
|
||||
it("defaults to current mode as active tab", () => {
|
||||
renderPromptsView({ mode: "ask" })
|
||||
|
||||
it('switches between tabs correctly', () => {
|
||||
renderPromptsView({ mode: 'code' })
|
||||
|
||||
const codeTab = screen.getByTestId('code-tab')
|
||||
const askTab = screen.getByTestId('ask-tab')
|
||||
const architectTab = screen.getByTestId('architect-tab')
|
||||
|
||||
// Initial state matches current mode (code)
|
||||
expect(codeTab).toHaveAttribute('data-active', 'true')
|
||||
expect(askTab).toHaveAttribute('data-active', 'false')
|
||||
expect(architectTab).toHaveAttribute('data-active', 'false')
|
||||
expect(architectTab).toHaveAttribute('data-active', 'false')
|
||||
|
||||
// Click Ask tab
|
||||
fireEvent.click(askTab)
|
||||
expect(askTab).toHaveAttribute('data-active', 'true')
|
||||
expect(codeTab).toHaveAttribute('data-active', 'false')
|
||||
expect(architectTab).toHaveAttribute('data-active', 'false')
|
||||
|
||||
// Click Architect tab
|
||||
fireEvent.click(architectTab)
|
||||
expect(architectTab).toHaveAttribute('data-active', 'true')
|
||||
expect(askTab).toHaveAttribute('data-active', 'false')
|
||||
expect(codeTab).toHaveAttribute('data-active', 'false')
|
||||
})
|
||||
const codeTab = screen.getByTestId("code-tab")
|
||||
const askTab = screen.getByTestId("ask-tab")
|
||||
const architectTab = screen.getByTestId("architect-tab")
|
||||
|
||||
it('handles prompt changes correctly', () => {
|
||||
renderPromptsView()
|
||||
|
||||
const textarea = screen.getByTestId('code-prompt-textarea')
|
||||
fireEvent(textarea, new CustomEvent('change', {
|
||||
detail: {
|
||||
target: {
|
||||
value: 'New prompt value'
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||
type: 'updatePrompt',
|
||||
promptMode: 'code',
|
||||
customPrompt: { roleDefinition: 'New prompt value' }
|
||||
})
|
||||
})
|
||||
expect(askTab).toHaveAttribute("data-active", "true")
|
||||
expect(codeTab).toHaveAttribute("data-active", "false")
|
||||
expect(architectTab).toHaveAttribute("data-active", "false")
|
||||
})
|
||||
|
||||
it('resets prompt to default value', () => {
|
||||
renderPromptsView()
|
||||
|
||||
const resetButton = screen.getByTestId('reset-prompt-button')
|
||||
fireEvent.click(resetButton)
|
||||
|
||||
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||
type: 'updatePrompt',
|
||||
promptMode: 'code',
|
||||
customPrompt: { roleDefinition: undefined }
|
||||
})
|
||||
})
|
||||
it("switches between tabs correctly", () => {
|
||||
renderPromptsView({ mode: "code" })
|
||||
|
||||
it('handles API configuration selection', () => {
|
||||
renderPromptsView()
|
||||
|
||||
const dropdown = screen.getByTestId('api-config-dropdown')
|
||||
fireEvent(dropdown, new CustomEvent('change', {
|
||||
detail: {
|
||||
target: {
|
||||
value: 'config1'
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
expect(mockExtensionState.setEnhancementApiConfigId).toHaveBeenCalledWith('config1')
|
||||
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||
type: 'enhancementApiConfigId',
|
||||
text: 'config1'
|
||||
})
|
||||
})
|
||||
const codeTab = screen.getByTestId("code-tab")
|
||||
const askTab = screen.getByTestId("ask-tab")
|
||||
const architectTab = screen.getByTestId("architect-tab")
|
||||
|
||||
it('handles clearing custom instructions correctly', async () => {
|
||||
const setCustomInstructions = jest.fn()
|
||||
renderPromptsView({
|
||||
...mockExtensionState,
|
||||
customInstructions: 'Initial instructions',
|
||||
setCustomInstructions
|
||||
})
|
||||
// Initial state matches current mode (code)
|
||||
expect(codeTab).toHaveAttribute("data-active", "true")
|
||||
expect(askTab).toHaveAttribute("data-active", "false")
|
||||
expect(architectTab).toHaveAttribute("data-active", "false")
|
||||
expect(architectTab).toHaveAttribute("data-active", "false")
|
||||
|
||||
const textarea = screen.getByTestId('global-custom-instructions-textarea')
|
||||
const changeEvent = new CustomEvent('change', {
|
||||
detail: { target: { value: '' } }
|
||||
})
|
||||
Object.defineProperty(changeEvent, 'target', {
|
||||
value: { value: '' }
|
||||
})
|
||||
await fireEvent(textarea, changeEvent)
|
||||
// Click Ask tab
|
||||
fireEvent.click(askTab)
|
||||
expect(askTab).toHaveAttribute("data-active", "true")
|
||||
expect(codeTab).toHaveAttribute("data-active", "false")
|
||||
expect(architectTab).toHaveAttribute("data-active", "false")
|
||||
|
||||
expect(setCustomInstructions).toHaveBeenCalledWith(undefined)
|
||||
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||
type: 'customInstructions',
|
||||
text: undefined
|
||||
})
|
||||
})
|
||||
})
|
||||
// Click Architect tab
|
||||
fireEvent.click(architectTab)
|
||||
expect(architectTab).toHaveAttribute("data-active", "true")
|
||||
expect(askTab).toHaveAttribute("data-active", "false")
|
||||
expect(codeTab).toHaveAttribute("data-active", "false")
|
||||
})
|
||||
|
||||
it("handles prompt changes correctly", () => {
|
||||
renderPromptsView()
|
||||
|
||||
const textarea = screen.getByTestId("code-prompt-textarea")
|
||||
fireEvent(
|
||||
textarea,
|
||||
new CustomEvent("change", {
|
||||
detail: {
|
||||
target: {
|
||||
value: "New prompt value",
|
||||
},
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||
type: "updatePrompt",
|
||||
promptMode: "code",
|
||||
customPrompt: { roleDefinition: "New prompt value" },
|
||||
})
|
||||
})
|
||||
|
||||
it("resets prompt to default value", () => {
|
||||
renderPromptsView()
|
||||
|
||||
const resetButton = screen.getByTestId("reset-prompt-button")
|
||||
fireEvent.click(resetButton)
|
||||
|
||||
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||
type: "updatePrompt",
|
||||
promptMode: "code",
|
||||
customPrompt: { roleDefinition: undefined },
|
||||
})
|
||||
})
|
||||
|
||||
it("handles API configuration selection", () => {
|
||||
renderPromptsView()
|
||||
|
||||
const dropdown = screen.getByTestId("api-config-dropdown")
|
||||
fireEvent(
|
||||
dropdown,
|
||||
new CustomEvent("change", {
|
||||
detail: {
|
||||
target: {
|
||||
value: "config1",
|
||||
},
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
expect(mockExtensionState.setEnhancementApiConfigId).toHaveBeenCalledWith("config1")
|
||||
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||
type: "enhancementApiConfigId",
|
||||
text: "config1",
|
||||
})
|
||||
})
|
||||
|
||||
it("handles clearing custom instructions correctly", async () => {
|
||||
const setCustomInstructions = jest.fn()
|
||||
renderPromptsView({
|
||||
...mockExtensionState,
|
||||
customInstructions: "Initial instructions",
|
||||
setCustomInstructions,
|
||||
})
|
||||
|
||||
const textarea = screen.getByTestId("global-custom-instructions-textarea")
|
||||
const changeEvent = new CustomEvent("change", {
|
||||
detail: { target: { value: "" } },
|
||||
})
|
||||
Object.defineProperty(changeEvent, "target", {
|
||||
value: { value: "" },
|
||||
})
|
||||
await fireEvent(textarea, changeEvent)
|
||||
|
||||
expect(setCustomInstructions).toHaveBeenCalledWith(undefined)
|
||||
expect(vscode.postMessage).toHaveBeenCalledWith({
|
||||
type: "customInstructions",
|
||||
text: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user