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

SAP / ui5-webcomponents-react / 9599924297

20 Jun 2024 03:08PM CUT coverage: 81.351% (-6.4%) from 87.716%
9599924297

Pull #5940

github

web-flow
Merge 999dd9bef into cb684cdfb
Pull Request #5940: feat: update to @ui5/webcomonents 2.0.0-rc.6

2634 of 3832 branches covered (68.74%)

10 of 11 new or added lines in 6 files covered. (90.91%)

374 existing lines in 5 files now uncovered.

4794 of 5893 relevant lines covered (81.35%)

69791.28 hits per line

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

2.76
/packages/main/src/components/FilterBar/FilterDialog.tsx
1
import BarDesign from '@ui5/webcomponents/dist/types/BarDesign.js';
2
import ButtonDesign from '@ui5/webcomponents/dist/types/ButtonDesign.js';
3
import TableSelectionMode from '@ui5/webcomponents/dist/types/TableSelectionMode.js';
4
import TitleLevel from '@ui5/webcomponents/dist/types/TitleLevel.js';
5
import group2Icon from '@ui5/webcomponents-icons/dist/group-2.js';
6
import listIcon from '@ui5/webcomponents-icons/dist/list.js';
7
import searchIcon from '@ui5/webcomponents-icons/dist/search.js';
8
import { enrichEventWithDetails, useI18nBundle, useIsomorphicId, useStylesheet } from '@ui5/webcomponents-react-base';
9
import type { Dispatch, ReactElement, RefObject, SetStateAction } from 'react';
10
import { Children, cloneElement, useEffect, useReducer, useRef, useState } from 'react';
11
import { createPortal } from 'react-dom';
12
import {
13
  FlexBoxDirection,
14
  FlexBoxJustifyContent,
15
  MessageBoxActions,
16
  MessageBoxTypes,
17
  ToolbarStyle
18
} from '../../enums/index.js';
19
import {
20
  ACTIVE,
21
  ALL,
22
  BASIC,
23
  CANCEL,
24
  FIELDS_BY_ATTRIBUTE,
25
  FILTER,
26
  FILTER_DIALOG_RESET_WARNING,
27
  FILTERS,
28
  GROUP_VIEW,
29
  HIDE_VALUES,
30
  LIST_VIEW,
31
  MANDATORY,
32
  OK,
33
  RESET,
34
  SEARCH_FOR_FILTERS,
35
  SHOW_VALUES,
36
  VISIBLE,
37
  VISIBLE_AND_ACTIVE
38
} from '../../i18n/i18n-defaults.js';
39
import { addCustomCSSWithScoping } from '../../internal/addCustomCSSWithScoping.js';
40
import type { OnReorderParams } from '../../internal/FilterBarDialogContext.js';
41
import { FilterBarDialogContext } from '../../internal/FilterBarDialogContext.js';
42
import { useCanRenderPortal } from '../../internal/ssr.js';
43
import { stopPropagation } from '../../internal/stopPropagation.js';
44
import type { Ui5CustomEvent } from '../../types/index.js';
45
import type { DialogDomRef, SegmentedButtonPropTypes, TableDomRef, TableRowDomRef } from '../../webComponents/index.js';
46
import {
47
  Bar,
48
  Button,
49
  Dialog,
50
  Icon,
51
  Input,
52
  Option,
53
  Panel,
54
  SegmentedButton,
55
  SegmentedButtonItem,
56
  Select,
57
  Table,
58
  TableHeaderCell,
59
  TableHeaderRow,
60
  TableSelection,
61
  Title
62
} from '../../webComponents/index.js';
63
import type { FilterGroupItemInternalProps } from '../FilterGroupItem/types.js';
64
import { FlexBox } from '../FlexBox/index.js';
65
import { MessageBox } from '../MessageBox/index.js';
66
import { Toolbar } from '../Toolbar/index.js';
67
import { ToolbarSpacer } from '../ToolbarSpacer/index.js';
68
import { classNames, styleData } from './FilterBarDialog.module.css.js';
69
import type { FilterBarPropTypes } from './types.js';
70
import { filterValue, syncRef } from './utils.js';
71

