From 7f382ce56844e4b5c2d01771ec0c603e61d02567 Mon Sep 17 00:00:00 2001 From: Forgotten Date: Fri, 20 Feb 2026 15:00:56 -0600 Subject: [PATCH] fix: add gap between labels and values in all properties panes Add gap-3 to PropertyRow flex containers so labels don't touch their values. Also add shrink-0 on labels and min-w-0 on value containers to prevent overflow issues. Applied to: IssueProperties, AgentProperties, GoalProperties, ProjectProperties. Co-Authored-By: Claude Opus 4.6 --- ui/src/components/AgentProperties.tsx | 6 +- ui/src/components/GoalProperties.tsx | 6 +- ui/src/components/IssueProperties.tsx | 6 +- ui/src/components/ProjectProperties.tsx | 120 ++++++++++++++++++++++-- 4 files changed, 121 insertions(+), 17 deletions(-) diff --git a/ui/src/components/AgentProperties.tsx b/ui/src/components/AgentProperties.tsx index 1d108342..544e58c9 100644 --- a/ui/src/components/AgentProperties.tsx +++ b/ui/src/components/AgentProperties.tsx @@ -23,9 +23,9 @@ const adapterLabels: Record = { function PropertyRow({ label, children }: { label: string; children: React.ReactNode }) { return ( -
- {label} -
{children}
+
+ {label} +
{children}
); } diff --git a/ui/src/components/GoalProperties.tsx b/ui/src/components/GoalProperties.tsx index be6ee7f0..8c8724c9 100644 --- a/ui/src/components/GoalProperties.tsx +++ b/ui/src/components/GoalProperties.tsx @@ -21,9 +21,9 @@ interface GoalPropertiesProps { function PropertyRow({ label, children }: { label: string; children: React.ReactNode }) { return ( -
- {label} -
{children}
+
+ {label} +
{children}
); } diff --git a/ui/src/components/IssueProperties.tsx b/ui/src/components/IssueProperties.tsx index ec595e5b..de6fad21 100644 --- a/ui/src/components/IssueProperties.tsx +++ b/ui/src/components/IssueProperties.tsx @@ -22,9 +22,9 @@ interface IssuePropertiesProps { function PropertyRow({ label, children }: { label: string; children: React.ReactNode }) { return ( -
- {label} -
{children}
+
+ {label} +
{children}
); } diff --git a/ui/src/components/ProjectProperties.tsx b/ui/src/components/ProjectProperties.tsx index 4b6b12ba..302668c6 100644 --- a/ui/src/components/ProjectProperties.tsx +++ b/ui/src/components/ProjectProperties.tsx @@ -1,7 +1,16 @@ +import { useState } from "react"; +import { Link } from "react-router-dom"; +import { useQuery } from "@tanstack/react-query"; import type { Project } from "@paperclip/shared"; import { StatusBadge } from "./StatusBadge"; import { formatDate } from "../lib/utils"; +import { goalsApi } from "../api/goals"; +import { useCompany } from "../context/CompanyContext"; +import { queryKeys } from "../lib/queryKeys"; import { Separator } from "@/components/ui/separator"; +import { Button } from "@/components/ui/button"; +import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; +import { Plus, X } from "lucide-react"; interface ProjectPropertiesProps { project: Project; @@ -10,14 +19,49 @@ interface ProjectPropertiesProps { function PropertyRow({ label, children }: { label: string; children: React.ReactNode }) { return ( -
- {label} -
{children}
+
+ {label} +
{children}
); } export function ProjectProperties({ project, onUpdate }: ProjectPropertiesProps) { + const { selectedCompanyId } = useCompany(); + const [goalOpen, setGoalOpen] = useState(false); + + const { data: allGoals } = useQuery({ + queryKey: queryKeys.goals.list(selectedCompanyId!), + queryFn: () => goalsApi.list(selectedCompanyId!), + enabled: !!selectedCompanyId, + }); + + const linkedGoalIds = project.goalIds.length > 0 + ? project.goalIds + : project.goalId + ? [project.goalId] + : []; + + const linkedGoals = project.goals.length > 0 + ? project.goals + : linkedGoalIds.map((id) => ({ + id, + title: allGoals?.find((g) => g.id === id)?.title ?? id.slice(0, 8), + })); + + const availableGoals = (allGoals ?? []).filter((g) => !linkedGoalIds.includes(g.id)); + + const removeGoal = (goalId: string) => { + if (!onUpdate) return; + onUpdate({ goalIds: linkedGoalIds.filter((id) => id !== goalId) }); + }; + + const addGoal = (goalId: string) => { + if (!onUpdate || linkedGoalIds.includes(goalId)) return; + onUpdate({ goalIds: [...linkedGoalIds, goalId] }); + setGoalOpen(false); + }; + return (
@@ -29,11 +73,71 @@ export function ProjectProperties({ project, onUpdate }: ProjectPropertiesProps) {project.leadAgentId.slice(0, 8)} )} - {project.goalId && ( - - {project.goalId.slice(0, 8)} - - )} +
+
+ Goals +
+ {linkedGoals.length === 0 ? ( + None + ) : ( +
+ {linkedGoals.map((goal) => ( + + + {goal.title} + + {onUpdate && ( + + )} + + ))} +
+ )} + {onUpdate && ( + + + + + + {availableGoals.length === 0 ? ( +
+ All goals linked. +
+ ) : ( + availableGoals.map((goal) => ( + + )) + )} +
+
+ )} +
+
+
{project.targetDate && ( {formatDate(project.targetDate)}