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

SAP / ui5-webcomponents-react / 9599598536

20 Jun 2024 02:47PM CUT coverage: 88.058% (+0.3%) from 87.716%
9599598536

Pull #5940

github

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

2877 of 4123 branches covered (69.78%)

17 of 18 new or added lines in 6 files covered. (94.44%)

7 existing lines in 3 files now uncovered.

5184 of 5887 relevant lines covered (88.06%)

69945.23 hits per line

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

90.77
/packages/main/src/components/VariantManagement/ManageViewsDialog.tsx
1
import BarDesign from '@ui5/webcomponents/dist/types/BarDesign.js';
2
import ButtonDesign from '@ui5/webcomponents/dist/types/ButtonDesign.js';
3
import searchIcon from '@ui5/webcomponents-icons/dist/search.js';
4
import { enrichEventWithDetails, useI18nBundle, useIsomorphicId, useStylesheet } from '@ui5/webcomponents-react-base';
5
import type { MouseEventHandler, ReactElement } from 'react';
6
import { isValidElement, Children, useEffect, useRef, useState } from 'react';
7
import { createPortal } from 'react-dom';
8
import { FlexBoxAlignItems, FlexBoxDirection } from '../../enums/index.js';
9
import {
10
  APPLY_AUTOMATICALLY,
11
  CANCEL,
12
  CREATED_BY,
13
  DEFAULT,
14
  MANAGE_VIEWS,
15
  SAVE,
16
  SEARCH,
17
  SHARING,
18
  VIEW
19
} from '../../i18n/i18n-defaults.js';
20
import { useCanRenderPortal } from '../../internal/ssr.js';
21
import { Bar } from '../../webComponents/Bar/index.js';
22
import { Button } from '../../webComponents/Button/index.js';
23
import type { DialogPropTypes } from '../../webComponents/Dialog/index.js';
24
import { Dialog } from '../../webComponents/Dialog/index.js';
25
import type { InputDomRef } from '../../webComponents/index.js';
26
import { Icon, Input } from '../../webComponents/index.js';
27
import { Table } from '../../webComponents/Table/index.js';
28
import { TableColumn } from '../../webComponents/TableColumn/index.js';
29
import { FlexBox } from '../FlexBox/index.js';
30
import { classNames, styleData } from './ManageViewsDialog.module.css.js';
31
import { ManageViewsTableRows } from './ManageViewsTableRows.js';
32
import type { VariantManagementPropTypes } from './types.js';
33
import type { VariantItemPropTypes } from './VariantItem.js';
34

35
type ManageViewsDialogChildType = boolean | undefined | null | ReactElement<VariantItemPropTypes>;
36

37
export interface ManageViewsDialogPropTypes {
38
  children: ManageViewsDialogChildType | ManageViewsDialogChildType[];
39
  onAfterClose: DialogPropTypes['onClose'];
40
  handleSaveManageViews: (
41
    e: MouseEventHandler<HTMLElement>,
42
    payload: {
43
      updatedRows: any;
44
      defaultView: string;
45
      deletedRows: any;
46
    }
47
  ) => void;
48
  showShare: boolean;
49
  showApplyAutomatically: boolean;
50
  showSetAsDefault: boolean;
51
  showCreatedBy: boolean;
52
  variantNames: string[];
53
  portalContainer: VariantManagementPropTypes['portalContainer'];
54
  showOnlyFavorites?: VariantManagementPropTypes['showOnlyFavorites'];
55
  onManageViewsCancel?: VariantManagementPropTypes['onManageViewsCancel'];
56
}
57

