@centreon/ui 26.12.10 → 26.12.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centreon/ui",
3
- "version": "26.12.10",
3
+ "version": "26.12.12",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "update:deps": "pnpx npm-check-updates -i --format group",
@@ -0,0 +1,17 @@
1
+ import type { SvgIconProps } from '@mui/material';
2
+
3
+ import type { ReactElement } from 'react';
4
+
5
+ import BaseIcon from './BaseIcon';
6
+
7
+ // Material Symbols "password". MUI only ships the asterisk version.
8
+ const icon = (
9
+ <path
10
+ d="M3 6C2.16667 6 1.45833 5.70833 0.875 5.125C0.291667 4.54167 0 3.83333 0 3C0 2.16667 0.291667 1.45833 0.875 0.875C1.45833 0.291667 2.16667 0 3 0C3.83333 0 4.54167 0.291667 5.125 0.875C5.70833 1.45833 6 2.16667 6 3C6 3.83333 5.70833 4.54167 5.125 5.125C4.54167 5.70833 3.83333 6 3 6ZM1 12V10H21V12H1ZM8.875 5.125C8.29167 4.54167 8 3.83333 8 3C8 2.16667 8.29167 1.45833 8.875 0.875C9.45833 0.291667 10.1667 0 11 0C11.8333 0 12.5417 0.291667 13.125 0.875C13.7083 1.45833 14 2.16667 14 3C14 3.83333 13.7083 4.54167 13.125 5.125C12.5417 5.70833 11.8333 6 11 6C10.1667 6 9.45833 5.70833 8.875 5.125ZM16.875 5.125C16.2917 4.54167 16 3.83333 16 3C16 2.16667 16.2917 1.45833 16.875 0.875C17.4583 0.291667 18.1667 0 19 0C19.8333 0 20.5417 0.291667 21.125 0.875C21.7083 1.45833 22 2.16667 22 3C22 3.83333 21.7083 4.54167 21.125 5.125C20.5417 5.70833 19.8333 6 19 6C18.1667 6 17.4583 5.70833 16.875 5.125Z"
11
+ transform="translate(1 6)"
12
+ />
13
+ );
14
+
15
+ export const PasswordIcon = (props: SvgIconProps): ReactElement => (
16
+ <BaseIcon {...props} dataTestId="PasswordIcon" Icon={icon} />
17
+ );
@@ -0,0 +1,17 @@
1
+ import type { SvgIconProps } from '@mui/material';
2
+
3
+ import type { ReactElement } from 'react';
4
+
5
+ import BaseIcon from './BaseIcon';
6
+
7
+ // Material Symbols "password_off".
8
+ const icon = (
9
+ <path
10
+ d="M3 10.2C2.16667 10.2 1.45833 9.90833 0.875 9.325C0.291667 8.74167 0 8.03333 0 7.2C0 6.36667 0.291667 5.65833 0.875 5.075C1.45833 4.49167 2.16667 4.2 3 4.2C3.83333 4.2 4.54167 4.49167 5.125 5.075C5.70833 5.65833 6 6.36667 6 7.2C6 8.03333 5.70833 8.74167 5.125 9.325C4.54167 9.90833 3.83333 10.2 3 10.2ZM16.875 9.325C16.2917 8.74167 16 8.03333 16 7.2C16 6.36667 16.2917 5.65833 16.875 5.075C17.4583 4.49167 18.1667 4.2 19 4.2C19.8333 4.2 20.5417 4.49167 21.125 5.075C21.7083 5.65833 22 6.36667 22 7.2C22 8.03333 21.7083 8.74167 21.125 9.325C20.5417 9.90833 19.8333 10.2 19 10.2C18.1667 10.2 17.4583 9.90833 16.875 9.325ZM13.5 8.85L9.35 4.7C9.58333 4.53333 9.84167 4.40833 10.125 4.325C10.4083 4.24167 10.7 4.2 11 4.2C11.8333 4.2 12.5417 4.49167 13.125 5.075C13.7083 5.65833 14 6.36667 14 7.2C14 7.5 13.9583 7.79167 13.875 8.075C13.7917 8.35833 13.6667 8.61667 13.5 8.85ZM18.8 19.8L15.2 16.2H1V14.2H13.2L0.4 1.4L1.8 0L20.2 18.4L18.8 19.8Z"
11
+ transform="translate(1 2.1)"
12
+ />
13
+ );
14
+
15
+ export const PasswordOffIcon = (props: SvgIconProps): ReactElement => (
16
+ <BaseIcon {...props} dataTestId="PasswordOffIcon" Icon={icon} />
17
+ );
package/src/Icon/index.ts CHANGED
@@ -7,6 +7,8 @@ export { HostGroupIcon } from './HostGroupIcon';
7
7
  export { HostIcon } from './HostIcon';
8
8
  export { InstallCommandIcon } from './InstallCommandIcon';
9
9
  export { MetaServiceIcon } from './MetaServiceIcon';
10
+ export { PasswordIcon } from './PasswordIcon';
11
+ export { PasswordOffIcon } from './PasswordOffIcon';
10
12
  export { RegexIcon } from './RegexIcon';
11
13
  export { ServiceGroupIcon } from './ServiceGroupIcon';
12
14
  export { ServiceIcon } from './ServiceIcon';
