Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apps/sim/app/api/users/me/settings/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const logger = createLogger('UserSettingsAPI')
const SettingsSchema = z.object({
theme: z.enum(['system', 'light', 'dark']).optional(),
autoConnect: z.boolean().optional(),
autoFillEnvVars: z.boolean().optional(), // DEPRECATED: kept for backwards compatibility
autoPan: z.boolean().optional(),
consoleExpandedByDefault: z.boolean().optional(),
telemetryEnabled: z.boolean().optional(),
Expand All @@ -29,13 +28,13 @@ const SettingsSchema = z.object({
showFloatingControls: z.boolean().optional(),
showTrainingControls: z.boolean().optional(),
superUserModeEnabled: z.boolean().optional(),
errorNotificationsEnabled: z.boolean().optional(),
})

// Default settings values
const defaultSettings = {
theme: 'system',
autoConnect: true,
autoFillEnvVars: true, // DEPRECATED: kept for backwards compatibility, always true
autoPan: true,
consoleExpandedByDefault: true,
telemetryEnabled: true,
Expand All @@ -44,6 +43,7 @@ const defaultSettings = {
showFloatingControls: true,
showTrainingControls: false,
superUserModeEnabled: false,
errorNotificationsEnabled: true,
}

export async function GET() {
Expand Down Expand Up @@ -72,7 +72,6 @@ export async function GET() {
data: {
theme: userSettings.theme,
autoConnect: userSettings.autoConnect,
autoFillEnvVars: userSettings.autoFillEnvVars, // DEPRECATED: kept for backwards compatibility
autoPan: userSettings.autoPan,
consoleExpandedByDefault: userSettings.consoleExpandedByDefault,
telemetryEnabled: userSettings.telemetryEnabled,
Expand All @@ -81,6 +80,7 @@ export async function GET() {
showFloatingControls: userSettings.showFloatingControls ?? true,
showTrainingControls: userSettings.showTrainingControls ?? false,
superUserModeEnabled: userSettings.superUserModeEnabled ?? true,
errorNotificationsEnabled: userSettings.errorNotificationsEnabled ?? true,
},
},
{ status: 200 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,6 @@ const WorkflowContent = React.memo(() => {
getDragStartPosition,
} = useWorkflowStore()

// (moved) resizeLoopNodesWrapper defined after hooks that provide resizeLoopNodes

// Get copilot cleanup function
const copilotCleanup = useCopilotStore((state) => state.cleanup)

Expand Down Expand Up @@ -656,7 +654,6 @@ const WorkflowContent = React.memo(() => {
data.enableTriggerMode === true

if (isTriggerBlock) {
const triggerName = TriggerUtils.getDefaultTriggerName(data.type) || 'trigger'
addNotification({
level: 'error',
message: 'Triggers cannot be placed inside loop or parallel subflows.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ const TOOLTIPS = {
'Show training controls for recording workflow edits to build copilot training datasets.',
superUserMode:
'Toggle super user mode UI. When enabled, you can see and approve pending templates. Your super user status in the database remains unchanged.',
errorNotifications:
'Show error notifications when blocks fail. When disabled, errors will only appear in the console.',
}

export function General() {
Expand Down Expand Up @@ -111,6 +113,12 @@ export function General() {
}
}

const handleErrorNotificationsChange = async (checked: boolean) => {
if (checked !== settings?.errorNotificationsEnabled && !updateSetting.isPending) {
await updateSetting.mutateAsync({ key: 'errorNotificationsEnabled', value: checked })
}
}

return (
<div className='px-6 pt-4 pb-2'>
<div className='flex flex-col gap-4'>
Expand Down Expand Up @@ -242,6 +250,36 @@ export function General() {
/>
</div>

<div className='flex items-center justify-between'>
<div className='flex items-center gap-2'>
<Label htmlFor='error-notifications' className='font-normal'>
Error notifications
</Label>
<Tooltip.Root>
<Tooltip.Trigger asChild>
<Button
variant='ghost'
size='sm'
className='h-7 p-1 text-gray-500'
aria-label='Learn more about error notifications'
disabled={updateSetting.isPending}
>
<Info className='h-5 w-5' />
</Button>
</Tooltip.Trigger>
<Tooltip.Content side='top' className='max-w-[300px] p-3'>
<p className='text-sm'>{TOOLTIPS.errorNotifications}</p>
</Tooltip.Content>
</Tooltip.Root>
</div>
<Switch
id='error-notifications'
checked={settings?.errorNotificationsEnabled ?? true}
onCheckedChange={handleErrorNotificationsChange}
disabled={updateSetting.isPending}
/>
</div>

{isTrainingEnabled && (
<div className='flex items-center justify-between'>
<div className='flex items-center gap-2'>
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/hooks/queries/general-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface GeneralSettings {
theme: 'light' | 'dark' | 'system'
telemetryEnabled: boolean
billingUsageNotificationsEnabled: boolean
errorNotificationsEnabled: boolean
}

/**
Expand All @@ -49,6 +50,7 @@ async function fetchGeneralSettings(): Promise<GeneralSettings> {
theme: data.theme || 'system',
telemetryEnabled: data.telemetryEnabled ?? true,
billingUsageNotificationsEnabled: data.billingUsageNotificationsEnabled ?? true,
errorNotificationsEnabled: data.errorNotificationsEnabled ?? true,
}
}

Expand All @@ -69,6 +71,7 @@ function syncSettingsToZustand(settings: GeneralSettings) {
theme: settings.theme,
telemetryEnabled: settings.telemetryEnabled,
isBillingUsageNotificationsEnabled: settings.billingUsageNotificationsEnabled,
isErrorNotificationsEnabled: settings.errorNotificationsEnabled,
})
}

Expand Down
1 change: 1 addition & 0 deletions apps/sim/stores/settings/general/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const initialState: General = {
theme: 'system',
telemetryEnabled: true,
isBillingUsageNotificationsEnabled: true,
isErrorNotificationsEnabled: true,
}

export const useGeneralStore = create<GeneralStore>()(
Expand Down
2 changes: 2 additions & 0 deletions apps/sim/stores/settings/general/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface General {
theme: 'system' | 'light' | 'dark'
telemetryEnabled: boolean
isBillingUsageNotificationsEnabled: boolean
isErrorNotificationsEnabled: boolean
}

export interface GeneralStore extends General {
Expand All @@ -25,4 +26,5 @@ export type UserSettings = {
superUserModeEnabled: boolean
telemetryEnabled: boolean
isBillingUsageNotificationsEnabled: boolean
errorNotificationsEnabled: boolean
}
38 changes: 22 additions & 16 deletions apps/sim/stores/terminal/console/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { redactApiKeys } from '@/lib/utils'
import type { NormalizedBlockOutput } from '@/executor/types'
import { useExecutionStore } from '@/stores/execution/store'
import { useNotificationStore } from '@/stores/notifications'
import { useGeneralStore } from '@/stores/settings/general/store'
import type { ConsoleEntry, ConsoleStore, ConsoleUpdate } from './types'

const logger = createLogger('TerminalConsoleStore')
Expand Down Expand Up @@ -102,24 +103,29 @@ export const useTerminalConsoleStore = create<ConsoleStore>()(
const newEntry = get().entries[0]

// Surface error notifications immediately when error entries are added
// Only show if error notifications are enabled in settings
if (newEntry?.error) {
try {
const errorMessage = String(newEntry.error)

useNotificationStore.getState().addNotification({
level: 'error',
message: errorMessage,
workflowId: entry.workflowId,
action: {
type: 'copilot',
const { isErrorNotificationsEnabled } = useGeneralStore.getState()

if (isErrorNotificationsEnabled) {
try {
const errorMessage = String(newEntry.error)

useNotificationStore.getState().addNotification({
level: 'error',
message: errorMessage,
},
})
} catch (notificationError) {
logger.error('Failed to create block error notification', {
entryId: newEntry.id,
error: notificationError,
})
workflowId: entry.workflowId,
action: {
type: 'copilot',
message: errorMessage,
},
})
} catch (notificationError) {
logger.error('Failed to create block error notification', {
entryId: newEntry.id,
error: notificationError,
})
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions packages/db/migrations/0110_broken_paladin.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE "settings" ADD COLUMN "error_notifications_enabled" boolean DEFAULT true NOT NULL;--> statement-breakpoint
ALTER TABLE "settings" DROP COLUMN "auto_fill_env_vars";
Loading