mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-14 09:25:43 +01:00
Feature Partial Diff (#1581)
With this pull request, diffs for Git are loaded in chunks. This means, that for diffs with a lot of files only a part of them are loaded. In the UI a button will be displayed to load more. In the REST API, the number of files can be specified. This only works for diffs, that are delivered as "parsed" diffs. Currently, this is only available for Git. Co-authored-by: Sebastian Sdorra <sebastian.sdorra@cloudogu.com>
This commit is contained in:
@@ -30,14 +30,14 @@ import simpleDiff from "../__resources__/Diff.simple";
|
||||
import hunksDiff from "../__resources__/Diff.hunks";
|
||||
import binaryDiff from "../__resources__/Diff.binary";
|
||||
import markdownDiff from "../__resources__/Diff.markdown";
|
||||
import { DiffEventContext, File, FileControlFactory } from "./DiffTypes";
|
||||
import { DiffEventContext, FileControlFactory } from "./DiffTypes";
|
||||
import Toast from "../toast/Toast";
|
||||
import { getPath } from "./diffs";
|
||||
import DiffButton from "./DiffButton";
|
||||
import styled from "styled-components";
|
||||
import { MemoryRouter } from "react-router-dom";
|
||||
import { one, two } from "../__resources__/changesets";
|
||||
import { Changeset } from "@scm-manager/ui-types";
|
||||
import { Changeset, FileDiff } from "@scm-manager/ui-types";
|
||||
import JumpToFileButton from "./JumpToFileButton";
|
||||
|
||||
const diffFiles = parser.parse(simpleDiff);
|
||||
@@ -141,7 +141,7 @@ storiesOf("Diff", module)
|
||||
return <Diff diff={binaryDiffFiles} />;
|
||||
})
|
||||
.add("SyntaxHighlighting", () => {
|
||||
const filesWithLanguage = diffFiles.map((file: File) => {
|
||||
const filesWithLanguage = diffFiles.map((file: FileDiff) => {
|
||||
const ext = getPath(file).split(".")[1];
|
||||
if (ext === "tsx") {
|
||||
file.language = "typescript";
|
||||
@@ -160,7 +160,7 @@ storiesOf("Diff", module)
|
||||
<Diff diff={diffFiles} defaultCollapse={(oldPath, newPath) => oldPath.endsWith(".java")} />
|
||||
))
|
||||
.add("Expandable", () => {
|
||||
const filesWithLanguage = diffFiles.map((file: File) => {
|
||||
const filesWithLanguage = diffFiles.map((file: FileDiff) => {
|
||||
file._links = { lines: { href: "http://example.com/" } };
|
||||
return file;
|
||||
});
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
*/
|
||||
import React from "react";
|
||||
import DiffFile from "./DiffFile";
|
||||
import { DiffObjectProps, File, FileControlFactory } from "./DiffTypes";
|
||||
import { DiffObjectProps, FileControlFactory } from "./DiffTypes";
|
||||
import { FileDiff } from "@scm-manager/ui-types";
|
||||
import { escapeWhitespace } from "./diffs";
|
||||
import Notification from "../Notification";
|
||||
import { WithTranslation, withTranslation } from "react-i18next";
|
||||
@@ -32,7 +33,7 @@ import { RouteComponentProps, withRouter } from "react-router-dom";
|
||||
type Props = RouteComponentProps &
|
||||
WithTranslation &
|
||||
DiffObjectProps & {
|
||||
diff: File[];
|
||||
diff: FileDiff[];
|
||||
fileControlFactory?: FileControlFactory;
|
||||
};
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
*/
|
||||
import fetchMock from "fetch-mock";
|
||||
import DiffExpander from "./DiffExpander";
|
||||
import { File, Hunk } from "./DiffTypes";
|
||||
import { FileDiff, Hunk } from "@scm-manager/ui-types";
|
||||
|
||||
const HUNK_0: Hunk = {
|
||||
content: "@@ -1,8 +1,8 @@",
|
||||
@@ -94,7 +94,7 @@ const HUNK_3: Hunk = {
|
||||
{ content: "line", type: "normal", oldLineNumber: 38, newLineNumber: 40, isNormal: true }
|
||||
]
|
||||
};
|
||||
const TEST_CONTENT_WITH_HUNKS: File = {
|
||||
const TEST_CONTENT_WITH_HUNKS: FileDiff = {
|
||||
hunks: [HUNK_0, HUNK_1, HUNK_2, HUNK_3],
|
||||
newEndingNewLine: true,
|
||||
newPath: "src/main/js/CommitMessage.js",
|
||||
@@ -112,7 +112,7 @@ const TEST_CONTENT_WITH_HUNKS: File = {
|
||||
}
|
||||
};
|
||||
|
||||
const TEST_CONTENT_WITH_NEW_BINARY_FILE: File = {
|
||||
const TEST_CONTENT_WITH_NEW_BINARY_FILE: FileDiff = {
|
||||
oldPath: "/dev/null",
|
||||
newPath: "src/main/fileUploadV2.png",
|
||||
oldEndingNewLine: true,
|
||||
@@ -122,7 +122,7 @@ const TEST_CONTENT_WITH_NEW_BINARY_FILE: File = {
|
||||
type: "add"
|
||||
};
|
||||
|
||||
const TEST_CONTENT_WITH_NEW_TEXT_FILE: File = {
|
||||
const TEST_CONTENT_WITH_NEW_TEXT_FILE: FileDiff = {
|
||||
oldPath: "/dev/null",
|
||||
newPath: "src/main/markdown/README.md",
|
||||
oldEndingNewLine: true,
|
||||
@@ -151,7 +151,7 @@ const TEST_CONTENT_WITH_NEW_TEXT_FILE: File = {
|
||||
}
|
||||
};
|
||||
|
||||
const TEST_CONTENT_WITH_DELETED_TEXT_FILE: File = {
|
||||
const TEST_CONTENT_WITH_DELETED_TEXT_FILE: FileDiff = {
|
||||
oldPath: "README.md",
|
||||
newPath: "/dev/null",
|
||||
oldEndingNewLine: true,
|
||||
@@ -171,7 +171,7 @@ const TEST_CONTENT_WITH_DELETED_TEXT_FILE: File = {
|
||||
_links: { lines: { href: "http://localhost:8081/dev/null?start={start}&end={end}", templated: true } }
|
||||
};
|
||||
|
||||
const TEST_CONTENT_WITH_DELETED_LINES_AT_END: File = {
|
||||
const TEST_CONTENT_WITH_DELETED_LINES_AT_END: FileDiff = {
|
||||
oldPath: "pom.xml",
|
||||
newPath: "pom.xml",
|
||||
oldEndingNewLine: true,
|
||||
@@ -214,7 +214,7 @@ const TEST_CONTENT_WITH_DELETED_LINES_AT_END: File = {
|
||||
}
|
||||
};
|
||||
|
||||
const TEST_CONTENT_WITH_ALL_LINES_REMOVED_FROM_FILE: File = {
|
||||
const TEST_CONTENT_WITH_ALL_LINES_REMOVED_FROM_FILE: FileDiff = {
|
||||
oldPath: "pom.xml",
|
||||
newPath: "pom.xml",
|
||||
oldEndingNewLine: true,
|
||||
@@ -281,7 +281,7 @@ describe("with hunks the diff expander", () => {
|
||||
const expandedHunk = diffExpander.getHunk(1).hunk;
|
||||
const subsequentHunk = diffExpander.getHunk(2).hunk;
|
||||
fetchMock.get("http://localhost:8081/scm/api/v2/content/abc/CommitMessage.js?start=20&end=21", "new line 1");
|
||||
let newFile: File;
|
||||
let newFile: FileDiff;
|
||||
await diffExpander
|
||||
.getHunk(1)
|
||||
.expandBottom(1)
|
||||
@@ -306,7 +306,7 @@ describe("with hunks the diff expander", () => {
|
||||
"http://localhost:8081/scm/api/v2/content/abc/CommitMessage.js?start=8&end=13",
|
||||
"new line 9\nnew line 10\nnew line 11\nnew line 12\nnew line 13"
|
||||
);
|
||||
let newFile: File;
|
||||
let newFile: FileDiff;
|
||||
await diffExpander
|
||||
.getHunk(1)
|
||||
.expandHead(5)
|
||||
@@ -335,7 +335,7 @@ describe("with hunks the diff expander", () => {
|
||||
"http://localhost:8081/scm/api/v2/content/abc/CommitMessage.js?start=40&end=50",
|
||||
"new line 40\nnew line 41\nnew line 42"
|
||||
);
|
||||
let newFile: File;
|
||||
let newFile: FileDiff;
|
||||
await diffExpander
|
||||
.getHunk(3)
|
||||
.expandBottom(10)
|
||||
@@ -348,7 +348,7 @@ describe("with hunks the diff expander", () => {
|
||||
"http://localhost:8081/scm/api/v2/content/abc/CommitMessage.js?start=40&end=-1",
|
||||
"new line 40\nnew line 41\nnew line 42"
|
||||
);
|
||||
let newFile: File;
|
||||
let newFile: FileDiff;
|
||||
await diffExpander
|
||||
.getHunk(3)
|
||||
.expandBottom(-1)
|
||||
|
||||
@@ -23,13 +23,12 @@
|
||||
*/
|
||||
|
||||
import { apiClient } from "@scm-manager/ui-components";
|
||||
import { Change, File, Hunk } from "./DiffTypes";
|
||||
import { Link } from "@scm-manager/ui-types";
|
||||
import { Change, FileDiff, Hunk, Link } from "@scm-manager/ui-types";
|
||||
|
||||
class DiffExpander {
|
||||
file: File;
|
||||
file: FileDiff;
|
||||
|
||||
constructor(file: File) {
|
||||
constructor(file: FileDiff) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@@ -73,7 +72,7 @@ class DiffExpander {
|
||||
}
|
||||
};
|
||||
|
||||
expandHead: (n: number, count: number) => Promise<File> = (n, count) => {
|
||||
expandHead: (n: number, count: number) => Promise<FileDiff> = (n, count) => {
|
||||
const start = this.minLineNumber(n) - Math.min(count, this.computeMaxExpandHeadRange(n)) - 1;
|
||||
const end = this.minLineNumber(n) - 1;
|
||||
return this.loadLines(start, end).then(lines => {
|
||||
@@ -90,7 +89,7 @@ class DiffExpander {
|
||||
});
|
||||
};
|
||||
|
||||
expandBottom: (n: number, count: number) => Promise<File> = (n, count) => {
|
||||
expandBottom: (n: number, count: number) => Promise<FileDiff> = (n, count) => {
|
||||
const maxExpandBottomRange = this.computeMaxExpandBottomRange(n);
|
||||
const start = this.maxLineNumber(n);
|
||||
const end =
|
||||
@@ -191,8 +190,8 @@ export type ExpandableHunk = {
|
||||
hunk: Hunk;
|
||||
maxExpandHeadRange: number;
|
||||
maxExpandBottomRange: number;
|
||||
expandHead: (count: number) => Promise<File>;
|
||||
expandBottom: (count: number) => Promise<File>;
|
||||
expandHead: (count: number) => Promise<FileDiff>;
|
||||
expandBottom: (count: number) => Promise<FileDiff>;
|
||||
};
|
||||
|
||||
export default DiffExpander;
|
||||
|
||||
@@ -30,7 +30,8 @@ import { Decoration, getChangeKey, Hunk } from "react-diff-view";
|
||||
import { ButtonGroup } from "../buttons";
|
||||
import Tag from "../Tag";
|
||||
import Icon from "../Icon";
|
||||
import { Change, ChangeEvent, DiffObjectProps, File, Hunk as HunkType } from "./DiffTypes";
|
||||
import { Change, FileDiff, Hunk as HunkType } from "@scm-manager/ui-types";
|
||||
import { ChangeEvent, DiffObjectProps } from "./DiffTypes";
|
||||
import TokenizedDiffView from "./TokenizedDiffView";
|
||||
import DiffButton from "./DiffButton";
|
||||
import { MenuContext, OpenInFullscreenButton } from "@scm-manager/ui-components";
|
||||
@@ -45,7 +46,7 @@ const EMPTY_ANNOTATION_FACTORY = {};
|
||||
|
||||
type Props = DiffObjectProps &
|
||||
WithTranslation & {
|
||||
file: File;
|
||||
file: FileDiff;
|
||||
};
|
||||
|
||||
type Collapsible = {
|
||||
@@ -53,7 +54,7 @@ type Collapsible = {
|
||||
};
|
||||
|
||||
type State = Collapsible & {
|
||||
file: File;
|
||||
file: FileDiff;
|
||||
sideBySide?: boolean;
|
||||
diffExpander: DiffExpander;
|
||||
expansionError?: any;
|
||||
@@ -257,7 +258,7 @@ class DiffFile extends React.Component<Props, State> {
|
||||
};
|
||||
};
|
||||
|
||||
diffExpanded = (newFile: File) => {
|
||||
diffExpanded = (newFile: FileDiff) => {
|
||||
this.setState({ file: newFile, diffExpander: new DiffExpander(newFile) });
|
||||
};
|
||||
|
||||
@@ -303,7 +304,7 @@ class DiffFile extends React.Component<Props, State> {
|
||||
}
|
||||
};
|
||||
|
||||
renderHunk = (file: File, expandableHunk: ExpandableHunk, i: number) => {
|
||||
renderHunk = (file: FileDiff, expandableHunk: ExpandableHunk, i: number) => {
|
||||
const hunk = expandableHunk.hunk;
|
||||
if (this.props.markConflicts && hunk.changes) {
|
||||
this.markConflicts(hunk);
|
||||
@@ -353,7 +354,7 @@ class DiffFile extends React.Component<Props, State> {
|
||||
}
|
||||
};
|
||||
|
||||
getAnchorId(file: File) {
|
||||
getAnchorId(file: FileDiff) {
|
||||
let path: string;
|
||||
if (file.type === "delete") {
|
||||
path = file.oldPath;
|
||||
@@ -363,7 +364,7 @@ class DiffFile extends React.Component<Props, State> {
|
||||
return escapeWhitespace(path);
|
||||
}
|
||||
|
||||
renderFileTitle = (file: File) => {
|
||||
renderFileTitle = (file: FileDiff) => {
|
||||
if (file.oldPath !== file.newPath && (file.type === "copy" || file.type === "rename")) {
|
||||
return (
|
||||
<>
|
||||
@@ -376,7 +377,7 @@ class DiffFile extends React.Component<Props, State> {
|
||||
return file.newPath;
|
||||
};
|
||||
|
||||
hoverFileTitle = (file: File): string => {
|
||||
hoverFileTitle = (file: FileDiff): string => {
|
||||
if (file.oldPath !== file.newPath && (file.type === "copy" || file.type === "rename")) {
|
||||
return `${file.oldPath} > ${file.newPath}`;
|
||||
} else if (file.type === "delete") {
|
||||
@@ -385,7 +386,7 @@ class DiffFile extends React.Component<Props, State> {
|
||||
return file.newPath;
|
||||
};
|
||||
|
||||
renderChangeTag = (file: File) => {
|
||||
renderChangeTag = (file: FileDiff) => {
|
||||
const { t } = this.props;
|
||||
if (!file.type) {
|
||||
return;
|
||||
@@ -401,7 +402,7 @@ class DiffFile extends React.Component<Props, State> {
|
||||
return <ChangeTypeTag className={classNames("is-rounded", "has-text-weight-normal")} color={color} label={value} />;
|
||||
};
|
||||
|
||||
hasContent = (file: File) => file && !file.isBinary && file.hunks && file.hunks.length > 0;
|
||||
hasContent = (file: FileDiff) => file && !file.isBinary && file.hunks && file.hunks.length > 0;
|
||||
|
||||
render() {
|
||||
const { fileControlFactory, fileAnnotationFactory, t } = this.props;
|
||||
|
||||
@@ -24,55 +24,7 @@
|
||||
|
||||
import { ReactNode } from "react";
|
||||
import { DefaultCollapsed } from "./defaultCollapsed";
|
||||
import { Links } from "@scm-manager/ui-types";
|
||||
|
||||
// We place the types here and not in @scm-manager/ui-types,
|
||||
// because they represent not a real scm-manager related type.
|
||||
// This types represents only the required types for the Diff related components,
|
||||
// such as every other component does with its Props.
|
||||
|
||||
export type FileChangeType = "add" | "modify" | "delete" | "copy" | "rename";
|
||||
|
||||
export type File = {
|
||||
hunks?: Hunk[];
|
||||
newEndingNewLine: boolean;
|
||||
newMode?: string;
|
||||
newPath: string;
|
||||
newRevision?: string;
|
||||
oldEndingNewLine: boolean;
|
||||
oldMode?: string;
|
||||
oldPath: string;
|
||||
oldRevision?: string;
|
||||
type: FileChangeType;
|
||||
language?: string;
|
||||
// TODO does this property exists?
|
||||
isBinary?: boolean;
|
||||
_links?: Links;
|
||||
};
|
||||
|
||||
export type Hunk = {
|
||||
changes: Change[];
|
||||
content: string;
|
||||
oldStart?: number;
|
||||
newStart?: number;
|
||||
oldLines?: number;
|
||||
newLines?: number;
|
||||
fullyExpanded?: boolean;
|
||||
expansion?: boolean;
|
||||
};
|
||||
|
||||
export type ChangeType = "insert" | "delete" | "normal" | "conflict";
|
||||
|
||||
export type Change = {
|
||||
content: string;
|
||||
isNormal?: boolean;
|
||||
isInsert?: boolean;
|
||||
isDelete?: boolean;
|
||||
lineNumber?: number;
|
||||
newLineNumber?: number;
|
||||
oldLineNumber?: number;
|
||||
type: ChangeType;
|
||||
};
|
||||
import { Change, Hunk, FileDiff as File } from "@scm-manager/ui-types";
|
||||
|
||||
export type ChangeEvent = {
|
||||
change: Change;
|
||||
|
||||
@@ -21,93 +21,72 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
import React from "react";
|
||||
import { apiClient, NotFoundError } from "@scm-manager/ui-api";
|
||||
import React, { FC } from "react";
|
||||
import { NotFoundError, useDiff } from "@scm-manager/ui-api";
|
||||
import ErrorNotification from "../ErrorNotification";
|
||||
// @ts-ignore
|
||||
import parser from "gitdiff-parser";
|
||||
import Notification from "../Notification";
|
||||
|
||||
import Loading from "../Loading";
|
||||
import Diff from "./Diff";
|
||||
import { DiffObjectProps, File } from "./DiffTypes";
|
||||
import { Notification } from "../index";
|
||||
import { withTranslation, WithTranslation } from "react-i18next";
|
||||
import { DiffObjectProps } from "./DiffTypes";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Button from "../buttons/Button";
|
||||
import styled from "styled-components";
|
||||
|
||||
type Props = WithTranslation &
|
||||
DiffObjectProps & {
|
||||
url: string;
|
||||
};
|
||||
|
||||
type State = {
|
||||
diff?: File[];
|
||||
loading: boolean;
|
||||
error?: Error;
|
||||
type Props = DiffObjectProps & {
|
||||
url: string;
|
||||
limit?: number;
|
||||
};
|
||||
|
||||
class LoadingDiff extends React.Component<Props, State> {
|
||||
static defaultProps = {
|
||||
sideBySide: false
|
||||
};
|
||||
type NotificationProps = {
|
||||
fetchNextPage: () => void;
|
||||
isFetchingNextPage: boolean;
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
loading: true
|
||||
};
|
||||
}
|
||||
const StyledNotification = styled(Notification)`
|
||||
margin-top: 1.5rem;
|
||||
`;
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchDiff();
|
||||
}
|
||||
const PartialNotification: FC<NotificationProps> = ({ fetchNextPage, isFetchingNextPage }) => {
|
||||
const [t] = useTranslation("repos");
|
||||
return (
|
||||
<StyledNotification type="info">
|
||||
<div className="columns is-centered">
|
||||
<div className="column">{t("changesets.moreDiffsAvailable")}</div>
|
||||
<Button label={t("changesets.loadMore")} action={fetchNextPage} loading={isFetchingNextPage} />
|
||||
</div>
|
||||
</StyledNotification>
|
||||
);
|
||||
};
|
||||
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
if (prevProps.url !== this.props.url) {
|
||||
this.fetchDiff();
|
||||
const LoadingDiff: FC<Props> = ({ url, limit, ...props }) => {
|
||||
const { error, isLoading, data, fetchNextPage, isFetchingNextPage } = useDiff(url, { limit });
|
||||
const [t] = useTranslation("repos");
|
||||
|
||||
if (error) {
|
||||
if (error instanceof NotFoundError) {
|
||||
return <Notification type="info">{t("changesets.noChangesets")}</Notification>;
|
||||
}
|
||||
return <ErrorNotification error={error} />;
|
||||
} else if (isLoading) {
|
||||
return <Loading />;
|
||||
} else if (!data?.files) {
|
||||
return null;
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
<Diff diff={data.files} {...props} />
|
||||
{data.partial ? (
|
||||
<PartialNotification fetchNextPage={fetchNextPage} isFetchingNextPage={isFetchingNextPage} />
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
fetchDiff = () => {
|
||||
const { url } = this.props;
|
||||
this.setState({ loading: true });
|
||||
apiClient
|
||||
.get(url)
|
||||
.then(response => {
|
||||
const contentType = response.headers.get("Content-Type");
|
||||
if (contentType && contentType.toLowerCase() === "application/vnd.scmm-diffparsed+json;v=2") {
|
||||
return response.json().then(data => data.files);
|
||||
} else {
|
||||
return response.text().then(parser.parse);
|
||||
}
|
||||
})
|
||||
.then((diff: File[]) => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
diff: diff
|
||||
});
|
||||
})
|
||||
.catch((error: Error) => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
error
|
||||
});
|
||||
});
|
||||
};
|
||||
LoadingDiff.defaultProps = {
|
||||
limit: 25,
|
||||
sideBySide: false
|
||||
};
|
||||
|
||||
render() {
|
||||
const { diff, loading, error } = this.state;
|
||||
if (error) {
|
||||
if (error instanceof NotFoundError) {
|
||||
return <Notification type="info">{this.props.t("changesets.noChangesets")}</Notification>;
|
||||
}
|
||||
return <ErrorNotification error={error} />;
|
||||
} else if (loading) {
|
||||
return <Loading />;
|
||||
} else if (!diff) {
|
||||
return null;
|
||||
} else {
|
||||
return <Diff diff={diff} {...this.props} />;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default withTranslation("repos")(LoadingDiff);
|
||||
export default LoadingDiff;
|
||||
|
||||
@@ -25,7 +25,7 @@ import React, { FC } from "react";
|
||||
import styled from "styled-components";
|
||||
// @ts-ignore we have no typings for react-diff-view
|
||||
import { Diff, useTokenizeWorker } from "react-diff-view";
|
||||
import { File } from "./DiffTypes";
|
||||
import { FileDiff } from "@scm-manager/ui-types";
|
||||
import { determineLanguage } from "../languages";
|
||||
|
||||
// @ts-ignore no types for css modules
|
||||
@@ -65,7 +65,7 @@ const tokenize = new Worker("./Tokenize.worker.ts", { name: "tokenizer", type: "
|
||||
tokenize.postMessage({ theme });
|
||||
|
||||
type Props = {
|
||||
file: File;
|
||||
file: FileDiff;
|
||||
viewType: "split" | "unified";
|
||||
className?: string;
|
||||
};
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import { File, FileChangeType, Hunk } from "./DiffTypes";
|
||||
import { FileChangeType, Hunk, FileDiff } from "@scm-manager/ui-types";
|
||||
import { getPath, createHunkIdentifier, createHunkIdentifierFromContext, escapeWhitespace } from "./diffs";
|
||||
|
||||
describe("tests for diff util functions", () => {
|
||||
const file = (type: FileChangeType, oldPath: string, newPath: string): File => {
|
||||
const file = (type: FileChangeType, oldPath: string, newPath: string): FileDiff => {
|
||||
return {
|
||||
hunks: [],
|
||||
type: type,
|
||||
|
||||
@@ -22,16 +22,17 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import { BaseContext, File, Hunk } from "./DiffTypes";
|
||||
import { BaseContext } from "./DiffTypes";
|
||||
import { FileDiff, Hunk } from "@scm-manager/ui-types";
|
||||
|
||||
export function getPath(file: File) {
|
||||
export function getPath(file: FileDiff) {
|
||||
if (file.type === "delete") {
|
||||
return file.oldPath;
|
||||
}
|
||||
return file.newPath;
|
||||
}
|
||||
|
||||
export function createHunkIdentifier(file: File, hunk: Hunk) {
|
||||
export function createHunkIdentifier(file: FileDiff, hunk: Hunk) {
|
||||
const path = getPath(file);
|
||||
return `${file.type}_${path}_${hunk.content}`;
|
||||
}
|
||||
|
||||
@@ -25,11 +25,6 @@
|
||||
import * as diffs from "./diffs";
|
||||
|
||||
import {
|
||||
File,
|
||||
FileChangeType,
|
||||
Hunk,
|
||||
Change,
|
||||
ChangeType,
|
||||
BaseContext,
|
||||
AnnotationFactory,
|
||||
AnnotationFactoryContext,
|
||||
@@ -37,6 +32,7 @@ import {
|
||||
DiffEventContext
|
||||
} from "./DiffTypes";
|
||||
|
||||
import { FileDiff as File, FileChangeType, Hunk, Change, ChangeType } from "@scm-manager/ui-types";
|
||||
export { diffs };
|
||||
|
||||
export * from "./annotate";
|
||||
|
||||
Reference in New Issue
Block a user