@centreon/ui 23.10.32 → 23.10.33

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.
Files changed (89) hide show
  1. package/package.json +12 -2
  2. package/src/Dashboard/DashboardLayout.stories.tsx +3 -5
  3. package/src/Dashboard/Layout.tsx +4 -4
  4. package/src/Dashboard/utils.ts +28 -28
  5. package/src/ThemeProvider/index.tsx +6 -5
  6. package/src/ThemeProvider/palettes.ts +389 -215
  7. package/src/api/TestQueryProvider.tsx +2 -1
  8. package/src/api/useFetchQuery/index.ts +8 -7
  9. package/src/api/useMutationQuery/index.ts +11 -10
  10. package/src/base/tokens/README.md +3 -0
  11. package/src/base/tokens/source/$metadata.json +5 -0
  12. package/src/base/tokens/source/base.json +142 -0
  13. package/src/base/tokens/themes/base.tokens.d.ts +38 -0
  14. package/src/base/tokens/themes/base.tokens.json +695 -0
  15. package/src/base/tokens/themes/base.tokens.ts +38 -0
  16. package/src/base/tokens/themes/ui-dark.tokens.d.ts +38 -0
  17. package/src/base/tokens/themes/ui-dark.tokens.json +695 -0
  18. package/src/base/tokens/themes/ui-dark.tokens.ts +38 -0
  19. package/src/base/tokens/themes/ui-light.tokens.d.ts +38 -0
  20. package/src/base/tokens/themes/ui-light.tokens.json +695 -0
  21. package/src/base/tokens/themes/ui-light.tokens.ts +38 -0
  22. package/src/components/Button/Button.styles.ts +17 -3
  23. package/src/components/Button/Button.tsx +6 -3
  24. package/src/components/Button/Icon/IconButton.styles.ts +9 -2
  25. package/src/components/DataTable/DataTable.stories.tsx +9 -0
  26. package/src/components/DataTable/DataTable.styles.ts +5 -0
  27. package/src/components/DataTable/DataTable.tsx +8 -6
  28. package/src/components/DataTable/EmptyState/DataTableEmptyState.tsx +4 -1
  29. package/src/components/DataTable/Item/DataTableItem.styles.ts +5 -2
  30. package/src/components/DataTable/Item/DataTableItem.tsx +36 -18
  31. package/src/components/Header/Header.styles.ts +0 -27
  32. package/src/components/Header/PageHeader/PageHeader.stories.tsx +88 -0
  33. package/src/components/Header/PageHeader/PageHeader.styles.ts +99 -0
  34. package/src/components/Header/PageHeader/PageHeader.tsx +15 -0
  35. package/src/components/Header/PageHeader/PageHeaderActions.tsx +17 -0
  36. package/src/components/Header/PageHeader/PageHeaderMain.tsx +15 -0
  37. package/src/components/Header/PageHeader/PageHeaderMenu.tsx +15 -0
  38. package/src/components/Header/PageHeader/PageHeaderTitle.tsx +47 -0
  39. package/src/components/Header/PageHeader/index.ts +12 -0
  40. package/src/components/Header/index.ts +1 -1
  41. package/src/components/Layout/AreaIndicator.styles.ts +33 -0
  42. package/src/components/Layout/AreaIndicator.tsx +35 -0
  43. package/src/components/Layout/PageLayout/PageLayout.stories.tsx +81 -0
  44. package/src/components/Layout/PageLayout/PageLayout.styles.ts +40 -0
  45. package/src/components/Layout/PageLayout/PageLayout.tsx +21 -0
  46. package/src/components/Layout/PageLayout/PageLayoutActions.tsx +15 -0
  47. package/src/components/Layout/PageLayout/PageLayoutBody.tsx +24 -0
  48. package/src/components/Layout/PageLayout/PageLayoutHeader.tsx +15 -0
  49. package/src/components/Layout/PageLayout/index.ts +10 -0
  50. package/src/components/Layout/index.ts +1 -0
  51. package/src/components/Menu/Button/MenuButton.stories.tsx +16 -0
  52. package/src/components/Menu/Button/MenuButton.styles.ts +27 -0
  53. package/src/components/Menu/Button/MenuButton.tsx +62 -0
  54. package/src/components/Menu/Button/index.ts +1 -0
  55. package/src/components/Menu/Menu.stories.tsx +71 -0
  56. package/src/components/Menu/Menu.styles.ts +70 -0
  57. package/src/components/Menu/Menu.tsx +25 -0
  58. package/src/components/Menu/MenuDivider.tsx +13 -0
  59. package/src/components/Menu/MenuItem.tsx +36 -0
  60. package/src/components/Menu/MenuItems.tsx +35 -0
  61. package/src/components/Menu/index.ts +12 -0
  62. package/src/components/Menu/useMenu.tsx +79 -0
  63. package/src/components/Modal/index.ts +2 -0
  64. package/src/components/Tooltip/TextOverflowTooltip/TextOverflowTooltip.stories.tsx +70 -0
  65. package/src/components/Tooltip/TextOverflowTooltip/TextOverflowTooltip.styles.ts +5 -0
  66. package/src/components/Tooltip/TextOverflowTooltip/TextOverflowTooltip.tsx +115 -0
  67. package/src/components/Tooltip/TextOverflowTooltip/index.tsx +1 -0
  68. package/src/components/Tooltip/Tooltip.stories.tsx +41 -0
  69. package/src/components/Tooltip/Tooltip.styles.ts +5 -0
  70. package/src/components/Tooltip/Tooltip.tsx +46 -0
  71. package/src/components/Tooltip/index.ts +1 -0
  72. package/src/components/index.ts +3 -0
  73. package/src/index.ts +0 -2
  74. package/src/screens/dashboard/DashboardsDetail.stories.tsx +108 -0
  75. package/src/screens/dashboard/DashboardsOverview.stories.tsx +110 -102
  76. package/src/styles/tokens/themes/_ui-dark.tokens.json +695 -0
  77. package/src/styles/tokens/themes/_ui-light.tokens.json +695 -0
  78. package/src/utils/index.ts +1 -1
  79. package/src/utils/sanitizedHTML.ts +1 -1
  80. package/src/utils/useResizeObserver.ts +6 -0
  81. package/test/setupTests.js +1 -1
  82. package/src/components/Header/Header.stories.tsx +0 -27
  83. package/src/components/Header/Header.tsx +0 -23
  84. package/src/layout/TiledListingPage/TiledListingActions.tsx +0 -15
  85. package/src/layout/TiledListingPage/TiledListingContent.tsx +0 -21
  86. package/src/layout/TiledListingPage/TiledListingList.tsx +0 -11
  87. package/src/layout/TiledListingPage/TiledListingPage.styles.ts +0 -16
  88. package/src/layout/TiledListingPage/TiledListingPage.tsx +0 -15
  89. package/src/layout/TiledListingPage/index.ts +0 -4
