@centreon/ui 26.3.19 → 26.5.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": "26.3.19",
3
+ "version": "26.5.0",
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;
@@ -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,11 @@ 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';
9
+
11
10
  import type { Column, ColumnConfiguration, RowColorCondition } from '../models';
12
11
 
13
12
  type Props = {
@@ -39,33 +38,8 @@ const Row = memo<RowProps>(
39
38
  tabIndex,
40
39
  onMouseOver,
41
40
  onFocus,
42
- onClick,
43
- isInViewport,
44
- visibleColumns,
45
- checkable,
46
- limit
41
+ onClick
47
42
  }: 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
43
  return (
70
44
  <TableRow
71
45
  className="cursor-pointer contents w-full"
@@ -83,7 +57,6 @@ const Row = memo<RowProps>(
83
57
  const {
84
58
  row: previousRow,
85
59
  rowColorConditions: previousRowColorConditions,
86
- isInViewport: prevIsInViewport,
87
60
  visibleColumns: previousVisibleColumns,
88
61
  isShiftKeyDown: prevIsShiftKeyDown,
89
62
  shiftKeyDownRowPivot: prevShiftKeyDownRowPivot,
@@ -117,18 +90,6 @@ const Row = memo<RowProps>(
117
90
  return false;
118
91
  }
119
92
 
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
93
  const previousRowConditions = previousRowColorConditions?.map(
133
94
  ({ condition }) => condition(previousRow)
134
95
  );
@@ -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,
@@ -46,6 +45,8 @@ import DataCell from './Cell/DataCell';
46
45
  import Checkbox from './Checkbox';
47
46
  import { EmptyResult } from './EmptyResult/EmptyResult';
48
47
  import { ListingHeader } from './Header';
48
+ import ListingRow from './Row/Row';
49
+ import { SkeletonLoader } from './Row/SkeletonLoaderRows';
49
50
  import type {
50
51
  Column,
51
52
  ColumnConfiguration,
@@ -54,8 +55,6 @@ import type {
54
55
  RowId,
55
56
  SortOrder
56
57
  } from './models';
57
- import ListingRow from './Row/Row';
58
- import { SkeletonLoader } from './Row/SkeletonLoaderRows';
59
58
  import { subItemsPivotsAtom } from './tableAtoms';
60
59
  import { labelNoResultFound as defaultLabelNoResultFound } from './translatedLabels';
61
60
  import useStyleTable, { useColumnStyle } from './useStyleTable';
@@ -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;
@@ -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