• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SAP / ui5-webcomponents-react / 11592854659

30 Oct 2024 12:08PM CUT coverage: 87.151% (-0.06%) from 87.214%
11592854659

Pull #6572

github

web-flow
Merge 1b3e38471 into 1e8cbf0a1
Pull Request #6572: docs: fix import copying

2890 of 3852 branches covered (75.03%)

5053 of 5798 relevant lines covered (87.15%)

98046.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.49
/packages/main/src/components/AnalyticalTable/TableBody/VirtualTableBody.tsx
1
import type { Virtualizer } from '@tanstack/react-virtual';
2
import { clsx } from 'clsx';
3
import type { MutableRefObject } from 'react';
4
import { useEffect, useMemo, useRef } from 'react';
5
import { AnalyticalTableSubComponentsBehavior } from '../../../enums/index.js';
6
import type {
7
  AnalyticalTablePropTypes,
8
  DivWithCustomScrollProp,
9
  ScrollToRefType,
10
  TableInstance,
11
  TriggerScrollState
12
} from '../types/index.js';
13
import { getSubRowsByString } from '../util/index.js';
14
import { EmptyRow } from './EmptyRow.js';
15
import { RowSubComponent as SubComponent } from './RowSubComponent.js';
16

17
interface VirtualTableBodyProps {
18
  classes: Record<string, string>;
19
  prepareRow: (row: unknown) => void;
20
  rows: TableInstance['rows'];
21
  isTreeTable?: AnalyticalTablePropTypes['isTreeTable'];
22
  internalRowHeight: number;
23
  alternateRowColor?: AnalyticalTablePropTypes['alternateRowColor'];
24
  visibleColumns: Record<string, unknown>[];
25
  renderRowSubComponent: AnalyticalTablePropTypes['renderRowSubComponent'];
26
  popInRowHeight: number;
27
  isRtl: boolean;
28
  markNavigatedRow?: AnalyticalTablePropTypes['markNavigatedRow'];
29
  alwaysShowSubComponent: boolean;
30
  dispatch?: (e: { type: string; payload?: Record<string, unknown> }) => void;
31
  subComponentsHeight?: Record<string, { rowId: string; subComponentHeight?: number }>;
32
  columnVirtualizer: Virtualizer<DivWithCustomScrollProp, Element>;
33
  manualGroupBy?: boolean;
34
  subRowsKey: string;
35
  scrollContainerRef?: MutableRefObject<HTMLDivElement>;
36
  subComponentsBehavior: AnalyticalTablePropTypes['subComponentsBehavior'];
37
  triggerScroll?: TriggerScrollState;
38
  scrollToRef: MutableRefObject<ScrollToRefType>;
39
  rowVirtualizer: Virtualizer<DivWithCustomScrollProp, HTMLElement>;
40
}
41

