Skip to content

Commit 1ae209e

Browse files
committed
Merge aligned backend and finish file UI review fixes
2 parents f4b0247 + 5dbd5ca commit 1ae209e

51 files changed

Lines changed: 36641 additions & 6074 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎apps/sim/app/workspace/[workspaceId]/files/components/file-copy-modal.test.tsx‎

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -86,23 +86,12 @@ it.each([
8686
[false, true],
8787
[true, false],
8888
[false, false],
89-
])(
90-
'stops Project destination reads and pagination after flags become %s/%s',
91-
async (projects, projectFiles) => {
92-
await render(true, true)
93-
await act(async () => vi.advanceTimersByTimeAsync(10))
94-
expect(document.body.textContent).toContain('Load more Projects')
95-
const selector = document.querySelector('[aria-label="Copy destination"]')
96-
if (!selector) throw new Error('Copy destination selector is unavailable')
97-
await act(async () =>
98-
selector.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }))
99-
)
100-
expect(document.body.textContent).toContain('Cached Project')
101-
requests.length = 0
102-
await render(projects, projectFiles)
103-
await act(async () => client.invalidateQueries())
104-
expect(requests.filter((url) => url.startsWith('/api/projects'))).toEqual([])
105-
expect(document.body.textContent).not.toContain('Load more Projects')
106-
expect(document.body.textContent).not.toContain('Cached Project')
107-
}
108-
)
89+
])('stops Project destination reads after flags become %s/%s', async (projects, projectFiles) => {
90+
await render(true, true)
91+
await act(async () => vi.advanceTimersByTimeAsync(10))
92+
expect(requests.some((url) => url.startsWith('/api/projects'))).toBe(true)
93+
requests.length = 0
94+
await render(projects, projectFiles)
95+
await act(async () => client.invalidateQueries())
96+
expect(requests.filter((url) => url.startsWith('/api/projects'))).toEqual([])
97+
})

