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

SAP / ui5-webcomponents-react / 14902210870

08 May 2025 08:32AM CUT coverage: 88.206% (-0.4%) from 88.625%
14902210870

Pull #7308

github

web-flow
Merge 7ea0c9eb2 into 5b75245a7
Pull Request #7308: feat: update to UI5 Web Components 2.10.0

3016 of 3985 branches covered (75.68%)

1 of 1 new or added line in 1 file covered. (100.0%)

28 existing lines in 3 files now uncovered.

5295 of 6003 relevant lines covered (88.21%)

104231.16 hits per line

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

93.24
/packages/main/src/components/AnalyticalTable/defaults/Column/ColumnHeaderModal.tsx
1
import IconMode from '@ui5/webcomponents/dist/types/IconMode.js';
2
import ListItemType from '@ui5/webcomponents/dist/types/ListItemType.js';
3
import PopoverHorizontalAlign from '@ui5/webcomponents/dist/types/PopoverHorizontalAlign.js';
4
import PopoverPlacement from '@ui5/webcomponents/dist/types/PopoverPlacement.js';
5
import { getScopedVarName } from '@ui5/webcomponents-base/dist/CustomElementsScope.js';
6
import iconDecline from '@ui5/webcomponents-icons/dist/decline.js';
7
import iconFilter from '@ui5/webcomponents-icons/dist/filter.js';
8
import iconGroup from '@ui5/webcomponents-icons/dist/group-2.js';
9
import iconSortAscending from '@ui5/webcomponents-icons/dist/sort-ascending.js';
10
import iconSortDescending from '@ui5/webcomponents-icons/dist/sort-descending.js';
11
import { enrichEventWithDetails, useI18nBundle } from '@ui5/webcomponents-react-base';
12
import { useEffect, useId, useMemo, useRef } from 'react';
13
import { FlexBoxAlignItems } from '../../../../enums/FlexBoxAlignItems.js';
14
import { TextAlign } from '../../../../enums/TextAlign.js';
15
import {
16
  CLEAR_SORTING,
17
  FILTER,
18
  GROUP,
19
  SORT_ASCENDING,
20
  SORT_DESCENDING,
21
  UNGROUP
22
} from '../../../../i18n/i18n-defaults.js';
23
import { stopPropagation } from '../../../../internal/stopPropagation.js';
24
import { getUi5TagWithSuffix } from '../../../../internal/utils.js';
25
import { Icon } from '../../../../webComponents/Icon/index.js';
26
import { List } from '../../../../webComponents/List/index.js';
27
import { ListItemCustom } from '../../../../webComponents/ListItemCustom/index.js';
28
import { ListItemStandard } from '../../../../webComponents/ListItemStandard/index.js';
29
import type { PopoverDomRef, PopoverPropTypes } from '../../../../webComponents/Popover/index.js';
30
import { Popover } from '../../../../webComponents/Popover/index.js';
31
import { Text } from '../../../../webComponents/Text/index.js';
32
import { FlexBox } from '../../../FlexBox/index.js';
33
import type { TableInstanceWithPopoverProps } from '../../types/index.js';
34
import { RenderColumnTypes } from '../../types/index.js';
35

