import type * as Diff2Html from 'diff2html' import HoganJsUtils from 'diff2html/lib/hoganjs-utils' import { get } from 'lodash-es' import type { CommentItem } from 'components/CommentBox/CommentBox' import type { TypesPullReqActivity } from 'services/code' import type { DiffFileEntry } from 'utils/types' export enum ViewStyle { SIDE_BY_SIDE = 'side-by-side', LINE_BY_LINE = 'line-by-line' } export enum CommentType { COMMENT = 'comment', CODE_COMMENT = 'code-comment', TITLE_CHANGE = 'title-change', REVIEW_SUBMIT = 'review-submit', MERGE = 'merge', BRANCH_UPDATE = 'branch-update', STATE_CHANGE = 'state-change' } /** * @deprecated */ export interface PullRequestCodeCommentPayload { type: CommentType version: string // used to avoid rendering old payload structure file_id: string // unique id of the changed file file_title: string language: string is_on_left: boolean // comment made on the left side pane at_line_number: number line_number_range: number[] range_text_content: string // raw text content where the comment is made diff_html_snapshot: string // snapshot used to render diff in comment (PR Conversation). Could be used to send email notification too (with more work on capturing CSS styles and put them inline) } export const DIFF_VIEWER_HEADER_HEIGHT = 36 // const DIFF_MAX_CHANGES = 100 // const DIFF_MAX_LINE_LENGTH = 100 export interface DiffCommentItem { left: boolean right: boolean lineNumber: number height: number commentItems: CommentItem[] filePath: string } export const DIFF2HTML_CONFIG = { outputFormat: 'side-by-side', drawFileList: false, fileListStartVisible: false, fileContentToggle: true, // diffMaxChanges: DIFF_MAX_CHANGES, // diffMaxLineLength: DIFF_MAX_LINE_LENGTH, // diffTooBigMessage: index => `${index} - is too big`, matching: 'lines', synchronisedScroll: true, highlight: true, renderNothingWhenEmpty: false, compiledTemplates: { 'generic-line': HoganJsUtils.compile(` {{{lineNumber}}} {{{filePath}}}
+
{{#prefix}} {{{prefix}}} {{/prefix}} {{^prefix}}   {{/prefix}} {{#content}} {{{content}}} {{/content}} {{^content}}
{{/content}}
`), 'side-by-side-file-diff': HoganJsUtils.compile(`
{{{filePath}}}
{{{diffs.left}}}
{{{diffs.right}}}
`), 'line-by-line-file-diff': HoganJsUtils.compile(` `), 'line-by-line-numbers': HoganJsUtils.compile(`
{{oldNumber}}
{{newNumber}}
`) } } as Readonly export function getCommentLineInfo( contentDOM: HTMLDivElement | null, commentEntry: DiffCommentItem, viewStyle: ViewStyle ) { const isSideBySideView = viewStyle === ViewStyle.SIDE_BY_SIDE const { left, lineNumber, filePath } = commentEntry const filePathBody = filePath ? contentDOM?.querySelector(`[data="${filePath}"`) : contentDOM const diffBody = filePathBody?.querySelector( `${isSideBySideView ? `.d2h-file-side-diff${left ? '.left' : '.right'} ` : ''}.d2h-diff-tbody` ) const rowElement = ( diffBody?.querySelector(`[data-content-for-line-number="${lineNumber}"]`) || diffBody?.querySelector( `${!isSideBySideView ? (left ? '.line-num1' : '.line-num2') : ''}[data-line-number="${lineNumber}"]` ) )?.closest('tr') as HTMLTableRowElement let node = rowElement as Element let rowPosition = 1 while (node?.previousElementSibling) { rowPosition++ node = node.previousElementSibling } let oppositeRowElement: HTMLTableRowElement | null = null if (isSideBySideView) { const filesDiff = rowElement?.closest('.d2h-files-diff') as HTMLElement const sideDiff = filesDiff?.querySelector(`div.${left ? 'right' : 'left'}`) as HTMLElement oppositeRowElement = sideDiff?.querySelector(`tr:nth-child(${rowPosition})`) } return { rowElement, rowPosition, hasCommentsRendered: !!rowElement?.dataset?.annotated, oppositeRowElement } } export function renderCommentOppositePlaceHolder(annotation: DiffCommentItem, oppositeRowElement: HTMLTableRowElement) { const placeHolderRow = document.createElement('tr') placeHolderRow.dataset.placeHolderForLine = String(annotation.lineNumber) placeHolderRow.innerHTML = `
 
` oppositeRowElement.after(placeHolderRow) } export const activityToCommentItem = (activity: TypesPullReqActivity): CommentItem => ({ author: activity.author?.display_name as string, created: activity.created as number, updated: activity.edited as number, deleted: activity.deleted as number, outdated: !!activity.code_comment?.outdated, content: (activity.text || (activity.payload as Unknown)?.Message) as string, payload: activity }) export function activitiesToDiffCommentItems(diff: DiffFileEntry): DiffCommentItem[] { return ( diff.fileActivities?.map(activity => { const replyComments = diff.activities ?.filter(replyActivity => replyActivity.parent_id === activity.id) .map(_activity => activityToCommentItem(_activity)) || [] const right = get(activity.payload, 'line_start_new', false) return { left: !right, right, height: 0, lineNumber: (right ? activity.code_comment?.line_new : activity.code_comment?.line_old) as number, commentItems: [activityToCommentItem(activity)].concat(replyComments), filePath: diff.filePath } }) || [] ) }