mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add pinned chats with drag-to-reorder (#23615)
https://github.com/user-attachments/assets/bd5d12a1-61b3-4b7d-83b6-317bdfb60b3c ## Summary Adds pinned chats to the agents page sidebar with server-side persistence and drag-to-reorder. Users can pin/unpin chats via the context menu, and pinned chats appear in a dedicated "Pinned" section above the time-grouped list. ## Database Migration `000453_chat_pin_order`: adds `pin_order integer DEFAULT 0 NOT NULL` column on `chats` (0 = unpinned, 1+ = pinned in display order). Three SQL queries handle pin operations server-side using CTEs with `ROW_NUMBER()`: - `PinChatByID`: normalizes existing orders and appends to end - `UnpinChatByID`: sets target to 0 and compacts remaining pins - `UpdateChatPinOrder`: shifts neighbors, clamps to `[1, pinned_count]` All queries exclude archived chats. `ArchiveChatByID` clears `pin_order` on archive. The handler rejects pinning archived chats with 400. ## Backend Pin/unpin/reorder go through the existing `PATCH /api/experimental/chats/{chat}` via the `pin_order` field on `UpdateChatRequest`. The handler routes based on current pin state: `pin_order == 0` unpins, `> 0` on an already-pinned chat reorders, `> 0` on an unpinned chat appends to end. ## Frontend - `pinChat` / `unpinChat` / `reorderPinnedChat` optimistic mutations using shared `isChatListQuery` predicate - Sidebar renders Pinned section above time groups, excludes pinned chats from time groups - Pin/Unpin context menu items (hidden for child/delegated chats) - `@dnd-kit/core` + `@dnd-kit/sortable` for drag-to-reorder with `MouseSensor`, `TouchSensor`, and `KeyboardSensor` - Local pin-order override prevents flash on drop; click blocker prevents NavLink navigation after drag --- *PR generated with Coder Agents*
This commit is contained in:
+13
-2
@@ -61,6 +61,7 @@ type Chat struct {
|
||||
CreatedAt time.Time `json:"created_at" format:"date-time"`
|
||||
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
|
||||
Archived bool `json:"archived"`
|
||||
PinOrder int32 `json:"pin_order"`
|
||||
MCPServerIDs []uuid.UUID `json:"mcp_server_ids" format:"uuid"`
|
||||
Labels map[string]string `json:"labels"`
|
||||
}
|
||||
@@ -323,8 +324,18 @@ type CreateChatRequest struct {
|
||||
|
||||
// UpdateChatRequest is the request to update a chat.
|
||||
type UpdateChatRequest struct {
|
||||
Title *string `json:"title,omitempty"`
|
||||
Archived *bool `json:"archived,omitempty"`
|
||||
Title *string `json:"title,omitempty"`
|
||||
Archived *bool `json:"archived,omitempty"`
|
||||
// PinOrder controls the chat's pinned state and position.
|
||||
// - nil: no change to pin state.
|
||||
// - 0: unpin the chat.
|
||||
// - >0 (chat is unpinned): pin the chat, appending it to
|
||||
// the end of the pinned list. The specific value is
|
||||
// ignored; the server assigns the next available position.
|
||||
// - >0 (chat is already pinned): move the chat to the
|
||||
// requested position, shifting neighbors as needed. The
|
||||
// value is clamped to [1, pinned_count].
|
||||
PinOrder *int32 `json:"pin_order,omitempty"`
|
||||
Labels *map[string]string `json:"labels,omitempty"`
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user