Skip to content

Commit da0a09e

Browse files
committed
Populate authorDate when parsing reflog
This allows us to greatly simplify several components and will allow implementing branch sorting options
1 parent b82a373 commit da0a09e

10 files changed

Lines changed: 45 additions & 158 deletions

File tree

app/src/lib/git/for-each-ref.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export async function getBranches(
2121
upstreamTrackingBranch: '%(upstream:track)',
2222
sha: '%(objectname)',
2323
symRef: '%(symref)',
24+
authorDate: '%(authordate:iso8601)',
2425
})
2526

2627
if (!prefixes || !prefixes.length) {
@@ -41,15 +42,20 @@ export async function getBranches(
4142
return []
4243
}
4344

44-
const branches = []
45+
const branches: Branch[] = []
4546

4647
for (const ref of parse(result.stdout)) {
4748
// excude symbolic refs from the branch list
4849
if (ref.symRef.length > 0) {
4950
continue
5051
}
5152

52-
const tip: IBranchTip = { sha: ref.sha }
53+
const tip: IBranchTip = {
54+
sha: ref.sha,
55+
author: {
56+
date: new Date(ref.authorDate),
57+
},
58+
}
5359

5460
const type = ref.fullName.startsWith('refs/heads')
5561
? BranchType.Local

app/src/models/branch.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,14 @@ export interface ITrackingBranch {
2828
readonly upstreamSha: string
2929
}
3030

31+
export interface IAuthor {
32+
readonly date: Date
33+
}
34+
3135
/** Basic data about the latest commit on the branch. */
3236
export interface IBranchTip {
3337
readonly sha: string
38+
readonly author: IAuthor
3439
}
3540

3641
/** Default rules for where to create a branch from */

app/src/ui/branches/branch-list.tsx

Lines changed: 12 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import { SectionFilterList } from '../lib/section-filter-list'
2424
import { Octicon } from '../octicons'
2525
import * as octicons from '../octicons/octicons.generated'
2626
import memoizeOne from 'memoize-one'
27-
import { getAuthors } from '../../lib/git/log'
2827
import { Repository } from '../../models/repository'
2928
import { formatDate } from '../../lib/format-date'
3029

@@ -107,18 +106,14 @@ interface IBranchListProps {
107106
readonly textbox?: TextBox
108107

109108
/** Aria label for a specific row */
110-
readonly getBranchAriaLabel: (
111-
item: IBranchListItem,
112-
authorDate: Date | undefined
113-
) => string | undefined
109+
readonly getBranchAriaLabel: (item: IBranchListItem) => string | undefined
114110

115111
/**
116112
* Render function to apply to each branch in the list
117113
*/
118114
readonly renderBranch: (
119115
item: IBranchListItem,
120-
matches: IMatches,
121-
authorDate: Date | undefined
116+
matches: IMatches
122117
) => JSX.Element
123118

124119
/**
@@ -145,17 +140,8 @@ interface IBranchListProps {
145140
readonly onDeleteBranch?: (branchName: string) => void
146141
}
147142

148-
interface IBranchListState {
149-
readonly commitAuthorDates: ReadonlyMap<string, Date>
150-
}
151-
152-
const commitDateCache = new Map<string, Date>()
153-
154143
/** The Branches list component. */
155-
export class BranchList extends React.Component<
156-
IBranchListProps,
157-
IBranchListState
158-
> {
144+
export class BranchList extends React.Component<IBranchListProps> {
159145
private branchFilterList: SectionFilterList<IBranchListItem> | null = null
160146

161147
private getGroups = memoizeOne(groupBranches)
@@ -167,7 +153,7 @@ export class BranchList extends React.Component<
167153
)
168154

169155
/**
170-
* Generate a new object any time groups or commitAuthorDates changes
156+
* Generate a new object any time groups changes
171157
* in order to force the list to re-render.
172158
*
173159
* Note, change is determined by reference equality. This opaque object
@@ -179,14 +165,11 @@ export class BranchList extends React.Component<
179165
* Using a guid which we used to do works but is overkill.
180166
*/
181167
private getInvalidationProp = memoizeOne(
182-
(
183-
_groups: ReturnType<typeof groupBranches>,
184-
_commitAuthorDates: IBranchListState['commitAuthorDates']
185-
) => ({})
168+
(_groups: ReturnType<typeof groupBranches>) => ({})
186169
)
187170

188171
private get invalidationProp() {
189-
return this.getInvalidationProp(this.groups, this.state.commitAuthorDates)
172+
return this.getInvalidationProp(this.groups)
190173
}
191174

192175
private get groups() {
@@ -203,62 +186,11 @@ export class BranchList extends React.Component<
203186
return this.getSelectedItem(this.groups, this.props.selectedBranch)
204187
}
205188

206-
public constructor(props: IBranchListProps) {
207-
super(props)
208-
this.state = {
209-
commitAuthorDates: new Map<string, Date>(),
210-
}
211-
}
212-
213189
public selectNextItem(focus: boolean = false, direction: SelectionDirection) {
214190
if (this.branchFilterList !== null) {
215191
this.branchFilterList.selectNextItem(focus, direction)
216192
}
217193
}
218-
219-
public componentDidUpdate(prevProps: IBranchListProps) {
220-
if (prevProps.allBranches !== this.props.allBranches) {
221-
this.populateCommitDates()
222-
}
223-
}
224-
225-
private populateCommitDates = () => {
226-
const cached = new Map<string, Date>()
227-
const missing = new Array<string>()
228-
const uniqShas = new Set(this.props.allBranches.map(b => b.tip.sha))
229-
230-
for (const sha of uniqShas) {
231-
const date = commitDateCache.get(sha)
232-
if (date) {
233-
cached.set(sha, date)
234-
} else {
235-
missing.push(sha)
236-
}
237-
}
238-
239-
// Clean up the cache
240-
for (const sha of commitDateCache.keys()) {
241-
if (!uniqShas.has(sha)) {
242-
commitDateCache.delete(sha)
243-
}
244-
}
245-
246-
this.setState({ commitAuthorDates: cached })
247-
248-
if (missing.length > 0) {
249-
getAuthors(this.props.repository, missing)
250-
.then(x => {
251-
x.forEach(({ date }, i) => commitDateCache.set(missing[i], date))
252-
this.populateCommitDates()
253-
})
254-
.catch(e => log.error(`Failed to populate commit dates`, e))
255-
}
256-
}
257-
258-
public componentDidMount() {
259-
this.populateCommitDates()
260-
}
261-
262194
public render() {
263195
return (
264196
<SectionFilterList<IBranchListItem>
@@ -334,25 +266,18 @@ export class BranchList extends React.Component<
334266
}
335267

336268
private renderItem = (item: IBranchListItem, matches: IMatches) => {
337-
return this.props.renderBranch(
338-
item,
339-
matches,
340-
this.state.commitAuthorDates.get(item.branch.tip.sha)
341-
)
269+
return this.props.renderBranch(item, matches)
342270
}
343271

344272
private renderRowFocusTooltip = (
345273
item: IBranchListItem
346274
): JSX.Element | string | null => {
347275
const { tip, name } = item.branch
348-
const authorDate = this.state.commitAuthorDates.get(tip.sha)
349276

350-
const absoluteDate = authorDate
351-
? formatDate(authorDate, {
352-
dateStyle: 'full',
353-
timeStyle: 'short',
354-
})
355-
: null
277+
const absoluteDate = formatDate(tip.author.date, {
278+
dateStyle: 'full',
279+
timeStyle: 'short',
280+
})
356281

357282
const otherWorktreeName = this.inUseByOtherWorktreeName(item)
358283
return (
@@ -400,10 +325,7 @@ export class BranchList extends React.Component<
400325
}
401326

402327
private getItemAriaLabel = (item: IBranchListItem) => {
403-
return this.props.getBranchAriaLabel(
404-
item,
405-
this.state.commitAuthorDates.get(item.branch.tip.sha)
406-
)
328+
return this.props.getBranchAriaLabel(item)
407329
}
408330

409331
private getGroupAriaLabel = (group: number) => {

app/src/ui/branches/branch-renderer.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ export function renderDefaultBranch(
1212
item: IBranchListItem,
1313
matches: IMatches,
1414
currentBranch: Branch | null,
15-
authorDate: Date | undefined,
1615
onDropOntoBranch?: (branchName: string) => void,
1716
onDropOntoCurrentBranch?: () => void
1817
): JSX.Element {
@@ -29,7 +28,7 @@ export function renderDefaultBranch(
2928
<BranchListItem
3029
name={branch.name}
3130
isCurrentBranch={branch.name === currentBranchName}
32-
authorDate={authorDate}
31+
authorDate={branch.tip.author.date}
3332
isLocalOnly={isLocalOnly}
3433
matches={matches}
3534
worktreeName={worktreeName}
@@ -39,11 +38,9 @@ export function renderDefaultBranch(
3938
)
4039
}
4140

42-
export function getDefaultAriaLabelForBranch(
43-
item: IBranchListItem,
44-
authorDate: Date | undefined
45-
): string {
41+
export function getDefaultAriaLabelForBranch(item: IBranchListItem): string {
4642
const branch = item.branch
43+
const authorDate = branch.tip.author.date
4744

4845
if (!authorDate) {
4946
return branch.name

app/src/ui/branches/branch-select.tsx

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -67,24 +67,12 @@ export class BranchSelect extends React.Component<
6767
}
6868
}
6969

70-
private renderBranch = (
71-
item: IBranchListItem,
72-
matches: IMatches,
73-
authorDate: Date | undefined
74-
) => {
75-
return renderDefaultBranch(
76-
item,
77-
matches,
78-
this.props.currentBranch,
79-
authorDate
80-
)
70+
private renderBranch = (item: IBranchListItem, matches: IMatches) => {
71+
return renderDefaultBranch(item, matches, this.props.currentBranch)
8172
}
8273

83-
private getBranchAriaLabel = (
84-
item: IBranchListItem,
85-
authorDate: Date | undefined
86-
): string => {
87-
return getDefaultAriaLabelForBranch(item, authorDate)
74+
private getBranchAriaLabel = (item: IBranchListItem): string => {
75+
return getDefaultAriaLabelForBranch(item)
8876
}
8977

9078
private onItemClick = (branch: Branch, source: ClickSource) => {

app/src/ui/branches/branches-container.tsx

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -223,26 +223,18 @@ export class BranchesContainer extends React.Component<
223223
)
224224
}
225225

226-
private renderBranch = (
227-
item: IBranchListItem,
228-
matches: IMatches,
229-
authorDate: Date | undefined
230-
) => {
226+
private renderBranch = (item: IBranchListItem, matches: IMatches) => {
231227
return renderDefaultBranch(
232228
item,
233229
matches,
234230
this.props.currentBranch,
235-
authorDate,
236231
this.onDropOntoBranch,
237232
this.onDropOntoCurrentBranch
238233
)
239234
}
240235

241-
private getBranchAriaLabel = (
242-
item: IBranchListItem,
243-
authorDate: Date | undefined
244-
): string => {
245-
return getDefaultAriaLabelForBranch(item, authorDate)
236+
private getBranchAriaLabel = (item: IBranchListItem): string => {
237+
return getDefaultAriaLabelForBranch(item)
246238
}
247239

248240
private renderSelectedTab() {

app/src/ui/multi-commit-operation/choose-branch/base-choose-branch-dialog.tsx

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -202,24 +202,12 @@ export class ChooseBranchDialog extends React.Component<
202202
return <div className="merge-status-component">{children}</div>
203203
}
204204

205-
private renderBranch = (
206-
item: IBranchListItem,
207-
matches: IMatches,
208-
authorDate: Date | undefined
209-
) => {
210-
return renderDefaultBranch(
211-
item,
212-
matches,
213-
this.props.currentBranch,
214-
authorDate
215-
)
205+
private renderBranch = (item: IBranchListItem, matches: IMatches) => {
206+
return renderDefaultBranch(item, matches, this.props.currentBranch)
216207
}
217208

218-
private getBranchAriaLabel = (
219-
item: IBranchListItem,
220-
authorDate: Date | undefined
221-
): string => {
222-
return getDefaultAriaLabelForBranch(item, authorDate)
209+
private getBranchAriaLabel = (item: IBranchListItem): string => {
210+
return getDefaultAriaLabelForBranch(item)
223211
}
224212

225213
public render() {

app/src/ui/multi-commit-operation/choose-branch/choose-target-branch.tsx

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -95,24 +95,12 @@ export class ChooseTargetBranchDialog extends React.Component<
9595
this.setState({ selectedBranch })
9696
}
9797

98-
private renderBranch = (
99-
item: IBranchListItem,
100-
matches: IMatches,
101-
authorDate: Date | undefined
102-
) => {
103-
return renderDefaultBranch(
104-
item,
105-
matches,
106-
this.props.currentBranch,
107-
authorDate
108-
)
98+
private renderBranch = (item: IBranchListItem, matches: IMatches) => {
99+
return renderDefaultBranch(item, matches, this.props.currentBranch)
109100
}
110101

111-
private getBranchAriaLabel = (
112-
item: IBranchListItem,
113-
authorDate: Date | undefined
114-
): string => {
115-
return getDefaultAriaLabelForBranch(item, authorDate)
102+
private getBranchAriaLabel = (item: IBranchListItem): string => {
103+
return getDefaultAriaLabelForBranch(item)
116104
}
117105

118106
private onEnterPressed = (branch: Branch, source: ClickSource) => {

app/test/unit/create-branch-test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111

1212
const stubTip: IBranchTip = {
1313
sha: 'deadbeef',
14+
author: { date: new Date(0) },
1415
}
1516

1617
const defaultBranch: Branch = {

app/test/unit/git/checkout-test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ describe('git/checkout', () => {
2929
isGone: false,
3030
upstreamWithoutRemote: null,
3131
type: BranchType.Local,
32-
tip: { sha: '' },
32+
tip: { sha: '', author: { date: new Date(0) } },
3333
remoteName: null,
3434
upstreamRemoteName: null,
3535
isDesktopForkRemoteBranch: false,

0 commit comments

Comments
 (0)