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

SAP / ui5-webcomponents-react / 10005755679

19 Jul 2024 09:23AM CUT coverage: 79.662% (+0.08%) from 79.583%
10005755679

Pull #6095

github

web-flow
Merge e6db46325 into 105b2da44
Pull Request #6095: refactor: drop support for React 16 & 17

2512 of 3755 branches covered (66.9%)

8 of 9 new or added lines in 9 files covered. (88.89%)

1 existing line in 1 file now uncovered.

4575 of 5743 relevant lines covered (79.66%)

70944.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, useStylesheet } from '@ui5/webcomponents-react-base';
9
import type { Dispatch, ReactElement, RefObject, SetStateAction } from 'react';
10
import { Children, cloneElement, useEffect, useId, useReducer, useRef, useState } from 'react';
11
import { createPortal } from 'react-dom';
12
import { FlexBoxDirection, FlexBoxJustifyContent, MessageBoxAction, MessageBoxType } from '../../enums/index.js';
13
import {
14
  ACTIVE,
15
  ALL,
16
  BASIC,
17
  CANCEL,
18
  FIELDS_BY_ATTRIBUTE,
19
  FILTER,
20
  FILTER_DIALOG_RESET_WARNING,
21
  FILTERS,
22
  GROUP_VIEW,
23
  HIDE_VALUES,
24
  LIST_VIEW,
25
  MANDATORY,
26
  OK,
27
  RESET,
28
  SEARCH_FOR_FILTERS,
29
  SHOW_VALUES,
30
  VISIBLE,
31
  VISIBLE_AND_ACTIVE
32
} from '../../i18n/i18n-defaults.js';
33
import { addCustomCSSWithScoping } from '../../internal/addCustomCSSWithScoping.js';
34
import type { OnReorderParams } from '../../internal/FilterBarDialogContext.js';
35
import { FilterBarDialogContext } from '../../internal/FilterBarDialogContext.js';
36
import { useCanRenderPortal } from '../../internal/ssr.js';
37
import { stopPropagation } from '../../internal/stopPropagation.js';
38
import type { Ui5CustomEvent } from '../../types/index.js';
39
import type { DialogDomRef, SegmentedButtonPropTypes, TableRowDomRef } from '../../webComponents/index.js';
40
import {
41
  Bar,
42
  Button,
43
  Dialog,
44
  Icon,
45
  Input,
46
  Option,
47
  Panel,
48
  SegmentedButton,
49
  SegmentedButtonItem,
50
  Select,
51
  Table,
52
  TableHeaderCell,
53
  TableHeaderRow,
54
  TableSelection,
55
  Title
56
} from '../../webComponents/index.js';
57
import type { FilterGroupItemInternalProps } from '../FilterGroupItem/types.js';
58
import { FlexBox } from '../FlexBox/index.js';
59
import { MessageBox } from '../MessageBox/index.js';
60
import { Toolbar } from '../Toolbar/index.js';
61
import { ToolbarSpacer } from '../ToolbarSpacer/index.js';
62
import { classNames, styleData } from './FilterBarDialog.module.css.js';
63
import type { FilterBarPropTypes } from './types.js';
64
import { filterValue, syncRef } from './utils.js';
65

66
addCustomCSSWithScoping(
361✔
67
  'ui5-table',
68
  `
69
:host([data-component-name="FilterBarDialogTable"][data-is-grouped]) #nodata-row {
70
  display: none;
71
}
72
`
73
);
74

75
addCustomCSSWithScoping(
361✔
76
  'ui5-table-header-row',
77
  `
78
:host([data-component-name="FilterBarDialogTableHeaderRow"]) :first-child {
79
  visibility: hidden;
80
}
81
`
82
);
83

84
type ActiveFilterAttributes = 'all' | 'visible' | 'active' | 'visibleAndActive' | 'mandatory';
85
const getActiveFilters = (
361✔
86
  activeFilterAttribute: ActiveFilterAttributes,
87
  filter: ReactElement<FilterGroupItemInternalProps>
88
) => {
89
  switch (activeFilterAttribute) {
×
90
    case 'all':
91
      return true;
×
92
    case 'visible':
93
      return filter.props?.hiddenInFilterBar !== true;
×
94
    case 'active':
95
      return filter.props?.active;
×
96
    case 'visibleAndActive':
97
      return filter.props?.hiddenInFilterBar !== true && filter.props?.active;
×
98
    case 'mandatory':
99
      return filter.props?.required;
×
100
    default:
101
      return true;
×
102
  }
103
};
104

