@canyonjs/report-component 0.0.3 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.css CHANGED
@@ -87,3 +87,87 @@
87
87
  margin-right: 5px;
88
88
  }
89
89
 
90
+ /* CoverageDetail 样式 */
91
+ .canyonjs-report-html .canyon-coverage-detail-container {
92
+ height: 100%;
93
+ position: relative;
94
+ }
95
+
96
+ .canyonjs-report-html .canyon-coverage-detail-editor {
97
+ width: 100%;
98
+ height: 100%;
99
+ }
100
+
101
+ /* ChangedCodeCoverageTable 折叠表格样式 */
102
+ .canyonjs-report-html .canyon-changed-code-coverage-table {
103
+ position: absolute;
104
+ top: 0;
105
+ left: 0;
106
+ right: 0;
107
+ z-index: 1000;
108
+ }
109
+
110
+ .canyonjs-report-html .canyon-changed-code-coverage-toggle {
111
+ position: absolute;
112
+ top: 0;
113
+ left: 0;
114
+ right: 0;
115
+ padding: 8px 16px;
116
+ background: #f5f5f5;
117
+ border: none;
118
+ border-bottom: 1px solid #e0e0e0;
119
+ color: #333333;
120
+ font-size: 13px;
121
+ font-family:
122
+ -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
123
+ cursor: pointer;
124
+ text-align: left;
125
+ display: flex;
126
+ align-items: center;
127
+ z-index: 1001;
128
+ transition: background 0.2s ease;
129
+ }
130
+
131
+ .canyonjs-report-html .canyon-changed-code-coverage-toggle:hover {
132
+ background: #e8e8e8;
133
+ }
134
+
135
+ .canyonjs-report-html .canyon-changed-code-coverage-icon {
136
+ margin-right: 8px;
137
+ }
138
+
139
+ .canyonjs-report-html .canyon-changed-code-coverage-arrow {
140
+ margin-left: 8px;
141
+ transition: transform 0.3s ease;
142
+ }
143
+
144
+ .canyonjs-report-html .canyon-changed-code-coverage-content {
145
+ position: absolute;
146
+ top: 33px;
147
+ left: 0;
148
+ right: 0;
149
+ max-height: 0;
150
+ overflow: hidden;
151
+ background: #ffffff;
152
+ border-bottom: 1px solid #e0e0e0;
153
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
154
+ z-index: 1000;
155
+ transition: max-height 0.3s ease;
156
+ }
157
+
158
+ .canyonjs-report-html .canyon-changed-code-coverage-table-wrapper {
159
+ padding: 16px;
160
+ background: #ffffff;
161
+ font-family:
162
+ -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
163
+ overflow: auto;
164
+ max-height: 300px;
165
+ }
166
+
167
+ .canyonjs-report-html .canyon-changed-code-coverage-table-title {
168
+ font-weight: bold;
169
+ font-size: 14px;
170
+ color: #007acc;
171
+ margin-bottom: 12px;
172
+ }
173
+
package/dist/index.d.ts CHANGED
@@ -21,6 +21,12 @@ interface CanyonReportProps {
21
21
  value: string;
22
22
  dataSource: DataSourceItem[];
23
23
  onSelect: (val: string) => Promise<FileDataResponse>;
24
+ /** 默认是否只展示变更的文件,默认为 false(非受控模式使用) */
25
+ defaultOnlyChange?: boolean;
26
+ /** 是否只展示变更的文件(受控模式) */
27
+ onlyChange?: boolean;
28
+ /** 当 onlyChange 状态改变时的回调(受控模式) */
29
+ onChangeOnlyChange?: (value: boolean) => void;
24
30
  }
25
31
  //#endregion
26
32
  //#region src/CanyonReport.d.ts
package/dist/index.js CHANGED
@@ -205,6 +205,142 @@ function coreFn(fileCoverage, fileDetail) {
205
205
  };
206
206
  }
207
207
 
