@centreon/ui 23.10.20 → 23.10.21-MON-19322-dashboard-pages-layout-component.0

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": "23.10.20",
3
+ "version": "23.10.21-MON-19322-dashboard-pages-layout-component.0",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "eslint": "eslint ./src --ext .js,.jsx,.ts,.tsx --max-warnings 0",
@@ -1,5 +1,3 @@
1
- import { ReactElement } from 'react';
2
-
3
1
  import { ComponentMeta } from '@storybook/react';
4
2
  import { Layout } from 'react-grid-layout';
5
3
 
@@ -62,18 +60,18 @@ const generateLayout = (maxElements: number): Array<CustomLayout> => {
62
60
  };
63
61
 
64
62
  interface DashboardTemplateProps {
65
- header?: ReactElement;
63
+ header?: JSX.Element;
66
64
  layout?: Array<CustomLayout>;
67
65
  }
68
66
 
69
- const Header = (): ReactElement => (
67
+ const Header = (): JSX.Element => (
70
68
  <Typography variant="body2">The title</Typography>
71
69
  );
72
70
 
73
71
  const DashboardTemplate = ({
74
72
  header,
75
73
  layout = dashboardLayout
76
- }: DashboardTemplateProps): ReactElement => (
74
+ }: DashboardTemplateProps): JSX.Element => (
77
75
  <DashboardLayout.Layout<CustomLayout> layout={layout}>
78
76
  {layout.map(({ i, content, shouldUseFluidTypography }) => (
79
77
  <DashboardLayout.Item header={header} key={i}>
@@ -1,4 +1,4 @@
1
- import { ReactElement, useEffect, useState } from 'react';
1
+ import { useEffect, useState } from 'react';
2
2
 
3
3
  import { Responsive } from '@visx/visx';
4
4
  import GridLayout, { Layout, WidthProvider } from 'react-grid-layout';
@@ -14,7 +14,7 @@ const ReactGridLayout = WidthProvider(GridLayout);
14
14
 
15
15
  interface DashboardLayoutProps<T> {
16
16
  changeLayout?: (newLayout: Array<Layout>) => void;
17
- children: Array<ReactElement>;
17
+ children: Array<JSX.Element>;
18
18
  displayGrid?: boolean;
19
19
  layout: Array<T>;
20
20
  }
@@ -24,7 +24,7 @@ const Layout = <T extends Layout>({
24
24
  changeLayout,
25
25
  displayGrid,
26
26
  layout
27
- }: DashboardLayoutProps<T>): ReactElement => {
27
+ }: DashboardLayoutProps<T>): JSX.Element => {
28
28
  const { classes } = useDashboardLayoutStyles();
29
29
 
30
30
  const [columns, setColumns] = useState(getColumnsFromScreenSize());
@@ -45,7 +45,7 @@ const Layout = <T extends Layout>({
45
45
  Component: (
46
46
  <ResponsiveHeight>
47
47
  <Responsive.ParentSize>
48
- {({ width, height }): ReactElement => (
48
+ {({ width, height }): JSX.Element => (
49
49
  <div className={classes.container}>
50
50
  {displayGrid && (
51
51
  <Grid columns={columns} height={height} width={width} />
@@ -1,28 +1,28 @@
1
- import { lt } from 'ramda';
2
- import { Layout } from 'react-grid-layout';
3
-
4
- export const maxColumns = 12;
5
- const minColumns = 1;
6
- const breakpoint = 768;
7
-
8
- export const rowHeight = 64;
9
-
10
- export const getIsSmallScreenSize = (): boolean =>
11
- lt(window.innerWidth, breakpoint);
12
-
13
- export const getColumnsFromScreenSize = (): number =>
14
- getIsSmallScreenSize() ? minColumns : maxColumns;
15
-
16
- export const getLayout = <T extends Layout>(layout: Array<T>): Array<T> => {
17
- const isSmallScreenSize = getIsSmallScreenSize();
18
- if (!isSmallScreenSize) {
19
- return layout;
20
- }
21
-
22
- return layout
23
- .sort((a, b) => a.x + a.y - (b.x + b.y))
24
- .map((widget) => ({
25
- ...widget,
26
- w: 1
27
- }));
28
- };
1
+ import { lt } from 'ramda';
2
+ import { Layout } from 'react-grid-layout';
3
+
4
+ export const maxColumns = 12;
5
+ const minColumns = 1;
6
+ const breakpoint = 768;
7
+
8
+ export const rowHeight = 64;
9
+
10
+ export const getIsSmallScreenSize = (): boolean =>
11
+ lt(window.innerWidth, breakpoint);
12
+
13
+ export const getColumnsFromScreenSize = (): number =>
14
+ getIsSmallScreenSize() ? minColumns : maxColumns;
15
+
16
+ export const getLayout = <T extends Layout>(layout: Array<T>): Array<T> => {
17
+ const isSmallScreenSize = getIsSmallScreenSize();
18
+ if (!isSmallScreenSize) {
19
+ return layout;
20
+ }
21
+
22
+ return layout
23
+ .sort((a, b) => a.x + a.y - (b.x + b.y))
24
+ .map((widget) => ({
25
+ ...widget,
26
+ w: 1
27
+ }));
28
+ };
@@ -1,201 +1,231 @@
1
- import { equals } from 'ramda';
2
-
3
- import { alpha, PaletteOptions } from '@mui/material';
4
-
5
- import { ThemeMode } from '@centreon/ui-context';
6
-
7
- declare module '@mui/material/styles/createPalette' {
8
- interface TypeAction {
9
- acknowledged: string;
10
- acknowledgedBackground: string;
11
- inDowntime: string;
12
- inDowntimeBackground: string;
13
- }
14
- }
15
-
16
- declare module '@mui/material/styles' {
17
- interface Palette {
18
- background: {
19
- default: string;
20
- listingHeader: string;
21
- paper: string;
22
- };
23
- pending: {
24
- contrastText: string;
25
- main: string;
26
- };
27
- statusBackground: StatusBackground;
28
- }
29
- interface StatusBackground {
30
- error: string;
31
- none: string;
32
- pending: string;
33
- success: string;
34
- unknown: string;
35
- warning: string;
36
- }
37
- interface PaletteOptions {
38
- pending: {
39
- contrastText: string;
40
- main: string;
41
- };
42
- statusBackground: StatusBackground;
43
- }
44
-
45
- interface TypeBackground {
46
- listingHeader: string;
47
- }
48
- }
49
-
50
- declare module '@mui/material/Button' {
51
- interface ButtonPropsColorOverrides {
52
- pending: true;
53
- }
54
- }
55
-
56
- declare module '@mui/material/Badge' {
57
- interface BadgePropsColorOverrides {
58
- pending: true;
59
- }
60
- }
61
-
62
- export const lightPalette: PaletteOptions = {
63
- action: {
64
- acknowledged: '#67532C',
65
- acknowledgedBackground: '#F5F1E9',
66
- activatedOpacity: 0.12,
67
- active: '#666666',
68
- disabled: '#999999',
69
- disabledBackground: 'rgba(0, 0, 0, 0.12)',
70
- focus: 'rgba(0, 0, 0, 0.12)',
71
- focusOpacity: 0.12,
72
- hover: 'rgba(0, 0, 0, 0.06)',
73
- hoverOpacity: 0.06,
74
- inDowntime: '#4B2352',
75
- inDowntimeBackground: '#F0E9F8',
76
- selected: 'rgba(102, 102, 102, 0.3)',
77
- selectedOpacity: 0.3
78
- },
79
- background: {
80
- default: '#F4F4F4',
81
- listingHeader: '#666666',
82
- paper: '#FFFFFF'
83
- },
84
- divider: '#E3E3E3',
85
- error: {
86
- contrastText: '#000',
87
- main: '#FF4A4A'
88
- },
89
- info: {
90
- contrastText: '#000',
91
- main: '#1588D1'
92
- },
93
- mode: ThemeMode.light,
94
- pending: {
95
- contrastText: '#000',
96
- main: '#1EBEB3'
97
- },
98
- primary: {
99
- contrastText: '#fff',
100
- dark: '#255891',
101
- light: '#cde7fc',
102
- main: '#2E68AA'
103
- },
104
- secondary: {
105
- contrastText: '#fff',
106
- main: '#C772D6'
107
- },
108
- statusBackground: {
109
- error: '#FF6666',
110
- none: alpha('#2E68AA', 0.1),
111
- pending: '#1EBEB3',
112
- success: '#88B922',
113
- unknown: '#E3E3E3',
114
- warning: '#FD9B27'
115
- },
116
- success: {
117
- contrastText: '#000',
118
- main: '#88B922'
119
- },
120
- text: {
121
- disabled: '#999999',
122
- primary: '#000000',
123
- secondary: '#666666'
124
- },
125
- warning: {
126
- contrastText: '#000',
127
- main: '#FD9B27'
128
- }
129
- };
130
-
131
- export const darkPalette: PaletteOptions = {
132
- action: {
133
- acknowledged: '#67532C',
134
- acknowledgedBackground: '#67532C',
135
- activatedOpacity: 0.3,
136
- active: '#B5B5B5',
137
- disabled: '#999999',
138
- disabledBackground: '#555555',
139
- focus: 'rgba(255, 255, 255, 0.30)',
140
- focusOpacity: 0.3,
141
- hover: 'rgba(255, 255, 255, 0.16)',
142
- hoverOpacity: 0.16,
143
- inDowntime: '#4B2352',
144
- inDowntimeBackground: '#4B2352',
145
- selected: 'rgba(255, 255, 255, 0.5)',
146
- selectedOpacity: 0.5
147
- },
148
- background: {
149
- default: '#4a4a4a',
150
- listingHeader: '#666666',
151
- paper: '#212121'
152
- },
153
- divider: '#666666',
154
- error: {
155
- contrastText: '#fff',
156
- main: '#D60101'
157
- },
158
- info: {
159
- contrastText: '#fff',
160
- main: '#1CA9F4'
161
- },
162
- mode: ThemeMode.dark,
163
- pending: {
164
- contrastText: '#fff',
165
- main: '#118077'
166
- },
167
- primary: {
168
- contrastText: '#000',
169
- dark: '#4974A5',
170
- light: '#8bbff9',
171
- main: '#6eaff8'
172
- },
173
- secondary: {
174
- contrastText: '#fff',
175
- main: '#7C1FA2'
176
- },
177
- statusBackground: {
178
- error: '#D60101',
179
- none: alpha('#2E68AA', 0.1),
180
- pending: '#118077',
181
- success: '#5F8118',
182
- unknown: '#666666',
183
- warning: '#C55400'
184
- },
185
- success: {
186
- contrastText: '#fff',
187
- main: '#5F8118'
188
- },
189
- text: {
190
- disabled: '#666666',
191
- primary: '#FFFFFF',
192
- secondary: '#CCCCCC'
193
- },
194
- warning: {
195
- contrastText: '#fff',
196
- main: '#C55400'
197
- }
198
- };
199
-
200
- export const getPalette = (mode: ThemeMode): PaletteOptions =>
201
- equals(mode, ThemeMode.dark) ? darkPalette : lightPalette;
1
+ import { equals } from 'ramda';
2
+
3
+ import { alpha, PaletteOptions } from '@mui/material';
4
+
5
+ import { ThemeMode } from '@centreon/ui-context';
6
+
7
+ declare module '@mui/material/styles/createPalette' {
8
+ interface TypeAction {
9
+ acknowledged: string;
10
+ acknowledgedBackground: string;
11
+ inDowntime: string;
12
+ inDowntimeBackground: string;
13
+ }
14
+ }
15
+
16
+ declare module '@mui/material/styles' {
17
+ interface Palette {
18
+ background: {
19
+ default: string;
20
+ listingHeader: string;
21
+ paper: string;
22
+ };
23
+ layout: TypeLayout;
24
+ pending: {
25
+ contrastText: string;
26
+ main: string;
27
+ };
28
+ statusBackground: StatusBackground;
29
+ }
30
+ interface StatusBackground {
31
+ error: string;
32
+ none: string;
33
+ pending: string;
34
+ success: string;
35
+ unknown: string;
36
+ warning: string;
37
+ }
38
+ interface PaletteOptions {
39
+ layout: TypeLayout;
40
+ pending: {
41
+ contrastText: string;
42
+ main: string;
43
+ };
44
+ statusBackground: StatusBackground;
45
+ }
46
+
47
+ interface TypeBackground {
48
+ listingHeader: string;
49
+ }
50
+
51
+ interface TypeLayout {
52
+ body: {
53
+ background: string;
54
+ };
55
+ header: {
56
+ background: string;
57
+ border: string;
58
+ };
59
+ }
60
+ }
61
+
62
+ declare module '@mui/material/Button' {
63
+ interface ButtonPropsColorOverrides {
64
+ pending: true;
65
+ }
66
+ }
67
+
68
+ declare module '@mui/material/Badge' {
69
+ interface BadgePropsColorOverrides {
70
+ pending: true;
71
+ }
72
+ }
73
+
74
+ export const lightPalette: PaletteOptions = {
75
+ action: {
76
+ acknowledged: '#67532C',
77
+ acknowledgedBackground: '#F5F1E9',
78
+ activatedOpacity: 0.12,
79
+ active: '#666666',
80
+ disabled: '#999999',
81
+ disabledBackground: 'rgba(0, 0, 0, 0.12)',
82
+ focus: 'rgba(0, 0, 0, 0.12)',
83
+ focusOpacity: 0.12,
84
+ hover: 'rgba(0, 0, 0, 0.06)',
85
+ hoverOpacity: 0.06,
86
+ inDowntime: '#4B2352',
87
+ inDowntimeBackground: '#F0E9F8',
88
+ selected: 'rgba(102, 102, 102, 0.3)',
89
+ selectedOpacity: 0.3
90
+ },
91
+ background: {
92
+ default: '#F4F4F4',
93
+ listingHeader: '#666666',
94
+ paper: '#FFFFFF'
95
+ },
96
+ divider: '#E3E3E3',
97
+ error: {
98
+ contrastText: '#000',
99
+ main: '#FF4A4A'
100
+ },
101
+ info: {
102
+ contrastText: '#000',
103
+ main: '#1588D1'
104
+ },
105
+ layout: {
106
+ body: {
107
+ background: '#F6F6F6'
108
+ },
109
+ header: {
110
+ background: '#FFFFFF',
111
+ border: '#E3E3E3'
112
+ }
113
+ },
114
+ mode: ThemeMode.light,
115
+ pending: {
116
+ contrastText: '#000',
117
+ main: '#1EBEB3'
118
+ },
119
+ primary: {
120
+ contrastText: '#fff',
121
+ dark: '#255891',
122
+ light: '#cde7fc',
123
+ main: '#2E68AA'
124
+ },
125
+ secondary: {
126
+ contrastText: '#fff',
127
+ main: '#C772D6'
128
+ },
129
+ statusBackground: {
130
+ error: '#FF6666',
131
+ none: alpha('#2E68AA', 0.1),
132
+ pending: '#1EBEB3',
133
+ success: '#88B922',
134
+ unknown: '#E3E3E3',
135
+ warning: '#FD9B27'
136
+ },
137
+ success: {
138
+ contrastText: '#000',
139
+ main: '#88B922'
140
+ },
141
+ text: {
142
+ disabled: '#999999',
143
+ primary: '#000000',
144
+ secondary: '#666666'
145
+ },
146
+ warning: {
147
+ contrastText: '#000',
148
+ main: '#FD9B27'
149
+ }
150
+ };
151
+
152
+ export const darkPalette: PaletteOptions = {
153
+ action: {
154
+ acknowledged: '#67532C',
155
+ acknowledgedBackground: '#67532C',
156
+ activatedOpacity: 0.3,
157
+ active: '#B5B5B5',
158
+ disabled: '#999999',
159
+ disabledBackground: '#555555',
160
+ focus: 'rgba(255, 255, 255, 0.30)',
161
+ focusOpacity: 0.3,
162
+ hover: 'rgba(255, 255, 255, 0.16)',
163
+ hoverOpacity: 0.16,
164
+ inDowntime: '#4B2352',
165
+ inDowntimeBackground: '#4B2352',
166
+ selected: 'rgba(255, 255, 255, 0.5)',
167
+ selectedOpacity: 0.5
168
+ },
169
+ background: {
170
+ default: '#4a4a4a',
171
+ listingHeader: '#666666',
172
+ paper: '#212121'
173
+ },
174
+ divider: '#666666',
175
+ error: {
176
+ contrastText: '#fff',
177
+ main: '#D60101'
178
+ },
179
+ info: {
180
+ contrastText: '#fff',
181
+ main: '#1CA9F4'
182
+ },
183
+ layout: {
184
+ body: {
185
+ background: '#F6F6F6'
186
+ },
187
+ header: {
188
+ background: '#FFFFFF',
189
+ border: '#E3E3E3'
190
+ }
191
+ },
192
+ mode: ThemeMode.dark,
193
+ pending: {
194
+ contrastText: '#fff',
195
+ main: '#118077'
196
+ },
197
+ primary: {
198
+ contrastText: '#000',
199
+ dark: '#4974A5',
200
+ light: '#8bbff9',
201
+ main: '#6eaff8'
202
+ },
203
+ secondary: {
204
+ contrastText: '#fff',
205
+ main: '#7C1FA2'
206
+ },
207
+ statusBackground: {
208
+ error: '#D60101',
209
+ none: alpha('#2E68AA', 0.1),
210
+ pending: '#118077',
211
+ success: '#5F8118',
212
+ unknown: '#666666',
213
+ warning: '#C55400'
214
+ },
215
+ success: {
216
+ contrastText: '#fff',
217
+ main: '#5F8118'
218
+ },
219
+ text: {
220
+ disabled: '#666666',
221
+ primary: '#FFFFFF',
222
+ secondary: '#CCCCCC'
223
+ },
224
+ warning: {
225
+ contrastText: '#fff',
226
+ main: '#C55400'
227
+ }
228
+ };
229
+
230
+ export const getPalette = (mode: ThemeMode): PaletteOptions =>
231
+ equals(mode, ThemeMode.dark) ? darkPalette : lightPalette;
@@ -12,7 +12,6 @@ const useStyles = makeStyles()((theme) => ({
12
12
  margin: theme.spacing(0, 0, 1.5, 0)
13
13
  },
14
14
  justifyContent: 'space-between',
15
- marginBottom: theme.spacing(2.5),
16
15
 
17
16
  nav: {
18
17
  display: 'flex',
@@ -0,0 +1,31 @@
1
+ import { makeStyles } from 'tss-react/mui';
2
+
3
+ export const useStyles = makeStyles()((theme) => ({
4
+ areaIndicator: {
5
+ '& .areaIndicator': {
6
+ left: theme.spacing(10)
7
+ },
8
+ '& label:first-of-type': {
9
+ fontSize: '0.75rem',
10
+ fontWeight: 500,
11
+ left: theme.spacing(1),
12
+ position: 'absolute',
13
+ top: theme.spacing(0.75)
14
+ },
15
+ '&[data-depth="1"]': {
16
+ '& label:first-of-type': {
17
+ '&:before': {
18
+ content: '"+ "'
19
+ },
20
+ left: theme.spacing(10)
21
+ }
22
+ },
23
+
24
+ backgroundColor: '#9747FF19',
25
+ borderRadius: '4px',
26
+ color: '#9747FFFF',
27
+ minHeight: theme.spacing(4),
28
+
29
+ position: 'relative'
30
+ }
31
+ }));
@@ -0,0 +1,35 @@
1
+ import { ReactElement, ReactNode } from 'react';
2
+
3
+ import { useStyles } from './AreaIndicator.styles';
4
+
5
+ type AreaIndicatorProps = {
6
+ children?: ReactNode | Array<ReactNode>;
7
+ depth?: number;
8
+ height?: number | string;
9
+ name: string;
10
+ width?: number | string;
11
+ };
12
+
13
+ const AreaIndicator = ({
14
+ children,
15
+ name = 'area',
16
+ width = '100%',
17
+ height = '100%',
18
+ depth = 0
19
+ }: AreaIndicatorProps): ReactElement => {
20
+ const { classes } = useStyles();
21
+
22
+ return (
23
+ <div
24
+ className={classes.areaIndicator}
25
+ data-depth={depth}
26
+ style={{ height, width }}
27
+ >
28
+ {/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
29
+ <label>{name}</label>
30
+ {children}
31
+ </div>
32
+ );
33
+ };
34
+
35
+ export { AreaIndicator };
@@ -0,0 +1,62 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+
3
+ import { AreaIndicator } from '../AreaIndicator';
4
+
5
+ import { PageLayout } from './index';
6
+
7
+ const meta: Meta<typeof PageLayout> = {
8
+ argTypes: {
9
+ variant: {
10
+ control: {
11
+ options: ['default', 'fixed-header']
12
+ }
13
+ }
14
+ },
15
+ component: PageLayout,
16
+ parameters: {
17
+ layout: 'fullscreen'
18
+ }
19
+ };
20
+
21
+ export default meta;
22
+ type Story = StoryObj<typeof PageLayout>;
23
+
24
+ export const Default: Story = {
25
+ args: {
26
+ children: (
27
+ <>
28
+ <PageLayout.Header>
29
+ <AreaIndicator name="header" />
30
+ </PageLayout.Header>
31
+ <PageLayout.Body>
32
+ <AreaIndicator height="100vh" name="body">
33
+ <PageLayout.Actions>
34
+ <AreaIndicator depth={1} name="actions" />
35
+ </PageLayout.Actions>
36
+ </AreaIndicator>
37
+ </PageLayout.Body>
38
+ </>
39
+ ),
40
+ variant: 'default'
41
+ }
42
+ };
43
+
44
+ export const FixedHeader: Story = {
45
+ args: {
46
+ children: (
47
+ <>
48
+ <PageLayout.Header>
49
+ <AreaIndicator name="header" />
50
+ </PageLayout.Header>
51
+ <PageLayout.Body hasBackground>
52
+ <AreaIndicator height="100vh" name="body">
53
+ <PageLayout.Actions>
54
+ <AreaIndicator depth={1} name="actions" />
55
+ </PageLayout.Actions>
56
+ </AreaIndicator>
57
+ </PageLayout.Body>
58
+ </>
59
+ ),
60
+ variant: 'fixed-header'
61
+ }
62
+ };
@@ -0,0 +1,30 @@
1
+ import { makeStyles } from 'tss-react/mui';
2
+
3
+ export const useStyles = makeStyles()((theme) => ({
4
+ pageLayout: {
5
+ display: 'flex',
6
+ flexDirection: 'column',
7
+ height: '100%'
8
+ },
9
+ pageLayoutActions: {
10
+ paddingBottom: theme.spacing(2.5)
11
+ },
12
+ pageLayoutBody: {
13
+ '&[data-has-background="true"]': {
14
+ backgroundColor: theme.palette.layout.body.background
15
+ },
16
+ padding: theme.spacing(3, 4, 5)
17
+ },
18
+ pageLayoutHeader: {
19
+ '[data-variant="fixed-header"] &': {
20
+ backgroundColor: theme.palette.layout.header.background,
21
+ borderBottom: `1px solid ${theme.palette.layout.header.border}`,
22
+ padding: theme.spacing(5, 4, 2),
23
+ position: 'sticky',
24
+ top: 0,
25
+ zIndex: `calc(${theme.zIndex.mobileStepper} - 100)`
26
+ },
27
+
28
+ padding: theme.spacing(5, 4, 0)
29
+ }
30
+ }));
@@ -0,0 +1,21 @@
1
+ import { ReactElement, ReactNode } from 'react';
2
+
3
+ import { useStyles } from './PageLayout.styles';
4
+
5
+ type PageLayoutProps = {
6
+ children: Array<ReactNode> | ReactNode;
7
+ variant?: 'default' | 'fixed-header';
8
+ };
9
+
10
+ export const PageLayout = ({
11
+ children,
12
+ variant = 'default'
13
+ }: PageLayoutProps): ReactElement => {
14
+ const { classes } = useStyles();
15
+
16
+ return (
17
+ <section className={classes.pageLayout} data-variant={variant}>
18
+ {children}
19
+ </section>
20
+ );
21
+ };
@@ -0,0 +1,15 @@
1
+ import { ReactElement, ReactNode } from 'react';
2
+
3
+ import { useStyles } from './PageLayout.styles';
4
+
5
+ type PageLayoutActionsProps = {
6
+ children: Array<ReactNode> | ReactNode;
7
+ };
8
+
9
+ export const PageLayoutActions = ({
10
+ children
11
+ }: PageLayoutActionsProps): ReactElement => {
12
+ const { classes } = useStyles();
13
+
14
+ return <section className={classes.pageLayoutActions}>{children}</section>;
15
+ };
@@ -0,0 +1,24 @@
1
+ import { ReactElement, ReactNode } from 'react';
2
+
3
+ import { useStyles } from './PageLayout.styles';
4
+
5
+ type PageLayoutBodyProps = {
6
+ children: Array<ReactNode> | ReactNode;
7
+ hasBackground?: boolean;
8
+ };
9
+
10
+ export const PageLayoutBody = ({
11
+ children,
12
+ hasBackground = false
13
+ }: PageLayoutBodyProps): ReactElement => {
14
+ const { classes } = useStyles();
15
+
16
+ return (
17
+ <section
18
+ className={classes.pageLayoutBody}
19
+ data-has-background={hasBackground}
20
+ >
21
+ {children}
22
+ </section>
23
+ );
24
+ };
@@ -0,0 +1,15 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ import { useStyles } from './PageLayout.styles';
4
+
5
+ type PageLayoutHeaderProps = {
6
+ children: Array<ReactNode> | ReactNode;
7
+ };
8
+
9
+ export const PageLayoutHeader = ({
10
+ children
11
+ }: PageLayoutHeaderProps): JSX.Element => {
12
+ const { classes } = useStyles();
13
+
14
+ return <header className={classes.pageLayoutHeader}>{children}</header>;
15
+ };
@@ -0,0 +1,10 @@
1
+ import { PageLayout as PageLayoutRoot } from './PageLayout';
2
+ import { PageLayoutHeader } from './PageLayoutHeader';
3
+ import { PageLayoutBody } from './PageLayoutBody';
4
+ import { PageLayoutActions } from './PageLayoutActions';
5
+
6
+ export const PageLayout = Object.assign(PageLayoutRoot, {
7
+ Actions: PageLayoutActions,
8
+ Body: PageLayoutBody,
9
+ Header: PageLayoutHeader
10
+ });
@@ -0,0 +1 @@
1
+ export * from './PageLayout';
@@ -3,3 +3,4 @@ export * from './Modal';
3
3
  export * from './Form';
4
4
  export * from './Header';
5
5
  export * from './DataTable';
6
+ export * from './Layout';
package/src/index.ts CHANGED
@@ -138,8 +138,6 @@ export { default as ActionsList } from './ActionsList';
138
138
 
139
139
  export type { ResponseError, CatchErrorProps } from './api/customFetch';
140
140
 
141
- export * from './layout/TiledListingPage';
142
-
143
141
  export * from './utils';
144
142
  export { default as FluidTypography } from './Typography/FluidTypography';
145
143
  export * from './Dashboard';
@@ -15,12 +15,7 @@ import {
15
15
  Modal
16
16
  } from '../../components';
17
17
  import { Default as DashboardFormDefaultStory } from '../../components/Form/Dashboard/DashboardForm.stories';
18
- import {
19
- TiledListingActions,
20
- TiledListingContent,
21
- TiledListingList,
22
- TiledListingPage
23
- } from '../../layout/TiledListingPage';
18
+ import { PageLayout } from '../../components/Layout/PageLayout';
24
19
 
25
20
  const meta: Meta = {
26
21
  args: {
@@ -64,6 +59,9 @@ const meta: Meta = {
64
59
  },
65
60
  title: 'Dashboards overview'
66
61
  },
62
+ parameters: {
63
+ layout: 'fullscreen'
64
+ },
67
65
  title: 'screens/Dashboards'
68
66
  };
69
67
 
@@ -134,10 +132,12 @@ const DefaultView = (args): JSX.Element => {
134
132
  };
135
133
 
136
134
  return (
137
- <TiledListingPage>
138
- <Header title={title} />
139
- <TiledListingList>
140
- <TiledListingActions>
135
+ <PageLayout>
136
+ <PageLayout.Header>
137
+ <Header title={title} />
138
+ </PageLayout.Header>
139
+ <PageLayout.Body>
140
+ <PageLayout.Actions>
141
141
  {dataDashboards.length !== 0 && (
142
142
  <Button
143
143
  aria-label="add"
@@ -150,101 +150,105 @@ const DefaultView = (args): JSX.Element => {
150
150
  {actions.create.label}
151
151
  </Button>
152
152
  )}
153
- </TiledListingActions>
154
- <TiledListingContent>
155
- <DataTable isEmpty={dataDashboards.length === 0}>
156
- {dataDashboards.length === 0 ? (
157
- <DataTable.EmptyState
158
- labels={list.emptyState.labels}
159
- onCreate={() =>
160
- setDialogState({ item: null, open: true, variant: 'create' })
161
- }
162
- />
163
- ) : (
164
- dataDashboards.map((dashboard) => (
165
- <DataTable.Item
166
- hasActions
167
- hasCardAction
168
- description={dashboard.description}
169
- key={dashboard.id}
170
- title={dashboard.name}
171
- onDelete={() =>
172
- setDeleteDialogState({ item: dashboard, open: true })
173
- }
174
- onEdit={() =>
175
- setDialogState({
176
- item: dashboard,
177
- open: true,
178
- variant: 'update'
179
- })
180
- }
181
- />
182
- ))
183
- )}
184
- </DataTable>
185
- </TiledListingContent>
186
- <Modal
187
- open={dialogState.open}
188
- onClose={() =>
189
- setDialogState({
190
- item: null,
191
- open: false,
192
- variant: dialogState.variant
193
- })
194
- }
195
- >
196
- <Modal.Header>
197
- {form.labels.title[dialogState.variant ?? 'create']}
198
- </Modal.Header>
199
- <Modal.Body>
200
- <DashboardForm
201
- labels={DashboardFormDefaultStory!.args!.labels!}
202
- resource={dialogState.item || undefined}
203
- variant={dialogState.variant}
204
- onCancel={() =>
153
+ </PageLayout.Actions>
154
+
155
+ <DataTable isEmpty={dataDashboards.length === 0}>
156
+ {dataDashboards.length === 0 ? (
157
+ <DataTable.EmptyState
158
+ labels={list.emptyState.labels}
159
+ onCreate={() =>
205
160
  setDialogState({
206
161
  item: null,
207
- open: false,
208
- variant: dialogState.variant
162
+ open: true,
163
+ variant: 'create'
209
164
  })
210
165
  }
211
- onSubmit={(values) =>
212
- dialogState.variant === 'create'
213
- ? createDashboard(values)
214
- : updateDashboard(values)
215
- }
216
166
  />
217
- </Modal.Body>
218
- </Modal>
219
- <Modal
220
- open={deleteDialogState.open}
221
- onClose={() =>
222
- setDeleteDialogState({
223
- ...deleteDialogState,
224
- open: false
225
- })
226
- }
227
- >
228
- <Modal.Header>{deleteConfirmation.labels.title}</Modal.Header>
229
- <Modal.Body>
230
- <p>
231
- {deleteConfirmation.labels.description(
232
- deleteDialogState.item?.name
233
- )}
234
- </p>
235
- </Modal.Body>
236
- <Modal.Actions
237
- isDanger
238
- labels={deleteConfirmation.labels.actions}
239
- onCancel={() => setDeleteDialogState({ item: null, open: false })}
240
- onConfirm={() => {
241
- deleteDashboard(deleteDialogState.item?.id);
242
- setDeleteDialogState({ item: null, open: false });
243
- }}
167
+ ) : (
168
+ dataDashboards.map((dashboard) => (
169
+ <DataTable.Item
170
+ hasActions
171
+ hasCardAction
172
+ description={dashboard.description}
173
+ key={dashboard.id}
174
+ title={dashboard.name}
175
+ onDelete={() =>
176
+ setDeleteDialogState({ item: dashboard, open: true })
177
+ }
178
+ onEdit={() =>
179
+ setDialogState({
180
+ item: dashboard,
181
+ open: true,
182
+ variant: 'update'
183
+ })
184
+ }
185
+ />
186
+ ))
187
+ )}
188
+ </DataTable>
189
+ </PageLayout.Body>
190
+
191
+ <Modal
192
+ open={dialogState.open}
193
+ onClose={() =>
194
+ setDialogState({
195
+ item: null,
196
+ open: false,
197
+ variant: dialogState.variant
198
+ })
199
+ }
200
+ >
201
+ <Modal.Header>
202
+ {form.labels.title[dialogState.variant ?? 'create']}
203
+ </Modal.Header>
204
+ <Modal.Body>
205
+ <DashboardForm
206
+ labels={DashboardFormDefaultStory!.args!.labels!}
207
+ resource={dialogState.item || undefined}
208
+ variant={dialogState.variant}
209
+ onCancel={() =>
210
+ setDialogState({
211
+ item: null,
212
+ open: false,
213
+ variant: dialogState.variant
214
+ })
215
+ }
216
+ onSubmit={(values) =>
217
+ dialogState.variant === 'create'
218
+ ? createDashboard(values)
219
+ : updateDashboard(values)
220
+ }
244
221
  />
245
- </Modal>
246
- </TiledListingList>
247
- </TiledListingPage>
222
+ </Modal.Body>
223
+ </Modal>
224
+ <Modal
225
+ open={deleteDialogState.open}
226
+ onClose={() =>
227
+ setDeleteDialogState({
228
+ ...deleteDialogState,
229
+ open: false
230
+ })
231
+ }
232
+ >
233
+ <Modal.Header>{deleteConfirmation.labels.title}</Modal.Header>
234
+ <Modal.Body>
235
+ <p>
236
+ {deleteConfirmation.labels.description(
237
+ deleteDialogState.item?.name
238
+ )}
239
+ </p>
240
+ </Modal.Body>
241
+ <Modal.Actions
242
+ isDanger
243
+ labels={deleteConfirmation.labels.actions}
244
+ onCancel={() => setDeleteDialogState({ item: null, open: false })}
245
+ onConfirm={() => {
246
+ deleteDashboard(deleteDialogState.item?.id);
247
+ setDeleteDialogState({ item: null, open: false });
248
+ }}
249
+ />
250
+ </Modal>
251
+ </PageLayout>
248
252
  );
249
253
  };
250
254
 
@@ -1,15 +0,0 @@
1
- import { ReactNode } from 'react';
2
-
3
- import { useTiledListingActionsStyles } from './TiledListingPage.styles';
4
-
5
- interface TiledListingActionsProps {
6
- children: Array<ReactNode> | ReactNode;
7
- }
8
-
9
- export const TiledListingActions = ({
10
- children
11
- }: TiledListingActionsProps): JSX.Element => {
12
- const { classes } = useTiledListingActionsStyles();
13
-
14
- return <div className={classes.actions}>{children}</div>;
15
- };
@@ -1,21 +0,0 @@
1
- import { ReactNode } from 'react';
2
-
3
- import Responsive from '../../Responsive';
4
-
5
- import { useTiledListingActionsStyles } from './TiledListingPage.styles';
6
-
7
- interface TiledListingContentProps {
8
- children: ReactNode;
9
- }
10
-
11
- export const TiledListingContent = ({
12
- children
13
- }: TiledListingContentProps): JSX.Element => {
14
- const { classes } = useTiledListingActionsStyles();
15
-
16
- return (
17
- <Responsive>
18
- <div className={classes.actions}>{children}</div>
19
- </Responsive>
20
- );
21
- };
@@ -1,11 +0,0 @@
1
- import { ReactNode } from 'react';
2
-
3
- interface TiledListingListProps {
4
- children: Array<ReactNode>;
5
- }
6
-
7
- export const TiledListingList = ({
8
- children
9
- }: TiledListingListProps): JSX.Element => {
10
- return <div>{children}</div>;
11
- };
@@ -1,16 +0,0 @@
1
- import { makeStyles } from 'tss-react/mui';
2
-
3
- export const useTiledListPageStyles = makeStyles()((theme) => ({
4
- listPage: {
5
- display: 'flex',
6
- flexDirection: 'column',
7
- height: '100%',
8
- padding: theme.spacing(1.5)
9
- }
10
- }));
11
-
12
- export const useTiledListingActionsStyles = makeStyles()((theme) => ({
13
- actions: {
14
- paddingBottom: theme.spacing(2.5)
15
- }
16
- }));
@@ -1,15 +0,0 @@
1
- import { ReactNode } from 'react';
2
-
3
- import { useTiledListPageStyles } from './TiledListingPage.styles';
4
-
5
- interface TiledListingPageProps {
6
- children: Array<ReactNode>;
7
- }
8
-
9
- export const TiledListingPage = ({
10
- children
11
- }: TiledListingPageProps): JSX.Element => {
12
- const { classes } = useTiledListPageStyles();
13
-
14
- return <div className={classes.listPage}>{children}</div>;
15
- };
@@ -1,4 +0,0 @@
1
- export * from './TiledListingPage';
2
- export * from './TiledListingActions';
3
- export * from './TiledListingList';
4
- export * from './TiledListingContent';