mirror of
https://github.com/desktop/desktop
synced 2024-10-02 14:23:59 +00:00
Merge pull request #18157 from desktop/add-selectable-range-info
Add Diff Selectable Line Group Check All: Add selectable range info
This commit is contained in:
commit
0a20e1fa2b
|
@ -135,6 +135,54 @@ export class DiffSelection {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value indicating whether the range is all selected, partially
|
||||
* selected, or not selected.
|
||||
*
|
||||
* @param from The line index (inclusive) from where to checking the range.
|
||||
*
|
||||
* @param length The number of lines to check from the start point of
|
||||
* 'from', Assumes positive number, returns None if length is <= 0.
|
||||
*/
|
||||
public isRangeSelected(from: number, length: number): DiffSelectionType {
|
||||
if (length <= 0) {
|
||||
// This shouldn't happen? But if it does we'll log it and return None.
|
||||
return DiffSelectionType.None
|
||||
}
|
||||
|
||||
const computedSelectionType = this.getSelectionType()
|
||||
if (computedSelectionType !== DiffSelectionType.Partial) {
|
||||
// Nothing for us to do here. If all lines are selected or none, then any
|
||||
// range of lines will be the same.
|
||||
return computedSelectionType
|
||||
}
|
||||
|
||||
if (length === 1) {
|
||||
return this.isSelected(from)
|
||||
? DiffSelectionType.All
|
||||
: DiffSelectionType.None
|
||||
}
|
||||
|
||||
const to = from + length
|
||||
let foundSelected = false
|
||||
let foundDeselected = false
|
||||
for (let i = from; i < to; i++) {
|
||||
if (this.isSelected(i)) {
|
||||
foundSelected = true
|
||||
}
|
||||
|
||||
if (!this.isSelected(i)) {
|
||||
foundDeselected = true
|
||||
}
|
||||
|
||||
if (foundSelected && foundDeselected) {
|
||||
return DiffSelectionType.Partial
|
||||
}
|
||||
}
|
||||
|
||||
return foundSelected ? DiffSelectionType.All : DiffSelectionType.None
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value indicating wether the given line number is selectable.
|
||||
* A line not being selectable usually means it's a hunk header or a context
|
||||
|
|
|
@ -13,7 +13,7 @@ import { Octicon } from '../octicons'
|
|||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { narrowNoNewlineSymbol } from './text-diff'
|
||||
import { shallowEquals, structuralEquals } from '../../lib/equality'
|
||||
import { DiffHunkExpansionType } from '../../models/diff'
|
||||
import { DiffHunkExpansionType, DiffSelectionType } from '../../models/diff'
|
||||
import { PopoverAnchorPosition } from '../lib/popover'
|
||||
import { WhitespaceHintPopover } from './whitespace-hint-popover'
|
||||
import { TooltipDirection } from '../lib/tooltip'
|
||||
|
@ -27,6 +27,37 @@ enum DiffRowPrefix {
|
|||
Nothing = '\u{A0}',
|
||||
}
|
||||
|
||||
/**
|
||||
* This interface is used to pass information about a continuous group of
|
||||
* selectable rows to the row component as it pertains to a given row.
|
||||
*
|
||||
* Primarily used for the styling of the row and it's check all control.
|
||||
*/
|
||||
export interface IRowSelectableGroup {
|
||||
/**
|
||||
* Whether or not the row is the first in the selectable group
|
||||
*/
|
||||
isFirst: boolean
|
||||
/**
|
||||
* Whether or not the row is the last in the selectable group
|
||||
*/
|
||||
isLast: boolean
|
||||
/**
|
||||
* Whether or not the group is hovered by the mouse
|
||||
*/
|
||||
isGroupHovered: boolean
|
||||
|
||||
/**
|
||||
* Whether or not the group is focused by the keyboard
|
||||
*/
|
||||
isGroupFocused: boolean
|
||||
|
||||
/**
|
||||
* The selection state of the group - 'All', 'Partial', or 'None'
|
||||
*/
|
||||
groupSelectionState: DiffSelectionType | null
|
||||
}
|
||||
|
||||
interface ISideBySideDiffRowProps {
|
||||
/**
|
||||
* The row data. This contains most of the information used to render the row.
|
||||
|
|
|
@ -29,7 +29,7 @@ import {
|
|||
OverscanIndicesGetterParams,
|
||||
defaultOverscanIndicesGetter,
|
||||
} from 'react-virtualized'
|
||||
import { SideBySideDiffRow } from './side-by-side-diff-row'
|
||||
import { IRowSelectableGroup, SideBySideDiffRow } from './side-by-side-diff-row'
|
||||
import memoize from 'memoize-one'
|
||||
import {
|
||||
findInteractiveOriginalDiffRange,
|
||||
|
@ -609,6 +609,63 @@ export class SideBySideDiff extends React.Component<
|
|||
return defaultOverscanIndicesGetter({ ...params, startIndex, stopIndex })
|
||||
}
|
||||
|
||||
/**
|
||||
* Gathers information about if the row is in a selectable group. This
|
||||
* information is used to facilitate the use of check all feature for the
|
||||
* selectable group.
|
||||
*
|
||||
* This will return null if the row is not in a selectable group. A group is
|
||||
* more than one row.
|
||||
*/
|
||||
private getRowSelectableGroupDetails(
|
||||
row: SimplifiedDiffRow,
|
||||
prev: SimplifiedDiffRow,
|
||||
next: SimplifiedDiffRow
|
||||
): IRowSelectableGroup | null {
|
||||
if (!('hunkStartLine' in row)) {
|
||||
// can't be a selection hunk without a hunkStartLine
|
||||
return null
|
||||
}
|
||||
|
||||
const { diff, hoveredHunk } = this.state
|
||||
|
||||
const selectableType = [
|
||||
DiffRowType.Added,
|
||||
DiffRowType.Deleted,
|
||||
DiffRowType.Modified,
|
||||
]
|
||||
|
||||
if (!selectableType.includes(row.type)) {
|
||||
// We only care about selectable rows
|
||||
return null
|
||||
}
|
||||
|
||||
const range = findInteractiveOriginalDiffRange(
|
||||
diff.hunks,
|
||||
row.hunkStartLine
|
||||
)
|
||||
if (range === null || range.to - range.from === 0) {
|
||||
// We only care about ranges with more than one line
|
||||
return null
|
||||
}
|
||||
|
||||
const selection = this.getSelection()
|
||||
if (selection === undefined) {
|
||||
// We only care about selectable rows.. so if no selection, no selectable rows
|
||||
return null
|
||||
}
|
||||
|
||||
const { from, to } = range
|
||||
|
||||
return {
|
||||
isFirst: prev === undefined || !selectableType.includes(prev.type),
|
||||
isLast: next === undefined || !selectableType.includes(next.type),
|
||||
isGroupHovered: hoveredHunk === row.hunkStartLine,
|
||||
isGroupFocused: true, // focusedHunk === row.hunkStartLine, - To be added in later PR
|
||||
groupSelectionState: selection.isRangeSelected(from, to - from + 1),
|
||||
}
|
||||
}
|
||||
|
||||
private renderRow = ({ index, parent, style, key }: ListRowProps) => {
|
||||
const { diff } = this.state
|
||||
const rows = getDiffRows(
|
||||
|
@ -644,8 +701,14 @@ export class SideBySideDiff extends React.Component<
|
|||
|
||||
const rowWithTokens = this.createFullRow(row, index)
|
||||
|
||||
const isHunkHovered =
|
||||
'hunkStartLine' in row && this.state.hoveredHunk === row.hunkStartLine
|
||||
const getRowSelectableGroupDetails = this.getRowSelectableGroupDetails(
|
||||
row,
|
||||
prev,
|
||||
next
|
||||
)
|
||||
|
||||
// Just temporary until pass the whole row group data down.
|
||||
const isHunkHovered = !!getRowSelectableGroupDetails?.isGroupHovered
|
||||
|
||||
return (
|
||||
<CellMeasurer
|
||||
|
|
Loading…
Reference in a new issue