105
const compareObjects = (firstObj, secondObj) =>
361✔
106
  Object.keys(firstObj).find((first) =>
×
107
    Object.keys(secondObj).every((second) => firstObj[second] !== secondObj[first])
×
108
  );
109

110
interface FilterDialogPropTypes {
111
  filterBarRefs: any;
112
  open: boolean;
113
  handleDialogClose: (event: Ui5CustomEvent<DialogDomRef>) => void;
114
  children: ReactElement<FilterGroupItemInternalProps>[];
115
  showRestoreButton: boolean;
116
  handleRestoreFilters: (e, source, filterElements) => void;
117
  handleDialogSave: (e, newRefs, updatedToggledFilters, orderedChildren) => void;
118
  handleSearchValueChange: Dispatch<SetStateAction<string>>;
119
  handleSelectionChange?: FilterBarPropTypes['onFiltersDialogSelectionChange'];
120
  handleDialogSearch?: (event: CustomEvent<{ value: string; element: HTMLElement }>) => void;
121
  handleDialogCancel?: (event: Ui5CustomEvent<HTMLElement>) => void;
122
  portalContainer: Element;
123
  onAfterFiltersDialogOpen: (event: Ui5CustomEvent<DialogDomRef>) => void;
124
  dialogRef: RefObject<DialogDomRef>;
125
  enableReordering?: FilterBarPropTypes['enableReordering'];
126
  isPhone?: boolean;
127
}
128

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

156
  const [forceRequired, setForceRequired] = useState<undefined | TableRowDomRef>();
×
157
  const [showBtnsOnHover, setShowBtnsOnHover] = useState(true);
×
158
  const [isListView, setIsListView] = useState(true);
×
159
  const [filteredAttribute, setFilteredAttribute] = useState<ActiveFilterAttributes>('all');
×
160
  const [currentReorderedItem, setCurrentReorderedItem] = useState<OnReorderParams | Record<string, never>>({});
×
161
  const tableRef = useRef(null);
×
162
  const okBtnRef = useRef(null);
×
163
  const handleReorder = (e: OnReorderParams) => {
×
164
    setCurrentReorderedItem(e);
×
165
  };
166

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

182
  const i18nBundle = useI18nBundle('@ui5/webcomponents-react');
×
183

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

202
  const visibleChildren = () =>
×
203
    children.filter((item) => {
×
204
      return !!item?.props && !item?.props?.hidden;
×
205
    });
206

207
  const [orderedChildren, setOrderedChildren] = useState([]);
×
208

209
  useEffect(() => {
×
210
    if (children.length) {
×
211
      setOrderedChildren(visibleChildren());
×
212
    }
213
  }, [children]);
214

215
  const renderChildren = () => {
×
216
    const searchStringLower = searchString.toLowerCase();
×
217
    const filteredChildren =
218
      searchStringLower.length > 0 || filteredAttribute !== 'all'
×
219
        ? orderedChildren.filter(
220
            (item) =>
×
221
              (searchStringLower === '' || item.props.label?.toLowerCase().includes(searchStringLower)) &&
222
              getActiveFilters(filteredAttribute, item)
223
          )
224
        : orderedChildren;
225

226
    return filteredChildren.map((child, index) => {
×
227
      const filterBarItemRef = filterBarRefs.current[child.key];
×
228
      let isSelected =
229
        child.props.hiddenInFilterBar !== true || child.props.required || child.type.displayName !== 'FilterGroupItem';
×
230
      if (toggledFilters.hasOwnProperty(child.key)) {
×
231
        isSelected = toggledFilters[child.key];
×
232
      }
233

234
      const filterItemProps = filterBarItemRef ? filterValue(filterBarItemRef, child) : {};
×
235

236
      return cloneElement<FilterGroupItemInternalProps>(child, {
×
237
        'data-selected': isSelected,
238
        'data-react-key': child.key,
239
        'data-index': index,
240
        children: {
241
          ...child.props.children,
242
          props: {
243
            ...(child.props.children.props || {}),
×
244
            ...filterItemProps
245
          },
246
          ref: (node) => {
247
            if (node) {
×
248
              dialogRefs.current[child.key] = node;
×
249
              syncRef(child.props.children.ref, node);
×
250
            }
251
          }
252
        }
253
      });
254
    });
255
  };
