feat: channel permissions UI, DM Sans font, private channel filtering, migration fix

- Rewrite ChannelSettingsModal with full tri-state permission override UI
  for roles and members (allow/neutral/deny per permission bit)
- Switch font from Inter to self-hosted DM Sans (woff2 variable fonts)
- Add client-side VIEW_CHANNEL filtering in ChannelSidebar for private channels
- Broadcast isPrivate flag on channel override changes
- Fix voice permission bit migration: gate behind persistent flag to prevent
  repeated re-runs that stripped STREAM from @everyone roles
- Add speakingUserIds set to voice store for efficient user-level lookups
- Clear current channel view when a channel is deleted
- Move .glass-strip to @layer utilities for proper CSS specificity
- Simplify avatar initials font size to proportional formula
This commit is contained in:
Jannis Braun
2026-03-13 02:47:32 +01:00
parent 2b810055f7
commit 07ef49eac0
15 changed files with 1053 additions and 177 deletions
+17 -1
View File
@@ -290,13 +290,29 @@ export async function spaceRoutes(app: FastifyInstance): Promise<void> {
// Compute space-level permissions for the requesting user
const spacePerms = computePermissions(request.userId, id);
// Batch-fetch all channel overrides for @everyone (role = spaceId) to determine isPrivate
const everyoneOverrides = db.select().from(schema.channelOverrides)
.where(and(
eq(schema.channelOverrides.targetType, 'role'),
eq(schema.channelOverrides.targetId, id),
))
.all();
const privateChannelIds = new Set<string>();
for (const o of everyoneOverrides) {
const denyBits = BigInt(o.deny || '0');
if ((denyBits & PermissionBits.VIEW_CHANNEL) !== 0n) {
privateChannelIds.add(o.channelId);
}
}
// Filter channels by VIEW_CHANNEL permission and attach per-channel myPermissions
const visibleChannels: (Channel & { myPermissions: string })[] = [];
const visibleChannels: (Channel & { isPrivate: boolean; myPermissions: string })[] = [];
for (const ch of channels) {
const perms = computePermissions(request.userId, id, ch.id);
if ((perms & PermissionBits.VIEW_CHANNEL) !== 0n) {
visibleChannels.push({
...rowToChannel(ch),
isPrivate: privateChannelIds.has(ch.id),
myPermissions: permissionsToString(perms),
});
}