@centreon/ui 23.10.96 → 23.10.97

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.96",
3
+ "version": "23.10.97",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "eslint": "eslint ./src --ext .js,.jsx,.ts,.tsx --max-warnings 0",
@@ -107,7 +107,7 @@
107
107
  "@lexical/rich-text": "^0.11.3",
108
108
  "@lexical/selection": "0.11.3",
109
109
  "@lexical/utils": "0.11.3",
110
- "@react-spring/web": "9.6.0",
110
+ "@react-spring/web": "^9.7.3",
111
111
  "@visx/curve": "^2.1.0",
112
112
  "@visx/group": "^3.3.0",
113
113
  "@visx/pattern": "^3.0.0",
@@ -92,7 +92,13 @@ export const useDashboardItemStyles = makeStyles<{ hasHeader: boolean }>()(
92
92
  '&[data-canMove="true"]': {
93
93
  cursor: 'move'
94
94
  },
95
- padding: theme.spacing(0.5, 2)
95
+ padding: theme.spacing(0.5, 2),
96
+ position: 'relative'
97
+ },
98
+ widgetHeaderDraggable: {
99
+ height: '100%',
100
+ position: 'absolute',
101
+ width: '100%'
96
102
  },
97
103
  widgetPadding: {
98
104
  overflowX: 'auto',
@@ -72,12 +72,12 @@ const Item = forwardRef(
72
72
  data-padding={!disablePadding}
73
73
  >
74
74
  {header && (
75
- <div
76
- {...listeners}
77
- className={classes.widgetHeader}
78
- data-canMove={canMove}
79
- data-testid={`${id}_move_panel`}
80
- >
75
+ <div className={classes.widgetHeader} data-canMove={canMove}>
76
+ <div
77
+ {...listeners}
78
+ className={classes.widgetHeaderDraggable}
79
+ data-testid={`${id}_move_panel`}
80
+ />
81
81
  {header}
82
82
  </div>
83
83
  )}
@@ -10,16 +10,15 @@ import IconClose from '@mui/icons-material/HighlightOff';
10
10
  const useStyles = makeStyles()((theme) => ({
11
11
  buttonClose: {
12
12
  position: 'absolute',
13
- right: theme.spacing(0.5),
14
- top: '40%'
13
+ right: theme.spacing(-0.5),
14
+ top: theme.spacing(-1)
15
15
  },
16
16
  tooltip: {
17
17
  backgroundColor: theme.palette.common.white,
18
18
  boxShadow: theme.shadows[3],
19
19
  color: theme.palette.text.primary,
20
20
  fontSize: theme.typography.pxToRem(12),
21
- maxWidth: 500,
22
- padding: theme.spacing(1, 2, 1, 1)
21
+ maxWidth: 500
23
22
  }
24
23
  }));
25
24
 
@@ -60,7 +59,7 @@ const PersistentTooltip = ({
60
59
  };
61
60
 
62
61
  const title = (
63
- <>
62
+ <div style={{ position: 'relative' }}>
64
63
  <IconButton
65
64
  className={classes.buttonClose}
66
65
  size="small"
@@ -69,7 +68,7 @@ const PersistentTooltip = ({
69
68
  <IconClose fontSize="small" />
70
69
  </IconButton>
71
70
  {children}
72
- </>
71
+ </div>
73
72
  );
74
73
 
75
74
  return (
@@ -82,34 +82,6 @@ describe('Multi connected autocomplete', () => {
82
82
  cy.makeSnapshot('hides the list when the user clicks on the input');
83
83
  });
84
84
 
85
- it('displays exactly one option on the list when the user types that option', () => {
86
- cy.get('[data-testid="Multi Connected Autocomplete"]').as('input');
87
-
88
- cy.get('@input').click();
89
-
90
- cy.waitForRequest('@getListOptions');
91
-
92
- cy.findByRole('presentation').as('listOptions');
93
-
94
- cy.get('@listOptions').should('be.visible');
95
-
96
- cy.get('@input').type(optionOne);
97
-
98
- cy.waitForRequest('@getSearchedOption');
99
-
100
- cy.fixture('inputField/searchedOption').then((optionData) => {
101
- cy.get('@listOptions')
102
- .find('li')
103
- .should('have.length', optionData.result.length);
104
- });
105
-
106
- cy.get('@listOptions').within(() => {
107
- cy.contains(optionOne).should('be.visible');
108
- });
109
-
110
- cy.makeSnapshot();
111
- });
112
-
113
85
  it('displays all options on the list when the user searches for and selects an option', () => {
114
86
  cy.get('[data-testid="Multi Connected Autocomplete"]').as('input');
115
87
 
@@ -125,13 +97,11 @@ describe('Multi connected autocomplete', () => {
125
97
 
126
98
  cy.waitForRequest('@getSearchedOption');
127
99
 
128
- cy.fixture('inputField/searchedOption').then((optionData) => {
129
- cy.get('@listOptions')
130
- .find('li')
131
- .should('have.length', optionData.result.length);
100
+ cy.fixture('inputField/searchedOption').then(() => {
101
+ cy.get('@listOptions').find('li').should('have.length', 5);
132
102
  });
133
103
 
134
- cy.get('[type="checkbox"]').check();
104
+ cy.get('[type="checkbox"]').eq(0).check();
135
105
  cy.get('@input')
136
106
  .parent()
137
107
  .within(() => {
@@ -153,7 +123,5 @@ describe('Multi connected autocomplete', () => {
153
123
  });
154
124
  });
155
125
  });
156
-
157
- cy.makeSnapshot();
158
126
  });
159
127
  });
@@ -95,9 +95,7 @@ describe(SingleConnectedAutocompleteField, () => {
95
95
 
96
96
  await waitFor(() => {
97
97
  expect(getFetchCall(2)).toEqual(
98
- `${baseEndpoint}?page=1&search=${encodeURIComponent(
99
- '{"$and":[{"host.name":{"$lk":"%My Option 2%"}}]}'
100
- )}`
98
+ `${baseEndpoint}?page=1&search=%7B%22%24and%22%3A%5B%7B%22%24or%22%3A%5B%7B%22host.name%22%3A%7B%22%24lk%22%3A%22%25My%20Option%202%25%22%7D%7D%5D%7D%5D%7D`
101
99
  );
102
100
  });
103
101
  });
@@ -118,9 +116,7 @@ describe(SingleConnectedAutocompleteField, () => {
118
116
 
119
117
  await waitFor(() => {
120
118
  expect(getFetchCall(0)).toEqual(
121
- `${baseEndpoint}?page=1&search=${encodeURIComponent(
122
- '{"$and":[{"parent_name":{"$eq":"Centreon-Server"}}]}'
123
- )}`
119
+ `${baseEndpoint}?page=1&search=%7B%22%24and%22%3A%5B%7B%22%24or%22%3A%5B%7B%22parent_name%22%3A%7B%22%24eq%22%3A%22Centreon-Server%22%7D%7D%5D%7D%5D%7D`
124
120
  );
125
121
  });
126
122
  });
@@ -53,24 +53,27 @@ const MultiAutocompleteField = ({
53
53
  const { classes } = useStyles();
54
54
 
55
55
  const renderTags = (renderedValue, getTagProps): Array<JSX.Element> =>
56
- renderedValue.map((option, index) => (
57
- <Tooltip
58
- key={option.id}
59
- placement="top"
60
- title={getOptionTooltipLabel?.(option)}
61
- >
62
- <Chip
63
- classes={{
64
- deleteIcon: classes.deleteIcon,
65
- root: classes.tag
66
- }}
67
- label={getTagLabel(option)}
68
- size="medium"
69
- {...getTagProps({ index })}
70
- {...chipProps}
71
- />
72
- </Tooltip>
73
- ));
56
+ renderedValue.map((option, index) => {
57
+ return (
58
+ <Tooltip
59
+ key={option.id}
60
+ placement="top"
61
+ title={getOptionTooltipLabel?.(option)}
62
+ >
63
+ <Chip
64
+ classes={{
65
+ deleteIcon: classes.deleteIcon,
66
+ root: classes.tag
67
+ }}
68
+ label={getTagLabel(option)}
69
+ size="medium"
70
+ {...getTagProps({ index })}
71
+ {...chipProps}
72
+ onDelete={(event) => chipProps?.onDelete?.(event, option)}
73
+ />
74
+ </Tooltip>
75
+ );
76
+ });
74
77
 
75
78
  const getLimitTagsText = (more): JSX.Element => <Option>{`+${more}`}</Option>;
76
79
 
@@ -38,6 +38,7 @@ export interface RichTextEditorProps {
38
38
  openLinkInNewTab?: boolean;
39
39
  placeholder?: string;
40
40
  resetEditorToInitialStateCondition?: () => boolean;
41
+ toolbarClassName?: string;
41
42
  toolbarPositions?: 'start' | 'end';
42
43
  }
43
44
 
@@ -136,7 +137,8 @@ const RichTextEditor = ({
136
137
  disabled = false,
137
138
  openLinkInNewTab = true,
138
139
  initialize,
139
- displayBlockButtons = true
140
+ displayBlockButtons = true,
141
+ toolbarClassName
140
142
  }: RichTextEditorProps): JSX.Element => {
141
143
  const { classes } = useStyles({ toolbarPositions });
142
144
 
@@ -175,6 +177,7 @@ const RichTextEditor = ({
175
177
  <div className={classes.container}>
176
178
  <div className={classes.toolbar}>
177
179
  <ToolbarPlugin
180
+ className={toolbarClassName}
178
181
  disabled={disabled}
179
182
  displayBlockButtons={displayBlockButtons}
180
183
  displayMacrosButton={displayMacrosButton}
@@ -9,6 +9,7 @@ import BlockButtons from './BlockButtons';
9
9
  import AlignPicker from './AlignPicker';
10
10
 
11
11
  interface Props {
12
+ className?: string;
12
13
  disabled: boolean;
13
14
  displayBlockButtons: boolean;
14
15
  displayMacrosButton?: boolean;
@@ -36,12 +37,13 @@ const ToolbarPlugin = ({
36
37
  editable,
37
38
  displayMacrosButton,
38
39
  disabled,
39
- displayBlockButtons
40
+ displayBlockButtons,
41
+ className
40
42
  }: Props): JSX.Element | null => {
41
- const { classes } = useStyles();
43
+ const { cx, classes } = useStyles();
42
44
 
43
45
  return editable ? (
44
- <div className={classes.container}>
46
+ <div className={cx(classes.container, className)}>
45
47
  <UndoRedoButtons disabled={disabled} />
46
48
  {displayBlockButtons && (
47
49
  <>
@@ -51,13 +53,13 @@ const ToolbarPlugin = ({
51
53
  )}
52
54
  <Divider flexItem orientation="vertical" />
53
55
  <FormatButtons disabled={disabled} />
56
+ <AlignPicker disabled={disabled} />
54
57
  {displayMacrosButton && (
55
58
  <>
56
59
  <Divider flexItem orientation="vertical" />
57
60
  <MacrosButton disabled={disabled} />
58
61
  </>
59
62
  )}
60
- <AlignPicker disabled={disabled} />
61
63
  </div>
62
64
  ) : null;
63
65
  };
@@ -29,6 +29,7 @@ const actionsBarLabelsDefaultValues = {
29
29
  };
30
30
 
31
31
  const Wizard = ({
32
+ classNameDialogContent,
32
33
  steps,
33
34
  onSubmit = undefined,
34
35
  initialValues = {},
@@ -41,7 +42,7 @@ const Wizard = ({
41
42
  displayConfirmDialog,
42
43
  ...rest
43
44
  }: WizardProps): JSX.Element => {
44
- const { classes } = useStyles();
45
+ const { classes, cx } = useStyles();
45
46
  const [currentStep, setCurrentStep] = useState(0);
46
47
  const [sendingRequest, setSendingRequest] = useState(false);
47
48
  const [openConfirm, setOpenConfirm] = useState(false);
@@ -131,7 +132,9 @@ const Wizard = ({
131
132
  validationSchema={validationSchema}
132
133
  onSubmit={submit}
133
134
  >
134
- <DialogContent className={classes.dialogContent}>
135
+ <DialogContent
136
+ className={cx(classes.dialogContent, classNameDialogContent)}
137
+ >
135
138
  <WizardContent
136
139
  actionsBarLabels={actionsBarLabels}
137
140
  currentStep={currentStep}
@@ -45,6 +45,7 @@ type ValueOf<T> = T[keyof T];
45
45
  export interface WizardProps {
46
46
  [key: string]: ValueOf<DialogProps>;
47
47
  actionsBarLabels?: ActionsBarLabels;
48
+ classNameDialogContent?: string;
48
49
  confirmDialogLabels?: ConfirmDialogLabels;
49
50
  displayConfirmDialog?: boolean;
50
51
  fullHeight?: boolean;
@@ -5,9 +5,10 @@ import {
5
5
  prop,
6
6
  head,
7
7
  toPairs,
8
- pipe,
9
- map,
10
- flatten
8
+ flatten,
9
+ pluck,
10
+ uniq,
11
+ equals
11
12
  } from 'ramda';
12
13
 
13
14
  import {
@@ -83,28 +84,38 @@ const getConditionsSearchQueryParameterValue = (
83
84
  return undefined;
84
85
  }
85
86
 
86
- const toIndividualOperatorValues = ({
87
- field,
88
- values,
89
- value
90
- }: ConditionsSearchParameter): Array<Record<string, unknown>> => {
91
- if (!isNil(value)) {
92
- return [
93
- {
94
- [field]: value
95
- }
96
- ];
97
- }
98
-
99
- return toPairs(values || {}).map(([operator, operatorValue]) => ({
100
- [field]: {
101
- [operator]: operatorValue
102
- }
103
- }));
87
+ const fields = uniq(pluck('field', conditions));
88
+
89
+ const toIndividualOperatorValues = (
90
+ listField: string
91
+ ): { $or: Array<Record<string, unknown>> } => {
92
+ const filteredItems = conditions.filter(({ field }) =>
93
+ equals(listField, field)
94
+ );
95
+
96
+ return {
97
+ $or: flatten(
98
+ filteredItems.map(({ value, values }) => {
99
+ if (!isNil(value)) {
100
+ return [
101
+ {
102
+ [listField]: value
103
+ }
104
+ ];
105
+ }
106
+
107
+ return toPairs(values || {}).map(([operator, operatorValue]) => ({
108
+ [listField]: {
109
+ [operator]: operatorValue
110
+ }
111
+ }));
112
+ })
113
+ )
114
+ };
104
115
  };
105
116
 
106
117
  return {
107
- $and: pipe(map(toIndividualOperatorValues), flatten)(conditions)
118
+ $and: fields.map(toIndividualOperatorValues)
108
119
  };
109
120
  };
110
121
 
@@ -115,7 +115,7 @@ describe(buildListingEndpoint, () => {
115
115
  });
116
116
 
117
117
  expect(decodeURIComponent(endpointWithValues)).toContain(
118
- '&search={"$and":[{"date":{"$gt":"2020-12-01T07:00:00"}},{"date":{"$lt":"2020-12-01T11:00:00"}}]}'
118
+ '&search={"$and":[{"$or":[{"date":{"$gt":"2020-12-01T07:00:00"}},{"date":{"$lt":"2020-12-01T11:00:00"}}]}]}'
119
119
  );
120
120
 
121
121
  const endpointWithValue = buildListingEndpoint({
@@ -134,7 +134,7 @@ describe(buildListingEndpoint, () => {
134
134
  });
135
135
 
136
136
  expect(decodeURIComponent(endpointWithValue)).toContain(
137
- '&search={"$and":[{"is_activated":true}]}'
137
+ '&search={"$and":[{"$or":[{"is_activated":true}]}]}'
138
138
  );
139
139
  });
140
140
  });
@@ -18,7 +18,6 @@ export interface Parameters {
18
18
  search?: SearchParameter;
19
19
  sort?: SortQueryParameterValue;
20
20
  }
21
-
22
21
  export interface SearchParameter {
23
22
  conditions?: Array<ConditionsSearchParameter>;
24
23
  lists?: Array<ListsSearchParameter>;