ソースを参照

History UI changes- Adding enums for history versions

GitOrigin-RevId: 63f3a324889ad10e4a96994fa61f04bea4333630
Davinder Singh 3 年 前
コミット
7e5a476a95

+ 5 - 1
services/web/frontend/js/features/history/components/change-list/all-history-list.tsx

@@ -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

+ 7 - 55
services/web/frontend/js/features/history/components/change-list/dropdown/menu-item/compare-items.tsx

@@ -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,

+ 5 - 2
services/web/frontend/js/features/history/components/change-list/history-version-details.tsx

@@ -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"

+ 34 - 12
services/web/frontend/js/features/history/components/change-list/history-version.tsx

@@ -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}
 

+ 2 - 1
services/web/frontend/js/features/history/components/change-list/label-list-item.tsx

@@ -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

+ 2 - 11
services/web/frontend/js/features/history/components/change-list/labels-list.tsx

@@ -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}

+ 53 - 11
services/web/frontend/js/features/history/utils/history-details.ts

@@ -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[]) =>

+ 36 - 4
services/web/frontend/stylesheets/app/editor/history-react.less

@@ -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;

+ 2 - 0
services/web/frontend/stylesheets/core/variables.less

@@ -44,6 +44,8 @@
 @blueDark: #040d2d;
 @green: #46a546;
 @green-10: #ebf6ea;
+@green-50: #138a07;
+@green-70: #1f5919;
 @green-30: #8cca86;
 @red: #a93529;
 @yellow: #a1a729;

+ 12 - 5
services/web/test/frontend/features/history/components/change-list.spec.tsx

@@ -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')
         )
       })