()
| 128 | } |
| 129 | |
| 130 | export default function RequestView() { |
| 131 | const [requests, setRequests] = useState<Request[]>([]); |
| 132 | const [sourceTypes, setSourceTypes] = useState<Record<string, DatabaseType>>({}); |
| 133 | const [toolReadonly, setToolReadonly] = useState<Record<string, boolean>>({}); |
| 134 | const [isLoading, setIsLoading] = useState(true); |
| 135 | const [error, setError] = useState<string | null>(null); |
| 136 | const [selectedSource, setSelectedSource] = useState<string | null>(null); |
| 137 | |
| 138 | useEffect(() => { |
| 139 | Promise.all([fetchRequests(), fetchSources()]) |
| 140 | .then(([requestsData, sourcesData]) => { |
| 141 | setRequests(requestsData.requests); |
| 142 | const typeMap: Record<string, DatabaseType> = {}; |
| 143 | const readonlyMap: Record<string, boolean> = {}; |
| 144 | for (const source of sourcesData) { |
| 145 | typeMap[source.id] = source.type; |
| 146 | for (const tool of source.tools) { |
| 147 | if (tool.readonly) { |
| 148 | readonlyMap[tool.name] = true; |
| 149 | } |
| 150 | } |
| 151 | } |
| 152 | setSourceTypes(typeMap); |
| 153 | setToolReadonly(readonlyMap); |
| 154 | setIsLoading(false); |
| 155 | }) |
| 156 | .catch((err) => { |
| 157 | console.error('Failed to fetch data:', err); |
| 158 | const message = err instanceof ApiError ? err.message : 'Failed to load data'; |
| 159 | setError(message); |
| 160 | setIsLoading(false); |
| 161 | }); |
| 162 | }, []); |
| 163 | |
| 164 | // Get unique source IDs from requests |
| 165 | const sourceIds = [...new Set(requests.map((r) => r.sourceId))].sort(); |
| 166 | |
| 167 | // Filter requests based on selected source |
| 168 | const filteredRequests = selectedSource |
| 169 | ? requests.filter((r) => r.sourceId === selectedSource) |
| 170 | : requests; |
| 171 | |
| 172 | if (isLoading) { |
| 173 | return ( |
| 174 | <div className="container mx-auto px-8 py-12"> |
| 175 | <div className="text-muted-foreground">Loading...</div> |
| 176 | </div> |
| 177 | ); |
| 178 | } |
| 179 | |
| 180 | if (error) { |
| 181 | return ( |
| 182 | <div className="container mx-auto px-8 py-12"> |
| 183 | <div className="bg-destructive/10 border border-destructive/20 rounded-lg p-6"> |
| 184 | <h2 className="text-lg font-semibold text-destructive mb-2">Error</h2> |
| 185 | <p className="text-destructive/90">{error}</p> |
| 186 | </div> |
| 187 | </div> |
nothing calls this directly
no test coverage detected