@@ -5,8 +5,6 @@ import { CSS } from "@dnd-kit/utilities";
55import {
66 Cross2Icon ,
77 CheckCircledIcon ,
8- UpdateIcon ,
9- ExclamationTriangleIcon ,
108 TimerIcon ,
119 DrawingPinFilledIcon ,
1210 Pencil1Icon ,
@@ -25,27 +23,15 @@ import {
2523} from "@/components/ui/context-menu" ;
2624import { workspaceDataAtom } from "@/store" ;
2725import { invoke } from "@tauri-apps/api/core" ;
28- import type { Feature , FeatureStatus , WorkspaceData } from "@/views/Workspace/types" ;
26+ import type { Feature , WorkspaceData } from "@/views/Workspace/types" ;
2927
3028interface FeatureTabProps {
3129 feature : Feature ;
3230 projectId : string ;
3331 isActive : boolean ;
3432 onSelect : ( ) => void ;
3533 isDragging ?: boolean ;
36- }
37-
38- function StatusIcon ( { status } : { status : FeatureStatus } ) {
39- switch ( status ) {
40- case "pending" :
41- return < TimerIcon className = "w-3 h-3 text-muted-foreground" /> ;
42- case "running" :
43- return < UpdateIcon className = "w-3 h-3 text-blue-500" /> ;
44- case "completed" :
45- return < CheckCircledIcon className = "w-3 h-3 text-green-500" /> ;
46- case "needs-review" :
47- return < ExclamationTriangleIcon className = "w-3 h-3 text-amber-500" /> ;
48- }
34+ dragHandleProps ?: ReturnType < typeof useSortable > [ "listeners" ] ;
4935}
5036
5137export function FeatureTab ( {
@@ -54,6 +40,7 @@ export function FeatureTab({
5440 isActive,
5541 onSelect,
5642 isDragging,
43+ dragHandleProps,
5744} : FeatureTabProps ) {
5845 const [ workspace , setWorkspace ] = useAtom ( workspaceDataAtom ) ;
5946 const [ isRenaming , setIsRenaming ] = useState ( false ) ;
@@ -100,7 +87,7 @@ export function FeatureTab({
10087 setIsRenaming ( false ) ;
10188 } ;
10289
103- const handleArchive = async ( ) => {
90+ const handleArchive = async ( note ?: string ) => {
10491 if ( ! workspace ) return ;
10592
10693 const newProjects = workspace . projects . map ( ( p ) => {
@@ -109,7 +96,7 @@ export function FeatureTab({
10996 return {
11097 ...p ,
11198 features : p . features . map ( ( f ) =>
112- f . id === feature . id ? { ...f , archived : true } : f
99+ f . id === feature . id ? { ...f , archived : true , archived_note : note } : f
113100 ) ,
114101 active_feature_id :
115102 p . active_feature_id === feature . id
@@ -158,23 +145,6 @@ export function FeatureTab({
158145 await saveWorkspace ( { ...workspace , projects : newProjects } ) ;
159146 } ;
160147
161- const handleStatusChange = async ( status : FeatureStatus ) => {
162- if ( ! workspace ) return ;
163-
164- const newProjects = workspace . projects . map ( ( p ) =>
165- p . id === projectId
166- ? {
167- ...p ,
168- features : p . features . map ( ( f ) =>
169- f . id === feature . id ? { ...f , status } : f
170- ) ,
171- }
172- : p
173- ) ;
174-
175- await saveWorkspace ( { ...workspace , projects : newProjects } ) ;
176- } ;
177-
178148 const handleDoubleClick = ( e : React . MouseEvent ) => {
179149 e . stopPropagation ( ) ;
180150 setRenameValue ( feature . name ) ;
@@ -209,10 +179,6 @@ export function FeatureTab({
209179 { feature . pinned && (
210180 < DrawingPinFilledIcon className = "w-2.5 h-2.5 text-primary/70 flex-shrink-0" />
211181 ) }
212- < span className = "flex-shrink-0" > < StatusIcon status = { feature . status } /> </ span >
213- { feature . seq > 0 && (
214- < span className = "text-[10px] text-muted-foreground/60 flex-shrink-0" > #{ feature . seq } </ span >
215- ) }
216182 { isRenaming ? (
217183 < input
218184 ref = { inputRef }
@@ -226,7 +192,11 @@ export function FeatureTab({
226192 className = "w-16 text-xs bg-card border border-border rounded px-1 outline-none focus:border-primary flex-shrink-0"
227193 />
228194 ) : (
229- < span className = "text-xs truncate min-w-0" title = { feature . name } >
195+ < span
196+ className = "text-xs truncate min-w-0 cursor-grab active:cursor-grabbing"
197+ title = { feature . name }
198+ { ...dragHandleProps }
199+ >
230200 { feature . name }
231201 </ span >
232202 ) }
@@ -259,51 +229,36 @@ export function FeatureTab({
259229 < DrawingPinFilledIcon className = "w-3.5 h-3.5" />
260230 { feature . pinned ? "Unpin" : "Pin" }
261231 </ ContextMenuItem >
232+ < ContextMenuSeparator />
262233 < ContextMenuSub >
263234 < ContextMenuSubTrigger className = "gap-2" >
264- < StatusIcon status = { feature . status } />
265- Status
235+ < ArchiveIcon className = "w-3.5 h-3.5" />
236+ Archive
266237 </ ContextMenuSubTrigger >
267238 < ContextMenuSubContent className = "min-w-[120px]" >
268239 < ContextMenuItem
269- onClick = { ( ) => handleStatusChange ( "pending" ) }
270- disabled = { feature . status === "pending" }
240+ onClick = { ( ) => handleArchive ( "completed" ) }
271241 className = "gap-2 cursor-pointer"
272242 >
273- < TimerIcon className = "w-3.5 h-3.5 text-muted-foreground" />
274- Pending
275- </ ContextMenuItem >
276- < ContextMenuItem
277- onClick = { ( ) => handleStatusChange ( "running" ) }
278- disabled = { feature . status === "running" }
279- className = "gap-2 cursor-pointer"
280- >
281- < UpdateIcon className = "w-3.5 h-3.5 text-blue-500" />
282- Running
243+ < CheckCircledIcon className = "w-3.5 h-3.5 text-green-500" />
244+ Completed
283245 </ ContextMenuItem >
284246 < ContextMenuItem
285- onClick = { ( ) => handleStatusChange ( "completed" ) }
286- disabled = { feature . status === "completed" }
247+ onClick = { ( ) => handleArchive ( "cancelled" ) }
287248 className = "gap-2 cursor-pointer"
288249 >
289- < CheckCircledIcon className = "w-3.5 h-3.5 text-green-500 " />
290- Completed
250+ < Cross2Icon className = "w-3.5 h-3.5 text-muted-foreground " />
251+ Cancelled
291252 </ ContextMenuItem >
292253 < ContextMenuItem
293- onClick = { ( ) => handleStatusChange ( "needs-review" ) }
294- disabled = { feature . status === "needs-review" }
254+ onClick = { ( ) => handleArchive ( "on-hold" ) }
295255 className = "gap-2 cursor-pointer"
296256 >
297- < ExclamationTriangleIcon className = "w-3.5 h-3.5 text-amber-500" />
298- Needs Review
257+ < TimerIcon className = "w-3.5 h-3.5 text-amber-500" />
258+ On Hold
299259 </ ContextMenuItem >
300260 </ ContextMenuSubContent >
301261 </ ContextMenuSub >
302- < ContextMenuSeparator />
303- < ContextMenuItem onClick = { handleArchive } className = "gap-2 cursor-pointer" >
304- < ArchiveIcon className = "w-3.5 h-3.5" />
305- Archive
306- </ ContextMenuItem >
307262 < ContextMenuItem
308263 onClick = { handleDelete }
309264 className = "gap-2 cursor-pointer text-destructive focus:text-destructive"
@@ -317,7 +272,7 @@ export function FeatureTab({
317272}
318273
319274// Sortable wrapper for drag-and-drop
320- export function SortableFeatureTab ( props : Omit < FeatureTabProps , "isDragging" > ) {
275+ export function SortableFeatureTab ( props : Omit < FeatureTabProps , "isDragging" | "dragHandleProps" > ) {
321276 const {
322277 attributes,
323278 listeners,
@@ -333,8 +288,8 @@ export function SortableFeatureTab(props: Omit<FeatureTabProps, "isDragging">) {
333288 } ;
334289
335290 return (
336- < div ref = { setNodeRef } style = { style } { ...attributes } { ... listeners } className = "flex-shrink-0" >
337- < FeatureTab { ...props } isDragging = { isDragging } />
291+ < div ref = { setNodeRef } style = { style } { ...attributes } className = "flex-shrink-0" >
292+ < FeatureTab { ...props } isDragging = { isDragging } dragHandleProps = { listeners } />
338293 </ div >
339294 ) ;
340295}
0 commit comments