@centreon/ui 23.10.79 → 23.10.81

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.79",
3
+ "version": "23.10.81",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "eslint": "eslint ./src --ext .js,.jsx,.ts,.tsx --max-warnings 0",
@@ -70,6 +70,7 @@ export const useDashboardItemStyles = makeStyles<{ hasHeader: boolean }>()(
70
70
  (theme, { hasHeader }) => ({
71
71
  widgetContainer: {
72
72
  height: '100%',
73
+ paddingBottom: theme.spacing(2),
73
74
  width: '100%'
74
75
  },
75
76
  widgetContent: {
@@ -89,7 +90,7 @@ export const useDashboardItemStyles = makeStyles<{ hasHeader: boolean }>()(
89
90
  },
90
91
  widgetPadding: {
91
92
  overflowX: 'auto',
92
- padding: hasHeader ? theme.spacing(1, 2, 2) : theme.spacing(1, 2)
93
+ padding: hasHeader ? theme.spacing(1, 2, 0) : theme.spacing(1, 2)
93
94
  }
94
95
  })
95
96
  );
@@ -1,5 +1,5 @@
1
1
  import { FormikValues, useFormikContext } from 'formik';
2
- import { equals, includes, path, split } from 'ramda';
2
+ import { equals, includes, path, split, type } from 'ramda';
3
3
  import { useTranslation } from 'react-i18next';
4
4
 
5
5
  import {
@@ -73,12 +73,23 @@ const Radio = ({
73
73
  disabled={disabled}
74
74
  id={getNormalizedId(`${dataTestId}${optionLabel}`)}
75
75
  inputProps={{
76
- 'aria-label': t(optionLabel) || ''
76
+ 'aria-label':
77
+ (equals(type(optionLabel), 'String') &&
78
+ t(optionLabel as string)) ||
79
+ ''
77
80
  }}
78
81
  />
79
82
  }
80
- key={optionLabel}
81
- label={t(optionLabel) as string}
83
+ key={
84
+ equals(type(optionLabel), 'String')
85
+ ? (optionLabel as string)
86
+ : `${optionValue}`
87
+ }
88
+ label={
89
+ equals(type(optionLabel), 'String')
90
+ ? (t(optionLabel as string) as string)
91
+ : optionLabel
92
+ }
82
93
  value={optionValue}
83
94
  />
84
95
  ))}