‎apps/sim/app/workspace/[workspaceId]/files/components/file-copy-modal.tsx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ function FileCopyDestinationPicker({ source, onClose }: FileCopyModalProps) {
9797
title='Destination'
9898
hint='Copies saved content. The original files stay in their current location.'
9999
error={
100-
workspaces.isError && (!projectDestinationsEnabled || projects.isError)
101-
? 'Could not load destinations.'
100+
workspaces.isError || (projectDestinationsEnabled && projects.isError)
101+
? 'Could not load all destinations.'
102102
: undefined
103103
}
104104
>

‎apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/docx-preview.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export const DocxPreview = memo(function DocxPreview({
7373
const containerRef = useRef<HTMLDivElement>(null)
7474
const scrollContainerRef = useRef<HTMLDivElement>(null)
7575
const zoomPercentRef = useRef(100)
76-
const preview = useDocPreviewBinary(workspaceId, file)
76+
const preview = useDocPreviewBinary({ workspaceId, file })
7777
const fileData = preview.data
7878
const [renderError, setRenderError] = useState<string | null>(null)
7979
const [rendering, setRendering] = useState(false)

‎apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/file-viewer.tsx‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ const IframePreview = memo(function IframePreview({
401401
file: ViewerFileRecord
402402
workspaceId: string | undefined
403403
}) {
404-
const preview = useDocPreviewBinary(workspaceId, file)
404+
const preview = useDocPreviewBinary({ workspaceId, file })
405405

406406
const bufferSource = useMemo<PdfDocumentSource | null>(
407407
() => (preview.data ? { kind: 'buffer', buffer: preview.data } : null),
@@ -422,7 +422,13 @@ const IframePreview = memo(function IframePreview({
422422
)
423423
})
424424

425-
function useBlobUrl(workspaceId: string | undefined, fileId: string, fileKey: string) {
425+
interface UseBlobUrlProps {
426+
workspaceId: string | undefined
427+
fileId: string
428+
fileKey: string
429+
}
430+
431+
function useBlobUrl({ workspaceId, fileId, fileKey }: UseBlobUrlProps) {
426432
const { data: fileData, isLoading, error } = useWorkspaceFileBinary(workspaceId, fileId, fileKey)
427433
const [blobUrl, setBlobUrl] = useState<string | null>(null)
428434
const blobUrlRef = useRef<string | null>(null)
@@ -466,7 +472,7 @@ const MediaPreview = memo(function MediaPreview({
466472
error: fetchError,
467473
blobUrl,
468474
replaceBlobUrl,
469-
} = useBlobUrl(workspaceId, file.id, file.key)
475+
} = useBlobUrl({ workspaceId, fileId: file.id, fileKey: file.key })
470476

471477
const mediaType = resolveMediaMimeType(file.type, file.name, kind)
472478

‎apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/pptx-preview.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const PptxPreview = memo(function PptxPreview({
2525
file: ViewerFileRecord
2626
workspaceId: string | undefined
2727
}) {
28-
const preview = useDocPreviewBinary(workspaceId, file)
28+
const preview = useDocPreviewBinary({ workspaceId, file })
2929
const fileData = preview.data
3030
const cacheKey = pptxCacheKey(file.id, preview.dataUpdatedAt, fileData?.byteLength ?? 0)
3131

‎apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/rich-markdown-editor.tsx‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,11 @@ function ReadOnlyPlaceholder({ content, file, workspaceId }: ReadOnlyPlaceholder
206206
() => buildEditorSelectionContext(editor, { id: file.id, name: file.name }, projectOwner),
207207
[editor, file.id, file.name, projectOwner]
208208
)
209-
useSelectionCopyBridge(containerRef, buildSelectionContext, projectOwner ?? workspaceId)
209+
useSelectionCopyBridge({
210+
containerRef,
211+
buildContext: buildSelectionContext,
212+
owner: projectOwner ?? workspaceId,
213+
})
210214
return (
211215
<>
212216
{editor && <LinkHoverCard editor={editor} />}
@@ -1410,12 +1414,12 @@ export function LoadedRichMarkdownEditor({
14101414
]
14111415
)
14121416

1413-
useSelectionCopyBridge(
1417+
useSelectionCopyBridge({
14141418
containerRef,
1415-
buildSelectionContext,
1416-
projectOwner ?? workspaceId,
1417-
!showPlaceholder
1418-
)
1419+
buildContext: buildSelectionContext,
1420+
owner: projectOwner ?? workspaceId,
1421+
enabled: !showPlaceholder,
1422+
})
14191423

14201424
/**
14211425
* Find is off while the placeholder is up. The text on screen then belongs to the placeholder's own

‎apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/text-editor.tsx‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -535,12 +535,12 @@ export const TextEditor = memo(function TextEditor({
535535

536536
// Enable once content has loaded — the container (and Monaco) only mount after
537537
// the `isContentLoading` early return below, so the bridge must (re-)attach then.
538-
useSelectionCopyBridge(
538+
useSelectionCopyBridge({
539539
containerRef,
540-
buildSelectionContext,
541-
projectOwner ?? workspaceId,
542-
!isContentLoading
543-
)
540+
buildContext: buildSelectionContext,
541+
owner: projectOwner ?? workspaceId,
542+
enabled: !isContentLoading,
543+
})
544544

545545
useEffect(() => {
546546
if (lastEditorValueRef.current === content) return

‎apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/use-doc-preview-binary.ts‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ export function stepDocPreviewBinary({
113113
return { resolved, hasResolvedForFile, lastGood: resolved.lastGood }
114114
}
115115

116+
interface UseDocPreviewBinaryProps {
117+
workspaceId: string | undefined
118+
file: DocPreviewFile
119+
}
120+
116121
/**
117122
* Resolves the compiled binary to render for a generated or uploaded document and
118123
* retains the last successfully fetched binary as a fallback.
@@ -126,10 +131,10 @@ export function stepDocPreviewBinary({
126131
* placeholder (which still holds the prior file's bytes) is ignored until a fresh
127132
* binary resolves for the new file, so one viewer never renders another file's content.
128133
*/
129-
export function useDocPreviewBinary(
130-
workspaceId: string | undefined,
131-
file: DocPreviewFile
132-
): DocPreviewBinary {
134+
export function useDocPreviewBinary({
135+
workspaceId,
136+
file,
137+
}: UseDocPreviewBinaryProps): DocPreviewBinary {
133138
const query = useWorkspaceFileBinary(workspaceId, file.id, file.key, {
134139
enabled: (file.size ?? 0) > 0,
135140
version: Number(new Date(file.updatedAt)) || file.size,

‎apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/use-selection-copy-bridge.ts‎

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ import { attachSelectionContextToClipboard } from '@/lib/mothership/chat/selecti
55
import type { FileOperationOwner } from '@/lib/mothership/generated/file-owner'
66
import type { ChatContext } from '@/stores/panel'
77

8+
interface UseSelectionCopyBridgeProps {
9+
containerRef: RefObject<HTMLElement | null>
10+
/** Returns null when there is no non-empty selection. */
11+
buildContext: () => ChatContext | null
12+
owner: string | FileOperationOwner | undefined
13+
/** Reattaches when a loading gate mounts the container, since a ref is not reactive. */
14+
enabled?: boolean
15+
}
16+
817
/**
918
* Rides a selection {@link ChatContext} onto the editor's native copy so a
1019
* highlighted passage copied with Cmd+C pastes into Chat as a reference chip.
@@ -13,18 +22,13 @@ import type { ChatContext } from '@/stores/panel'
1322
* handler — Monaco and ProseMirror both `clearData()` before writing
1423
* `text/plain`, so the custom type must be added last to survive.
1524
*
16-
* @param buildContext - Returns null when there is no non-empty selection.
17-
* @param workspaceId - Workspace that owns the selected resource.
18-
* @param enabled - Re-runs the effect for a container that mounts late (behind a
19-
* loading gate); a ref isn't reactive, so the effect would otherwise bail on the
20-
* first render and never re-attach.
2125
*/
22-
export function useSelectionCopyBridge(
23-
containerRef: RefObject<HTMLElement | null>,
24-
buildContext: () => ChatContext | null,
25-
owner: string | FileOperationOwner | undefined,
26-
enabled = true
27-
): void {
26+
export function useSelectionCopyBridge({
27+
containerRef,
28+
buildContext,
29+
owner,
30+
enabled = true,
31+
}: UseSelectionCopyBridgeProps): void {
2832
useEffect(() => {
2933
const dom = containerRef.current
3034
if (!dom || !enabled || !owner) return

‎apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/xlsx-preview.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export const XlsxPreview = memo(function XlsxPreview({
3636
workspaceId: string | undefined
3737
}) {
3838
const scrollRef = useHorizontalWheelScroll()
39-
const preview = useDocPreviewBinary(workspaceId, file)
39+
const preview = useDocPreviewBinary({ workspaceId, file })
4040
const fileData = preview.data
4141

4242
const [sheetNames, setSheetNames] = useState<string[]>([])

0 commit comments

Comments
 (0)