72
addCustomCSSWithScoping(
403✔
73
  'ui5-table',
74
  `
75
:host([data-component-name="FilterBarDialogTable"][data-is-grouped]) #nodata-row {
76
  display: none;
77
}
78
`
79
);
80

81
addCustomCSSWithScoping(
403✔
82
  'ui5-table-header-row',
83
  `
84
:host([data-component-name="FilterBarDialogTableHeaderRow"]) :first-child {
85
  visibility: hidden;
86
}
87
`
88
);
89

90
type ActiveFilterAttributes = 'all' | 'visible' | 'active' | 'visibleAndActive' | 'mandatory';
91
const getActiveFilters = (
403✔
92
  activeFilterAttribute: ActiveFilterAttributes,
93
  filter: ReactElement<FilterGroupItemInternalProps>
94
) => {
UNCOV
95
  switch (activeFilterAttribute) {
×
96
    case 'all':
UNCOV
97
      return true;
×
98
    case 'visible':
99
      return filter.props?.visibleInFilterBar;
×
100
    case 'active':
101
      return filter.props?.active;
×
102
    case 'visibleAndActive':
103
      return filter.props?.visibleInFilterBar && filter.props?.active;
×
104
    case 'mandatory':
105
      return filter.props?.required;
×
106
    default:
107
      return true;
×
108
  }
109
};
110

111
const compareObjects = (firstObj, secondObj) =>
403✔
UNCOV
112
  Object.keys(firstObj).find((first) =>
×
UNCOV
113
    Object.keys(secondObj).every((second) => firstObj[second] !== secondObj[first])
×
114
  );
115

116
interface FilterDialogPropTypes {
117
  filterBarRefs: any;
118
  open: boolean;
119
  handleDialogClose: (event: Ui5CustomEvent<DialogDomRef>) => void;
120
  children: ReactElement<FilterGroupItemInternalProps>[];
121
  showRestoreButton: boolean;
122
  handleRestoreFilters: (e, source, filterElements) => void;
123
  handleDialogSave: (e, newRefs, updatedToggledFilters, orderedChildren) => void;
124
  handleSearchValueChange: Dispatch<SetStateAction<string>>;
125
  handleSelectionChange?: (
126
    event: Ui5CustomEvent<
127
      TableDomRef,
128
      { element: TableRowDomRef; checked: boolean; selectedRows: unknown[]; previouslySelectedRows: unknown[] }
129
    >
130
  ) => void;
131
  handleDialogSearch?: (event: CustomEvent<{ value: string; element: HTMLElement }>) => void;
132
  handleDialogCancel?: (event: Ui5CustomEvent<HTMLElement>) => void;
133
  portalContainer: Element;
134
  onAfterFiltersDialogOpen: (event: Ui5CustomEvent<DialogDomRef>) => void;
135
  dialogRef: RefObject<DialogDomRef>;
136
  enableReordering?: FilterBarPropTypes['enableReordering'];
137
  isPhone?: boolean;
138
}
139