@@ -0,0 +1,79 @@
1
+ import { ReactElement, ReactNode, useRef } from 'react';
2
+
3
+ import {
4
+ atom,
5
+ createStore,
6
+ useAtom,
7
+ Provider,
8
+ useStore,
9
+ useAtomValue
10
+ } from 'jotai';
11
+ import { useHydrateAtoms } from 'jotai/utils';
12
+
13
+ /** state */
14
+
15
+ const isMenuOpenAtom = atom(false);
16
+ const anchorElAtom = atom<null | HTMLElement>(null);
17
+ const onOpenAtom = atom<(() => void) | null>(null);
18
+ const onCloseAtom = atom<(() => void) | null>(null);
19
+
20
+ /** provider */
21
+
22
+ type MenuProviderProps = {
23
+ children: ReactNode;
24
+ initialIsOpen?: boolean;
25
+ onClose?: () => void;
26
+ onOpen?: () => void;
27
+ };
28
+
29
+ const MenuProvider = ({
30
+ children,
31
+ initialIsOpen,
32
+ onOpen,
33
+ onClose
34
+ }: MenuProviderProps): ReactElement => {
35
+ const menuStore = useRef(createStore()).current;
36
+
37
+ useHydrateAtoms(
38
+ [
39
+ [isMenuOpenAtom, initialIsOpen ?? false],
40
+ [anchorElAtom, null],
41
+ [onOpenAtom, onOpen],
42
+ [onCloseAtom, onClose]
43
+ ],
44
+ { store: menuStore }
45
+ );
46
+
47
+ return <Provider store={menuStore}>{children}</Provider>;
48
+ };
49
+
50
+ /** hook */
51
+
52
+ type UseMenu = {
53
+ anchorEl: null | HTMLElement;
54
+ isMenuOpen: boolean;
55
+ onClose: (() => void) | null;
56
+ onOpen: (() => void) | null;
57
+ setAnchorEl: (event: null | HTMLElement) => void;
58
+ setIsMenuOpen: (isOpen: boolean | ((currentIsMenuOpen) => boolean)) => void;
59
+ };
60
+
61
+ const useMenu = (): UseMenu => {
62
+ const store = useStore();
63
+
64
+ const [isMenuOpen, setIsMenuOpen] = useAtom(isMenuOpenAtom, { store });
65
+ const [anchorEl, setAnchorEl] = useAtom(anchorElAtom, { store });
66
+ const onOpen = useAtomValue(onOpenAtom, { store });
67
+ const onClose = useAtomValue(onCloseAtom, { store });
68
+
69
+ return {
70
+ anchorEl,
71
+ isMenuOpen,
72
+ onClose,
73
+ onOpen,
74
+ setAnchorEl,
75
+ setIsMenuOpen
76
+ };
77
+ };
78
+
79
+ export { useMenu, MenuProvider };
@@ -8,3 +8,5 @@ export const Modal = Object.assign(ModalRoot, {
8
8
  Body: ModalBody,
9
9
  Header: ModalHeader
10
10
  });
