Commit Graph
100 Commits
Author SHA1 Message Date
Jannis Braun b3cb84c6a2 feat: rebuild SpaceSettings with expanded layout and grouped sidebar 2026-03-22 02:19:15 +01:00
Jannis Braun d54de16ec8 feat: add panel title headings to all UserSettings panels 2026-03-22 02:17:38 +01:00
Jannis Braun 3b06818614 feat: rebuild UserSettings with expanded layout and grouped sidebar 2026-03-22 02:15:27 +01:00
Jannis Braun 9bacc8fb3d feat: add size='settings' variant to Modal component 2026-03-22 02:13:49 +01:00
Jannis Braun 4c4bd8dec6 fix: add editable input alongside slider step presets for custom values 2026-03-22 01:44:24 +01:00
Jannis Braun 46f17cf172 fix: replace slider step number input with pill presets 2026-03-22 01:29:40 +01:00
Jannis Braun eff3210f29 fix: make slider step a compact inline row instead of prominent section 2026-03-22 01:25:03 +01:00
Jannis Braun 30cbf58770 fix: stack bitrate slider and input vertically for responsive layout 2026-03-22 01:19:28 +01:00
Jannis Braun 7e7e77b298 fix: prevent ghost voice users after server restart
Replace the stale-flag-based voice re-registration in the WS ready
handler with a server-authoritative check. If the server's voiceStates
doesn't include us (server restarted, lost in-memory voiceRooms),
cleanly tear down the LiveKit session via leaveVoice() + disconnect().
If the server still knows about us (WS blip), do nothing.
2026-03-22 01:05:30 +01:00
Jannis Braun f3ff07aa6d feat: add bitrate matrix editor with scale macro and uncapped max inputs 2026-03-22 00:52:40 +01:00
Jannis Braun c0618a0b75 refactor: convert screenShare.ts to kbps with override-first lookup 2026-03-22 00:47:08 +01:00
Jannis Braun 19cdfe58a4 feat: add bitrateMatrixOverrides validation, raise bitrate caps to 1 Gbps
- Import BITRATE_MATRIX_KBPS from shared constants
- Parse and return bitrateMatrixOverrides in rowToLimits
- Widen updateData type to accept null values
- Raise maxBitrateKbps and minBitrateKbps caps from 50 000 to 1 000 000 kbps
- Add full validation for bitrateMatrixOverrides (null to clear, key/value checks)
2026-03-22 00:44:24 +01:00
Jannis Braun 267dc8d992 feat: add bitrateMatrixOverrides to types, schema, and migration 2026-03-22 00:42:23 +01:00
Jannis Braun c7c7793aef feat: add BITRATE_MATRIX_KBPS to shared constants 2026-03-22 00:41:55 +01:00
Jannis Braun 6122c7829f fix: replace regex-based isNewlyCreated with explicit isNew prop
Pass isNew from parent state instead of guessing from the role name
pattern. Set true on create/copy, cleared on back/click-to-edit.
2026-03-22 00:17:14 +01:00
Jannis Braun b8c8e39dfd fix: use existing success banner style for role created indicator
Match the status-online pattern already used for "Role saved" in the
same file, instead of introducing a one-off accent-primary variant.
2026-03-22 00:12:33 +01:00
Jannis Braun 0bd87c4ebf fix: auto-focus name input and show creation indicator in role editor
After creating or copying a role, the name input is now auto-focused
with text selected so the user immediately starts typing. A subtle
"Role created" banner appears until the user makes any change.
2026-03-22 00:05:17 +01:00
Jannis Braun da82ba6d94 fix: add key prop to RoleEditView to reset state when switching roles
RoleEditView used useState(role.name) for draft state, but React
reuses the component instance when editingRoleId changes, ignoring
the new initial value. Adding key={editingRoleId} forces a remount,
re-initializing all draft state (name, color, permissions) correctly.
2026-03-21 23:43:00 +01:00
Jannis Braun 09bfd1ccab fix: use grid layout for stream settings pills to prevent uneven wrapping 2026-03-21 23:41:01 +01:00
Jannis Braun f9f7dd158f feat: guard applyConstraints for native mode in useLiveKit 2026-03-21 23:33:30 +01:00
Jannis Braun 8885662766 docs: update CLAUDE.md with high-end streaming settings 2026-03-21 23:32:04 +01:00
Jannis Braun b4b22faf55 feat: auto-increment role names to avoid uniqueness conflicts on create and copy 2026-03-21 23:31:35 +01:00
Jannis Braun a9a676bc70 feat: expand admin streaming pills, add high-end resource warning
Replaces hardcoded 3-resolution/3-framerate arrays with ALL_RESOLUTIONS
and STANDARD_FRAMERATES from shared constants (540p–Native, 30–120 fps).
Adds amber warning banner when high-end options (≥1440p or ≥75 fps) are
enabled, and fixes toggleResolution to handle 'native' with correct sort.
2026-03-21 23:30:46 +01:00
Jannis Braun 5ac0917d81 feat: dynamic resolution/framerate pills from instance limits 2026-03-21 23:30:14 +01:00
Jannis Braun 57b192533d feat: add Copy Role button to duplicate roles with permissions 2026-03-21 23:30:12 +01:00
Jannis Braun cb34bfc8ea feat: expand bitrate matrix, add native mode with pixel-proportional fallback 2026-03-21 23:26:54 +01:00
Jannis Braun 3fe9f774a1 feat: add client-side role name uniqueness validation with 409 handling 2026-03-21 23:26:06 +01:00
Jannis Braun b9f11489fe feat: update server validation for expanded resolutions and framerates
Replace hardcoded VALID_RESOLUTIONS/VALID_FRAMERATES with shared STANDARD_RESOLUTIONS/STANDARD_FRAMERATES constants. Update rowToLimits to handle the 'native' resolution value in DB parsing, and update all PATCH validation blocks to accept the expanded resolution/framerate sets and the 'native' option.
2026-03-21 23:23:25 +01:00
Jannis Braun a02b098fa7 feat: widen ScreenShareConfig types, bump persist to v12 2026-03-21 23:22:49 +01:00
Jannis Braun ec71dd2c50 feat: widen InstanceStreamingLimits.allowedResolutions to support 'native' 2026-03-21 23:22:46 +01:00
Jannis Braun bc1d92f853 feat: add shared streaming constants module 2026-03-21 23:20:58 +01:00
Jannis Braun 05fe1df5f0 feat: enforce case-insensitive unique role names per space 2026-03-21 23:20:40 +01:00
Jannis Braun 7fb87de09a feat: default new roles to @everyone permissions instead of null 2026-03-21 23:17:16 +01:00
Jannis Braun f7657e3adb fix: prevent duplicate messages when sending image without text
Optimistic message used content: '' while the server normalized it to
null, causing the content-based dedup to fail and leaving both the
empty temp message and the real attachment message in the list.
2026-03-21 22:46:01 +01:00
Jannis Braun 0d8913f589 feat: register CategorySettingsModal in AppLayout 2026-03-21 22:18:01 +01:00
Jannis Braun cb2eac24eb docs: update CLAUDE.md with category overrides schema, API, and permission changes 2026-03-21 22:11:22 +01:00
Jannis Braun cc7d1c191c feat: add CategorySettingsModal with overview and permissions tabs 2026-03-21 22:08:47 +01:00
Jannis Braun edb050fd39 feat: add category settings context menu, lock icon, empty category hiding 2026-03-21 18:38:47 +01:00
Jannis Braun 892164f3a5 refactor: use extracted PermissionsEditor in ChannelSettingsModal 2026-03-21 18:35:38 +01:00
Jannis Braun c43afc23a8 feat: extract TriStateToggle, OverrideEntry, PermissionsEditor shared components 2026-03-21 18:35:35 +01:00
Jannis Braun 637e083e9a feat: add category override API endpoints, fix channel categoryId reassignment, include isPrivate on categories
- Add GET/PUT/DELETE /api/categories/:id/overrides endpoints with
  privilege escalation guard matching existing channel override pattern
