Merge changes from topic "ts-diff-host"
* changes: Convert gr-diff-host to typescript Rename files to preserve history
This commit is contained in:
@@ -27,6 +27,7 @@ import {runA11yAudit} from '../../../test/a11y-test-utils.js';
|
|||||||
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
|
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
|
||||||
import {TestKeyboardShortcutBinder} from '../../../test/test-utils.js';
|
import {TestKeyboardShortcutBinder} from '../../../test/test-utils.js';
|
||||||
import {Shortcut} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.js';
|
import {Shortcut} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.js';
|
||||||
|
import {ChangeComments} from '../../diff/gr-comment-api/gr-comment-api.js';
|
||||||
|
|
||||||
const commentApiMock = createCommentApiMockWithTemplateElement(
|
const commentApiMock = createCommentApiMockWithTemplateElement(
|
||||||
'gr-file-list-comment-api-mock', html`
|
'gr-file-list-comment-api-mock', html`
|
||||||
@@ -351,7 +352,7 @@ suite('gr-file-list tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('comment filtering', () => {
|
test('comment filtering', () => {
|
||||||
element.changeComments._comments = {
|
const comments = {
|
||||||
'/COMMIT_MSG': [
|
'/COMMIT_MSG': [
|
||||||
{patch_set: 1, message: 'Done', updated: '2017-02-08 16:40:49'},
|
{patch_set: 1, message: 'Done', updated: '2017-02-08 16:40:49'},
|
||||||
{patch_set: 1, message: 'oh hay', updated: '2017-02-09 16:40:49'},
|
{patch_set: 1, message: 'oh hay', updated: '2017-02-09 16:40:49'},
|
||||||
@@ -387,7 +388,7 @@ suite('gr-file-list tests', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
element.changeComments._drafts = {
|
const drafts = {
|
||||||
'/COMMIT_MSG': [
|
'/COMMIT_MSG': [
|
||||||
{
|
{
|
||||||
patch_set: 1,
|
patch_set: 1,
|
||||||
@@ -414,6 +415,7 @@ suite('gr-file-list tests', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
element.changeComments = new ChangeComments(comments, {}, drafts, 123);
|
||||||
|
|
||||||
const parentTo1 = {
|
const parentTo1 = {
|
||||||
basePatchNum: 'PARENT',
|
basePatchNum: 'PARENT',
|
||||||
|
|||||||
@@ -97,11 +97,8 @@ import {
|
|||||||
PolymerSplice,
|
PolymerSplice,
|
||||||
PolymerSpliceChange,
|
PolymerSpliceChange,
|
||||||
} from '@polymer/polymer/interfaces';
|
} from '@polymer/polymer/interfaces';
|
||||||
import {assertNever, hasOwnProperty} from '../../../utils/common-util';
|
import {assertNever} from '../../../utils/common-util';
|
||||||
import {
|
import {CommentThread, isDraft} from '../../diff/gr-comment-api/gr-comment-api';
|
||||||
CommentThread,
|
|
||||||
HumanCommentInfoWithPath,
|
|
||||||
} from '../../diff/gr-comment-api/gr-comment-api';
|
|
||||||
import {GrTextarea} from '../../shared/gr-textarea/gr-textarea';
|
import {GrTextarea} from '../../shared/gr-textarea/gr-textarea';
|
||||||
import {GrAccountChip} from '../../shared/gr-account-chip/gr-account-chip';
|
import {GrAccountChip} from '../../shared/gr-account-chip/gr-account-chip';
|
||||||
import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
|
import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
|
||||||
@@ -1029,10 +1026,7 @@ export class GrReplyDialog extends KeyboardShortcutMixin(
|
|||||||
_containsNewCommentThread(threads: CommentThread[]) {
|
_containsNewCommentThread(threads: CommentThread[]) {
|
||||||
return threads.some(
|
return threads.some(
|
||||||
thread =>
|
thread =>
|
||||||
!!thread.comments &&
|
!!thread.comments && !!thread.comments[0] && isDraft(thread.comments[0])
|
||||||
!!thread.comments[0] &&
|
|
||||||
hasOwnProperty(thread.comments[0], '__draft') &&
|
|
||||||
!!(thread.comments[0] as HumanCommentInfoWithPath).__draft
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,12 @@ import {parseDate} from '../../../utils/date-util';
|
|||||||
|
|
||||||
import {NO_THREADS_MSG} from '../../../constants/messages';
|
import {NO_THREADS_MSG} from '../../../constants/messages';
|
||||||
import {CommentSide, SpecialFilePath} from '../../../constants/constants';
|
import {CommentSide, SpecialFilePath} from '../../../constants/constants';
|
||||||
import {customElement, property, observe} from '@polymer/decorators';
|
import {customElement, observe, property} from '@polymer/decorators';
|
||||||
import {CommentThread} from '../../diff/gr-comment-api/gr-comment-api';
|
import {
|
||||||
import {Comment, RobotComment} from '../../shared/gr-comment/gr-comment';
|
CommentThread,
|
||||||
|
isDraft,
|
||||||
|
UIRobot,
|
||||||
|
} from '../../diff/gr-comment-api/gr-comment-api';
|
||||||
import {PolymerSpliceChange} from '@polymer/polymer/interfaces';
|
import {PolymerSpliceChange} from '@polymer/polymer/interfaces';
|
||||||
import {ChangeInfo} from '../../../types/common';
|
import {ChangeInfo} from '../../../types/common';
|
||||||
|
|
||||||
@@ -303,27 +306,32 @@ export class GrThreadList extends GestureEventListeners(
|
|||||||
|
|
||||||
_getThreadWithStatusInfo(thread: CommentThread): CommentThreadWithInfo {
|
_getThreadWithStatusInfo(thread: CommentThread): CommentThreadWithInfo {
|
||||||
const comments = thread.comments;
|
const comments = thread.comments;
|
||||||
const lastComment = (comments[comments.length - 1] || {}) as Comment;
|
const lastComment = comments.length
|
||||||
|
? comments[comments.length - 1]
|
||||||
|
: undefined;
|
||||||
let hasRobotComment = false;
|
let hasRobotComment = false;
|
||||||
let hasHumanReplyToRobotComment = false;
|
let hasHumanReplyToRobotComment = false;
|
||||||
comments.forEach(comment => {
|
comments.forEach(comment => {
|
||||||
if ((comment as RobotComment).robot_id) {
|
if ((comment as UIRobot).robot_id) {
|
||||||
hasRobotComment = true;
|
hasRobotComment = true;
|
||||||
} else if (hasRobotComment) {
|
} else if (hasRobotComment) {
|
||||||
hasHumanReplyToRobotComment = true;
|
hasHumanReplyToRobotComment = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
let updated = undefined;
|
||||||
|
if (lastComment) {
|
||||||
|
if (isDraft(lastComment)) updated = lastComment.__date;
|
||||||
|
if (lastComment.updated) updated = parseDate(lastComment.updated);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
thread,
|
thread,
|
||||||
hasRobotComment,
|
hasRobotComment,
|
||||||
hasHumanReplyToRobotComment,
|
hasHumanReplyToRobotComment,
|
||||||
unresolved: !!lastComment.unresolved,
|
unresolved: !!lastComment && !!lastComment.unresolved,
|
||||||
isEditing: !!lastComment.__editing,
|
isEditing: !!lastComment && !!lastComment.__editing,
|
||||||
hasDraft: !!lastComment.__draft,
|
hasDraft: !!lastComment && isDraft(lastComment),
|
||||||
updated: lastComment.updated
|
updated,
|
||||||
? parseDate(lastComment.updated)
|
|
||||||
: lastComment.__date,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ suite('gr-thread-list tests', () => {
|
|||||||
message: 'resolved draft',
|
message: 'resolved draft',
|
||||||
unresolved: false,
|
unresolved: false,
|
||||||
__draft: true,
|
__draft: true,
|
||||||
__draftID: '0.m683trwff68',
|
__draftID: '0.m683trwff69',
|
||||||
__editing: false,
|
__editing: false,
|
||||||
patch_set: '2',
|
patch_set: '2',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -38,11 +38,9 @@ import {
|
|||||||
RobotId,
|
RobotId,
|
||||||
} from '../../../types/common';
|
} from '../../../types/common';
|
||||||
import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
|
import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
|
||||||
import {
|
import {CommentEventDetail} from '../../shared/gr-comment/gr-comment';
|
||||||
CommentEventDetail,
|
|
||||||
isRobotComment,
|
|
||||||
} from '../../shared/gr-comment/gr-comment';
|
|
||||||
import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
|
import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
|
||||||
|
import {isRobot} from '../gr-comment-api/gr-comment-api';
|
||||||
|
|
||||||
export interface GrApplyFixDialog {
|
export interface GrApplyFixDialog {
|
||||||
$: {
|
$: {
|
||||||
@@ -115,7 +113,7 @@ export class GrApplyFixDialog extends GestureEventListeners(
|
|||||||
open(e: CustomEvent<CommentEventDetail>) {
|
open(e: CustomEvent<CommentEventDetail>) {
|
||||||
const detail = e.detail;
|
const detail = e.detail;
|
||||||
const comment = detail.comment;
|
const comment = detail.comment;
|
||||||
if (!detail.patchNum || !comment || !isRobotComment(comment)) {
|
if (!detail.patchNum || !comment || !isRobot(comment)) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
this._patchNum = detail.patchNum;
|
this._patchNum = detail.patchNum;
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ import {
|
|||||||
} from '../../../utils/patch-set-util';
|
} from '../../../utils/patch-set-util';
|
||||||
import {customElement, property} from '@polymer/decorators';
|
import {customElement, property} from '@polymer/decorators';
|
||||||
import {
|
import {
|
||||||
|
CommentBasics,
|
||||||
CommentInfo,
|
CommentInfo,
|
||||||
ConfigInfo,
|
ConfigInfo,
|
||||||
ParentPatchSetNum,
|
ParentPatchSetNum,
|
||||||
PatchRange,
|
PatchRange,
|
||||||
PatchSetNum,
|
PatchSetNum,
|
||||||
PathToCommentsInfoMap,
|
|
||||||
PathToRobotCommentsInfoMap,
|
PathToRobotCommentsInfoMap,
|
||||||
RobotCommentInfo,
|
RobotCommentInfo,
|
||||||
Timestamp,
|
Timestamp,
|
||||||
@@ -40,36 +40,61 @@ import {
|
|||||||
NumericChangeId,
|
NumericChangeId,
|
||||||
} from '../../../types/common';
|
} from '../../../types/common';
|
||||||
import {hasOwnProperty} from '../../../utils/common-util';
|
import {hasOwnProperty} from '../../../utils/common-util';
|
||||||
import {CommentSide} from '../../../constants/constants';
|
import {CommentSide, Side} from '../../../constants/constants';
|
||||||
import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
|
import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
|
||||||
|
|
||||||
export interface HumanCommentInfoWithPath extends CommentInfo {
|
export interface DraftCommentProps {
|
||||||
path: string;
|
|
||||||
__draft?: boolean;
|
__draft?: boolean;
|
||||||
|
__draftID?: string;
|
||||||
__date?: Date;
|
__date?: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RobotCommentInfoWithPath extends RobotCommentInfo {
|
export type DraftInfo = CommentBasics & DraftCommentProps;
|
||||||
path: string;
|
|
||||||
|
/**
|
||||||
|
* Each of the type implements or extends CommentBasics.
|
||||||
|
*/
|
||||||
|
export type Comment = DraftInfo | CommentInfo | RobotCommentInfo;
|
||||||
|
|
||||||
|
export interface UIStateCommentProps {
|
||||||
|
// The `side` of the comment is PARENT or REVISION, but this is LEFT or RIGHT.
|
||||||
|
// TODO(TS): Remove the naming confusion of commentSide being of type of Side,
|
||||||
|
// but side being of type CommentSide. :-)
|
||||||
|
__commentSide?: Side;
|
||||||
|
// TODO(TS): Remove this. Seems to be exactly the same as `path`??
|
||||||
|
__path?: string;
|
||||||
|
collapsed?: boolean;
|
||||||
|
// TODO(TS): Consider allowing this only for drafts.
|
||||||
|
__editing?: boolean;
|
||||||
|
__otherEditing?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CommentInfoWithPath =
|
export type UIDraft = DraftInfo & UIStateCommentProps;
|
||||||
| HumanCommentInfoWithPath
|
|
||||||
| RobotCommentInfoWithPath;
|
|
||||||
|
|
||||||
// TODO(TS): Can be removed, CommentInfoWithTwoPaths already has a path
|
export type UIHuman = CommentInfo & UIStateCommentProps;
|
||||||
export type CommentInfoWithTwoPaths = CommentInfoWithPath & {__path: string};
|
|
||||||
|
|
||||||
export type PathToCommentsInfoWithPathMap = {
|
export type UIRobot = RobotCommentInfo & UIStateCommentProps;
|
||||||
[path: string]: CommentInfoWithPath[];
|
|
||||||
};
|
export type UIComment = UIHuman | UIRobot | UIDraft;
|
||||||
|
|
||||||
export type CommentMap = {[path: string]: boolean};
|
export type CommentMap = {[path: string]: boolean};
|
||||||
|
|
||||||
|
export function isRobot<T extends CommentInfo>(
|
||||||
|
x: T | DraftInfo | RobotCommentInfo | undefined
|
||||||
|
): x is RobotCommentInfo {
|
||||||
|
return !!x && !!(x as RobotCommentInfo).robot_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isDraft<T extends CommentInfo>(
|
||||||
|
x: T | UIDraft | undefined
|
||||||
|
): x is UIDraft {
|
||||||
|
return !!x && !!(x as UIDraft).__draft;
|
||||||
|
}
|
||||||
|
|
||||||
export interface PatchSetFile {
|
export interface PatchSetFile {
|
||||||
path: string;
|
path: string;
|
||||||
basePath?: string;
|
basePath?: string;
|
||||||
patchNum: PatchSetNum;
|
patchNum?: PatchSetNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PatchNumOnly {
|
export interface PatchNumOnly {
|
||||||
@@ -107,9 +132,13 @@ export function sortComments<T extends SortableComment>(comments: T[]): T[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface CommentThread {
|
export interface CommentThread {
|
||||||
comments: CommentInfoWithTwoPaths[];
|
comments: UIComment[];
|
||||||
patchNum?: PatchSetNum;
|
patchNum?: PatchSetNum;
|
||||||
path: string;
|
path: string;
|
||||||
|
// TODO(TS): It would be nice to use LineNumber here, but the comment thread
|
||||||
|
// element actually relies on line to be undefined for file comments. Be
|
||||||
|
// aware of element attribute getters and setters, if you try to refactor
|
||||||
|
// this. :-) Still worthwhile to do ...
|
||||||
line?: number;
|
line?: number;
|
||||||
rootId: UrlEncodedCommentId;
|
rootId: UrlEncodedCommentId;
|
||||||
commentSide?: CommentSide;
|
commentSide?: CommentSide;
|
||||||
@@ -119,7 +148,7 @@ export type CommentIdToCommentThreadMap = {
|
|||||||
[urlEncodedCommentId: string]: CommentThread;
|
[urlEncodedCommentId: string]: CommentThread;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface TwoSidesComments {
|
export interface TwoSidesComments {
|
||||||
// TODO(TS): remove meta - it is not used anywhere
|
// TODO(TS): remove meta - it is not used anywhere
|
||||||
meta: {
|
meta: {
|
||||||
changeNum: NumericChangeId;
|
changeNum: NumericChangeId;
|
||||||
@@ -127,16 +156,16 @@ interface TwoSidesComments {
|
|||||||
patchRange: PatchRange;
|
patchRange: PatchRange;
|
||||||
projectConfig?: ConfigInfo;
|
projectConfig?: ConfigInfo;
|
||||||
};
|
};
|
||||||
left: CommentInfoWithPath[];
|
left: UIComment[];
|
||||||
right: CommentInfoWithPath[];
|
right: UIComment[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ChangeComments {
|
export class ChangeComments {
|
||||||
private readonly _comments: PathToCommentsInfoWithPathMap;
|
private readonly _comments: {[path: string]: UIHuman[]};
|
||||||
|
|
||||||
private readonly _robotComments: PathToCommentsInfoWithPathMap;
|
private readonly _robotComments: {[path: string]: UIRobot[]};
|
||||||
|
|
||||||
private readonly _drafts: PathToCommentsInfoWithPathMap;
|
private readonly _drafts: {[path: string]: UIDraft[]};
|
||||||
|
|
||||||
private readonly _changeNum: NumericChangeId;
|
private readonly _changeNum: NumericChangeId;
|
||||||
|
|
||||||
@@ -145,9 +174,9 @@ export class ChangeComments {
|
|||||||
* elements of that which uses the gr-comment-api.
|
* elements of that which uses the gr-comment-api.
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
comments: PathToCommentsInfoMap | undefined,
|
comments: {[path: string]: UIHuman[]} | undefined,
|
||||||
robotComments: PathToRobotCommentsInfoMap | undefined,
|
robotComments: {[path: string]: UIRobot[]} | undefined,
|
||||||
drafts: PathToCommentsInfoMap | undefined,
|
drafts: {[path: string]: UIDraft[]} | undefined,
|
||||||
changeNum: NumericChangeId
|
changeNum: NumericChangeId
|
||||||
) {
|
) {
|
||||||
this._comments = this._addPath(comments);
|
this._comments = this._addPath(comments);
|
||||||
@@ -164,10 +193,10 @@ export class ChangeComments {
|
|||||||
* TODO(taoalpha): should consider changing BE to send path
|
* TODO(taoalpha): should consider changing BE to send path
|
||||||
* back within CommentInfo
|
* back within CommentInfo
|
||||||
*/
|
*/
|
||||||
_addPath(
|
_addPath<T>(
|
||||||
comments: PathToCommentsInfoMap = {}
|
comments: {[path: string]: T[]} = {}
|
||||||
): PathToCommentsInfoWithPathMap {
|
): {[path: string]: Array<T & {path: string}>} {
|
||||||
const updatedComments: PathToCommentsInfoWithPathMap = {};
|
const updatedComments: {[path: string]: Array<T & {path: string}>} = {};
|
||||||
for (const filePath of Object.keys(comments)) {
|
for (const filePath of Object.keys(comments)) {
|
||||||
const allCommentsForPath = comments[filePath] || [];
|
const allCommentsForPath = comments[filePath] || [];
|
||||||
if (allCommentsForPath.length) {
|
if (allCommentsForPath.length) {
|
||||||
@@ -191,10 +220,8 @@ export class ChangeComments {
|
|||||||
return this._robotComments;
|
return this._robotComments;
|
||||||
}
|
}
|
||||||
|
|
||||||
findCommentById(
|
findCommentById(commentId: UrlEncodedCommentId): Comment | undefined {
|
||||||
commentId: UrlEncodedCommentId
|
const findComment = (comments: {[path: string]: CommentBasics[]}) => {
|
||||||
): HumanCommentInfoWithPath | RobotCommentInfoWithPath | undefined {
|
|
||||||
const findComment = (comments: PathToCommentsInfoWithPathMap) => {
|
|
||||||
let comment;
|
let comment;
|
||||||
for (const path of Object.keys(comments)) {
|
for (const path of Object.keys(comments)) {
|
||||||
comment = comment || comments[path].find(c => c.id === commentId);
|
comment = comment || comments[path].find(c => c.id === commentId);
|
||||||
@@ -216,7 +243,11 @@ export class ChangeComments {
|
|||||||
* patchNum and basePatchNum properties to represent the range.
|
* patchNum and basePatchNum properties to represent the range.
|
||||||
*/
|
*/
|
||||||
getPaths(patchRange?: PatchRange): CommentMap {
|
getPaths(patchRange?: PatchRange): CommentMap {
|
||||||
const responses = [this.comments, this.drafts, this.robotComments];
|
const responses: {[path: string]: UIComment[]}[] = [
|
||||||
|
this.comments,
|
||||||
|
this.drafts,
|
||||||
|
this.robotComments,
|
||||||
|
];
|
||||||
const commentMap: CommentMap = {};
|
const commentMap: CommentMap = {};
|
||||||
for (const response of responses) {
|
for (const response of responses) {
|
||||||
for (const path in response) {
|
for (const path in response) {
|
||||||
@@ -240,9 +271,7 @@ export class ChangeComments {
|
|||||||
/**
|
/**
|
||||||
* Gets all the comments and robot comments for the given change.
|
* Gets all the comments and robot comments for the given change.
|
||||||
*/
|
*/
|
||||||
getAllPublishedComments(
|
getAllPublishedComments(patchNum?: PatchSetNum) {
|
||||||
patchNum?: PatchSetNum
|
|
||||||
): PathToCommentsInfoWithPathMap {
|
|
||||||
return this.getAllComments(false, patchNum);
|
return this.getAllComments(false, patchNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,12 +292,9 @@ export class ChangeComments {
|
|||||||
/**
|
/**
|
||||||
* Gets all the comments and robot comments for the given change.
|
* Gets all the comments and robot comments for the given change.
|
||||||
*/
|
*/
|
||||||
getAllComments(
|
getAllComments(includeDrafts?: boolean, patchNum?: PatchSetNum) {
|
||||||
includeDrafts?: boolean,
|
|
||||||
patchNum?: PatchSetNum
|
|
||||||
): PathToCommentsInfoWithPathMap {
|
|
||||||
const paths = this.getPaths();
|
const paths = this.getPaths();
|
||||||
const publishedComments: PathToCommentsInfoWithPathMap = {};
|
const publishedComments: {[path: string]: CommentBasics[]} = {};
|
||||||
for (const path of Object.keys(paths)) {
|
for (const path of Object.keys(paths)) {
|
||||||
publishedComments[path] = this.getAllCommentsForPath(
|
publishedComments[path] = this.getAllCommentsForPath(
|
||||||
path,
|
path,
|
||||||
@@ -282,9 +308,9 @@ export class ChangeComments {
|
|||||||
/**
|
/**
|
||||||
* Gets all the drafts for the given change.
|
* Gets all the drafts for the given change.
|
||||||
*/
|
*/
|
||||||
getAllDrafts(patchNum?: PatchSetNum): PathToCommentsInfoWithPathMap {
|
getAllDrafts(patchNum?: PatchSetNum) {
|
||||||
const paths = this.getPaths();
|
const paths = this.getPaths();
|
||||||
const drafts: PathToCommentsInfoWithPathMap = {};
|
const drafts: {[path: string]: UIDraft[]} = {};
|
||||||
for (const path of Object.keys(paths)) {
|
for (const path of Object.keys(paths)) {
|
||||||
drafts[path] = this.getAllDraftsForPath(path, patchNum);
|
drafts[path] = this.getAllDraftsForPath(path, patchNum);
|
||||||
}
|
}
|
||||||
@@ -302,8 +328,8 @@ export class ChangeComments {
|
|||||||
path: string,
|
path: string,
|
||||||
patchNum?: PatchSetNum,
|
patchNum?: PatchSetNum,
|
||||||
includeDrafts?: boolean
|
includeDrafts?: boolean
|
||||||
): CommentInfoWithPath[] {
|
): Comment[] {
|
||||||
const comments = this._comments[path] || [];
|
const comments: Comment[] = this._comments[path] || [];
|
||||||
const robotComments = this._robotComments[path] || [];
|
const robotComments = this._robotComments[path] || [];
|
||||||
let allComments = comments.concat(robotComments);
|
let allComments = comments.concat(robotComments);
|
||||||
if (includeDrafts) {
|
if (includeDrafts) {
|
||||||
@@ -347,10 +373,7 @@ export class ChangeComments {
|
|||||||
* This will return a shallow copy of all drafts every time,
|
* This will return a shallow copy of all drafts every time,
|
||||||
* so changes on any copy will not affect other copies.
|
* so changes on any copy will not affect other copies.
|
||||||
*/
|
*/
|
||||||
getAllDraftsForPath(
|
getAllDraftsForPath(path: string, patchNum?: PatchSetNum): Comment[] {
|
||||||
path: string,
|
|
||||||
patchNum?: PatchSetNum
|
|
||||||
): CommentInfoWithPath[] {
|
|
||||||
let comments = this._drafts[path] || [];
|
let comments = this._drafts[path] || [];
|
||||||
if (patchNum) {
|
if (patchNum) {
|
||||||
comments = comments.filter(c => patchNumEquals(c.patch_set, patchNum));
|
comments = comments.filter(c => patchNumEquals(c.patch_set, patchNum));
|
||||||
@@ -365,7 +388,7 @@ export class ChangeComments {
|
|||||||
*
|
*
|
||||||
* // TODO(taoalpha): maybe merge in *ForPath
|
* // TODO(taoalpha): maybe merge in *ForPath
|
||||||
*/
|
*/
|
||||||
getAllDraftsForFile(file: PatchSetFile): CommentInfoWithPath[] {
|
getAllDraftsForFile(file: PatchSetFile): Comment[] {
|
||||||
let allDrafts = this.getAllDraftsForPath(file.path, file.patchNum);
|
let allDrafts = this.getAllDraftsForPath(file.path, file.patchNum);
|
||||||
if (file.basePath) {
|
if (file.basePath) {
|
||||||
allDrafts = allDrafts.concat(
|
allDrafts = allDrafts.concat(
|
||||||
@@ -390,9 +413,9 @@ export class ChangeComments {
|
|||||||
patchRange: PatchRange,
|
patchRange: PatchRange,
|
||||||
projectConfig?: ConfigInfo
|
projectConfig?: ConfigInfo
|
||||||
): TwoSidesComments {
|
): TwoSidesComments {
|
||||||
let comments: CommentInfoWithPath[] = [];
|
let comments: Comment[] = [];
|
||||||
let drafts: CommentInfoWithPath[] = [];
|
let drafts: DraftInfo[] = [];
|
||||||
let robotComments: CommentInfoWithPath[] = [];
|
let robotComments: RobotCommentInfo[] = [];
|
||||||
if (this.comments && this.comments[path]) {
|
if (this.comments && this.comments[path]) {
|
||||||
comments = this.comments[path];
|
comments = this.comments[path];
|
||||||
}
|
}
|
||||||
@@ -404,11 +427,10 @@ export class ChangeComments {
|
|||||||
}
|
}
|
||||||
|
|
||||||
drafts.forEach(d => {
|
drafts.forEach(d => {
|
||||||
// drafts don't include robot comments
|
d.__draft = true;
|
||||||
(d as HumanCommentInfoWithPath).__draft = true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const all = comments
|
const all: Comment[] = comments
|
||||||
.concat(drafts)
|
.concat(drafts)
|
||||||
.concat(robotComments)
|
.concat(robotComments)
|
||||||
.map(c => {
|
.map(c => {
|
||||||
@@ -450,7 +472,7 @@ export class ChangeComments {
|
|||||||
file: PatchSetFile,
|
file: PatchSetFile,
|
||||||
patchRange: PatchRange,
|
patchRange: PatchRange,
|
||||||
projectConfig?: ConfigInfo
|
projectConfig?: ConfigInfo
|
||||||
) {
|
): TwoSidesComments {
|
||||||
const comments = this.getCommentsBySideForPath(
|
const comments = this.getCommentsBySideForPath(
|
||||||
file.path,
|
file.path,
|
||||||
patchRange,
|
patchRange,
|
||||||
@@ -476,24 +498,22 @@ export class ChangeComments {
|
|||||||
* also includes the file that it was left on, which was the key of the
|
* also includes the file that it was left on, which was the key of the
|
||||||
* originall object.
|
* originall object.
|
||||||
*/
|
*/
|
||||||
_commentObjToArrayWithFile(
|
_commentObjToArrayWithFile<T>(comments: {
|
||||||
comments: PathToCommentsInfoWithPathMap
|
[path: string]: T[];
|
||||||
): CommentInfoWithTwoPaths[] {
|
}): Array<T & {__path: string}> {
|
||||||
let commentArr: CommentInfoWithTwoPaths[] = [];
|
let commentArr: Array<T & {__path: string}> = [];
|
||||||
for (const file of Object.keys(comments)) {
|
for (const file of Object.keys(comments)) {
|
||||||
const commentsForFile = [];
|
const commentsForFile: Array<T & {__path: string}> = [];
|
||||||
for (const comment of comments[file]) {
|
for (const comment of comments[file]) {
|
||||||
commentsForFile.push({__path: file, ...comment});
|
commentsForFile.push({...comment, __path: file});
|
||||||
}
|
}
|
||||||
commentArr = commentArr.concat(commentsForFile);
|
commentArr = commentArr.concat(commentsForFile);
|
||||||
}
|
}
|
||||||
return commentArr;
|
return commentArr;
|
||||||
}
|
}
|
||||||
|
|
||||||
_commentObjToArray(
|
_commentObjToArray<T>(comments: {[path: string]: T[]}): T[] {
|
||||||
comments: PathToCommentsInfoWithPathMap
|
let commentArr: T[] = [];
|
||||||
): CommentInfoWithPath[] {
|
|
||||||
let commentArr: CommentInfoWithPath[] = [];
|
|
||||||
for (const file of Object.keys(comments)) {
|
for (const file of Object.keys(comments)) {
|
||||||
commentArr = commentArr.concat(comments[file]);
|
commentArr = commentArr.concat(comments[file]);
|
||||||
}
|
}
|
||||||
@@ -527,8 +547,8 @@ export class ChangeComments {
|
|||||||
* Computes a number of unresolved comment threads in a given file and path.
|
* Computes a number of unresolved comment threads in a given file and path.
|
||||||
*/
|
*/
|
||||||
computeUnresolvedNum(file: PatchSetFile | PatchNumOnly) {
|
computeUnresolvedNum(file: PatchSetFile | PatchNumOnly) {
|
||||||
let comments: CommentInfoWithPath[] = [];
|
let comments: Comment[] = [];
|
||||||
let drafts: CommentInfoWithPath[] = [];
|
let drafts: Comment[] = [];
|
||||||
|
|
||||||
if (isPatchSetFile(file)) {
|
if (isPatchSetFile(file)) {
|
||||||
comments = this.getAllCommentsForFile(file);
|
comments = this.getAllCommentsForFile(file);
|
||||||
@@ -541,12 +561,7 @@ export class ChangeComments {
|
|||||||
|
|
||||||
comments = comments.concat(drafts);
|
comments = comments.concat(drafts);
|
||||||
|
|
||||||
// TODO(TS): the 'as CommentInfoWithTwoPaths[]' is completely wrong below
|
const threads = this.getCommentThreads(sortComments(comments));
|
||||||
// However, this doesn't affect the final result of computeUnresolvedNum
|
|
||||||
// This should be fixed by removing CommentInfoWithTwoPaths later
|
|
||||||
const threads = this.getCommentThreads(
|
|
||||||
sortComments(comments) as CommentInfoWithTwoPaths[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const unresolvedThreads = threads.filter(
|
const unresolvedThreads = threads.filter(
|
||||||
thread =>
|
thread =>
|
||||||
@@ -568,7 +583,7 @@ export class ChangeComments {
|
|||||||
*
|
*
|
||||||
* @param comments sorted by updated timestamp.
|
* @param comments sorted by updated timestamp.
|
||||||
*/
|
*/
|
||||||
getCommentThreads(comments: CommentInfoWithTwoPaths[]) {
|
getCommentThreads(comments: UIComment[]) {
|
||||||
const threads: CommentThread[] = [];
|
const threads: CommentThread[] = [];
|
||||||
const idThreadMap: CommentIdToCommentThreadMap = {};
|
const idThreadMap: CommentIdToCommentThreadMap = {};
|
||||||
for (const comment of comments) {
|
for (const comment of comments) {
|
||||||
@@ -585,10 +600,13 @@ export class ChangeComments {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, this comment starts its own thread.
|
// Otherwise, this comment starts its own thread.
|
||||||
|
if (!comment.__path && !comment.path) {
|
||||||
|
throw new Error('Comment missing required "path".');
|
||||||
|
}
|
||||||
const newThread: CommentThread = {
|
const newThread: CommentThread = {
|
||||||
comments: [comment],
|
comments: [comment],
|
||||||
patchNum: comment.patch_set,
|
patchNum: comment.patch_set,
|
||||||
path: comment.__path,
|
path: comment.__path || comment.path!,
|
||||||
line: comment.line,
|
line: comment.line,
|
||||||
rootId: comment.id,
|
rootId: comment.id,
|
||||||
};
|
};
|
||||||
@@ -605,7 +623,7 @@ export class ChangeComments {
|
|||||||
* Whether the given comment should be included in the base side of the
|
* Whether the given comment should be included in the base side of the
|
||||||
* given patch range.
|
* given patch range.
|
||||||
*/
|
*/
|
||||||
_isInBaseOfPatchRange(comment: CommentInfo, range: PatchRange) {
|
_isInBaseOfPatchRange(comment: CommentBasics, range: PatchRange) {
|
||||||
// If the base of the patch range is a parent of a merge, and the comment
|
// If the base of the patch range is a parent of a merge, and the comment
|
||||||
// appears on a specific parent then only show the comment if the parent
|
// appears on a specific parent then only show the comment if the parent
|
||||||
// index of the comment matches that of the range.
|
// index of the comment matches that of the range.
|
||||||
@@ -636,7 +654,7 @@ export class ChangeComments {
|
|||||||
* Whether the given comment should be included in the revision side of the
|
* Whether the given comment should be included in the revision side of the
|
||||||
* given patch range.
|
* given patch range.
|
||||||
*/
|
*/
|
||||||
_isInRevisionOfPatchRange(comment: CommentInfo, range: PatchRange) {
|
_isInRevisionOfPatchRange(comment: CommentBasics, range: PatchRange) {
|
||||||
return (
|
return (
|
||||||
comment.side !== CommentSide.PARENT &&
|
comment.side !== CommentSide.PARENT &&
|
||||||
patchNumEquals(comment.patch_set, range.patchNum)
|
patchNumEquals(comment.patch_set, range.patchNum)
|
||||||
@@ -646,7 +664,7 @@ export class ChangeComments {
|
|||||||
/**
|
/**
|
||||||
* Whether the given comment should be included in the given patch range.
|
* Whether the given comment should be included in the given patch range.
|
||||||
*/
|
*/
|
||||||
_isInPatchRange(comment: CommentInfo, range: PatchRange): boolean {
|
_isInPatchRange(comment: CommentBasics, range: PatchRange): boolean {
|
||||||
return (
|
return (
|
||||||
this._isInBaseOfPatchRange(comment, range) ||
|
this._isInBaseOfPatchRange(comment, range) ||
|
||||||
this._isInRevisionOfPatchRange(comment, range)
|
this._isInRevisionOfPatchRange(comment, range)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
import '../../../test/common-test-setup-karma.js';
|
import '../../../test/common-test-setup-karma.js';
|
||||||
import './gr-comment-api.js';
|
import './gr-comment-api.js';
|
||||||
|
import {ChangeComments} from './gr-comment-api.js';
|
||||||
|
|
||||||
const basicFixture = fixtureFromElement('gr-comment-api');
|
const basicFixture = fixtureFromElement('gr-comment-api');
|
||||||
|
|
||||||
@@ -216,7 +217,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setup(() => {
|
setup(() => {
|
||||||
element._changeComments._drafts = {
|
const drafts = {
|
||||||
'file/one': [
|
'file/one': [
|
||||||
{
|
{
|
||||||
id: '11',
|
id: '11',
|
||||||
@@ -244,7 +245,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
element._changeComments._robotComments = {
|
const robotComments = {
|
||||||
'file/one': [
|
'file/one': [
|
||||||
{
|
{
|
||||||
id: '01',
|
id: '01',
|
||||||
@@ -268,7 +269,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
element._changeComments._comments = {
|
const comments = {
|
||||||
'file/one': [
|
'file/one': [
|
||||||
{
|
{
|
||||||
id: '03',
|
id: '03',
|
||||||
@@ -305,6 +306,8 @@ suite('gr-comment-api tests', () => {
|
|||||||
{id: '10', patch_set: 5, line: 1, updated: makeTime(1)},
|
{id: '10', patch_set: 5, line: 1, updated: makeTime(1)},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
element._changeComments =
|
||||||
|
new ChangeComments(comments, robotComments, drafts, 1234);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('getPaths', () => {
|
test('getPaths', () => {
|
||||||
@@ -405,9 +408,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('computeUnresolvedNum w/ non-linear thread', () => {
|
test('computeUnresolvedNum w/ non-linear thread', () => {
|
||||||
element._changeComments._drafts = {};
|
const comments = {
|
||||||
element._changeComments._robotComments = {};
|
|
||||||
element._changeComments._comments = {
|
|
||||||
path: [{
|
path: [{
|
||||||
id: '9c6ba3c6_28b7d467',
|
id: '9c6ba3c6_28b7d467',
|
||||||
patch_set: 1,
|
patch_set: 1,
|
||||||
@@ -433,6 +434,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
unresolved: false,
|
unresolved: false,
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
|
element._changeComments = new ChangeComments(comments, {}, {}, 1234);
|
||||||
assert.equal(
|
assert.equal(
|
||||||
element._changeComments.computeUnresolvedNum(1, 'path'), 0);
|
element._changeComments.computeUnresolvedNum(1, 'path'), 0);
|
||||||
});
|
});
|
||||||
@@ -523,6 +525,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
end_line: 2,
|
end_line: 2,
|
||||||
end_character: 2,
|
end_character: 2,
|
||||||
},
|
},
|
||||||
|
path: 'file/one',
|
||||||
__path: 'file/one',
|
__path: 'file/one',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -538,6 +541,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
patch_set: 2,
|
patch_set: 2,
|
||||||
side: 'PARENT',
|
side: 'PARENT',
|
||||||
line: 2,
|
line: 2,
|
||||||
|
path: 'file/one',
|
||||||
__path: 'file/one',
|
__path: 'file/one',
|
||||||
updated: '2013-02-26 15:01:43.986000000',
|
updated: '2013-02-26 15:01:43.986000000',
|
||||||
},
|
},
|
||||||
@@ -553,6 +557,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
id: '04',
|
id: '04',
|
||||||
patch_set: 2,
|
patch_set: 2,
|
||||||
line: 1,
|
line: 1,
|
||||||
|
path: 'file/one',
|
||||||
__path: 'file/one',
|
__path: 'file/one',
|
||||||
updated: '2013-02-26 15:01:43.986000000',
|
updated: '2013-02-26 15:01:43.986000000',
|
||||||
},
|
},
|
||||||
@@ -562,6 +567,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
patch_set: 2,
|
patch_set: 2,
|
||||||
unresolved: true,
|
unresolved: true,
|
||||||
line: 1,
|
line: 1,
|
||||||
|
path: 'file/one',
|
||||||
__path: 'file/one',
|
__path: 'file/one',
|
||||||
updated: '2013-02-26 15:03:43.986000000',
|
updated: '2013-02-26 15:03:43.986000000',
|
||||||
},
|
},
|
||||||
@@ -570,6 +576,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
in_reply_to: '04',
|
in_reply_to: '04',
|
||||||
patch_set: 2,
|
patch_set: 2,
|
||||||
line: 1,
|
line: 1,
|
||||||
|
path: 'file/one',
|
||||||
__path: 'file/one',
|
__path: 'file/one',
|
||||||
__draft: true,
|
__draft: true,
|
||||||
updated: '2013-02-26 15:02:43.986000000',
|
updated: '2013-02-26 15:02:43.986000000',
|
||||||
@@ -585,6 +592,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
id: '05',
|
id: '05',
|
||||||
patch_set: 2,
|
patch_set: 2,
|
||||||
line: 2,
|
line: 2,
|
||||||
|
path: 'file/two',
|
||||||
__path: 'file/two',
|
__path: 'file/two',
|
||||||
updated: '2013-02-26 15:01:43.986000000',
|
updated: '2013-02-26 15:01:43.986000000',
|
||||||
},
|
},
|
||||||
@@ -599,6 +607,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
id: '06',
|
id: '06',
|
||||||
patch_set: 3,
|
patch_set: 3,
|
||||||
line: 2,
|
line: 2,
|
||||||
|
path: 'file/two',
|
||||||
__path: 'file/two',
|
__path: 'file/two',
|
||||||
updated: '2013-02-26 15:01:43.986000000',
|
updated: '2013-02-26 15:01:43.986000000',
|
||||||
},
|
},
|
||||||
@@ -615,6 +624,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
side: 'PARENT',
|
side: 'PARENT',
|
||||||
unresolved: true,
|
unresolved: true,
|
||||||
line: 1,
|
line: 1,
|
||||||
|
path: 'file/three',
|
||||||
__path: 'file/three',
|
__path: 'file/three',
|
||||||
updated: '2013-02-26 15:01:43.986000000',
|
updated: '2013-02-26 15:01:43.986000000',
|
||||||
},
|
},
|
||||||
@@ -630,6 +640,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
id: '08',
|
id: '08',
|
||||||
patch_set: 3,
|
patch_set: 3,
|
||||||
line: 1,
|
line: 1,
|
||||||
|
path: 'file/three',
|
||||||
__path: 'file/three',
|
__path: 'file/three',
|
||||||
updated: '2013-02-26 15:01:43.986000000',
|
updated: '2013-02-26 15:01:43.986000000',
|
||||||
},
|
},
|
||||||
@@ -645,6 +656,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
patch_set: 5,
|
patch_set: 5,
|
||||||
side: 'PARENT',
|
side: 'PARENT',
|
||||||
line: 1,
|
line: 1,
|
||||||
|
path: 'file/four',
|
||||||
__path: 'file/four',
|
__path: 'file/four',
|
||||||
updated: '2013-02-26 15:01:43.986000000',
|
updated: '2013-02-26 15:01:43.986000000',
|
||||||
},
|
},
|
||||||
@@ -660,6 +672,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
id: '10',
|
id: '10',
|
||||||
patch_set: 5,
|
patch_set: 5,
|
||||||
line: 1,
|
line: 1,
|
||||||
|
path: 'file/four',
|
||||||
__path: 'file/four',
|
__path: 'file/four',
|
||||||
updated: '2013-02-26 15:01:43.986000000',
|
updated: '2013-02-26 15:01:43.986000000',
|
||||||
},
|
},
|
||||||
@@ -674,6 +687,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
id: '05',
|
id: '05',
|
||||||
patch_set: 3,
|
patch_set: 3,
|
||||||
line: 1,
|
line: 1,
|
||||||
|
path: 'file/two',
|
||||||
__path: 'file/two',
|
__path: 'file/two',
|
||||||
__draft: true,
|
__draft: true,
|
||||||
updated: '2013-02-26 15:03:43.986000000',
|
updated: '2013-02-26 15:03:43.986000000',
|
||||||
@@ -690,6 +704,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
patch_set: 2,
|
patch_set: 2,
|
||||||
side: 'PARENT',
|
side: 'PARENT',
|
||||||
line: 1,
|
line: 1,
|
||||||
|
path: 'file/one',
|
||||||
__path: 'file/one',
|
__path: 'file/one',
|
||||||
__draft: true,
|
__draft: true,
|
||||||
updated: '2013-02-26 15:03:43.986000000',
|
updated: '2013-02-26 15:03:43.986000000',
|
||||||
@@ -710,6 +725,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
let expectedComments = [
|
let expectedComments = [
|
||||||
{
|
{
|
||||||
__path: 'file/one',
|
__path: 'file/one',
|
||||||
|
path: 'file/one',
|
||||||
id: '04',
|
id: '04',
|
||||||
patch_set: 2,
|
patch_set: 2,
|
||||||
line: 1,
|
line: 1,
|
||||||
@@ -717,6 +733,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
__path: 'file/one',
|
__path: 'file/one',
|
||||||
|
path: 'file/one',
|
||||||
id: '02',
|
id: '02',
|
||||||
in_reply_to: '04',
|
in_reply_to: '04',
|
||||||
patch_set: 2,
|
patch_set: 2,
|
||||||
@@ -726,6 +743,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
__path: 'file/one',
|
__path: 'file/one',
|
||||||
|
path: 'file/one',
|
||||||
__draft: true,
|
__draft: true,
|
||||||
id: '12',
|
id: '12',
|
||||||
in_reply_to: '04',
|
in_reply_to: '04',
|
||||||
@@ -742,6 +760,7 @@ suite('gr-comment-api tests', () => {
|
|||||||
patch_set: 2,
|
patch_set: 2,
|
||||||
side: 'PARENT',
|
side: 'PARENT',
|
||||||
line: 1,
|
line: 1,
|
||||||
|
path: 'file/one',
|
||||||
__path: 'file/one',
|
__path: 'file/one',
|
||||||
__draft: true,
|
__draft: true,
|
||||||
updated: '2013-02-26 15:03:43.986000000',
|
updated: '2013-02-26 15:03:43.986000000',
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-l
|
|||||||
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
|
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
|
||||||
import {PolymerElement} from '@polymer/polymer/polymer-element';
|
import {PolymerElement} from '@polymer/polymer/polymer-element';
|
||||||
import {htmlTemplate} from './gr-coverage-layer_html';
|
import {htmlTemplate} from './gr-coverage-layer_html';
|
||||||
import {CoverageType, DiffLayer} from '../../../types/types';
|
import {CoverageRange, CoverageType, DiffLayer} from '../../../types/types';
|
||||||
import {customElement, property} from '@polymer/decorators';
|
import {customElement, property} from '@polymer/decorators';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@@ -45,11 +45,9 @@ export class GrCoverageLayer
|
|||||||
/**
|
/**
|
||||||
* Must be sorted by code_range.start_line.
|
* Must be sorted by code_range.start_line.
|
||||||
* Must only contain ranges that match the side.
|
* Must only contain ranges that match the side.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
// TODO(TS): convert into AnnotationLayer once gr-diff-is converted
|
|
||||||
@property({type: Array})
|
@property({type: Array})
|
||||||
coverageRanges: any[] = [];
|
coverageRanges: CoverageRange[] = [];
|
||||||
|
|
||||||
@property({type: String})
|
@property({type: String})
|
||||||
side?: string;
|
side?: string;
|
||||||
|
|||||||
@@ -317,9 +317,7 @@ export class GrDiffBuilderElement extends GestureEventListeners(
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSideByLineEl(lineEl: Element) {
|
getSideByLineEl(lineEl: Element) {
|
||||||
return lineEl.classList.contains(GrDiffBuilder.Side.RIGHT)
|
return lineEl.classList.contains(Side.RIGHT) ? Side.RIGHT : Side.LEFT;
|
||||||
? Side.RIGHT
|
|
||||||
: Side.LEFT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emitGroup(group: GrDiffGroup, sectionEl: HTMLElement) {
|
emitGroup(group: GrDiffGroup, sectionEl: HTMLElement) {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import {
|
|||||||
} from '../gr-diff/gr-diff-group';
|
} from '../gr-diff/gr-diff-group';
|
||||||
import {BlameInfo, DiffInfo, DiffPreferencesInfo} from '../../../types/common';
|
import {BlameInfo, DiffInfo, DiffPreferencesInfo} from '../../../types/common';
|
||||||
import {Side} from '../../../constants/constants';
|
import {Side} from '../../../constants/constants';
|
||||||
|
import {DiffLayer} from '../../../types/types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In JS, unicode code points above 0xFFFF occupy two elements of a string.
|
* In JS, unicode code points above 0xFFFF occupy two elements of a string.
|
||||||
@@ -86,8 +87,7 @@ export abstract class GrDiffBuilder {
|
|||||||
diff: DiffInfo,
|
diff: DiffInfo,
|
||||||
prefs: DiffPreferencesInfo,
|
prefs: DiffPreferencesInfo,
|
||||||
outputEl: HTMLElement,
|
outputEl: HTMLElement,
|
||||||
// TODO(TS): Replace any by a layer interface.
|
readonly layers: DiffLayer[] = []
|
||||||
readonly layers: any[] = []
|
|
||||||
) {
|
) {
|
||||||
this._diff = diff;
|
this._diff = diff;
|
||||||
this._numLinesLeft = this._diff.content
|
this._numLinesLeft = this._diff.content
|
||||||
@@ -142,12 +142,6 @@ export abstract class GrDiffBuilder {
|
|||||||
REMOVED: 'edit_a',
|
REMOVED: 'edit_a',
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO(TS): Convert to enum.
|
|
||||||
static readonly Side = {
|
|
||||||
LEFT: 'left',
|
|
||||||
RIGHT: 'right',
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO(TS): Replace usages with ContextButtonType enum.
|
// TODO(TS): Replace usages with ContextButtonType enum.
|
||||||
static readonly ContextButtonType = {
|
static readonly ContextButtonType = {
|
||||||
ABOVE: 'above',
|
ABOVE: 'above',
|
||||||
@@ -480,10 +474,14 @@ export abstract class GrDiffBuilder {
|
|||||||
contentText.setAttribute('data-side', side);
|
contentText.setAttribute('data-side', side);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const layer of this.layers) {
|
if (lineNumberEl) {
|
||||||
if (typeof layer.annotate === 'function') {
|
for (const layer of this.layers) {
|
||||||
layer.annotate(contentText, lineNumberEl, line);
|
if (typeof layer.annotate === 'function') {
|
||||||
|
layer.annotate(contentText, lineNumberEl, line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.error('The lineNumberEl is null, skipping layer annotations.');
|
||||||
}
|
}
|
||||||
|
|
||||||
td.appendChild(contentText);
|
td.appendChild(contentText);
|
||||||
|
|||||||
@@ -26,9 +26,8 @@ import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-l
|
|||||||
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
|
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
|
||||||
import {PolymerElement} from '@polymer/polymer/polymer-element';
|
import {PolymerElement} from '@polymer/polymer/polymer-element';
|
||||||
import {htmlTemplate} from './gr-diff-cursor_html';
|
import {htmlTemplate} from './gr-diff-cursor_html';
|
||||||
import {ScrollMode} from '../../../constants/constants';
|
import {ScrollMode, Side} from '../../../constants/constants';
|
||||||
import {customElement, property, observe} from '@polymer/decorators';
|
import {customElement, property, observe} from '@polymer/decorators';
|
||||||
import {DiffSide} from '../gr-diff/gr-diff-utils';
|
|
||||||
import {GrDiffLineType} from '../gr-diff/gr-diff-line';
|
import {GrDiffLineType} from '../gr-diff/gr-diff-line';
|
||||||
import {PolymerSpliceChange} from '@polymer/polymer/interfaces';
|
import {PolymerSpliceChange} from '@polymer/polymer/interfaces';
|
||||||
import {PolymerDomWrapper} from '../../../types/types';
|
import {PolymerDomWrapper} from '../../../types/types';
|
||||||
@@ -83,7 +82,7 @@ export class GrDiffCursor extends GestureEventListeners(
|
|||||||
private _lastDisplayedNavigateToNextFileToast: number | null = null;
|
private _lastDisplayedNavigateToNextFileToast: number | null = null;
|
||||||
|
|
||||||
@property({type: String})
|
@property({type: String})
|
||||||
side = DiffSide.RIGHT;
|
side = Side.RIGHT;
|
||||||
|
|
||||||
@property({type: Object, notify: true, observer: '_rowChanged'})
|
@property({type: Object, notify: true, observer: '_rowChanged'})
|
||||||
diffRow?: HTMLElement;
|
diffRow?: HTMLElement;
|
||||||
@@ -162,14 +161,14 @@ export class GrDiffCursor extends GestureEventListeners(
|
|||||||
}
|
}
|
||||||
|
|
||||||
moveLeft() {
|
moveLeft() {
|
||||||
this.side = DiffSide.LEFT;
|
this.side = Side.LEFT;
|
||||||
if (this._isTargetBlank()) {
|
if (this._isTargetBlank()) {
|
||||||
this.moveUp();
|
this.moveUp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
moveRight() {
|
moveRight() {
|
||||||
this.side = DiffSide.RIGHT;
|
this.side = Side.RIGHT;
|
||||||
if (this._isTargetBlank()) {
|
if (this._isTargetBlank()) {
|
||||||
this.moveUp();
|
this.moveUp();
|
||||||
}
|
}
|
||||||
@@ -272,7 +271,7 @@ export class GrDiffCursor extends GestureEventListeners(
|
|||||||
this._fixSide();
|
this._fixSide();
|
||||||
}
|
}
|
||||||
|
|
||||||
moveToLineNumber(number: number, side: DiffSide, path?: string) {
|
moveToLineNumber(number: number, side: Side, path?: string) {
|
||||||
const row = this._findRowByNumberAndFile(number, side, path);
|
const row = this._findRowByNumberAndFile(number, side, path);
|
||||||
if (row) {
|
if (row) {
|
||||||
this.side = side;
|
this.side = side;
|
||||||
@@ -291,7 +290,7 @@ export class GrDiffCursor extends GestureEventListeners(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this._getViewMode() === DiffViewMode.SIDE_BY_SIDE) {
|
if (this._getViewMode() === DiffViewMode.SIDE_BY_SIDE) {
|
||||||
lineElSelector += this.side === DiffSide.LEFT ? '.left' : '.right';
|
lineElSelector += this.side === Side.LEFT ? '.left' : '.right';
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.diffRow.querySelector(lineElSelector);
|
return this.diffRow.querySelector(lineElSelector);
|
||||||
@@ -452,7 +451,7 @@ export class GrDiffCursor extends GestureEventListeners(
|
|||||||
|
|
||||||
_rowHasSide(row: Element) {
|
_rowHasSide(row: Element) {
|
||||||
const selector =
|
const selector =
|
||||||
(this.side === DiffSide.LEFT ? '.left' : '.right') + ' + .content';
|
(this.side === Side.LEFT ? '.left' : '.right') + ' + .content';
|
||||||
return !!row.querySelector(selector);
|
return !!row.querySelector(selector);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,7 +477,7 @@ export class GrDiffCursor extends GestureEventListeners(
|
|||||||
this._getViewMode() === DiffViewMode.SIDE_BY_SIDE &&
|
this._getViewMode() === DiffViewMode.SIDE_BY_SIDE &&
|
||||||
this._isTargetBlank()
|
this._isTargetBlank()
|
||||||
) {
|
) {
|
||||||
this.side = this.side === DiffSide.LEFT ? DiffSide.RIGHT : DiffSide.LEFT;
|
this.side = this.side === Side.LEFT ? Side.RIGHT : Side.LEFT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,8 +488,8 @@ export class GrDiffCursor extends GestureEventListeners(
|
|||||||
|
|
||||||
const actions = this._getActionsForRow();
|
const actions = this._getActionsForRow();
|
||||||
return (
|
return (
|
||||||
(this.side === DiffSide.LEFT && !actions.left) ||
|
(this.side === Side.LEFT && !actions.left) ||
|
||||||
(this.side === DiffSide.RIGHT && !actions.right)
|
(this.side === Side.RIGHT && !actions.right)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,16 +505,8 @@ export class GrDiffCursor extends GestureEventListeners(
|
|||||||
if (!this.diffRow) {
|
if (!this.diffRow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.toggleClass(
|
this.toggleClass(LEFT_SIDE_CLASS, this.side === Side.LEFT, this.diffRow);
|
||||||
LEFT_SIDE_CLASS,
|
this.toggleClass(RIGHT_SIDE_CLASS, this.side === Side.RIGHT, this.diffRow);
|
||||||
this.side === DiffSide.LEFT,
|
|
||||||
this.diffRow
|
|
||||||
);
|
|
||||||
this.toggleClass(
|
|
||||||
RIGHT_SIDE_CLASS,
|
|
||||||
this.side === DiffSide.RIGHT,
|
|
||||||
this.diffRow
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_isActionType(type: GrDiffRowType) {
|
_isActionType(type: GrDiffRowType) {
|
||||||
@@ -601,7 +592,7 @@ export class GrDiffCursor extends GestureEventListeners(
|
|||||||
|
|
||||||
_findRowByNumberAndFile(
|
_findRowByNumberAndFile(
|
||||||
targetNumber: number,
|
targetNumber: number,
|
||||||
side: DiffSide,
|
side: Side,
|
||||||
path?: string
|
path?: string
|
||||||
): HTMLElement | undefined {
|
): HTMLElement | undefined {
|
||||||
let stops;
|
let stops;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
1228
polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
Normal file
1228
polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -20,8 +20,8 @@ import './gr-diff-host.js';
|
|||||||
import {GrDiffBuilderImage} from '../gr-diff-builder/gr-diff-builder-image.js';
|
import {GrDiffBuilderImage} from '../gr-diff-builder/gr-diff-builder-image.js';
|
||||||
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
|
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
|
||||||
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
|
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
|
||||||
import {DiffSide} from '../gr-diff/gr-diff-utils.js';
|
|
||||||
import {sortComments} from '../gr-comment-api/gr-comment-api.js';
|
import {sortComments} from '../gr-comment-api/gr-comment-api.js';
|
||||||
|
import {Side} from '../../../constants/constants.js';
|
||||||
|
|
||||||
const basicFixture = fixtureFromElement('gr-diff-host');
|
const basicFixture = fixtureFromElement('gr-diff-host');
|
||||||
|
|
||||||
@@ -36,6 +36,8 @@ suite('gr-diff-host tests', () => {
|
|||||||
async getLoggedIn() { return getLoggedIn; },
|
async getLoggedIn() { return getLoggedIn; },
|
||||||
});
|
});
|
||||||
element = basicFixture.instantiate();
|
element = basicFixture.instantiate();
|
||||||
|
element.changeNum = 123;
|
||||||
|
element.path = 'some/path';
|
||||||
sinon.stub(element.reporting, 'time');
|
sinon.stub(element.reporting, 'time');
|
||||||
sinon.stub(element.reporting, 'timeEnd');
|
sinon.stub(element.reporting, 'timeEnd');
|
||||||
});
|
});
|
||||||
@@ -47,6 +49,8 @@ suite('gr-diff-host tests', () => {
|
|||||||
getDiffLayers() { return pluginLayers; },
|
getDiffLayers() { return pluginLayers; },
|
||||||
});
|
});
|
||||||
element = basicFixture.instantiate();
|
element = basicFixture.instantiate();
|
||||||
|
element.changeNum = 123;
|
||||||
|
element.path = 'some/path';
|
||||||
});
|
});
|
||||||
test('plugin layers requested', () => {
|
test('plugin layers requested', () => {
|
||||||
element.patchRange = {};
|
element.patchRange = {};
|
||||||
@@ -172,7 +176,6 @@ suite('gr-diff-host tests', () => {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
element._removeComment({});
|
|
||||||
// Using JSON.stringify because Safari 9.1 (11601.5.17.1) doesn’t seem
|
// Using JSON.stringify because Safari 9.1 (11601.5.17.1) doesn’t seem
|
||||||
// to believe that one object deepEquals another even when they do :-/.
|
// to believe that one object deepEquals another even when they do :-/.
|
||||||
assert.equal(JSON.stringify(element.comments), JSON.stringify({
|
assert.equal(JSON.stringify(element.comments), JSON.stringify({
|
||||||
@@ -249,12 +252,20 @@ suite('gr-diff-host tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('thread-discard handling', () => {
|
test('thread-discard handling', () => {
|
||||||
const threads = [
|
const threads = element._createThreads([
|
||||||
{comments: [{id: 4711}]},
|
{
|
||||||
{comments: [{id: 42}]},
|
id: 4711,
|
||||||
];
|
__commentSide: 'left',
|
||||||
|
updated: '2015-12-20 15:01:20.396000000',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 42,
|
||||||
|
__commentSide: 'left',
|
||||||
|
updated: '2017-12-20 15:01:20.396000000',
|
||||||
|
},
|
||||||
|
]);
|
||||||
element._parentIndex = 1;
|
element._parentIndex = 1;
|
||||||
element.changeNum = '2';
|
element.changeNum = 2;
|
||||||
element.path = 'some/path';
|
element.path = 'some/path';
|
||||||
element.projectName = 'Some project';
|
element.projectName = 'Some project';
|
||||||
const threadEls = threads.map(
|
const threadEls = threads.map(
|
||||||
@@ -268,8 +279,8 @@ suite('gr-diff-host tests', () => {
|
|||||||
return threadEl;
|
return threadEl;
|
||||||
});
|
});
|
||||||
assert.equal(threadEls.length, 2);
|
assert.equal(threadEls.length, 2);
|
||||||
assert.equal(threadEls[0].rootId, 4711);
|
assert.equal(threadEls[0].comments[0].id, 4711);
|
||||||
assert.equal(threadEls[1].rootId, 42);
|
assert.equal(threadEls[1].comments[0].id, 42);
|
||||||
for (const threadEl of threadEls) {
|
for (const threadEl of threadEls) {
|
||||||
element.appendChild(threadEl);
|
element.appendChild(threadEl);
|
||||||
}
|
}
|
||||||
@@ -279,7 +290,7 @@ suite('gr-diff-host tests', () => {
|
|||||||
const attachedThreads = element.queryAllEffectiveChildren(
|
const attachedThreads = element.queryAllEffectiveChildren(
|
||||||
'gr-comment-thread');
|
'gr-comment-thread');
|
||||||
assert.equal(attachedThreads.length, 1);
|
assert.equal(attachedThreads.length, 1);
|
||||||
assert.equal(attachedThreads[0].rootId, 42);
|
assert.equal(attachedThreads[0].comments[0].id, 42);
|
||||||
});
|
});
|
||||||
|
|
||||||
suite('render reporting', () => {
|
suite('render reporting', () => {
|
||||||
@@ -393,6 +404,8 @@ suite('gr-diff-host tests', () => {
|
|||||||
setup(() => {
|
setup(() => {
|
||||||
getLoggedIn = false;
|
getLoggedIn = false;
|
||||||
element = basicFixture.instantiate();
|
element = basicFixture.instantiate();
|
||||||
|
element.changeNum = 123;
|
||||||
|
element.path = 'some/path';
|
||||||
});
|
});
|
||||||
|
|
||||||
test('reload() loads files weblinks', () => {
|
test('reload() loads files weblinks', () => {
|
||||||
@@ -852,6 +865,8 @@ suite('gr-diff-host tests', () => {
|
|||||||
suite('blame', () => {
|
suite('blame', () => {
|
||||||
setup(() => {
|
setup(() => {
|
||||||
element = basicFixture.instantiate();
|
element = basicFixture.instantiate();
|
||||||
|
element.changeNum = 123;
|
||||||
|
element.path = 'some/path';
|
||||||
});
|
});
|
||||||
|
|
||||||
test('clearBlame', () => {
|
test('clearBlame', () => {
|
||||||
@@ -933,9 +948,8 @@ suite('gr-diff-host tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('passes in changeNum', () => {
|
test('passes in changeNum', () => {
|
||||||
const value = '12345';
|
element.changeNum = 12345;
|
||||||
element.changeNum = value;
|
assert.equal(element.$.diff.changeNum, 12345);
|
||||||
assert.equal(element.$.diff.changeNum, value);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('passes in noAutoRender', () => {
|
test('passes in noAutoRender', () => {
|
||||||
@@ -963,9 +977,8 @@ suite('gr-diff-host tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('passes in changeNum', () => {
|
test('passes in changeNum', () => {
|
||||||
const value = '12345';
|
element.changeNum = 12345;
|
||||||
element.changeNum = value;
|
assert.equal(element.$.diff.changeNum, 12345);
|
||||||
assert.equal(element.$.diff.changeNum, value);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('passes in projectName', () => {
|
test('passes in projectName', () => {
|
||||||
@@ -1016,6 +1029,7 @@ suite('gr-diff-host tests', () => {
|
|||||||
|
|
||||||
setup(() => {
|
setup(() => {
|
||||||
element = basicFixture.instantiate();
|
element = basicFixture.instantiate();
|
||||||
|
element.changeNum = 123;
|
||||||
element.path = 'file.txt';
|
element.path = 'file.txt';
|
||||||
element.patchRange = {basePatchNum: 1};
|
element.patchRange = {basePatchNum: 1};
|
||||||
reportStub = sinon.stub(element.reporting, 'reportInteraction');
|
reportStub = sinon.stub(element.reporting, 'reportInteraction');
|
||||||
@@ -1167,23 +1181,17 @@ suite('gr-diff-host tests', () => {
|
|||||||
|
|
||||||
assert.equal(actualThreads.length, 2);
|
assert.equal(actualThreads.length, 2);
|
||||||
|
|
||||||
assert.equal(
|
|
||||||
actualThreads[0].start_datetime, '2015-12-23 15:00:20.396000000');
|
|
||||||
assert.equal(actualThreads[0].commentSide, 'left');
|
assert.equal(actualThreads[0].commentSide, 'left');
|
||||||
assert.equal(actualThreads[0].comments.length, 2);
|
assert.equal(actualThreads[0].comments.length, 2);
|
||||||
assert.deepEqual(actualThreads[0].comments[0], comments[0]);
|
assert.deepEqual(actualThreads[0].comments[0], comments[0]);
|
||||||
assert.deepEqual(actualThreads[0].comments[1], comments[1]);
|
assert.deepEqual(actualThreads[0].comments[1], comments[1]);
|
||||||
assert.equal(actualThreads[0].patchNum, undefined);
|
assert.equal(actualThreads[0].patchNum, undefined);
|
||||||
assert.equal(actualThreads[0].rootId, 'sallys_confession');
|
|
||||||
assert.equal(actualThreads[0].lineNum, 1);
|
assert.equal(actualThreads[0].lineNum, 1);
|
||||||
|
|
||||||
assert.equal(
|
|
||||||
actualThreads[1].start_datetime, '2015-12-20 15:01:20.396000000');
|
|
||||||
assert.equal(actualThreads[1].commentSide, 'left');
|
assert.equal(actualThreads[1].commentSide, 'left');
|
||||||
assert.equal(actualThreads[1].comments.length, 1);
|
assert.equal(actualThreads[1].comments.length, 1);
|
||||||
assert.deepEqual(actualThreads[1].comments[0], comments[2]);
|
assert.deepEqual(actualThreads[1].comments[0], comments[2]);
|
||||||
assert.equal(actualThreads[1].patchNum, undefined);
|
assert.equal(actualThreads[1].patchNum, undefined);
|
||||||
assert.equal(actualThreads[1].rootId, 'new_draft');
|
|
||||||
assert.equal(actualThreads[1].lineNum, undefined);
|
assert.equal(actualThreads[1].lineNum, undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1205,7 +1213,6 @@ suite('gr-diff-host tests', () => {
|
|||||||
|
|
||||||
const expectedThreads = [
|
const expectedThreads = [
|
||||||
{
|
{
|
||||||
start_datetime: '2015-12-24 15:00:10.396000000',
|
|
||||||
commentSide: 'left',
|
commentSide: 'left',
|
||||||
comments: [{
|
comments: [{
|
||||||
id: 'betsys_confession',
|
id: 'betsys_confession',
|
||||||
@@ -1222,7 +1229,6 @@ suite('gr-diff-host tests', () => {
|
|||||||
line: 1,
|
line: 1,
|
||||||
}],
|
}],
|
||||||
patchNum: 5,
|
patchNum: 5,
|
||||||
rootId: 'betsys_confession',
|
|
||||||
range: {
|
range: {
|
||||||
start_line: 1,
|
start_line: 1,
|
||||||
start_character: 1,
|
start_character: 1,
|
||||||
@@ -1264,14 +1270,12 @@ suite('gr-diff-host tests', () => {
|
|||||||
id: 'sallys_confession',
|
id: 'sallys_confession',
|
||||||
message: 'i like you, jack',
|
message: 'i like you, jack',
|
||||||
updated: '2015-12-23 15:00:20.396000000',
|
updated: '2015-12-23 15:00:20.396000000',
|
||||||
// line: 1,
|
__commentSide: 'left',
|
||||||
// __commentSide: 'left',
|
|
||||||
}, {
|
}, {
|
||||||
id: 'jacks_reply',
|
id: 'jacks_reply',
|
||||||
message: 'i like you, too',
|
message: 'i like you, too',
|
||||||
updated: '2015-12-24 15:01:20.396000000',
|
updated: '2015-12-24 15:01:20.396000000',
|
||||||
// __commentSide: 'left',
|
__commentSide: 'left',
|
||||||
// line: 1,
|
|
||||||
in_reply_to: 'sallys_confession',
|
in_reply_to: 'sallys_confession',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -1375,9 +1379,9 @@ suite('gr-diff-host tests', () => {
|
|||||||
const threads = [];
|
const threads = [];
|
||||||
assert.deepEqual(element._filterThreadElsForLocation(threads, line), []);
|
assert.deepEqual(element._filterThreadElsForLocation(threads, line), []);
|
||||||
assert.deepEqual(element._filterThreadElsForLocation(threads, line,
|
assert.deepEqual(element._filterThreadElsForLocation(threads, line,
|
||||||
DiffSide.LEFT), []);
|
Side.LEFT), []);
|
||||||
assert.deepEqual(element._filterThreadElsForLocation(threads, line,
|
assert.deepEqual(element._filterThreadElsForLocation(threads, line,
|
||||||
DiffSide.RIGHT), []);
|
Side.RIGHT), []);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('_filterThreadElsForLocation for line comments', () => {
|
test('_filterThreadElsForLocation for line comments', () => {
|
||||||
@@ -1403,9 +1407,9 @@ suite('gr-diff-host tests', () => {
|
|||||||
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line),
|
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line),
|
||||||
[l3, r5]);
|
[l3, r5]);
|
||||||
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
|
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
|
||||||
DiffSide.LEFT), [l3]);
|
Side.LEFT), [l3]);
|
||||||
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
|
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
|
||||||
DiffSide.RIGHT), [r5]);
|
Side.RIGHT), [r5]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('_filterThreadElsForLocation for file comments', () => {
|
test('_filterThreadElsForLocation for file comments', () => {
|
||||||
@@ -1423,11 +1427,11 @@ suite('gr-diff-host tests', () => {
|
|||||||
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line),
|
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line),
|
||||||
[l, r]);
|
[l, r]);
|
||||||
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
|
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
|
||||||
DiffSide.BOTH), [l, r]);
|
Side.BOTH), [l, r]);
|
||||||
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
|
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
|
||||||
DiffSide.LEFT), [l]);
|
Side.LEFT), [l]);
|
||||||
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
|
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
|
||||||
DiffSide.RIGHT), [r]);
|
Side.RIGHT), [r]);
|
||||||
});
|
});
|
||||||
|
|
||||||
suite('syntax layer with syntax_highlighting on', () => {
|
suite('syntax layer with syntax_highlighting on', () => {
|
||||||
@@ -1441,6 +1445,8 @@ suite('gr-diff-host tests', () => {
|
|||||||
};
|
};
|
||||||
element.patchRange = {};
|
element.patchRange = {};
|
||||||
element.prefs = prefs;
|
element.prefs = prefs;
|
||||||
|
element.changeNum = 123;
|
||||||
|
element.path = 'some/path';
|
||||||
});
|
});
|
||||||
|
|
||||||
test('gr-diff-host provides syntax highlighting layer to gr-diff', () => {
|
test('gr-diff-host provides syntax highlighting layer to gr-diff', () => {
|
||||||
@@ -1551,6 +1557,8 @@ suite('gr-diff-host tests', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
element = basicFixture.instantiate();
|
element = basicFixture.instantiate();
|
||||||
|
element.changeNum = 123;
|
||||||
|
element.path = 'some/path';
|
||||||
const prefs = {
|
const prefs = {
|
||||||
line_length: 10,
|
line_length: 10,
|
||||||
show_tabs: true,
|
show_tabs: true,
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
import {CancelablePromise, util} from '../../../scripts/util';
|
import {CancelablePromise, util} from '../../../scripts/util';
|
||||||
import {customElement, property} from '@polymer/decorators';
|
import {customElement, property} from '@polymer/decorators';
|
||||||
import {DiffContent} from '../../../types/common';
|
import {DiffContent} from '../../../types/common';
|
||||||
import {DiffSide} from '../gr-diff/gr-diff-utils';
|
import {Side} from '../../../constants/constants';
|
||||||
|
|
||||||
const WHOLE_FILE = -1;
|
const WHOLE_FILE = -1;
|
||||||
|
|
||||||
@@ -567,8 +567,8 @@ export class GrDiffProcessor extends GestureEventListeners(
|
|||||||
for (let i = 0; i < numLines; i++) {
|
for (let i = 0; i < numLines; i++) {
|
||||||
// If this line should not be collapsed.
|
// If this line should not be collapsed.
|
||||||
if (
|
if (
|
||||||
this.keyLocations[DiffSide.LEFT][leftOffset + i] ||
|
this.keyLocations[Side.LEFT][leftOffset + i] ||
|
||||||
this.keyLocations[DiffSide.RIGHT][rightOffset + i]
|
this.keyLocations[Side.RIGHT][rightOffset + i]
|
||||||
) {
|
) {
|
||||||
// If any lines have been accumulated into the chunk leading up to
|
// If any lines have been accumulated into the chunk leading up to
|
||||||
// this non-collapse line, then add them as a chunk and start a new
|
// this non-collapse line, then add them as a chunk and start a new
|
||||||
|
|||||||
@@ -18,17 +18,12 @@
|
|||||||
import {CommentRange} from '../../../types/common';
|
import {CommentRange} from '../../../types/common';
|
||||||
import {FILE, LineNumber} from './gr-diff-line';
|
import {FILE, LineNumber} from './gr-diff-line';
|
||||||
|
|
||||||
export enum DiffSide {
|
|
||||||
LEFT = 'left',
|
|
||||||
RIGHT = 'right',
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare two ranges. Either argument may be falsy, but will only return
|
* Compare two ranges. Either argument may be falsy, but will only return
|
||||||
* true if both are falsy or if neither are falsy and have the same position
|
* true if both are falsy or if neither are falsy and have the same position
|
||||||
* values.
|
* values.
|
||||||
*/
|
*/
|
||||||
export function rangesEqual(a: CommentRange, b: CommentRange): boolean {
|
export function rangesEqual(a?: CommentRange, b?: CommentRange): boolean {
|
||||||
if (!a && !b) {
|
if (!a && !b) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-l
|
|||||||
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
|
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
|
||||||
import {htmlTemplate} from './gr-diff_html';
|
import {htmlTemplate} from './gr-diff_html';
|
||||||
import {FILE, LineNumber} from './gr-diff-line';
|
import {FILE, LineNumber} from './gr-diff-line';
|
||||||
import {DiffSide, getLineNumber, rangesEqual} from './gr-diff-utils';
|
import {getLineNumber, rangesEqual} from './gr-diff-utils';
|
||||||
import {getHiddenScroll} from '../../../scripts/hiddenscroll';
|
import {getHiddenScroll} from '../../../scripts/hiddenscroll';
|
||||||
import {isMergeParent, patchNumEquals} from '../../../utils/patch-set-util';
|
import {isMergeParent, patchNumEquals} from '../../../utils/patch-set-util';
|
||||||
import {customElement, observe, property} from '@polymer/decorators';
|
import {customElement, observe, property} from '@polymer/decorators';
|
||||||
@@ -95,7 +95,7 @@ const COMMIT_MSG_LINE_LENGTH = 72;
|
|||||||
|
|
||||||
const RENDER_DIFF_TABLE_DEBOUNCE_NAME = 'renderDiffTable';
|
const RENDER_DIFF_TABLE_DEBOUNCE_NAME = 'renderDiffTable';
|
||||||
|
|
||||||
interface LineOfInterest {
|
export interface LineOfInterest {
|
||||||
number: number;
|
number: number;
|
||||||
leftSide: boolean;
|
leftSide: boolean;
|
||||||
}
|
}
|
||||||
@@ -534,7 +534,7 @@ export class GrDiff extends GestureEventListeners(
|
|||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('line-selected', {
|
new CustomEvent('line-selected', {
|
||||||
detail: {
|
detail: {
|
||||||
side: el.classList.contains('left') ? DiffSide.LEFT : DiffSide.RIGHT,
|
side: el.classList.contains('left') ? Side.LEFT : Side.RIGHT,
|
||||||
number: el.getAttribute('data-value'),
|
number: el.getAttribute('data-value'),
|
||||||
path: this.path,
|
path: this.path,
|
||||||
},
|
},
|
||||||
@@ -614,7 +614,7 @@ export class GrDiff extends GestureEventListeners(
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const patchNum = el.classList.contains(DiffSide.LEFT)
|
const patchNum = el.classList.contains(Side.LEFT)
|
||||||
? this.patchRange.basePatchNum
|
? this.patchRange.basePatchNum
|
||||||
: this.patchRange.patchNum;
|
: this.patchRange.patchNum;
|
||||||
|
|
||||||
@@ -717,7 +717,7 @@ export class GrDiff extends GestureEventListeners(
|
|||||||
let patchNum = this.patchRange.patchNum;
|
let patchNum = this.patchRange.patchNum;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(lineEl.classList.contains(DiffSide.LEFT) ||
|
(lineEl.classList.contains(Side.LEFT) ||
|
||||||
contentEl.classList.contains('remove')) &&
|
contentEl.classList.contains('remove')) &&
|
||||||
this.patchRange.basePatchNum !== 'PARENT' &&
|
this.patchRange.basePatchNum !== 'PARENT' &&
|
||||||
!isMergeParent(this.patchRange.basePatchNum)
|
!isMergeParent(this.patchRange.basePatchNum)
|
||||||
@@ -730,7 +730,7 @@ export class GrDiff extends GestureEventListeners(
|
|||||||
_getIsParentCommentByLineAndContent(lineEl: Element, contentEl: Element) {
|
_getIsParentCommentByLineAndContent(lineEl: Element, contentEl: Element) {
|
||||||
if (!this.patchRange) throw Error('patch range not set');
|
if (!this.patchRange) throw Error('patch range not set');
|
||||||
return (
|
return (
|
||||||
(lineEl.classList.contains(DiffSide.LEFT) ||
|
(lineEl.classList.contains(Side.LEFT) ||
|
||||||
contentEl.classList.contains('remove')) &&
|
contentEl.classList.contains('remove')) &&
|
||||||
(this.patchRange.basePatchNum === 'PARENT' ||
|
(this.patchRange.basePatchNum === 'PARENT' ||
|
||||||
isMergeParent(this.patchRange.basePatchNum))
|
isMergeParent(this.patchRange.basePatchNum))
|
||||||
@@ -740,7 +740,7 @@ export class GrDiff extends GestureEventListeners(
|
|||||||
_getCommentSideByLineAndContent(lineEl: Element, contentEl: Element): Side {
|
_getCommentSideByLineAndContent(lineEl: Element, contentEl: Element): Side {
|
||||||
let side = Side.RIGHT;
|
let side = Side.RIGHT;
|
||||||
if (
|
if (
|
||||||
lineEl.classList.contains(DiffSide.LEFT) ||
|
lineEl.classList.contains(Side.LEFT) ||
|
||||||
contentEl.classList.contains('remove')
|
contentEl.classList.contains('remove')
|
||||||
) {
|
) {
|
||||||
side = Side.LEFT;
|
side = Side.LEFT;
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ import {
|
|||||||
DropDownValueChangeEvent,
|
DropDownValueChangeEvent,
|
||||||
GrDropdownList,
|
GrDropdownList,
|
||||||
} from '../../shared/gr-dropdown-list/gr-dropdown-list';
|
} from '../../shared/gr-dropdown-list/gr-dropdown-list';
|
||||||
import {WebLink} from '../../core/gr-navigation/gr-navigation';
|
import {GeneratedWebLink} from '../../core/gr-navigation/gr-navigation';
|
||||||
|
|
||||||
// Maximum length for patch set descriptions.
|
// Maximum length for patch set descriptions.
|
||||||
const PATCH_DESC_MAX_LENGTH = 500;
|
const PATCH_DESC_MAX_LENGTH = 500;
|
||||||
@@ -63,9 +63,9 @@ export interface PatchRangeChangeDetail {
|
|||||||
|
|
||||||
export type PatchRangeChangeEvent = CustomEvent<PatchRangeChangeDetail>;
|
export type PatchRangeChangeEvent = CustomEvent<PatchRangeChangeDetail>;
|
||||||
|
|
||||||
interface FilesWebLinks {
|
export interface FilesWebLinks {
|
||||||
meta_a: WebLink[];
|
meta_a: GeneratedWebLink[];
|
||||||
meta_b: WebLink[];
|
meta_b: GeneratedWebLink[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GrPatchRangeSelect {
|
export interface GrPatchRangeSelect {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import {RevisionInfo} from '../../shared/revision-info/revision-info.js';
|
|||||||
import {createCommentApiMockWithTemplateElement} from '../../../test/mocks/comment-api';
|
import {createCommentApiMockWithTemplateElement} from '../../../test/mocks/comment-api';
|
||||||
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
|
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
|
||||||
import {SPECIAL_PATCH_SET_NUM} from '../../../utils/patch-set-util.js';
|
import {SPECIAL_PATCH_SET_NUM} from '../../../utils/patch-set-util.js';
|
||||||
|
import {ChangeComments} from '../gr-comment-api/gr-comment-api.js';
|
||||||
|
|
||||||
const commentApiMockElement = createCommentApiMockWithTemplateElement(
|
const commentApiMockElement = createCommentApiMockWithTemplateElement(
|
||||||
'gr-patch-range-select-comment-api-mock', html`
|
'gr-patch-range-select-comment-api-mock', html`
|
||||||
@@ -355,7 +356,7 @@ suite('gr-patch-range-select tests', () => {
|
|||||||
|
|
||||||
test('_computePatchSetCommentsString', () => {
|
test('_computePatchSetCommentsString', () => {
|
||||||
// Test string with unresolved comments.
|
// Test string with unresolved comments.
|
||||||
element.changeComments._comments = {
|
const comments = {
|
||||||
foo: [{
|
foo: [{
|
||||||
id: '27dcee4d_f7b77cfa',
|
id: '27dcee4d_f7b77cfa',
|
||||||
message: 'test',
|
message: 'test',
|
||||||
@@ -377,6 +378,7 @@ suite('gr-patch-range-select tests', () => {
|
|||||||
}],
|
}],
|
||||||
abc: [],
|
abc: [],
|
||||||
};
|
};
|
||||||
|
element.changeComments = new ChangeComments(comments, {}, {}, 123);
|
||||||
|
|
||||||
assert.equal(element._computePatchSetCommentsString(
|
assert.equal(element._computePatchSetCommentsString(
|
||||||
element.changeComments, 1), ' (3 comments, 1 unresolved)');
|
element.changeComments, 1), ' (3 comments, 1 unresolved)');
|
||||||
|
|||||||
@@ -27,10 +27,17 @@ import {
|
|||||||
CustomKeyboardEvent,
|
CustomKeyboardEvent,
|
||||||
KeyboardShortcutMixin,
|
KeyboardShortcutMixin,
|
||||||
} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
|
} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
|
||||||
import {sortComments} from '../../diff/gr-comment-api/gr-comment-api';
|
import {
|
||||||
|
isDraft,
|
||||||
|
isRobot,
|
||||||
|
sortComments,
|
||||||
|
UIComment,
|
||||||
|
UIDraft,
|
||||||
|
UIRobot,
|
||||||
|
} from '../../diff/gr-comment-api/gr-comment-api';
|
||||||
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
|
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
|
||||||
import {appContext} from '../../../services/app-context';
|
import {appContext} from '../../../services/app-context';
|
||||||
import {CommentSide, SpecialFilePath} from '../../../constants/constants';
|
import {CommentSide, Side, SpecialFilePath} from '../../../constants/constants';
|
||||||
import {computeDisplayPath} from '../../../utils/path-list-util';
|
import {computeDisplayPath} from '../../../utils/path-list-util';
|
||||||
import {customElement, observe, property} from '@polymer/decorators';
|
import {customElement, observe, property} from '@polymer/decorators';
|
||||||
import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
|
import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
|
||||||
@@ -42,7 +49,7 @@ import {
|
|||||||
RepoName,
|
RepoName,
|
||||||
UrlEncodedCommentId,
|
UrlEncodedCommentId,
|
||||||
} from '../../../types/common';
|
} from '../../../types/common';
|
||||||
import {Comment, GrComment, RobotComment} from '../gr-comment/gr-comment';
|
import {GrComment} from '../gr-comment/gr-comment';
|
||||||
import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
|
import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
|
||||||
import {GrStorage, StorageLocation} from '../gr-storage/gr-storage';
|
import {GrStorage, StorageLocation} from '../gr-storage/gr-storage';
|
||||||
|
|
||||||
@@ -102,7 +109,7 @@ export class GrCommentThread extends KeyboardShortcutMixin(
|
|||||||
changeNum?: NumericChangeId;
|
changeNum?: NumericChangeId;
|
||||||
|
|
||||||
@property({type: Array})
|
@property({type: Array})
|
||||||
comments: Comment[] = [];
|
comments: UIComment[] = [];
|
||||||
|
|
||||||
@property({type: Object, reflectToAttribute: true})
|
@property({type: Object, reflectToAttribute: true})
|
||||||
range?: CommentRange;
|
range?: CommentRange;
|
||||||
@@ -111,7 +118,7 @@ export class GrCommentThread extends KeyboardShortcutMixin(
|
|||||||
keyEventTarget: HTMLElement = document.body;
|
keyEventTarget: HTMLElement = document.body;
|
||||||
|
|
||||||
@property({type: String, reflectToAttribute: true})
|
@property({type: String, reflectToAttribute: true})
|
||||||
commentSide?: string;
|
commentSide?: Side;
|
||||||
|
|
||||||
@property({type: String})
|
@property({type: String})
|
||||||
patchNum?: PatchSetNum;
|
patchNum?: PatchSetNum;
|
||||||
@@ -151,10 +158,10 @@ export class GrCommentThread extends KeyboardShortcutMixin(
|
|||||||
_showActions?: boolean;
|
_showActions?: boolean;
|
||||||
|
|
||||||
@property({type: Object})
|
@property({type: Object})
|
||||||
_lastComment?: Comment;
|
_lastComment?: UIComment;
|
||||||
|
|
||||||
@property({type: Array})
|
@property({type: Array})
|
||||||
_orderedComments: Comment[] = [];
|
_orderedComments: UIComment[] = [];
|
||||||
|
|
||||||
@property({type: Object})
|
@property({type: Object})
|
||||||
_projectConfig?: ConfigInfo;
|
_projectConfig?: ConfigInfo;
|
||||||
@@ -197,7 +204,7 @@ export class GrCommentThread extends KeyboardShortcutMixin(
|
|||||||
|
|
||||||
addOrEditDraft(lineNum?: number, rangeParam?: CommentRange) {
|
addOrEditDraft(lineNum?: number, rangeParam?: CommentRange) {
|
||||||
const lastComment = this.comments[this.comments.length - 1] || {};
|
const lastComment = this.comments[this.comments.length - 1] || {};
|
||||||
if (lastComment.__draft) {
|
if (isDraft(lastComment)) {
|
||||||
const commentEl = this._commentElWithDraftID(
|
const commentEl = this._commentElWithDraftID(
|
||||||
lastComment.id || lastComment.__draftID
|
lastComment.id || lastComment.__draftID
|
||||||
);
|
);
|
||||||
@@ -237,7 +244,7 @@ export class GrCommentThread extends KeyboardShortcutMixin(
|
|||||||
_getDiffUrlForPath(path: string) {
|
_getDiffUrlForPath(path: string) {
|
||||||
if (!this.changeNum) throw new Error('changeNum is missing');
|
if (!this.changeNum) throw new Error('changeNum is missing');
|
||||||
if (!this.projectName) throw new Error('projectName is missing');
|
if (!this.projectName) throw new Error('projectName is missing');
|
||||||
if (this.comments[0].__draft) {
|
if (isDraft(this.comments[0])) {
|
||||||
return GerritNav.getUrlForDiffById(
|
return GerritNav.getUrlForDiffById(
|
||||||
this.changeNum,
|
this.changeNum,
|
||||||
this.projectName,
|
this.projectName,
|
||||||
@@ -251,14 +258,15 @@ export class GrCommentThread extends KeyboardShortcutMixin(
|
|||||||
}
|
}
|
||||||
|
|
||||||
_getDiffUrlForComment(
|
_getDiffUrlForComment(
|
||||||
projectName: RepoName,
|
projectName?: RepoName,
|
||||||
changeNum: NumericChangeId,
|
changeNum?: NumericChangeId,
|
||||||
path: string,
|
path?: string,
|
||||||
patchNum: PatchSetNum
|
patchNum?: PatchSetNum
|
||||||
) {
|
) {
|
||||||
|
if (!projectName || !changeNum || !path) return undefined;
|
||||||
if (
|
if (
|
||||||
(this.comments.length && this.comments[0].side === 'PARENT') ||
|
(this.comments.length && this.comments[0].side === 'PARENT') ||
|
||||||
this.comments[0].__draft
|
isDraft(this.comments[0])
|
||||||
) {
|
) {
|
||||||
return GerritNav.getUrlForDiffById(
|
return GerritNav.getUrlForDiffById(
|
||||||
changeNum,
|
changeNum,
|
||||||
@@ -271,9 +279,7 @@ export class GrCommentThread extends KeyboardShortcutMixin(
|
|||||||
}
|
}
|
||||||
const id = this.comments[0].id;
|
const id = this.comments[0].id;
|
||||||
if (!id) throw new Error('A published comment is missing the id.');
|
if (!id) throw new Error('A published comment is missing the id.');
|
||||||
if (!this.changeNum) throw new Error('changeNum is missing');
|
return GerritNav.getUrlForComment(changeNum, projectName, id);
|
||||||
if (!this.projectName) throw new Error('projectName is missing');
|
|
||||||
return GerritNav.getUrlForComment(this.changeNum, this.projectName, id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_isPatchsetLevelComment(path: string) {
|
_isPatchsetLevelComment(path: string) {
|
||||||
@@ -315,19 +321,19 @@ export class GrCommentThread extends KeyboardShortcutMixin(
|
|||||||
if (this._orderedComments.length) {
|
if (this._orderedComments.length) {
|
||||||
this._lastComment = this._getLastComment();
|
this._lastComment = this._getLastComment();
|
||||||
this.unresolved = this._lastComment.unresolved;
|
this.unresolved = this._lastComment.unresolved;
|
||||||
this.hasDraft = this._lastComment.__draft;
|
this.hasDraft = isDraft(this._lastComment);
|
||||||
this.isRobotComment = !!(this._lastComment as RobotComment).robot_id;
|
this.isRobotComment = isRobot(this._lastComment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_shouldDisableAction(_showActions?: boolean, _lastComment?: Comment) {
|
_shouldDisableAction(_showActions?: boolean, _lastComment?: UIComment) {
|
||||||
return !_showActions || !_lastComment || !!_lastComment.__draft;
|
return !_showActions || !_lastComment || isDraft(_lastComment);
|
||||||
}
|
}
|
||||||
|
|
||||||
_hideActions(_showActions?: boolean, _lastComment?: Comment) {
|
_hideActions(_showActions?: boolean, _lastComment?: UIComment) {
|
||||||
return (
|
return (
|
||||||
this._shouldDisableAction(_showActions, _lastComment) ||
|
this._shouldDisableAction(_showActions, _lastComment) ||
|
||||||
!!(_lastComment as RobotComment).robot_id
|
isRobot(_lastComment)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,7 +377,7 @@ export class GrCommentThread extends KeyboardShortcutMixin(
|
|||||||
if (this._orderedComments) {
|
if (this._orderedComments) {
|
||||||
for (let i = 0; i < this._orderedComments.length; i++) {
|
for (let i = 0; i < this._orderedComments.length; i++) {
|
||||||
const comment = this._orderedComments[i];
|
const comment = this._orderedComments[i];
|
||||||
const isRobotComment = !!(comment as RobotComment).robot_id;
|
const isRobotComment = !!(comment as UIRobot).robot_id;
|
||||||
// False if it's an unresolved comment under UNRESOLVED_EXPAND_COUNT.
|
// False if it's an unresolved comment under UNRESOLVED_EXPAND_COUNT.
|
||||||
const resolvedThread =
|
const resolvedThread =
|
||||||
!this.unresolved ||
|
!this.unresolved ||
|
||||||
@@ -417,8 +423,8 @@ export class GrCommentThread extends KeyboardShortcutMixin(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_isDraft(comment: Comment) {
|
_isDraft(comment: UIComment) {
|
||||||
return !!comment.__draft;
|
return isDraft(comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
_processCommentReply(quote?: boolean) {
|
_processCommentReply(quote?: boolean) {
|
||||||
@@ -463,9 +469,9 @@ export class GrCommentThread extends KeyboardShortcutMixin(
|
|||||||
const els = this.root?.querySelectorAll('gr-comment');
|
const els = this.root?.querySelectorAll('gr-comment');
|
||||||
if (!els) return null;
|
if (!els) return null;
|
||||||
for (const el of els) {
|
for (const el of els) {
|
||||||
if (el.comment?.id === id || el.comment?.__draftID === id) {
|
const c = el.comment;
|
||||||
return el;
|
if (isRobot(c)) continue;
|
||||||
}
|
if (c?.id === id || (isDraft(c) && c?.__draftID === id)) return el;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -487,7 +493,7 @@ export class GrCommentThread extends KeyboardShortcutMixin(
|
|||||||
}
|
}
|
||||||
|
|
||||||
_newDraft(lineNum?: number, range?: CommentRange) {
|
_newDraft(lineNum?: number, range?: CommentRange) {
|
||||||
const d: Comment = {
|
const d: UIDraft = {
|
||||||
__draft: true,
|
__draft: true,
|
||||||
__draftID: Math.random().toString(36),
|
__draftID: Math.random().toString(36),
|
||||||
__date: new Date(),
|
__date: new Date(),
|
||||||
@@ -529,14 +535,16 @@ export class GrCommentThread extends KeyboardShortcutMixin(
|
|||||||
return isOnParent ? CommentSide.PARENT : CommentSide.REVISION;
|
return isOnParent ? CommentSide.PARENT : CommentSide.REVISION;
|
||||||
}
|
}
|
||||||
|
|
||||||
_computeRootId(comments: PolymerDeepPropertyChange<Comment[], unknown>) {
|
_computeRootId(comments: PolymerDeepPropertyChange<UIComment[], unknown>) {
|
||||||
// Keep the root ID even if the comment was removed, so that notification
|
// Keep the root ID even if the comment was removed, so that notification
|
||||||
// to sync will know which thread to remove.
|
// to sync will know which thread to remove.
|
||||||
if (!comments.base.length) {
|
if (!comments.base.length) {
|
||||||
return this.rootId;
|
return this.rootId;
|
||||||
}
|
}
|
||||||
const rootComment = comments.base[0];
|
const rootComment = comments.base[0];
|
||||||
return rootComment.id || rootComment.__draftID;
|
if (rootComment.id) return rootComment.id;
|
||||||
|
if (isDraft(rootComment)) return rootComment.__draftID;
|
||||||
|
throw new Error('Missing id in root comment.');
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleCommentDiscard(e: Event) {
|
_handleCommentDiscard(e: Event) {
|
||||||
@@ -599,12 +607,12 @@ export class GrCommentThread extends KeyboardShortcutMixin(
|
|||||||
this.updateThreadProperties();
|
this.updateThreadProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
_indexOf(comment: Comment | undefined, arr: Comment[]) {
|
_indexOf(comment: UIComment | undefined, arr: UIComment[]) {
|
||||||
if (!comment) return -1;
|
if (!comment) return -1;
|
||||||
for (let i = 0; i < arr.length; i++) {
|
for (let i = 0; i < arr.length; i++) {
|
||||||
const c = arr[i];
|
const c = arr[i];
|
||||||
if (
|
if (
|
||||||
(c.__draftID && c.__draftID === comment.__draftID) ||
|
(isDraft(c) && isDraft(comment) && c.__draftID === comment.__draftID) ||
|
||||||
(c.id && c.id === comment.id)
|
(c.id && c.id === comment.id)
|
||||||
) {
|
) {
|
||||||
return i;
|
return i;
|
||||||
|
|||||||
@@ -38,22 +38,27 @@ import {htmlTemplate} from './gr-comment_html';
|
|||||||
import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
|
import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
|
||||||
import {getRootElement} from '../../../scripts/rootElement';
|
import {getRootElement} from '../../../scripts/rootElement';
|
||||||
import {appContext} from '../../../services/app-context';
|
import {appContext} from '../../../services/app-context';
|
||||||
import {customElement, property, observe} from '@polymer/decorators';
|
import {customElement, observe, property} from '@polymer/decorators';
|
||||||
import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
|
import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
|
||||||
import {GrTextarea} from '../gr-textarea/gr-textarea';
|
import {GrTextarea} from '../gr-textarea/gr-textarea';
|
||||||
import {GrStorage, StorageLocation} from '../gr-storage/gr-storage';
|
import {GrStorage, StorageLocation} from '../gr-storage/gr-storage';
|
||||||
import {GrOverlay} from '../gr-overlay/gr-overlay';
|
import {GrOverlay} from '../gr-overlay/gr-overlay';
|
||||||
import {
|
import {
|
||||||
RobotCommentInfo,
|
|
||||||
PatchSetNum,
|
|
||||||
CommentInfo,
|
|
||||||
ConfigInfo,
|
|
||||||
AccountDetailInfo,
|
AccountDetailInfo,
|
||||||
NumericChangeId,
|
NumericChangeId,
|
||||||
|
ConfigInfo,
|
||||||
|
PatchSetNum,
|
||||||
} from '../../../types/common';
|
} from '../../../types/common';
|
||||||
import {GrButton} from '../gr-button/gr-button';
|
import {GrButton} from '../gr-button/gr-button';
|
||||||
import {GrConfirmDeleteCommentDialog} from '../gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog';
|
import {GrConfirmDeleteCommentDialog} from '../gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog';
|
||||||
import {GrDialog} from '../gr-dialog/gr-dialog';
|
import {GrDialog} from '../gr-dialog/gr-dialog';
|
||||||
|
import {Side} from '../../../constants/constants';
|
||||||
|
import {
|
||||||
|
isDraft,
|
||||||
|
UIComment,
|
||||||
|
UIDraft,
|
||||||
|
UIRobot,
|
||||||
|
} from '../../diff/gr-comment-api/gr-comment-api';
|
||||||
|
|
||||||
const STORAGE_DEBOUNCE_INTERVAL = 400;
|
const STORAGE_DEBOUNCE_INTERVAL = 400;
|
||||||
const TOAST_DEBOUNCE_INTERVAL = 200;
|
const TOAST_DEBOUNCE_INTERVAL = 200;
|
||||||
@@ -84,23 +89,6 @@ const RESPECTFUL_REVIEW_TIPS = [
|
|||||||
'When disagreeing, explain the advantage of your approach.',
|
'When disagreeing, explain the advantage of your approach.',
|
||||||
];
|
];
|
||||||
|
|
||||||
export interface Draft {
|
|
||||||
collapsed?: boolean;
|
|
||||||
__editing?: boolean;
|
|
||||||
__otherEditing?: boolean;
|
|
||||||
__draft?: boolean;
|
|
||||||
__draftID?: string;
|
|
||||||
__commentSide?: string;
|
|
||||||
__date?: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Comment = Draft & CommentInfo;
|
|
||||||
export type RobotComment = Draft & RobotCommentInfo;
|
|
||||||
|
|
||||||
export function isRobotComment(c: Comment | RobotComment): c is RobotComment {
|
|
||||||
return (c as RobotComment).robot_id !== undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CommentOverlays {
|
interface CommentOverlays {
|
||||||
confirmDelete?: GrOverlay | null;
|
confirmDelete?: GrOverlay | null;
|
||||||
confirmDiscard?: GrOverlay | null;
|
confirmDiscard?: GrOverlay | null;
|
||||||
@@ -117,7 +105,7 @@ export interface GrComment {
|
|||||||
|
|
||||||
export interface CommentEventDetail {
|
export interface CommentEventDetail {
|
||||||
patchNum?: PatchSetNum;
|
patchNum?: PatchSetNum;
|
||||||
comment?: Comment | RobotComment;
|
comment?: UIComment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@customElement('gr-comment')
|
@customElement('gr-comment')
|
||||||
@@ -174,10 +162,10 @@ export class GrComment extends KeyboardShortcutMixin(
|
|||||||
changeNum?: NumericChangeId;
|
changeNum?: NumericChangeId;
|
||||||
|
|
||||||
@property({type: Object, notify: true, observer: '_commentChanged'})
|
@property({type: Object, notify: true, observer: '_commentChanged'})
|
||||||
comment?: Comment | RobotComment;
|
comment?: UIComment | UIRobot;
|
||||||
|
|
||||||
@property({type: Array})
|
@property({type: Array})
|
||||||
comments?: (Comment | RobotComment)[];
|
comments?: (UIComment | UIRobot)[];
|
||||||
|
|
||||||
@property({type: Boolean, reflectToAttribute: true})
|
@property({type: Boolean, reflectToAttribute: true})
|
||||||
isRobotComment = false;
|
isRobotComment = false;
|
||||||
@@ -235,7 +223,7 @@ export class GrComment extends KeyboardShortcutMixin(
|
|||||||
_messageText = '';
|
_messageText = '';
|
||||||
|
|
||||||
@property({type: String})
|
@property({type: String})
|
||||||
commentSide?: string;
|
commentSide?: Side;
|
||||||
|
|
||||||
@property({type: String})
|
@property({type: String})
|
||||||
side?: string;
|
side?: string;
|
||||||
@@ -311,7 +299,7 @@ export class GrComment extends KeyboardShortcutMixin(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_getAuthor(comment: Comment) {
|
_getAuthor(comment: UIComment) {
|
||||||
return comment.author || this._selfAccount;
|
return comment.author || this._selfAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,7 +398,7 @@ export class GrComment extends KeyboardShortcutMixin(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@observe('comment')
|
@observe('comment')
|
||||||
_isRobotComment(comment: RobotComment) {
|
_isRobotComment(comment: UIRobot) {
|
||||||
this.isRobotComment = !!comment.robot_id;
|
this.isRobotComment = !!comment.robot_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,7 +421,7 @@ export class GrComment extends KeyboardShortcutMixin(
|
|||||||
return 'DRAFT' + (unableToSave ? '(Failed to save)' : '');
|
return 'DRAFT' + (unableToSave ? '(Failed to save)' : '');
|
||||||
}
|
}
|
||||||
|
|
||||||
save(opt_comment?: Comment) {
|
save(opt_comment?: UIComment) {
|
||||||
let comment = opt_comment;
|
let comment = opt_comment;
|
||||||
if (!comment) {
|
if (!comment) {
|
||||||
comment = this.comment;
|
comment = this.comment;
|
||||||
@@ -456,7 +444,8 @@ export class GrComment extends KeyboardShortcutMixin(
|
|||||||
|
|
||||||
this._eraseDraftComment();
|
this._eraseDraftComment();
|
||||||
return this.$.restAPI.getResponseObject(response).then(obj => {
|
return this.$.restAPI.getResponseObject(response).then(obj => {
|
||||||
const resComment = (obj as unknown) as Comment;
|
const resComment = (obj as unknown) as UIDraft;
|
||||||
|
if (!isDraft(this.comment)) throw new Error('Can only save drafts.');
|
||||||
resComment.__draft = true;
|
resComment.__draft = true;
|
||||||
// Maintain the ephemeral draft ID for identification by other
|
// Maintain the ephemeral draft ID for identification by other
|
||||||
// elements.
|
// elements.
|
||||||
@@ -495,7 +484,7 @@ export class GrComment extends KeyboardShortcutMixin(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_commentChanged(comment: Comment) {
|
_commentChanged(comment: UIComment) {
|
||||||
this.editing = !!comment.__editing;
|
this.editing = !!comment.__editing;
|
||||||
this.resolved = !comment.unresolved;
|
this.resolved = !comment.unresolved;
|
||||||
if (this.editing) {
|
if (this.editing) {
|
||||||
@@ -513,7 +502,7 @@ export class GrComment extends KeyboardShortcutMixin(
|
|||||||
c =>
|
c =>
|
||||||
c.in_reply_to &&
|
c.in_reply_to &&
|
||||||
c.in_reply_to === comment.id &&
|
c.in_reply_to === comment.id &&
|
||||||
!(c as RobotComment).robot_id
|
!(c as UIRobot).robot_id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -587,7 +576,7 @@ export class GrComment extends KeyboardShortcutMixin(
|
|||||||
|
|
||||||
_computeSaveDisabled(
|
_computeSaveDisabled(
|
||||||
draft: string,
|
draft: string,
|
||||||
comment: Comment | undefined,
|
comment: UIComment | undefined,
|
||||||
resolved?: boolean
|
resolved?: boolean
|
||||||
) {
|
) {
|
||||||
// If resolved state has changed and a msg exists, save should be enabled.
|
// If resolved state has changed and a msg exists, save should be enabled.
|
||||||
@@ -753,8 +742,8 @@ export class GrComment extends KeyboardShortcutMixin(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_hasNoFix(comment: Comment) {
|
_hasNoFix(comment: UIComment) {
|
||||||
return !comment || !(comment as RobotComment).fix_suggestions;
|
return !comment || !(comment as UIRobot).fix_suggestions;
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleDiscard(e: Event) {
|
_handleDiscard(e: Event) {
|
||||||
@@ -785,7 +774,7 @@ export class GrComment extends KeyboardShortcutMixin(
|
|||||||
|
|
||||||
_discardDraft() {
|
_discardDraft() {
|
||||||
if (!this.comment) return Promise.reject(new Error('undefined comment'));
|
if (!this.comment) return Promise.reject(new Error('undefined comment'));
|
||||||
if (!this.comment.__draft) {
|
if (!isDraft(this.comment)) {
|
||||||
return Promise.reject(new Error('Cannot discard a non-draft comment.'));
|
return Promise.reject(new Error('Cannot discard a non-draft comment.'));
|
||||||
}
|
}
|
||||||
this.discarding = true;
|
this.discarding = true;
|
||||||
@@ -883,7 +872,7 @@ export class GrComment extends KeyboardShortcutMixin(
|
|||||||
this._handleFailedDraftRequest();
|
this._handleFailedDraftRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
_saveDraft(draft?: Comment) {
|
_saveDraft(draft?: UIComment) {
|
||||||
if (!draft || this.changeNum === undefined || this.patchNum === undefined) {
|
if (!draft || this.changeNum === undefined || this.patchNum === undefined) {
|
||||||
throw new Error('undefined draft or changeNum or patchNum');
|
throw new Error('undefined draft or changeNum or patchNum');
|
||||||
}
|
}
|
||||||
@@ -907,7 +896,7 @@ export class GrComment extends KeyboardShortcutMixin(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_deleteDraft(draft: Comment) {
|
_deleteDraft(draft: UIComment) {
|
||||||
if (this.changeNum === undefined || this.patchNum === undefined) {
|
if (this.changeNum === undefined || this.patchNum === undefined) {
|
||||||
throw new Error('undefined changeNum or patchNum');
|
throw new Error('undefined changeNum or patchNum');
|
||||||
}
|
}
|
||||||
@@ -937,7 +926,7 @@ export class GrComment extends KeyboardShortcutMixin(
|
|||||||
_loadLocalDraft(
|
_loadLocalDraft(
|
||||||
changeNum: number,
|
changeNum: number,
|
||||||
patchNum?: PatchSetNum,
|
patchNum?: PatchSetNum,
|
||||||
comment?: Comment
|
comment?: UIComment
|
||||||
) {
|
) {
|
||||||
// Polymer 2: check for undefined
|
// Polymer 2: check for undefined
|
||||||
if ([changeNum, patchNum, comment].includes(undefined)) {
|
if ([changeNum, patchNum, comment].includes(undefined)) {
|
||||||
@@ -1012,7 +1001,7 @@ export class GrComment extends KeyboardShortcutMixin(
|
|||||||
return overlay.open();
|
return overlay.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
_computeHideRunDetails(comment: RobotComment, collapsed: boolean) {
|
_computeHideRunDetails(comment: UIRobot, collapsed: boolean) {
|
||||||
if (!comment) return true;
|
if (!comment) return true;
|
||||||
return !(comment.robot_id && comment.url && !collapsed);
|
return !(comment.robot_id && comment.url && !collapsed);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,19 +15,18 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import {GrAnnotationActionsContext} from './gr-annotation-actions-context';
|
import {GrAnnotationActionsContext} from './gr-annotation-actions-context';
|
||||||
import {GrDiffLine, LineNumber} from '../../diff/gr-diff/gr-diff-line';
|
import {GrDiffLine} from '../../diff/gr-diff/gr-diff-line';
|
||||||
import {CoverageRange} from '../../../types/types';
|
import {
|
||||||
|
CoverageRange,
|
||||||
|
DiffLayer,
|
||||||
|
DiffLayerListener,
|
||||||
|
} from '../../../types/types';
|
||||||
import {Side} from '../../../constants/constants';
|
import {Side} from '../../../constants/constants';
|
||||||
import {PluginApi} from '../../plugins/gr-plugin-types';
|
import {PluginApi} from '../../plugins/gr-plugin-types';
|
||||||
|
import {NumericChangeId} from '../../../types/common';
|
||||||
|
|
||||||
type AddLayerFunc = (ctx: GrAnnotationActionsContext) => void;
|
type AddLayerFunc = (ctx: GrAnnotationActionsContext) => void;
|
||||||
|
|
||||||
type LayerUpdateListener = (
|
|
||||||
start: LineNumber,
|
|
||||||
end: LineNumber,
|
|
||||||
side: Side
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
type NotifyFunc = (
|
type NotifyFunc = (
|
||||||
path: string,
|
path: string,
|
||||||
start: number,
|
start: number,
|
||||||
@@ -36,10 +35,10 @@ type NotifyFunc = (
|
|||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
export type CoverageProvider = (
|
export type CoverageProvider = (
|
||||||
changeNum: number,
|
changeNum: NumericChangeId,
|
||||||
path: string,
|
path: string,
|
||||||
basePatchNum: number,
|
basePatchNum?: number,
|
||||||
patchNum: number
|
patchNum?: number
|
||||||
) => Promise<Array<CoverageRange>>;
|
) => Promise<Array<CoverageRange>>;
|
||||||
|
|
||||||
export class GrAnnotationActionsInterface {
|
export class GrAnnotationActionsInterface {
|
||||||
@@ -205,8 +204,8 @@ export class GrAnnotationActionsInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AnnotationLayer {
|
export class AnnotationLayer implements DiffLayer {
|
||||||
private listeners: LayerUpdateListener[] = [];
|
private listeners: DiffLayerListener[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to create an instance of the Annotation Layer interface.
|
* Used to create an instance of the Annotation Layer interface.
|
||||||
@@ -232,12 +231,12 @@ export class AnnotationLayer {
|
|||||||
* Should accept as arguments the line numbers for the start and end of
|
* Should accept as arguments the line numbers for the start and end of
|
||||||
* the update and the side as a string.
|
* the update and the side as a string.
|
||||||
*/
|
*/
|
||||||
addListener(fn: () => void) {
|
addListener(listener: DiffLayerListener) {
|
||||||
this.listeners.push(fn);
|
this.listeners.push(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeListener(fn: () => void) {
|
removeListener(listener: DiffLayerListener) {
|
||||||
this.listeners = this.listeners.filter(f => f !== fn);
|
this.listeners = this.listeners.filter(f => f !== listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -271,7 +270,7 @@ export class AnnotationLayer {
|
|||||||
* @param end The line where the update ends.
|
* @param end The line where the update ends.
|
||||||
* @param side The side of the update. ('left' or 'right')
|
* @param side The side of the update. ('left' or 'right')
|
||||||
*/
|
*/
|
||||||
notifyListeners(start: LineNumber, end: LineNumber, side: Side) {
|
notifyListeners(start: number, end: number, side: Side) {
|
||||||
for (const listener of this.listeners) {
|
for (const listener of this.listeners) {
|
||||||
listener(start, end, side);
|
listener(start, end, side);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,7 @@ import {getPluginLoader} from './gr-plugin-loader';
|
|||||||
import {patchNumEquals} from '../../../utils/patch-set-util';
|
import {patchNumEquals} from '../../../utils/patch-set-util';
|
||||||
import {customElement} from '@polymer/decorators';
|
import {customElement} from '@polymer/decorators';
|
||||||
import {ChangeInfo, RevisionInfo} from '../../../types/common';
|
import {ChangeInfo, RevisionInfo} from '../../../types/common';
|
||||||
import {
|
import {GrAnnotationActionsInterface} from './gr-annotation-actions-js-api';
|
||||||
CoverageProvider,
|
|
||||||
GrAnnotationActionsInterface,
|
|
||||||
} from './gr-annotation-actions-js-api';
|
|
||||||
import {GrAdminApi} from '../../plugins/gr-admin-api/gr-admin-api';
|
import {GrAdminApi} from '../../plugins/gr-admin-api/gr-admin-api';
|
||||||
import {
|
import {
|
||||||
JsApiService,
|
JsApiService,
|
||||||
@@ -33,7 +30,7 @@ import {
|
|||||||
ShowRevisionActionsDetail,
|
ShowRevisionActionsDetail,
|
||||||
} from './gr-js-api-types';
|
} from './gr-js-api-types';
|
||||||
import {EventType, TargetElement} from '../../plugins/gr-plugin-types';
|
import {EventType, TargetElement} from '../../plugins/gr-plugin-types';
|
||||||
import {HighlightJS} from '../../../types/types';
|
import {DiffLayer, HighlightJS} from '../../../types/types';
|
||||||
|
|
||||||
const elements: {[key: string]: HTMLElement} = {};
|
const elements: {[key: string]: HTMLElement} = {};
|
||||||
const eventCallbacks: {[key: string]: EventCallback[]} = {};
|
const eventCallbacks: {[key: string]: EventCallback[]} = {};
|
||||||
@@ -248,7 +245,7 @@ export class GrJsApiInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
getDiffLayers(path: string, changeNum: number) {
|
getDiffLayers(path: string, changeNum: number) {
|
||||||
const layers = [];
|
const layers: DiffLayer[] = [];
|
||||||
for (const cb of this._getEventCallbacks(EventType.ANNOTATE_DIFF)) {
|
for (const cb of this._getEventCallbacks(EventType.ANNOTATE_DIFF)) {
|
||||||
const annotationApi = (cb as unknown) as GrAnnotationActionsInterface;
|
const annotationApi = (cb as unknown) as GrAnnotationActionsInterface;
|
||||||
try {
|
try {
|
||||||
@@ -279,7 +276,9 @@ export class GrJsApiInterface
|
|||||||
* provider, the first one is returned. If no plugin offers a coverage provider,
|
* provider, the first one is returned. If no plugin offers a coverage provider,
|
||||||
* will resolve to null.
|
* will resolve to null.
|
||||||
*/
|
*/
|
||||||
getCoverageAnnotationApi(): Promise<CoverageProvider | undefined> {
|
getCoverageAnnotationApi(): Promise<
|
||||||
|
GrAnnotationActionsInterface | undefined
|
||||||
|
> {
|
||||||
return getPluginLoader()
|
return getPluginLoader()
|
||||||
.awaitPluginsLoaded()
|
.awaitPluginsLoaded()
|
||||||
.then(
|
.then(
|
||||||
@@ -287,7 +286,7 @@ export class GrJsApiInterface
|
|||||||
this._getEventCallbacks(EventType.ANNOTATE_DIFF).find(cb => {
|
this._getEventCallbacks(EventType.ANNOTATE_DIFF).find(cb => {
|
||||||
const annotationApi = (cb as unknown) as GrAnnotationActionsInterface;
|
const annotationApi = (cb as unknown) as GrAnnotationActionsInterface;
|
||||||
return annotationApi.getCoverageProvider();
|
return annotationApi.getCoverageProvider();
|
||||||
}) as CoverageProvider | undefined
|
}) as GrAnnotationActionsInterface | undefined
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
*/
|
*/
|
||||||
import {ActionInfo, ChangeInfo, PatchSetNum} from '../../../types/common';
|
import {ActionInfo, ChangeInfo, PatchSetNum} from '../../../types/common';
|
||||||
import {EventType, TargetElement} from '../../plugins/gr-plugin-types';
|
import {EventType, TargetElement} from '../../plugins/gr-plugin-types';
|
||||||
|
import {DiffLayer} from '../../../types/types';
|
||||||
|
import {GrAnnotationActionsInterface} from './gr-annotation-actions-js-api';
|
||||||
|
|
||||||
export interface ShowChangeDetail {
|
export interface ShowChangeDetail {
|
||||||
change: ChangeInfo;
|
change: ChangeInfo;
|
||||||
@@ -45,5 +47,8 @@ export interface JsApiService {
|
|||||||
origMsg: string
|
origMsg: string
|
||||||
): string;
|
): string;
|
||||||
addElement(key: TargetElement, el: HTMLElement): void;
|
addElement(key: TargetElement, el: HTMLElement): void;
|
||||||
|
getDiffLayers(path: string, changeNum: number): DiffLayer[];
|
||||||
|
disposeDiffLayers(path: string): void;
|
||||||
|
getCoverageAnnotationApi(): Promise<GrAnnotationActionsInterface | undefined>;
|
||||||
// TODO(TS): Add more methods when needed for the TS conversion.
|
// TODO(TS): Add more methods when needed for the TS conversion.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ import {
|
|||||||
FixId,
|
FixId,
|
||||||
FilePathToDiffInfoMap,
|
FilePathToDiffInfoMap,
|
||||||
ChangeViewChangeInfo,
|
ChangeViewChangeInfo,
|
||||||
|
BlameInfo,
|
||||||
} from '../../../types/common';
|
} from '../../../types/common';
|
||||||
import {
|
import {
|
||||||
CancelConditionCallback,
|
CancelConditionCallback,
|
||||||
@@ -2524,7 +2525,7 @@ export class GrRestApiInterface
|
|||||||
req.fetchOptions.headers.append('Cache-Control', 'no-cache');
|
req.fetchOptions.headers.append('Cache-Control', 'no-cache');
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._getChangeURLAndFetch(req);
|
return this._getChangeURLAndFetch(req) as Promise<DiffInfo | undefined>;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDiffComments(
|
getDiffComments(
|
||||||
@@ -2639,11 +2640,9 @@ export class GrRestApiInterface
|
|||||||
|
|
||||||
_setRanges(comments?: CommentInfo[]) {
|
_setRanges(comments?: CommentInfo[]) {
|
||||||
comments = comments || [];
|
comments = comments || [];
|
||||||
comments.sort((a, b) => {
|
comments.sort(
|
||||||
if (!a.updated) return 1;
|
(a, b) => parseDate(a.updated).valueOf() - parseDate(b.updated).valueOf()
|
||||||
if (!b.updated) return -1;
|
);
|
||||||
return parseDate(a.updated).valueOf() - parseDate(b.updated).valueOf();
|
|
||||||
});
|
|
||||||
for (const comment of comments) {
|
for (const comment of comments) {
|
||||||
this._setRange(comments, comment);
|
this._setRange(comments, comment);
|
||||||
}
|
}
|
||||||
@@ -3472,7 +3471,7 @@ export class GrRestApiInterface
|
|||||||
patchNum,
|
patchNum,
|
||||||
params: base ? {base: 't'} : undefined,
|
params: base ? {base: 't'} : undefined,
|
||||||
anonymizedEndpoint: '/files/*/blame',
|
anonymizedEndpoint: '/files/*/blame',
|
||||||
});
|
}) as Promise<BlameInfo[] | undefined>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -87,9 +87,13 @@ import {
|
|||||||
EmailAddress,
|
EmailAddress,
|
||||||
FixId,
|
FixId,
|
||||||
FilePathToDiffInfoMap,
|
FilePathToDiffInfoMap,
|
||||||
|
DiffInfo,
|
||||||
|
BlameInfo,
|
||||||
|
PatchRange,
|
||||||
|
ImagesForDiff,
|
||||||
} from '../../../types/common';
|
} from '../../../types/common';
|
||||||
import {ParsedChangeInfo} from '../../../elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser';
|
import {ParsedChangeInfo} from '../../../elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser';
|
||||||
import {HttpMethod} from '../../../constants/constants';
|
import {HttpMethod, IgnoreWhitespaceType} from '../../../constants/constants';
|
||||||
|
|
||||||
export type ErrorCallback = (response?: Response | null, err?: Error) => void;
|
export type ErrorCallback = (response?: Response | null, err?: Error) => void;
|
||||||
export type CancelConditionCallback = () => boolean;
|
export type CancelConditionCallback = () => boolean;
|
||||||
@@ -735,4 +739,26 @@ export interface RestApiService {
|
|||||||
patchNum: PatchSetNum,
|
patchNum: PatchSetNum,
|
||||||
fixId: string
|
fixId: string
|
||||||
): Promise<Response>;
|
): Promise<Response>;
|
||||||
|
|
||||||
|
getDiff(
|
||||||
|
changeNum: NumericChangeId,
|
||||||
|
basePatchNum: PatchSetNum,
|
||||||
|
patchNum: PatchSetNum,
|
||||||
|
path: string,
|
||||||
|
whitespace?: IgnoreWhitespaceType,
|
||||||
|
errFn?: ErrorCallback
|
||||||
|
): Promise<DiffInfo | undefined>;
|
||||||
|
|
||||||
|
getBlame(
|
||||||
|
changeNum: NumericChangeId,
|
||||||
|
patchNum: PatchSetNum,
|
||||||
|
path: string,
|
||||||
|
base?: boolean
|
||||||
|
): Promise<BlameInfo[] | undefined>;
|
||||||
|
|
||||||
|
getImagesForDiff(
|
||||||
|
changeNum: NumericChangeId,
|
||||||
|
diff: DiffInfo,
|
||||||
|
patchRange: PatchRange
|
||||||
|
): Promise<ImagesForDiff>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1078,7 +1078,7 @@ export interface UserConfigInfo {
|
|||||||
*/
|
*/
|
||||||
export interface CommentInfo extends CommentInput {
|
export interface CommentInfo extends CommentInput {
|
||||||
patch_set?: PatchSetNum;
|
patch_set?: PatchSetNum;
|
||||||
id?: UrlEncodedCommentId;
|
id: UrlEncodedCommentId;
|
||||||
path?: string;
|
path?: string;
|
||||||
side?: CommentSide;
|
side?: CommentSide;
|
||||||
parent?: number;
|
parent?: number;
|
||||||
@@ -1086,7 +1086,7 @@ export interface CommentInfo extends CommentInput {
|
|||||||
range?: CommentRange;
|
range?: CommentRange;
|
||||||
in_reply_to?: UrlEncodedCommentId;
|
in_reply_to?: UrlEncodedCommentId;
|
||||||
message?: string;
|
message?: string;
|
||||||
updated?: Timestamp;
|
updated: Timestamp;
|
||||||
author?: AccountInfo;
|
author?: AccountInfo;
|
||||||
tag?: string;
|
tag?: string;
|
||||||
unresolved?: boolean;
|
unresolved?: boolean;
|
||||||
@@ -1876,6 +1876,18 @@ export type RecipientTypeToNotifyInfoMap = {
|
|||||||
*/
|
*/
|
||||||
export type RobotCommentInput = RobotCommentInfo;
|
export type RobotCommentInput = RobotCommentInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is what human, robot and draft comments can agree upon.
|
||||||
|
*
|
||||||
|
* Human, robot and saved draft comments all have a required id, but unsaved
|
||||||
|
* drafts do not. That is why the id is omitted from CommentInfo, such that it
|
||||||
|
* can be optional in Draft, but required in CommentInfo and RobotCommentInfo.
|
||||||
|
*/
|
||||||
|
export interface CommentBasics extends Omit<CommentInfo, 'id' | 'updated'> {
|
||||||
|
id?: UrlEncodedCommentId;
|
||||||
|
updated?: Timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The RobotCommentInfo entity contains information about a robot inline comment
|
* The RobotCommentInfo entity contains information about a robot inline comment
|
||||||
* https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#robot-comment-info
|
* https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#robot-comment-info
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {IronA11yAnnouncer} from '@polymer/iron-a11y-announcer/iron-a11y-announce
|
|||||||
import {GrDiffLine} from '../elements/diff/gr-diff/gr-diff-line';
|
import {GrDiffLine} from '../elements/diff/gr-diff/gr-diff-line';
|
||||||
import {FlattenedNodesObserver} from '@polymer/polymer/lib/utils/flattened-nodes-observer';
|
import {FlattenedNodesObserver} from '@polymer/polymer/lib/utils/flattened-nodes-observer';
|
||||||
import {PaperInputElement} from '@polymer/paper-input/paper-input';
|
import {PaperInputElement} from '@polymer/paper-input/paper-input';
|
||||||
|
import {CommitId} from './common';
|
||||||
|
|
||||||
export function notUndefined<T>(x: T | undefined): x is T {
|
export function notUndefined<T>(x: T | undefined): x is T {
|
||||||
return x !== undefined;
|
return x !== undefined;
|
||||||
@@ -28,6 +29,11 @@ export interface FixIronA11yAnnouncer extends IronA11yAnnouncer {
|
|||||||
requestAvailability(): void;
|
requestAvailability(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CommitRange {
|
||||||
|
baseCommit: CommitId;
|
||||||
|
commit: CommitId;
|
||||||
|
}
|
||||||
|
|
||||||
export interface CoverageRange {
|
export interface CoverageRange {
|
||||||
type: CoverageType;
|
type: CoverageType;
|
||||||
side: Side;
|
side: Side;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
ChangeInfo,
|
ChangeInfo,
|
||||||
PatchSetNum,
|
PatchSetNum,
|
||||||
EditPatchSetNum,
|
EditPatchSetNum,
|
||||||
|
BrandType,
|
||||||
} from '../types/common';
|
} from '../types/common';
|
||||||
import {RestApiService} from '../services/services/gr-rest-api/gr-rest-api';
|
import {RestApiService} from '../services/services/gr-rest-api/gr-rest-api';
|
||||||
import {ParsedChangeInfo} from '../elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser';
|
import {ParsedChangeInfo} from '../elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser';
|
||||||
@@ -81,6 +82,12 @@ export function isMergeParent(n: PatchSetNum) {
|
|||||||
return `${n}`[0] === '-';
|
return `${n}`[0] === '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isNumber(
|
||||||
|
psn: PatchSetNum
|
||||||
|
): psn is BrandType<number, '_patchSet'> {
|
||||||
|
return typeof psn === 'number';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an object of revisions, get a particular revision based on patch
|
* Given an object of revisions, get a particular revision based on patch
|
||||||
* num.
|
* num.
|
||||||
|
|||||||
Reference in New Issue
Block a user