[AI] Add thread actions, filters, and archive support (#20068)
## PR Description ### Summary - Add AI chat thread actions: rename, archive (soft-delete via `deletedAt`), and hard-delete with confirmation. - Add chat thread filtering by status (active/archived/all), group-by mode, and last activity. - Rework drawer/side-panel thread lists to share thread sections, item menus, archive icons, and empty-state behavior. - Extend server chat thread model/API with `deletedAt`, mutations, broadcasts, and archive-aware stream guards. ### Decisions - Two-stage lifecycle: Archive sets `deletedAt` (soft); Delete is a separate action on archived threads that hard-deletes the row. Aligns with Twenty's soft-delete convention (Felix's suggestion). - `lastMessageAt` is derived from `MAX(agentMessage.createdAt)` on read, not stored. List query does inline aggregation for sort; `@ResolveField` covers single-thread / mutation paths so the schema contract is honest everywhere. Matches `timeline-messaging.service.ts` precedent and the existing `totalInputCredits` / `totalOutputCredits` `@ResolveField` pattern in the same resolver. - Replaced auto-CRUD `chatThreads` (cursor-paginated Connection) with a custom `[AgentChatThreadDTO!]` resolver. Frontend metadata-store treats threads as a flat collection and filters/sorts client-side, so cursor pagination was performative. - Sending in an archived chat unarchives it optimistically on the client and authoritatively on the server. - Grouping and last-activity filtering use `lastMessageAt ?? updatedAt` so archive/rename don't bump threads in the list. - Kept metadata-store core API unchanged; AI chat uses the same local cast pattern already used by other metadata-store partial updates. https://github.com/user-attachments/assets/1b179b7b-1a2a-4a7a-aa0a-c88f6f051a87
This commit is contained in:
+7
-4
@@ -92,15 +92,15 @@ const StyledItem = styled.button<StyledItemProps>`
|
||||
border-radius: ${themeCssVariables.border.radius.sm};
|
||||
box-sizing: border-box;
|
||||
color: ${({ active, isSoon, variant }) => {
|
||||
if (variant === 'tertiary') {
|
||||
return themeCssVariables.font.color.tertiary;
|
||||
}
|
||||
if (active === true) {
|
||||
return themeCssVariables.font.color.primary;
|
||||
}
|
||||
if (isSoon) {
|
||||
return themeCssVariables.font.color.light;
|
||||
}
|
||||
if (variant === 'tertiary') {
|
||||
return themeCssVariables.font.color.tertiary;
|
||||
}
|
||||
return themeCssVariables.font.color.secondary;
|
||||
}};
|
||||
cursor: ${({ isSoon, isDragging }) =>
|
||||
@@ -129,7 +129,10 @@ const StyledItem = styled.button<StyledItemProps>`
|
||||
|
||||
&:hover {
|
||||
background: ${themeCssVariables.background.transparent.light};
|
||||
color: ${themeCssVariables.font.color.primary};
|
||||
color: ${({ variant }) =>
|
||||
variant === 'tertiary'
|
||||
? themeCssVariables.font.color.tertiary
|
||||
: themeCssVariables.font.color.primary};
|
||||
}
|
||||
|
||||
&:hover .keyboard-shortcuts {
|
||||
|
||||
Reference in New Issue
Block a user