feat: space sidebar drag-and-drop reordering with folder system
Add user_space_layout table and PUT /api/users/@me/space-layout endpoint for persisting per-user sidebar ordering. Spaces can be freely reordered via drag-and-drop, folders created by dragging one space onto another, and folders auto-dissolve when they have fewer than 2 members. Includes folder context menu (rename, color, ungroup), collapsed folder mini-grid icons, multi-tab sync via WebSocket, and localStorage collapse state. Removes the rigid native/federated split — federated spaces now intermix freely while keeping their globe badge.
This commit is contained in:
@@ -68,6 +68,19 @@ function buildFullSpace(spaceId: string, forUserId: string): SpaceWithChannelsAn
|
||||
.where(eq(schema.channels.spaceId, spaceId))
|
||||
.all();
|
||||
|
||||
const categories = db.select()
|
||||
.from(schema.channelCategories)
|
||||
.where(eq(schema.channelCategories.spaceId, spaceId))
|
||||
.orderBy(schema.channelCategories.position)
|
||||
.all()
|
||||
.map(c => ({
|
||||
id: c.id,
|
||||
spaceId: c.spaceId,
|
||||
name: c.name,
|
||||
position: c.position ?? 0,
|
||||
createdAt: c.createdAt,
|
||||
}));
|
||||
|
||||
const roles = db.select()
|
||||
.from(schema.roles)
|
||||
.where(eq(schema.roles.spaceId, spaceId))
|
||||
@@ -135,6 +148,7 @@ function buildFullSpace(spaceId: string, forUserId: string): SpaceWithChannelsAn
|
||||
type: ch.type as Channel['type'],
|
||||
topic: ch.topic,
|
||||
position: ch.position ?? 0,
|
||||
categoryId: ch.categoryId ?? null,
|
||||
createdAt: ch.createdAt,
|
||||
myPermissions: permissionsToString(chPerms),
|
||||
});
|
||||
@@ -153,6 +167,7 @@ function buildFullSpace(spaceId: string, forUserId: string): SpaceWithChannelsAn
|
||||
description: space.description ?? null,
|
||||
createdAt: space.createdAt,
|
||||
channels: visibleChannels,
|
||||
categories,
|
||||
members,
|
||||
roles: roles.map(r => ({
|
||||
id: r.id,
|
||||
|
||||
Reference in New Issue
Block a user