mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
feat: complete desktop notification system UI integration
- Add desktop notification settings to NotificationSettings component - Update SettingsView to pass desktop notification props - Add desktop notification message handlers in webviewMessageHandler - Update global settings types to include desktop notification settings - Add translation keys for desktop notification UI elements - Integrate desktop notification settings into state management This completes the desktop notification system implementation with: - Cross-platform OS notifications using node-notifier - User configurable settings for different notification types - Timeout control for notification display duration - Full UI integration in VSCode extension settings panel
This commit is contained in:
parent
c2fe775757
commit
fe1d864053
8 changed files with 188 additions and 1 deletions
|
|
@ -69,6 +69,13 @@ export const globalSettingsSchema = z.object({
|
|||
soundEnabled: z.boolean().optional(),
|
||||
soundVolume: z.number().optional(),
|
||||
|
||||
// Desktop notification settings
|
||||
desktopNotificationsEnabled: z.boolean().optional(),
|
||||
desktopNotificationApprovalRequests: z.boolean().optional(),
|
||||
desktopNotificationErrors: z.boolean().optional(),
|
||||
desktopNotificationTaskCompletion: z.boolean().optional(),
|
||||
desktopNotificationTimeout: z.number().optional(),
|
||||
|
||||
maxOpenTabsContext: z.number().optional(),
|
||||
maxWorkspaceFiles: z.number().optional(),
|
||||
showRooIgnoredFiles: z.boolean().optional(),
|
||||
|
|
|
|||
|
|
@ -1407,6 +1407,7 @@ export class ClineProvider
|
|||
listApiConfigMeta,
|
||||
pinnedApiConfigs,
|
||||
mode,
|
||||
modeApiConfigs,
|
||||
customModePrompts,
|
||||
customSupportPrompts,
|
||||
enhancementApiConfigId,
|
||||
|
|
@ -1434,6 +1435,11 @@ export class ClineProvider
|
|||
profileThresholds,
|
||||
alwaysAllowFollowupQuestions,
|
||||
followupAutoApproveTimeoutMs,
|
||||
desktopNotificationsEnabled,
|
||||
desktopNotificationApprovalRequests,
|
||||
desktopNotificationErrors,
|
||||
desktopNotificationTaskCompletion,
|
||||
desktopNotificationTimeout,
|
||||
} = await this.getState()
|
||||
|
||||
const telemetryKey = process.env.POSTHOG_API_KEY
|
||||
|
|
@ -1506,6 +1512,7 @@ export class ClineProvider
|
|||
listApiConfigMeta: listApiConfigMeta ?? [],
|
||||
pinnedApiConfigs: pinnedApiConfigs ?? {},
|
||||
mode: mode ?? defaultModeSlug,
|
||||
modeApiConfigs: modeApiConfigs ?? {},
|
||||
customModePrompts: customModePrompts ?? {},
|
||||
customSupportPrompts: customSupportPrompts ?? {},
|
||||
enhancementApiConfigId,
|
||||
|
|
@ -1553,6 +1560,12 @@ export class ClineProvider
|
|||
hasOpenedModeSelector: this.getGlobalState("hasOpenedModeSelector") ?? false,
|
||||
alwaysAllowFollowupQuestions: alwaysAllowFollowupQuestions ?? false,
|
||||
followupAutoApproveTimeoutMs: followupAutoApproveTimeoutMs ?? 60000,
|
||||
// Desktop notification settings
|
||||
desktopNotificationsEnabled: desktopNotificationsEnabled ?? false,
|
||||
desktopNotificationApprovalRequests: desktopNotificationApprovalRequests ?? true,
|
||||
desktopNotificationErrors: desktopNotificationErrors ?? true,
|
||||
desktopNotificationTaskCompletion: desktopNotificationTaskCompletion ?? true,
|
||||
desktopNotificationTimeout: desktopNotificationTimeout ?? 10000,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1715,6 +1728,12 @@ export class ClineProvider
|
|||
codebaseIndexSearchMinScore: stateValues.codebaseIndexConfig?.codebaseIndexSearchMinScore,
|
||||
},
|
||||
profileThresholds: stateValues.profileThresholds ?? {},
|
||||
// Desktop notification settings
|
||||
desktopNotificationsEnabled: stateValues.desktopNotificationsEnabled ?? false,
|
||||
desktopNotificationApprovalRequests: stateValues.desktopNotificationApprovalRequests ?? true,
|
||||
desktopNotificationErrors: stateValues.desktopNotificationErrors ?? true,
|
||||
desktopNotificationTaskCompletion: stateValues.desktopNotificationTaskCompletion ?? true,
|
||||
desktopNotificationTimeout: stateValues.desktopNotificationTimeout ?? 10000,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -964,6 +964,26 @@ export const webviewMessageHandler = async (
|
|||
case "stopTts":
|
||||
stopTts()
|
||||
break
|
||||
case "desktopNotificationsEnabled":
|
||||
await updateGlobalState("desktopNotificationsEnabled", message.bool ?? true)
|
||||
await provider.postStateToWebview()
|
||||
break
|
||||
case "desktopNotificationApprovalRequests":
|
||||
await updateGlobalState("desktopNotificationApprovalRequests", message.bool ?? true)
|
||||
await provider.postStateToWebview()
|
||||
break
|
||||
case "desktopNotificationErrors":
|
||||
await updateGlobalState("desktopNotificationErrors", message.bool ?? true)
|
||||
await provider.postStateToWebview()
|
||||
break
|
||||
case "desktopNotificationTaskCompletion":
|
||||
await updateGlobalState("desktopNotificationTaskCompletion", message.bool ?? true)
|
||||
await provider.postStateToWebview()
|
||||
break
|
||||
case "desktopNotificationTimeout":
|
||||
await updateGlobalState("desktopNotificationTimeout", message.value ?? 10000)
|
||||
await provider.postStateToWebview()
|
||||
break
|
||||
case "diffEnabled":
|
||||
const diffEnabled = message.bool ?? true
|
||||
await updateGlobalState("diffEnabled", diffEnabled)
|
||||
|
|
|
|||
|
|
@ -195,6 +195,11 @@ export type ExtensionState = Pick<
|
|||
| "ttsSpeed"
|
||||
| "soundEnabled"
|
||||
| "soundVolume"
|
||||
| "desktopNotificationsEnabled"
|
||||
| "desktopNotificationApprovalRequests"
|
||||
| "desktopNotificationErrors"
|
||||
| "desktopNotificationTaskCompletion"
|
||||
| "desktopNotificationTimeout"
|
||||
// | "maxOpenTabsContext" // Optional in GlobalSettings, required here.
|
||||
// | "maxWorkspaceFiles" // Optional in GlobalSettings, required here.
|
||||
// | "showRooIgnoredFiles" // Optional in GlobalSettings, required here.
|
||||
|
|
|
|||
|
|
@ -92,6 +92,14 @@ export interface WebviewMessage {
|
|||
| "ttsEnabled"
|
||||
| "ttsSpeed"
|
||||
| "soundVolume"
|
||||
| "desktopNotificationsEnabled"
|
||||
| "desktopNotificationApprovalRequests"
|
||||
| "desktopNotificationErrors"
|
||||
| "desktopNotificationTaskCompletion"
|
||||
| "desktopNotificationUserInputRequired"
|
||||
| "desktopNotificationSessionTimeouts"
|
||||
| "desktopNotificationTimeout"
|
||||
| "desktopNotificationSound"
|
||||
| "diffEnabled"
|
||||
| "enableCheckpoints"
|
||||
| "browserViewportSize"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,23 @@ type NotificationSettingsProps = HTMLAttributes<HTMLDivElement> & {
|
|||
ttsSpeed?: number
|
||||
soundEnabled?: boolean
|
||||
soundVolume?: number
|
||||
setCachedStateField: SetCachedStateField<"ttsEnabled" | "ttsSpeed" | "soundEnabled" | "soundVolume">
|
||||
// Desktop notification settings
|
||||
desktopNotificationsEnabled?: boolean
|
||||
desktopNotificationApprovalRequests?: boolean
|
||||
desktopNotificationErrors?: boolean
|
||||
desktopNotificationTaskCompletion?: boolean
|
||||
desktopNotificationTimeout?: number
|
||||
setCachedStateField: SetCachedStateField<
|
||||
| "ttsEnabled"
|
||||
| "ttsSpeed"
|
||||
| "soundEnabled"
|
||||
| "soundVolume"
|
||||
| "desktopNotificationsEnabled"
|
||||
| "desktopNotificationApprovalRequests"
|
||||
| "desktopNotificationErrors"
|
||||
| "desktopNotificationTaskCompletion"
|
||||
| "desktopNotificationTimeout"
|
||||
>
|
||||
}
|
||||
|
||||
export const NotificationSettings = ({
|
||||
|
|
@ -21,6 +37,11 @@ export const NotificationSettings = ({
|
|||
ttsSpeed,
|
||||
soundEnabled,
|
||||
soundVolume,
|
||||
desktopNotificationsEnabled,
|
||||
desktopNotificationApprovalRequests,
|
||||
desktopNotificationErrors,
|
||||
desktopNotificationTaskCompletion,
|
||||
desktopNotificationTimeout,
|
||||
setCachedStateField,
|
||||
...props
|
||||
}: NotificationSettingsProps) => {
|
||||
|
|
@ -100,6 +121,78 @@ export const NotificationSettings = ({
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<VSCodeCheckbox
|
||||
checked={desktopNotificationsEnabled}
|
||||
onChange={(e: any) => setCachedStateField("desktopNotificationsEnabled", e.target.checked)}
|
||||
data-testid="desktop-notifications-enabled-checkbox">
|
||||
<span className="font-medium">{t("settings:notifications.desktop.label")}</span>
|
||||
</VSCodeCheckbox>
|
||||
<div className="text-vscode-descriptionForeground text-sm mt-1">
|
||||
{t("settings:notifications.desktop.description")}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{desktopNotificationsEnabled && (
|
||||
<div className="flex flex-col gap-3 pl-3 border-l-2 border-vscode-button-background">
|
||||
<div>
|
||||
<VSCodeCheckbox
|
||||
checked={desktopNotificationApprovalRequests}
|
||||
onChange={(e: any) => setCachedStateField("desktopNotificationApprovalRequests", e.target.checked)}
|
||||
data-testid="desktop-notification-approval-requests-checkbox">
|
||||
<span className="font-medium">{t("settings:notifications.desktop.approvalRequests.label")}</span>
|
||||
</VSCodeCheckbox>
|
||||
<div className="text-vscode-descriptionForeground text-sm mt-1">
|
||||
{t("settings:notifications.desktop.approvalRequests.description")}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<VSCodeCheckbox
|
||||
checked={desktopNotificationErrors}
|
||||
onChange={(e: any) => setCachedStateField("desktopNotificationErrors", e.target.checked)}
|
||||
data-testid="desktop-notification-errors-checkbox">
|
||||
<span className="font-medium">{t("settings:notifications.desktop.errors.label")}</span>
|
||||
</VSCodeCheckbox>
|
||||
<div className="text-vscode-descriptionForeground text-sm mt-1">
|
||||
{t("settings:notifications.desktop.errors.description")}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<VSCodeCheckbox
|
||||
checked={desktopNotificationTaskCompletion}
|
||||
onChange={(e: any) => setCachedStateField("desktopNotificationTaskCompletion", e.target.checked)}
|
||||
data-testid="desktop-notification-task-completion-checkbox">
|
||||
<span className="font-medium">{t("settings:notifications.desktop.taskCompletion.label")}</span>
|
||||
</VSCodeCheckbox>
|
||||
<div className="text-vscode-descriptionForeground text-sm mt-1">
|
||||
{t("settings:notifications.desktop.taskCompletion.description")}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block font-medium mb-1">
|
||||
{t("settings:notifications.desktop.timeout.label")}
|
||||
</label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Slider
|
||||
min={0}
|
||||
max={60}
|
||||
step={1}
|
||||
value={[Math.round((desktopNotificationTimeout ?? 10000) / 1000)]}
|
||||
onValueChange={([value]) => setCachedStateField("desktopNotificationTimeout", value * 1000)}
|
||||
data-testid="desktop-notification-timeout-slider"
|
||||
/>
|
||||
<span className="w-10">{Math.round((desktopNotificationTimeout ?? 10000) / 1000)}s</span>
|
||||
</div>
|
||||
<div className="text-vscode-descriptionForeground text-sm mt-1">
|
||||
{t("settings:notifications.desktop.timeout.description")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -176,6 +176,11 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
alwaysAllowFollowupQuestions,
|
||||
alwaysAllowUpdateTodoList,
|
||||
followupAutoApproveTimeoutMs,
|
||||
desktopNotificationsEnabled,
|
||||
desktopNotificationApprovalRequests,
|
||||
desktopNotificationErrors,
|
||||
desktopNotificationTaskCompletion,
|
||||
desktopNotificationTimeout,
|
||||
} = cachedState
|
||||
|
||||
const apiConfiguration = useMemo(() => cachedState.apiConfiguration ?? {}, [cachedState.apiConfiguration])
|
||||
|
|
@ -323,6 +328,11 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
vscode.postMessage({ type: "upsertApiConfiguration", text: currentApiConfigName, apiConfiguration })
|
||||
vscode.postMessage({ type: "telemetrySetting", text: telemetrySetting })
|
||||
vscode.postMessage({ type: "profileThresholds", values: profileThresholds })
|
||||
vscode.postMessage({ type: "desktopNotificationsEnabled", bool: desktopNotificationsEnabled })
|
||||
vscode.postMessage({ type: "desktopNotificationApprovalRequests", bool: desktopNotificationApprovalRequests })
|
||||
vscode.postMessage({ type: "desktopNotificationErrors", bool: desktopNotificationErrors })
|
||||
vscode.postMessage({ type: "desktopNotificationTaskCompletion", bool: desktopNotificationTaskCompletion })
|
||||
vscode.postMessage({ type: "desktopNotificationTimeout", value: desktopNotificationTimeout })
|
||||
setChangeDetected(false)
|
||||
}
|
||||
}
|
||||
|
|
@ -640,6 +650,11 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
ttsSpeed={ttsSpeed}
|
||||
soundEnabled={soundEnabled}
|
||||
soundVolume={soundVolume}
|
||||
desktopNotificationsEnabled={desktopNotificationsEnabled}
|
||||
desktopNotificationApprovalRequests={desktopNotificationApprovalRequests}
|
||||
desktopNotificationErrors={desktopNotificationErrors}
|
||||
desktopNotificationTaskCompletion={desktopNotificationTaskCompletion}
|
||||
desktopNotificationTimeout={desktopNotificationTimeout}
|
||||
setCachedStateField={setCachedStateField}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -426,6 +426,26 @@
|
|||
"label": "Enable text-to-speech",
|
||||
"description": "When enabled, Roo will read aloud its responses using text-to-speech.",
|
||||
"speedLabel": "Speed"
|
||||
},
|
||||
"desktop": {
|
||||
"label": "Enable desktop notifications",
|
||||
"description": "When enabled, Roo will show OS-level desktop notifications for important events.",
|
||||
"approvalRequests": {
|
||||
"label": "Show approval request notifications",
|
||||
"description": "Get notified when Roo needs approval to perform actions."
|
||||
},
|
||||
"errors": {
|
||||
"label": "Show error notifications",
|
||||
"description": "Get notified when errors occur during task execution."
|
||||
},
|
||||
"taskCompletion": {
|
||||
"label": "Show task completion notifications",
|
||||
"description": "Get notified when tasks are completed successfully."
|
||||
},
|
||||
"timeout": {
|
||||
"label": "Notification timeout",
|
||||
"description": "How long notifications stay visible (in seconds). Set to 0 for no timeout."
|
||||
}
|
||||
}
|
||||
},
|
||||
"contextManagement": {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue