mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-12 16:15:13 +00:00
fix(ui): handle 404 errors in profile settings fetch
- throw on non-OK responses in ProfileEditor queryFn - add isError state with user-friendly message and retry button - add defensive null check for data.path before .replace() call - apply same defensive check to provider-editor.tsx Fixes blank screen when API profile settings file doesn't exist.
This commit is contained in:
1 parent
d746ec77ca
commit
60c01c7e60
2 files changed
+22
-4
No files matched your search
@@ -566,7 +566,7 @@ export function ProviderEditor({
|
|||||||
<div>
|
<div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<h2 className="text-lg font-semibold">{displayName}</h2>
|
<h2 className="text-lg font-semibold">{displayName}</h2>
|
||||||
{data && (
|
{data?.path && (
|
||||||
<Badge variant="outline" className="text-xs">
|
<Badge variant="outline" className="text-xs">
|
||||||
{data.path.replace(/^.*\//, '')}
|
{data.path.replace(/^.*\//, '')}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
|||||||
@@ -46,9 +46,15 @@ export function ProfileEditor({ profileName, onDelete }: ProfileEditorProps) {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
// Fetch settings for selected profile
|
// Fetch settings for selected profile
|
||||||
const { data, isLoading, refetch } = useQuery<SettingsResponse>({
|
const { data, isLoading, isError, refetch } = useQuery<SettingsResponse>({
|
||||||
queryKey: ['settings', profileName],
|
queryKey: ['settings', profileName],
|
||||||
queryFn: () => fetch(`/api/settings/${profileName}/raw`).then((r) => r.json()),
|
queryFn: async () => {
|
||||||
|
const res = await fetch(`/api/settings/${profileName}/raw`);
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(`Failed to load settings: ${res.status}`);
|
||||||
|
}
|
||||||
|
return res.json();
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Derive raw JSON content
|
// Derive raw JSON content
|
||||||
@@ -427,7 +433,7 @@ export function ProfileEditor({ profileName, onDelete }: ProfileEditorProps) {
|
|||||||
<div>
|
<div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<h2 className="text-lg font-semibold">{profileName}</h2>
|
<h2 className="text-lg font-semibold">{profileName}</h2>
|
||||||
{data && (
|
{data?.path && (
|
||||||
<Badge variant="outline" className="text-xs">
|
<Badge variant="outline" className="text-xs">
|
||||||
{data.path.replace(/^.*\//, '')}
|
{data.path.replace(/^.*\//, '')}
|
||||||
</Badge>
|
</Badge>
|
||||||
@@ -473,6 +479,18 @@ export function ProfileEditor({ profileName, onDelete }: ProfileEditorProps) {
|
|||||||
<Loader2 className="w-8 h-8 animate-spin text-muted-foreground" />
|
<Loader2 className="w-8 h-8 animate-spin text-muted-foreground" />
|
||||||
<span className="ml-3 text-muted-foreground">Loading settings...</span>
|
<span className="ml-3 text-muted-foreground">Loading settings...</span>
|
||||||
</div>
|
</div>
|
||||||
|
) : isError ? (
|
||||||
|
<div className="flex-1 flex items-center justify-center">
|
||||||
|
<div className="text-center space-y-3">
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Failed to load settings for this profile.
|
||||||
|
</p>
|
||||||
|
<Button variant="outline" size="sm" onClick={() => refetch()}>
|
||||||
|
<RefreshCw className="w-4 h-4 mr-1" />
|
||||||
|
Retry
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
// Split Layout (40% Left / 60% Right)
|
// Split Layout (40% Left / 60% Right)
|
||||||
<div className="flex-1 grid grid-cols-[40%_60%] divide-x overflow-hidden">
|
<div className="flex-1 grid grid-cols-[40%_60%] divide-x overflow-hidden">
|
||||||
|
|||||||
Reference in new issue
Block a user