gitlab-org--gitlab-foss/app/assets/javascripts/notes/components/multiline_comment_utils.js

118 lines
4.0 KiB
JavaScript

import { takeRightWhile } from 'lodash';
export function getSymbol(type) {
if (type === 'new') return '+';
if (type === 'old') return '-';
return '';
}
function getLineNumber(lineRange, key) {
if (!lineRange || !key || !lineRange[key]) return '';
const { new_line: newLine, old_line: oldLine, type } = lineRange[key];
const otherKey = key === 'start' ? 'end' : 'start';
// By default we want to see the "old" or "left side" line number
// The exception is if the "end" line is on the "right" side
// `otherLineType` is only used if `type` is null to make sure the line
// number relfects the "right" side number, if that is the side
// the comment form is located on
const otherLineType = !type ? lineRange[otherKey]?.type : null;
const lineType = type || '';
let lineNumber = oldLine;
if (lineType === 'new' || otherLineType === 'new') lineNumber = newLine;
return (lineNumber && getSymbol(lineType) + lineNumber) || '';
}
export function getStartLineNumber(lineRange) {
return getLineNumber(lineRange, 'start');
}
export function getEndLineNumber(lineRange) {
return getLineNumber(lineRange, 'end');
}
export function getLineClasses(line) {
const symbol = typeof line === 'string' ? line.charAt(0) : getSymbol(line?.type);
if (symbol !== '+' && symbol !== '-') return '';
return [
'gl-px-1 gl-rounded-small gl-border-solid gl-border-1 gl-border-white',
{
'gl-bg-green-100 gl-text-green-800': symbol === '+',
'gl-bg-red-100 gl-text-red-800': symbol === '-',
},
];
}
export function commentLineOptions(diffLines, startingLine, lineCode, side = 'left') {
const preferredSide = side === 'left' ? 'old_line' : 'new_line';
const fallbackSide = preferredSide === 'new_line' ? 'old_line' : 'new_line';
const notMatchType = (l) => l.type !== 'match';
const linesCopy = [...diffLines]; // don't mutate the argument
const startingLineCode = startingLine.line_code;
const currentIndex = linesCopy.findIndex((line) => line.line_code === lineCode);
// We're limiting adding comments to only lines above the current line
// to make rendering simpler. Future interations will use a more
// intuitive dragging interface that will make this unnecessary
const upToSelected = linesCopy.slice(0, currentIndex + 1);
// Only include the lines up to the first "Show unchanged lines" block
// i.e. not a "match" type
const lines = takeRightWhile(upToSelected, notMatchType);
// If the selected line is "hidden" in an unchanged line block
// or "above" the current group of lines add it to the array so
// that the drop down is not defaulted to empty
const selectedIndex = lines.findIndex((line) => line.line_code === startingLineCode);
if (selectedIndex < 0) lines.unshift(startingLine);
return lines.map((l) => {
const { line_code, type, old_line, new_line } = l;
return {
value: { line_code, type, old_line, new_line },
text: `${getSymbol(type)}${l[preferredSide] || l[fallbackSide]}`,
};
});
}
export function formatLineRange(start, end) {
const extractProps = ({ line_code, type, old_line, new_line }) => ({
line_code,
type,
old_line,
new_line,
});
return {
start: extractProps(start),
end: extractProps(end),
};
}
export function getCommentedLines(selectedCommentPosition, diffLines) {
if (!selectedCommentPosition) {
// This structure simplifies the logic that consumes this result
// by keeping the returned shape the same and adjusting the bounds
// to something unreachable. This way our component logic stays:
// "if index between start and end"
return {
startLine: diffLines.length + 1,
endLine: diffLines.length + 1,
};
}
const findLineCodeIndex = (line) => (position) => {
return [position.line_code, position.left?.line_code, position.right?.line_code].includes(
line.line_code,
);
};
const { start, end } = selectedCommentPosition;
const startLine = diffLines.findIndex(findLineCodeIndex(start));
const endLine = diffLines.findIndex(findLineCodeIndex(end));
return { startLine, endLine };
}