- Add isCategoryPrivate() and broadcastCategoryOverrideChange() helpers
  that cascade visibility changes to all channels in a category
- Fix PATCH /api/channels/:id to recompute permissions via
  broadcastOverrideChange when categoryId changes (different category
  overrides may apply)
- Include isPrivate flag on categories in GET /api/spaces/:id payload
  using batch-fetched @everyone overrides
- Include isPrivate on categories in broadcastChannelLayout and
  PATCH /api/categories/:id broadcasts
2026-03-21 18:29:25 +01:00
Jannis Braun b5ac7d3ee4 feat: add category override API client methods 2026-03-21 18:29:16 +01:00
Jannis Braun 17289445bd feat: add categorySettings modal type to uiStore 2026-03-21 18:25:56 +01:00
Jannis Braun bfe317f465 feat: interleaved category override resolution in permission engine 2026-03-21 18:22:22 +01:00
Jannis Braun 1473f4f88c fix: emoji reaction picker no longer overflows viewport on bottom messages 2026-03-21 18:21:30 +01:00
Jannis Braun eb04c4ad30 feat: add category_overrides table schema and migration 2026-03-21 18:20:21 +01:00
Jannis Braun 90d702338d feat: add slideDown animation for upward-flipping popovers 2026-03-21 18:20:02 +01:00
Jannis Braun 3300ce8d5c feat: add CategoryOverride type and isPrivate to ChannelCategory 2026-03-21 18:19:45 +01:00
Jannis Braun 448ff9a59c fix: exclude desktop, installers, and other non-Docker files from deploy rsync 2026-03-21 17:42:13 +01:00
Jannis Braun fe6de6456a feat: add ffmpeg to Docker runtime for video thumbnail generation 2026-03-21 17:23:19 +01:00
Jannis Braun 80d97d72c9 feat: add backfill migration for media dimensions and video thumbnails 2026-03-21 17:22:44 +01:00
Jannis Braun 7ec61c16fd feat: use aspect-ratio and preload=none for video/image attachments 2026-03-21 17:20:54 +01:00
Jannis Braun 561c9bc4f3 feat: include width, height, duration in all attachment serialization 2026-03-21 17:20:04 +01:00
Jannis Braun 7c767b580a feat: extract media dimensions and video thumbnails on upload 2026-03-21 17:18:59 +01:00
Jannis Braun d0f33446de feat: add video thumbnail generation and media metadata extraction 2026-03-21 17:16:40 +01:00
Jannis Braun b74e33b349 feat: add width, height, duration columns to attachments schema 2026-03-21 17:15:09 +01:00
Jannis Braun 948fa6de5c feat(desktop): add remote dictionary sync engine to activity detector
Refactor loadDictionary to accept a file path and support both legacy
bare-array (version 0) and versioned object formats. Add background
sync that fetches the latest games.json from GitHub, uses ETag-based
conditional requests (304 support), atomic cache writes, and hot-swaps
processMap/gameEntries without resetting current detection state.
On startup, the best local source (cache vs bundled seed) is loaded
immediately for instant detection, then sync runs fire-and-forget.
2026-03-21 04:12:21 +01:00
Jannis Braun 228ffe4894 feat(desktop): expand game dictionary to 249 entries with versioned schema
Rewrite games.json from bare array (28 entries) to versioned format
{ version: 1, games: [...] } with 249 entries covering top Steam games,
competitive titles, AAA, indie, survival/craft, simulation, horror,
fighting, racing, MMOs, and media apps (Spotify, VLC, OBS, mpv).
Every process name is specific enough to avoid false-positive detection.
2026-03-21 04:12:15 +01:00
Jannis Braun 156189dfa2 fix: redesign activity cards with glass-pill material and accent borders
Replace bg-surface-elevated cards and inline text badges with glass-pill
rows featuring colored left borders (mint=playing, sky=listening,
lavender=watching, rose=streaming). Identical treatment in both
ActivityPanel and MemberSidebar — no more compact/full distinction.
Members with rich activities get the frosted glass row; others stay plain.
2026-03-21 03:50:09 +01:00
Jannis Braun 2c122d066e fix: add console warnings for invalid games.json entries 2026-03-21 03:00:14 +01:00
Jannis Braun 0f4f129337 feat(desktop): add automatic game/app activity detection
Add cross-platform process scanning that detects running games and apps,
then broadcasts them as Rich Presence activities via the existing Phase 1
pipeline (activityStore -> WS -> other users).

