diff --git a/frontend/src/desktop/DesktopWorkspace.tsx b/frontend/src/desktop/DesktopWorkspace.tsx index f39642f..a0b53b1 100644 --- a/frontend/src/desktop/DesktopWorkspace.tsx +++ b/frontend/src/desktop/DesktopWorkspace.tsx @@ -124,10 +124,24 @@ const DesktopWorkspace: React.FC = ({ useEffect(() => { if (tenantId && viewId) { + // Clear store when switching views to prevent stale items + layoutStore.clear(); layoutStore.loadLayout(String(tenantId), viewId); } }, [layoutStore, tenantId, viewId]); + // Sync LayoutStore items with current entries to remove stale items + useEffect(() => { + const currentIds = new Set(items.map((doc, index) => doc.id ? String(doc.id) : `temp-${index}`)); + + // Identify and remove items that are no longer present + for (const id of layoutStore.items.keys()) { + if (!currentIds.has(id)) { + layoutStore.unregister(id); + } + } + }, [items, layoutStore]); + // Selection Context const { selectedDocumentIds, @@ -216,8 +230,8 @@ const DesktopWorkspace: React.FC = ({ const size = ensureDocumentSize(doc); const layoutCard = layoutStore.initialize(docId, null, { - width: size.width, - height: size.height + width: Number.isFinite(size.width) && size.width > 0 ? size.width : 200, + height: Number.isFinite(size.height) && size.height > 0 ? size.height : 200 }); return ( diff --git a/frontend/src/desktop/LayoutSystem.ts b/frontend/src/desktop/LayoutSystem.ts index b19afcb..ded71b7 100644 --- a/frontend/src/desktop/LayoutSystem.ts +++ b/frontend/src/desktop/LayoutSystem.ts @@ -363,6 +363,12 @@ export class LayoutStore { this.items.delete(id); } + clear() { + this.items.clear(); + this.zCounter = 100; + this.savedLayouts.clear(); + } + setContainerSize(width: number, height: number) { this.containerWidth = width; this.containerHeight = height; diff --git a/frontend/src/desktop/hooks/usePreviewMetadata.ts b/frontend/src/desktop/hooks/usePreviewMetadata.ts index ab8901e..86dfa04 100644 --- a/frontend/src/desktop/hooks/usePreviewMetadata.ts +++ b/frontend/src/desktop/hooks/usePreviewMetadata.ts @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import { useEffect, useState, useRef } from 'react'; import type { DocumentId } from '../../types/identifiers'; import type { Document } from '../../types/documents'; @@ -22,6 +22,7 @@ const usePreviewMetadata = ( ensureAssetUrl?: EnsureAssetUrl, ) => { const [metadataMap, setMetadataMap] = useState>(() => new Map()); + const failedIds = useRef(new Set()); // Track failed fetches to prevent loops useEffect(() => { let cancelled = false; @@ -51,14 +52,23 @@ const usePreviewMetadata = ( Number(meta.height) > 0; if (!hasDimensions(metadata) && ensureAssetUrl && docId && asset?.id) { - try { - const ensured = await ensureAssetUrl(doc.id, asset); - if (ensured) { - asset = ensured; - metadata = (asset?.metadata as { width?: number; height?: number } | null) || null; + // Skip if we already failed for this doc to avoid infinite loops + if (!failedIds.current.has(docId)) { + try { + const ensured = await ensureAssetUrl(doc.id, asset); + if (ensured) { + asset = ensured; + metadata = (asset?.metadata as { width?: number; height?: number } | null) || null; + } + + // If still no dimensions, mark as failed so we don't try again + if (!hasDimensions(metadata)) { + failedIds.current.add(docId); + } + } catch (error) { + console.warn('[desk] ensureDocumentSize metadata fetch failed', error); + failedIds.current.add(docId); } - } catch (error) { - console.warn('[desk] ensureDocumentSize metadata fetch failed', error); } }