@centreon/ui 26.3.19 → 26.5.1

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.3.19",
3
+ "version": "26.5.1",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "update:deps": "pnpx npm-check-updates -i --format group",
@@ -28,8 +28,8 @@
28
28
  "url": "git+https://github.com/centreon/centreon.git"
29
29
  },
30
30
  "keywords": [
31
- "centreon",
32
- "react"
31
+ "react",
32
+ "centreon"
33
33
  ],
34
34
  "author": {
35
35
  "name": "centreon@centreon.com"
@@ -1,4 +1,4 @@
1
- import { type FormikValues, useFormikContext } from 'formik';
1
+ import { FormikValues, useFormikContext } from 'formik';
2
2
  import { equals, isEmpty, path, propEq, reject, split } from 'ramda';
3
3
  import { useCallback, useMemo } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
@@ -9,7 +9,7 @@ import {
9
9
  useMemoComponent
10
10
  } from '../..';
11
11
  import MultiConnectedAutocompleteField from '../../InputField/Select/Autocomplete/Connected/Multi';
12
- import { type InputPropsWithoutGroup, InputType } from './models';
12
+ import { InputPropsWithoutGroup, InputType } from './models';
13
13
 
14
14
  const defaultFilterKey = 'name';
15
15
 
@@ -42,10 +42,26 @@ const ConnectedAutocomplete = ({
42
42
 
43
43
  const isMultiple = equals(type, InputType.MultiConnectedAutocomplete);
44
44
 
45
- const getEndpoint = (parameters): string =>
46
- buildListingEndpoint({
45
+ const getEndpoint = (parameters): string => {
46
+ const nameQueryParameters =
47
+ connectedAutocomplete?.useNewAPIFormat && parameters?.search
48
+ ? [
49
+ {
50
+ name: 'name[lk]',
51
+ value: parameters.search.conditions[0].values.$lk.slice(1, -1)
52
+ }
53
+ ]
54
+ : [];
55
+
56
+ return buildListingEndpoint({
57
+ apiFormat: connectedAutocomplete?.useNewAPIFormat
58
+ ? 'JSON-LD'
59
+ : 'Standard',
47
60
  baseEndpoint: connectedAutocomplete?.endpoint,
48
- customQueryParameters: connectedAutocomplete?.customQueryParameters || [],
61
+ customQueryParameters: [
62
+ ...(connectedAutocomplete?.customQueryParameters || []),
63
+ ...nameQueryParameters
64
+ ],
49
65
  parameters: {
50
66
  ...parameters,
51
67
  search: {
@@ -58,6 +74,7 @@ const ConnectedAutocomplete = ({
58
74
  sort: { [filterKey]: 'ASC' }
59
75
  }
60
76
  });
77
+ };
61
78
 
62
79
  const fieldNamePath = split('.', fieldName);
63
80
 
@@ -79,15 +96,7 @@ const ConnectedAutocomplete = ({
79
96
  setFieldTouched(fieldName, true, false);
80
97
  setFieldValue(fieldName, value);
81
98
  },
82
- [
83
- fieldName,
84
- change,
85
- setFieldTouched,
86
- setFieldValue,
87
- setTouched,
88
- setValues,
89
- values
90
- ]
99
+ [fieldName, touched, additionalMemoProps]
91
100
  );
92
101
 
93
102
  const blur = (): void => setFieldTouched(fieldName, true);
@@ -56,6 +56,7 @@ export interface InputProps {
56
56
  options?: Array<string>;
57
57
  };
58
58
  connectedAutocomplete?: {
59
+ useNewAPIFormat?: boolean;
59
60
  additionalConditionParameters: Array<ConditionsSearchParameter>;
60
61
  customQueryParameters: Array<QueryParameter>;
61
62
  chipColor?: string;
@@ -136,7 +136,9 @@ const toLine = ({
136
136
  ...defaultDsData,
137
137
  ...(ds_data || {}),
138
138
  ds_color_area:
139
- ds_data?.ds_color_area ?? ds_data?.ds_color_line ?? defaultDsData.ds_color_line
139
+ ds_data?.ds_color_area ??
140
+ ds_data?.ds_color_line ??
141
+ defaultDsData.ds_color_line
140
142
  };
141
143
 
142
144
  return {
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  Box,
3
3
  InputAdornment,
4
- type InputProps,
4
+ InputProps,
5
5
  TextField as MuiTextField,
6
- type TextFieldProps,
7
- type TextFieldSlotsAndSlotProps,
8
- type Theme,
6
+ TextFieldProps,
7
+ TextFieldSlotsAndSlotProps,
8
+ Theme,
9
9
  Tooltip,
10
10
  Typography
11
11
  } from '@mui/material';
@@ -170,6 +170,7 @@ const TextField = forwardRef(
170
170
  ref={ref}
171
171
  size={size || 'small'}
172
172
  {...getValueProps()}
173
+ autoComplete="off"
173
174
  className={classes.textField}
174
175
  required={required}
175
176
  slotProps={{
@@ -2,12 +2,10 @@ import { TableRow, type TableRowProps, useTheme } from '@mui/material';
2
2
 
3
3
  import type { ListingVariant } from '@centreon/ui-context';
4
4
 
5
- import { equals, gte, lt, not, pluck } from 'ramda';
5
+ import { equals, lt, not, pluck } from 'ramda';
6
6
  import { memo, useCallback, useEffect, useRef } from 'react';
7
7
 
8
- import LoadingSkeleton from '../../LoadingSkeleton';
9
8
  import { useViewportIntersection } from '../../utils/useViewportIntersection';
10
- import { performanceRowsLimit } from '../index';
11
9
  import type { Column, ColumnConfiguration, RowColorCondition } from '../models';
12
10
 
13
11
  type Props = {
@@ -39,33 +37,8 @@ const Row = memo<RowProps>(
39
37
  tabIndex,
40
38
  onMouseOver,
41
39
  onFocus,
42
- onClick,
43
- isInViewport,
44
- visibleColumns,
45
- checkable,
46
- limit
40
+ onClick
47
41
  }: RowProps): JSX.Element => {
48
- if (not(isInViewport) && gte(limit, performanceRowsLimit)) {
49
- return (
50
- <div className="contents">
51
- {checkable && (
52
- <div className="p-1">
53
- <div>
54
- <LoadingSkeleton className="w-full" />
55
- </div>
56
- </div>
57
- )}
58
- {visibleColumns.map(({ id }) => (
59
- <div className="p-1" key={`loading_${id}`}>
60
- <div>
61
- <LoadingSkeleton className="w-full" />
62
- </div>
63
- </div>
64
- ))}
65
- </div>
66
- );
67
- }
68
-
69
42
  return (
70
43
  <TableRow
71
44
  className="cursor-pointer contents w-full"
@@ -83,7 +56,6 @@ const Row = memo<RowProps>(
83
56
  const {
84
57
  row: previousRow,
85
58
  rowColorConditions: previousRowColorConditions,
86
- isInViewport: prevIsInViewport,
87
59
  visibleColumns: previousVisibleColumns,
88
60
  isShiftKeyDown: prevIsShiftKeyDown,
89
61
  shiftKeyDownRowPivot: prevShiftKeyDownRowPivot,
@@ -117,18 +89,6 @@ const Row = memo<RowProps>(
117
89
  return false;
118
90
  }
119
91
 
120
- const isNoLongerInViewport = not(prevIsInViewport) && not(nextIsInViewport);
121
-
122
- if (isNoLongerInViewport && gte(nextLimit, performanceRowsLimit)) {
123
- return true;
124
- }
125
-
126
- const isBackInViewport = not(prevIsInViewport) && nextIsInViewport;
127
-
128
- if (isBackInViewport && gte(nextLimit, performanceRowsLimit)) {
129
- return false;
130
- }
131
-
132
92
  const previousRowConditions = previousRowColorConditions?.map(
133
93
  ({ condition }) => condition(previousRow)
134
94
  );
@@ -185,7 +145,7 @@ const IntersectionRow = ({ isHovered, ...rest }: Props): JSX.Element => {
185
145
 
186
146
  useEffect(() => {
187
147
  setElement(getFirstCellElement() as HTMLDivElement);
188
- }, [getFirstCellElement, setElement]);
148
+ }, [getFirstCellElement()]);
189
149
 
190
150
  return (
191
151
  <div className="contents w-full" data-is-hovered={isHovered} ref={rowRef}>
@@ -10,7 +10,6 @@ import {
10
10
  filter,
11
11
  findIndex,
12
12
  gt,
13
- gte,
14
13
  identity,
15
14
  includes,
16
15
  isNil,
@@ -143,8 +142,6 @@ const defaultColumnConfiguration = {
143
142
  sortable: false
144
143
  };
145
144
 
146
- export const performanceRowsLimit = 60;
147
-
148
145
  const Listing = <
149
146
  TRow extends {
150
147
  id: RowId;
@@ -598,7 +595,7 @@ const Listing = <
598
595
  component="div"
599
596
  onMouseLeave={clearHoveredRow}
600
597
  >
601
- {rowsToDisplay.map((row, index) => {
598
+ {rowsToDisplay.map((row) => {
602
599
  const isRowSelected = isSelected(row);
603
600
  const isSubItem = allSubItemIds.includes(
604
601
  getSubItemRowId(row)
@@ -617,11 +614,7 @@ const Listing = <
617
614
  isHovered={isRowHovered}
618
615
  isSelected={isRowSelected}
619
616
  isShiftKeyDown={isShiftKeyDown}
620
- key={
621
- gte(limit, performanceRowsLimit)
622
- ? `row_${index}`
623
- : getRowId(row)
624
- }
617
+ key={getRowId(row)}
625
618
  lastSelectionIndex={lastSelectionIndex}
626
619
  limit={limit}
627
620
  listingVariant={listingVariant}
@@ -1,6 +1,7 @@
1
+ import { equals } from 'ramda';
1
2
  import { JsonDecoder } from 'ts.data.json';
2
3
 
3
- import type { Listing, ListingMeta } from './models';
4
+ import { Listing, ListingMeta } from './models';
4
5
 
5
6
  const metaDecoder = JsonDecoder.object<ListingMeta>(
6
7
  {
@@ -15,13 +16,34 @@ interface ListingDecoderOptions<TEntity> {
15
16
  entityDecoder: JsonDecoder.Decoder<TEntity>;
16
17
  entityDecoderName: string;
17
18
  listingDecoderName: string;
19
+ apiFormat?: 'Standard' | 'JSON-LD';
18
20
  }
19
21
 
20
- const buildListingDecoder = <TEntity>({
21
- entityDecoder,
22
- entityDecoderName,
23
- listingDecoderName
24
- }: ListingDecoderOptions<TEntity>): JsonDecoder.Decoder<Listing<TEntity>> =>
22
+ const jsonLdListingDecoder = <TEntity>(
23
+ entityDecoder: JsonDecoder.Decoder<TEntity>,
24
+ entityDecoderName: string,
25
+ listingDecoderName: string
26
+ ): JsonDecoder.Decoder<Listing<TEntity>> =>
27
+ JsonDecoder.object(
28
+ {
29
+ member: JsonDecoder.array(entityDecoder, entityDecoderName),
30
+ totalItems: JsonDecoder.number
31
+ },
32
+ listingDecoderName
33
+ ).map((data) => ({
34
+ meta: {
35
+ limit: data.member.length,
36
+ page: 1,
37
+ total: data.totalItems
38
+ },
39
+ result: data.member
40
+ })) as JsonDecoder.Decoder<Listing<TEntity>>;
41
+
42
+ const standardListingDecoder = <TEntity>(
43
+ entityDecoder: JsonDecoder.Decoder<TEntity>,
44
+ entityDecoderName: string,
45
+ listingDecoderName: string
46
+ ): JsonDecoder.Decoder<Listing<TEntity>> =>
25
47
  JsonDecoder.object<Listing<TEntity>>(
26
48
  {
27
49
  meta: metaDecoder,
@@ -30,4 +52,15 @@ const buildListingDecoder = <TEntity>({
30
52
  listingDecoderName
31
53
  );
32
54
 
55
+ const buildListingDecoder = <TEntity>({
56
+ entityDecoder,
57
+ entityDecoderName,
58
+ listingDecoderName,
59
+ apiFormat = 'Standard'
60
+ }: ListingDecoderOptions<TEntity>): JsonDecoder.Decoder<Listing<TEntity>> => {
61
+ return (
62
+ equals(apiFormat, 'JSON-LD') ? jsonLdListingDecoder : standardListingDecoder
63
+ )(entityDecoder, entityDecoderName, listingDecoderName);
64
+ };
65
+
33
66
  export default buildListingDecoder;
@@ -1,15 +1,27 @@
1
+ import { equals, keys, values } from 'ramda';
2
+
1
3
  import toRawQueryParameters from '../../queryParameters';
2
- import type { QueryParameter } from '../../queryParameters/models';
4
+ import { QueryParameter } from '../../queryParameters/models';
3
5
  import { getSearchQueryParameterValue } from './getSearchQueryParameterValue';
4
- import type { BuildListingEndpointParameters, Parameters } from './models';
6
+ import { BuildListingEndpointParameters, Parameters } from './models';
5
7
 
6
8
  const getQueryParameters = ({
7
9
  sort,
8
10
  page,
9
11
  limit,
10
12
  search,
11
- customQueryParameters = []
13
+ customQueryParameters = [],
14
+ apiFormat
12
15
  }: Parameters): Array<QueryParameter> => {
16
+ if (equals(apiFormat, 'JSON-LD')) {
17
+ return [
18
+ { name: 'page', value: page },
19
+ { name: 'itemsPerPage', value: limit },
20
+ { name: `sort[${keys(sort || {})[0]}]`, value: values(sort || {})[0] },
21
+ ...customQueryParameters
22
+ ];
23
+ }
24
+
13
25
  return [
14
26
  { name: 'page', value: page },
15
27
  { name: 'limit', value: limit },
@@ -22,33 +34,25 @@ const getQueryParameters = ({
22
34
  ];
23
35
  };
24
36
 
25
- const buildEndpoint = ({ baseEndpoint, queryParameters }): string => {
26
- return `${baseEndpoint}?${toRawQueryParameters(queryParameters)}`;
27
- };
28
-
29
- const buildCustomEndpoint = ({ baseEndpoint, queryParameters }): string => {
30
- return `${baseEndpoint}&${toRawQueryParameters(queryParameters)}`;
37
+ const buildEndpoint = ({
38
+ baseEndpoint,
39
+ queryParameters,
40
+ apiFormat
41
+ }): string => {
42
+ return `${baseEndpoint}?${toRawQueryParameters({ apiFormat, queryParameters })}`;
31
43
  };
32
44
 
33
45
  const buildListingEndpoint = ({
34
46
  baseEndpoint,
35
47
  parameters,
36
48
  customQueryParameters,
37
- isCustomEndpoint = false
49
+ apiFormat = 'Standard'
38
50
  }: BuildListingEndpointParameters): string => {
39
- if (isCustomEndpoint) {
40
- return buildCustomEndpoint({
41
- baseEndpoint,
42
- queryParameters: [
43
- ...getQueryParameters({ ...parameters, customQueryParameters })
44
- ]
45
- });
46
- }
47
-
48
51
  return buildEndpoint({
52
+ apiFormat,
49
53
  baseEndpoint,
50
54
  queryParameters: [
51
- ...getQueryParameters({ ...parameters, customQueryParameters })
55
+ ...getQueryParameters({ ...parameters, apiFormat, customQueryParameters })
52
56
  ]
53
57
  });
54
58
  };
@@ -3,8 +3,8 @@ import type { QueryParameter } from '../../queryParameters/models';
3
3
  export interface BuildListingEndpointParameters {
4
4
  baseEndpoint?: string;
5
5
  customQueryParameters?: Array<QueryParameter>;
6
- parameters: Parameters;
7
- isCustomEndpoint?: boolean;
6
+ parameters: Omit<Parameters, 'apiFormat' | 'customQueryParameters'>;
7
+ apiFormat?: 'Standard' | 'JSON-LD';
8
8
  }
9
9
 
10
10
  export interface SearchMatch {
@@ -18,7 +18,9 @@ export interface Parameters {
18
18
  page?: number;
19
19
  search?: SearchParameter;
20
20
  sort?: SortQueryParameterValue;
21
+ apiFormat: 'Standard' | 'JSON-LD';
21
22
  }
23
+
22
24
  export interface SearchParameter {
23
25
  conditions?: Array<ConditionsSearchParameter>;
24
26
  lists?: Array<ListsSearchParameter>;
@@ -114,7 +114,9 @@ const useMutationQuery = <T extends object, TMeta>({
114
114
  defaultFailureMessage,
115
115
  endpoint: getEndpoint(_meta as TMeta),
116
116
  headers: new Headers({
117
- 'Content-Type': 'application/json',
117
+ 'Content-Type': equals(method, Method.PATCH)
118
+ ? 'application/merge-patch+json'
119
+ : 'application/json',
118
120
  ...fetchHeaders
119
121
  }),
120
122
  isMutation: true,
@@ -1,14 +1,26 @@
1
- import { isEmpty, isNil } from 'ramda';
1
+ import { equals, isEmpty, isNil } from 'ramda';
2
2
 
3
3
  import type { QueryParameter } from './models';
4
4
 
5
+ interface ToRawQueryParametersProps {
6
+ queryParameters: Array<QueryParameter>;
7
+ apiFormat: 'Standard' | 'JSON-LD';
8
+ }
9
+
5
10
  const toRawQueryParameter = ({ name, value }): string => {
6
- return `${name}=${encodeURIComponent(JSON.stringify(value))}`;
11
+ return `${name}=${encodeURIComponent(value)}`;
7
12
  };
8
13
 
9
- const toRawQueryParameters = (queryParameters: Array<QueryParameter>): string =>
14
+ const toRawQueryParameters = ({
15
+ queryParameters,
16
+ apiFormat
17
+ }: ToRawQueryParametersProps): string =>
10
18
  queryParameters
11
19
  .filter(({ value }) => !isNil(value) && !isEmpty(value))
20
+ .map(({ name, value }) => ({
21
+ name,
22
+ value: equals(apiFormat, 'JSON-LD') ? value : JSON.stringify(value)
23
+ }))
12
24
  .map(toRawQueryParameter)
13
25
  .join('&');
14
26
 
@@ -21,7 +21,7 @@ interface MemoComponent {
21
21
  export const useMemoComponent = ({
22
22
  Component,
23
23
  memoProps
24
- }: MemoComponent): JSX.Element =>
25
- useMemo(() => Component, [...useDeepCompare(memoProps), Component]);
24
+ }: MemoComponent): ReactElement =>
25
+ useMemo(() => Component, useDeepCompare(memoProps));
26
26
 
27
27
  export default useMemoComponent;