- games.json dictionary with 26 entries (games, Spotify, VLC, OBS)
- activityDetector module: polls OS process list every 15s via execFile,
  matches against dictionary, emits IPC on state change only
- IPC bridge in main.ts/preload.ts with cleanup on quit
- Frontend activityBridge subscribes to IPC and feeds activityStore
- Supports Windows (tasklist CSV), macOS (ps -c), Linux (ps)
2026-03-21 02:57:30 +01:00
Jannis Braun 568b049b22 ci: add GitHub Actions workflow for desktop release builds
Triggers on v* tag push, builds for Windows, macOS (arm64), and Linux.
Uses electron-builder --publish to upload artifacts to GitHub Releases.
2026-03-21 02:32:43 +01:00
Jannis Braun 2593f7075c feat(desktop): add version display and check-for-updates to account settings 2026-03-21 02:32:19 +01:00
Jannis Braun a9fcdb72a8 feat(desktop): add manual download fallback to UpdateToast
Extends UpdateToast to handle update-error events from the preload bridge,
showing a "Download" link to the GitHub release URL when auto-update fails.
2026-03-21 02:31:20 +01:00
Jannis Braun 6ebb124d25 feat(desktop): update preload bridge types for enhanced update-error and getVersion 2026-03-21 02:30:06 +01:00
Jannis Braun a7d5abfca9 feat(desktop): enhance update-error payload with release URL, add get-app-version IPC 2026-03-21 02:29:42 +01:00
Jannis Braun a234041210 feat(desktop): switch auto-update provider from generic to github 2026-03-21 02:29:28 +01:00
Jannis Braun 9e4878c48f fix: move showActivity toggle from Account to Privacy settings panel 2026-03-21 02:13:32 +01:00
Jannis Braun 1f4e149ee1 feat: add frontend Rich Presence — activityStore, ActivityCard, sidebar upgrades, settings toggle
- Task 7: Create activityStore (Zustand) with Map<userId, Activity[]>, showActivity toggle,
  debounced pushActivities, and reset on logout
