Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,10 @@ interface FileViewerProps {

export function FileViewer(props: FileViewerProps) {
const { contentSource, workspaceId } = props
const imageDimensions = useWorkspaceImageDimensionsAdapter(workspaceId)
// A caller-supplied contentSource means the adapter is unused (and its `workspaceId` may be a share token).
const imageDimensions = useWorkspaceImageDimensionsAdapter(workspaceId, {
enabled: !contentSource,
})
const source = useMemo(
() => contentSource ?? createWorkspaceFileContentSource(workspaceId, imageDimensions),
[contentSource, workspaceId, imageDimensions]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function fakeNode(attrs: Record<string, unknown>) {
}

function fakeEditor(): Editor {
return { storage: { mention: { navigable: false } } } as unknown as Editor
return { storage: { mentionMenu: { navigable: false } } } as unknown as Editor
}

let container: HTMLDivElement | null = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function MentionChipView({ node, editor }: ReactNodeViewProps) {
const { kind, id, label } = node.attrs as MentionAttrs
const Icon = mentionIcon(kind, id, label) as StyleableIcon | undefined
const iconStyle = Icon ? getBareIconStyle(Icon) : undefined
const navigable = editor.storage.mention?.navigable === true
const navigable = editor.storage.mentionMenu?.navigable === true
Comment thread
waleedlatif1 marked this conversation as resolved.
const workspaceId = typeof params.workspaceId === 'string' ? params.workspaceId : undefined
const path = navigable && workspaceId ? simLinkPath(workspaceId, kind, id) : null

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export interface MentionStorage {

declare module '@tiptap/core' {
interface Storage {
mention: MentionStorage
mentionMenu: MentionStorage
}
}

Expand All @@ -35,10 +35,10 @@ declare module '@tiptap/core' {
* entity inserts it as a portable `sim:<kind>/<id>` markdown link (same wire format as the chat
* composer's `chip-clipboard-codec`), so it round-trips natively through the editor's link + markdown
* machinery. The plugin's `items` is an empty gate; the real list is sourced reactively from the store
* inside {@link MentionList}, populated by the host via the extension's `mention` storage.
* inside {@link MentionList}, populated by the host via the extension's `mentionMenu` storage.
*/
export const Mention = Extension.create<Record<string, never>, MentionStorage>({
name: 'mention',
name: 'mentionMenu',

addStorage() {
return { store: createMentionStore(), onOpen: null, enabled: true, navigable: false }
Expand All @@ -53,7 +53,7 @@ export const Mention = Extension.create<Record<string, never>, MentionStorage>({
allowSpaces: false,
startOfLine: false,
allow: ({ editor, range }) => {
if (!editor.storage.mention.enabled) return false
if (!editor.storage.mentionMenu.enabled) return false
if (editor.isActive('codeBlock') || editor.isActive('link') || editor.isActive('code')) {
return false
}
Expand All @@ -78,10 +78,10 @@ export const Mention = Extension.create<Record<string, never>, MentionStorage>({
mapProps: (props) => ({
query: props.query,
command: props.command,
store: props.editor.storage.mention.store,
store: props.editor.storage.mentionMenu.store,
editor: props.editor,
}),
onOpen: (props) => props.editor.storage.mention?.onOpen?.(),
onOpen: (props) => props.editor.storage.mentionMenu?.onOpen?.(),
}),
}),
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ export function useEditorMentions(
useEffect(() => {
if (!editor) return
const taggingOn = Boolean(workspaceId) && !disableTagging
editor.storage.mention.enabled = taggingOn
editor.storage.mention.navigable = navigable
editor.storage.mention.onOpen = taggingOn ? () => setActive(true) : null
editor.storage.mentionMenu.enabled = taggingOn
editor.storage.mentionMenu.navigable = navigable
editor.storage.mentionMenu.onOpen = taggingOn ? () => setActive(true) : null
return () => {
editor.storage.mention.onOpen = null
editor.storage.mentionMenu.onOpen = null
}
}, [editor, workspaceId, navigable, disableTagging])

useEffect(() => {
editor?.storage.mention.store.set(items)
editor?.storage.mentionMenu.store.set(items)
}, [editor, items])
}
28 changes: 18 additions & 10 deletions apps/sim/hooks/queries/workspace-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,20 +142,28 @@ export function useWorkspaceFiles(
}

/**
* Back the file content source's image-dimension capability with workspace file metadata. Reads intrinsic
* dimensions synchronously from the already-loaded active file list (so a stored image reserves its box on
* the first render), and persists the browser's measured dimensions when they're absent or disagree with
* what's stored — an overwrite, so a stale value (left over after a content swap, or a non-EXIF-corrected
* one) self-corrects rather than sticking. The write is fire-and-forget and de-duped (an exact-match cache
* check plus mismatch-only reporting from the caller), so it never storms, never blocks render, and never
* touches the collaborative document.
* Back the file content source's image-dimension capability with workspace file metadata. Subscribes to
* the active file list ({@link useWorkspaceFiles}) and reads each image's stored intrinsic dimensions from
* it, so a stored image reserves its box before it downloads. A reactive read (not a one-shot
* `getQueryData`), so it also works on a cold direct file-view load where the list isn't cached until after
* the image first renders: the subscription re-runs the node view's dimension read once the list resolves.
* Persists the browser's measured dimensions when they're absent or disagree with what's stored — an
* overwrite, so a stale value (left over after a content swap, or a non-EXIF-corrected one) self-corrects
* rather than sticking. The write is fire-and-forget and de-duped (an exact-match cache check plus
* mismatch-only reporting from the caller), so it never storms, never blocks render, and never touches the
* collaborative document. `options.enabled` turns the subscription off for callers that supply their own
* content source (the public share page, whose `workspaceId` is a share token that would 404).
*/
export function useWorkspaceImageDimensionsAdapter(workspaceId: string): ImageDimensionsSource {
export function useWorkspaceImageDimensionsAdapter(
workspaceId: string,
options?: { enabled?: boolean }
): ImageDimensionsSource {
const queryClient = useQueryClient()
const { data: files } = useWorkspaceFiles(workspaceId, 'active', options)
return useMemo<ImageDimensionsSource>(() => {
const listKey = workspaceFilesKeys.list(workspaceId, 'active')
const findRecord = (src: string | undefined): WorkspaceFileRecord | undefined =>
findWorkspaceFileBySrc(queryClient.getQueryData<WorkspaceFileRecord[]>(listKey), src)
findWorkspaceFileBySrc(files, src)
return {
getImageDimensions: (src) => {
const record = findRecord(src)
Expand Down Expand Up @@ -194,7 +202,7 @@ export function useWorkspaceImageDimensionsAdapter(workspaceId: string): ImageDi
.catch(() => {})
},
}
}, [queryClient, workspaceId])
}, [files, queryClient, workspaceId])
}

/**
Expand Down
Loading