react-terminal-viewer-cicd 3.0.0-beta.43 → 3.0.0-beta.44

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.
@@ -1,7 +1,7 @@
1
1
  function LogWorker() {
2
2
  var workerPath = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '/worker';
3
3
  var worker = null;
4
- var version = "3.0.0-beta.43" || '0.0.0';
4
+ var version = "3.0.0-beta.44" || '0.0.0';
5
5
  var path = workerPath.includes('http') ? "".concat(workerPath, "/log.worker.js") : "".concat(window.location.origin).concat(workerPath, "/log.worker.js");
6
6
  var blob = new Blob(["importScripts(\"".concat(path, "?v=").concat(version, "\")")], {
7
7
  type: 'application/javascript'
@@ -1 +1 @@
1
- {"version":3,"file":"PipelineLogViewer.d.ts","sourceRoot":"","sources":["../../../src/PipelineLogViewer/PipelineLogViewer.tsx"],"names":[],"mappings":"AAoBA,OAAO,KASN,MAAM,OAAO,CAAC;AAef,OAAO,cAAc,CAAC;AACtB,OAAO,KAAK,EAGV,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,SAAS,CAAC;AAwEjB,QAAA,MAAM,iBAAiB,qGAoxCtB,CAAC;AAIF,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"PipelineLogViewer.d.ts","sourceRoot":"","sources":["../../../src/PipelineLogViewer/PipelineLogViewer.tsx"],"names":[],"mappings":"AAoBA,OAAO,KASN,MAAM,OAAO,CAAC;AAiBf,OAAO,cAAc,CAAC;AACtB,OAAO,KAAK,EAGV,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,SAAS,CAAC;AAwEjB,QAAA,MAAM,iBAAiB,qGAkyCtB,CAAC;AAIF,eAAe,iBAAiB,CAAC"}
@@ -36,14 +36,14 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
36
36
  import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from 'react';
37
37
  import { Virtuoso } from 'react-virtuoso';
38
38
  import { GroupHeader, LogRow, SearchBar, StickyHeader } from "./components";
39
- import { BOUNDARY_PREFETCH_INDEX_MARGIN, DEFAULT_MAX_MEMORY_LINES, DEFAULT_PAGE_SIZE, DEFAULT_VIRTUOSO_ITEM_HEIGHT } from "./constants";
39
+ import { BOUNDARY_PREFETCH_INDEX_MARGIN, DEFAULT_MAX_MEMORY_LINES, DEFAULT_PAGE_SIZE, DEFAULT_VIRTUOSO_ITEM_HEIGHT, IGNORE_BOUNDARY_FETCH_MS_AFTER_SCROLL, IGNORE_BOUNDARY_FETCH_MS_FIRST_SCREEN } from "./constants";
40
40
  import useDisplayLogs from "./hooks/useDisplayLogs";
41
41
  import useGroupManager from "./hooks/useGroupManager";
42
42
  import useLogFetcher from "./hooks/useLogFetcher";
43
43
  import useLogSearch from "./hooks/useLogSearch";
44
44
  import useStickyHeader from "./hooks/useStickyHeader";
45
45
  import "./index.less";
46
- import { getGlobalVisibleLineNumberLabel } from "./utils/groupLineNumber";
46
+ import { getPipelineGroupedLineNumberLabel } from "./utils/groupLineNumber";
47
47
  import normalizeGroupsForPipelineStatus from "./utils/normalizeGroupsForPipelineStatus";
48
48
  import { applyBoundaryScrollCompensation } from "./utils/virtuosoBoundaryScroll";
49
49
  import { firstVisibleIndexFromRenderedItems, lastVisibleIndexFromRenderedItems } from "./utils/virtuosoVisibleItems";
@@ -137,7 +137,9 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
137
137
  groupStatusIcons = _ref2.groupStatusIcons,
138
138
  onCollapsedChange = _ref2.onCollapsedChange,
139
139
  serverOffsetTime = _ref2.serverOffsetTime,
140
- highlightOptions = _ref2.highlightOptions;
140
+ highlightOptions = _ref2.highlightOptions,
141
+ _ref2$showLogTime = _ref2.showLogTime,
142
+ showLogTime = _ref2$showLogTime === void 0 ? true : _ref2$showLogTime;
141
143
  // ===================================================================
142
144
  // 一、分组数据
143
145
  // ===================================================================
@@ -350,12 +352,13 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
350
352
  useEffect(function () {
351
353
  if (initializedRef.current) return;
352
354
  initializedRef.current = true;
355
+ ignoreBoundaryFetchRef.current = Date.now() + IGNORE_BOUNDARY_FETCH_MS_FIRST_SCREEN;
353
356
  Promise.all([fetchGroups().then(function (groupData) {
354
357
  if (groupData && groupData.length > 0) {
355
358
  setGroups(normalizeGroupsForPipelineStatus(groupData, status));
356
359
  }
357
360
  }), initLoadRef.current()]).then(function () {
358
- ignoreBoundaryFetchRef.current = Date.now() + 500;
361
+ ignoreBoundaryFetchRef.current = Math.max(ignoreBoundaryFetchRef.current, Date.now() + IGNORE_BOUNDARY_FETCH_MS_AFTER_SCROLL);
359
362
  requestAnimationFrame(function () {
360
363
  var _virtuosoRef$current;
361
364
  (_virtuosoRef$current = virtuosoRef.current) === null || _virtuosoRef$current === void 0 || _virtuosoRef$current.scrollToIndex({
@@ -389,7 +392,7 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
389
392
  boundaryFetchingRef.current = false;
390
393
  pendingScrollAfterPrevRef.current = null;
391
394
  pendingScrollAfterNextRef.current = null;
392
- ignoreBoundaryFetchRef.current = Date.now() + 500;
395
+ ignoreBoundaryFetchRef.current = Date.now() + IGNORE_BOUNDARY_FETCH_MS_AFTER_SCROLL;
393
396
  }, [fetchLogs, logFetcherResult.reset, groupManager.expandAll, logSearchResult.clearSearch, status]);
394
397
  /* eslint-enable react-hooks/exhaustive-deps */
395
398
 
@@ -555,7 +558,7 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
555
558
  var prepended = prependedCountFromPrevRef.current;
556
559
  pendingScrollAfterPrevRef.current = null;
557
560
  displayLogsLenBeforeLoadPrevRef.current = null;
558
- ignoreBoundaryFetchRef.current = Date.now() + 500;
561
+ ignoreBoundaryFetchRef.current = Date.now() + IGNORE_BOUNDARY_FETCH_MS_AFTER_SCROLL;
559
562
  if (boundaryIgnoreFollowUpTimeoutRef.current) {
560
563
  clearTimeout(boundaryIgnoreFollowUpTimeoutRef.current);
561
564
  }
@@ -582,7 +585,7 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
582
585
  var headRemoved = headRemovedFromNextRef.current;
583
586
  pendingScrollAfterNextRef.current = null;
584
587
  displayLogsLenBeforeLoadNextRef.current = null;
585
- ignoreBoundaryFetchRef.current = Date.now() + 500;
588
+ ignoreBoundaryFetchRef.current = Date.now() + IGNORE_BOUNDARY_FETCH_MS_AFTER_SCROLL;
586
589
  var comp = applyBoundaryScrollCompensation(v, anchorRowNext, displayLogs, {
587
590
  sameLength: _sameLength && headRemoved > 0,
588
591
  sameLengthPixelDeltaCount: headRemoved,
@@ -740,7 +743,7 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
740
743
  if (groupActionRef.current) return;
741
744
  if (collapseAirdropActiveRef.current) return;
742
745
  if (userStoppedFollowingRef.current) return;
743
- ignoreBoundaryFetchRef.current = Date.now() + 500;
746
+ ignoreBoundaryFetchRef.current = Date.now() + IGNORE_BOUNDARY_FETCH_MS_AFTER_SCROLL;
744
747
  (_virtuosoRef$current4 = virtuosoRef.current) === null || _virtuosoRef$current4 === void 0 || _virtuosoRef$current4.scrollToIndex({
745
748
  index: 'LAST',
746
749
  align: 'end',
@@ -758,7 +761,7 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
758
761
  // ===================================================================
759
762
  var scheduleScrollToDisplayIndex = useCallback(function (displayIndex) {
760
763
  var align = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'center';
761
- ignoreBoundaryFetchRef.current = Date.now() + 500;
764
+ ignoreBoundaryFetchRef.current = Date.now() + IGNORE_BOUNDARY_FETCH_MS_AFTER_SCROLL;
762
765
  requestAnimationFrame(function () {
763
766
  var v = virtuosoRef.current;
764
767
  if (!v || displayLogsRef.current.length === 0) return;
@@ -916,7 +919,7 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
916
919
  if (newIndex !== -1) {
917
920
  var _virtuosoRef$current5;
918
921
  // 勿用更短的窗口覆盖分组操作已设置的较长忽略期
919
- ignoreBoundaryFetchRef.current = Math.max(ignoreBoundaryFetchRef.current, Date.now() + 800);
922
+ ignoreBoundaryFetchRef.current = Math.max(ignoreBoundaryFetchRef.current, Date.now() + IGNORE_BOUNDARY_FETCH_MS_FIRST_SCREEN);
920
923
  (_virtuosoRef$current5 = virtuosoRef.current) === null || _virtuosoRef$current5 === void 0 || _virtuosoRef$current5.scrollToIndex({
921
924
  index: newIndex,
922
925
  align: 'start'
@@ -965,14 +968,20 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
965
968
  });
966
969
  if (group) {
967
970
  if (airdropExpandInFlightRef.current.has(name)) return;
968
- suppressFollowForGroupAction();
969
- if (group.status === 'running') {
970
- // --- Running 分组:展开后跳到最新日志并恢复跟随 ---
971
+
972
+ /**
973
+ * 运行中、失败的分组从收起展开:始终 initLoad(倒序最后一页 = 当前最新日志窗口),
974
+ * 再展开并滚到底,避免仍停留在历史缓冲而看不到尾部输出。
975
+ * 此处不置 userStoppedFollowing / isUserBrowsingHistory,以便置底后继续 followOutput。
976
+ */
977
+ if (group.status === 'running' || group.status === 'failure') {
978
+ collapseAirdropActiveRef.current = false;
979
+ suppressFollowForGroupAction();
971
980
  airdropExpandInFlightRef.current.add(name);
972
981
  setLoadingGroupNames(function (prev) {
973
982
  return prev.includes(name) ? prev : [].concat(_toConsumableArray(prev), [name]);
974
983
  });
975
- var runExpandToLatest = /*#__PURE__*/function () {
984
+ var runRunningExpandToTail = /*#__PURE__*/function () {
976
985
  var _ref9 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5() {
977
986
  return _regeneratorRuntime().wrap(function _callee5$(_context5) {
978
987
  while (1) switch (_context5.prev = _context5.next) {
@@ -986,11 +995,8 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
986
995
  silent: true
987
996
  });
988
997
  case 5:
998
+ ignoreBoundaryFetchRef.current = Math.max(ignoreBoundaryFetchRef.current, Date.now() + IGNORE_BOUNDARY_FETCH_MS_FIRST_SCREEN);
989
999
  groupManager.toggleGroup(name);
990
- userStoppedFollowingRef.current = false;
991
- collapseAirdropActiveRef.current = false;
992
- logFetcherResult.setIsUserBrowsingHistory(false);
993
- ignoreBoundaryFetchRef.current = Date.now() + 500;
994
1000
  requestAnimationFrame(function () {
995
1001
  var _virtuosoRef$current6;
996
1002
  (_virtuosoRef$current6 = virtuosoRef.current) === null || _virtuosoRef$current6 === void 0 || _virtuosoRef$current6.scrollToIndex({
@@ -998,102 +1004,108 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
998
1004
  align: 'end',
999
1005
  behavior: 'auto'
1000
1006
  });
1007
+ // 未走「停跟」分支时仍可能带着此前的查阅历史态,置底后显式恢复跟随
1008
+ userStoppedFollowingRef.current = false;
1009
+ logFetcherResult.setIsUserBrowsingHistory(false);
1001
1010
  });
1002
- case 11:
1003
- _context5.prev = 11;
1011
+ _context5.next = 13;
1012
+ break;
1013
+ case 10:
1014
+ _context5.prev = 10;
1015
+ _context5.t0 = _context5["catch"](0);
1016
+ console.error('[PipelineLogViewer] running group expand to tail failed:', _context5.t0);
1017
+ case 13:
1018
+ _context5.prev = 13;
1004
1019
  airdropExpandInFlightRef.current.delete(name);
1005
1020
  setLoadingGroupNames(function (prev) {
1006
1021
  return prev.filter(function (n) {
1007
1022
  return n !== name;
1008
1023
  });
1009
1024
  });
1010
- return _context5.finish(11);
1011
- case 15:
1025
+ return _context5.finish(13);
1026
+ case 17:
1012
1027
  case "end":
1013
1028
  return _context5.stop();
1014
1029
  }
1015
- }, _callee5, null, [[0,, 11, 15]]);
1030
+ }, _callee5, null, [[0, 10, 13, 17]]);
1016
1031
  }));
1017
- return function runExpandToLatest() {
1032
+ return function runRunningExpandToTail() {
1018
1033
  return _ref9.apply(this, arguments);
1019
1034
  };
1020
1035
  }();
1021
- runExpandToLatest();
1022
- } else {
1023
- var _group$end2;
1024
- // --- 非 running 分组:展开后跳到分组最后一行 ---
1025
- var groupEnd = (_group$end2 = group.end) !== null && _group$end2 !== void 0 ? _group$end2 : group.start;
1026
- var _logFetcherResult$cur3 = logFetcherResult.cursor,
1027
- bufStart = _logFetcherResult$cur3.currentStartRow,
1028
- bufEnd = _logFetcherResult$cur3.currentEndRow;
1029
- var groupEndInBuffer = bufStart <= groupEnd && groupEnd <= bufEnd;
1030
- userStoppedFollowingRef.current = true;
1031
- logFetcherResult.setIsUserBrowsingHistory(true);
1032
- if (!groupEndInBuffer) {
1033
- airdropExpandInFlightRef.current.add(name);
1034
- setLoadingGroupNames(function (prev) {
1035
- return prev.includes(name) ? prev : [].concat(_toConsumableArray(prev), [name]);
1036
- });
1037
- var runAirdropThenExpand = /*#__PURE__*/function () {
1038
- var _ref10 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6() {
1039
- var ok;
1040
- return _regeneratorRuntime().wrap(function _callee6$(_context6) {
1041
- while (1) switch (_context6.prev = _context6.next) {
1042
- case 0:
1043
- _context6.prev = 0;
1044
- _context6.next = 3;
1045
- return waitForFetchUnlock();
1046
- case 3:
1047
- _context6.next = 5;
1048
- return logFetcherResult.airdropLoad(groupEnd, {
1049
- window: 'center',
1050
- silent: true
1051
- });
1052
- case 5:
1053
- ok = _context6.sent;
1054
- if (ok) {
1055
- groupManager.toggleGroup(name);
1056
- pendingScrollAlignRef.current = 'center';
1057
- pendingScrollRowRef.current = groupEnd;
1058
- }
1059
- case 7:
1060
- _context6.prev = 7;
1061
- airdropExpandInFlightRef.current.delete(name);
1062
- setLoadingGroupNames(function (prev) {
1063
- return prev.filter(function (n) {
1064
- return n !== name;
1036
+ runRunningExpandToTail();
1037
+ return;
1038
+ }
1039
+ suppressFollowForGroupAction();
1040
+ userStoppedFollowingRef.current = true;
1041
+ logFetcherResult.setIsUserBrowsingHistory(true);
1042
+ var _logFetcherResult$cur3 = logFetcherResult.cursor,
1043
+ bufStart = _logFetcherResult$cur3.currentStartRow,
1044
+ bufEnd = _logFetcherResult$cur3.currentEndRow;
1045
+ // 当前内存窗口是否已包含 group.start(重复展开同一分组时不重复空降)
1046
+ var groupStartInBuffer = bufStart <= group.start && group.start <= bufEnd;
1047
+ if (!groupStartInBuffer) {
1048
+ airdropExpandInFlightRef.current.add(name);
1049
+ setLoadingGroupNames(function (prev) {
1050
+ return prev.includes(name) ? prev : [].concat(_toConsumableArray(prev), [name]);
1051
+ });
1052
+ var runAirdropThenExpand = /*#__PURE__*/function () {
1053
+ var _ref10 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6() {
1054
+ var ok;
1055
+ return _regeneratorRuntime().wrap(function _callee6$(_context6) {
1056
+ while (1) switch (_context6.prev = _context6.next) {
1057
+ case 0:
1058
+ _context6.prev = 0;
1059
+ _context6.next = 3;
1060
+ return logFetcherResult.airdropLoad(group.start, {
1061
+ window: 'fromStart',
1062
+ silent: true
1063
+ });
1064
+ case 3:
1065
+ ok = _context6.sent;
1066
+ if (!ok) {
1067
+ _context6.next = 7;
1068
+ break;
1069
+ }
1070
+ _context6.next = 7;
1071
+ return new Promise(function (resolve) {
1072
+ requestAnimationFrame(function () {
1073
+ requestAnimationFrame(function () {
1074
+ maintainScrollPosition(function () {
1075
+ groupManager.toggleGroup(name);
1076
+ });
1077
+ resolve();
1065
1078
  });
1066
1079
  });
1067
- return _context6.finish(7);
1068
- case 11:
1069
- case "end":
1070
- return _context6.stop();
1071
- }
1072
- }, _callee6, null, [[0,, 7, 11]]);
1073
- }));
1074
- return function runAirdropThenExpand() {
1075
- return _ref10.apply(this, arguments);
1076
- };
1077
- }();
1078
- runAirdropThenExpand();
1079
- } else {
1080
+ });
1081
+ case 7:
1082
+ _context6.prev = 7;
1083
+ airdropExpandInFlightRef.current.delete(name);
1084
+ setLoadingGroupNames(function (prev) {
1085
+ return prev.filter(function (n) {
1086
+ return n !== name;
1087
+ });
1088
+ });
1089
+ return _context6.finish(7);
1090
+ case 11:
1091
+ case "end":
1092
+ return _context6.stop();
1093
+ }
1094
+ }, _callee6, null, [[0,, 7, 11]]);
1095
+ }));
1096
+ return function runAirdropThenExpand() {
1097
+ return _ref10.apply(this, arguments);
1098
+ };
1099
+ }();
1100
+ runAirdropThenExpand().catch(function (err) {
1101
+ console.error('[PipelineLogViewer] airdrop expand failed:', err);
1102
+ });
1103
+ } else {
1104
+ // 缓冲内展开:用当前视口锚点重定位,避免原先 scrollToIndex(group.start) 把起点硬拉到顶,
1105
+ // running 等大分组展开时整屏上跳;与折叠分支一致走 maintainScrollPosition。
1106
+ maintainScrollPosition(function () {
1080
1107
  groupManager.toggleGroup(name);
1081
- ignoreBoundaryFetchRef.current = Date.now() + 500;
1082
- requestAnimationFrame(function () {
1083
- var currentLogs = displayLogsRef.current;
1084
- var displayIndex = currentLogs.findIndex(function (l) {
1085
- return l.absoluteRow === groupEnd;
1086
- });
1087
- if (displayIndex >= 0) {
1088
- var _virtuosoRef$current7;
1089
- (_virtuosoRef$current7 = virtuosoRef.current) === null || _virtuosoRef$current7 === void 0 || _virtuosoRef$current7.scrollToIndex({
1090
- index: displayIndex,
1091
- align: 'center',
1092
- behavior: 'auto'
1093
- });
1094
- }
1095
- });
1096
- }
1108
+ });
1097
1109
  }
1098
1110
  return;
1099
1111
  }
@@ -1143,27 +1155,7 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
1143
1155
  return map;
1144
1156
  }, [groups]);
1145
1157
 
1146
- /** START/END 控制行绝对行号集合(用于行号体系扣减,不参与分组边界判断) */
1147
- var controlMarkerRows = useMemo(function () {
1148
- var set = new Set();
1149
- var _iterator2 = _createForOfIteratorHelper(displayLogs),
1150
- _step2;
1151
- try {
1152
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1153
- var line = _step2.value;
1154
- if (isPipelineEndMarkerText(line.text) || isPipelineStartMarkerText(line.text)) {
1155
- set.add(line.absoluteRow);
1156
- }
1157
- }
1158
- } catch (err) {
1159
- _iterator2.e(err);
1160
- } finally {
1161
- _iterator2.f();
1162
- }
1163
- return set;
1164
- }, [displayLogs]);
1165
-
1166
- /** 整条流水线日志起算绝对行号(用于全局连续行号) */
1158
+ /** 整条流水线日志起算绝对行号(早于该行的缓冲内容行号展示回退) */
1167
1159
  var pipelineMinAbsoluteRow = useMemo(function () {
1168
1160
  return groups.length > 0 ? Math.min.apply(Math, _toConsumableArray(groups.map(function (g) {
1169
1161
  return g.start;
@@ -1181,8 +1173,6 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
1181
1173
  handleToggleGroupRef.current = handleToggleGroup;
1182
1174
  var lineNumberWidthRef = useRef(lineNumberWidth);
1183
1175
  lineNumberWidthRef.current = lineNumberWidth;
1184
- var controlMarkerRowsRef = useRef(controlMarkerRows);
1185
- controlMarkerRowsRef.current = controlMarkerRows;
1186
1176
  var pipelineMinAbsoluteRowRef = useRef(pipelineMinAbsoluteRow);
1187
1177
  pipelineMinAbsoluteRowRef.current = pipelineMinAbsoluteRow;
1188
1178
 
@@ -1198,7 +1188,7 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
1198
1188
  return {};
1199
1189
  },
1200
1190
  // eslint-disable-next-line react-hooks/exhaustive-deps
1201
- [groupManager.collapsedGroups, logSearchResult.searchState, lineNumberWidth, currentStartRow, highlightOptions, groups, loadingGroupNames]);
1191
+ [groupManager.collapsedGroups, logSearchResult.searchState, lineNumberWidth, currentStartRow, highlightOptions, groups, loadingGroupNames, showLogTime]);
1202
1192
  var itemContent = useCallback(function (index) {
1203
1193
  var _groupsForHeader;
1204
1194
  var currentDisplayLogs = displayLogsRef.current;
@@ -1236,14 +1226,20 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
1236
1226
  var showLogRow = !line.isFoldedGroupStart && !line.isEmptyGroupStart;
1237
1227
  var isControlEndMarker = isPipelineEndMarkerText(line.text);
1238
1228
  var isControlStartMarker = isPipelineStartMarkerText(line.text);
1239
- /** 仅压扁 START/END 控制行;行号体系也仅基于控制行扣减 */
1229
+ /** 仅压扁 START/END 控制行;行号规则见 getPipelineGroupedLineNumberLabel */
1240
1230
  var collapseGroupEdgeLog = showLogRow && !line.isEmptyGroupStart && (isControlEndMarker || isControlStartMarker);
1241
- var lineNumberLabel = groups.length > 0 && showLogRow ? getGlobalVisibleLineNumberLabel(line.absoluteRow, controlMarkerRowsRef.current, pipelineMinAbsoluteRowRef.current) : undefined;
1231
+ var rowGroup = currentGroupManager.getGroupByRow(line.absoluteRow);
1232
+ var rowGroupIndex = rowGroup ? groups.findIndex(function (g) {
1233
+ return g.name === rowGroup.name;
1234
+ }) : -1;
1235
+ var isControlMarkerRow = showLogRow && !line.isEmptyGroupStart && (isControlEndMarker || isControlStartMarker);
1236
+ var lineNumberLabel = groups.length > 0 && showLogRow ? getPipelineGroupedLineNumberLabel(line.absoluteRow, rowGroup, rowGroupIndex, isControlMarkerRow, pipelineMinAbsoluteRowRef.current) : undefined;
1242
1237
  var logRow = /*#__PURE__*/React.createElement(LogRow, {
1243
1238
  absoluteRow: line.absoluteRow,
1244
1239
  lineNumberLabel: lineNumberLabel,
1245
1240
  text: line.text,
1246
1241
  logTime: line.logTime,
1242
+ showLogTime: showLogTime,
1247
1243
  isMatched: isMatched,
1248
1244
  isActiveMatch: isActiveMatch,
1249
1245
  lineNumberWidth: lineNumberWidthRef.current,
@@ -1291,7 +1287,7 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
1291
1287
  }))) : 0;
1292
1288
  bufStart = logFetcherResult.cursor.currentStartRow;
1293
1289
  needsTopWindow = bufStart > globalFirstRow;
1294
- ignoreBoundaryFetchRef.current = Date.now() + 500;
1290
+ ignoreBoundaryFetchRef.current = Date.now() + IGNORE_BOUNDARY_FETCH_MS_AFTER_SCROLL;
1295
1291
  if (!needsTopWindow) {
1296
1292
  _context7.next = 21;
1297
1293
  break;
@@ -1321,8 +1317,8 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
1321
1317
  return _context7.abrupt("return");
1322
1318
  case 21:
1323
1319
  requestAnimationFrame(function () {
1324
- var _virtuosoRef$current8;
1325
- (_virtuosoRef$current8 = virtuosoRef.current) === null || _virtuosoRef$current8 === void 0 || _virtuosoRef$current8.scrollToIndex({
1320
+ var _virtuosoRef$current7;
1321
+ (_virtuosoRef$current7 = virtuosoRef.current) === null || _virtuosoRef$current7 === void 0 || _virtuosoRef$current7.scrollToIndex({
1326
1322
  index: 0,
1327
1323
  align: 'start',
1328
1324
  behavior: 'auto'
@@ -1345,30 +1341,33 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
1345
1341
  return _regeneratorRuntime().wrap(function _callee8$(_context8) {
1346
1342
  while (1) switch (_context8.prev = _context8.next) {
1347
1343
  case 0:
1344
+ _context8.next = 2;
1345
+ return waitForFetchUnlock();
1346
+ case 2:
1348
1347
  groupManager.expandAll();
1349
1348
  userStoppedFollowingRef.current = false;
1350
1349
  collapseAirdropActiveRef.current = false;
1351
1350
  needsFetch = status !== 'running' && !logFetcherResult.boundaryLock.isLastPage || status === 'running' && logFetcherResult.isUserBrowsingHistory;
1352
1351
  if (!needsFetch) {
1353
- _context8.next = 8;
1352
+ _context8.next = 10;
1354
1353
  break;
1355
1354
  }
1356
- _context8.next = 7;
1355
+ _context8.next = 9;
1357
1356
  return logFetcherResult.initLoad();
1358
- case 7:
1357
+ case 9:
1359
1358
  logFetcherResult.updateBoundaryLock({
1360
1359
  isFirstPage: false
1361
1360
  });
1362
- case 8:
1363
- ignoreBoundaryFetchRef.current = Date.now() + 500;
1361
+ case 10:
1362
+ ignoreBoundaryFetchRef.current = Date.now() + IGNORE_BOUNDARY_FETCH_MS_AFTER_SCROLL;
1364
1363
  setTimeout(function () {
1365
- var _virtuosoRef$current9;
1366
- (_virtuosoRef$current9 = virtuosoRef.current) === null || _virtuosoRef$current9 === void 0 || _virtuosoRef$current9.scrollToIndex({
1364
+ var _virtuosoRef$current8;
1365
+ (_virtuosoRef$current8 = virtuosoRef.current) === null || _virtuosoRef$current8 === void 0 || _virtuosoRef$current8.scrollToIndex({
1367
1366
  index: 'LAST',
1368
1367
  align: 'end'
1369
1368
  });
1370
1369
  }, 50);
1371
- case 10:
1370
+ case 12:
1372
1371
  case "end":
1373
1372
  return _context8.stop();
1374
1373
  }
@@ -1425,7 +1424,7 @@ var PipelineLogViewer = /*#__PURE__*/forwardRef(function (_ref2, ref) {
1425
1424
  group: stickyHeader.stickyGroup,
1426
1425
  collapsed: stickyHeader.stickyGroup ? groupManager.collapsedGroups.has(stickyHeader.stickyGroup.name) : false,
1427
1426
  loading: stickyHeader.stickyGroup != null && loadingGroupNames.includes(stickyHeader.stickyGroup.name),
1428
- onToggle: handleToggleGroup,
1427
+ onToggle: handleToggleGroupRef.current,
1429
1428
  groupStatusIcons: groupStatusIcons,
1430
1429
  serverOffsetTime: serverOffsetTime
1431
1430
  }), /*#__PURE__*/React.createElement(Virtuoso, {
@@ -17,6 +17,8 @@ interface LogRowProps {
17
17
  lineNumberWidth: number;
18
18
  /** 是否显示行号 */
19
19
  showLineNumber?: boolean;
20
+ /** 是否显示日志时间列(默认 true) */
21
+ showLogTime?: boolean;
20
22
  /** 关键字规则高亮;搜索命中时不会应用 */
21
23
  highlightOptions?: IHighlightOptions[];
22
24
  /** 当前搜索关键字(非空且本行命中时在 HTML 内包裹 mark,仅高亮关键字) */
@@ -1 +1 @@
1
- {"version":3,"file":"LogRow.d.ts","sourceRoot":"","sources":["../../../../src/PipelineLogViewer/components/LogRow.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAkB,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AA4BlD,UAAU,WAAW;IACnB,aAAa;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,kBAAkB;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa;IACb,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wBAAwB;IACxB,gBAAgB,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACvC,8CAA8C;IAC9C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;;AAiED,wBAAkC"}
1
+ {"version":3,"file":"LogRow.d.ts","sourceRoot":"","sources":["../../../../src/PipelineLogViewer/components/LogRow.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAkB,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AA4BlD,UAAU,WAAW;IACnB,aAAa;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,kBAAkB;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa;IACb,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,yBAAyB;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,wBAAwB;IACxB,gBAAgB,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACvC,8CAA8C;IAC9C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;;AAkED,wBAAkC"}
@@ -40,6 +40,8 @@ var LogRow = function LogRow(_ref) {
40
40
  lineNumberWidth = _ref.lineNumberWidth,
41
41
  _ref$showLineNumber = _ref.showLineNumber,
42
42
  showLineNumber = _ref$showLineNumber === void 0 ? true : _ref$showLineNumber,
43
+ _ref$showLogTime = _ref.showLogTime,
44
+ showLogTime = _ref$showLogTime === void 0 ? true : _ref$showLogTime,
43
45
  highlightOptions = _ref.highlightOptions,
44
46
  _ref$searchKeyword = _ref.searchKeyword,
45
47
  searchKeyword = _ref$searchKeyword === void 0 ? '' : _ref$searchKeyword;
@@ -69,7 +71,7 @@ var LogRow = function LogRow(_ref) {
69
71
  style: {
70
72
  minWidth: "".concat(lineNumberWidth, "px")
71
73
  }
72
- }, lineNumberLabel === null ? '' : lineNumberLabel !== null && lineNumberLabel !== void 0 ? lineNumberLabel : absoluteRow), logTime != null && logTime > 0 && /*#__PURE__*/React.createElement("span", {
74
+ }, lineNumberLabel === null ? '' : lineNumberLabel !== null && lineNumberLabel !== void 0 ? lineNumberLabel : absoluteRow), showLogTime && logTime != null && logTime > 0 && /*#__PURE__*/React.createElement("span", {
73
75
  className: "pipeline-log-row__log-time"
74
76
  }, formatLogTime(logTime)), /*#__PURE__*/React.createElement("span", {
75
77
  className: "pipeline-log-row__text",
@@ -9,7 +9,17 @@ export declare const DEFAULT_VIRTUOSO_ITEM_HEIGHT = 20;
9
9
  * 过小(如 10)时,必须把「缓冲区内第一屏」滚到几乎贴顶才触发,此时锚点往往是 bufferStart(如 7550),
10
10
  * 而不是用户刚看到的行(如 7571 在顶时 startIndex 可能已是 21,却满足不了 <=10)。
11
11
  */
12
- export declare const BOUNDARY_PREFETCH_INDEX_MARGIN = 400;
12
+ export declare const BOUNDARY_PREFETCH_INDEX_MARGIN = 200;
13
+ /**
14
+ * 首屏 init / 新日志源首包:屏蔽 rangeChanged 边界预取时长 (ms)。
15
+ * 略长于普通窗口,避免弹窗首帧、scrollToIndex(LAST) 前误判触顶触发 loadPrev。
16
+ */
17
+ export declare const IGNORE_BOUNDARY_FETCH_MS_FIRST_SCREEN = 800;
18
+ /**
19
+ * 程序化滚动、loadPrev/loadNext 补偿、scrollToTop/Bottom 等之后:
20
+ * 屏蔽 rangeChanged 边界预取时长 (ms)。
21
+ */
22
+ export declare const IGNORE_BOUNDARY_FETCH_MS_AFTER_SCROLL = 500;
13
23
  /** running 态轮询间隔 (默认值,单位 ms) */
14
24
  export declare const DEFAULT_POLL_INTERVAL = 1000;
15
25
  /** running→结束态:收尾 initLoad 之后追加 loadNext 的次数 */
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/PipelineLogViewer/constants.ts"],"names":[],"mappings":"AAKA,mBAAmB;AACnB,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC,qBAAqB;AACrB,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C,kGAAkG;AAClG,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAElD,gCAAgC;AAChC,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAE1C,gDAAgD;AAChD,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAE/C,iCAAiC;AACjC,eAAO,MAAM,mCAAmC,OAAO,CAAC;AAExD,yBAAyB;AACzB,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC,gBAAgB;AAChB,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AAEvD,oBAAoB;AACpB,eAAO,MAAM,wBAAwB,gBAAgB,CAAC;AAEtD,cAAc;AACd,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAE9C,cAAc;AACd,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAE9C,oBAAoB;AACpB,eAAO,MAAM,mBAAmB,YAAY,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/PipelineLogViewer/constants.ts"],"names":[],"mappings":"AAKA,mBAAmB;AACnB,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC,qBAAqB;AACrB,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C,kGAAkG;AAClG,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAElD;;;GAGG;AACH,eAAO,MAAM,qCAAqC,MAAM,CAAC;AAEzD;;;GAGG;AACH,eAAO,MAAM,qCAAqC,MAAM,CAAC;AAEzD,gCAAgC;AAChC,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAE1C,gDAAgD;AAChD,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAE/C,iCAAiC;AACjC,eAAO,MAAM,mCAAmC,OAAO,CAAC;AAExD,yBAAyB;AACzB,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC,gBAAgB;AAChB,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AAEvD,oBAAoB;AACpB,eAAO,MAAM,wBAAwB,gBAAgB,CAAC;AAEtD,cAAc;AACd,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAE9C,cAAc;AACd,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAE9C,oBAAoB;AACpB,eAAO,MAAM,mBAAmB,YAAY,CAAC"}
@@ -17,7 +17,19 @@ export var DEFAULT_VIRTUOSO_ITEM_HEIGHT = 20;
17
17
  * 过小(如 10)时,必须把「缓冲区内第一屏」滚到几乎贴顶才触发,此时锚点往往是 bufferStart(如 7550),
18
18
  * 而不是用户刚看到的行(如 7571 在顶时 startIndex 可能已是 21,却满足不了 <=10)。
19
19
  */
20
- export var BOUNDARY_PREFETCH_INDEX_MARGIN = 400;
20
+ export var BOUNDARY_PREFETCH_INDEX_MARGIN = 200;
21
+
22
+ /**
23
+ * 首屏 init / 新日志源首包:屏蔽 rangeChanged 边界预取时长 (ms)。
24
+ * 略长于普通窗口,避免弹窗首帧、scrollToIndex(LAST) 前误判触顶触发 loadPrev。
25
+ */
26
+ export var IGNORE_BOUNDARY_FETCH_MS_FIRST_SCREEN = 800;
27
+
28
+ /**
29
+ * 程序化滚动、loadPrev/loadNext 补偿、scrollToTop/Bottom 等之后:
30
+ * 屏蔽 rangeChanged 边界预取时长 (ms)。
31
+ */
32
+ export var IGNORE_BOUNDARY_FETCH_MS_AFTER_SCROLL = 500;
21
33
 
22
34
  /** running 态轮询间隔 (默认值,单位 ms) */
23
35
  export var DEFAULT_POLL_INTERVAL = 1000;
@@ -232,7 +232,7 @@ input.pipeline-log-search-bar__input {
232
232
 
233
233
  .pipeline-log-search-bar__dirty-hint,
234
234
  .pipeline-log-search-bar__nav-hint {
235
- margin-right: 4px;
235
+ margin: 0 4px;
236
236
  color: #959da5bf;
237
237
  font-size: 11px;
238
238
  line-height: 1.2;
@@ -335,7 +335,7 @@ input.pipeline-log-search-bar__input {
335
335
  }
336
336
 
337
337
  .pipeline-log-search-bar__result-count {
338
- margin-right: 4px;
338
+ margin: 0 4px;
339
339
  font-size: 12px;
340
340
  }
341
341
 
@@ -92,6 +92,10 @@ export interface PipelineLogViewerProps {
92
92
  highlightOptions?: IHighlightOptions[];
93
93
  /** 服务器当前时间 (ms) 与本地 Date.now() 的偏移时间差 */
94
94
  serverOffsetTime?: number;
95
+ /**
96
+ * 是否展示每行日志时间列;默认 true。
97
+ */
98
+ showLogTime?: boolean;
95
99
  }
96
100
  /** 日志游标状态 —— 标识内存中日志块的物理边界 */
97
101
  export interface LogCursor {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/PipelineLogViewer/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/PipelineLogViewer/types.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,13 @@
1
+ import type { GroupData } from '../types';
1
2
  /**
2
- * 全局连续行号(隐藏各分组首尾边界行后,从 1 递增)。
3
+ * 流水线分组场景下的左侧行号。
3
4
  *
4
- * 对非边界行 R:序号 = 1 + |{ r | pipelineMinRow ≤ r < R 且 r 不在 edgeRows }|
5
- * 即:absoluteRow - pipelineMinRow - (落在 [pipelineMinRow, absoluteRow) 内的边界行个数) + 1
5
+ * 规则(与产品约定一致):
6
+ * - 每个分组在日志流中有 START / END 两行控制标识,各占一个绝对行号。
7
+ * - 第一个分组(groups[0]):非控制行展示 **绝对行号** `absoluteRow`。
8
+ * - 第 n 个分组(n = groups 下标,且 n ≥ 1):非控制行展示 `absoluteRow - (2n)`, 不是 2n -1 是因为第一个分组第1行才是有效日志,把整体行号往前推了1。
9
+ * - START/END 控制行:左侧不展示数字(返回 null)。
6
10
  *
7
- * pipelineMinRow 取各分组 start 的最小值,作为整条流水日志的起算行。
8
- *
9
- * @returns null 表示当前行为分组首尾占位行,左侧不展示数字;undefined 表示早于流水线起点,沿用绝对行号
11
+ * @returns null = 控制行不占位数字;undefined = 无法归类或早于 pipeline 起点,由 LogRow 回退为 absoluteRow
10
12
  */
11
- export declare function getGlobalVisibleLineNumberLabel(absoluteRow: number, edgeRows: Set<number>, pipelineMinRow: number): number | null | undefined;
13
+ export declare function getPipelineGroupedLineNumberLabel(absoluteRow: number, group: GroupData | undefined, groupIndex: number, isControlMarkerRow: boolean, pipelineMinRow: number): number | null | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"groupLineNumber.d.ts","sourceRoot":"","sources":["../../../../src/PipelineLogViewer/utils/groupLineNumber.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,wBAAgB,+BAA+B,CAC7C,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,EACrB,cAAc,EAAE,MAAM,GACrB,MAAM,GAAG,IAAI,GAAG,SAAS,CAQ3B"}
1
+ {"version":3,"file":"groupLineNumber.d.ts","sourceRoot":"","sources":["../../../../src/PipelineLogViewer/utils/groupLineNumber.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C;;;;;;;;;;GAUG;AACH,wBAAgB,iCAAiC,CAC/C,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,SAAS,GAAG,SAAS,EAC5B,UAAU,EAAE,MAAM,EAClB,kBAAkB,EAAE,OAAO,EAC3B,cAAc,EAAE,MAAM,GACrB,MAAM,GAAG,IAAI,GAAG,SAAS,CAS3B"}
@@ -1,34 +1,22 @@
1
- function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
2
- function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
3
- function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
4
- /* eslint-disable no-plusplus */
5
1
  /* eslint-disable import/prefer-default-export */
6
- /* eslint-disable no-restricted-syntax */
2
+
7
3
  /**
8
- * 全局连续行号(隐藏各分组首尾边界行后,从 1 递增)。
4
+ * 流水线分组场景下的左侧行号。
9
5
  *
10
- * 对非边界行 R:序号 = 1 + |{ r | pipelineMinRow ≤ r < R 且 r 不在 edgeRows }|
11
- * 即:absoluteRow - pipelineMinRow - (落在 [pipelineMinRow, absoluteRow) 内的边界行个数) + 1
6
+ * 规则(与产品约定一致):
7
+ * - 每个分组在日志流中有 START / END 两行控制标识,各占一个绝对行号。
8
+ * - 第一个分组(groups[0]):非控制行展示 **绝对行号** `absoluteRow`。
9
+ * - 第 n 个分组(n = groups 下标,且 n ≥ 1):非控制行展示 `absoluteRow - (2n)`, 不是 2n -1 是因为第一个分组第1行才是有效日志,把整体行号往前推了1。
10
+ * - START/END 控制行:左侧不展示数字(返回 null)。
12
11
  *
13
- * pipelineMinRow 取各分组 start 的最小值,作为整条流水日志的起算行。
14
- *
15
- * @returns null 表示当前行为分组首尾占位行,左侧不展示数字;undefined 表示早于流水线起点,沿用绝对行号
12
+ * @returns null = 控制行不占位数字;undefined = 无法归类或早于 pipeline 起点,由 LogRow 回退为 absoluteRow
16
13
  */
17
- export function getGlobalVisibleLineNumberLabel(absoluteRow, edgeRows, pipelineMinRow) {
18
- if (edgeRows.has(absoluteRow)) return null;
14
+ export function getPipelineGroupedLineNumberLabel(absoluteRow, group, groupIndex, isControlMarkerRow, pipelineMinRow) {
15
+ if (isControlMarkerRow) return null;
19
16
  if (absoluteRow < pipelineMinRow) return undefined;
20
- var edgeBefore = 0;
21
- var _iterator = _createForOfIteratorHelper(edgeRows),
22
- _step;
23
- try {
24
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
25
- var e = _step.value;
26
- if (e >= pipelineMinRow && e < absoluteRow) edgeBefore++;
27
- }
28
- } catch (err) {
29
- _iterator.e(err);
30
- } finally {
31
- _iterator.f();
17
+ if (!group || groupIndex < 0) return undefined;
18
+ if (groupIndex === 0) {
19
+ return absoluteRow;
32
20
  }
33
- return absoluteRow - pipelineMinRow - edgeBefore + 1;
21
+ return absoluteRow - 2 * groupIndex;
34
22
  }
@@ -17,6 +17,8 @@ interface LogRowProps {
17
17
  lineNumberWidth: number;
18
18
  /** 是否显示行号 */
19
19
  showLineNumber?: boolean;
20
+ /** 是否显示日志时间列(默认 true) */
21
+ showLogTime?: boolean;
20
22
  /** 关键字规则高亮;搜索命中时不会应用 */
21
23
  highlightOptions?: IHighlightOptions[];
22
24
  /** 当前搜索关键字(非空且本行命中时在 HTML 内包裹 mark,仅高亮关键字) */
@@ -9,7 +9,17 @@ export declare const DEFAULT_VIRTUOSO_ITEM_HEIGHT = 20;
9
9
  * 过小(如 10)时,必须把「缓冲区内第一屏」滚到几乎贴顶才触发,此时锚点往往是 bufferStart(如 7550),
10
10
  * 而不是用户刚看到的行(如 7571 在顶时 startIndex 可能已是 21,却满足不了 <=10)。
11
11
  */
12
- export declare const BOUNDARY_PREFETCH_INDEX_MARGIN = 400;
12
+ export declare const BOUNDARY_PREFETCH_INDEX_MARGIN = 200;
13
+ /**
14
+ * 首屏 init / 新日志源首包:屏蔽 rangeChanged 边界预取时长 (ms)。
15
+ * 略长于普通窗口,避免弹窗首帧、scrollToIndex(LAST) 前误判触顶触发 loadPrev。
16
+ */
17
+ export declare const IGNORE_BOUNDARY_FETCH_MS_FIRST_SCREEN = 800;
18
+ /**
19
+ * 程序化滚动、loadPrev/loadNext 补偿、scrollToTop/Bottom 等之后:
20
+ * 屏蔽 rangeChanged 边界预取时长 (ms)。
21
+ */
22
+ export declare const IGNORE_BOUNDARY_FETCH_MS_AFTER_SCROLL = 500;
13
23
  /** running 态轮询间隔 (默认值,单位 ms) */
14
24
  export declare const DEFAULT_POLL_INTERVAL = 1000;
15
25
  /** running→结束态:收尾 initLoad 之后追加 loadNext 的次数 */
@@ -92,6 +92,10 @@ export interface PipelineLogViewerProps {
92
92
  highlightOptions?: IHighlightOptions[];
93
93
  /** 服务器当前时间 (ms) 与本地 Date.now() 的偏移时间差 */
94
94
  serverOffsetTime?: number;
95
+ /**
96
+ * 是否展示每行日志时间列;默认 true。
97
+ */
98
+ showLogTime?: boolean;
95
99
  }
96
100
  /** 日志游标状态 —— 标识内存中日志块的物理边界 */
97
101
  export interface LogCursor {
@@ -1,11 +1,13 @@
1
+ import type { GroupData } from '../types';
1
2
  /**
2
- * 全局连续行号(隐藏各分组首尾边界行后,从 1 递增)。
3
+ * 流水线分组场景下的左侧行号。
3
4
  *
4
- * 对非边界行 R:序号 = 1 + |{ r | pipelineMinRow ≤ r < R 且 r 不在 edgeRows }|
5
- * 即:absoluteRow - pipelineMinRow - (落在 [pipelineMinRow, absoluteRow) 内的边界行个数) + 1
5
+ * 规则(与产品约定一致):
6
+ * - 每个分组在日志流中有 START / END 两行控制标识,各占一个绝对行号。
7
+ * - 第一个分组(groups[0]):非控制行展示 **绝对行号** `absoluteRow`。
8
+ * - 第 n 个分组(n = groups 下标,且 n ≥ 1):非控制行展示 `absoluteRow - (2n)`, 不是 2n -1 是因为第一个分组第1行才是有效日志,把整体行号往前推了1。
9
+ * - START/END 控制行:左侧不展示数字(返回 null)。
6
10
  *
7
- * pipelineMinRow 取各分组 start 的最小值,作为整条流水日志的起算行。
8
- *
9
- * @returns null 表示当前行为分组首尾占位行,左侧不展示数字;undefined 表示早于流水线起点,沿用绝对行号
11
+ * @returns null = 控制行不占位数字;undefined = 无法归类或早于 pipeline 起点,由 LogRow 回退为 absoluteRow
10
12
  */
11
- export declare function getGlobalVisibleLineNumberLabel(absoluteRow: number, edgeRows: Set<number>, pipelineMinRow: number): number | null | undefined;
13
+ export declare function getPipelineGroupedLineNumberLabel(absoluteRow: number, group: GroupData | undefined, groupIndex: number, isControlMarkerRow: boolean, pipelineMinRow: number): number | null | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-terminal-viewer-cicd",
3
- "version": "3.0.0-beta.43",
3
+ "version": "3.0.0-beta.44",
4
4
  "author": "https://gitee.com/gitee-frontend",
5
5
  "license": "MIT",
6
6
  "keywords": [