11
+
12
+ export type { ModalActionsLabels } from './ModalActions';
@@ -0,0 +1,70 @@
1
+ /* eslint-disable react-hooks/rules-of-hooks */
2
+ import { useEffect, useState } from 'react';
3
+
4
+ import { Meta, StoryObj } from '@storybook/react';
5
+
6
+ import { TextOverflowTooltip } from './TextOverflowTooltip';
7
+
8
+ const meta: Meta<typeof TextOverflowTooltip> = {
9
+ args: {},
10
+ component: TextOverflowTooltip,
11
+ parameters: {
12
+ layout: 'centered'
13
+ }
14
+ };
15
+
16
+ export default meta;
17
+ type Story = StoryObj<typeof TextOverflowTooltip>;
18
+
19
+ export const Default: Story = {
20
+ args: {
21
+ label:
22
+ 'Qui deserunt pariatur quis. Duis nisi velit culpa labore ipsum reprehenderit sunt laborum anim sint quis magna consequat amet. Voluptate tempor nostrud eiusmod enim qui reprehenderit.'
23
+ },
24
+ render: ({ label, ...args }) => {
25
+ const [labelValue, setLabelValue] = useState(label);
26
+ useEffect(() => setLabelValue(label), [label]);
27
+
28
+ return (
29
+ <TextOverflowTooltip {...args} data-testid="tooltip" label={labelValue}>
30
+ <p
31
+ data-testid="paragraph"
32
+ style={{
33
+ overflow: 'hidden',
34
+ textOverflow: 'ellipsis',
35
+ whiteSpace: 'nowrap',
36
+ width: '40vw'
37
+ }}
38
+ >
39
+ {labelValue}
40
+ </p>
41
+ </TextOverflowTooltip>
42
+ );
43
+ }
44
+ };
45
+
46
+ export const AsMultiLine: Story = {
47
+ args: {
48
+ ...Default.args
49
+ },
50
+ render: ({ label, ...args }) => {
51
+ const [labelValue, setLabelValue] = useState(label);
52
+ useEffect(() => setLabelValue(label), [label]);
53
+
54
+ return (
55
+ <TextOverflowTooltip {...args} label={labelValue}>
56
+ <p
57
+ style={{
58
+ WebkitBoxOrient: 'vertical',
59
+ WebkitLineClamp: '2',
60
+ display: '-webkit-box',
61
+ overflow: 'hidden',
62
+ width: '40vw'
63
+ }}
64
+ >
65
+ {labelValue}
66
+ </p>
67
+ </TextOverflowTooltip>
68
+ );
69
+ }
70
+ };
@@ -0,0 +1,5 @@
1
+ import { makeStyles } from 'tss-react/mui';
2
+
3
+ export const useStyles = makeStyles()(() => ({
4
+ textOverflowTooltip: {}
5
+ }));
@@ -0,0 +1,115 @@
1
+ import { ReactElement, useCallback, useEffect, useRef } from 'react';
2
+
3
+ import { atom, useAtom } from 'jotai';
4
+
5
+ import { Tooltip, TooltipProps } from '../Tooltip';
6
+ import { useResizeObserver } from '../../../utils/useResizeObserver';
7
+
8
+ import { useStyles } from './TextOverflowTooltip.styles';
9
+
10
+ type TextOverflowTooltipProps = Omit<TooltipProps, 'followCursor' | 'hasCaret'>;
11
+
12
+ /** @description
13
+ * This component is used to display a tooltip when the text is too long, and displays the full text on hover.
14
+ *
15
+ * It's up to the child component to define it's `width` / `max-width`, and ellipsis.
16
+ *
17
+ * For single lines use :
18
+ * ```
19
+ * width: var(--width-of-the-text);
20
+ * white-space: nowrap;
21
+ * ```
22
+ *
23
+ * For multi-lines use :
24
+ * ```
25
+ * width: var(--width-of-the-text);
26
+ * display: -webkit-box;
27
+ * -webkit-box-orient: vertical;
28
+ * -webkit-line-clamp: var(--max-lines-of-the-text);
29
+ * ```
30
+ */
31
+
32
+ const TextOverflowTooltip = ({
33
+ children,
34
+ label,
35
+ position = 'bottom',
36
+ isOpen,
37
+ ...tooltipProps
38
+ }: TextOverflowTooltipProps): ReactElement => {
39
+ const { classes } = useStyles();
40
+
41
+ const stateAtom = useRef(
42
+ atom<{
43
+ hasOverflow: boolean;
44
+ isOpen: boolean;
45
+ }>({ hasOverflow: false, isOpen: false })
46
+ ).current;
47
+
48
+ const [state, setState] = useAtom(stateAtom);
49
+
50
+ const onMouseEnter = useCallback(
51
+ () =>
52
+ state.hasOverflow &&
53
+ setState({
54
+ ...state,
55
+ isOpen: true
56
+ }),
57
+ [state.hasOverflow]
58
+ );
59
+
60
+ const onMouseLeave = useCallback(
61
+ () =>
62
+ state.hasOverflow &&
63
+ setState({
64
+ ...state,
65
+ isOpen: false
66
+ }),
67
+ [state.hasOverflow]
68
+ );
69
+
70
+ const elRef = useRef<HTMLDivElement>(null);
71
+
72
+ const onResize = (): void => {
73
+ const { firstElementChild: el } = elRef.current || {};
74
+ if (el instanceof HTMLElement) {
75
+ setState({
76
+ ...state,
77
+ hasOverflow:
78
+ el.scrollWidth > el.offsetWidth || el.scrollHeight > el.offsetHeight
79
+ });
80
+ }
81
+ };
82
+
83
+ useResizeObserver({
84
+ onResize,
85
+ ref: elRef
86
+ });
87
+
88
+ useEffect(() => {
89
+ if (isOpen) setState({ ...state, isOpen });
90
+ onResize();
91
+ }, [isOpen, label]);
92
+
93
+ return (
94
+ <Tooltip
95
+ followCursor
96
+ hasCaret={false}
97
+ isOpen={state.isOpen}
98
+ label={label}
99
+ position={position}
100
+ {...tooltipProps}
101
+ >
102
+ <div
103
+ className={classes.textOverflowTooltip}
104
+ data-has-overflow={state.hasOverflow}
105
+ ref={elRef}
106
+ onMouseEnter={onMouseEnter}
107
+ onMouseLeave={onMouseLeave}
108
+ >
109
+ {children}
110
+ </div>
111
+ </Tooltip>
112
+ );
113
+ };
114
+
115
+ export { TextOverflowTooltip };
@@ -0,0 +1 @@
1
+ export * from './TextOverflowTooltip';
@@ -0,0 +1,41 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+
3
+ import { Info as InfoIcon } from '@mui/icons-material';
4
+
5
+ import { Tooltip } from './Tooltip';
6
+
7
+ const meta: Meta<typeof Tooltip> = {
8
+ argTypes: {
9
+ position: {
10
+ control: {
11
+ options: ['top', 'bottom', 'left', 'right']
12
+ }
13
+ }
14
+ },
15
+ component: Tooltip,
16
+ parameters: {
17
+ layout: 'centered'
18
+ }
19
+ };
20
+
21
+ export default meta;
22
+ type Story = StoryObj<typeof Tooltip>;
23
+
24
+ export const Default: Story = {
25
+ args: {
26
+ children: <InfoIcon />,
27
+ label: 'Tooltip content'
28
+ }
29
+ };
30
+
31
+ export const WrappedContent: Story = {
32
+ args: {
33
+ children: <InfoIcon />,
34
+ followCursor: false,
35
+ hasCaret: true,
36
+ isOpen: true,
37
+ label:
38
+ 'Qui deserunt pariatur quis. Duis nisi velit culpa labore ipsum reprehenderit sunt laborum anim sint quis magna consequat amet. Voluptate tempor nostrud eiusmod enim qui reprehenderit.',
39
+ position: 'right'
40
+ }
41
+ };
@@ -0,0 +1,5 @@
1
+ import { makeStyles } from 'tss-react/mui';
2
+
3
+ export const useStyles = makeStyles()(() => ({
4
+ tooltip: {}
5
+ }));
@@ -0,0 +1,46 @@
1
+ import { ReactElement, ReactNode } from 'react';
2
+
3
+ import { Tooltip as MuiTooltip } from '@mui/material';
4
+
5
+ import { AriaLabelingAttributes } from '../../@types/aria-attributes';
6
+ import { DataTestAttributes } from '../../@types/data-attributes';
7
+
8
+ import { useStyles } from './Tooltip.styles';
9
+
10
+ export type TooltipProps = {
11
+ children: ReactElement;
12
+ followCursor?: boolean;
13
+ hasCaret?: boolean;
14
+ isOpen?: boolean;
15
+ label: ReactNode;
16
+ position?: 'top' | 'bottom' | 'left' | 'right';
17
+ } & AriaLabelingAttributes &
18
+ DataTestAttributes;
19
+
20
+ const Tooltip = ({
21
+ children,
22
+ label,
23
+ position = 'bottom',
24
+ followCursor = true,
25
+ isOpen,
26
+ hasCaret = false,
27
+ ...attr
28
+ }: TooltipProps): ReactElement => {
29
+ const { classes } = useStyles();
30
+
31
+ return (
32
+ <MuiTooltip
33
+ arrow={hasCaret}
34
+ className={classes.tooltip}
35
+ followCursor={followCursor}
36
+ open={isOpen}
37
+ placement={position}
38
+ title={label}
39
+ {...attr}
40
+ >
41
+ {children}
42
+ </MuiTooltip>
43
+ );
44
+ };
45
+
46
+ export { Tooltip };
@@ -0,0 +1 @@
1
+ export * from './Tooltip';
@@ -3,3 +3,6 @@ export * from './Modal';
3
3
  export * from './Form';