36
export const ColumnHeaderModal = (instance: TableInstanceWithPopoverProps) => {
444✔
37
  const { setOpen, openerRef } = instance.popoverProps;
6,832✔
38
  const { column, state, webComponentsReactProperties } = instance;
6,832✔
39
  const { isRtl, groupBy } = state;
6,832✔
40
  const { onGroup, onSort, classes: classNames } = webComponentsReactProperties;
6,832✔
41
  const uniqueId = useId();
6,832✔
42

43
  const showFilter = column.canFilter;
6,832✔
44
  const showGroup = column.canGroupBy;
6,832✔
45
  const showSort = column.canSort;
6,832✔
46

47
  const ref = useRef<PopoverDomRef>(null);
6,832✔
48
  const listRef = useRef(null);
6,832✔
49

50
  const i18nBundle = useI18nBundle('@ui5/webcomponents-react');
6,832✔
51

52
  const clearSortingText = i18nBundle.getText(CLEAR_SORTING);
6,832✔
53
  const sortAscendingText = i18nBundle.getText(SORT_ASCENDING);
6,832✔
54
  const sortDescendingText = i18nBundle.getText(SORT_DESCENDING);
6,832✔
55
  const groupText = i18nBundle.getText(GROUP);
6,832✔
56
  const ungroupText = i18nBundle.getText(UNGROUP);
6,832✔
57
  const filterText = i18nBundle.getText(FILTER);
6,832✔
58

59
  const filterStyles = useMemo(() => {
6,832✔
60
    if (showFilter) {
1,776✔
61
      return {
784✔
62
        iconDimensions: `var(${getScopedVarName('--_ui5_list_item_icon_size')})`,
63
        fontSize: `var(${getScopedVarName('--_ui5_list_item_title_size')})`
64
      };
65
    }
66
  }, [showFilter]);
67

68
  const handleSort = (e) => {
6,832✔
69
    const sortType = e.detail.item.getAttribute('data-sort');
554✔
70

71
    switch (sortType) {
554✔
72
      case 'asc':
73
        column.toggleSortBy(false, !!column.enableMultiSort);
231✔
74
        if (typeof onSort === 'function') {
231✔
75
          onSort(
53✔
76
            enrichEventWithDetails(e, {
77
              column,
78
              sortDirection: sortType
79
            })
80
          );
81
        }
82
        break;
231✔
83
      case 'desc':
84
        column.toggleSortBy(true, !!column.enableMultiSort);
84✔
85
        if (typeof onSort === 'function') {
84✔
86
          onSort(
53✔
87
            enrichEventWithDetails(e, {
88
              column,
89
              sortDirection: sortType
90
            })
91
          );
92
        }
93
        break;
84✔
94
      case 'clear':
95
        column.clearSortBy();
84✔
96
        if (typeof onSort === 'function') {
84✔
97
          onSort(
53✔
98
            enrichEventWithDetails(e, {
99
              column,
100
              sortDirection: sortType
101
            })
102
          );
103
        }
104
        break;
84✔
105
      case 'group': {
106
        const willGroup = !column.isGrouped;
155✔
107
        column.toggleGroupBy(willGroup);
155✔
108
        let groupedColumns;
109
        if (willGroup) {
155✔
110
          groupedColumns = [...groupBy, column.id];
93✔
111
        } else {
112
          groupedColumns = groupBy.filter((group) => group !== column.id);
106✔
113
        }
114
        if (typeof onGroup === 'function') {
155✔
115
          onGroup(
14✔
116
            enrichEventWithDetails(e, {
117
              column,
118
              groupedColumns,
119
              isGrouped: willGroup
120
            })
121
          );
122
        }
123
        break;
155✔
124
      }
125
    }
126
    setOpen(false);
554✔
127
  };
128

129
  const isSortedAscending = column.isSorted && column.isSortedDesc === false;
6,832✔
130
  const isSortedDescending = column.isSorted && column.isSortedDesc === true;
6,832✔
131

132
  const onAfterClose: PopoverPropTypes['onClose'] = (e) => {
6,832✔
133
    stopPropagation(e);
886✔
134
    setOpen(false);
886✔
135
  };
136

137
  const onAfterOpen = () => {
6,832✔
138
    listRef.current?.children?.[0]?.focus();
870✔
139
  };
140

141
  const horizontalAlign = (() => {
6,832✔
142
    switch (column.hAlign) {
6,832!
143
      case TextAlign.Begin:
UNCOV
144
        return PopoverHorizontalAlign.Start;
×
145
      case TextAlign.End:
UNCOV
146
        return PopoverHorizontalAlign.End;
×
147
      case TextAlign.Left:
UNCOV
148
        return isRtl ? PopoverHorizontalAlign.End : PopoverHorizontalAlign.Start;
×
149
      case TextAlign.Right:
UNCOV
150
        return isRtl ? PopoverHorizontalAlign.Start : PopoverHorizontalAlign.End;
×
151
      case TextAlign.Center:
UNCOV
152
        return PopoverHorizontalAlign.Center;
×
153
      default:
154
        return PopoverHorizontalAlign.Start;
6,832✔
155
    }
156
  })();
157

158
  const handleCustomLiKeyDown = (e) => {
6,832✔
159
    if (e.key === 'Enter') {
220✔
160
      setOpen(false);
220✔
161
    }
162
  };
163

164
  const handleListKeyDown = (e) => {
6,832✔
165
    if (e.key !== 'Escape') {
220✔
166
      stopPropagation(e);
220✔
167
    }
168
  };
169

170
  useEffect(() => {
6,832✔
171
    if (ref.current && openerRef.current) {
1,776✔
172
      void customElements.whenDefined(getUi5TagWithSuffix('ui5-popover')).then(() => {
1,776✔
173
        ref.current.opener = openerRef.current;
1,776✔
174
        ref.current.open = true;
1,776✔
175
      });
176
    }
177
  }, []);
178

179
  return (
6,832✔
180
    <Popover
181
      hideArrow
182
      horizontalAlign={horizontalAlign}
183
      placement={PopoverPlacement.Bottom}
184
      ref={ref}
185
      className={classNames.popover}
186
      onClick={stopPropagation}
187
      onClose={onAfterClose}
188
      onOpen={onAfterOpen}
189
      data-component-name="ATHeaderPopover"
190
    >
191
      <List
192
        onItemClick={handleSort}
193
        ref={listRef}
194
        onKeyDown={handleListKeyDown}
195
        data-component-name="ATHeaderPopoverList"
196
      >
197
        {isSortedAscending && (
6,974✔
198
          <ListItemStandard type={ListItemType.Active} icon={iconDecline} data-sort="clear">
199
            {clearSortingText}
200
          </ListItemStandard>
×
201
        )}
202
        {showSort && !isSortedAscending && (
10,926✔
203
          <ListItemStandard type={ListItemType.Active} icon={iconSortAscending} data-sort="asc">
204
            {sortAscendingText}
205
          </ListItemStandard>
206
        )}
207
        {showSort && !isSortedDescending && (
10,718✔
208
          <ListItemStandard type={ListItemType.Active} icon={iconSortDescending} data-sort="desc">
×
209
            {sortDescendingText}
210
          </ListItemStandard>
211
        )}
212
        {isSortedDescending && (
7,182✔
213
          <ListItemStandard type={ListItemType.Active} icon={iconDecline} data-sort="clear">
214
            {clearSortingText}
215
          </ListItemStandard>
216
        )}
×
217
        {showFilter && (
11,626✔
218
          <ListItemCustom type={ListItemType.Inactive} onKeyDown={handleCustomLiKeyDown} accessibleName={filterText}>
219
            <FlexBox alignItems={FlexBoxAlignItems.Center}>
×
220
              <Icon
221
                name={iconFilter}
222
                className={classNames.filterIcon}
223
                mode={IconMode.Decorative}
224
                style={{
225
                  minWidth: filterStyles.iconDimensions,
226
                  minHeight: filterStyles.iconDimensions
227
                }}
228
              />
229
              <Text
230
                maxLines={1}
231
                className={classNames.filterText}
232
                style={{
233
                  fontSize: filterStyles.fontSize
234
                }}
235
                id={`${uniqueId}-filter-text`}
236
              >
237
                {filterText}
238
              </Text>
239
              {column.render(RenderColumnTypes.Filter, {
240
                accessibleNameRef: `${uniqueId}-filter-text`,
241
                popoverRef: ref
242
              })}
243
            </FlexBox>
244
          </ListItemCustom>
245
        )}
246
        {showGroup && (
7,760✔
247
          <ListItemStandard type={ListItemType.Active} icon={iconGroup} data-sort={'group'}>
248
            {column.isGrouped ? ungroupText : groupText}
928!
249
          </ListItemStandard>
250
        )}
251
      </List>
252
    </Popover>
253
  );
×
254
};
255
ColumnHeaderModal.displayName = 'ColumnHeaderModal';
281✔
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