208
+ //#endregion
209
+ //#region src/widgets/ChangedCodeCoverageTable.tsx
210
+ const ChangedCodeCoverageTable = ({ coverage, addLines }) => {
211
+ console.log("coverage", coverage);
212
+ console.log("addLines", addLines);
213
+ const [isOpen, setIsOpen] = useState(false);
214
+ const relatedStatements = useMemo(() => {
215
+ if (addLines.length === 0 || !coverage.s || !coverage.statementMap) return [];
216
+ const addedLinesSet = new Set(addLines);
217
+ const statements = [];
218
+ Object.entries(coverage.statementMap).forEach(([stId, meta]) => {
219
+ const startLine = meta.start.line;
220
+ const endLine = meta.end.line;
221
+ const startCol = meta.start.column;
222
+ const endCol = meta.end.column;
223
+ const relatedLines = [];
224
+ for (let line = startLine; line <= endLine; line++) if (addedLinesSet.has(line)) relatedLines.push(line);
225
+ if (relatedLines.length > 0) {
226
+ const count = coverage.s[stId] || 0;
227
+ const covered = count > 0;
228
+ const locationDisplay = endLine > startLine ? `${startLine}:${startCol + 1} - ${endLine}:${endCol + 1}` : `${startLine}:${startCol + 1}`;
229
+ const relatedLinesDisplay = relatedLines.join(", ");
230
+ statements.push({
231
+ key: stId,
232
+ Status: covered ? "✓ Covered" : "✗ Not Covered",
233
+ Location: locationDisplay,
234
+ "Changed Lines": relatedLinesDisplay,
235
+ "Hit Count": covered ? `${count}x` : "Not covered"
236
+ });
237
+ }
238
+ });
239
+ statements.sort((a, b) => {
240
+ return parseInt(a.Location.split(":")[0] || "0") - parseInt(b.Location.split(":")[0] || "0");
241
+ });
242
+ return statements;
243
+ }, [addLines, coverage]);
244
+ const coverageStats = useMemo(() => {
245
+ if (relatedStatements.length === 0) return {
246
+ coveredCount: 0,
247
+ totalCount: 0,
248
+ coveragePercent: 0
249
+ };
250
+ const coveredCount = relatedStatements.filter((s) => s.Status.includes("✓")).length;
251
+ const totalCount = relatedStatements.length;
252
+ return {
253
+ coveredCount,
254
+ totalCount,
255
+ coveragePercent: totalCount > 0 ? Math.round(coveredCount / totalCount * 100) : 0
256
+ };
257
+ }, [relatedStatements]);
258
+ if (relatedStatements.length === 0) return null;
259
+ return /* @__PURE__ */ jsxs("div", {
260
+ className: "canyon-changed-code-coverage-table",
261
+ children: [/* @__PURE__ */ jsxs("button", {
262
+ className: "canyon-changed-code-coverage-toggle",
263
+ onClick: () => setIsOpen(!isOpen),
264
+ type: "button",
265
+ children: [
266
+ /* @__PURE__ */ jsx("span", {
267
+ className: "canyon-changed-code-coverage-icon",
268
+ children: "📊"
269
+ }),
270
+ /* @__PURE__ */ jsxs("span", { children: [
271
+ "Changed Code Coverage: ",
272
+ coverageStats.coveragePercent,
273
+ "% (",
274
+ coverageStats.coveredCount,
275
+ "/",
276
+ coverageStats.totalCount,
277
+ ")"
278
+ ] }),
279
+ /* @__PURE__ */ jsx("span", {
280
+ className: "canyon-changed-code-coverage-arrow",
281
+ children: isOpen ? "▲" : "▼"
282
+ })
283
+ ]
284
+ }), /* @__PURE__ */ jsx("div", {
285
+ className: "canyon-changed-code-coverage-content",
286
+ style: { maxHeight: isOpen ? "350px" : "0" },
287
+ children: /* @__PURE__ */ jsxs("div", {
288
+ className: "canyon-changed-code-coverage-table-wrapper",
289
+ children: [/* @__PURE__ */ jsxs("div", {
290
+ className: "canyon-changed-code-coverage-table-title",
291
+ children: [
292
+ "Changed Code Statements (",
293
+ coverageStats.totalCount,
294
+ ") - Coverage:",
295
+ " ",
296
+ coverageStats.coveragePercent,
297
+ "% (",
298
+ coverageStats.coveredCount,
299
+ "/",
300
+ coverageStats.totalCount,
301
+ ")"
302
+ ]
303
+ }), /* @__PURE__ */ jsx(ConfigProvider, {
304
+ theme: { token: { borderRadius: 0 } },
305
+ children: /* @__PURE__ */ jsx(Table, {
306
+ dataSource: relatedStatements,
307
+ columns: [
308
+ {
309
+ title: "Status",
310
+ dataIndex: "Status",
311
+ key: "Status",
312
+ render: (text) => /* @__PURE__ */ jsx("span", {
313
+ style: { color: text.includes("✓") ? "#4caf50" : "#f44336" },
314
+ children: text
315
+ })
316
+ },
317
+ {
318
+ title: "Location",
319
+ dataIndex: "Location",
320
+ key: "Location"
321
+ },
322
+ {
323
+ title: "Changed Lines",
324
+ dataIndex: "Changed Lines",
325
+ key: "Changed Lines"
326
+ },
327
+ {
328
+ title: "Hit Count",
329
+ dataIndex: "Hit Count",
330
+ key: "Hit Count"
331
+ }
332
+ ],
333
+ pagination: false,
334
+ size: "small",
335
+ bordered: true
336
+ })
337
+ })]
338
+ })
339
+ })]
340
+ });
341
+ };
342
+ var ChangedCodeCoverageTable_default = ChangedCodeCoverageTable;
343
+
208
344
  //#endregion
