Browse Source

Add a setAlwaysAllowBrowser checkbox to settings

Matt Rubens 1 year ago
parent
commit
0346fdeecb

+ 2 - 2
package-lock.json

@@ -1,12 +1,12 @@
 {
 {
   "name": "roo-cline",
   "name": "roo-cline",
-  "version": "2.0.2",
+  "version": "2.0.3",
   "lockfileVersion": 3,
   "lockfileVersion": 3,
   "requires": true,
   "requires": true,
   "packages": {
   "packages": {
     "": {
     "": {
       "name": "roo-cline",
       "name": "roo-cline",
-      "version": "2.0.2",
+      "version": "2.0.3",
       "dependencies": {
       "dependencies": {
         "@anthropic-ai/bedrock-sdk": "^0.10.2",
         "@anthropic-ai/bedrock-sdk": "^0.10.2",
         "@anthropic-ai/sdk": "^0.26.0",
         "@anthropic-ai/sdk": "^0.26.0",

+ 10 - 1
package.json

@@ -2,7 +2,7 @@
   "name": "roo-cline",
   "name": "roo-cline",
   "displayName": "Roo Cline",
   "displayName": "Roo Cline",
   "description": "Autonomous coding agent right in your IDE, capable of creating/editing files, running commands, using the browser, and more with your permission every step of the way.",
   "description": "Autonomous coding agent right in your IDE, capable of creating/editing files, running commands, using the browser, and more with your permission every step of the way.",
-  "version": "2.0.2",
+  "version": "2.0.3",
   "icon": "assets/icons/icon_Roo.png",
   "icon": "assets/icons/icon_Roo.png",
   "galleryBanner": {
   "galleryBanner": {
     "color": "#617A91",
     "color": "#617A91",
@@ -111,6 +111,15 @@
           "when": "view == claude-dev.SidebarProvider"
           "when": "view == claude-dev.SidebarProvider"
         }
         }
       ]
       ]
+    },
+    "configuration": {
+      "properties": {
+        "cline.alwaysAllowBrowser": {
+          "type": "boolean",
+          "default": false,
+          "description": "Always allow browser actions without requiring confirmation"
+        }
+      }
     }
     }
   },
   },
   "scripts": {
   "scripts": {

+ 23 - 7
src/core/Cline.ts

@@ -77,6 +77,7 @@ export class Cline {
 	alwaysAllowReadOnly: boolean
 	alwaysAllowReadOnly: boolean
 	alwaysAllowWrite: boolean
 	alwaysAllowWrite: boolean
 	alwaysAllowExecute: boolean
 	alwaysAllowExecute: boolean
+	alwaysAllowBrowser: boolean
 
 
 	apiConversationHistory: Anthropic.MessageParam[] = []
 	apiConversationHistory: Anthropic.MessageParam[] = []
 	clineMessages: ClineMessage[] = []
 	clineMessages: ClineMessage[] = []
@@ -109,6 +110,7 @@ export class Cline {
 		alwaysAllowReadOnly?: boolean,
 		alwaysAllowReadOnly?: boolean,
 		alwaysAllowWrite?: boolean,
 		alwaysAllowWrite?: boolean,
 		alwaysAllowExecute?: boolean,
 		alwaysAllowExecute?: boolean,
+		alwaysAllowBrowser?: boolean,
 		task?: string,
 		task?: string,
 		images?: string[],
 		images?: string[],
 		historyItem?: HistoryItem
 		historyItem?: HistoryItem
@@ -123,6 +125,7 @@ export class Cline {
 		this.alwaysAllowReadOnly = alwaysAllowReadOnly ?? false
 		this.alwaysAllowReadOnly = alwaysAllowReadOnly ?? false
 		this.alwaysAllowWrite = alwaysAllowWrite ?? false
 		this.alwaysAllowWrite = alwaysAllowWrite ?? false
 		this.alwaysAllowExecute = alwaysAllowExecute ?? false		
 		this.alwaysAllowExecute = alwaysAllowExecute ?? false		
+		this.alwaysAllowBrowser = alwaysAllowBrowser ?? false
 
 
 		if (historyItem) {
 		if (historyItem) {
 			this.taskId = historyItem.id
 			this.taskId = historyItem.id
@@ -869,7 +872,7 @@ export class Cline {
 					// (have to do this for partial and complete since sending content in thinking tags to markdown renderer will automatically be removed)
 					// (have to do this for partial and complete since sending content in thinking tags to markdown renderer will automatically be removed)
 					// Remove end substrings of <thinking or </thinking (below xml parsing is only for opening tags)
 					// Remove end substrings of <thinking or </thinking (below xml parsing is only for opening tags)
 					// (this is done with the xml parsing below now, but keeping here for reference)
 					// (this is done with the xml parsing below now, but keeping here for reference)
-					// content = content.replace(/<\/?t(?:h(?:i(?:n(?:k(?:i(?:n(?:g)?)?)?)?)?$/, "")
+					// content = content.replace(/<\/?t(?:h(?:i(?:n(?:k(?:i(?:n(?:g)?)?)?)?$/, "")
 					// Remove all instances of <thinking> (with optional line break after) and </thinking> (with optional line break before)
 					// Remove all instances of <thinking> (with optional line break after) and </thinking> (with optional line break before)
 					// - Needs to be separate since we dont want to remove the line break before the first tag
 					// - Needs to be separate since we dont want to remove the line break before the first tag
 					// - Needs to happen before the xml parsing below
 					// - Needs to happen before the xml parsing below
@@ -1418,11 +1421,24 @@ export class Cline {
 						try {
 						try {
 							if (block.partial) {
 							if (block.partial) {
 								if (action === "launch") {
 								if (action === "launch") {
-									await this.ask(
-										"browser_action_launch",
-										removeClosingTag("url", url),
-										block.partial
-									).catch(() => {})
+									if (this.alwaysAllowBrowser) {
+										await this.say(
+											"browser_action",
+											JSON.stringify({
+												action: action as BrowserAction,
+												coordinate: undefined,
+												text: undefined
+											} satisfies ClineSayBrowserAction),
+											undefined,
+											block.partial
+										)
+									} else {
+										await this.ask(
+											"browser_action_launch",
+											removeClosingTag("url", url),
+											block.partial
+										).catch(() => {})
+									}
 								} else {
 								} else {
 									await this.say(
 									await this.say(
 										"browser_action",
 										"browser_action",
@@ -1448,7 +1464,7 @@ export class Cline {
 										break
 										break
 									}
 									}
 									this.consecutiveMistakeCount = 0
 									this.consecutiveMistakeCount = 0
-									const didApprove = await askApproval("browser_action_launch", url)
+									const didApprove = this.alwaysAllowBrowser || await askApproval("browser_action_launch", url)
 									if (!didApprove) {
 									if (!didApprove) {
 										break
 										break
 									}
 									}

+ 8 - 0
src/core/__tests__/Cline.test.ts

@@ -239,12 +239,14 @@ describe('Cline', () => {
                 undefined, // alwaysAllowReadOnly
                 undefined, // alwaysAllowReadOnly
                 undefined, // alwaysAllowWrite
                 undefined, // alwaysAllowWrite
                 undefined, // alwaysAllowExecute
                 undefined, // alwaysAllowExecute
+                undefined, // alwaysAllowBrowser
                 'test task'
                 'test task'
             );
             );
 
 
             expect(cline.alwaysAllowReadOnly).toBe(false);
             expect(cline.alwaysAllowReadOnly).toBe(false);
             expect(cline.alwaysAllowWrite).toBe(false);
             expect(cline.alwaysAllowWrite).toBe(false);
             expect(cline.alwaysAllowExecute).toBe(false);
             expect(cline.alwaysAllowExecute).toBe(false);
+            expect(cline.alwaysAllowBrowser).toBe(false);
         });
         });
 
 
         it('should respect provided settings', () => {
         it('should respect provided settings', () => {
@@ -255,12 +257,14 @@ describe('Cline', () => {
                 true,  // alwaysAllowReadOnly
                 true,  // alwaysAllowReadOnly
                 true,  // alwaysAllowWrite
                 true,  // alwaysAllowWrite
                 true,  // alwaysAllowExecute
                 true,  // alwaysAllowExecute
+                true,  // alwaysAllowBrowser
                 'test task'
                 'test task'
             );
             );
 
 
             expect(cline.alwaysAllowReadOnly).toBe(true);
             expect(cline.alwaysAllowReadOnly).toBe(true);
             expect(cline.alwaysAllowWrite).toBe(true);
             expect(cline.alwaysAllowWrite).toBe(true);
             expect(cline.alwaysAllowExecute).toBe(true);
             expect(cline.alwaysAllowExecute).toBe(true);
+            expect(cline.alwaysAllowBrowser).toBe(true);
             expect(cline.customInstructions).toBe('custom instructions');
             expect(cline.customInstructions).toBe('custom instructions');
         });
         });
 
 
@@ -285,6 +289,7 @@ describe('Cline', () => {
                 false,
                 false,
                 false,
                 false,
                 false,
                 false,
+                false,
                 'test task'
                 'test task'
             );
             );
         });
         });
@@ -297,6 +302,7 @@ describe('Cline', () => {
                 false,
                 false,
                 true,  // alwaysAllowWrite
                 true,  // alwaysAllowWrite
                 false,
                 false,
+                false,
                 'test task'
                 'test task'
             );
             );
 
 
@@ -312,6 +318,7 @@ describe('Cline', () => {
                 false,
                 false,
                 false,  // alwaysAllowWrite
                 false,  // alwaysAllowWrite
                 false,
                 false,
+                false,
                 'test task'
                 'test task'
             );
             );
 
 
@@ -350,6 +357,7 @@ describe('Cline', () => {
                 false,      // alwaysAllowReadOnly
                 false,      // alwaysAllowReadOnly
                 false,      // alwaysAllowWrite
                 false,      // alwaysAllowWrite
                 false,      // alwaysAllowExecute
                 false,      // alwaysAllowExecute
+                false,      // alwaysAllowBrowser
                 'test task' // task
                 'test task' // task
             )
             )
 
 

+ 58 - 8
src/core/webview/ClineProvider.ts

@@ -48,6 +48,7 @@ type GlobalStateKey =
 	| "alwaysAllowReadOnly"
 	| "alwaysAllowReadOnly"
 	| "alwaysAllowWrite"
 	| "alwaysAllowWrite"
 	| "alwaysAllowExecute"
 	| "alwaysAllowExecute"
+	| "alwaysAllowBrowser"
 	| "taskHistory"
 	| "taskHistory"
 	| "openAiBaseUrl"
 	| "openAiBaseUrl"
 	| "openAiModelId"
 	| "openAiModelId"
@@ -189,14 +190,40 @@ export class ClineProvider implements vscode.WebviewViewProvider {
 	}
 	}
 
 
 	async initClineWithTask(task?: string, images?: string[]) {
 	async initClineWithTask(task?: string, images?: string[]) {
-		await this.clearTask() // ensures that an exising task doesn't exist before starting a new one, although this shouldn't be possible since user must clear task before starting a new one
-		const { apiConfiguration, customInstructions, alwaysAllowReadOnly, alwaysAllowWrite, alwaysAllowExecute } = await this.getState()
-		this.cline = new Cline(this, apiConfiguration, customInstructions, alwaysAllowReadOnly, alwaysAllowWrite, alwaysAllowExecute, task, images)
+		await this.clearTask()
+		const { 
+			apiConfiguration, 
+			customInstructions, 
+			alwaysAllowReadOnly, 
+			alwaysAllowWrite, 
+			alwaysAllowExecute,
+			alwaysAllowBrowser 
+		} = await this.getState()
+		
+		this.cline = new Cline(
+			this, 
+			apiConfiguration, 
+			customInstructions, 
+			alwaysAllowReadOnly, 
+			alwaysAllowWrite, 
+			alwaysAllowExecute,
+			alwaysAllowBrowser,
+			task, 
+			images
+		)
 	}
 	}
 
 
 	async initClineWithHistoryItem(historyItem: HistoryItem) {
 	async initClineWithHistoryItem(historyItem: HistoryItem) {
 		await this.clearTask()
 		await this.clearTask()
-		const { apiConfiguration, customInstructions, alwaysAllowReadOnly, alwaysAllowWrite, alwaysAllowExecute } = await this.getState()
+		const { 
+			apiConfiguration, 
+			customInstructions, 
+			alwaysAllowReadOnly, 
+			alwaysAllowWrite, 
+			alwaysAllowExecute,
+			alwaysAllowBrowser 
+		} = await this.getState()
+		
 		this.cline = new Cline(
 		this.cline = new Cline(
 			this,
 			this,
 			apiConfiguration,
 			apiConfiguration,
@@ -204,6 +231,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
 			alwaysAllowReadOnly,
 			alwaysAllowReadOnly,
 			alwaysAllowWrite,
 			alwaysAllowWrite,
 			alwaysAllowExecute,
 			alwaysAllowExecute,
+			alwaysAllowBrowser,
 			undefined,
 			undefined,
 			undefined,
 			undefined,
 			historyItem
 			historyItem
@@ -499,6 +527,13 @@ export class ClineProvider implements vscode.WebviewViewProvider {
 							// await this.postStateToWebview() // new Cline instance will post state when it's ready. having this here sent an empty messages array to webview leading to virtuoso having to reload the entire list
 							// await this.postStateToWebview() // new Cline instance will post state when it's ready. having this here sent an empty messages array to webview leading to virtuoso having to reload the entire list
 						}
 						}
 
 
+						break
+					case "alwaysAllowBrowser":
+						await this.updateGlobalState("alwaysAllowBrowser", message.bool ?? undefined)
+						if (this.cline) {
+							this.cline.alwaysAllowBrowser = message.bool ?? false
+						}
+						await this.postStateToWebview()
 						break
 						break
 					// Add more switch case statements here as more webview message commands
 					// Add more switch case statements here as more webview message commands
 					// are created within the webview context (i.e. inside media/main.js)
 					// are created within the webview context (i.e. inside media/main.js)
@@ -785,7 +820,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
 
 
 	async deleteTaskFromState(id: string) {
 	async deleteTaskFromState(id: string) {
 		// Remove the task from history
 		// Remove the task from history
-		const taskHistory = ((await this.getGlobalState("taskHistory")) as HistoryItem[] | undefined) || []
+		const taskHistory = ((await this.getGlobalState("taskHistory")) as HistoryItem[]) || []
 		const updatedTaskHistory = taskHistory.filter((task) => task.id !== id)
 		const updatedTaskHistory = taskHistory.filter((task) => task.id !== id)
 		await this.updateGlobalState("taskHistory", updatedTaskHistory)
 		await this.updateGlobalState("taskHistory", updatedTaskHistory)
 
 
@@ -799,8 +834,17 @@ export class ClineProvider implements vscode.WebviewViewProvider {
 	}
 	}
 
 
 	async getStateToPostToWebview() {
 	async getStateToPostToWebview() {
-		const { apiConfiguration, lastShownAnnouncementId, customInstructions, alwaysAllowReadOnly, alwaysAllowWrite, alwaysAllowExecute, taskHistory } =
-			await this.getState()
+		const { 
+			apiConfiguration, 
+			lastShownAnnouncementId, 
+			customInstructions, 
+			alwaysAllowReadOnly, 
+			alwaysAllowWrite, 
+			alwaysAllowExecute,
+			alwaysAllowBrowser, 
+			taskHistory 
+		} = await this.getState()
+		
 		return {
 		return {
 			version: this.context.extension?.packageJSON?.version ?? "",
 			version: this.context.extension?.packageJSON?.version ?? "",
 			apiConfiguration,
 			apiConfiguration,
@@ -808,9 +852,12 @@ export class ClineProvider implements vscode.WebviewViewProvider {
 			alwaysAllowReadOnly: alwaysAllowReadOnly ?? false,
 			alwaysAllowReadOnly: alwaysAllowReadOnly ?? false,
 			alwaysAllowWrite: alwaysAllowWrite ?? false,
 			alwaysAllowWrite: alwaysAllowWrite ?? false,
 			alwaysAllowExecute: alwaysAllowExecute ?? false,
 			alwaysAllowExecute: alwaysAllowExecute ?? false,
+			alwaysAllowBrowser: alwaysAllowBrowser ?? false,
 			uriScheme: vscode.env.uriScheme,
 			uriScheme: vscode.env.uriScheme,
 			clineMessages: this.cline?.clineMessages || [],
 			clineMessages: this.cline?.clineMessages || [],
-			taskHistory: (taskHistory || []).filter((item) => item.ts && item.task).sort((a, b) => b.ts - a.ts),
+			taskHistory: (taskHistory || [])
+				.filter((item) => item.ts && item.task)
+				.sort((a, b) => b.ts - a.ts),
 			shouldShowAnnouncement: lastShownAnnouncementId !== this.latestAnnouncementId,
 			shouldShowAnnouncement: lastShownAnnouncementId !== this.latestAnnouncementId,
 		}
 		}
 	}
 	}
@@ -898,6 +945,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
 			alwaysAllowWrite,
 			alwaysAllowWrite,
 			alwaysAllowExecute,
 			alwaysAllowExecute,
 			taskHistory,
 			taskHistory,
+			alwaysAllowBrowser,
 		] = await Promise.all([
 		] = await Promise.all([
 			this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>,
 			this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>,
 			this.getGlobalState("apiModelId") as Promise<string | undefined>,
 			this.getGlobalState("apiModelId") as Promise<string | undefined>,
@@ -929,6 +977,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
 			this.getGlobalState("alwaysAllowWrite") as Promise<boolean | undefined>,
 			this.getGlobalState("alwaysAllowWrite") as Promise<boolean | undefined>,
 			this.getGlobalState("alwaysAllowExecute") as Promise<boolean | undefined>,
 			this.getGlobalState("alwaysAllowExecute") as Promise<boolean | undefined>,
 			this.getGlobalState("taskHistory") as Promise<HistoryItem[] | undefined>,
 			this.getGlobalState("taskHistory") as Promise<HistoryItem[] | undefined>,
+			this.getGlobalState("alwaysAllowBrowser") as Promise<boolean | undefined>,
 		])
 		])
 
 
 		let apiProvider: ApiProvider
 		let apiProvider: ApiProvider
@@ -977,6 +1026,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
 			alwaysAllowReadOnly: alwaysAllowReadOnly ?? false,
 			alwaysAllowReadOnly: alwaysAllowReadOnly ?? false,
 			alwaysAllowWrite: alwaysAllowWrite ?? false,
 			alwaysAllowWrite: alwaysAllowWrite ?? false,
 			alwaysAllowExecute: alwaysAllowExecute ?? false,
 			alwaysAllowExecute: alwaysAllowExecute ?? false,
+			alwaysAllowBrowser: alwaysAllowBrowser ?? false,
 			taskHistory,
 			taskHistory,
 		}
 		}
 	}
 	}

+ 1 - 0
src/shared/ExtensionMessage.ts

@@ -35,6 +35,7 @@ export interface ExtensionState {
 	alwaysAllowReadOnly?: boolean
 	alwaysAllowReadOnly?: boolean
 	alwaysAllowWrite?: boolean
 	alwaysAllowWrite?: boolean
 	alwaysAllowExecute?: boolean
 	alwaysAllowExecute?: boolean
+	alwaysAllowBrowser?: boolean
 	uriScheme?: string
 	uriScheme?: string
 	clineMessages: ClineMessage[]
 	clineMessages: ClineMessage[]
 	taskHistory: HistoryItem[]
 	taskHistory: HistoryItem[]

+ 1 - 0
src/shared/WebviewMessage.ts

@@ -25,6 +25,7 @@ export interface WebviewMessage {
 		| "openMention"
 		| "openMention"
 		| "cancelTask"
 		| "cancelTask"
 		| "refreshOpenRouterModels"
 		| "refreshOpenRouterModels"
+		| "alwaysAllowBrowser"
 	text?: string
 	text?: string
 	askResponse?: ClineAskResponse
 	askResponse?: ClineAskResponse
 	apiConfiguration?: ApiConfiguration
 	apiConfiguration?: ApiConfiguration

+ 19 - 0
webview-ui/src/components/settings/SettingsView.tsx

@@ -23,6 +23,8 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
 		setAlwaysAllowWrite,
 		setAlwaysAllowWrite,
 		alwaysAllowExecute,
 		alwaysAllowExecute,
 		setAlwaysAllowExecute,
 		setAlwaysAllowExecute,
+		alwaysAllowBrowser,
+		setAlwaysAllowBrowser,
 		openRouterModels,
 		openRouterModels,
 	} = useExtensionState()
 	} = useExtensionState()
 	const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined)
 	const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined)
@@ -39,6 +41,7 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
 			vscode.postMessage({ type: "alwaysAllowReadOnly", bool: alwaysAllowReadOnly })
 			vscode.postMessage({ type: "alwaysAllowReadOnly", bool: alwaysAllowReadOnly })
 			vscode.postMessage({ type: "alwaysAllowWrite", bool: alwaysAllowWrite })
 			vscode.postMessage({ type: "alwaysAllowWrite", bool: alwaysAllowWrite })
 			vscode.postMessage({ type: "alwaysAllowExecute", bool: alwaysAllowExecute })
 			vscode.postMessage({ type: "alwaysAllowExecute", bool: alwaysAllowExecute })
+			vscode.postMessage({ type: "alwaysAllowBrowser", bool: alwaysAllowBrowser })
 			onDone()
 			onDone()
 		}
 		}
 	}
 	}
@@ -170,6 +173,22 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
 					</p>
 					</p>
 				</div>
 				</div>
 
 
+				<div style={{ marginBottom: 5 }}>
+					<VSCodeCheckbox
+						checked={alwaysAllowBrowser}
+						onChange={(e: any) => setAlwaysAllowBrowser(e.target.checked)}>
+						<span style={{ fontWeight: "500" }}>Always approve browser actions</span>
+					</VSCodeCheckbox>
+					<p
+						style={{
+							fontSize: "12px",
+							marginTop: "5px",
+							color: "var(--vscode-descriptionForeground)",
+						}}>
+						When enabled, Cline will automatically perform browser actions without requiring
+						you to click the Approve button.
+					</p>
+				</div>
 
 
 				{IS_DEV && (
 				{IS_DEV && (
 					<>
 					<>

+ 2 - 0
webview-ui/src/context/ExtensionStateContext.tsx

@@ -22,6 +22,7 @@ export interface ExtensionStateContextType extends ExtensionState {
 	setAlwaysAllowReadOnly: (value: boolean) => void
 	setAlwaysAllowReadOnly: (value: boolean) => void
 	setAlwaysAllowWrite: (value: boolean) => void
 	setAlwaysAllowWrite: (value: boolean) => void
 	setAlwaysAllowExecute: (value: boolean) => void
 	setAlwaysAllowExecute: (value: boolean) => void
+	setAlwaysAllowBrowser: (value: boolean) => void
 	setShowAnnouncement: (value: boolean) => void
 	setShowAnnouncement: (value: boolean) => void
 }
 }
 
 
@@ -118,6 +119,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
 		setAlwaysAllowReadOnly: (value) => setState((prevState) => ({ ...prevState, alwaysAllowReadOnly: value })),
 		setAlwaysAllowReadOnly: (value) => setState((prevState) => ({ ...prevState, alwaysAllowReadOnly: value })),
 		setAlwaysAllowWrite: (value) => setState((prevState) => ({ ...prevState, alwaysAllowWrite: value })),
 		setAlwaysAllowWrite: (value) => setState((prevState) => ({ ...prevState, alwaysAllowWrite: value })),
 		setAlwaysAllowExecute: (value) => setState((prevState) => ({ ...prevState, alwaysAllowExecute: value })),
 		setAlwaysAllowExecute: (value) => setState((prevState) => ({ ...prevState, alwaysAllowExecute: value })),
+		setAlwaysAllowBrowser: (value) => setState((prevState) => ({ ...prevState, alwaysAllowBrowser: value })),
 		setShowAnnouncement: (value) => setState((prevState) => ({ ...prevState, shouldShowAnnouncement: value })),
 		setShowAnnouncement: (value) => setState((prevState) => ({ ...prevState, shouldShowAnnouncement: value })),
 	}
 	}