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

SAP / ui5-webcomponents-react / 9742178811

01 Jul 2024 10:00AM CUT coverage: 81.445% (+0.06%) from 81.387%
9742178811

Pull #5978

github

web-flow
Merge 362695332 into 2cf618399
Pull Request #5978: feat(ThemeProvider): apply Fiori scrollbar styling to all scroll containers

2649 of 3845 branches covered (68.89%)

2 of 2 new or added lines in 2 files covered. (100.0%)

164 existing lines in 4 files now uncovered.

4815 of 5912 relevant lines covered (81.44%)

70456.25 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
  MessageBoxAction,
16
  MessageBoxType,
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, 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(
405✔
73
  'ui5-table',
74
  `
75
:host([data-component-name="FilterBarDialogTable"][data-is-grouped]) #nodata-row {
76
  display: none;
77
}
78
`
79
);
80

81
addCustomCSSWithScoping(
405✔
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 = (
405✔
92
  activeFilterAttribute: ActiveFilterAttributes,
93
  filter: ReactElement<FilterGroupItemInternalProps>
94
) => {
95
  switch (activeFilterAttribute) {
×
96
    case 'all':
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) =>
405✔
112
  Object.keys(firstObj).find((first) =>
×
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?: FilterBarPropTypes['onFiltersDialogSelectionChange'];
126
  handleDialogSearch?: (event: CustomEvent<{ value: string; element: HTMLElement }>) => void;
127
  handleDialogCancel?: (event: Ui5CustomEvent<HTMLElement>) => void;
128
  portalContainer: Element;
129
  onAfterFiltersDialogOpen: (event: Ui5CustomEvent<DialogDomRef>) => void;
130
  dialogRef: RefObject<DialogDomRef>;
131
  enableReordering?: FilterBarPropTypes['enableReordering'];
132
  isPhone?: boolean;
133
}
134

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

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

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

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

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

208
  const visibleChildren = () =>
×
209
    children.filter((item) => {
×
210
      return !!item?.props && (typeof item.props.visible === 'undefined' || item?.props?.visible);
×
211
    });
212

213
  const [orderedChildren, setOrderedChildren] = useState([]);
×
214

215
  useEffect(() => {
×
UNCOV
216
    if (children.length) {
×
UNCOV
217
      setOrderedChildren(visibleChildren());
×
218
    }
219
  }, [children]);
220

221
  const renderChildren = () => {
×
222
    const searchStringLower = searchString.toLowerCase();
×
223
    const filteredChildren =
UNCOV
224
      searchStringLower.length > 0 || filteredAttribute !== 'all'
×
225
        ? orderedChildren.filter(
226
            (item) =>
×
227
              (searchStringLower === '' || item.props.label?.toLowerCase().includes(searchStringLower)) &&
228
              getActiveFilters(filteredAttribute, item)
229
          )
230
        : orderedChildren;
231

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

240
      const filterItemProps = filterBarItemRef ? filterValue(filterBarItemRef, child) : {};
×
241

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

UNCOV
263
  const handleSearch = (e) => {
×
UNCOV
264
    if (typeof handleDialogSearch === 'function') {
×
UNCOV
265
      handleDialogSearch(enrichEventWithDetails(e, { value: e.target.value, element: e.target }));
×
266
    }
UNCOV
267
    setSearchString(e.target.value);
×
268
  };
269
  const handleSave = (e) => {
×
270
    const orderedChildrenIds = enableReordering ? orderedChildren.map((child) => child.props.orderId) : [];
×
UNCOV
271
    handleDialogSave(e, dialogRefs.current, toggledFilters, orderedChildrenIds);
×
272
  };
273

274
  const handleClose = (e) => {
×
275
    setToggledFilters({});
×
276
    stopPropagation(e);
×
UNCOV
277
    if (typeof handleDialogCancel === 'function') {
×
UNCOV
278
      handleDialogCancel(e);
×
279
    }
280
    handleDialogClose(e);
×
281
  };
282

283
  const handleCancel = (e) => {
×
UNCOV
284
    if (handleDialogCancel) {
×
285
      handleDialogCancel(e);
×
286
    }
UNCOV
287
    handleDialogClose(e);
×
288
  };
289

290
  const handleRestore = () => {
×
UNCOV
291
    setMessageBoxOpen(true);
×
292
  };
UNCOV
293
  const handleViewChange: SegmentedButtonPropTypes['onSelectionChange'] = (e) => {
×
UNCOV
294
    const selectedItem = e.detail.selectedItems.at(0);
×
295
    setIsListView(selectedItem.dataset.id === 'list');
×
296
  };
297

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

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

UNCOV
351
  useEffect(() => {
×
352
    if (updatedIndex != null) {
×
UNCOV
353
      prevOderId.current = undefined;
×
354
    }
355
  }, [updatedIndex]);
356

357
  const handleAttributeFilterChange = (e) => {
×
358
    setFilteredAttribute(e.detail.selectedOption.dataset.id);
×
359
  };
360

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

375
      const changedRowKey =
376
        e.detail.previouslySelectedRows > e.detail.selectedRows
×
377
          ? compareObjects(prevRowsByKey, rowsByKey)
378
          : compareObjects(rowsByKey, prevRowsByKey);
379

UNCOV
380
      const element = rowsByKey[changedRowKey] || prevRowsByKey[changedRowKey];
×
381

382
      // todo: workaround until specific rows can be disabled
UNCOV
383
      if (element.dataset?.required === 'true') {
×
UNCOV
384
        setForceRequired(element);
×
385
        return;
×
386
      }
387

388
      if (typeof handleSelectionChange === 'function') {
×
389
        handleSelectionChange(enrichEventWithDetails(e, { element, checked: element.selected }));
×
390
      }
391

UNCOV
392
      setToggledFilters((prev) => {
×
393
        return { ...prev, [changedRowKey]: element.selected };
×
394
      });
395
    }
396
  };
397

398
  useEffect(() => {
×
UNCOV
399
    if (forceRequired) {
×
UNCOV
400
      forceRequired.setAttribute('selected', 'true');
×
UNCOV
401
      setForceRequired(undefined);
×
402
    }
403
  }, [forceRequired]);
404

405
  const canRenderPortal = useCanRenderPortal();
×
406
  if (!canRenderPortal) {
×
UNCOV
407
    return null;
×
408
  }
409

410
  const renderGroups = () => {
×
411
    const groups = {};
×
412
    Children.forEach(renderChildren(), (child) => {
×
UNCOV
413
      const childGroups = child.props.groupName ?? 'default';
×
UNCOV
414
      if (groups[childGroups]) {
×
415
        groups[childGroups].push(child);
×
416
      } else {
417
        groups[childGroups] = [child];
×
418
      }
419
    });
420

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

UNCOV
456
  const currentReorderedItemOrderId = currentReorderedItem?.orderId;
×
457

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