209
345
  //#region src/widgets/lineNumbers.tsx
210
346
  function genBgColor(hit) {
@@ -264,6 +400,8 @@ function lineNumbers(lineNumber, linesState, _addLines) {
264
400
  const CoverageDetail = ({ source, coverage, diff }) => {
265
401
  const { lines } = coreFn(coverage, source);
266
402
  const addLines = diff.additions || [];
403
+ const ref = useRef(null);
404
+ const hasChangedLines = addLines.length > 0 && coverage["s"] && coverage["statementMap"];
267
405
  const linesState = (() => {
268
406
  return lines.map((line, index) => {
269
407
  return {
@@ -276,7 +414,6 @@ const CoverageDetail = ({ source, coverage, diff }) => {
276
414
  const lineNumbersMinChars = (() => {
277
415
  return Math.max(...linesState.map((line) => line.hit)).toString().length + 8;
278
416
  })();
279
- const ref = useRef(null);
280
417
  useEffect(() => {
281
418
  if (ref.current) {
282
419
  const dom = ref.current;
@@ -345,10 +482,27 @@ const CoverageDetail = ({ source, coverage, diff }) => {
345
482
  if (editor) editor?.createDecorationsCollection?.(decorations);
346
483
  }
347
484
  }
348
- }, [source]);
349
- return /* @__PURE__ */ jsx("div", {
350
- ref,
351
- style: { height: "100%" }
485
+ }, [source, coverage]);
486
+ return /* @__PURE__ */ jsxs("div", {
487
+ className: "canyon-coverage-detail-container",
488
+ style: {
489
+ height: "100%",
490
+ position: "relative"
491
+ },
492
+ children: [hasChangedLines ? /* @__PURE__ */ jsx(ChangedCodeCoverageTable_default, {
493
+ coverage,
494
+ addLines
495
+ }) : null, /* @__PURE__ */ jsx("div", {
496
+ ref,
497
+ className: "canyon-coverage-detail-editor",
498
+ style: {
499
+ height: hasChangedLines ? "calc(100% - 33px)" : "100%",
500
+ top: hasChangedLines ? "33px" : "0",
501
+ position: "absolute",
502
+ left: 0,
503
+ right: 0
504
+ }
505
+ })]
352
506
  });
353
507
  };
354
508
  var CoverageDetail_default = CoverageDetail;
@@ -793,7 +947,7 @@ var TopControl_default = TopControl;
793
947
 
794
948
  //#endregion
795
949
  //#region src/CanyonReport.tsx
796
- const CanyonReport = ({ value, name, dataSource, onSelect }) => {
950
+ const CanyonReport = ({ value, name, dataSource, onSelect, defaultOnlyChange = false, onlyChange: controlledOnlyChange, onChangeOnlyChange: controlledOnChangeOnlyChange }) => {
797
951
  const [_isLoading, _setIsLoading] = useState(false);
798
952
  const [filenameKeywords, setFilenameKeywords] = useState("");
799
953
  const [showMode, setShowMode] = useState("tree");
@@ -808,10 +962,13 @@ const CanyonReport = ({ value, name, dataSource, onSelect }) => {
808
962
  });
809
963
  const [fileContent, setFileContent] = useState("");
810
964
  const [fileCodeChange, setFileCodeChange] = useState([]);
811
- const [onlyChange, setOnlyChange] = useState(Boolean(false));
965
+ const isControlled = controlledOnlyChange !== void 0 && controlledOnChangeOnlyChange !== void 0;
966
+ const [internalOnlyChange, setInternalOnlyChange] = useState(defaultOnlyChange);
967
+ const onlyChange = isControlled ? controlledOnlyChange : internalOnlyChange;
812
968
  const rootClassName = useMemo(() => `report-scope-${Math.random().toString(36).slice(2, 9)} canyonjs-report-html`, []);
813
969
  function onChangeOnlyChange(v) {
814
- setOnlyChange(v);
970
+ if (isControlled && controlledOnChangeOnlyChange) controlledOnChangeOnlyChange(v);
971
+ else setInternalOnlyChange(v);
815
972
  }
816
973
  const newOnSelect = useMemo(() => {
817
974
  return async (val) => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@canyonjs/report-component",
3
3
  "type": "module",
4
- "version": "0.0.3",
4
+ "version": "0.0.6",
5
5
  "author": "Travis Zhang<https://github.com/travzhang>",
6
6
  "repository": {
7
7
  "type": "git",