Commit Graph

19 Commits

Author SHA1 Message Date
Nicolas Varrot
d9e1b88a70 fix: persist deleted sessions via localStorage blacklist
Deleted sessions would reappear after page refresh because the
gateway sessions.list response still included them. Now maintains
a localStorage blacklist of deleted session keys that filters them
out on every load, regardless of gateway-side deletion support.
2026-02-12 21:40:07 +00:00
Nicolas Varrot
53d619c357 feat: relative timestamps, message preview, and recency sort in sidebar
- Show relative time (2m, 3h, 1d) next to each session name
- Display last message preview below session name (truncated to 80 chars)
- Sort sessions by most recently updated (within pinned/unpinned groups)
- Map updatedAt and lastMessagePreview from gateway sessions.list response
2026-02-12 17:59:16 +00:00
Nicolas Varrot
e94325b38a feat: delete session from sidebar with confirmation dialog 2026-02-12 16:57:18 +00:00
Nicolas Varrot
581675d00c feat: distinguish system events from user messages
System events (heartbeats, cron triggers, webhooks, channel events)
now render as subtle inline notifications instead of full user bubbles.
Detection based on content patterns ([EVENT], [cron:], [HEARTBEAT], etc.).
2026-02-12 16:49:16 +00:00
Nicolas Varrot
96f28836cd feat: display model name badge in header for active session
Shows the model (e.g. claude-opus-4-6) as a subtle chip next to the
session label in the header. Hovering reveals agent ID if available.
Model and agentId are now extracted from sessions.list response.
2026-02-12 12:06:12 +00:00
Nicolas Varrot
c0d27a7754 feat: add unread message indicators on sidebar sessions
Show a cyan dot on sessions that received new messages while
viewing a different session. The dot clears when switching to
that session.
2026-02-12 11:36:31 +00:00
Nicolas Varrot
6734b54389 fix: resolve CI lint errors in Sidebar, TypingIndicator, and useGateway
- Sidebar: replace useEffect setState with callback pattern for filter reset
- TypingIndicator: initialize useRef with 0 instead of impure Date.now()
- TypingIndicator: remove redundant setElapsed(0) from mount effect
- useGateway: remove unused eslint-disable directive
2026-02-12 11:27:42 +00:00
Nicolas Varrot
e53ef36715 feat: show active session name in browser tab title
Updates document.title dynamically to show the current session label
(e.g. 'main — PinchChat'). Integrates with the existing notification
system so unread badges still work correctly (e.g. '(3) main — PinchChat').
Resets to plain 'PinchChat' when no session is selected.
2026-02-12 09:17:15 +00:00
Nicolas Varrot
8301cba339 fix: guard Notification API for unsupported browsers
Check typeof Notification before accessing .permission or
requestPermission(). Fixes crash on browsers/contexts where
the Notification API is unavailable (e.g. some WebViews).
2026-02-12 07:58:23 +00:00
Nicolas Varrot
cb882f5ead feat: add loading indicator when switching sessions
Show a spinner with 'Loading messages…' text while chat history
is being fetched during session switches, instead of briefly
flashing the empty welcome screen. Includes EN/FR i18n.
2026-02-12 05:52:06 +00:00
Nicolas Varrot
73d9e5f6f2 feat: add channel/type icons to session list in sidebar
Show Discord, Telegram, WhatsApp, Signal, Slack brand icons,
clock icon for cron sessions, bot icon for sub-agents, and
globe icon for webchat sessions. Falls back to message bubble
for unknown channels.

Closes feedback #23
2026-02-12 02:45:33 +00:00
Nicolas Varrot
29482e377a fix: resolve ESLint errors for React compiler rules
- Chat.tsx: replace mutable variable in render IIFE with useMemo+reduce
  to satisfy react-hooks/immutability rule
- ConnectionBanner.tsx: move setState calls into a useCallback to avoid
  synchronous setState in effect body (react-hooks/set-state-in-effect)
- useGateway.ts: suppress set-state-in-effect for legitimate mount init
2026-02-12 01:42:40 +00:00
Nicolas Varrot
916910f5ce fix: resolve all ESLint errors and add lint step to CI
- Extract credential helpers to src/lib/credentials.ts (fixes react-refresh/only-export-components)
- Extract buildImageSrc to src/lib/image.ts (fixes react-refresh/only-export-components)
- Reorder useCallback declarations in useGateway to fix react-hooks/immutability
- Sync refs via useEffect instead of during render (fixes react-hooks/refs)
- Replace useState initializer effect with lazy initializer functions in LoginScreen
- Add comments to empty catch blocks (fixes no-empty)
- Remove unused variable (fixes @typescript-eslint/no-unused-vars)
- Downgrade react-hooks/set-state-in-effect to warning (valid init/status patterns)
- Add lint step to CI workflow (runs before type-check and build)
2026-02-11 23:37:37 +00:00
Nicolas Varrot
473d23c140 feat: add browser notifications and tab title badge for unread messages
When the tab is not focused:
- Tab title shows unread count: (3) PinchChat
- Browser notification with message preview (if permitted)
- Notifications collapse into one via tag
- Click notification to focus tab
- All clears when tab regains focus
- Permission requested on first user interaction
2026-02-11 21:45:59 +00:00
Nicolas Varrot
693229c14e refactor: replace any types with proper TypeScript types across gateway client, hooks, and components
- Add GatewayMessage and JsonPayload interfaces to gateway.ts
- Type WebSocket message parsing with GatewayMessage instead of any
- Use ReturnType<typeof setTimeout> for timer refs
- Type chat event payload destructuring explicitly
- Add ChatPayloadMessage interface for extractText()
- Replace any casts in loadSessions/loadHistory with typed assertions
- Add str() helper in ToolCall.tsx for safe unknown→string extraction
- Use Extract<MessageBlock, ...> type guards instead of `as any` casts
- Type CodeBlock children prop properly
2026-02-11 21:17:44 +00:00
Nicolas Varrot
762a5f2026 feat: inline image display with lightbox
- Add image block type for base64 and URL images
- Parse image/image_url blocks from gateway history
- Render images inline in chat messages (rounded, dark-themed)
- Click-to-zoom lightbox with Escape to close
- Markdown images also use the lightbox component
- Detect base64 images in tool results (e.g. Read tool on image files)
- Support png, jpg, gif, webp formats
2026-02-11 17:18:10 +00:00
Nicolas Varrot
9b3aed4adc feat: add runtime language selector in header (EN/FR toggle)
- Add LanguageSelector component with globe icon + cycle button
- Refactor i18n to support reactive locale switching via useSyncExternalStore
- Locale priority: localStorage > VITE_LOCALE > navigator.language > 'en'
- All components now use useT() hook for reactive re-rendering on locale change
- Persists choice to localStorage (key: pinchchat-locale)
- No page reload needed — instant switch
2026-02-11 16:18:22 +00:00
Nicolas Varrot
36f948027b feat: runtime login screen — remove token from build
- Add LoginScreen component with Gateway URL + Token fields
- Store credentials in localStorage (not in bundle)
- Auto-reconnect with stored credentials on reload
- Add logout button (LogOut icon) in Header
- Remove VITE_GATEWAY_TOKEN from .env.example
- VITE_GATEWAY_WS_URL now only pre-fills the URL field
- Dark neon theme consistent with rest of app

Closes feedback item #4
2026-02-11 12:48:58 +00:00
Nicolas Varrot
1f8ff9ae0a Initial commit — ClawChat v1.0.0 2026-02-11 00:48:43 +00:00