@@ -82,6 +82,26 @@ const useStyles = makeStyles<StyleProps>()(
82
82
  })
83
83
  );
84
84
 
85
+ const defaultRowsPerPageOptions = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
86
+
87
+ // The page size can be any number (the platform setting is free), so it is
88
+ // added to the options when missing, for the selector to show it. `Number`
89
+ // because `onLimitChange` is typed `string | number`, so a consumer may store a
90
+ // string limit.
91
+ const getRowsPerPageOptions = (limit: number | string): Array<number> => {
92
+ const rowsPerPage = Number(limit);
93
+
94
+ if (
95
+ !Number.isInteger(rowsPerPage) ||
96
+ rowsPerPage <= 0 ||
97
+ defaultRowsPerPageOptions.includes(rowsPerPage)
98
+ ) {
99
+ return defaultRowsPerPageOptions;
100
+ }
101
+
102
+ return [...defaultRowsPerPageOptions, rowsPerPage].sort((a, b) => a - b);
103
+ };
104
+
85
105
  type Props = Pick<
86
106
  ListingProps<unknown>,
87
107
  | 'actions'
@@ -287,7 +307,7 @@ const MemoListingActionBar = ({
287
307
  onRowsPerPageChange={changeRowPerPage}
288
308
  page={currentPage ?? 0}
289
309
  rowsPerPage={limit ?? 10}
290
- rowsPerPageOptions={[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]}
310
+ rowsPerPageOptions={getRowsPerPageOptions(limit ?? 10)}
291
311
  SelectProps={{
292
312
  id: labelRowsPerPage,
293
313
  MenuProps: {
@@ -473,4 +473,100 @@ describe('Listing', () => {
473
473
  });
474
474
  expect(onRowClick).not.toHaveBeenCalled();
475
475
  });
476
+
477
+ describe('Rows per page', () => {
478
+ const defaultOptions = [
479
+ '10',
480
+ '20',
481
+ '30',
482
+ '40',
483
+ '50',
484
+ '60',
485
+ '70',
486
+ '80',
487
+ '90',
488
+ '100'
489
+ ];
490
+
491
+ const openRowsPerPage = async (limit: number): Promise<HTMLElement> => {
492
+ render(
493
+ <Listing
494
+ columns={defaultColumn}
495
+ currentPage={0}
496
+ limit={limit}
497
+ rows={listingWithSubItems3Rows}
498
+ totalRows={3}
499
+ />
500
+ );
501
+
502
+ const rowsPerPage = within(
503
+ await screen.findByTestId('Listing Pagination')
504
+ ).getByRole('combobox');
505
+
506
+ expect(rowsPerPage).toHaveTextContent(new RegExp(`^${limit}$`));
507
+
508
+ await userEvent.click(rowsPerPage);
509
+
510
+ return screen.findByRole('listbox');
511
+ };
512
+
513
+ const getOptionLabels = (listbox: HTMLElement): Array<string | null> =>
514
+ within(listbox)
515
+ .getAllByRole('option')
516
+ .map((option) => option.textContent);
517
+
518
+ it.each([
519
+ {
520
+ limit: 25,
521
+ options: [
522
+ '10',
523
+ '20',
524
+ '25',
525
+ '30',
526
+ '40',
527
+ '50',
528
+ '60',
529
+ '70',
530
+ '80',
531
+ '90',
532
+ '100'
533
+ ]
534
+ },
535
+ {
536
+ limit: 150,
537
+ options: [
538
+ '10',
539
+ '20',
540
+ '30',
541
+ '40',
542
+ '50',
543
+ '60',
544
+ '70',
545
+ '80',
546
+ '90',
547
+ '100',
548
+ '150'
549
+ ]
550
+ }
551
+ ])(
552
+ 'adds the page size $limit to the options when it is not one of them',
553
+ async ({ limit, options }) => {
554
+ const listbox = await openRowsPerPage(limit);
555
+
556
+ expect(getOptionLabels(listbox)).toEqual(options);
557
+ expect(
558
+ within(listbox).getByRole('option', { name: `${limit}` })
559
+ ).toHaveAttribute('aria-selected', 'true');
560
+ }
561
+ );
562
+
563
+ it('keeps the default options when the page size is one of them', async () => {
564
+ const listbox = await openRowsPerPage(30);
565
+
566
+ expect(getOptionLabels(listbox)).toEqual(defaultOptions);
567
+ expect(
568
+ within(listbox).getByRole('option', { name: '30' })
569
+ ).toHaveAttribute('aria-selected', 'true');
570
+ });
571
+ });
476
572
  });
@@ -1,4 +1,4 @@
1
- import DeleteIcon from '@mui/icons-material/Delete';
1
+ import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
2
2
  import DragIndicatorIcon from '@mui/icons-material/DragIndicator';
3
3
 
4
4
  import { useSortable } from '@dnd-kit/sortable';
@@ -96,7 +96,7 @@ export const Row = <T,>({
96
96
  <RowButton
97
97
  className="text-error-main"
98
98
  data-testid="delete-row"
99
- icon={<DeleteIcon />}
99
+ icon={<DeleteOutlineIcon />}
100
100
  label={t(labelDelete)}
101
101
  onClick={(): void => onDelete(id)}
102
102
  />