mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #13104 from overleaf/td-history-compare-to-from
History migration: Add "compare to" and "compare from" options GitOrigin-RevId: f550ad06b1e812011ecb32e6772354eb0abc2163
This commit is contained in:
parent
5d0ce8c4cd
commit
c870bd5f53
12 changed files with 136 additions and 99 deletions
|
@ -401,7 +401,9 @@
|
|||
"history_add_label": "",
|
||||
"history_adding_label": "",
|
||||
"history_are_you_sure_delete_label": "",
|
||||
"history_compare_with_this_version": "",
|
||||
"history_compare_from_this_version": "",
|
||||
"history_compare_to_selected_version": "",
|
||||
"history_compare_to_this_version": "",
|
||||
"history_delete_label": "",
|
||||
"history_deleting_label": "",
|
||||
"history_download_this_version": "",
|
||||
|
|
|
@ -99,6 +99,7 @@ function AllHistoryList() {
|
|||
const faded =
|
||||
updatesInfo.freeHistoryLimitHit &&
|
||||
index === visibleUpdates.length - 1
|
||||
const selectable = !faded && (selection.comparing || !selected)
|
||||
|
||||
return (
|
||||
<HistoryVersion
|
||||
|
@ -109,7 +110,7 @@ function AllHistoryList() {
|
|||
setSelection={setSelection}
|
||||
selected={selected}
|
||||
currentUserId={currentUserId}
|
||||
comparing={selection.comparing}
|
||||
selectable={selectable}
|
||||
projectId={projectId}
|
||||
setActiveDropdownItem={setActiveDropdownItem}
|
||||
closeDropdownForItem={closeDropdownForItem}
|
||||
|
|
|
@ -1,24 +1,22 @@
|
|||
import Download from './menu-item/download'
|
||||
import Compare from './menu-item/compare'
|
||||
import { Version } from '../../../services/types/update'
|
||||
import { ActiveDropdown } from '../../../hooks/use-dropdown-active-item'
|
||||
import { useCallback } from 'react'
|
||||
import CompareItems from './menu-item/compare-items'
|
||||
|
||||
type LabelDropdownContentProps = {
|
||||
projectId: string
|
||||
version: Version
|
||||
updateMetaEndTimestamp: number
|
||||
versionTimestamp: number
|
||||
selected: boolean
|
||||
comparing: boolean
|
||||
closeDropdownForItem: ActiveDropdown['closeDropdownForItem']
|
||||
}
|
||||
|
||||
function LabelDropdownContent({
|
||||
projectId,
|
||||
version,
|
||||
updateMetaEndTimestamp,
|
||||
versionTimestamp,
|
||||
selected,
|
||||
comparing,
|
||||
closeDropdownForItem,
|
||||
}: LabelDropdownContentProps) {
|
||||
const closeDropdown = useCallback(() => {
|
||||
|
@ -32,15 +30,16 @@ function LabelDropdownContent({
|
|||
version={version}
|
||||
closeDropdown={closeDropdown}
|
||||
/>
|
||||
{!comparing && !selected && (
|
||||
<Compare
|
||||
projectId={projectId}
|
||||
fromV={version}
|
||||
toV={version}
|
||||
updateMetaEndTimestamp={updateMetaEndTimestamp}
|
||||
<CompareItems
|
||||
updateRange={{
|
||||
fromV: version,
|
||||
toV: version,
|
||||
fromVTimestamp: versionTimestamp,
|
||||
toVTimestamp: versionTimestamp,
|
||||
}}
|
||||
selected={selected}
|
||||
closeDropdown={closeDropdown}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import { useHistoryContext } from '../../../../context/history-context'
|
||||
import { UpdateRange } from '../../../../services/types/update'
|
||||
import Compare from './compare'
|
||||
import { updateRangeUnion } from '../../../../utils/range'
|
||||
|
||||
type CompareItemsProps = {
|
||||
updateRange: UpdateRange
|
||||
selected: boolean
|
||||
closeDropdown: () => void
|
||||
}
|
||||
|
||||
function CompareItems({
|
||||
updateRange,
|
||||
selected,
|
||||
closeDropdown,
|
||||
}: CompareItemsProps) {
|
||||
const { t } = useTranslation()
|
||||
const { selection } = useHistoryContext()
|
||||
const { updateRange: selRange, comparing } = selection
|
||||
const notASelectionBoundary =
|
||||
!!selRange &&
|
||||
comparing &&
|
||||
updateRange.toV !== selRange.toV &&
|
||||
updateRange.fromV !== selRange.fromV
|
||||
const showCompareWithSelected = !comparing && !!selRange && !selected
|
||||
const showCompareToThis =
|
||||
notASelectionBoundary && updateRange.toV > selRange.fromV
|
||||
const showCompareFromThis =
|
||||
notASelectionBoundary && updateRange.fromV < selRange.toV
|
||||
|
||||
return (
|
||||
<>
|
||||
{showCompareWithSelected ? (
|
||||
<Compare
|
||||
comparisonRange={updateRangeUnion(updateRange, selRange)}
|
||||
closeDropdown={closeDropdown}
|
||||
text={t('history_compare_to_selected_version')}
|
||||
/>
|
||||
) : null}
|
||||
{showCompareToThis ? (
|
||||
<Compare
|
||||
comparisonRange={{
|
||||
fromV: selRange.fromV,
|
||||
toV: updateRange.toV,
|
||||
fromVTimestamp: selRange.fromVTimestamp,
|
||||
toVTimestamp: updateRange.toVTimestamp,
|
||||
}}
|
||||
closeDropdown={closeDropdown}
|
||||
text={t('history_compare_to_this_version')}
|
||||
/>
|
||||
) : null}
|
||||
{showCompareFromThis ? (
|
||||
<Compare
|
||||
comparisonRange={{
|
||||
fromV: updateRange.fromV,
|
||||
toV: selRange.toV,
|
||||
fromVTimestamp: updateRange.fromVTimestamp,
|
||||
toVTimestamp: selRange.toVTimestamp,
|
||||
}}
|
||||
closeDropdown={closeDropdown}
|
||||
text={t('history_compare_from_this_version')}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default CompareItems
|
|
@ -1,56 +1,36 @@
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import { MenuItem, MenuItemProps } from 'react-bootstrap'
|
||||
import Icon from '../../../../../../shared/components/icon'
|
||||
import { useHistoryContext } from '../../../../context/history-context'
|
||||
import { computeUpdateRange } from '../../../../utils/range'
|
||||
import { UpdateRange } from '../../../../services/types/update'
|
||||
|
||||
type CompareProps = {
|
||||
projectId: string
|
||||
updateMetaEndTimestamp: number
|
||||
comparisonRange: UpdateRange
|
||||
text: string
|
||||
closeDropdown: () => void
|
||||
} & Pick<UpdateRange, 'fromV' | 'toV'>
|
||||
}
|
||||
|
||||
function Compare({
|
||||
projectId,
|
||||
fromV,
|
||||
toV,
|
||||
updateMetaEndTimestamp,
|
||||
comparisonRange,
|
||||
text,
|
||||
closeDropdown,
|
||||
...props
|
||||
}: CompareProps) {
|
||||
const { t } = useTranslation()
|
||||
const { setSelection } = useHistoryContext()
|
||||
|
||||
const handleCompareVersion = (e: React.MouseEvent<MenuItemProps>) => {
|
||||
e.stopPropagation()
|
||||
closeDropdown()
|
||||
|
||||
setSelection(prevSelection => {
|
||||
const { updateRange } = prevSelection
|
||||
|
||||
if (updateRange) {
|
||||
const range = computeUpdateRange(
|
||||
updateRange,
|
||||
fromV,
|
||||
toV,
|
||||
updateMetaEndTimestamp
|
||||
)
|
||||
|
||||
return {
|
||||
updateRange: range,
|
||||
setSelection({
|
||||
updateRange: comparisonRange,
|
||||
comparing: true,
|
||||
files: [],
|
||||
}
|
||||
}
|
||||
|
||||
return prevSelection
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<MenuItem onClick={handleCompareVersion} {...props}>
|
||||
<Icon type="exchange" fw /> {t('history_compare_with_this_version')}
|
||||
<Icon type="exchange" fw /> {text}
|
||||
</MenuItem>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import AddLabel from './menu-item/add-label'
|
||||
import Download from './menu-item/download'
|
||||
import Compare from './menu-item/compare'
|
||||
import { LoadedUpdate } from '../../../services/types/update'
|
||||
import { useCallback } from 'react'
|
||||
import { ActiveDropdown } from '../../../hooks/use-dropdown-active-item'
|
||||
import CompareItems from './menu-item/compare-items'
|
||||
import { updateRangeForUpdate } from '../../../utils/history-details'
|
||||
|
||||
type VersionDropdownContentProps = {
|
||||
projectId: string
|
||||
update: LoadedUpdate
|
||||
selected: boolean
|
||||
comparing: boolean
|
||||
closeDropdownForItem: ActiveDropdown['closeDropdownForItem']
|
||||
}
|
||||
|
||||
|
@ -17,9 +17,10 @@ function VersionDropdownContent({
|
|||
projectId,
|
||||
update,
|
||||
selected,
|
||||
comparing,
|
||||
closeDropdownForItem,
|
||||
}: VersionDropdownContentProps) {
|
||||
const updateRange = updateRangeForUpdate(update)
|
||||
|
||||
const closeDropdown = useCallback(() => {
|
||||
closeDropdownForItem(update)
|
||||
}, [closeDropdownForItem, update])
|
||||
|
@ -36,15 +37,11 @@ function VersionDropdownContent({
|
|||
version={update.toV}
|
||||
closeDropdown={closeDropdown}
|
||||
/>
|
||||
{!comparing && !selected && (
|
||||
<Compare
|
||||
projectId={projectId}
|
||||
fromV={update.fromV}
|
||||
toV={update.toV}
|
||||
updateMetaEndTimestamp={update.meta.end_ts}
|
||||
<CompareItems
|
||||
updateRange={updateRange}
|
||||
selected={selected}
|
||||
closeDropdown={closeDropdown}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ type HistoryVersionProps = {
|
|||
update: LoadedUpdate
|
||||
currentUserId: string
|
||||
projectId: string
|
||||
comparing: boolean
|
||||
selectable: boolean
|
||||
faded: boolean
|
||||
showDivider: boolean
|
||||
selected: boolean
|
||||
|
@ -33,7 +33,7 @@ function HistoryVersion({
|
|||
update,
|
||||
currentUserId,
|
||||
projectId,
|
||||
comparing,
|
||||
selectable,
|
||||
faded,
|
||||
showDivider,
|
||||
selected,
|
||||
|
@ -44,7 +44,6 @@ function HistoryVersion({
|
|||
closeDropdownForItem,
|
||||
}: HistoryVersionProps) {
|
||||
const orderedLabels = orderBy(update.labels, ['created_at'], ['desc'])
|
||||
const selectable = !faded && (comparing || !selected)
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -99,7 +98,6 @@ function HistoryVersion({
|
|||
>
|
||||
{dropdownActive ? (
|
||||
<VersionDropdownContent
|
||||
comparing={comparing}
|
||||
selected={selected}
|
||||
update={update}
|
||||
projectId={projectId}
|
||||
|
|
|
@ -17,7 +17,6 @@ type LabelListItemProps = {
|
|||
labels: LoadedLabel[]
|
||||
currentUserId: string
|
||||
projectId: string
|
||||
comparing: boolean
|
||||
selected: boolean
|
||||
selectable: boolean
|
||||
setSelection: HistoryContextValue['setSelection']
|
||||
|
@ -32,7 +31,6 @@ function LabelListItem({
|
|||
labels,
|
||||
currentUserId,
|
||||
projectId,
|
||||
comparing,
|
||||
selected,
|
||||
selectable,
|
||||
setSelection,
|
||||
|
@ -105,10 +103,9 @@ function LabelListItem({
|
|||
>
|
||||
{dropdownActive ? (
|
||||
<LabelDropdownContent
|
||||
comparing={comparing}
|
||||
selected={selected}
|
||||
version={version}
|
||||
updateMetaEndTimestamp={toVTimestamp}
|
||||
versionTimestamp={toVTimestamp}
|
||||
projectId={projectId}
|
||||
closeDropdownForItem={closeDropdownForItem}
|
||||
/>
|
||||
|
|
|
@ -39,7 +39,6 @@ function LabelsList() {
|
|||
version={version}
|
||||
currentUserId={currentUserId}
|
||||
projectId={projectId}
|
||||
comparing={selection.comparing}
|
||||
selected={selected}
|
||||
selectable={!(singleVersionSelected && selected)}
|
||||
setSelection={setSelection}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import { useHistoryContext } from '../../context/history-context'
|
||||
import { getUpdateForVersion } from '../../utils/history-details'
|
||||
import { computeUpdateRange } from '../../utils/range'
|
||||
import {
|
||||
getUpdateForVersion,
|
||||
updateRangeForUpdate,
|
||||
} from '../../utils/history-details'
|
||||
import { isAnyVersionMatchingSelection } from '../../utils/label'
|
||||
import { HistoryContextValue } from '../../context/types/history-context-value'
|
||||
import { updateRangeUnion } from '../../utils/range'
|
||||
|
||||
type ToggleSwitchProps = Pick<
|
||||
HistoryContextValue,
|
||||
|
@ -28,22 +31,19 @@ function ToggleSwitch({ labelsOnly, setLabelsOnly }: ToggleSwitchProps) {
|
|||
// in labels only mode the `fromV` is equal to `toV` value
|
||||
// switching to all history mode and triggering immediate comparison with
|
||||
// an older version would cause a bug if the computation below is skipped.
|
||||
const update = selection.updateRange?.toV
|
||||
? getUpdateForVersion(selection.updateRange.toV, updatesInfo.updates)
|
||||
: null
|
||||
|
||||
const { updateRange } = selection
|
||||
const update = updateRange?.toV
|
||||
? getUpdateForVersion(updateRange.toV, updatesInfo.updates)
|
||||
: null
|
||||
|
||||
if (
|
||||
updateRange &&
|
||||
update &&
|
||||
(update.fromV !== updateRange.fromV || update.toV !== updateRange.toV)
|
||||
) {
|
||||
const range = computeUpdateRange(
|
||||
updateRange,
|
||||
update.fromV,
|
||||
update.toV,
|
||||
update.meta.end_ts
|
||||
const range = updateRangeUnion(
|
||||
updateRangeForUpdate(update),
|
||||
updateRange
|
||||
)
|
||||
|
||||
setSelection({
|
||||
|
|
|
@ -1,26 +1,19 @@
|
|||
import { UpdateRange } from '../services/types/update'
|
||||
|
||||
export const computeUpdateRange = (
|
||||
updateRange: UpdateRange,
|
||||
fromV: number,
|
||||
toV: number,
|
||||
updateMetaEndTimestamp: number
|
||||
export const updateRangeUnion = (
|
||||
updateRange1: UpdateRange,
|
||||
updateRange2: UpdateRange
|
||||
) => {
|
||||
const fromVersion = Math.min(fromV, updateRange.fromV)
|
||||
const toVersion = Math.max(toV, updateRange.toV)
|
||||
const fromVTimestamp = Math.min(
|
||||
updateMetaEndTimestamp,
|
||||
updateRange.fromVTimestamp
|
||||
)
|
||||
const toVTimestamp = Math.max(
|
||||
updateMetaEndTimestamp,
|
||||
updateRange.toVTimestamp
|
||||
)
|
||||
|
||||
return {
|
||||
fromV: fromVersion,
|
||||
toV: toVersion,
|
||||
fromVTimestamp,
|
||||
toVTimestamp,
|
||||
fromV: Math.min(updateRange1.fromV, updateRange2.fromV),
|
||||
toV: Math.max(updateRange1.toV, updateRange2.toV),
|
||||
fromVTimestamp: Math.min(
|
||||
updateRange1.fromVTimestamp,
|
||||
updateRange2.fromVTimestamp
|
||||
),
|
||||
toVTimestamp: Math.max(
|
||||
updateRange1.toVTimestamp,
|
||||
updateRange2.toVTimestamp
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -682,7 +682,9 @@
|
|||
"history_add_label": "Add label",
|
||||
"history_adding_label": "Adding label",
|
||||
"history_are_you_sure_delete_label": "Are you sure you want to delete the following label",
|
||||
"history_compare_with_this_version": "Compare with this version",
|
||||
"history_compare_from_this_version": "Compare from this version",
|
||||
"history_compare_to_selected_version": "Compare to selected version",
|
||||
"history_compare_to_this_version": "Compare to this version",
|
||||
"history_delete_label": "Delete label",
|
||||
"history_deleting_label": "Deleting label",
|
||||
"history_download_this_version": "Download this version",
|
||||
|
|
Loading…
Reference in a new issue