mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
History UI changes- Extracting compare outside dropdown menu
GitOrigin-RevId: 67f51428debefdafe2c9bb746de5da8fc0ac5385
This commit is contained in:
parent
28a7c13887
commit
3490f6a58e
12 changed files with 158 additions and 86 deletions
|
@ -57,7 +57,8 @@ class TestServer {
|
|||
})
|
||||
|
||||
this.app.get('/json/basic-auth', (req, res) => {
|
||||
const expectedAuth = 'Basic ' + Buffer.from('user:pass').toString('base64')
|
||||
const expectedAuth =
|
||||
'Basic ' + Buffer.from('user:pass').toString('base64')
|
||||
if (req.headers.authorization === expectedAuth) {
|
||||
res.json({ key: 'verysecret' })
|
||||
} else {
|
||||
|
|
|
@ -441,7 +441,6 @@
|
|||
"history_adding_label": "",
|
||||
"history_are_you_sure_delete_label": "",
|
||||
"history_compare_from_this_version": "",
|
||||
"history_compare_to_selected_version": "",
|
||||
"history_compare_up_to_this_version": "",
|
||||
"history_delete_label": "",
|
||||
"history_deleting_label": "",
|
||||
|
|
Binary file not shown.
|
@ -2,21 +2,16 @@ import Download from './menu-item/download'
|
|||
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
|
||||
versionTimestamp: number
|
||||
selected: boolean
|
||||
closeDropdownForItem: ActiveDropdown['closeDropdownForItem']
|
||||
}
|
||||
|
||||
function LabelDropdownContent({
|
||||
projectId,
|
||||
version,
|
||||
versionTimestamp,
|
||||
selected,
|
||||
closeDropdownForItem,
|
||||
}: LabelDropdownContentProps) {
|
||||
const closeDropdown = useCallback(() => {
|
||||
|
@ -30,16 +25,6 @@ function LabelDropdownContent({
|
|||
version={version}
|
||||
closeDropdown={closeDropdown}
|
||||
/>
|
||||
<CompareItems
|
||||
updateRange={{
|
||||
fromV: version,
|
||||
toV: version,
|
||||
fromVTimestamp: versionTimestamp,
|
||||
toVTimestamp: versionTimestamp,
|
||||
}}
|
||||
selected={selected}
|
||||
closeDropdown={closeDropdown}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -19,16 +19,44 @@ function CompareItems({
|
|||
const { t } = useTranslation()
|
||||
const { selection } = useHistoryContext()
|
||||
const { updateRange: selRange, comparing } = selection
|
||||
const notASelectionBoundary =
|
||||
|
||||
// Comparing mode variables
|
||||
const notASelectionBoundaryComparingMode =
|
||||
!!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
|
||||
const showCompareToThisComparingMode =
|
||||
notASelectionBoundaryComparingMode && updateRange.toV > selRange.toV
|
||||
const showCompareFromThisComparingMode =
|
||||
notASelectionBoundaryComparingMode && updateRange.fromV < selRange.fromV
|
||||
|
||||
// Normal mode variables
|
||||
const notASelectionBoundaryNormalMode =
|
||||
!!selRange &&
|
||||
updateRange.toV !== selRange.toV &&
|
||||
updateRange.fromV !== selRange.fromV
|
||||
const showCompareToThisNormalMode =
|
||||
notASelectionBoundaryNormalMode && updateRange.toV > selRange.toV
|
||||
const showCompareFromThisNormalMode =
|
||||
notASelectionBoundaryNormalMode && updateRange.fromV < selRange.fromV
|
||||
|
||||
let iconTypeNonSelectedVersion = ''
|
||||
let toolTipDescriptionNonSelectedVersion = ''
|
||||
|
||||
if (showCompareToThisNormalMode) {
|
||||
iconTypeNonSelectedVersion = 'align_start'
|
||||
toolTipDescriptionNonSelectedVersion = t(
|
||||
'history_compare_up_to_this_version'
|
||||
)
|
||||
}
|
||||
if (showCompareFromThisNormalMode) {
|
||||
iconTypeNonSelectedVersion = 'align_end'
|
||||
toolTipDescriptionNonSelectedVersion = t(
|
||||
'history_compare_from_this_version'
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -36,10 +64,16 @@ function CompareItems({
|
|||
<Compare
|
||||
comparisonRange={updateRangeUnion(updateRange, selRange)}
|
||||
closeDropdown={closeDropdown}
|
||||
text={t('history_compare_to_selected_version')}
|
||||
toolTipDescription={toolTipDescriptionNonSelectedVersion}
|
||||
icon={
|
||||
<MaterialIcon
|
||||
type={iconTypeNonSelectedVersion}
|
||||
className="material-symbols-rounded history-dropdown-icon p-1"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
{showCompareFromThis ? (
|
||||
{showCompareFromThisComparingMode ? (
|
||||
<Compare
|
||||
comparisonRange={{
|
||||
fromV: updateRange.fromV,
|
||||
|
@ -48,11 +82,16 @@ function CompareItems({
|
|||
toVTimestamp: selRange.toVTimestamp,
|
||||
}}
|
||||
closeDropdown={closeDropdown}
|
||||
text={t('history_compare_from_this_version')}
|
||||
icon={<MaterialIcon type="line_start_circle" className="fa-fw" />}
|
||||
toolTipDescription={t('history_compare_from_this_version')}
|
||||
icon={
|
||||
<MaterialIcon
|
||||
type="align_end"
|
||||
className="material-symbols-rounded history-dropdown-icon p-1"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
{showCompareToThis ? (
|
||||
{showCompareToThisComparingMode ? (
|
||||
<Compare
|
||||
comparisonRange={{
|
||||
fromV: selRange.fromV,
|
||||
|
@ -61,8 +100,13 @@ function CompareItems({
|
|||
toVTimestamp: updateRange.toVTimestamp,
|
||||
}}
|
||||
closeDropdown={closeDropdown}
|
||||
text={t('history_compare_up_to_this_version')}
|
||||
icon={<MaterialIcon type="line_end_circle" className="fa-fw" />}
|
||||
toolTipDescription={t('history_compare_up_to_this_version')}
|
||||
icon={
|
||||
<MaterialIcon
|
||||
type="align_start"
|
||||
className="material-symbols-rounded history-dropdown-icon p-1"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
|
|
|
@ -1,26 +1,27 @@
|
|||
import { MenuItem, MenuItemProps } from 'react-bootstrap'
|
||||
import Icon from '../../../../../../shared/components/icon'
|
||||
import { useHistoryContext } from '../../../../context/history-context'
|
||||
import { UpdateRange } from '../../../../services/types/update'
|
||||
import { ReactNode } from 'react'
|
||||
import Tooltip from '../../../../../../shared/components/tooltip'
|
||||
import { Button } from 'react-bootstrap'
|
||||
|
||||
type CompareProps = {
|
||||
comparisonRange: UpdateRange
|
||||
text: string
|
||||
icon?: ReactNode
|
||||
toolTipDescription?: string
|
||||
closeDropdown: () => void
|
||||
}
|
||||
|
||||
function Compare({
|
||||
comparisonRange,
|
||||
text,
|
||||
closeDropdown,
|
||||
toolTipDescription,
|
||||
icon = <Icon type="exchange" fw />,
|
||||
...props
|
||||
}: CompareProps) {
|
||||
const { setSelection } = useHistoryContext()
|
||||
|
||||
const handleCompareVersion = (e: React.MouseEvent<MenuItemProps>) => {
|
||||
const handleCompareVersion = (e: React.MouseEvent<Button>) => {
|
||||
e.stopPropagation()
|
||||
closeDropdown()
|
||||
|
||||
|
@ -33,9 +34,20 @@ function Compare({
|
|||
}
|
||||
|
||||
return (
|
||||
<MenuItem onClick={handleCompareVersion} {...props}>
|
||||
{icon} {text}
|
||||
</MenuItem>
|
||||
<Tooltip
|
||||
description={toolTipDescription}
|
||||
id="compare-btn"
|
||||
overlayProps={{ placement: 'left' }}
|
||||
>
|
||||
<Button
|
||||
bsStyle="link"
|
||||
className="history-compare-btn"
|
||||
onClick={handleCompareVersion}
|
||||
>
|
||||
<span className="sr-only">{toolTipDescription}</span>
|
||||
{icon}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,24 +3,18 @@ import Download from './menu-item/download'
|
|||
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
|
||||
closeDropdownForItem: ActiveDropdown['closeDropdownForItem']
|
||||
}
|
||||
|
||||
function VersionDropdownContent({
|
||||
projectId,
|
||||
update,
|
||||
selected,
|
||||
closeDropdownForItem,
|
||||
}: VersionDropdownContentProps) {
|
||||
const updateRange = updateRangeForUpdate(update)
|
||||
|
||||
const closeDropdown = useCallback(() => {
|
||||
closeDropdownForItem(update)
|
||||
}, [closeDropdownForItem, update])
|
||||
|
@ -37,11 +31,6 @@ function VersionDropdownContent({
|
|||
version={update.toV}
|
||||
closeDropdown={closeDropdown}
|
||||
/>
|
||||
<CompareItems
|
||||
updateRange={updateRange}
|
||||
selected={selected}
|
||||
closeDropdown={closeDropdown}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -10,9 +10,10 @@ import { LoadedUpdate } from '../../services/types/update'
|
|||
import classNames from 'classnames'
|
||||
import { updateRangeForUpdate } from '../../utils/history-details'
|
||||
import { ActiveDropdown } from '../../hooks/use-dropdown-active-item'
|
||||
import { memo } from 'react'
|
||||
import { memo, useCallback } from 'react'
|
||||
import { HistoryContextValue } from '../../context/types/history-context-value'
|
||||
import VersionDropdownContent from './dropdown/version-dropdown-content'
|
||||
import CompareItems from './dropdown/menu-item/compare-items'
|
||||
|
||||
type HistoryVersionProps = {
|
||||
update: LoadedUpdate
|
||||
|
@ -45,6 +46,12 @@ function HistoryVersion({
|
|||
}: HistoryVersionProps) {
|
||||
const orderedLabels = orderBy(update.labels, ['created_at'], ['desc'])
|
||||
|
||||
const closeDropdown = useCallback(() => {
|
||||
closeDropdownForItem(update)
|
||||
}, [closeDropdownForItem, update])
|
||||
|
||||
const updateRange = updateRangeForUpdate(update)
|
||||
|
||||
return (
|
||||
<>
|
||||
{showDivider ? <hr className="history-version-divider" /> : null}
|
||||
|
@ -75,7 +82,6 @@ function HistoryVersion({
|
|||
>
|
||||
{dropdownActive ? (
|
||||
<VersionDropdownContent
|
||||
selected={selected}
|
||||
update={update}
|
||||
projectId={projectId}
|
||||
closeDropdownForItem={closeDropdownForItem}
|
||||
|
@ -83,6 +89,17 @@ function HistoryVersion({
|
|||
) : null}
|
||||
</HistoryDropdown>
|
||||
)}
|
||||
|
||||
{!selected ? (
|
||||
<span data-testid="compare-icon-version" className="pull-right">
|
||||
<CompareItems
|
||||
updateRange={updateRange}
|
||||
selected={selected}
|
||||
closeDropdown={closeDropdown}
|
||||
/>
|
||||
</span>
|
||||
) : null}
|
||||
|
||||
<div className="history-version-main-details">
|
||||
<time
|
||||
className="history-version-metadata-time"
|
||||
|
|
|
@ -11,6 +11,7 @@ import { useTranslation } from 'react-i18next'
|
|||
import { ActiveDropdown } from '../../hooks/use-dropdown-active-item'
|
||||
import { HistoryContextValue } from '../../context/types/history-context-value'
|
||||
import LabelDropdownContent from './dropdown/label-dropdown-content'
|
||||
import CompareItems from './dropdown/menu-item/compare-items'
|
||||
|
||||
type LabelListItemProps = {
|
||||
version: Version
|
||||
|
@ -59,6 +60,9 @@ function LabelListItem({
|
|||
},
|
||||
[setActiveDropdownItem, version]
|
||||
)
|
||||
const closeDropdown = useCallback(() => {
|
||||
closeDropdownForItem(version)
|
||||
}, [closeDropdownForItem, version])
|
||||
|
||||
return (
|
||||
<HistoryVersionDetails
|
||||
|
@ -75,14 +79,24 @@ function LabelListItem({
|
|||
>
|
||||
{dropdownActive ? (
|
||||
<LabelDropdownContent
|
||||
selected={selected}
|
||||
version={version}
|
||||
versionTimestamp={toVTimestamp}
|
||||
projectId={projectId}
|
||||
closeDropdownForItem={closeDropdownForItem}
|
||||
/>
|
||||
) : null}
|
||||
</HistoryDropdown>
|
||||
<span className="pull-right">
|
||||
<CompareItems
|
||||
updateRange={{
|
||||
fromV: version,
|
||||
toV: version,
|
||||
fromVTimestamp: toVTimestamp,
|
||||
toVTimestamp,
|
||||
}}
|
||||
selected={selected}
|
||||
closeDropdown={closeDropdown}
|
||||
/>
|
||||
</span>
|
||||
<div className="history-version-main-details">
|
||||
{labels.map(label => (
|
||||
<div key={label.id} className="history-version-label">
|
||||
|
|
|
@ -375,6 +375,15 @@ history-root {
|
|||
}
|
||||
}
|
||||
|
||||
.history-dropdown-icon {
|
||||
color: @neutral-90;
|
||||
}
|
||||
|
||||
.history-compare-btn {
|
||||
line-height: 1;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.history-file-tree {
|
||||
display: flex !important; // To work around jQuery layout's inline styles
|
||||
flex-direction: column;
|
||||
|
|
|
@ -719,7 +719,6 @@
|
|||
"history_adding_label": "Adding label",
|
||||
"history_are_you_sure_delete_label": "Are you sure you want to delete the following label",
|
||||
"history_compare_from_this_version": "Compare from this version",
|
||||
"history_compare_to_selected_version": "Compare to selected version",
|
||||
"history_compare_up_to_this_version": "Compare up to this version",
|
||||
"history_delete_label": "Delete label",
|
||||
"history_deleting_label": "Deleting label",
|
||||
|
|
|
@ -332,14 +332,10 @@ describe('change list', function () {
|
|||
cy.findAllByTestId('history-version-details')
|
||||
.eq(1)
|
||||
.within(() => {
|
||||
cy.findByRole('button', { name: /more actions/i }).click()
|
||||
cy.findByRole('menu').within(() => {
|
||||
cy.findByRole('menuitem', {
|
||||
name: /compare to selected version/i,
|
||||
}).click()
|
||||
})
|
||||
cy.findByRole('button', {
|
||||
name: /Compare/i,
|
||||
}).click()
|
||||
})
|
||||
cy.wait('@diff')
|
||||
cy.findByLabelText(/all history/i).click({ force: true })
|
||||
cy.findAllByTestId('history-version-details').should($versions => {
|
||||
const [first, ...rest] = Array.from($versions)
|
||||
|
@ -350,6 +346,40 @@ describe('change list', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('compare mode', function () {
|
||||
beforeEach(function () {
|
||||
mountWithEditorProviders(<ChangeList />, scope, {
|
||||
user: {
|
||||
id: USER_ID,
|
||||
email: USER_EMAIL,
|
||||
isAdmin: true,
|
||||
},
|
||||
})
|
||||
waitForData()
|
||||
})
|
||||
|
||||
it('compares versions', function () {
|
||||
cy.findAllByTestId('history-version-details').should($versions => {
|
||||
const [first, ...rest] = Array.from($versions)
|
||||
expect(first).to.have.attr('data-selected', 'true')
|
||||
rest.forEach(version =>
|
||||
expect(version).to.have.attr('data-selected', 'false')
|
||||
)
|
||||
})
|
||||
|
||||
cy.intercept('GET', '/project/*/filetree/diff*', {
|
||||
body: { diff: [{ pathname: 'main.tex' }, { pathname: 'name.tex' }] },
|
||||
}).as('compareDiff')
|
||||
|
||||
cy.findAllByTestId('history-version-details')
|
||||
.last()
|
||||
.within(() => {
|
||||
cy.findByTestId('compare-icon-version').click()
|
||||
})
|
||||
cy.wait('@compareDiff')
|
||||
})
|
||||
})
|
||||
|
||||
describe('dropdown', function () {
|
||||
beforeEach(function () {
|
||||
mountWithEditorProviders(<ChangeList />, scope, {
|
||||
|
@ -421,33 +451,6 @@ describe('change list', function () {
|
|||
})
|
||||
cy.wait('@download')
|
||||
})
|
||||
|
||||
it('compares versions', function () {
|
||||
cy.findAllByTestId('history-version-details').should($versions => {
|
||||
const [first, ...rest] = Array.from($versions)
|
||||
expect(first).to.have.attr('data-selected', 'true')
|
||||
rest.forEach(version =>
|
||||
expect(version).to.have.attr('data-selected', 'false')
|
||||
)
|
||||
})
|
||||
|
||||
cy.intercept('GET', '/project/*/filetree/diff*', {
|
||||
body: { diff: [{ pathname: 'main.tex' }, { pathname: 'name.tex' }] },
|
||||
}).as('compareDiff')
|
||||
|
||||
cy.findAllByTestId('history-version-details')
|
||||
.last()
|
||||
.within(() => {
|
||||
cy.findByRole('button', { name: /more actions/i }).click()
|
||||
cy.findByRole('menu').within(() => {
|
||||
cy.findByRole('menuitem', {
|
||||
name: /compare to selected version/i,
|
||||
}).click()
|
||||
})
|
||||
})
|
||||
|
||||
cy.wait('@compareDiff')
|
||||
})
|
||||
})
|
||||
|
||||
describe('paywall', function () {
|
||||
|
|
Loading…
Reference in a new issue