42
export const VirtualTableBody = (props: VirtualTableBodyProps) => {
417✔
43
  const {
44
    alternateRowColor,
45
    classes,
46
    prepareRow,
47
    rows,
48
    scrollToRef,
49
    isTreeTable,
50
    internalRowHeight,
51
    visibleColumns,
52
    renderRowSubComponent,
53
    popInRowHeight,
54
    markNavigatedRow,
55
    isRtl,
56
    alwaysShowSubComponent,
57
    dispatch,
58
    subComponentsHeight,
59
    columnVirtualizer,
60
    manualGroupBy,
61
    subRowsKey,
62
    scrollContainerRef,
63
    subComponentsBehavior,
64
    triggerScroll,
65
    rowVirtualizer
66
  } = props;
26,301✔
67

68
  const rowHeight = popInRowHeight !== internalRowHeight ? popInRowHeight : internalRowHeight;
26,301✔
69
  const lastNonEmptyRow = useRef(null);
26,301✔
70

71
  scrollToRef.current = {
26,301✔
72
    ...scrollToRef.current,
73
    scrollToOffset: rowVirtualizer.scrollToOffset,
74
    scrollToIndex: rowVirtualizer.scrollToIndex
75
  };
76

77
  useEffect(() => {
26,301✔
78
    if (triggerScroll && triggerScroll.direction === 'vertical') {
2,926✔
79
      if (triggerScroll.type === 'offset') {
12✔
80
        rowVirtualizer.scrollToOffset(...triggerScroll.args);
6✔
81
      } else {
82
        rowVirtualizer.scrollToIndex(...triggerScroll.args);
6✔
83
      }
84
    }
85
  }, [triggerScroll]);
86

87
  const popInColumn = useMemo(
26,301✔
88
    () =>
89
      visibleColumns.filter(
4,483✔
90
        (item) =>
91
          item.id !== '__ui5wcr__internal_highlight_column' &&
22,337✔
92
          item.id !== '__ui5wcr__internal_selection_column' &&
93
          item.id !== '__ui5wcr__internal_navigation_column'
94
      )[0],
95
    [visibleColumns]
96
  );
97
  return (
26,301✔
98
    <div
99
      ref={scrollContainerRef}
100
      data-component-name="AnalyticalTableBodyScrollableContainer"
101
      style={{
102
        position: 'relative',
103
        height: `${rowVirtualizer.getTotalSize()}px`,
104
        width: `${columnVirtualizer.getTotalSize()}px`
105
      }}
106
    >
107
      {rowVirtualizer.getVirtualItems().map((virtualRow, visibleRowIndex) => {
108
        const row = rows[virtualRow.index];
282,517✔
109
        const rowIndexWithHeader = virtualRow.index + 1;
282,517✔
110
        if (!row || row.groupByVal === 'undefined') {
282,517✔
111
          const alternate = alternateRowColor && virtualRow.index % 2 !== 0;
39,919✔
112
          if (!lastNonEmptyRow.current?.cells) {
39,919!
113
            return (
×
114
              <EmptyRow
115
                key={`empty_row_${virtualRow.index}`}
116
                virtualRow={virtualRow}
117
                className={clsx(classes.tr, alternate && classes.alternateRowColor)}
×
118
              />
119
            );
120
          }
121
          const cells = lastNonEmptyRow.current.cells;
39,919✔
122
          return (
39,919✔
123
            <EmptyRow
124
              key={`empty_row_${virtualRow.index}`}
125
              virtualRow={virtualRow}
126
              className={clsx(classes.tr, alternate && classes.alternateRowColor)}
40,069✔
127
            >
128
              {columnVirtualizer.getVirtualItems().map((item) => {
129
                const cell = cells[item.index];
169,797✔
130
                const cellProps = cell.getCellProps();
169,797✔
131
                const {
132
                  'aria-colindex': _0,
133
                  'aria-selected': _1,
134
                  'aria-label': _2,
135
                  tabIndex: _3,
136
                  ...emptyRowCellProps
137
                } = cellProps;
169,797✔
138
                return (
169,797✔
139
                  <div
140
                    {...emptyRowCellProps}
141
                    key={`${visibleRowIndex}-${emptyRowCellProps.key}`}
142
                    data-empty-row-cell="true"
143
                    tabIndex={-1}
144
                    aria-hidden
145
                    style={{ ...emptyRowCellProps.style, cursor: 'unset', width: item.size }}
146
                  />
147
                );
148
              })}
149
            </EmptyRow>
150
          );
151
        } else {
152
          lastNonEmptyRow.current = row;
242,598✔
153
        }
154
        prepareRow(row);
242,598✔
155
        const { key, ...rowProps } = row.getRowProps({
242,598✔
156
          'aria-rowindex': virtualRow.index + 1,
157
          'data-virtual-row-index': virtualRow.index
158
        });
159
        const isNavigatedCell = typeof markNavigatedRow === 'function' ? markNavigatedRow(row) : false;
242,598✔
160
        const RowSubComponent = typeof renderRowSubComponent === 'function' ? renderRowSubComponent(row) : undefined;
242,598✔
161

162
        if (
242,598✔
163
          (!RowSubComponent ||
164
            (subComponentsBehavior === AnalyticalTableSubComponentsBehavior.IncludeHeightExpandable &&
165
              !row.isExpanded)) &&
166
          subComponentsHeight &&
167
          subComponentsHeight?.[virtualRow.index]?.subComponentHeight
168
        ) {
169
          dispatch({
40✔
170
            type: 'SUB_COMPONENTS_HEIGHT',
171
            payload: {
172
              ...subComponentsHeight,
173
              [virtualRow.index]: { subComponentHeight: 0, rowId: row.id }
174
            }
175
          });
176
        }
177
        let updatedHeight = rowHeight;
242,598✔
178
        if (
242,598✔
179
          renderRowSubComponent &&
271,871✔
180
          (rows[virtualRow.index]?.isExpanded || alwaysShowSubComponent) &&
181
          subComponentsHeight?.[virtualRow.index]?.rowId === rows[virtualRow.index]?.id
182
        ) {
183
          updatedHeight += subComponentsHeight?.[virtualRow.index]?.subComponentHeight ?? 0;
3,247!
184
        }
185

186
        const measureRef =
187
          isTreeTable && renderRowSubComponent && (row.isExpanded || alwaysShowSubComponent)
242,598✔
188
            ? (node) => {
189
                rowVirtualizer.measureElement(node);
1,347✔
190
              }
191
            : rowVirtualizer.measureElement;
192

193
        return (
242,598✔
194
          <div
195
            key={key}
196
            {...rowProps}
197
            ref={measureRef}
198
            style={{
199
              ...(rowProps.style ?? {}),
485,196✔
200
              transform: `translateY(${virtualRow.start}px)`,
201
              position: 'absolute',
202
              boxSizing: 'border-box',
203
              height: `${updatedHeight}px`
204
            }}
205
          >
206
            {RowSubComponent && (row.isExpanded || alwaysShowSubComponent) && (
268,580✔
207
              <SubComponent
208
                subComponentsHeight={subComponentsHeight}
209
                virtualRow={virtualRow}
210
                dispatch={dispatch}
211
                row={row}
212
                rowHeight={rowHeight}
213
                rows={rows}
214
                alwaysShowSubComponent={alwaysShowSubComponent}
215
                rowIndex={visibleRowIndex + 1}
216
              >
217
                {RowSubComponent}
218
              </SubComponent>
219
            )}
220
            {columnVirtualizer.getVirtualItems().map((virtualColumn, visibleColumnIndex) => {
221
              const cell = row.cells[virtualColumn.index];
1,445,435✔
222
              const directionStyles = isRtl
1,445,435✔
223
                ? {
224
                    transform: `translateX(-${virtualColumn.start}px)`,
225
                    insertInlineStart: 0
226
                  }
227
                : { transform: `translateX(${virtualColumn.start}px)`, insertInlineStart: 0 };
228
              if (!cell) {
1,445,435!
229
                return null;
×
230
              }
231
              const { key, ...cellProps } = cell.getCellProps();
1,445,435✔
232
              const allCellProps = {
1,445,435✔
233
                ...cellProps,
234
                ['data-visible-column-index']: visibleColumnIndex,
235
                ['data-column-index']: virtualColumn.index,
236
                ['data-visible-row-index']: visibleRowIndex + 1,
237
                ['data-row-index']: rowIndexWithHeader,
238
                style: {
239
                  ...cellProps.style,
240
                  position: 'absolute',
241
                  width: `${virtualColumn.size}px`,
242
                  top: 0,
243
                  height: `${rowHeight}px`,
244
                  ...directionStyles
245
                }
246
              };
247
              let contentToRender;
248
              if (
1,445,435✔
249
                cell.column.id === '__ui5wcr__internal_highlight_column' ||
4,234,957✔
250
                cell.column.id === '__ui5wcr__internal_selection_column' ||
251
                cell.column.id === '__ui5wcr__internal_navigation_column'
252
              ) {
253
                contentToRender = 'Cell';
100,405✔
254
              } else if (isTreeTable || (!alwaysShowSubComponent && RowSubComponent)) {
1,345,030✔
255
                contentToRender = 'Expandable';
259,082✔
256
              } else if (
1,085,948✔
257
                cell.isGrouped ||
2,168,121✔
258
                (manualGroupBy &&
259
                  cell.column.isGrouped &&
260
                  getSubRowsByString(subRowsKey, row.original) != null &&
261
                  cell.value !== undefined)
262
              ) {
263
                contentToRender = 'Grouped';
5,133✔
264
              } else if (cell.isAggregated) {
1,080,815✔
265
                contentToRender = 'Aggregated';
11,540✔
266
              } else if (cell.isPlaceholder) {
1,069,275✔
267
                contentToRender = 'RepeatedValue';
7,710✔
268
              } else {
269
                contentToRender = 'Cell';
1,061,565✔
270
              }
271

272
              return (
1,445,435✔
273
                <div
274
                  key={key}
275
                  {...allCellProps}
276
                  data-selection-cell={cell.column.id === '__ui5wcr__internal_selection_column'}
277
                >
278
                  {popInRowHeight !== internalRowHeight && popInColumn.id === cell.column.id
2,894,790✔
279
                    ? cell.render('PopIn', { contentToRender, internalRowHeight })
280
                    : cell.render(contentToRender, isNavigatedCell === true ? { isNavigatedCell } : {})}
1,443,171✔
281
                </div>
282
              );
283
            })}
284
          </div>
285
        );
286
      })}
287
    </div>
288
  );
289
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc