166 lines · 5.6 KB · TypeScript
RawDownload
/** * NotificationsSection - Notification settings including triggers and ignored repositories. */ import {  RepositoryDropdown,  SelectedRepositoryItem,} from '@renderer/components/common/RepositoryDropdown'; import { SettingRow, SettingsSectionHeader, SettingsSelect, SettingsToggle } from '../components';import { NotificationTriggerSettings } from '../NotificationTriggerSettings'; import type { RepositoryDropdownItem, SafeConfig } from '../hooks/useSettingsConfig';import type { NotificationTrigger } from '@renderer/types/data'; // Snooze duration optionsconst SNOOZE_OPTIONS = [  { value: 15, label: '15 minutes' },  { value: 30, label: '30 minutes' },  { value: 60, label: '1 hour' },  { value: 120, label: '2 hours' },  { value: 240, label: '4 hours' },  { value: -1, label: 'Until tomorrow' },] as const; interface NotificationsSectionProps {  readonly safeConfig: SafeConfig;  readonly saving: boolean;  readonly isSnoozed: boolean;  readonly ignoredRepositoryItems: RepositoryDropdownItem[];  readonly excludedRepositoryIds: string[];  readonly onNotificationToggle: (    key: 'enabled' | 'soundEnabled' | 'includeSubagentErrors',    value: boolean  ) => void;  readonly onSnooze: (minutes: number) => Promise<void>;  readonly onClearSnooze: () => Promise<void>;  readonly onAddIgnoredRepository: (item: RepositoryDropdownItem) => Promise<void>;  readonly onRemoveIgnoredRepository: (repositoryId: string) => Promise<void>;  readonly onAddTrigger: (trigger: Omit<NotificationTrigger, 'isBuiltin'>) => Promise<void>;  readonly onUpdateTrigger: (    triggerId: string,    updates: Partial<NotificationTrigger>  ) => Promise<void>;  readonly onRemoveTrigger: (triggerId: string) => Promise<void>;} export const NotificationsSection = ({  safeConfig,  saving,  isSnoozed,  ignoredRepositoryItems,  excludedRepositoryIds,  onNotificationToggle,  onSnooze,  onClearSnooze,  onAddIgnoredRepository,  onRemoveIgnoredRepository,  onAddTrigger,  onUpdateTrigger,  onRemoveTrigger,}: NotificationsSectionProps): React.JSX.Element => {  return (    <div>      {/* Notification Triggers */}      <NotificationTriggerSettings        triggers={safeConfig.notifications.triggers || []}        saving={saving}        onUpdateTrigger={onUpdateTrigger}        onAddTrigger={onAddTrigger}        onRemoveTrigger={onRemoveTrigger}      />       {/* Notification Settings */}      <SettingsSectionHeader title="Notification Settings" />      <SettingRow        label="Enable System Notifications"        description="Show system notifications for errors and events"      >        <SettingsToggle          enabled={safeConfig.notifications.enabled}          onChange={(v) => onNotificationToggle('enabled', v)}          disabled={saving}        />      </SettingRow>      <SettingRow label="Play sound" description="Play a sound when notifications appear">        <SettingsToggle          enabled={safeConfig.notifications.soundEnabled}          onChange={(v) => onNotificationToggle('soundEnabled', v)}          disabled={saving || !safeConfig.notifications.enabled}        />      </SettingRow>      <SettingRow        label="Include subagent errors"        description="Detect and notify about errors in subagent sessions"      >        <SettingsToggle          enabled={safeConfig.notifications.includeSubagentErrors}          onChange={(v) => onNotificationToggle('includeSubagentErrors', v)}          disabled={saving || !safeConfig.notifications.enabled}        />      </SettingRow>      <SettingRow        label="Snooze notifications"        description={          isSnoozed            ? `Snoozed until ${new Date(safeConfig.notifications.snoozedUntil!).toLocaleTimeString()}`            : 'Temporarily pause notifications'        }      >        <div className="flex items-center gap-2">          {isSnoozed ? (            <button              onClick={onClearSnooze}              disabled={saving}              className={`rounded-md bg-red-500/10 px-3 py-1.5 text-sm font-medium text-red-400 transition-all duration-150 hover:bg-red-500/20 ${saving ? 'cursor-not-allowed opacity-50' : ''} `}            >              Clear Snooze            </button>          ) : (            <SettingsSelect              value={0}              options={[{ value: 0, label: 'Select duration...' }, ...SNOOZE_OPTIONS]}              onChange={(v) => v !== 0 && onSnooze(v)}              disabled={saving || !safeConfig.notifications.enabled}              dropUp            />          )}        </div>      </SettingRow>       <SettingsSectionHeader title="Ignored Repositories" />      <p className="mb-3 text-xs" style={{ color: 'var(--color-text-muted)' }}>        Notifications from these repositories will be ignored      </p>      {ignoredRepositoryItems.length > 0 ? (        <div className="mb-3">          {ignoredRepositoryItems.map((item) => (            <SelectedRepositoryItem              key={item.id}              item={item}              onRemove={() => onRemoveIgnoredRepository(item.id)}              disabled={saving}            />          ))}        </div>      ) : (        <div          className="mb-3 rounded-md border border-dashed py-3 text-center"          style={{ borderColor: 'var(--color-border)' }}        >          <p className="text-sm" style={{ color: 'var(--color-text-muted)' }}>            No repositories ignored          </p>        </div>      )}      <RepositoryDropdown        onSelect={onAddIgnoredRepository}        excludeIds={excludedRepositoryIds}        placeholder="Select repository to ignore..."        disabled={saving}        dropUp      />    </div>  );};