4
4
  export * from './Header';
5
5
  export * from './DataTable';
6
+ export * from './Layout';
7
+ export * from './Tooltip';
8
+ export * from './Menu';
package/src/index.ts CHANGED
@@ -140,8 +140,6 @@ export { default as ActionsList } from './ActionsList';
140
140
 
141
141
  export type { ResponseError, CatchErrorProps } from './api/customFetch';
142
142
 
143
- export * from './layout/TiledListingPage';
144
-
145
143
  export * from './utils';
146
144
  export { default as FluidTypography } from './Typography/FluidTypography';
147
145
  export * from './Dashboard';
@@ -0,0 +1,108 @@
1
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
+ import React, { ReactElement } from 'react';
3
+
4
+ import { Meta } from '@storybook/react';
5
+
6
+ import {
7
+ Add as AddIcon,
8
+ Settings as SettingsIcon,
9
+ Share as ShareIcon
10
+ } from '@mui/icons-material';
11
+
12
+ import {
13
+ Button,
14
+ IconButton,
15
+ Menu,
16
+ PageHeader,
17
+ PageLayout
18
+ } from '../../components';
19
+
20
+ const meta: Meta = {
21
+ args: {
22
+ actions: {}
23
+ },
24
+ parameters: {
25
+ layout: 'fullscreen'
26
+ },
27
+ title: 'screens/Dashboards detail'
28
+ };
29
+
30
+ export default meta;
31
+
32
+ const DefaultView = (args): ReactElement => {
33
+ const { data } = args;
34
+
35
+ return (
36
+ <PageLayout>
37
+ <PageLayout.Header>
38
+ <PageHeader>
39
+ <PageHeader.Main>
40
+ <PageHeader.Menu>
41
+ <Menu>
42
+ <Menu.Button />
43
+ <Menu.Items>
44
+ <Menu.Item>Menu Item</Menu.Item>
45
+ <Menu.Item>Menu Item</Menu.Item>
46
+ <Menu.Item>Menu Item</Menu.Item>
47
+ <Menu.Divider />
48
+ <Menu.Item>
49
+ <Button
50
+ icon={<AddIcon />}
51
+ iconVariant="start"
52
+ variant="ghost"
53
+ >
54
+ Add item
55
+ </Button>
56
+ </Menu.Item>
57
+ </Menu.Items>
58
+ </Menu>
59
+ </PageHeader.Menu>
60
+ <PageHeader.Title
61
+ description={data.dashboard.description}
62
+ title={data.dashboard.name}
63
+ />
64
+ </PageHeader.Main>
65
+ </PageHeader>
66
+ </PageLayout.Header>
67
+ <PageLayout.Body>
68
+ <PageLayout.Actions>
69
+ <IconButton
70
+ aria-label="edit"
71
+ data-testid="edit"
72
+ icon={<SettingsIcon />}
73
+ size="small"
74
+ variant="ghost"
75
+ />
76
+ <IconButton
77
+ aria-label="share"
78
+ data-testid="share"
79
+ icon={<ShareIcon />}
80
+ size="small"
81
+ variant="ghost"
82
+ />
83
+ </PageLayout.Actions>
84
+ </PageLayout.Body>
85
+ </PageLayout>
86
+ );
87
+ };
88
+
89
+ export const Default = {
90
+ args: {
91
+ data: {
92
+ dashboard: {
93
+ description:
94
+ 'Description et culpa sit commodo ea enim excepteur elit. Velit irure velit tempor culpa commodo eu adipisicing eu proident ullamco.',
95
+ id: 1,
96
+ name: 'Dashboard 1'
97
+ }
98
+ }
99
+ },
100
+ render: DefaultView
101
+ };
102
+
103
+ export const AsEditLayoutState = {
104
+ args: {
105
+ ...Default.args
106
+ },
107
+ render: DefaultView
108
+ };