- Task 8: Wire WS integration — presence_update propagates activities to store,
  ready payload initializes userActivities and showActivity (via setState to avoid side effects)
- Task 9: Create ActivityCard component with compact/full modes, type-colored labels,
  elapsed time display, asset images, and fallback to customStatus
- Task 10: Upgrade ActivityPanel to three groups — active friends (full cards, no header),
  online friends (compact), offline friends — using getPrimaryActivity for grouping
- Task 11: Upgrade MemberSidebar to show compact ActivityCards instead of raw customStatus
- Task 12: Add showActivity toggle in AccountPanel settings (Activity Status section)
  with API persistence and store sync
2026-03-21 01:55:17 +01:00
Jannis Braun 9403ded8da feat: add showActivity toggle to PATCH @me with activity broadcast clear
- Accept showActivity boolean in PATCH /api/users/@me body
- Validate and persist as integer in DB
- Update ConnectionManager cache on toggle
- Broadcast empty activities via presence_update when toggled off
2026-03-21 01:49:41 +01:00
Jannis Braun ceb8894d58 feat: add WS activity_update handler and enhanced presence_update with activities
- Add validateActivities() with full field validation against ACTIVITY_LIMITS
- Add handleActivityUpdate() with showActivity gate and rate limiting
- Enhance handlePresenceUpdate() to include activities in broadcast payload
- Update status cache via connectionManager.setUserStatus() on presence change
- Wire activity_update case into event router switch statement
2026-03-21 01:48:57 +01:00
Jannis Braun d4366a2207 feat: add ConnectionManager in-memory activity state and ready payload
Add Rich Presence infrastructure to ConnectionManager:
- Four new Maps: userActivities, userShowActivity, userStatuses, lastActivityUpdate
- Public accessors: set/get/clear activities, showActivity, status, rate limit check
- Cleanup in finalizeDisconnect() and forceDisconnectUser()
- Cache showActivity and status from DB at auth time in buildReadyPayload()
- Assemble userActivities snapshot in ready payload with customStatus fallback
- Include activities: [] in offline presence_update broadcast
2026-03-21 01:44:36 +01:00
Jannis Braun bc408235c9 feat: add Activity type system, DB migration, and self-only showActivity in sanitizeUser
- Add Activity, ActivityType, ActivityTimestamps, ActivityAssets types to shared types
- Add activity_update client event and activities field on presence_update server event
- Add userActivities to ready payload and showActivity to User/UpdateUserRequest
- Create shared activities.ts with ACTIVITY_LIMITS, ACTIVITY_PRIORITY, getPrimaryActivity
- Add show_activity column to users table (schema + migration)
- Update sanitizeUser with isSelf parameter; only include showActivity for self
- Fix .map(sanitizeUser) calls to use arrow wrapper to prevent index-as-boolean bug
- Mark auth routes (register/login) as isSelf=true since they return own user data
2026-03-21 01:38:36 +01:00
Jannis Braun ce981ee5fc fix: prevent metadata fetch from overwriting fallback thumbnail with null
Use logical OR when merging fetched metadata so null values from
failed og: extraction don't destroy valid defaults (e.g. YouTube
thumbnail set before the fetch).
2026-03-21 00:35:44 +01:00
Jannis Braun 1c7d8557c6 fix: use predictable YouTube thumbnail URL as fallback for embed poster
YouTube may block og:image extraction via BackspaceBot user-agent.
Use img.youtube.com/vi/{ID}/hqdefault.jpg as a guaranteed thumbnail
that doesn't require metadata fetching. If og:image is successfully
fetched, it overwrites the fallback.
2026-03-21 00:31:59 +01:00
Jannis Braun a3db74c7f7 fix: resolve YouTube Error 153 by adding origin param and removing no-referrer
YouTube's embed API requires knowing the embedding origin to authorize
playback. The referrerPolicy="no-referrer" was stripping the Referer
header, and the missing origin param meant youtube-nocookie.com couldn't
verify the embed source, causing Error 153 (video player configuration
error). Fix: pass origin param explicitly and let the browser send the
default referrer.
2026-03-21 00:26:32 +01:00
Jannis Braun c0133397e3 fix: resolve 4 media embed bugs from testing
1. Video aspect ratio: remove container border/overflow-hidden, use
   preload="metadata" so browser knows dimensions before play
