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

SAP / ui5-webcomponents-react / 11599014172

30 Oct 2024 06:01PM CUT coverage: 87.151% (-0.06%) from 87.214%
11599014172

Pull #6575

github

web-flow
Merge 41c4bac09 into 1e8cbf0a1
Pull Request #6575: Translation Delivery

2890 of 3852 branches covered (75.03%)

5053 of 5798 relevant lines covered (87.15%)

94248.16 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,336✔
67

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

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

77
  useEffect(() => {
26,336✔
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,336✔
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,336✔
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];
277,460✔
109
        const rowIndexWithHeader = virtualRow.index + 1;
277,460✔
110
        if (!row || row.groupByVal === 'undefined') {
277,460✔
111
          const alternate = alternateRowColor && virtualRow.index % 2 !== 0;
35,620✔
112
          if (!lastNonEmptyRow.current?.cells) {
35,620!
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;
35,620✔
122
          return (
35,620✔
123
            <EmptyRow
124
              key={`empty_row_${virtualRow.index}`}
125
              virtualRow={virtualRow}
126
              className={clsx(classes.tr, alternate && classes.alternateRowColor)}
35,770✔
127
            >
128
              {columnVirtualizer.getVirtualItems().map((item) => {
129
                const cell = cells[item.index];
152,818✔
130
                const cellProps = cell.getCellProps();
152,818✔
131
                const {
132
                  'aria-colindex': _0,
133
                  'aria-selected': _1,
134
                  'aria-label': _2,
135
                  tabIndex: _3,
136
                  ...emptyRowCellProps
137
                } = cellProps;
152,818✔
138
                return (
152,818✔
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;
241,840✔
153
        }
154
        prepareRow(row);
241,840✔
155
        const { key, ...rowProps } = row.getRowProps({
241,840✔
156
          'aria-rowindex': virtualRow.index + 1,
157
          'data-virtual-row-index': virtualRow.index
158
        });
159
        const isNavigatedCell = typeof markNavigatedRow === 'function' ? markNavigatedRow(row) : false;
241,840✔
160
        const RowSubComponent = typeof renderRowSubComponent === 'function' ? renderRowSubComponent(row) : undefined;
241,840✔
161

162
        if (
241,840✔
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;
241,840✔
178
        if (
241,840✔
179
          renderRowSubComponent &&
270,777✔
180
          (rows[virtualRow.index]?.isExpanded || alwaysShowSubComponent) &&
181
          subComponentsHeight?.[virtualRow.index]?.rowId === rows[virtualRow.index]?.id
182
        ) {
183
          updatedHeight += subComponentsHeight?.[virtualRow.index]?.subComponentHeight ?? 0;
3,219!
184
        }
185

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

193
        return (
241,840✔
194
          <div
195
            key={key}
196
            {...rowProps}
197
            ref={measureRef}
198
            style={{
199
              ...(rowProps.style ?? {}),
483,680✔
200
              transform: `translateY(${virtualRow.start}px)`,
201
              position: 'absolute',
202
              boxSizing: 'border-box',
203
              height: `${updatedHeight}px`
204
            }}
205
          >
206
            {RowSubComponent && (row.isExpanded || alwaysShowSubComponent) && (
267,726✔
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,348,058✔
222
              const directionStyles = isRtl
1,348,058✔
223
                ? {
224
                    transform: `translateX(-${virtualColumn.start}px)`,
225
                    insertInlineStart: 0
226
                  }
227
                : { transform: `translateX(${virtualColumn.start}px)`, insertInlineStart: 0 };
228
              if (!cell) {
1,348,058!
229
                return null;
×
230
              }
231
              const { key, ...cellProps } = cell.getCellProps();
1,348,058✔
232
              const allCellProps = {
1,348,058✔
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,348,058✔
249
                cell.column.id === '__ui5wcr__internal_highlight_column' ||
3,942,203✔
250
                cell.column.id === '__ui5wcr__internal_selection_column' ||
251
                cell.column.id === '__ui5wcr__internal_navigation_column'
252
              ) {
253
                contentToRender = 'Cell';
101,028✔
254
              } else if (isTreeTable || (!alwaysShowSubComponent && RowSubComponent)) {
1,247,030✔
255
                contentToRender = 'Expandable';
261,590✔
256
              } else if (
985,440✔
257
                cell.isGrouped ||
1,967,224✔
258
                (manualGroupBy &&
259
                  cell.column.isGrouped &&
260
                  getSubRowsByString(subRowsKey, row.original) != null &&
261
                  cell.value !== undefined)
262
              ) {
263
                contentToRender = 'Grouped';
5,014✔
264
              } else if (cell.isAggregated) {
980,426✔
265
                contentToRender = 'Aggregated';
11,183✔
266
              } else if (cell.isPlaceholder) {
969,243✔
267
                contentToRender = 'RepeatedValue';
7,338✔
268
              } else {
269
                contentToRender = 'Cell';
961,905✔
270
              }
271

272
              return (
1,348,058✔
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,700,036✔
279
                    ? cell.render('PopIn', { contentToRender, internalRowHeight })
280
                    : cell.render(contentToRender, isNavigatedCell === true ? { isNavigatedCell } : {})}
1,345,794✔
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