History UI changes- Adding enums for history versions

GitOrigin-RevId: 63f3a324889ad10e4a96994fa61f04bea4333630
This commit is contained in:
Davinder Singh
2023-08-22 14:32:59 +01:00
committed by Copybot
parent 68c4b58eaa
commit 7e5a476a95
10 changed files with 158 additions and 102 deletions
@@ -99,7 +99,11 @@ function AllHistoryList() {
const faded =
updatesInfo.freeHistoryLimitHit &&
index === visibleUpdates.length - 1
const selectable = !faded && (selection.comparing || !selected)
const selectable =
!faded &&
(selection.comparing ||
selected === 'aboveSelected' ||
selected === 'belowSelected')
return (
<HistoryVersion
@@ -2,12 +2,12 @@ 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'
import MaterialIcon from '../../../../../../shared/components/material-icon'
import { ItemSelectionState } from '../../../../utils/history-details'
type CompareItemsProps = {
updateRange: UpdateRange
selected: boolean
selected: ItemSelectionState
closeDropdown: () => void
}
@@ -18,62 +18,14 @@ function CompareItems({
}: CompareItemsProps) {
const { t } = useTranslation()
const { selection } = useHistoryContext()
const { updateRange: selRange, comparing } = selection
// Comparing mode variables
const notASelectionBoundaryComparingMode =
!!selRange &&
comparing &&
updateRange.toV !== selRange.toV &&
updateRange.fromV !== selRange.fromV
const showCompareWithSelected = !comparing && !!selRange && !selected
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'
)
const { updateRange: selRange } = selection
if (selRange === null) {
return null
}
return (
<>
{showCompareWithSelected ? (
<Compare
comparisonRange={updateRangeUnion(updateRange, selRange)}
closeDropdown={closeDropdown}
toolTipDescription={toolTipDescriptionNonSelectedVersion}
icon={
<MaterialIcon
type={iconTypeNonSelectedVersion}
className="material-symbols-rounded history-dropdown-icon p-1"
/>
}
/>
) : null}
{showCompareFromThisComparingMode ? (
{selected === 'belowSelected' ? (
<Compare
comparisonRange={{
fromV: updateRange.fromV,
@@ -91,7 +43,7 @@ function CompareItems({
}
/>
) : null}
{showCompareToThisComparingMode ? (
{selected === 'aboveSelected' ? (
<Compare
comparisonRange={{
fromV: selRange.fromV,
@@ -2,11 +2,12 @@ import classnames from 'classnames'
import { HistoryContextValue } from '../../context/types/history-context-value'
import { UpdateRange } from '../../services/types/update'
import { ReactNode, MouseEvent } from 'react'
import { ItemSelectionState } from '../../utils/history-details'
type HistoryVersionDetailsProps = {
children: ReactNode
updateRange: UpdateRange
selected: boolean
selected: ItemSelectionState
selectable: boolean
setSelection: HistoryContextValue['setSelection']
}
@@ -35,7 +36,9 @@ function HistoryVersionDetails({
// eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
<div
className={classnames('history-version-details clearfix', {
'history-version-selected': selected,
'history-version-selected':
selected === 'selectedEdge' || selected === 'selected',
'history-version-within-selected': selected === 'withinSelected',
'history-version-selectable': selectable,
})}
data-testid="history-version-details"
@@ -8,7 +8,10 @@ import { formatTime, relativeDate } from '../../../utils/format-date'
import { orderBy } from 'lodash'
import { LoadedUpdate } from '../../services/types/update'
import classNames from 'classnames'
import { updateRangeForUpdate } from '../../utils/history-details'
import {
updateRangeForUpdate,
ItemSelectionState,
} from '../../utils/history-details'
import { ActiveDropdown } from '../../hooks/use-dropdown-active-item'
import { memo, useCallback } from 'react'
import { HistoryContextValue } from '../../context/types/history-context-value'
@@ -22,7 +25,7 @@ type HistoryVersionProps = {
selectable: boolean
faded: boolean
showDivider: boolean
selected: boolean
selected: ItemSelectionState
setSelection: HistoryContextValue['setSelection']
dropdownOpen: boolean
dropdownActive: boolean
@@ -54,11 +57,28 @@ function HistoryVersion({
return (
<>
{showDivider ? <hr className="history-version-divider" /> : null}
{showDivider ? (
<div
className={classNames({
'history-version-divider-container': true,
'version-element-within-selected ':
selected === 'withinSelected' || selected === 'selectedEdge',
})}
>
<hr className="history-version-divider" />
</div>
) : null}
{update.meta.first_in_day ? (
<time className="history-version-day">
{relativeDate(update.meta.end_ts)}
</time>
<div
className={classNames({
'version-element-within-selected ':
selected === 'withinSelected' || selected === 'selectedEdge',
})}
>
<time className="history-version-day">
{relativeDate(update.meta.end_ts)}
</time>
</div>
) : null}
<div
data-testid="history-version"
@@ -90,13 +110,15 @@ function HistoryVersion({
</HistoryDropdown>
)}
{!selected ? (
{selected !== 'selected' ? (
<span data-testid="compare-icon-version" className="pull-right">
<CompareItems
updateRange={updateRange}
selected={selected}
closeDropdown={closeDropdown}
/>
{selected !== 'withinSelected' ? (
<CompareItems
updateRange={updateRange}
selected={selected}
closeDropdown={closeDropdown}
/>
) : null}
</span>
) : null}
@@ -12,13 +12,14 @@ 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'
import { ItemSelectionState } from '../../utils/history-details'
type LabelListItemProps = {
version: Version
labels: LoadedLabel[]
currentUserId: string
projectId: string
selected: boolean
selected: ItemSelectionState
selectable: boolean
setSelection: HistoryContextValue['setSelection']
dropdownOpen: boolean
@@ -1,7 +1,6 @@
import { useUserContext } from '../../../../shared/context/user-context'
import { isVersionSelected } from '../../utils/history-details'
import { useMemo } from 'react'
import { Version } from '../../services/types/update'
import LabelListItem from './label-list-item'
import useDropdownActiveItem from '../../hooks/use-dropdown-active-item'
import { getVersionWithLabels } from '../../utils/label'
@@ -18,18 +17,10 @@ function LabelsList() {
[labels]
)
const selectedVersions = new Set<Version>(
Array.from(versionWithLabels.values(), value => value.version).filter(
version => isVersionSelected(selection, version)
)
)
const singleVersionSelected = selectedVersions.size === 1
return (
<>
{versionWithLabels.map(({ version, labels }) => {
const selected = selectedVersions.has(version)
const selected = isVersionSelected(selection, version)
const dropdownActive = version === activeDropdownItem.item
return (
@@ -40,7 +31,7 @@ function LabelsList() {
currentUserId={currentUserId}
projectId={projectId}
selected={selected}
selectable={!(singleVersionSelected && selected)}
selectable={selected !== 'selected'}
setSelection={setSelection}
dropdownOpen={activeDropdownItem.isOpened && dropdownActive}
dropdownActive={dropdownActive}
@@ -37,36 +37,78 @@ export const getProjectOpDoc = (projectOp: ProjectOp) => {
return ''
}
export type ItemSelectionState =
| 'selectedEdge'
| 'withinSelected'
| 'aboveSelected'
| 'belowSelected'
| 'selected'
| null
export function isVersionSelected(
selection: Selection,
version: Version
): boolean
): ItemSelectionState
// eslint-disable-next-line no-redeclare
export function isVersionSelected(
selection: Selection,
fromV: Version,
toV: Version
): boolean
): ItemSelectionState
// eslint-disable-next-line no-redeclare
export function isVersionSelected(
selection: Selection,
...args: [Version] | [Version, Version]
): boolean {
): ItemSelectionState {
if (selection.updateRange) {
let [fromV, toV] = args
toV = toV ?? fromV
if (selection.comparing) {
// compare mode
return (
fromV >= selection.updateRange.fromV && toV <= selection.updateRange.toV
)
} else {
if (
fromV > selection.updateRange.fromV &&
toV < selection.updateRange.toV
) {
return 'withinSelected'
}
// Condition for selectedEdge when the comparing versions are from labels list
if (fromV === toV) {
if (
toV === selection.updateRange.fromV ||
fromV === selection.updateRange.toV
) {
return 'selectedEdge'
}
}
// Comparing mode above selected condition
if (fromV >= selection.updateRange.toV) {
return 'aboveSelected'
}
// Comparing mode below selected condition
if (toV <= selection.updateRange.fromV) {
return 'belowSelected'
}
if (
fromV === selection.updateRange.fromV ||
toV === selection.updateRange.toV
) {
return 'selectedEdge'
}
} else if (toV === selection.updateRange.toV) {
// single version mode
return toV === selection.updateRange.toV
return 'selected'
} else if (fromV >= selection.updateRange.toV) {
// Non-Comparing mode above selected condition
return 'aboveSelected'
} else if (toV <= selection.updateRange.fromV) {
// Non-Comparing mode below selected condition
return 'belowSelected'
}
}
return false
return null
}
export const getUpdateForVersion = (version: number, updates: LoadedUpdate[]) =>
@@ -90,7 +90,6 @@ history-root {
padding-top: 12px;
padding-bottom: 4px;
line-height: 20px;
background-color: @white;
}
.history-version-details {
@@ -106,10 +105,34 @@ history-root {
}
}
&.history-version-selected,
&.history-version-selected.history-version-selectable:hover {
&.history-version-selected {
background-color: @green-10;
border-left: 3px solid @green-50;
}
&.history-version-selected.history-version-selectable:hover {
background-color: fade(@green-70, 16%);
border-left: 3px solid @green-50;
}
&.history-version-within-selected {
background-color: @neutral-10;
border-left: 3px solid @green-50;
}
&.history-version-within-selected:hover {
background-color: fade(@neutral-90, 8%);
}
}
.version-element-within-selected {
background-color: @neutral-10;
border-left: 3px solid @green-50;
}
.version-element-selected {
background-color: @green-10;
border-left: 3px solid @green-50;
}
.history-version-metadata-time {
@@ -176,8 +199,12 @@ history-root {
overflow-wrap: anywhere;
}
.history-version-divider-container {
padding: 6px 8px;
}
.history-version-divider {
margin: 6px 8px;
margin: 0px;
border-color: @neutral-20;
}
@@ -384,6 +411,11 @@ history-root {
padding: 0;
}
.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;
@@ -44,6 +44,8 @@
@blueDark: #040d2d;
@green: #46a546;
@green-10: #ebf6ea;
@green-50: #138a07;
@green-70: #1f5919;
@green-30: #8cca86;
@red: #a93529;
@yellow: #a1a729;
@@ -339,9 +339,14 @@ describe('change list', function () {
cy.findByLabelText(/all history/i).click({ force: true })
cy.findAllByTestId('history-version-details').should($versions => {
const [first, ...rest] = Array.from($versions)
expect(first.dataset.selected === 'true').to.be.true
expect(rest.every(version => version.dataset.selected === 'false')).to
.be.true
expect(first.dataset.selected === 'selected').to.be.true
expect(
rest.every(
version =>
version.dataset.selected === 'belowSelected' ||
version.dataset.selected === 'aboveSelected'
)
).to.be.true
})
})
})
@@ -361,9 +366,11 @@ describe('change list', function () {
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')
expect(first).to.have.attr('data-selected', 'selected')
rest.forEach(version =>
expect(version).to.have.attr('data-selected', 'false')
// Based on the fact that we are selecting first version as we load the page
// Every other version will be belowSelected
expect(version).to.have.attr('data-selected', 'belowSelected')
)
})