2. YouTube Error 153: remove sandbox attr (too restrictive), add full
   allow permissions (encrypted-media, accelerometer, gyroscope, etc.)
3. Google Images not displaying: detect image Content-Type from HTTP
   response in metadataFetcher, override classifier to create image
   embed for URLs that serve image/* content
4. Audio seeking broken: add HTTP Range request support in uploads
   route (Accept-Ranges, Content-Range, 206 Partial Content)
2026-03-21 00:19:04 +01:00
Jannis Braun ff2decded5 fix: address code review issues for embeds implementation
- Fix ?? to || in metadataFetcher.ts to handle empty strings from Cheerio
- Fix stale embeds on message edit: delete old embeds synchronously before
  broadcast, then resolve new ones async (all 4 edit paths: REST+WS, msg+DM)
- Revert unrelated MessageList.tsx scroll threshold change (5000 not 150)
- Remove duplicate embed indexes from migrateAddIndexes (kept standalone ones)
2026-03-20 23:58:06 +01:00
Jannis Braun dcdf10c5de docs: update CLAUDE.md with embeds schema, WS events, and feature status 2026-03-20 23:50:48 +01:00
Jannis Braun 4486341007 feat: add embeds_resolved WS handlers and optimistic embeds:[] default
- chatStore: normalize embeds to [] in addMessage, addRealtimeMessage, and updateMessage to guard against missing field from older servers/federation
- useWebSocket: add embeds_resolved and dm_embeds_resolved cases that patch the in-memory message cache when the server broadcasts resolved embed data
- useWebSocket: normalize embed image URLs for remote origins in message_created, message_updated, dm_message_created, dm_message_updated, and the new embeds_resolved handlers
2026-03-20 23:49:15 +01:00
Jannis Braun 95762a1974 feat: replace Embed.tsx with AttachmentRenderer + EmbedRenderer in Message
Switches Message.tsx from client-side URL metadata fetching (old Embed.tsx)
to server-driven embed objects via message.embeds[]. Delegates attachment
rendering to AttachmentRenderer. Removes firstUrl extraction and urlRegex.
2026-03-20 23:47:16 +01:00
Jannis Braun 5a670bc6ad feat: add embed sub-components (Generic, Video, Image, Rich) and dispatcher 2026-03-20 23:45:32 +01:00
Jannis Braun a800d9ff25 feat: add AttachmentRenderer with video/audio inline playback 2026-03-20 23:43:31 +01:00
Jannis Braun 01ee7ab67a feat: wire embeds into all message query and creation paths
Integrate embed infrastructure into the complete message flow:
- messages.ts: batch-fetch embeds in GET, resolve on POST, re-resolve on PATCH
- dm.ts: same pattern for DM messages with isDm=true
- search.ts: include embeds in all 4 search/around endpoints
- events.ts: embed resolution in WS message create/edit for both space and DM
- Fix embedClassifier.ts type errors (regex match undefined → null)
- Add embeds: [] to all inline MessageWithUser/DmMessageWithUser constructions
- Add embeds: [] to chatStore optimistic message
2026-03-20 23:41:53 +01:00
Jannis Braun 5fe25fb077 feat: add embed resolver with async resolution and batch fetching 2026-03-20 23:33:21 +01:00
Jannis Braun 29cfd88a15 feat: add URL classifier for embed type detection 2026-03-20 23:30:13 +01:00
Jannis Braun de1c0b4ed8 refactor: extract metadata fetcher into reusable utility 2026-03-20 23:30:01 +01:00
Jannis Braun ebc1868dd1 feat: add embeds database table with schema and migration 2026-03-20 23:28:57 +01:00
Jannis Braun 009923a12f feat: add Embed types and extend MessageWithUser with embeds[] 2026-03-20 23:25:58 +01:00
Jannis Braun f7d388c9a8 fix: clean up redundant regex guard and differentiate copy icons 2026-03-20 22:23:15 +01:00
Jannis Braun 720a3c4553 feat: wire up enhanced message context menu with all actions 2026-03-20 22:19:12 +01:00
Jannis Braun 3aa7e93a4d feat: pass previousMessageId prop from MessageList to Message 2026-03-20 22:16:55 +01:00
Jannis Braun 8da412c0d4 feat: create message context menu builder function 2026-03-20 22:15:31 +01:00
Jannis Braun 896cb77b5c feat: add markUnread store action and WS handler 2026-03-20 22:13:47 +01:00
Jannis Braun 2e26f98246 feat: add mark_unread WebSocket event handler 2026-03-20 22:11:42 +01:00
Jannis Braun 3c23893549 feat: add mark_unread to WebSocket event types 2026-03-20 22:09:40 +01:00
Jannis Braun c90ba431e8 fix: resolve mentions in reply previews to display usernames
Reply preview was rendering raw <@userId> tokens as plain text instead
of resolving them to MentionBadge components with proper usernames.
2026-03-20 21:25:45 +01:00
Jannis Braun 9fe46ad19b fix: voice drop zone was swallowing channel reorder drops
handleVoiceDropZoneDrop called stopPropagation and clearState
unconditionally, preventing container's handleContainerDrop from
firing when dropping a channel onto a voice channel. Add early
return for non-voiceUser drags so channel/category drops bubble
through to the container handler correctly.
2026-03-20 21:15:13 +01:00
Jannis Braun 99e6f2f249 fix: normalize drop indicator to single line between channels
Port the SpaceSidebar normalization pattern: convert 'before B'
to 'after A' so only one drop indicator renders at any gap.
Fixes double-line visual glitch and unreliable drops when cursor
is between two channels. Also adjust indicator offsets from
top-0/bottom-0 to -top-[1px]/-bottom-[1px] to center in the gap.
2026-03-20 21:07:20 +01:00
Jannis Braun ebe34a710b refactor: update VoiceChannel to use useDragManager hook-provided handlers 2026-03-20 20:46:49 +01:00