256

257
  const handleSearch = (e) => {
×
258
    if (typeof handleDialogSearch === 'function') {
×
259
      handleDialogSearch(enrichEventWithDetails(e, { value: e.target.value, element: e.target }));
×
260
    }
261
    setSearchString(e.target.value);
×
262
  };
263
  const handleSave = (e) => {
×
264
    const orderedChildrenIds = enableReordering ? orderedChildren.map((child) => child.props.orderId) : [];
×
265
    handleDialogSave(e, dialogRefs.current, toggledFilters, orderedChildrenIds);
×
266
  };
267

268
  const handleClose = (e) => {
×
269
    setToggledFilters({});
×
270
    stopPropagation(e);
×
271
    if (typeof handleDialogCancel === 'function') {
×
272
      handleDialogCancel(e);
×
273
    }
274
    handleDialogClose(e);
×
275
  };
276

277
  const handleCancel = (e) => {
×
278
    if (handleDialogCancel) {
×
279
      handleDialogCancel(e);
×
280
    }
281
    handleDialogClose(e);
×
282
  };
283

284
  const handleRestore = () => {
×
285
    setMessageBoxOpen(true);
×
286
  };
287
  const handleViewChange: SegmentedButtonPropTypes['onSelectionChange'] = (e) => {
×
288
    const selectedItem = e.detail.selectedItems.at(0);
×
289
    setIsListView(selectedItem.dataset.id === 'list');
×
290
  };
291

292
  const handleMessageBoxClose = (e) => {
×
293
    if (e.detail.action === 'OK') {
×
294
      setToggledFilters({});
×
295
      setOrderedChildren(visibleChildren());
×
296
      handleRestoreFilters(e, 'dialog', { filters: Array.from(dialogRef.current.querySelectorAll('ui5-table-row')) });
×
297
    }
298
    setMessageBoxOpen(false);
×
299
    okBtnRef.current.focus();
×
300
  };
301

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

345
  useEffect(() => {
×
346
    if (updatedIndex != null) {
×
347
      prevOderId.current = undefined;
×
348
    }
349
  }, [updatedIndex]);
350

351
  const handleAttributeFilterChange = (e) => {
×
352
    setFilteredAttribute(e.detail.selectedOption.dataset.id);
×
353
  };
354

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

369
      const changedRowKey =
370
        e.detail.previouslySelectedRows > e.detail.selectedRows
×
371
          ? compareObjects(prevRowsByKey, rowsByKey)
372
          : compareObjects(rowsByKey, prevRowsByKey);
373

374
      const element = rowsByKey[changedRowKey] || prevRowsByKey[changedRowKey];
×
375

376
      // todo: workaround until specific rows can be disabled
377
      if (element.dataset?.required === 'true') {
×
378
        setForceRequired(element);
×
379
        return;
×
380
      }
381

382
      if (typeof handleSelectionChange === 'function') {
×
383
        handleSelectionChange(enrichEventWithDetails(e, { element, checked: element.selected }));
×
384
      }
385

386
      setToggledFilters((prev) => {
×
387
        return { ...prev, [changedRowKey]: element.selected };
×
388
      });
389
    }
390
  };
391

392
  useEffect(() => {
×
393
    if (forceRequired) {
×
394
      forceRequired.setAttribute('selected', 'true');
×
395
      setForceRequired(undefined);
×
396
    }
397
  }, [forceRequired]);
398

399
  const canRenderPortal = useCanRenderPortal();
×
400
  if (!canRenderPortal) {
×
401
    return null;
×
402
  }
403

404
  const renderGroups = () => {
×
405
    const groups = {};
×
406
    Children.forEach(renderChildren(), (child) => {
×
407
      const childGroups = child.props.groupName ?? 'default';
×
408
      if (groups[childGroups]) {
×
409
        groups[childGroups].push(child);
×
410
      } else {
411
        groups[childGroups] = [child];
×
412
      }
413
    });
414

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

450
  const currentReorderedItemOrderId = currentReorderedItem?.orderId;
×
451

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