Force file content reload when opening paths from terminal links (#5575)
Introduce a `fileContentReloadNonce` on open files and a new `forceContentReload` option for `openFile`. When terminal links or file-open actions re-open an existing clean tab, increment the nonce to trigger a refetch of the file content. This provides a manual recovery path for when remote file watchers miss external writes.
This commit is contained in:
parent
38e289602d
commit
b1563c8dae
|
|
@ -0,0 +1,129 @@
|
|||
// @vitest-environment happy-dom
|
||||
|
||||
import { act } from 'react'
|
||||
import { createRoot, type Root } from 'react-dom/client'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import type { OpenFile } from '@/store/slices/editor'
|
||||
import type { FileContent } from './editor-panel-content-types'
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
readRuntimeFileContent: vi.fn(),
|
||||
getConnectionId: vi.fn(),
|
||||
getState: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('@/runtime/runtime-file-client', () => ({
|
||||
getRuntimeFileReadScope: vi.fn(
|
||||
(
|
||||
settings: { activeRuntimeEnvironmentId?: string | null } | null | undefined,
|
||||
connectionId?: string
|
||||
) => connectionId ?? settings?.activeRuntimeEnvironmentId ?? null
|
||||
),
|
||||
readRuntimeFileContent: mocks.readRuntimeFileContent,
|
||||
subscribeRuntimeFileChanges: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('@/runtime/runtime-git-client', () => ({
|
||||
getRuntimeGitBranchDiff: vi.fn(),
|
||||
getRuntimeGitCommitDiff: vi.fn(),
|
||||
getRuntimeGitDiff: vi.fn(),
|
||||
getRuntimeGitScope: vi.fn(() => null)
|
||||
}))
|
||||
|
||||
vi.mock('@/lib/connection-context', () => ({
|
||||
getConnectionId: mocks.getConnectionId
|
||||
}))
|
||||
|
||||
vi.mock('@/store', () => ({
|
||||
useAppStore: {
|
||||
getState: mocks.getState
|
||||
}
|
||||
}))
|
||||
|
||||
import { useEditorPanelContentState } from './useEditorPanelContentState'
|
||||
|
||||
type ProbeProps = {
|
||||
activeFile: OpenFile
|
||||
openFiles: OpenFile[]
|
||||
}
|
||||
|
||||
let latestFileContents: Record<string, FileContent> = {}
|
||||
|
||||
function HookProbe({ activeFile, openFiles }: ProbeProps): null {
|
||||
latestFileContents = useEditorPanelContentState({
|
||||
activeFile,
|
||||
isChangesMode: false,
|
||||
openFiles,
|
||||
gitStatusByWorktree: {},
|
||||
editorViewMode: {}
|
||||
}).fileContents
|
||||
return null
|
||||
}
|
||||
|
||||
function createOpenFile(overrides: Partial<OpenFile> = {}): OpenFile {
|
||||
return {
|
||||
id: '/repo/file.ts',
|
||||
filePath: '/repo/file.ts',
|
||||
relativePath: 'file.ts',
|
||||
worktreeId: 'wt-1',
|
||||
language: 'typescript',
|
||||
isDirty: false,
|
||||
mode: 'edit',
|
||||
...overrides
|
||||
}
|
||||
}
|
||||
|
||||
describe('useEditorPanelContentState', () => {
|
||||
let container: HTMLDivElement | null = null
|
||||
let root: Root | null = null
|
||||
|
||||
beforeEach(() => {
|
||||
latestFileContents = {}
|
||||
mocks.readRuntimeFileContent.mockReset()
|
||||
mocks.getConnectionId.mockReset()
|
||||
mocks.getConnectionId.mockReturnValue(undefined)
|
||||
mocks.getState.mockReset()
|
||||
mocks.getState.mockReturnValue({ settings: null })
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
if (root) {
|
||||
act(() => root?.unmount())
|
||||
}
|
||||
container?.remove()
|
||||
container = null
|
||||
root = null
|
||||
})
|
||||
|
||||
it('reloads a clean file when its file content reload nonce changes', async () => {
|
||||
const activeFile = createOpenFile()
|
||||
mocks.readRuntimeFileContent
|
||||
.mockResolvedValueOnce({ content: 'old content', isBinary: false })
|
||||
.mockResolvedValueOnce({ content: 'fresh content', isBinary: false })
|
||||
|
||||
container = document.createElement('div')
|
||||
document.body.appendChild(container)
|
||||
root = createRoot(container)
|
||||
|
||||
await act(async () => {
|
||||
root?.render(<HookProbe activeFile={activeFile} openFiles={[activeFile]} />)
|
||||
})
|
||||
|
||||
await vi.waitFor(() => expect(latestFileContents[activeFile.id]?.content).toBe('old content'))
|
||||
|
||||
const reloadedFile = { ...activeFile, fileContentReloadNonce: 1 }
|
||||
await act(async () => {
|
||||
root?.render(<HookProbe activeFile={reloadedFile} openFiles={[reloadedFile]} />)
|
||||
})
|
||||
|
||||
await vi.waitFor(() => expect(latestFileContents[activeFile.id]?.content).toBe('fresh content'))
|
||||
expect(mocks.readRuntimeFileContent).toHaveBeenCalledTimes(2)
|
||||
expect(mocks.readRuntimeFileContent).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({
|
||||
filePath: '/repo/file.ts',
|
||||
relativePath: 'file.ts',
|
||||
worktreeId: 'wt-1'
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
@ -388,6 +388,30 @@ export function useEditorPanelContentState({
|
|||
void loadDiffContent(current, { force: true })
|
||||
}, [activeFile?.diffContentReloadNonce, activeFile?.id, loadDiffContent])
|
||||
|
||||
useEffect(() => {
|
||||
const nonce = activeFile?.fileContentReloadNonce
|
||||
if (!activeFile?.id || nonce === undefined || nonce === 0) {
|
||||
return
|
||||
}
|
||||
const current = openFilesRef.current.find((f) => f.id === activeFile.id)
|
||||
if (
|
||||
!current ||
|
||||
current.isDirty ||
|
||||
(current.mode !== 'edit' && current.mode !== 'markdown-preview')
|
||||
) {
|
||||
return
|
||||
}
|
||||
setFileContents((prev) => {
|
||||
if (!prev[current.id]) {
|
||||
return prev
|
||||
}
|
||||
const next = { ...prev }
|
||||
delete next[current.id]
|
||||
return next
|
||||
})
|
||||
void loadFileContent(current.filePath, current.id, current.worktreeId, current.relativePath)
|
||||
}, [activeFile?.fileContentReloadNonce, activeFile?.filePath, activeFile?.id, loadFileContent])
|
||||
|
||||
useEditorPanelExternalContentEvents({
|
||||
loadDiffContent,
|
||||
loadFileContent,
|
||||
|
|
|
|||
|
|
@ -170,14 +170,17 @@ export function openDetectedFilePath(
|
|||
activateAndRevealWorktree(worktreeId)
|
||||
}
|
||||
|
||||
store.openFile({
|
||||
filePath,
|
||||
relativePath,
|
||||
worktreeId: worktreeId || '',
|
||||
language: detectLanguage(filePath),
|
||||
mode: 'edit',
|
||||
runtimeEnvironmentId
|
||||
})
|
||||
store.openFile(
|
||||
{
|
||||
filePath,
|
||||
relativePath,
|
||||
worktreeId: worktreeId || '',
|
||||
language: detectLanguage(filePath),
|
||||
mode: 'edit',
|
||||
runtimeEnvironmentId
|
||||
},
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
|
||||
if (line !== null) {
|
||||
const targetColumn = column ?? 1
|
||||
|
|
|
|||
|
|
@ -288,7 +288,8 @@ describe('handleOscLink', () => {
|
|||
await flushDoubleRaf()
|
||||
|
||||
expect(openFileMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ filePath: '/tmp/src/main.ts' })
|
||||
expect.objectContaining({ filePath: '/tmp/src/main.ts' }),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
expect(setPendingEditorRevealMock).toHaveBeenNthCalledWith(1, null)
|
||||
expect(setPendingEditorRevealMock).toHaveBeenNthCalledWith(2, {
|
||||
|
|
@ -344,7 +345,8 @@ describe('handleOscLink', () => {
|
|||
|
||||
expect(openFilePathMock).toHaveBeenCalledWith('/tmp/src/main.ts')
|
||||
expect(openFileMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ filePath: '/tmp/src/main.ts' })
|
||||
expect.objectContaining({ filePath: '/tmp/src/main.ts' }),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
expect(setPendingEditorRevealMock).toHaveBeenNthCalledWith(1, null)
|
||||
expect(setPendingEditorRevealMock).toHaveBeenNthCalledWith(2, {
|
||||
|
|
@ -400,7 +402,8 @@ describe('handleOscLink', () => {
|
|||
|
||||
expect(authorizeExternalPathMock).toHaveBeenCalledWith({ targetPath: '/tmp/test.txt' })
|
||||
expect(openFileMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ filePath: '/tmp/test.txt' })
|
||||
expect.objectContaining({ filePath: '/tmp/test.txt' }),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
expect(openFilePathMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
|
@ -424,7 +427,8 @@ describe('handleOscLink', () => {
|
|||
targetPath: 'C:/repo/src/index.ts'
|
||||
})
|
||||
expect(openFileMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ filePath: 'C:/repo/src/index.ts' })
|
||||
expect.objectContaining({ filePath: 'C:/repo/src/index.ts' }),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
expect(setPendingEditorRevealMock).toHaveBeenNthCalledWith(1, null)
|
||||
expect(setPendingEditorRevealMock).toHaveBeenNthCalledWith(2, {
|
||||
|
|
@ -452,7 +456,8 @@ describe('handleOscLink', () => {
|
|||
targetPath: '//server/share/repo/test.txt'
|
||||
})
|
||||
expect(openFileMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ filePath: '//server/share/repo/test.txt' })
|
||||
expect.objectContaining({ filePath: '//server/share/repo/test.txt' }),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
})
|
||||
|
||||
|
|
@ -483,7 +488,8 @@ describe('handleOscLink', () => {
|
|||
expect(authorizeExternalPathMock).toHaveBeenCalledWith({ targetPath: '/tmp/test.txt' })
|
||||
expect(openFilePathMock).not.toHaveBeenCalled()
|
||||
expect(openFileMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ filePath: '/tmp/test.txt' })
|
||||
expect.objectContaining({ filePath: '/tmp/test.txt' }),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
expect(setPendingEditorRevealMock).toHaveBeenNthCalledWith(1, null)
|
||||
expect(setPendingEditorRevealMock).toHaveBeenNthCalledWith(2, {
|
||||
|
|
@ -524,7 +530,8 @@ describe('handleOscLink', () => {
|
|||
|
||||
expect(authorizeExternalPathMock).toHaveBeenCalledWith({ targetPath: '/tmp/test.txt' })
|
||||
expect(openFileMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ filePath: '/tmp/test.txt' })
|
||||
expect.objectContaining({ filePath: '/tmp/test.txt' }),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
expect(setPendingEditorRevealMock).toHaveBeenNthCalledWith(1, null)
|
||||
expect(setPendingEditorRevealMock).toHaveBeenNthCalledWith(2, {
|
||||
|
|
@ -556,7 +563,8 @@ describe('handleOscLink', () => {
|
|||
expect.objectContaining({
|
||||
filePath: '//server/Share/Repo/src/app.ts',
|
||||
relativePath: 'src/app.ts'
|
||||
})
|
||||
}),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
expect(setPendingEditorRevealMock).toHaveBeenNthCalledWith(1, null)
|
||||
expect(setPendingEditorRevealMock).toHaveBeenNthCalledWith(2, {
|
||||
|
|
@ -588,7 +596,8 @@ describe('handleOscLink', () => {
|
|||
expect.objectContaining({
|
||||
filePath: '/tmp/project/docs/README.md',
|
||||
relativePath: 'project/docs/README.md'
|
||||
})
|
||||
}),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
expect(openFilePathMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
|
@ -614,7 +623,8 @@ describe('handleOscLink', () => {
|
|||
expect(openFileMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
filePath: '/home/alice/file.ts'
|
||||
})
|
||||
}),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
expect(openFilePathMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
|
@ -646,7 +656,8 @@ describe('handleOscLink', () => {
|
|||
expect.objectContaining({
|
||||
filePath: '/tmp/src/main.ts',
|
||||
relativePath: 'src/main.ts'
|
||||
})
|
||||
}),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
})
|
||||
|
||||
|
|
@ -679,7 +690,8 @@ describe('handleOscLink', () => {
|
|||
filePath: '/tmp/src/main.ts',
|
||||
relativePath: 'src/main.ts',
|
||||
runtimeEnvironmentId: 'env-1'
|
||||
})
|
||||
}),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
})
|
||||
|
||||
|
|
@ -703,7 +715,8 @@ describe('handleOscLink', () => {
|
|||
expect.objectContaining({
|
||||
filePath: '/home/me/repo/src/main.ts',
|
||||
relativePath: 'src/main.ts'
|
||||
})
|
||||
}),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
})
|
||||
|
||||
|
|
@ -723,7 +736,8 @@ describe('handleOscLink', () => {
|
|||
expect.objectContaining({
|
||||
filePath: '/home/me/repo/report.html',
|
||||
relativePath: 'report.html'
|
||||
})
|
||||
}),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
})
|
||||
|
||||
|
|
@ -872,7 +886,8 @@ describe('handleOscLink', () => {
|
|||
expect(openFilePathMock).not.toHaveBeenCalled()
|
||||
expect(openFileMock).toHaveBeenCalledTimes(1)
|
||||
expect(openFileMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ filePath: '/tmp/src/second.ts' })
|
||||
expect.objectContaining({ filePath: '/tmp/src/second.ts' }),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
expect(setPendingEditorRevealMock).toHaveBeenNthCalledWith(1, null)
|
||||
expect(setPendingEditorRevealMock).toHaveBeenNthCalledWith(2, {
|
||||
|
|
@ -1320,7 +1335,8 @@ describe('createFilePathLinkProvider range bounds', () => {
|
|||
// existence probe; openDetectedFilePath still stats before routing.
|
||||
expect(window.api.shell.pathExists).not.toHaveBeenCalled()
|
||||
expect(openFileMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ filePath: '/tmp/package.json' })
|
||||
expect.objectContaining({ filePath: '/tmp/package.json' }),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
expect(openFilePathMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
|
@ -1393,7 +1409,8 @@ describe('createFilePathLinkProvider range bounds', () => {
|
|||
|
||||
expect(opened).toBe(true)
|
||||
expect(openFileMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ filePath: '/Users/alice/Documents/Path/file_name' })
|
||||
expect.objectContaining({ filePath: '/Users/alice/Documents/Path/file_name' }),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
expect(openFilePathMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
|
@ -1417,7 +1434,8 @@ describe('createFilePathLinkProvider range bounds', () => {
|
|||
|
||||
expect(opened).toBe(true)
|
||||
expect(openFileMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ filePath: '/home/alice/Documents/Path/file_name' })
|
||||
expect.objectContaining({ filePath: '/home/alice/Documents/Path/file_name' }),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
expect(openFilePathMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
|
@ -1506,7 +1524,8 @@ describe('createFilePathLinkProvider range bounds', () => {
|
|||
|
||||
expect(opened).toBe(true)
|
||||
expect(openFileMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ filePath: '/repo/My Folder' })
|
||||
expect.objectContaining({ filePath: '/repo/My Folder' }),
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
expect(openFilePathMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -454,6 +454,62 @@ describe('createEditorSlice openDiff', () => {
|
|||
expect(store.getState().openFiles[0]?.diffContentReloadNonce).toBe(2)
|
||||
})
|
||||
|
||||
it('bumps fileContentReloadNonce when re-opening an existing clean file with reload requested', () => {
|
||||
const store = createEditorStore()
|
||||
|
||||
const openFileWithReloadRequest = (): void =>
|
||||
store.getState().openFile(
|
||||
{
|
||||
filePath: '/repo/file.ts',
|
||||
relativePath: 'file.ts',
|
||||
worktreeId: 'wt-1',
|
||||
language: 'typescript',
|
||||
mode: 'edit'
|
||||
},
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
|
||||
openFileWithReloadRequest()
|
||||
expect(store.getState().openFiles[0]?.fileContentReloadNonce).toBeUndefined()
|
||||
|
||||
openFileWithReloadRequest()
|
||||
expect(store.getState().openFiles[0]?.fileContentReloadNonce).toBe(1)
|
||||
|
||||
openFileWithReloadRequest()
|
||||
expect(store.getState().openFiles[0]?.fileContentReloadNonce).toBe(2)
|
||||
})
|
||||
|
||||
it('does not bump fileContentReloadNonce when a dirty file is re-opened', () => {
|
||||
const store = createEditorStore()
|
||||
|
||||
store.getState().openFile({
|
||||
filePath: '/repo/file.ts',
|
||||
relativePath: 'file.ts',
|
||||
worktreeId: 'wt-1',
|
||||
language: 'typescript',
|
||||
mode: 'edit'
|
||||
})
|
||||
store.getState().markFileDirty('/repo/file.ts', true)
|
||||
|
||||
store.getState().openFile(
|
||||
{
|
||||
filePath: '/repo/file.ts',
|
||||
relativePath: 'file.ts',
|
||||
worktreeId: 'wt-1',
|
||||
language: 'typescript',
|
||||
mode: 'edit'
|
||||
},
|
||||
{ forceContentReload: true }
|
||||
)
|
||||
|
||||
expect(store.getState().openFiles[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
isDirty: true,
|
||||
fileContentReloadNonce: undefined
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('opens the visible diff tab in the requested split group', () => {
|
||||
const store = createEditorTabsStore()
|
||||
const sourceTab = store.getState().createUnifiedTab('wt-1', 'terminal', { id: 'terminal-1' })
|
||||
|
|
|
|||
|
|
@ -222,6 +222,9 @@ export type OpenFile = {
|
|||
* tab from the tree bumps this so the panel refetches instead of reusing a
|
||||
* stale snapshot. */
|
||||
diffContentReloadNonce?: number
|
||||
/** Why: terminal/agent links can be the user's manual recovery path when a
|
||||
* remote watcher misses an external write. Bumping this refetches clean tabs. */
|
||||
fileContentReloadNonce?: number
|
||||
/** Why: CI check full-details tabs are virtual editor tabs backed by fetched
|
||||
* PR check-run metadata instead of a file on disk. */
|
||||
checkRunDetails?: OpenCheckRunDetailsState
|
||||
|
|
@ -258,6 +261,7 @@ type EditorOpenTargetOptions = {
|
|||
targetGroupId?: string
|
||||
preview?: boolean
|
||||
runtimeEnvironmentId?: string | null
|
||||
forceContentReload?: boolean
|
||||
}
|
||||
|
||||
type GitRuntimeOperationOptions = {
|
||||
|
|
@ -404,6 +408,7 @@ export type EditorSlice = {
|
|||
targetGroupId?: string
|
||||
recordReplacedPreview?: boolean
|
||||
suppressActiveRuntimeFallback?: boolean
|
||||
forceContentReload?: boolean
|
||||
}
|
||||
) => void
|
||||
openNewMarkdownInActiveWorkspace: (groupId: string) => Promise<void>
|
||||
|
|
@ -899,6 +904,19 @@ function withDiffContentReloadRequest(file: OpenFile): OpenFile {
|
|||
}
|
||||
}
|
||||
|
||||
function shouldRequestExistingFileContentReload(
|
||||
existing: OpenFile,
|
||||
nextMode: OpenFile['mode'],
|
||||
options: EditorOpenTargetOptions | undefined
|
||||
): boolean {
|
||||
return (
|
||||
options?.forceContentReload === true &&
|
||||
!existing.isDirty &&
|
||||
(existing.mode === 'edit' || existing.mode === 'markdown-preview') &&
|
||||
(nextMode === 'edit' || nextMode === 'markdown-preview')
|
||||
)
|
||||
}
|
||||
|
||||
function isEditorFileIdOccupiedByOtherOwner(
|
||||
file: Pick<
|
||||
OpenFile,
|
||||
|
|
@ -1703,6 +1721,13 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
|
|||
if (existing) {
|
||||
// If opening as non-preview, also pin the existing tab
|
||||
const updatedPreview = isPreview ? existing.isPreview : false
|
||||
const fileContentReloadNonce = shouldRequestExistingFileContentReload(
|
||||
existing,
|
||||
file.mode,
|
||||
options
|
||||
)
|
||||
? (existing.fileContentReloadNonce ?? 0) + 1
|
||||
: existing.fileContentReloadNonce
|
||||
const needsExistingUpdate =
|
||||
existing.mode !== file.mode ||
|
||||
existing.diffSource !== file.diffSource ||
|
||||
|
|
@ -1716,7 +1741,8 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
|
|||
existing.language !== file.language ||
|
||||
existing.relativePath !== file.relativePath ||
|
||||
existing.worktreeId !== file.worktreeId ||
|
||||
existing.runtimeEnvironmentId !== runtimeEnvironmentId
|
||||
existing.runtimeEnvironmentId !== runtimeEnvironmentId ||
|
||||
existing.fileContentReloadNonce !== fileContentReloadNonce
|
||||
if (!needsExistingUpdate) {
|
||||
return activeResult
|
||||
}
|
||||
|
|
@ -1740,7 +1766,8 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
|
|||
conflict: file.conflict,
|
||||
skippedConflicts: file.skippedConflicts,
|
||||
conflictReview: file.conflictReview,
|
||||
isPreview: updatedPreview
|
||||
isPreview: updatedPreview,
|
||||
fileContentReloadNonce
|
||||
}
|
||||
: f
|
||||
),
|
||||
|
|
|
|||
Loading…
Reference in New Issue