140
export const FilterDialog = (props: FilterDialogPropTypes) => {
403✔
141
  const {
142
    filterBarRefs,
143
    open,
144
    handleDialogClose,
145
    children,
146
    showRestoreButton,
147
    handleRestoreFilters,
148
    handleDialogSave,
149
    handleSelectionChange,
150
    handleDialogSearch,
151
    handleDialogCancel,
152
    onAfterFiltersDialogOpen,
153
    portalContainer,
154
    dialogRef,
155
    enableReordering,
156
    isPhone
UNCOV
157
  } = props;
×
UNCOV
158
  useStylesheet(styleData, 'FilterBarDialog');
×
UNCOV
159
  const uniqueId = useIsomorphicId();
×
UNCOV
160
  const [searchString, setSearchString] = useState('');
×
UNCOV
161
  const [toggledFilters, setToggledFilters] = useState({});
×
UNCOV
162
  const dialogRefs = useRef({});
×
UNCOV
163
  const dialogSearchRef = useRef(null);
×
UNCOV
164
  const [showValues, toggleValues] = useReducer((prev) => !prev, false);
×
UNCOV
165
  const [messageBoxOpen, setMessageBoxOpen] = useState(false);
×
166

UNCOV
167
  const [forceRequired, setForceRequired] = useState<undefined | TableRowDomRef>();
×
UNCOV
168
  const [showBtnsOnHover, setShowBtnsOnHover] = useState(true);
×
UNCOV
169
  const [isListView, setIsListView] = useState(true);
×
UNCOV
170
  const [filteredAttribute, setFilteredAttribute] = useState<ActiveFilterAttributes>('all');
×
UNCOV
171
  const [currentReorderedItem, setCurrentReorderedItem] = useState<OnReorderParams | Record<string, never>>({});
×
UNCOV
172
  const tableRef = useRef(null);
×
UNCOV
173
  const okBtnRef = useRef(null);
×
UNCOV
174
  const handleReorder = (e: OnReorderParams) => {
×
UNCOV
175
    setCurrentReorderedItem(e);
×
176
  };
177

UNCOV
178
  const prevOderId = useRef(undefined);
×
UNCOV
179
  const handleFocusFallback = () => {
×
UNCOV
180
    const orderId = currentReorderedItem?.target?.dataset.orderId;
×
UNCOV
181
    if (orderId && tableRef.current && orderId !== prevOderId.current) {
×
182
      // we have to retrigger the internal item navigation logic after reordering,
183
      // otherwise keyboard nav and general focus handling is not working properly
UNCOV
184
      setTimeout(() => {
×
UNCOV
185
        const itemNav = tableRef.current._itemNavigation;
×
UNCOV
186
        itemNav._getItems = () => Array.from(tableRef.current.querySelectorAll('[ui5-table-row]'));
×
UNCOV
187
        itemNav.setCurrentItem(tableRef.current.querySelector(`[data-order-id="${orderId}"]`));
×
188
      });
UNCOV
189
      prevOderId.current = orderId;
×
190
    }
191
  };
192

UNCOV
193
  const i18nBundle = useI18nBundle('@ui5/webcomponents-react');
×
194

UNCOV
195
  const basicText = i18nBundle.getText(BASIC);
×
UNCOV
196
  const cancelText = i18nBundle.getText(CANCEL);
×
UNCOV
197
  const okText = i18nBundle.getText(OK);
×
UNCOV
198
  const searchForFiltersText = i18nBundle.getText(SEARCH_FOR_FILTERS);
×
UNCOV
199
  const filtersTitle = i18nBundle.getText(FILTERS);
×
UNCOV
200
  const resetText = i18nBundle.getText(RESET);
×
UNCOV
201
  const allText = i18nBundle.getText(ALL);
×
UNCOV
202
  const activeText = i18nBundle.getText(ACTIVE);
×
UNCOV
203
  const visibleText = i18nBundle.getText(VISIBLE);
×
UNCOV
204
  const visibleAndActiveText = i18nBundle.getText(VISIBLE_AND_ACTIVE);
×
UNCOV
205
  const mandatoryText = i18nBundle.getText(MANDATORY);
×
UNCOV
206
  const listViewText = i18nBundle.getText(LIST_VIEW);
×
UNCOV
207
  const groupViewText = i18nBundle.getText(GROUP_VIEW);
×
UNCOV
208
  const showValuesText = i18nBundle.getText(SHOW_VALUES);
×
UNCOV
209
  const hideValuesText = i18nBundle.getText(HIDE_VALUES);
×
UNCOV
210
  const filterText = i18nBundle.getText(FILTER);
×
UNCOV
211
  const fieldsByAttributeText = i18nBundle.getText(FIELDS_BY_ATTRIBUTE);
×
212

UNCOV
213
  const visibleChildren = () =>
×
UNCOV
214
    children.filter((item) => {
×
UNCOV
215
      return !!item?.props && (typeof item.props.visible === 'undefined' || item?.props?.visible);
×
216
    });
217

UNCOV
218
  const [orderedChildren, setOrderedChildren] = useState([]);
×
219

UNCOV
220
  useEffect(() => {
×
UNCOV
221
    if (children.length) {
×
UNCOV
222
      setOrderedChildren(visibleChildren());
×
223
    }
224
  }, [children]);
225

UNCOV
226
  const renderChildren = () => {
×
UNCOV
227
    const searchStringLower = searchString.toLowerCase();
×
228
    const filteredChildren =
UNCOV
229
      searchStringLower.length > 0 || filteredAttribute !== 'all'
×
230
        ? orderedChildren.filter(
UNCOV
231
            (item) =>
×
232
              (searchStringLower === '' || item.props.label?.toLowerCase().includes(searchStringLower)) &&
233
              getActiveFilters(filteredAttribute, item)
234
          )
235
        : orderedChildren;
236

UNCOV
237
    return filteredChildren.map((child, index) => {
×
UNCOV
238
      const filterBarItemRef = filterBarRefs.current[child.key];
×
239
      let isSelected =
UNCOV
240
        child.props.visibleInFilterBar || child.props.required || child.type.displayName !== 'FilterGroupItem';
×
UNCOV
241
      if (toggledFilters.hasOwnProperty(child.key)) {
×
UNCOV
242
        isSelected = toggledFilters[child.key];
×
243
      }
244

UNCOV
245
      const filterItemProps = filterBarItemRef ? filterValue(filterBarItemRef, child) : {};
×
246

UNCOV
247
      return cloneElement<FilterGroupItemInternalProps>(child, {
×
248
        'data-selected': isSelected,
249
        'data-react-key': child.key,
250
        'data-index': index,
251
        children: {
252
          ...child.props.children,
253
          props: {
254
            ...(child.props.children.props || {}),
×
255
            ...filterItemProps
256
          },
257
          ref: (node) => {
258
            if (node) {
×
259
              dialogRefs.current[child.key] = node;
×
260
              syncRef(child.props.children.ref, node);
×
261
            }
262
          }
263
        }
264
      });
265
    });
266
  };
267

UNCOV
268
  const handleSearch = (e) => {
×
UNCOV
269
    if (handleDialogSearch) {
×
UNCOV
270
      handleDialogSearch(enrichEventWithDetails(e, { value: e.target.value, element: e.target }));
×
271
    }
UNCOV
272
    setSearchString(e.target.value);
×
273
  };
UNCOV
274
  const handleSave = (e) => {
×
UNCOV
275
    const orderedChildrenIds = enableReordering ? orderedChildren.map((child) => child.props.orderId) : [];
×
UNCOV
276
    handleDialogSave(e, dialogRefs.current, toggledFilters, orderedChildrenIds);
×
277
  };
278

UNCOV
279
  const handleClose = (e) => {
×
UNCOV
280
    setToggledFilters({});
×
UNCOV
281
    stopPropagation(e);
×
UNCOV
282
    if (handleDialogCancel) {
×
UNCOV
283
      handleDialogCancel(e);
×
284
    }
UNCOV
285
    handleDialogClose(e);
×
286
  };
287

UNCOV
288
  const handleCancel = (e) => {
×
UNCOV
289
    if (handleDialogCancel) {
×
UNCOV
290
      handleDialogCancel(e);
×
291
    }
UNCOV
292
    handleDialogClose(e);
×
293
  };
294

UNCOV
295
  const handleRestore = () => {
×
UNCOV
296
    setMessageBoxOpen(true);
×
297
  };
UNCOV
298
  const handleViewChange: SegmentedButtonPropTypes['onSelectionChange'] = (e) => {
×
UNCOV
299
    const selectedItem = e.detail.selectedItems.at(0);
×
UNCOV
300
    setIsListView(selectedItem.dataset.id === 'list');
×
301
  };
302

UNCOV
303
  const handleMessageBoxClose = (e) => {
×
UNCOV
304
    if (e.detail.action === 'OK') {
×
UNCOV
305
      setToggledFilters({});
×
UNCOV
306
      setOrderedChildren(visibleChildren());
×
UNCOV
307
      handleRestoreFilters(e, 'dialog', { filters: Array.from(dialogRef.current.querySelectorAll('ui5-table-row')) });
×
308
    }
UNCOV
309
    setMessageBoxOpen(false);
×
UNCOV
310
    okBtnRef.current.focus();
×
311
  };
312

UNCOV
313
  const [updatedIndex, setUpdatedIndex] = useState(undefined);
×
UNCOV
314
  useEffect(() => {
×
UNCOV
315
    if (currentReorderedItem?.index != null) {
×
UNCOV
316
      setOrderedChildren((prev: any[]) => {
×
UNCOV
317
        const { index, direction } = currentReorderedItem;
×
UNCOV
318
        switch (direction) {
×
319
          case 'up':
UNCOV
320
            if (index > 0) {
×
UNCOV
321
              setUpdatedIndex(index - 1);
×
UNCOV
322
              const temp = prev[index];
×
UNCOV
323
              prev[index] = prev[index - 1];
×
UNCOV
324
              prev[index - 1] = temp;
×
325
            }
UNCOV
326
            break;
×
327
          case 'down':
UNCOV
328
            if (index < prev.length - 1) {
×
UNCOV
329
              setUpdatedIndex(index + 1);
×
UNCOV
330
              const temp = prev[index];
×
UNCOV
331
              prev[index] = prev[index + 1];
×
UNCOV
332
              prev[index + 1] = temp;
×
333
            }
UNCOV
334
            break;
×
335
          case 'top':
UNCOV
336
            if (index > 0) {
×
UNCOV
337
              setUpdatedIndex(0);
×
UNCOV
338
              const item = prev.splice(index, 1)[0];
×
UNCOV
339
              prev.unshift(item);
×
340
            }
UNCOV
341
            break;
×
342
          case 'bottom':
UNCOV
343
            if (index < prev.length - 1) {
×
UNCOV
344
              setUpdatedIndex(prev.length - 1);
×
UNCOV
345
              const item = prev.splice(index, 1)[0];
×
UNCOV
346
              prev.push(item);
×
347
            }
UNCOV
348
            break;
×
349
        }
UNCOV
350
        return [...prev];
×
351
      });
UNCOV
352
      void currentReorderedItem.target.focus();
×
353
    }
354
  }, [currentReorderedItem]);
355

UNCOV
356
  useEffect(() => {
×
UNCOV
357
    if (updatedIndex != null) {
×
UNCOV
358
      prevOderId.current = undefined;
×
359
    }
360
  }, [updatedIndex]);
361

UNCOV
362
  const handleAttributeFilterChange = (e) => {
×
363
    setFilteredAttribute(e.detail.selectedOption.dataset.id);
×
364
  };
365

UNCOV
366
  const handleCheckBoxChange = (e) => {
×
UNCOV
367
    if (e.target.hasAttribute('ui5-table')) {
×
368
      // preventDefault should only be called if the target is the table, otherwise bubbled `selection-change` events
369
      // also prevent their default behavior (e.g. the event of the MultiComboBox)
UNCOV
370
      e.preventDefault();
×
UNCOV
371
      const prevRowsByKey = e.detail.previouslySelectedRows.reduce(
×
UNCOV
372
        (acc, prevSelRow) => ({ ...acc, [prevSelRow.dataset.reactKey]: prevSelRow }),
×
373
        {}
374
      );
UNCOV
375
      const rowsByKey = e.detail.selectedRows.reduce(
×
UNCOV
376
        (acc, selRow) => ({ ...acc, [selRow.dataset.reactKey]: selRow }),
×
377
        {}
378
      );
379

380
      const changedRowKey =
UNCOV
381
        e.detail.previouslySelectedRows > e.detail.selectedRows
×
382
          ? compareObjects(prevRowsByKey, rowsByKey)
383
          : compareObjects(rowsByKey, prevRowsByKey);
384

UNCOV
385
      const element = rowsByKey[changedRowKey] || prevRowsByKey[changedRowKey];
×
386

387
      // todo: workaround until specific rows can be disabled
UNCOV
388
      if (element.dataset?.required === 'true') {
×
389
        setForceRequired(element);
×
390
        return;
×
391
      }
392

UNCOV
393
      if (typeof handleSelectionChange === 'function') {
×
UNCOV
394
        handleSelectionChange(enrichEventWithDetails(e, { element, checked: element.selected }));
×
395
      }
396

UNCOV
397
      setToggledFilters((prev) => {
×
UNCOV
398
        return { ...prev, [changedRowKey]: element.selected };
×
399
      });
400
    }
401
  };
402

UNCOV
403
  useEffect(() => {
×
UNCOV
404
    if (forceRequired) {
×
405
      forceRequired.setAttribute('selected', 'true');
×
406
      setForceRequired(undefined);
×
407
    }
408
  }, [forceRequired]);
409

UNCOV
410
  const canRenderPortal = useCanRenderPortal();
×
UNCOV
411
  if (!canRenderPortal) {
×
UNCOV
412
    return null;
×
413
  }
414

UNCOV
415
  const renderGroups = () => {
×
UNCOV
416
    const groups = {};
×
UNCOV
417
    Children.forEach(renderChildren(), (child) => {
×
UNCOV
418
      const childGroups = child.props.groupName ?? 'default';
×
UNCOV
419
      if (groups[childGroups]) {
×
UNCOV
420
        groups[childGroups].push(child);
×
421
      } else {
UNCOV
422
        groups[childGroups] = [child];
×
423
      }
424
    });
425

UNCOV
426
    const filterGroups = Object.keys(groups)
×
UNCOV
427
      .sort((x, y) => (x === 'default' ? -1 : y === 'role' ? 1 : 0))
×
428
      .map((item, index) => {
NEW
429
        const selectedRows = groups[item].map((child) => child.props['data-react-key']).join(' ');
×
UNCOV
430
        return (
×
431
          <Panel
432
            headerText={item === 'default' ? basicText : item}
×
433
            className={classNames.groupPanel}
434
            key={`${item === 'default' ? basicText : item}${index}`}
×
435
          >
436
            <Table
437
              className={classNames.tableInGroup}
438
              data-component-name="FilterBarDialogPanelTable"
439
              features={
440
                <TableSelection
441
                  mode={TableSelectionMode.Multiple}
442
                  selected={selectedRows}
443
                  onChange={handleCheckBoxChange}
444
                />
445
              }
446
              headerRow={
447
                <TableHeaderRow className={classNames.groupedTableHeader}>
448
                  <TableHeaderCell>{filterText}</TableHeaderCell>
449
                  {!showValues && <TableHeaderCell className={classNames.tHactive}>{activeText}</TableHeaderCell>}
×
450
                </TableHeaderRow>
451
              }
452
            >
453
              {groups[item]}
454
            </Table>
455
          </Panel>
456
        );
457
      });
UNCOV
458
    return filterGroups;
×
459
  };
460

UNCOV
461
  const currentReorderedItemOrderId = currentReorderedItem?.orderId;
×
462

UNCOV
463
  return (
×
464
    <FilterBarDialogContext.Provider
465
      value={{
466
        isFilterInDialog: true,
467
        enableReordering,
468
        onReorder: handleReorder,
469
        isListView,
470
        withValues: showValues,
471
        handleFocusFallback,
472
        showBtnsOnHover,
473
        setShowBtnsOnHover,
474
        currentReorderedItemOrderId
475
      }}
476
    >
477
      {createPortal(
478
        <Dialog
479
          open={open}
480
          ref={dialogRef}
481
          data-component-name="FilterBarDialog"
482
          data-is-phone={isPhone}
483
          onClose={handleClose}
484
          onOpen={onAfterFiltersDialogOpen}
485
          resizable
486
          draggable
487
          className={classNames.dialogComponent}
488
          preventFocusRestore
489
          initialFocus={`${uniqueId}-fb-dialog-search`}
490
          header={
491
            <Bar
492
              design={BarDesign.Header}
493
              startContent={
494
                <Title level={TitleLevel.H4} title={filtersTitle}>
495
                  {filtersTitle}
496
                </Title>
497
              }
498
              endContent={
499
                showRestoreButton && (
×
500
                  <Button design={ButtonDesign.Transparent} onClick={handleRestore}>
501
                    {resetText}
502
                  </Button>
503
                )
504
              }
505
            />
506
          }
507
          footer={
508
            <Bar
509
              design={BarDesign.Footer}
510
              endContent={
511
                <FlexBox justifyContent={FlexBoxJustifyContent.End} className={classNames.footer}>
512
                  <Button
513
                    ref={okBtnRef}
514
                    onClick={handleSave}
515
                    data-component-name="FilterBarDialogSaveBtn"
516
                    design={ButtonDesign.Emphasized}
517
                  >
518
                    {okText}
519
                  </Button>
520
                  <Button
521
                    design={ButtonDesign.Transparent}
522
                    onClick={handleCancel}
523
                    data-component-name="FilterBarDialogCancelBtn"
524
                  >
525
                    {cancelText}
526
                  </Button>
527
                </FlexBox>
528
              }
529
            />
530
          }
531
        >
532
          <FlexBox direction={FlexBoxDirection.Column} className={classNames.subheaderContainer}>
533
            <Toolbar className={classNames.subheader} toolbarStyle={ToolbarStyle.Clear}>
534
              <Select
535
                onChange={handleAttributeFilterChange}
536
                title={fieldsByAttributeText}
537
                accessibleName={fieldsByAttributeText}
538
              >
539
                <Option selected={filteredAttribute === 'all'} data-id="all">
540
                  {allText}
541
                </Option>
542
                <Option selected={filteredAttribute === 'visible'} data-id="visible">
543
                  {visibleText}
544
                </Option>
545
                <Option selected={filteredAttribute === 'active'} data-id="active">
546
                  {activeText}
547
                </Option>
548
                <Option selected={filteredAttribute === 'visibleAndActive'} data-id="visibleAndActive">
549
                  {visibleAndActiveText}
550
                </Option>
551
                <Option selected={filteredAttribute === 'mandatory'} data-id="mandatory">
552
                  {mandatoryText}
553
                </Option>
554
              </Select>
555
              <ToolbarSpacer />
556
              <Button design={ButtonDesign.Transparent} onClick={toggleValues} aria-live="polite">
557
                {showValues ? hideValuesText : showValuesText}
×
558
              </Button>
559
              <SegmentedButton onSelectionChange={handleViewChange}>
560
                <SegmentedButtonItem
561
                  icon={listIcon}
562
                  data-id="list"
563
                  selected={isListView}
564
                  accessibleName={listViewText}
565
                />
566
                <SegmentedButtonItem
567
                  icon={group2Icon}
568
                  data-id="group"
569
                  selected={!isListView}
570
                  accessibleName={groupViewText}
571
                />
572
              </SegmentedButton>
573
            </Toolbar>
574
            <FlexBox className={classNames.searchInputContainer}>
575
              <Input
576
                id={`${uniqueId}-fb-dialog-search`}
577
                noTypeahead
578
                placeholder={searchForFiltersText}
579
                onInput={handleSearch}
580
                showClearIcon
581
                icon={<Icon name={searchIcon} />}
582
                ref={dialogSearchRef}
583
                className={classNames.searchInput}
584
                data-component-name="FilterBarDialogSearchInput"
585
              />
586
            </FlexBox>
587
          </FlexBox>
588
          <Table
589
            ref={tableRef}
590
            data-component-name="FilterBarDialogTable"
591
            data-is-grouped={!isListView}
592
            nodata={!isListView ? <span /> : undefined}
×
593
            tabIndex={!isListView ? -1 : undefined}
×
594
            features={
595
              <>
596
                <TableSelection mode={TableSelectionMode.Multiple} onChange={handleCheckBoxChange} />
597
              </>
598
            }
599
            headerRow={
600
              <TableHeaderRow data-component-name="FilterBarDialogTableHeaderRow">
601
                <TableHeaderCell>{filterText}</TableHeaderCell>
602
                {!showValues && <TableHeaderCell className={classNames.tHactive}>{activeText}</TableHeaderCell>}
×
603
              </TableHeaderRow>
604
            }
605
          >
606
            {isListView && renderChildren()}
×
607
          </Table>
608
          {!isListView && renderGroups()}
×
609
        </Dialog>,
610
        portalContainer ?? document.body
×
611
      )}
612
      {showRestoreButton &&
×
613
        messageBoxOpen &&
614
        createPortal(
615
          <MessageBox
616
            open
617
            type={MessageBoxTypes.Warning}
618
            actions={[MessageBoxActions.OK, MessageBoxActions.Cancel]}
619
            onClose={handleMessageBoxClose}
620
            data-component-name="FilterBarDialogResetMessageBox"
621
          >
622
            {i18nBundle.getText(FILTER_DIALOG_RESET_WARNING)}
623
          </MessageBox>,
624
          portalContainer ?? document.body
×
625
        )}
626
    </FilterBarDialogContext.Provider>
627
  );
628
};
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