Skip to content

Commit d11c5fa

Browse files
committed
feat: update diff editor
1 parent cf6ace4 commit d11c5fa

File tree

10 files changed

+219
-36
lines changed

10 files changed

+219
-36
lines changed

packages/canyon-backend/src/app.module.ts

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { TypeOrmModule } from "@nestjs/typeorm";
1818
import { CollectModule } from "./apps/collect/collect.module";
1919
import { CoveragediskEntity } from "./apps/collect/entity/coveragedisk.entity";
2020
import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default';
21+
import {CodeModule} from "./code/code.module";
2122

2223

2324
@Module({
@@ -37,6 +38,7 @@ import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin
3738
CoverageModule,
3839
CodechangeModule,
3940
SourcecodeModule,
41+
CodeModule,
4042
ServeStaticModule.forRoot({
4143
rootPath: join(__dirname, "../../canyon-platform", "dist"),
4244
exclude: ["/graphql"], // 这样就不会触发 path-to-regexp 解析错误
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { Controller, Get, Query } from "@nestjs/common";
2+
import { CodeService } from "./code.service";
3+
import {Codechange2Service} from "./codechange2.service";
4+
5+
interface CodeResponse {
6+
oldContent: string;
7+
content: string;
8+
additions:number[];
9+
compareTarget: string;
10+
}
11+
12+
@Controller("")
13+
export class CodeController {
14+
constructor(
15+
private readonly sourcecodeService: CodeService,
16+
private readonly codechange2Service: Codechange2Service
17+
) {}
18+
@Get("api/code")
19+
async code(@Query() query): Promise<CodeResponse> {
20+
const { projectID, sha, filepath } = query;
21+
22+
23+
const codechange = await this.codechange2Service.getCodechange(sha, filepath);
24+
const sourcecode = await this.sourcecodeService.getsourcecode(projectID, sha, filepath);
25+
26+
27+
if (codechange.compareTarget ===sha){
28+
return {
29+
compareTarget: codechange.compareTarget,
30+
oldContent: '',
31+
content: sourcecode.content,
32+
additions: codechange.additions,
33+
}
34+
} else {
35+
const oldSourcecode = await this.sourcecodeService.getsourcecode(projectID, codechange.compareTarget, filepath);
36+
return {
37+
compareTarget: codechange.compareTarget,
38+
oldContent: oldSourcecode.content,
39+
content: sourcecode.content,
40+
additions: codechange.additions,
41+
}
42+
}
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Module } from "@nestjs/common";
2+
import { PrismaService } from "../prisma/prisma.service";
3+
import { CodeService } from "./code.service";
4+
import {Codechange2Service} from "./codechange2.service";
5+
import {CodeController} from "./code.controller";
6+
7+
@Module({
8+
controllers: [CodeController],
9+
providers: [CodeService, PrismaService,Codechange2Service],
10+
})
11+
export class CodeModule {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { Injectable } from "@nestjs/common";
2+
import { PrismaService } from "../prisma/prisma.service";
3+
import { getFileInfo } from "../adapter/gitlab.adapter";
4+
5+
@Injectable()
6+
export class CodeService {
7+
constructor(private readonly prisma: PrismaService) {}
8+
async getsourcecode(projectID, sha, filepath): Promise<any> {
9+
const gitProvider = await this.prisma.gitProvider.findFirst({
10+
where: {
11+
id: projectID.split("-")[0],
12+
},
13+
});
14+
// console.log(gitProvider,'gitProvider')
15+
return getFileInfo(
16+
{
17+
projectID: projectID.split("-")[1],
18+
filepath: encodeURIComponent(filepath),
19+
commitSha: sha,
20+
},
21+
gitProvider?.privateToken,
22+
gitProvider?.url,
23+
);
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { Injectable } from "@nestjs/common";
2+
import { PrismaService } from "../prisma/prisma.service";
3+
4+
@Injectable()
5+
export class Codechange2Service {
6+
constructor(private readonly prisma: PrismaService) {}
7+
8+
async getCodechange(sha, filepath) {
9+
const { compareTarget } = await this.prisma.coverage
10+
.findFirst({
11+
where: {
12+
sha: sha,
13+
covType: "all",
14+
projectID: {
15+
not: {
16+
contains: "-ut",
17+
},
18+
},
19+
},
20+
})
21+
.then((res) => res || { compareTarget: sha });
22+
return this.prisma.codechange
23+
.findFirst({
24+
where: {
25+
compareTarget,
26+
sha: sha,
27+
path: filepath,
28+
},
29+
})
30+
.then((r) => {
31+
if (r) {
32+
return r;
33+
} else {
34+
return {
35+
id: "",
36+
projectID: "",
37+
compareTarget: compareTarget,
38+
sha: sha,
39+
path: filepath,
40+
additions: [],
41+
deletions: [],
42+
};
43+
}
44+
});
45+
}
46+
}

packages/canyon-platform/src/pages/index/projects/[id]/commits/[sha]/[...filepath].tsx

+1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ const Sha = () => {
9191
fileContent: res.fileContent,
9292
fileCoverage: res.fileCoverage,
9393
fileCodeChange: res.fileCodeChange,
94+
fileCodeChangeContent: res.fileCodeChangeContent,
9495
};
9596
});
9697
}}

packages/canyon-platform/src/pages/index/projects/[id]/commits/helper/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export function handleSelectFile({
1515
reportID,
1616
}: HandleSelectFile) {
1717
const fileContentRequest = axios
18-
.get(`/api/sourcecode`, {
18+
.get(`/api/code`, {
1919
params: {
2020
projectID: projectID,
2121
sha: sha,
@@ -52,6 +52,7 @@ export function handleSelectFile({
5252
fileContent: getDecode(fileContent.content),
5353
fileCoverage: fileCoverage,
5454
fileCodeChange: fileCodeChange.additions || [],
55+
fileCodeChangeContent: getDecode(fileContent.oldContent),
5556
};
5657
});
5758
}

packages/canyon-report/src/components/report.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const onSelectDefault = () => {
1515
fileContent: "",
1616
fileCoverage: emptyFileCoverageData,
1717
fileCodeChange: [],
18+
fileCodeChangeContent: "",
1819
});
1920
};
2021

@@ -38,6 +39,7 @@ const Report: FC<ReportProps> = ({
3839
b: {},
3940
});
4041
const [fileContent, setFileContent] = useState<string>("");
42+
const [fileCodeChangeContent, setFileCodeChangeContent] = useState<string>("");
4143
const [fileCodeChange, setFileCodeChange] = useState<number[]>([]);
4244
const [onlyChange, setOnlyChange] = useState(Boolean(defaultOnlyShowChanged));
4345

@@ -46,6 +48,7 @@ const Report: FC<ReportProps> = ({
4648
setFileContent(res.fileContent);
4749
setFileCoverage(res.fileCoverage);
4850
setFileCodeChange(res.fileCodeChange);
51+
setFileCodeChangeContent(res.fileCodeChangeContent);
4952
return res;
5053
}
5154

@@ -143,6 +146,7 @@ const Report: FC<ReportProps> = ({
143146
Object.keys(fileCoverage).length > 0 &&
144147
Object.keys(fileContent).length > 0 && (
145148
<FileCoverageDetail
149+
fileCodeChangeContent={fileCodeChangeContent}
146150
fileContent={fileContent}
147151
fileCodeChange={fileCodeChange}
148152
fileCoverage={fileCoverage}

packages/canyon-report/src/components/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export interface ReportProps {
88
fileCoverage: FileCoverageData;
99
fileContent: string;
1010
fileCodeChange: number[];
11+
fileCodeChangeContent: string;
1112
}>;
1213
defaultOnlyShowChanged: boolean;
1314
}

packages/canyon-report/src/components/widgets/FileCoverageDetail.tsx

+83-35
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FC, useEffect, useMemo, useRef, useState } from "react";
2-
import { Editor } from "@monaco-editor/react";
2+
import { DiffEditor, Editor } from "@monaco-editor/react";
33

44
// import * as monaco from "monaco-editor";
55
import {
@@ -14,20 +14,21 @@ const { useToken } = theme;
1414
const FileCoverageDetail: FC<{
1515
fileContent: string;
1616
fileCodeChange: number[];
17+
fileCodeChangeContent: string;
1718
fileCoverage: any;
18-
}> = ({ fileContent, fileCoverage, fileCodeChange }) => {
19+
}> = ({ fileContent, fileCoverage, fileCodeChange, fileCodeChangeContent }) => {
1920
const { token } = useToken();
2021
const { lines } = coreFn(fileCoverage, fileContent);
2122

2223
const linesState = useMemo(() => {
2324
return lines.map((line, index) => {
2425
return {
2526
lineNumber: index + 1,
26-
change: fileCodeChange.includes(index + 1),
27+
change: false,
2728
hit: line.executionNumber,
2829
};
2930
});
30-
}, [lines, fileCodeChange]);
31+
}, [lines]);
3132

3233
const lineNumbersMinChars = useMemo(() => {
3334
const maxHit = Math.max(...linesState.map((line) => line.hit));
@@ -62,7 +63,20 @@ const FileCoverageDetail: FC<{
6263
}
6364
useEffect(() => {
6465
if (editor) {
65-
editor?.deltaDecorations?.(
66+
let needDeltaDecorationsEditor = null;
67+
68+
if (fileCodeChangeContent) {
69+
const originalEditor = editor.getOriginalEditor();
70+
originalEditor.updateOptions({
71+
lineNumbers: false,
72+
});
73+
const modifiedEditor = editor.getModifiedEditor();
74+
needDeltaDecorationsEditor = modifiedEditor;
75+
} else {
76+
needDeltaDecorationsEditor = editor;
77+
}
78+
79+
needDeltaDecorationsEditor?.deltaDecorations?.(
6680
[], // oldDecorations 每次清空上次标记的
6781
decorations.map(
6882
({ inlineClassName, startLine, startCol, endLine, endCol }) => ({
@@ -91,36 +105,70 @@ const FileCoverageDetail: FC<{
91105
// border: "1px solid " + token.colorBorder,
92106
}}
93107
>
94-
<Editor
95-
value={fileContent}
96-
theme={token.colorBgBase === "#000" ? "nightOwl" : "vs"}
97-
height={"calc(100vh - 200px)"}
98-
// height={`${18 * (lineCount + 1)}px`}
99-
language={"javascript"}
100-
onMount={handleEditorDidMount}
101-
options={{
102-
lineHeight: 18,
103-
lineNumbers: (lineNumber) => {
104-
return lineNumbers(
105-
lineNumber,
106-
linesState,
107-
token.colorBgBase === "#000",
108-
);
109-
},
110-
lineNumbersMinChars: lineNumbersMinChars,
111-
readOnly: true,
112-
folding: false,
113-
minimap: { enabled: false },
114-
scrollBeyondLastLine: false,
115-
showUnused: false,
116-
fontSize: 12,
117-
fontFamily: "IBMPlexMono",
118-
scrollbar: {
119-
// handleMouseWheel: false,
120-
},
121-
contextmenu: false,
122-
}}
123-
/>
108+
{fileCodeChangeContent ? (
109+
<DiffEditor
110+
original={fileCodeChangeContent}
111+
modified={fileContent}
112+
// theme={"vs-dark"}
113+
height={"calc(100vh - 200px)"}
114+
// height={`${18 * (lineCount + 1)}px`}
115+
language={"javascript"}
116+
onMount={handleEditorDidMount}
117+
options={{
118+
lineHeight: 18,
119+
lineNumbers: (lineNumber) => {
120+
return lineNumbers(
121+
lineNumber,
122+
linesState,
123+
token.colorBgBase === "#000",
124+
);
125+
},
126+
lineNumbersMinChars: lineNumbersMinChars,
127+
readOnly: true,
128+
folding: false,
129+
minimap: { enabled: false },
130+
scrollBeyondLastLine: false,
131+
showUnused: false,
132+
fontSize: 12,
133+
fontFamily: "IBMPlexMono",
134+
scrollbar: {
135+
// handleMouseWheel: false,
136+
},
137+
contextmenu: false,
138+
}}
139+
/>
140+
) : (
141+
<Editor
142+
value={fileContent}
143+
theme={token.colorBgBase === "#000" ? "nightOwl" : "vs"}
144+
height={"calc(100vh - 200px)"}
145+
// height={`${18 * (lineCount + 1)}px`}
146+
language={"javascript"}
147+
onMount={handleEditorDidMount}
148+
options={{
149+
lineHeight: 18,
150+
lineNumbers: (lineNumber) => {
151+
return lineNumbers(
152+
lineNumber,
153+
linesState,
154+
token.colorBgBase === "#000",
155+
);
156+
},
157+
lineNumbersMinChars: lineNumbersMinChars,
158+
readOnly: true,
159+
folding: false,
160+
minimap: { enabled: false },
161+
scrollBeyondLastLine: false,
162+
showUnused: false,
163+
fontSize: 12,
164+
fontFamily: "IBMPlexMono",
165+
scrollbar: {
166+
// handleMouseWheel: false,
167+
},
168+
contextmenu: false,
169+
}}
170+
/>
171+
)}
124172
</div>
125173
);
126174
};

0 commit comments

Comments
 (0)