mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-02 00:18:17 +00:00
Surface gallery load errors with message and copy-to-clipboard (#1356)
When listUserMediaFiles fails (HTTP error, network error, null reference, or any other exception), the gallery now shows the error message with a "Copy error" button instead of silently falling through to "No items yet". This is a diagnostic aid for a macOS-only blank gallery bug where the root cause is unknown (CORS, session cookie, or runtime exception) and there is no access to production logs.
This commit is contained in:
1 parent
b7c8151d28
commit
44cadf84cc
1 file changed
+31
-1
@@ -401,6 +401,9 @@ export const GalleryModal = React.memo(
|
||||
// Track whether this is the very first load (no cache, no items yet)
|
||||
const [initialLoading, setInitialLoading] = useState(false);
|
||||
|
||||
// Error message from failed listUserMediaFiles call (null = no error)
|
||||
const [itemsLoadError, setItemsLoadError] = useState<string | null>(null);
|
||||
|
||||
// Bulk selection state (view mode only)
|
||||
const [bulkSelectedIds, setBulkSelectedIds] = useState<Set<string>>(
|
||||
new Set(),
|
||||
@@ -545,6 +548,7 @@ export const GalleryModal = React.memo(
|
||||
const response = await api.listUserMediaFiles(query);
|
||||
|
||||
if (response.success && response.data) {
|
||||
setItemsLoadError(null);
|
||||
const newItems = response.data
|
||||
.filter(
|
||||
(item: any) => item.media_type !== FilterMediaType.SCENE_JSON,
|
||||
@@ -589,9 +593,13 @@ export const GalleryModal = React.memo(
|
||||
});
|
||||
return latest;
|
||||
});
|
||||
} else {
|
||||
setItemsLoadError(response.errorMessage || "Request failed (unknown error)");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch library items:", error);
|
||||
const msg = error instanceof Error ? error.message : String(error);
|
||||
console.error("Failed to fetch library items:", msg);
|
||||
setItemsLoadError(msg);
|
||||
}
|
||||
setLoading(false);
|
||||
setPaginationLoading(false);
|
||||
@@ -603,6 +611,7 @@ export const GalleryModal = React.memo(
|
||||
|
||||
// refresh logic — shows cached items immediately, then background-refreshes
|
||||
const refreshGallery = useCallback(() => {
|
||||
setItemsLoadError(null);
|
||||
const cacheKey = `gallery_${activeFilterRef.current}`;
|
||||
const cached = galleryCacheMap.get(cacheKey);
|
||||
|
||||
@@ -1139,6 +1148,27 @@ export const GalleryModal = React.memo(
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : itemsLoadError && allItems.length === 0 ? (
|
||||
<div className="flex h-full items-center justify-center">
|
||||
<div className="flex flex-col items-center gap-3 text-sm max-w-xs text-center">
|
||||
<div className="text-base-fg/60">Failed to load gallery.</div>
|
||||
<div className="text-xs text-base-fg/40 font-mono break-all">{itemsLoadError}</div>
|
||||
<div className="flex gap-3">
|
||||
<button
|
||||
className="text-xs text-blue-400 hover:text-blue-300 underline"
|
||||
onClick={() => navigator.clipboard?.writeText(itemsLoadError!)}
|
||||
>
|
||||
Copy error
|
||||
</button>
|
||||
<button
|
||||
className="text-xs text-blue-400 hover:text-blue-300 underline"
|
||||
onClick={() => refreshGallery()}
|
||||
>
|
||||
Retry
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (initialLoading || !username) && allItems.length === 0 ? (
|
||||
<SkeletonGrid columns={gridColumns} />
|
||||
) : allItems.length === 0 && !loading ? (
|
||||
|
||||
Reference in new issue
Block a user