Skip to content

Commit eacc0dd

Browse files
authored
Add unassigned event (#6972)
Fixes #6897
1 parent 5cdf414 commit eacc0dd

File tree

5 files changed

+93
-15
lines changed

5 files changed

+93
-15
lines changed

src/common/timelineEvent.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export enum EventType {
1616
Labeled,
1717
Milestoned,
1818
Assigned,
19+
Unassigned,
1920
HeadRefDeleted,
2021
Merged,
2122
CrossReferenced,
@@ -102,6 +103,14 @@ export interface AssignEvent {
102103
createdAt: string;
103104
}
104105

106+
export interface UnassignEvent {
107+
id: number;
108+
event: EventType.Unassigned;
109+
unassignees: IAccount[];
110+
actor: IActor;
111+
createdAt: string;
112+
}
113+
105114
export interface HeadRefDeleteEvent {
106115
id: string;
107116
event: EventType.HeadRefDeleted;
@@ -139,4 +148,4 @@ export interface ReopenedEvent {
139148
createdAt: string;
140149
}
141150

142-
export type TimelineEvent = CommitEvent | ReviewEvent | CommentEvent | NewCommitsSinceReviewEvent | MergedEvent | AssignEvent | HeadRefDeleteEvent | CrossReferencedEvent | ClosedEvent | ReopenedEvent;
151+
export type TimelineEvent = CommitEvent | ReviewEvent | CommentEvent | NewCommitsSinceReviewEvent | MergedEvent | AssignEvent | UnassignEvent | HeadRefDeleteEvent | CrossReferencedEvent | ClosedEvent | ReopenedEvent;

src/github/graphql.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,14 @@ export interface AssignedEvent {
198198
createdAt: string;
199199
}
200200

201+
export interface UnassignedEvent {
202+
__typename: string;
203+
id: number;
204+
actor: Actor;
205+
user: Account;
206+
createdAt: string;
207+
}
208+
201209
export interface MergeQueueEntry {
202210
position: number;
203211
state: MergeQueueState;

src/github/queriesShared.gql

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,20 @@ fragment AssignedEvent on AssignedEvent {
140140
createdAt
141141
}
142142

143+
fragment UnassignedEvent on UnassignedEvent {
144+
id
145+
actor {
146+
...Node
147+
...Actor
148+
}
149+
user {
150+
...Node
151+
...Actor
152+
...User
153+
}
154+
createdAt
155+
}
156+
143157
fragment CrossReferencedEvent on CrossReferencedEvent {
144158
id
145159
actor {
@@ -288,6 +302,7 @@ query TimelineEvents($owner: String!, $name: String!, $number: Int!, $last: Int
288302
...Review
289303
...Commit
290304
...AssignedEvent
305+
...UnassignedEvent
291306
...HeadRefDeleted
292307
...CrossReferencedEvent
293308
...ClosedEvent
@@ -309,6 +324,7 @@ query IssueTimelineEvents($owner: String!, $name: String!, $number: Int!, $last:
309324
__typename
310325
...Comment
311326
...AssignedEvent
327+
...UnassignedEvent
312328
...CrossReferencedEvent
313329
...ClosedEvent
314330
...ReopenedEvent
@@ -1545,6 +1561,7 @@ mutation MergePullRequest($input: MergePullRequestInput!, $last: Int = 150) {
15451561
...Review
15461562
...Commit
15471563
...AssignedEvent
1564+
...UnassignedEvent
15481565
...HeadRefDeleted
15491566
}
15501567
}

src/github/utils.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,8 @@ export function convertGraphQLEventType(text: string) {
471471
return Common.EventType.Milestoned;
472472
case 'AssignedEvent':
473473
return Common.EventType.Assigned;
474+
case 'UnassignedEvent':
475+
return Common.EventType.Unassigned;
474476
case 'HeadRefDeletedEvent':
475477
return Common.EventType.HeadRefDeleted;
476478
case 'IssueComment':
@@ -1082,6 +1084,17 @@ export async function parseGraphQLTimelineEvents(
10821084
createdAt: assignEv.createdAt,
10831085
});
10841086
break;
1087+
case Common.EventType.Unassigned:
1088+
const unassignEv = event as GraphQL.UnassignedEvent;
1089+
1090+
normalizedEvents.push({
1091+
id: unassignEv.id,
1092+
event: type,
1093+
unassignees: [parseAccount(unassignEv.user, githubRepository)],
1094+
actor: parseAccount(unassignEv.actor),
1095+
createdAt: unassignEv.createdAt,
1096+
});
1097+
break;
10851098
case Common.EventType.HeadRefDeleted:
10861099
const deletedEv = event as GraphQL.HeadRefDeletedEvent;
10871100

webviews/components/timeline.tsx

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ import {
1717
ReopenedEvent,
1818
ReviewEvent,
1919
TimelineEvent,
20+
UnassignEvent,
2021
} from '../../src/common/timelineEvent';
2122
import { groupBy, UnreachableCaseError } from '../../src/common/utils';
23+
import { IAccount, IActor } from '../../src/github/interface';
2224
import { ReviewType } from '../../src/github/views';
2325
import PullRequestContext from '../common/context';
2426
import { CommentView } from './comment';
@@ -28,16 +30,32 @@ import { nbsp } from './space';
2830
import { Timestamp } from './timestamp';
2931
import { AuthorLink, Avatar } from './user';
3032

33+
function isAssignUnassignEvent(event: TimelineEvent | ConsolidatedAssignUnassignEvent): event is AssignEvent | UnassignEvent {
34+
return event.event === EventType.Assigned || event.event === EventType.Unassigned;
35+
}
36+
37+
interface ConsolidatedAssignUnassignEvent {
38+
id: number;
39+
event: EventType.Assigned | EventType.Unassigned;
40+
assignees?: IAccount[];
41+
unassignees?: IAccount[];
42+
actor: IActor;
43+
createdAt: string;
44+
}
45+
3146
export const Timeline = ({ events, isIssue }: { events: TimelineEvent[], isIssue: boolean }) => {
32-
const consolidatedEvents: TimelineEvent[] = [];
47+
const consolidatedEvents: (TimelineEvent | ConsolidatedAssignUnassignEvent)[] = [];
3348
for (let i = 0; i < events.length; i++) {
34-
if ((i > 0) && (events[i].event === EventType.Assigned) && (consolidatedEvents[consolidatedEvents.length - 1].event === EventType.Assigned)) {
35-
const lastEvent = consolidatedEvents[consolidatedEvents.length - 1] as AssignEvent;
36-
const newEvent = events[i] as AssignEvent;
37-
if (new Date(lastEvent.createdAt).getTime() + (1000 * 60 * 10) > new Date(newEvent.createdAt).getTime()) { // within 10 minutes
38-
if (lastEvent.assignees.every(a => a.id !== newEvent.assignees[0].id)) {
39-
lastEvent.assignees = [...lastEvent.assignees, ...newEvent.assignees];
40-
}
49+
if ((i > 0) && isAssignUnassignEvent(events[i]) && isAssignUnassignEvent(consolidatedEvents[consolidatedEvents.length - 1])) {
50+
const lastEvent = consolidatedEvents[consolidatedEvents.length - 1] as ConsolidatedAssignUnassignEvent;
51+
const newEvent = events[i] as ConsolidatedAssignUnassignEvent;
52+
if ((lastEvent.actor.login === newEvent.actor.login) && (new Date(lastEvent.createdAt).getTime() + (1000 * 60 * 10) > new Date(newEvent.createdAt).getTime())) { // within 10 minutes
53+
const assignees = lastEvent.assignees || [];
54+
const unassignees = lastEvent.unassignees || [];
55+
const newAssignees = newEvent.assignees?.filter(a => !assignees.some(b => b.id === a.id)) ?? [];
56+
const newUnassignees = newEvent.unassignees?.filter(a => !unassignees.some(b => b.id === a.id)) ?? [];
57+
lastEvent.assignees = [...assignees, ...newAssignees];
58+
lastEvent.unassignees = [...unassignees, ...newUnassignees];
4159
lastEvent.createdAt = newEvent.createdAt;
4260
} else {
4361
consolidatedEvents.push(newEvent);
@@ -58,7 +76,9 @@ export const Timeline = ({ events, isIssue }: { events: TimelineEvent[], isIssue
5876
case EventType.Merged:
5977
return <MergedEventView key={`merged${event.id}`} {...event} />;
6078
case EventType.Assigned:
61-
return <AssignEventView key={`assign${event.id}`} event={event} isIssue={isIssue} />;
79+
return <AssignUnassignEventView key={`assign${event.id}`} event={event} />;
80+
case EventType.Unassigned:
81+
return <AssignUnassignEventView key={`unassign${event.id}`} event={event} />;
6282
case EventType.HeadRefDeleted:
6383
return <HeadDeleteEventView key={`head${event.id}`} {...event} />;
6484
case EventType.CrossReferenced:
@@ -344,9 +364,22 @@ function joinWithAnd(arr: JSX.Element[]): JSX.Element {
344364
return <>{arr.slice(0, -1).map(item => <>{item}, </>)} and {arr[arr.length - 1]}</>;
345365
}
346366

347-
const AssignEventView = ({ event, isIssue }: { event: AssignEvent, isIssue: boolean }) => {
348-
const { actor, assignees } = event;
367+
const AssignUnassignEventView = ({ event }: { event: AssignEvent | UnassignEvent | ConsolidatedAssignUnassignEvent }) => {
368+
const { actor } = event;
369+
const assignees = (event as AssignEvent).assignees || [];
370+
const unassignees = (event as UnassignEvent).unassignees || [];
349371
const joinedAssignees = joinWithAnd(assignees.map(a => <AuthorLink key={a.id} for={a} />));
372+
const joinedUnassignees = joinWithAnd(unassignees.map(a => <AuthorLink key={a.id} for={a} />));
373+
374+
let message: JSX.Element;
375+
if (assignees.length > 0 && unassignees.length > 0) {
376+
message = <>assigned {joinedAssignees} and unassigned {joinedUnassignees}</>;
377+
} else if (assignees.length > 0) {
378+
message = <>assigned {joinedAssignees}</>;
379+
} else {
380+
message = <>unassigned {joinedUnassignees}</>;
381+
}
382+
350383
return (
351384
<div className="comment-container commit">
352385
<div className="commit-message">
@@ -355,9 +388,7 @@ const AssignEventView = ({ event, isIssue }: { event: AssignEvent, isIssue: bool
355388
</div>
356389
<AuthorLink for={actor} />
357390
<div className="message">
358-
{isIssue
359-
? <>assigned {joinedAssignees}</>
360-
: <>assigned {joinedAssignees} to this pull request</>}
391+
{message}
361392
</div>
362393
</div>
363394
<Timestamp date={event.createdAt} />

0 commit comments

Comments
 (0)