()
| 74 | } |
| 75 | |
| 76 | export function WorkflowList() { |
| 77 | const navigate = useNavigate(); |
| 78 | const [workflows, setWorkflows] = useState<WorkflowMetadataNormalized[]>([]); |
| 79 | const [isLoading, setIsLoading] = useState(true); |
| 80 | const [error, setError] = useState<string | null>(null); |
| 81 | const [retryCount, setRetryCount] = useState(0); |
| 82 | const retryCountRef = useRef(0); // Use ref to track actual count |
| 83 | const retryTimeoutRef = useRef<NodeJS.Timeout | null>(null); |
| 84 | const roles = useAuthStore((state) => state.roles); |
| 85 | const canManageWorkflows = hasAdminRole(roles); |
| 86 | const isReadOnly = !canManageWorkflows; |
| 87 | const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); |
| 88 | const [workflowToDelete, setWorkflowToDelete] = useState<WorkflowMetadataNormalized | null>(null); |
| 89 | const [deleteError, setDeleteError] = useState<string | null>(null); |
| 90 | const [isDeleting, setIsDeleting] = useState(false); |
| 91 | const { isAuthenticated, isLoading: authLoading } = useAuth(); |
| 92 | const token = useAuthStore((state) => state.token); |
| 93 | const adminUsername = useAuthStore((state) => state.adminUsername); |
| 94 | |
| 95 | const sensors = useSensors( |
| 96 | useSensor(PointerSensor, { activationConstraint: { distance: 5 } }), |
| 97 | useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }), |
| 98 | ); |
| 99 | |
| 100 | const handleDragEnd = useCallback((event: DragEndEvent) => { |
| 101 | const { active, over } = event; |
| 102 | if (!over || active.id === over.id) return; |
| 103 | setWorkflows((prev) => { |
| 104 | const oldIndex = prev.findIndex((w) => w.id === active.id); |
| 105 | const newIndex = prev.findIndex((w) => w.id === over.id); |
| 106 | if (oldIndex !== -1 && newIndex !== -1) { |
| 107 | const reordered = arrayMove(prev, oldIndex, newIndex); |
| 108 | saveOrder(reordered.map((w) => w.id)); |
| 109 | return reordered; |
| 110 | } |
| 111 | return prev; |
| 112 | }); |
| 113 | }, []); |
| 114 | |
| 115 | const MAX_RETRY_ATTEMPTS = 30; // Try for ~60 seconds (30 attempts × 2s) |
| 116 | const RETRY_INTERVAL_MS = 2000; // 2 seconds between retries |
| 117 | |
| 118 | useEffect(() => { |
| 119 | // Wait for auth to be ready before loading workflows |
| 120 | if (authLoading) { |
| 121 | return; |
| 122 | } |
| 123 | |
| 124 | // Check if we have authentication (either token or admin credentials) |
| 125 | const hasAuth = isAuthenticated || token || adminUsername; |
| 126 | |
| 127 | if (hasAuth) { |
| 128 | loadWorkflows(); |
| 129 | } else { |
| 130 | setIsLoading(false); |
| 131 | setError('Please log in to view workflows'); |
| 132 | } |
| 133 | }, [isAuthenticated, authLoading, token, adminUsername]); |
nothing calls this directly
no test coverage detected