@centreon/ui 26.3.18 → 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 +3 -3
- package/src/Form/Inputs/ConnectedAutocomplete.tsx +23 -14
- package/src/Form/Inputs/models.ts +1 -0
- package/src/Form/storiesData.tsx +2 -1
- package/src/InputField/Select/Autocomplete/index.tsx +5 -1
- package/src/InputField/Text/index.tsx +9 -5
- package/src/Listing/Row/Row.tsx +3 -42
- package/src/Listing/index.tsx +3 -10
- package/src/api/buildListingDecoder.ts +39 -6
- package/src/api/buildListingEndpoint/index.ts +24 -20
- package/src/api/buildListingEndpoint/models.ts +4 -2
- package/src/api/useMutationQuery/index.ts +3 -1
- package/src/queryParameters/index.ts +15 -3
- package/src/utils/useViewportIntersection.ts +6 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@centreon/ui",
|
|
3
|
-
"version": "26.
|
|
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
|
-
"
|
|
32
|
-
"
|
|
31
|
+
"react",
|
|
32
|
+
"centreon"
|
|
33
33
|
],
|
|
34
34
|
"author": {
|
|
35
35
|
"name": "centreon@centreon.com"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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 {
|
|
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
|
-
|
|
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:
|
|
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;
|
package/src/Form/storiesData.tsx
CHANGED
|
@@ -327,7 +327,8 @@ export const basicFormInputs: Array<InputProps> = [
|
|
|
327
327
|
{
|
|
328
328
|
connectedAutocomplete: {
|
|
329
329
|
additionalConditionParameters: [],
|
|
330
|
-
endpoint: 'endpoint'
|
|
330
|
+
endpoint: 'endpoint',
|
|
331
|
+
helperText: 'Hello I am testing'
|
|
331
332
|
},
|
|
332
333
|
fieldName: 'group',
|
|
333
334
|
label: 'Group (Single connected autocomplete)',
|
|
@@ -18,7 +18,8 @@ import {
|
|
|
18
18
|
type ForwardedRef,
|
|
19
19
|
forwardRef,
|
|
20
20
|
type HTMLAttributes,
|
|
21
|
-
type ReactElement
|
|
21
|
+
type ReactElement,
|
|
22
|
+
ReactNode
|
|
22
23
|
} from 'react';
|
|
23
24
|
import { useTranslation } from 'react-i18next';
|
|
24
25
|
|
|
@@ -32,6 +33,7 @@ import { useAutoCompleteStyles } from './autoComplete.styles';
|
|
|
32
33
|
export type Props = {
|
|
33
34
|
autoFocus?: boolean;
|
|
34
35
|
autoSize?: boolean;
|
|
36
|
+
helperText?: ReactNode;
|
|
35
37
|
autoSizeCustomPadding?: number;
|
|
36
38
|
autoSizeDefaultWidth?: number;
|
|
37
39
|
dataTestId?: string;
|
|
@@ -95,6 +97,7 @@ const AutocompleteField = forwardRef(
|
|
|
95
97
|
displayPopupIcon = true,
|
|
96
98
|
autoFocus = false,
|
|
97
99
|
hideInput = false,
|
|
100
|
+
helperText,
|
|
98
101
|
dataTestId,
|
|
99
102
|
autoSize = false,
|
|
100
103
|
autoSizeDefaultWidth = 0,
|
|
@@ -151,6 +154,7 @@ const AutocompleteField = forwardRef(
|
|
|
151
154
|
}}
|
|
152
155
|
error={error}
|
|
153
156
|
externalValueForAutoSize={autocompleteProps?.value?.name}
|
|
157
|
+
helperText={helperText}
|
|
154
158
|
label={label}
|
|
155
159
|
onChange={onTextChange}
|
|
156
160
|
placeholder={isNil(placeholder) ? t(searchLabel) : placeholder}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Box,
|
|
3
3
|
InputAdornment,
|
|
4
|
-
|
|
4
|
+
InputProps,
|
|
5
5
|
TextField as MuiTextField,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
TextFieldProps,
|
|
7
|
+
TextFieldSlotsAndSlotProps,
|
|
8
|
+
Theme,
|
|
9
9
|
Tooltip,
|
|
10
10
|
Typography
|
|
11
11
|
} from '@mui/material';
|
|
@@ -123,6 +123,7 @@ const TextField = forwardRef(
|
|
|
123
123
|
type,
|
|
124
124
|
textFieldSlotsAndSlotProps,
|
|
125
125
|
forceUncontrolled,
|
|
126
|
+
helperText,
|
|
126
127
|
...rest
|
|
127
128
|
}: TextProps,
|
|
128
129
|
ref: React.ForwardedRef<HTMLDivElement>
|
|
@@ -160,13 +161,16 @@ const TextField = forwardRef(
|
|
|
160
161
|
<MuiTextField
|
|
161
162
|
data-testid={dataTestId}
|
|
162
163
|
error={!isNil(error)}
|
|
163
|
-
helperText={
|
|
164
|
+
helperText={
|
|
165
|
+
(displayErrorInTooltip ? undefined : error) || helperText
|
|
166
|
+
}
|
|
164
167
|
id={getNormalizedId(dataTestId || '')}
|
|
165
168
|
label={label}
|
|
166
169
|
onChange={changeInputValue}
|
|
167
170
|
ref={ref}
|
|
168
171
|
size={size || 'small'}
|
|
169
172
|
{...getValueProps()}
|
|
173
|
+
autoComplete="off"
|
|
170
174
|
className={classes.textField}
|
|
171
175
|
required={required}
|
|
172
176
|
slotProps={{
|
package/src/Listing/Row/Row.tsx
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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
|
);
|
package/src/Listing/index.tsx
CHANGED
|
@@ -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
|
|
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
|
|
21
|
-
entityDecoder
|
|
22
|
-
entityDecoderName,
|
|
23
|
-
listingDecoderName
|
|
24
|
-
|
|
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
|
|
4
|
+
import { QueryParameter } from '../../queryParameters/models';
|
|
3
5
|
import { getSearchQueryParameterValue } from './getSearchQueryParameterValue';
|
|
4
|
-
import
|
|
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 = ({
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return `${baseEndpoint}
|
|
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
|
-
|
|
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
|
-
|
|
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':
|
|
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(
|
|
11
|
+
return `${name}=${encodeURIComponent(value)}`;
|
|
7
12
|
};
|
|
8
13
|
|
|
9
|
-
const toRawQueryParameters = (
|
|
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
|
|
|
@@ -18,11 +18,14 @@ export const useViewportIntersection = (
|
|
|
18
18
|
const [element, setElement] = useState<HTMLElement | null>(null);
|
|
19
19
|
|
|
20
20
|
const observer = useRef<IntersectionObserver | null>(null);
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
const sanitizedOptions = {
|
|
23
23
|
...options,
|
|
24
|
-
root:
|
|
25
|
-
|
|
24
|
+
root:
|
|
25
|
+
options?.root instanceof HTMLElement
|
|
26
|
+
? `${options.root.tagName}_${options.root.className}`
|
|
27
|
+
: null
|
|
28
|
+
};
|
|
26
29
|
|
|
27
30
|
useEffect(() => {
|
|
28
31
|
if (observer.current) {
|