feat: Introduce spatial workspace architecture design document, enhance layout store item synchronization, and prevent metadata fetch retries.

This commit is contained in:
2025-11-26 22:03:09 +01:00
parent e36732cc2d
commit 0c6504ef1c
3 changed files with 40 additions and 10 deletions
+16 -2
View File
@@ -124,10 +124,24 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
useEffect(() => { useEffect(() => {
if (tenantId && viewId) { if (tenantId && viewId) {
// Clear store when switching views to prevent stale items
layoutStore.clear();
layoutStore.loadLayout(String(tenantId), viewId); layoutStore.loadLayout(String(tenantId), viewId);
} }
}, [layoutStore, 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 // Selection Context
const { const {
selectedDocumentIds, selectedDocumentIds,
@@ -216,8 +230,8 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
const size = ensureDocumentSize(doc); const size = ensureDocumentSize(doc);
const layoutCard = layoutStore.initialize(docId, null, { const layoutCard = layoutStore.initialize(docId, null, {
width: size.width, width: Number.isFinite(size.width) && size.width > 0 ? size.width : 200,
height: size.height height: Number.isFinite(size.height) && size.height > 0 ? size.height : 200
}); });
return ( return (
+6
View File
@@ -363,6 +363,12 @@ export class LayoutStore {
this.items.delete(id); this.items.delete(id);
} }
clear() {
this.items.clear();
this.zCounter = 100;
this.savedLayouts.clear();
}
setContainerSize(width: number, height: number) { setContainerSize(width: number, height: number) {
this.containerWidth = width; this.containerWidth = width;
this.containerHeight = height; this.containerHeight = height;
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react'; import { useEffect, useState, useRef } from 'react';
import type { DocumentId } from '../../types/identifiers'; import type { DocumentId } from '../../types/identifiers';
import type { Document } from '../../types/documents'; import type { Document } from '../../types/documents';
@@ -22,6 +22,7 @@ const usePreviewMetadata = (
ensureAssetUrl?: EnsureAssetUrl, ensureAssetUrl?: EnsureAssetUrl,
) => { ) => {
const [metadataMap, setMetadataMap] = useState<Map<string, PreviewMetadataEntry>>(() => new Map()); const [metadataMap, setMetadataMap] = useState<Map<string, PreviewMetadataEntry>>(() => new Map());
const failedIds = useRef(new Set<string>()); // Track failed fetches to prevent loops
useEffect(() => { useEffect(() => {
let cancelled = false; let cancelled = false;
@@ -51,14 +52,23 @@ const usePreviewMetadata = (
Number(meta.height) > 0; Number(meta.height) > 0;
if (!hasDimensions(metadata) && ensureAssetUrl && docId && asset?.id) { if (!hasDimensions(metadata) && ensureAssetUrl && docId && asset?.id) {
try { // Skip if we already failed for this doc to avoid infinite loops
const ensured = await ensureAssetUrl(doc.id, asset); if (!failedIds.current.has(docId)) {
if (ensured) { try {
asset = ensured; const ensured = await ensureAssetUrl(doc.id, asset);
metadata = (asset?.metadata as { width?: number; height?: number } | null) || null; 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);
} }
} }