140✔
58
export const ManageViewsDialog = (props: ManageViewsDialogPropTypes) => {
277✔
59
  const {
60
    children,
61
    onAfterClose,
62
    handleSaveManageViews,
63
    showShare,
64
    showApplyAutomatically,
65
    showSetAsDefault,
66
    showCreatedBy,
67
    variantNames,
68
    portalContainer,
69
    showOnlyFavorites,
70
    onManageViewsCancel
71
  } = props;
864✔
72
  const uniqueId = useIsomorphicId();
864✔
73
  const i18nBundle = useI18nBundle('@ui5/webcomponents-react');
864✔
74
  const cancelText = i18nBundle.getText(CANCEL);
864✔
75
  const saveText = i18nBundle.getText(SAVE);
864✔
76
  const viewHeaderText = i18nBundle.getText(VIEW);
864✔
77
  const sharingHeaderText = i18nBundle.getText(SHARING);
864✔
78
  const defaultHeaderText = i18nBundle.getText(DEFAULT);
864✔
79
  const applyAutomaticallyHeaderText = i18nBundle.getText(APPLY_AUTOMATICALLY);
864✔
80
  const createdByHeaderText = i18nBundle.getText(CREATED_BY);
864✔
81
  const manageViewsText = i18nBundle.getText(MANAGE_VIEWS);
864✔
82
  const searchText = i18nBundle.getText(SEARCH);
864✔
83

84
  const [changedVariantNames, setChangedVariantNames] = useState(new Map());
864✔
85
  const [invalidVariants, setInvalidVariants] = useState<Record<string, InputDomRef & { isInvalid?: boolean }>>({});
864✔
86

87
  useStylesheet(styleData, 'ManageViewsDialog');
864✔
88

89
  const columns = (
×
90
    <>
864✔
91
      {showOnlyFavorites && <TableColumn key="favorite-variant-item" />}
1,151✔
92
      <TableColumn>{viewHeaderText}</TableColumn>
93
      {showShare && (
1,728✔
94
        <TableColumn demandPopin minWidth={600}>
95
          {sharingHeaderText}
96
        </TableColumn>
97
      )}
98
      {showSetAsDefault && (
1,728✔
99
        <TableColumn demandPopin minWidth={600} popinText={defaultHeaderText}>
100
          {defaultHeaderText}
101
        </TableColumn>
102
      )}
103
      {showApplyAutomatically && (
1,728✔
104
        <TableColumn demandPopin minWidth={600} popinText={applyAutomaticallyHeaderText}>
×
105
          {applyAutomaticallyHeaderText}
106
        </TableColumn>
107
      )}
108
      {showCreatedBy && (
1,728✔
109
        <TableColumn demandPopin minWidth={600} popinText={createdByHeaderText}>
110
          {createdByHeaderText}
111
        </TableColumn>
×
112
      )}
113
      <TableColumn key="delete-variant-item" />
114
    </>
115
  );
116

117
  const [childrenProps, setChildrenProps] = useState<Partial<VariantItemPropTypes>[]>(
864✔
118
    Children.map(children, (child) => {
119
      if (!isValidElement(child)) {
2,427!
UNCOV
120
        return {};
×
121
      }
122
      return child.props;
2,427✔
123
    })
124
  );
125
  useEffect(() => {
864✔
126
    setChildrenProps(
154✔
127
      Children.map(children, (child) => {
128
        if (!isValidElement(child)) {
457!
UNCOV
129
          return {};
×
130
        }
131
        return child.props;
457✔
132
      })
133
    );
134
  }, [children]);
135

136
  const [filteredProps, setFilteredProps] = useState(childrenProps);
864✔
137
  useEffect(() => {
864!
138
    setFilteredProps(childrenProps);
256✔
139
  }, [childrenProps]);
×
140

141
  const [defaultView, setDefaultView] = useState<string>();
864✔
142

143
  const changedTableRows = useRef({});
864✔
144
  const handleTableRowChange = (e, payload) => {
864✔
145
    if (payload) {
260✔
146
      changedTableRows.current[payload.currentVariant] = {
260✔
147
        ...(changedTableRows.current[payload.currentVariant] ?? {}),
300✔
148
        ...payload
149
      };
150
    }
151
  };
×
152
  const deletedTableRows = useRef(new Set([]));
864✔
153
  const handleDelete = (e) => {
864✔
154
    deletedTableRows.current.add(e.target.dataset.children);
8✔
155
    setChildrenProps((prev) =>
8✔
156
      prev
8✔
157
        .filter((item) => item.children !== e.target.dataset.children)
20✔
158
        .map((item) => {
159
          if (changedTableRows.current.hasOwnProperty(item.children)) {
12!
UNCOV
160
            return { ...item, ...changedTableRows.current[item.children] };
×
161
          }
162
          return item;
12✔
163
        })
164
    );
165
  };
166

167
  const handleSave = (e) => {
864✔
168
    if (Object.keys(invalidVariants).length === 0) {
69✔
169
      handleSaveManageViews(e, {
48✔
170
        updatedRows: changedTableRows.current,
171
        defaultView,
172
        deletedRows: deletedTableRows.current
×
173
      });
174
    } else {
175
      Object.values(invalidVariants)[0].focus();
21✔
176
    }
177
  };
178

179
  const handleClose = (e) => {
864✔
180
    if (e.detail.escPressed) {
15!
181
      handleCancel(e);
15✔
182
    } else {
183
      onAfterClose(e);
184
    }
185
  };
186

187
  const handleCancel = (e) => {
864✔
188
    if (typeof onManageViewsCancel === 'function') {
46✔
189
      onManageViewsCancel(
30✔
190
        enrichEventWithDetails(e, {
191
          invalidVariants
192
        })
193
      );
194
    }
195
    setInvalidVariants((prev) => {
46✔
UNCOV
196
      Object.values(prev).forEach((item) => {
×
197
        item.isInvalid = false;
×
198
      });
199
      return {};
200
    });
201
    onAfterClose(e);
46!
202
  };
203

204
  const handleSearchInput = (e) => {
864✔
205
    const lowerCaseVal = e.target.value.toLowerCase();
NEW
206
    setFilteredProps(
×
207
      childrenProps.filter(
208
        (item) =>
209
          item.children?.toLowerCase()?.includes(lowerCaseVal) || item.author?.toLowerCase()?.includes(lowerCaseVal)
×
210
      )
211
    );
212
  };
213

214
  const canRenderPortal = useCanRenderPortal();
864✔
215
  if (!canRenderPortal) {
864✔
216
    return null;
94✔
217
  }
218

219
  return createPortal(
770✔
220
    <Dialog
221
      open
222
      className={classNames.manageViewsDialog}
223
      data-component-name="VariantManagementManageViewsDialog"
224
      onClose={onAfterClose}
225
      onBeforeClose={handleClose}
226
      headerText={manageViewsText}
227
      initialFocus={`search-${uniqueId}`}
228
      header={
229
        <FlexBox direction={FlexBoxDirection.Column} style={{ width: '100%' }} alignItems={FlexBoxAlignItems.Center}>
230
          <h2 className={classNames.headerText}>{manageViewsText}</h2>
231
          <Input
232
            id={`search-${uniqueId}`}
233
            className={classNames.search}
234
            placeholder={searchText}
235
            showClearIcon
236
            icon={<Icon name={searchIcon} className={classNames.inputIcon} />}
237
            onInput={handleSearchInput}
238
          />
239
        </FlexBox>
240
      }
241
      resizable
242
      footer={
243
        <Bar
244
          design={BarDesign.Footer}
245
          endContent={
246
            <>
247
              <Button design={ButtonDesign.Emphasized} onClick={handleSave}>
248
                {saveText}
249
              </Button>
250
              <Button design={ButtonDesign.Transparent} onClick={handleCancel}>
251
                {cancelText}
252
              </Button>
253
            </>
254
          }
255
        />
256
      }
257
    >
258
      <Table columns={columns} stickyColumnHeader role="table">
259
        {filteredProps.map((itemProps) => {
260
          return (
2,074✔
261
            <ManageViewsTableRows
262
              {...itemProps}
263
              setInvalidVariants={setInvalidVariants}
264
              setChangedVariantNames={setChangedVariantNames}
265
              changedVariantNames={changedVariantNames}
266
              variantNames={variantNames}
267
              handleRowChange={handleTableRowChange}
268
              handleDelete={handleDelete}
269
              defaultView={defaultView}
270
              setDefaultView={setDefaultView}
271
              showShare={showShare}
272
              showApplyAutomatically={showApplyAutomatically}
273
              showSetAsDefault={showSetAsDefault}
274
              showCreatedBy={showCreatedBy}
275
              key={itemProps?.children}
276
              showOnlyFavorites={showOnlyFavorites}
277
            />
278
          );
279
        })}
280
      </Table>
281
    </Dialog>,
282
    portalContainer ?? document.body
1,540✔
283
  );
284
};
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