fix(activity): address code review feedback
- Fix activity:created WS payload to match frontend expectations (issue_id at top level, entry as TimelineEntry object) - Promote child comments to top-level when parent is deleted (both in handleDeleteComment and WS comment:deleted handler) - Enforce one-level reply nesting: reject replies to replies with 400 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e7fe6ea79b
commit
ba3c8e1b3f
3 changed files with 33 additions and 6 deletions
|
|
@ -315,7 +315,13 @@ export function IssueDetail({ issueId, onDelete }: IssueDetailProps) {
|
|||
const handleDeleteComment = async (commentId: string) => {
|
||||
try {
|
||||
await api.deleteComment(commentId);
|
||||
setTimeline((prev) => prev.filter((e) => e.id !== commentId));
|
||||
setTimeline((prev) =>
|
||||
prev
|
||||
// Promote replies of deleted comment to top-level
|
||||
.map((e) => e.parent_id === commentId ? { ...e, parent_id: null } : e)
|
||||
// Remove the deleted comment
|
||||
.filter((e) => e.id !== commentId)
|
||||
);
|
||||
} catch {
|
||||
toast.error("Failed to delete comment");
|
||||
}
|
||||
|
|
@ -379,7 +385,11 @@ export function IssueDetail({ issueId, onDelete }: IssueDetailProps) {
|
|||
useCallback((payload: unknown) => {
|
||||
const { comment_id, issue_id } = payload as CommentDeletedPayload;
|
||||
if (issue_id === id) {
|
||||
setTimeline((prev) => prev.filter((e) => e.id !== comment_id));
|
||||
setTimeline((prev) =>
|
||||
prev
|
||||
.map((e) => e.parent_id === comment_id ? { ...e, parent_id: null } : e)
|
||||
.filter((e) => e.id !== comment_id)
|
||||
);
|
||||
}
|
||||
}, [id]),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -186,19 +186,26 @@ func handleTaskActivity(ctx context.Context, bus *events.Bus, queries *db.Querie
|
|||
}
|
||||
|
||||
// publishActivityEvent sends an activity:created event for WS broadcasting.
|
||||
// Payload matches frontend ActivityCreatedPayload: { issue_id, entry: TimelineEntry }
|
||||
func publishActivityEvent(bus *events.Bus, original events.Event, activity db.ActivityLog) {
|
||||
actorType := ""
|
||||
if activity.ActorType.Valid {
|
||||
actorType = activity.ActorType.String
|
||||
}
|
||||
action := activity.Action
|
||||
bus.Publish(events.Event{
|
||||
Type: protocol.EventActivityCreated,
|
||||
WorkspaceID: original.WorkspaceID,
|
||||
ActorType: original.ActorType,
|
||||
ActorID: original.ActorID,
|
||||
Payload: map[string]any{
|
||||
"activity": map[string]any{
|
||||
"issue_id": util.UUIDToString(activity.IssueID),
|
||||
"entry": map[string]any{
|
||||
"type": "activity",
|
||||
"id": util.UUIDToString(activity.ID),
|
||||
"issue_id": util.UUIDToString(activity.IssueID),
|
||||
"actor_type": util.TextToPtr(activity.ActorType),
|
||||
"actor_type": actorType,
|
||||
"actor_id": util.UUIDToString(activity.ActorID),
|
||||
"action": activity.Action,
|
||||
"action": &action,
|
||||
"details": json.RawMessage(activity.Details),
|
||||
"created_at": util.TimestampToString(activity.CreatedAt),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -94,6 +94,16 @@ func (h *Handler) CreateComment(w http.ResponseWriter, r *http.Request) {
|
|||
var parentID pgtype.UUID
|
||||
if req.ParentID != nil {
|
||||
parentID = parseUUID(*req.ParentID)
|
||||
// Only allow one level of nesting: parent must be a top-level comment
|
||||
parent, err := h.Queries.GetComment(r.Context(), parentID)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "parent comment not found")
|
||||
return
|
||||
}
|
||||
if parent.ParentID.Valid {
|
||||
writeError(w, http.StatusBadRequest, "replies to replies are not supported")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
comment, err := h.Queries.CreateComment(r.Context(), db.CreateCommentParams{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue