mirror of
https://github.com/overleaf/overleaf.git
synced 2025-03-15 04:51:56 +00:00
Merge pull request #13146 from overleaf/ii-history-react-save-last-selected-file-in-local-storage
[web] Save lastly selected file in the file tree GitOrigin-RevId: 4b4dcdcb1340e253d4cd2003280f67385975d664
This commit is contained in:
parent
9fd9e991a7
commit
bb815268f2
11 changed files with 89 additions and 32 deletions
|
@ -26,8 +26,8 @@ else
|
|||
minimum-restore-size-west="130"
|
||||
custom-toggler-pane=hasFeature('custom-togglers') ? "west" : false
|
||||
custom-toggler-msg-when-open=hasFeature('custom-togglers') ? translate("tooltip_hide_filetree") : false
|
||||
custom-toggler-msg-when-closed=hasFeature('custom-togglers') ? translate("tooltip_show_filetree") : false
|
||||
tabindex="0"
|
||||
custom-toggler-msg-when-closed=hasFeature('custom-togglers') ? translate("tooltip_show_filetree") : false
|
||||
tabindex="0"
|
||||
initial-size-east="250"
|
||||
init-closed-east="true"
|
||||
open-east="ui.chatOpen"
|
||||
|
@ -44,9 +44,7 @@ else
|
|||
include ./editor
|
||||
|
||||
if (historyViewReact)
|
||||
history-root(
|
||||
ng-if="ui.view == 'history'"
|
||||
)
|
||||
history-root()
|
||||
else
|
||||
include ./history
|
||||
|
||||
|
|
|
@ -24,11 +24,12 @@ function Compare({
|
|||
e.stopPropagation()
|
||||
closeDropdown()
|
||||
|
||||
setSelection({
|
||||
setSelection(({ previouslySelectedPathname }) => ({
|
||||
updateRange: comparisonRange,
|
||||
comparing: true,
|
||||
files: [],
|
||||
})
|
||||
previouslySelectedPathname,
|
||||
}))
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -21,11 +21,12 @@ function HistoryVersionDetails({
|
|||
const handleSelect = (e: MouseEvent<HTMLDivElement>) => {
|
||||
const target = e.target as HTMLElement
|
||||
if (!target.closest('.dropdown') && e.currentTarget.contains(target)) {
|
||||
setSelection({
|
||||
setSelection(({ previouslySelectedPathname }) => ({
|
||||
updateRange,
|
||||
comparing: false,
|
||||
files: [],
|
||||
})
|
||||
previouslySelectedPathname,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,11 +46,12 @@ function ToggleSwitch({ labelsOnly, setLabelsOnly }: ToggleSwitchProps) {
|
|||
updateRange
|
||||
)
|
||||
|
||||
setSelection({
|
||||
setSelection(({ previouslySelectedPathname }) => ({
|
||||
updateRange: range,
|
||||
comparing: false,
|
||||
files: [],
|
||||
})
|
||||
previouslySelectedPathname,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ function HistoryFileTreeFolderList({
|
|||
return {
|
||||
...prevSelection,
|
||||
selectedFile: file,
|
||||
previouslySelectedPathname: file.pathname,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import ChangeList from './change-list/change-list'
|
||||
import DiffView from './diff-view/diff-view'
|
||||
import { HistoryProvider, useHistoryContext } from '../context/history-context'
|
||||
import { useLayoutContext } from '../../../shared/context/layout-context'
|
||||
import { createPortal } from 'react-dom'
|
||||
import HistoryFileTree from './history-file-tree'
|
||||
import LoadingSpinner from '../../../shared/components/loading-spinner'
|
||||
|
@ -10,8 +11,13 @@ import withErrorBoundary from '../../../infrastructure/error-boundary'
|
|||
const fileTreeContainer = document.getElementById('history-file-tree')
|
||||
|
||||
function Main() {
|
||||
const { view } = useLayoutContext()
|
||||
const { updatesInfo } = useHistoryContext()
|
||||
|
||||
if (view !== 'history') {
|
||||
return null
|
||||
}
|
||||
|
||||
let content
|
||||
if (updatesInfo.loadingState === 'loadingInitial') {
|
||||
content = <LoadingSpinner />
|
||||
|
|
|
@ -63,6 +63,16 @@ const selectionInitialState: Selection = {
|
|||
updateRange: null,
|
||||
comparing: false,
|
||||
files: [],
|
||||
previouslySelectedPathname: null,
|
||||
}
|
||||
|
||||
const updatesInfoInitialState: HistoryContextValue['updatesInfo'] = {
|
||||
updates: [],
|
||||
visibleUpdateCount: null,
|
||||
atEnd: false,
|
||||
freeHistoryLimitHit: false,
|
||||
nextBeforeTimestamp: undefined,
|
||||
loadingState: 'loadingInitial',
|
||||
}
|
||||
|
||||
function useHistory() {
|
||||
|
@ -81,14 +91,7 @@ function useHistory() {
|
|||
|
||||
const [updatesInfo, setUpdatesInfo] = useState<
|
||||
HistoryContextValue['updatesInfo']
|
||||
>({
|
||||
updates: [],
|
||||
visibleUpdateCount: null,
|
||||
atEnd: false,
|
||||
freeHistoryLimitHit: false,
|
||||
nextBeforeTimestamp: undefined,
|
||||
loadingState: 'loadingInitial',
|
||||
})
|
||||
>(updatesInfoInitialState)
|
||||
const [labels, setLabels] = useState<HistoryContextValue['labels']>(null)
|
||||
const [labelsOnly, setLabelsOnly] = usePersistedState(
|
||||
`history.userPrefs.showOnlyLabels.${projectId}`,
|
||||
|
@ -220,6 +223,20 @@ function useHistory() {
|
|||
}
|
||||
}, [view, fetchNextBatchOfUpdates])
|
||||
|
||||
useEffect(() => {
|
||||
// Reset some parts of the state
|
||||
if (view !== 'history') {
|
||||
initialFetch.current = false
|
||||
setSelection(prevSelection => ({
|
||||
...selectionInitialState,
|
||||
// retain the previously selected pathname
|
||||
previouslySelectedPathname: prevSelection.previouslySelectedPathname,
|
||||
}))
|
||||
setUpdatesInfo(updatesInfoInitialState)
|
||||
setLabels(null)
|
||||
}
|
||||
}, [view])
|
||||
|
||||
const resetSelection = useCallback(() => {
|
||||
setSelection(selectionInitialState)
|
||||
}, [])
|
||||
|
@ -249,7 +266,8 @@ function useHistory() {
|
|||
files,
|
||||
toV,
|
||||
previousSelection.comparing,
|
||||
updateForToV
|
||||
updateForToV,
|
||||
previousSelection.previouslySelectedPathname
|
||||
)
|
||||
const newFiles = files.map(file => {
|
||||
if (isFileRenamed(file) && file.newPathname) {
|
||||
|
@ -258,7 +276,12 @@ function useHistory() {
|
|||
|
||||
return file
|
||||
})
|
||||
return { ...previousSelection, files: newFiles, selectedFile }
|
||||
return {
|
||||
...previousSelection,
|
||||
files: newFiles,
|
||||
selectedFile,
|
||||
previouslySelectedPathname: selectedFile.pathname,
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(handleError)
|
||||
|
@ -277,7 +300,8 @@ function useHistory() {
|
|||
useEffect(() => {
|
||||
// Set update range if there isn't one and updates have loaded
|
||||
if (updates.length && !updateRange) {
|
||||
setSelection({
|
||||
setSelection(prevSelection => ({
|
||||
...prevSelection,
|
||||
updateRange: {
|
||||
fromV: updates[0].fromV,
|
||||
toV: updates[0].toV,
|
||||
|
@ -286,7 +310,7 @@ function useHistory() {
|
|||
},
|
||||
comparing: false,
|
||||
files: [],
|
||||
})
|
||||
}))
|
||||
}
|
||||
}, [updateRange, updates])
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { FileDiff } from './file'
|
||||
import { FileDiff, FileUnchanged } from './file'
|
||||
import { UpdateRange } from './update'
|
||||
import { Nullable } from '../../../../../../types/utils'
|
||||
|
||||
export interface Selection {
|
||||
updateRange: UpdateRange | null
|
||||
comparing: boolean
|
||||
files: FileDiff[]
|
||||
selectedFile?: FileDiff
|
||||
previouslySelectedPathname: Nullable<FileUnchanged['pathname']>
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import type { Nullable } from '../../../../../types/utils'
|
|||
import type { FileDiff } from '../services/types/file'
|
||||
import type { FileOperation } from '../services/types/file-operation'
|
||||
import type { LoadedUpdate, Version } from '../services/types/update'
|
||||
import type { Selection } from '../services/types/selection'
|
||||
import { fileFinalPathname, isFileEditable } from './file-diff'
|
||||
|
||||
type FileWithOps = {
|
||||
|
@ -100,9 +101,21 @@ export function autoSelectFile(
|
|||
files: FileDiff[],
|
||||
toV: Version,
|
||||
comparing: boolean,
|
||||
updateForToV: LoadedUpdate | undefined
|
||||
updateForToV: LoadedUpdate | undefined,
|
||||
previouslySelectedPathname: Selection['previouslySelectedPathname']
|
||||
): FileDiff {
|
||||
const filesWithOps = getFilesWithOps(files, toV, comparing, updateForToV)
|
||||
const previouslySelectedFile = files.find(file => {
|
||||
return file.pathname === previouslySelectedPathname
|
||||
})
|
||||
const previouslySelectedFileHasOp = filesWithOps.some(file => {
|
||||
return file.pathname === previouslySelectedPathname
|
||||
})
|
||||
|
||||
if (previouslySelectedFile && previouslySelectedFileHasOp) {
|
||||
return previouslySelectedFile
|
||||
}
|
||||
|
||||
for (const opType of orderedOpTypes) {
|
||||
const fileWithMatchingOpType = filesWithOps.find(
|
||||
file => file.operation === opType && file.editable
|
||||
|
@ -119,6 +132,7 @@ export function autoSelectFile(
|
|||
}
|
||||
|
||||
return (
|
||||
previouslySelectedFile ||
|
||||
files.find(file => /main\.tex$/.test(file.pathname)) ||
|
||||
files.find(file => /\.tex$/.test(file.pathname)) ||
|
||||
files[0]
|
||||
|
|
|
@ -54,6 +54,7 @@ describe('history toolbar', function () {
|
|||
pathname: 'main.tex',
|
||||
editable: true,
|
||||
},
|
||||
previouslySelectedPathname: null,
|
||||
}
|
||||
|
||||
cy.mount(
|
||||
|
@ -103,6 +104,7 @@ describe('history toolbar', function () {
|
|||
pathname: 'main.tex',
|
||||
editable: true,
|
||||
},
|
||||
previouslySelectedPathname: null,
|
||||
}
|
||||
|
||||
cy.mount(
|
||||
|
|
|
@ -270,7 +270,8 @@ describe('autoSelectFile', function () {
|
|||
files,
|
||||
updates[0].toV,
|
||||
comparing,
|
||||
getUpdateForVersion(updates[0].toV, updates)
|
||||
getUpdateForVersion(updates[0].toV, updates),
|
||||
null
|
||||
)
|
||||
|
||||
expect(pathname).to.equal('newfolder1/newfile10.tex')
|
||||
|
@ -344,7 +345,8 @@ describe('autoSelectFile', function () {
|
|||
files,
|
||||
updates[0].toV,
|
||||
comparing,
|
||||
getUpdateForVersion(updates[0].toV, updates)
|
||||
getUpdateForVersion(updates[0].toV, updates),
|
||||
null
|
||||
)
|
||||
|
||||
expect(pathname).to.equal('newfile1.tex')
|
||||
|
@ -449,7 +451,8 @@ describe('autoSelectFile', function () {
|
|||
files,
|
||||
updates[0].toV,
|
||||
comparing,
|
||||
getUpdateForVersion(updates[0].toV, updates)
|
||||
getUpdateForVersion(updates[0].toV, updates),
|
||||
null
|
||||
)
|
||||
|
||||
expect(pathname).to.equal('main3.tex')
|
||||
|
@ -624,7 +627,8 @@ describe('autoSelectFile', function () {
|
|||
files,
|
||||
updates[0].toV,
|
||||
comparing,
|
||||
getUpdateForVersion(updates[0].toV, updates)
|
||||
getUpdateForVersion(updates[0].toV, updates),
|
||||
null
|
||||
)
|
||||
|
||||
expect(pathname).to.equal('main.tex')
|
||||
|
@ -735,7 +739,8 @@ describe('autoSelectFile', function () {
|
|||
files,
|
||||
updates[0].toV,
|
||||
comparing,
|
||||
getUpdateForVersion(updates[0].toV, updates)
|
||||
getUpdateForVersion(updates[0].toV, updates),
|
||||
null
|
||||
)
|
||||
|
||||
expect(pathname).to.equal('certainly_not_main.tex')
|
||||
|
@ -808,7 +813,8 @@ describe('autoSelectFile', function () {
|
|||
files,
|
||||
updates[0].toV,
|
||||
comparing,
|
||||
getUpdateForVersion(updates[0].toV, updates)
|
||||
getUpdateForVersion(updates[0].toV, updates),
|
||||
null
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -883,7 +889,8 @@ describe('autoSelectFile', function () {
|
|||
files,
|
||||
updates[0].toV,
|
||||
comparing,
|
||||
getUpdateForVersion(updates[0].toV, updates)
|
||||
getUpdateForVersion(updates[0].toV, updates),
|
||||
null
|
||||
)
|
||||
|
||||
expect(pathname).to.equal('main.tex')
|
||||
|
|
Loading…
Reference in a new issue