@@ -77,7 +77,7 @@ export interface InputProps {
77
77
  label: string;
78
78
  radio?: {
79
79
  options?: Array<{
80
- label: string;
80
+ label: string | JSX.Element;
81
81
  value: boolean | string;
82
82
  }>;
83
83
  row?: boolean;
@@ -134,7 +134,7 @@ const ResponsiveGauge = ({
134
134
  ...baseStyles,
135
135
  backgroundColor: theme.palette.background.paper,
136
136
  color: theme.palette.text.primary,
137
- transform: 'translate(-50%, 0)'
137
+ transform: 'translate(-50%, -24px)'
138
138
  }}
139
139
  top={(tooltipTop || 0) - svgTop + 20}
140
140
  >
@@ -127,47 +127,54 @@ const ResponsiveSingleBar = ({
127
127
  const springStyle = useSpring({ width: metricBarWidth });
128
128
 
129
129
  return (
130
- <Box
131
- sx={{
130
+ <div
131
+ style={{
132
132
  height: '100%',
133
- overflow: 'hidden',
134
- position: 'relative',
135
- width: '100%'
133
+ position: 'relative'
136
134
  }}
137
135
  >
138
- <svg height={height} ref={svgRef} width={width}>
139
- <Group.Group>
140
- {text}
141
- <animated.rect
142
- data-testid={`${latestMetricData}-bar-${barColor}`}
143
- fill={barColor}
144
- height={barHeights[size]}
145
- rx={4}
146
- style={springStyle}
147
- x={0}
148
- y={groupMargin + (isSmall ? 0 : 2 * margins.top)}
149
- />
150
- <Bar
151
- fill="transparent"
152
- height={barHeights[size]}
153
- rx={4}
154
- ry={4}
155
- stroke={alpha(theme.palette.text.primary, 0.3)}
156
- width={maxBarWidth}
157
- x={0}
158
- y={groupMargin + (isSmall ? 0 : 2 * margins.top)}
159
- />
160
- {thresholds.enabled && (
161
- <Thresholds
162
- hideTooltip={hideTooltip}
163
- showTooltip={showTooltip}
164
- size={size}
165
- thresholds={thresholds}
166
- xScale={xScale}
136
+ <Box
137
+ sx={{
138
+ height: '100%',
139
+ overflow: 'hidden',
140
+ position: 'relative',
141
+ width: '100%'
142
+ }}
143
+ >
144
+ <svg height={height} ref={svgRef} width={width}>
145
+ <Group.Group>
146
+ {text}
147
+ <animated.rect
148
+ data-testid={`${latestMetricData}-bar-${barColor}`}
149
+ fill={barColor}
150
+ height={barHeights[size]}
151
+ rx={4}
152
+ style={springStyle}
153
+ x={0}
154
+ y={groupMargin + (isSmall ? 0 : 2 * margins.top)}
155
+ />
156
+ <Bar
157
+ fill="transparent"
158
+ height={barHeights[size]}
159
+ rx={4}
160
+ ry={4}
161
+ stroke={alpha(theme.palette.text.primary, 0.3)}
162
+ width={maxBarWidth}
163
+ x={0}
164
+ y={groupMargin + (isSmall ? 0 : 2 * margins.top)}
167
165
  />
168
- )}
169
- </Group.Group>
170
- </svg>
166
+ {thresholds.enabled && (
167
+ <Thresholds
168
+ hideTooltip={hideTooltip}
169
+ showTooltip={showTooltip}
170
+ size={size}
171
+ thresholds={thresholds}
172
+ xScale={xScale}
173
+ />
174
+ )}
175
+ </Group.Group>
176
+ </svg>
177
+ </Box>
171
178
  <Fade in={tooltipOpen}>
172
179
  <Tooltip.Tooltip
173
180
  left={tooltipLeft}
@@ -175,7 +182,7 @@ const ResponsiveSingleBar = ({
175
182
  ...baseStyles,
176
183
  backgroundColor: theme.palette.background.paper,
177
184
  color: theme.palette.text.primary,
178
- transform: `translate(-50%, ${isSmall ? -60 : -20}px)`,
185
+ transform: `translate(-50%, ${isSmall ? -100 : -120}px)`,
179
186
  zIndex: theme.zIndex.tooltip
180
187
  }}
181
188
  top={tooltipTop}
@@ -183,7 +190,7 @@ const ResponsiveSingleBar = ({
183
190
  {tooltipData}
184
191
  </Tooltip.Tooltip>
185
192
  </Fade>
186
- </Box>
193
+ </div>
187
194
  );
188
195
  };
189
196
 
@@ -16,9 +16,6 @@ interface StyleProps {
16
16
  const useStyles = makeStyles<StyleProps>()(
17
17
  (theme, { minInputHeight, editable, error }) => ({
18
18
  container: {
19
- '& p': {
20
- margin: 0
21
- },
22
19
  backgroundColor: theme.palette.background.paper,
23
20
  border: error
24
21
  ? `1px solid ${theme.palette.error.main}`
@@ -41,6 +38,11 @@ const useStyles = makeStyles<StyleProps>()(
41
38
  placeholder: {
42
39
  color: theme.palette.grey[500],
43
40
  pointerEvents: 'none'
41
+ },
42
+ root: {
43
+ '& p,h1,h2,h3,h4,h5,h6,span': {
44
+ margin: 0
45
+ }
44
46
  }
45
47
  })
46
48
  );
@@ -121,11 +123,13 @@ const ContentEditable = ({
121
123
  const shouldResetEditorToInitialState =
122
124
  resetEditorToInitialStateCondition?.();
123
125
 
124
- if (!shouldResetEditorToInitialState || isNil(initialEditorState)) {
126
+ if (!shouldResetEditorToInitialState) {
125
127
  return;
126
128
  }
127
129
 
128
- const newEditorState = editor.parseEditorState(initialEditorState);
130
+ const newEditorState = editor.parseEditorState(
131
+ initialEditorState || defaultState
132
+ );
129
133
 
130
134
  editor.setEditorState(newEditorState);
131
135
  }, [editorState]);
@@ -156,7 +160,8 @@ const ContentEditable = ({
156
160
  return (
157
161
  <div
158
162
  className={cx(
159
- classes.container,
163
+ classes.root,
164
+ editable && classes.container,
160
165
  className,
161
166
  isFocused && classes.inputFocused
162
167
  )}
@@ -67,6 +67,13 @@ withEditableFalse.args = {
67
67
  initialEditorState: JSON.stringify(initialEditorState)
68
68
  };
69
69
 
70
+ export const Disabled = Template.bind({});
71
+ Disabled.args = {
72
+ disabled: true,
73
+ editable: false,
74
+ editorState: JSON.stringify(initialEditorState)
75
+ };
76
+
70
77
  const StoryWithEditableFalseLikePreview = (): JSX.Element => {
71
78
  const [editorState, setEditorState] =
72
79
  useState<EditorState>(initialEditorState);
@@ -1,4 +1,9 @@
1
1
  export type DashboardResource = {
2
2
  description?: string | null;
3
+ globalRefreshInterval?: {
4
+ global: string;
5
+ manual: string;
6
+ title: string;
7
+ };
3
8
  name: string;
4
9
  };
@@ -5,9 +5,17 @@ const useStyles = makeStyles()(() => ({
5
5
  display: 'flex',
6
6
  flexDirection: 'column',
7
7
  maxWidth: '480px',
8
-
9
8
  width: '100%'
10
9
  }
11
10
  }));
12
11
 
13
- export { useStyles };
12
+ const useGlobalRefreshIntervalStyles = makeStyles()((theme) => ({
13
+ globalRefreshInterval: {
14
+ alignItems: 'center',
15
+ display: 'flex',
16
+ flexDirection: 'row',
17
+ gap: theme.spacing(1)
18
+ }
19
+ }));
20
+
21
+ export { useStyles, useGlobalRefreshIntervalStyles };
@@ -16,11 +16,13 @@ import {
16
16
  labelRequired
17
17
  } from './translatedLabels';
18
18
  import { DashboardResource } from './Dashboard.resource';
19
+ import GlobalRefreshFieldOption from './GlobalRefreshFieldOption';
19
20
 
20
21
  export type DashboardFormProps = {
21
22
  labels: DashboardFormLabels;
22
23
  onSubmit?: FormProps<DashboardResource>['submit'];
23
24
  resource?: DashboardResource;
25
+ showRefreshIntervalFields?: boolean;
24
26
  variant?: FormVariant;
25
27
  } & Pick<FormActionsProps, 'onCancel'>;
26
28
 
@@ -34,7 +36,8 @@ const DashboardForm = ({
34
36
  resource,
35
37
  labels,
36
38
  onSubmit,
37
- onCancel
39
+ onCancel,
40
+ showRefreshIntervalFields
38
41
  }: DashboardFormProps): ReactElement => {
39
42
  const { classes } = useStyles();
40
43
  const { t } = useTranslation();
@@ -58,6 +61,26 @@ const DashboardForm = ({
58
61
  multilineRows: 3
59
62
  },
60
63
  type: InputType.Text
64
+ },
65
+ {
66
+ fieldName: 'refresh.type',
67
+ group: 'main',
68
+ hideInput: () => !showRefreshIntervalFields,
69
+ label: labels?.entity?.globalRefreshInterval?.title,
70
+ radio: {
71
+ options: [
72
+ {
73
+ label: <GlobalRefreshFieldOption />,
74
+ value: 'global'
75
+ },
76
+ {
77
+ label: labels?.entity?.globalRefreshInterval?.manual,
78
+ value: 'manual'
79
+ }
80
+ ],
81
+ row: false
82
+ },
83
+ type: InputType.Radio
61
84
  }
62
85
  ],
63
86
  submit: (values, bag) => onSubmit?.(values, bag),
@@ -70,6 +93,16 @@ const DashboardForm = ({
70
93
  `${p.label} ${t(labelMustBeMost)} ${p.max} ${t(labelCharacters)}`
71
94
  )
72
95
  .nullable(),
96
+ globalRefreshInterval: Yup.object().shape({
97
+ interval: Yup.number().when('type', {
98
+ is: 'global',
99
+ otherwise: Yup.number().nullable(),
100
+ then: Yup.number()
101
+ .min(1, ({ min }) => t(labelMustBeAtLeast, { min }))
102
+ .required(t(labelRequired) as string)
103
+ }),
104
+ type: Yup.string()
105
+ }),
73
106
  name: Yup.string()
74
107
  .label(labels?.entity?.name)
75
108
  .min(3, ({ min, label }) => t(labelMustBeAtLeast, { label, min }))
@@ -0,0 +1,54 @@
1
+ import { ChangeEvent } from 'react';
2
+
3
+ import { FormikValues, useFormikContext } from 'formik';
4
+ import { useTranslation } from 'react-i18next';
5
+ import { isEmpty } from 'ramda';
6
+ import pluralize from 'pluralize';
7
+
8
+ import { Typography } from '@mui/material';
9
+
10
+ import { TextField } from '../../..';
11
+
12
+ import {
13
+ labelGlobalRefreshInterval,
14
+ labelInterval,
15
+ labelSeconds
16
+ } from './translatedLabels';
17
+ import { useGlobalRefreshIntervalStyles } from './DashboardForm.styles';
18
+
19
+ const GlobalRefreshFieldOption = (): JSX.Element => {
20
+ const { classes } = useGlobalRefreshIntervalStyles();
21
+ const { t } = useTranslation();
22
+
23
+ const { values, setFieldValue } = useFormikContext<FormikValues>();
24
+
25
+ const value = values.refresh.interval;
26
+
27
+ const changeInput = (event: ChangeEvent<HTMLInputElement>): void => {
28
+ setFieldValue(
29
+ 'refresh.interval',
30
+ !isEmpty(event.target.value) ? Number(event.target.value) || 1 : null
31
+ );
32
+ };
33
+
34
+ return (
35
+ <div className={classes.globalRefreshInterval}>
36
+ <Typography>{t(labelGlobalRefreshInterval)}</Typography>
37
+ <TextField
38
+ autoSize
39
+ dataTestId={labelInterval}
40
+ inputProps={{
41
+ 'aria-label': t(labelInterval) as string,
42
+ min: 1
43
+ }}
44
+ size="compact"
45
+ type="number"
46
+ value={value || ''}
47
+ onChange={changeInput}
48
+ />
49
+ <Typography>{pluralize(t(labelSeconds), value)}</Typography>
50
+ </div>
51
+ );
52
+ };
53
+
54
+ export default GlobalRefreshFieldOption;
@@ -4,3 +4,6 @@ export const labelMustBeAtLeast =
4
4
  '{{label}} should be at least {{min}} characters long';
5
5
  export const labelRequired = 'Required';
6
6
  export const labelCharacters = 'characters';
7
+ export const labelGlobalRefreshInterval = 'Global refresh interval';
8
+ export const labelSeconds = 'seconds';
9
+ export const labelInterval = 'Interval';
@@ -1,7 +1,13 @@
1
+ import { useAtomValue } from 'jotai';
1
2
  import { always, cond, equals } from 'ramda';
2
3
 
4
+ import { refreshIntervalAtom } from '@centreon/ui-context';
5
+
3
6
  interface Props {
4
- globalRefreshInterval?: number;
7
+ globalRefreshInterval: {
8
+ interval: number | null;
9
+ type: 'global' | 'manual';
10
+ };
5
11
  refreshInterval: 'default' | 'custom' | 'manual';
6
12
  refreshIntervalCustom?: number;
7
13
  }
@@ -11,11 +17,20 @@ export const useRefreshInterval = ({
11
17
  refreshIntervalCustom,
12
18
  globalRefreshInterval
13
19
  }: Props): number | false => {
20
+ const platformInterval = useAtomValue(refreshIntervalAtom);
21
+
14
22
  const refreshIntervalToUse = cond([
15
- [equals('default'), always(globalRefreshInterval)],
23
+ [
24
+ equals('default'),
25
+ always(
26
+ equals(globalRefreshInterval.type, 'manual')
27
+ ? false
28
+ : globalRefreshInterval.interval || platformInterval
29
+ )
30
+ ],
16
31
  [equals('custom'), always(refreshIntervalCustom)],
17
- [equals('manual'), always(0)]
32
+ [equals('manual'), always(false)]
18
33
  ])(refreshInterval);
19
34
 
20
- return refreshIntervalToUse ? refreshIntervalToUse * 1000 : false;
35
+ return refreshIntervalToUse ? (refreshIntervalToUse as number) * 1000 : false;
21
36
  };