@centreon/ui 24.4.4 → 24.4.6

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.
Files changed (66) hide show
  1. package/package.json +12 -16
  2. package/src/Button/Save/StartIcon.tsx +3 -3
  3. package/src/Dashboard/Item.tsx +1 -1
  4. package/src/Dashboard/Layout.tsx +2 -2
  5. package/src/FileDropZone/index.tsx +1 -3
  6. package/src/Form/Inputs/CheckboxGroup.tsx +4 -1
  7. package/src/Form/Inputs/index.tsx +1 -1
  8. package/src/Graph/HeatMap/HeatMap.styles.tsx +0 -1
  9. package/src/Graph/HeatMap/ResponsiveHeatMap.tsx +8 -12
  10. package/src/Graph/HeatMap/model.ts +0 -1
  11. package/src/Graph/LineChart/BasicComponents/Lines/Threshold/Circle.tsx +2 -2
  12. package/src/Graph/LineChart/BasicComponents/Lines/Threshold/index.tsx +4 -5
  13. package/src/Graph/LineChart/BasicComponents/Thresholds.tsx +2 -2
  14. package/src/Graph/LineChart/BasicComponents/useFilterLines.ts +1 -1
  15. package/src/Graph/LineChart/InteractiveComponents/AnchorPoint/GuidingLines.tsx +2 -2
  16. package/src/Graph/LineChart/InteractiveComponents/Annotations/Annotation/index.tsx +3 -2
  17. package/src/Graph/LineChart/InteractiveComponents/Annotations/EventAnnotations.tsx +1 -1
  18. package/src/Graph/LineChart/Legend/useLegend.ts +3 -3
  19. package/src/Graph/LineChart/helpers/doc.ts +13 -16
  20. package/src/Graph/LineChart/helpers/index.ts +1 -1
  21. package/src/Graph/LineChart/index.stories.tsx +2 -4
  22. package/src/Graph/SingleBar/Thresholds.tsx +2 -2
  23. package/src/Graph/Text/Text.stories.tsx +4 -60
  24. package/src/Graph/common/timeSeries/index.ts +3 -3
  25. package/src/InputField/Select/Autocomplete/Connected/Multi/index.test.tsx +0 -1
  26. package/src/InputField/Select/Autocomplete/Connected/index.test.tsx +0 -1
  27. package/src/InputField/Select/Autocomplete/Connected/index.tsx +7 -13
  28. package/src/InputField/Select/Autocomplete/Draggable/SortableList.tsx +1 -1
  29. package/src/InputField/Select/Autocomplete/Draggable/SortableListContent.tsx +1 -1
  30. package/src/InputField/Select/Autocomplete/Draggable/index.tsx +1 -1
  31. package/src/InputField/Select/IconPopover/index.tsx +2 -2
  32. package/src/InputField/Select/index.tsx +1 -1
  33. package/src/InputField/Text/index.tsx +1 -6
  34. package/src/Listing/Header/ListingHeader.tsx +1 -1
  35. package/src/Listing/index.stories.tsx +1 -12
  36. package/src/Listing/index.tsx +1 -1
  37. package/src/RichTextEditor/RichTextEditor.tsx +1 -12
  38. package/src/SortableItems/index.tsx +7 -2
  39. package/src/ThemeProvider/palettes.ts +4 -4
  40. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/PickersStartEndDate.tsx +3 -8
  41. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/models.ts +2 -0
  42. package/src/TimePeriods/DateTimePickerInput.tsx +17 -45
  43. package/src/TimePeriods/TimePeriods.cypress.spec.tsx +33 -9
  44. package/src/TimePeriods/helpers/index.ts +1 -1
  45. package/src/TimePeriods/index.stories.tsx +4 -12
  46. package/src/TimePeriods/index.tsx +2 -2
  47. package/src/api/QueryProvider.tsx +1 -1
  48. package/src/api/TestQueryProvider.tsx +1 -1
  49. package/src/api/buildListingEndpoint/models.ts +1 -2
  50. package/src/api/customFetch.ts +3 -12
  51. package/src/api/useFetchQuery/index.ts +28 -43
  52. package/src/api/useMutationQuery/index.ts +18 -43
  53. package/src/components/DataTable/Item/DataTableItem.tsx +2 -2
  54. package/src/components/Form/AccessRights/__fixtures__/contactAccessRight.mock.ts +0 -2
  55. package/src/components/Form/AccessRights/useAccessRightsForm.utils.ts +1 -1
  56. package/src/components/Form/Dashboard/DashboardForm.tsx +12 -15
  57. package/src/index.ts +0 -1
  58. package/src/queryParameters/url/index.ts +1 -5
  59. package/src/screens/dashboard/DashboardsDetail.stories.tsx +108 -0
  60. package/src/screens/dashboard/DashboardsOverview.stories.tsx +281 -0
  61. package/src/utils/index.ts +1 -0
  62. package/src/utils/useDateTimePickerAdapter.ts +309 -0
  63. package/src/utils/useInfiniteScrollListing.ts +7 -22
  64. package/src/utils/{useLicenseExpirationWarning.test.tsx → useLicenseExpirationWarning.cypress.spec.tsx} +37 -48
  65. package/src/utils/useLicenseExpirationWarning.ts +18 -18
  66. package/src/utils/useLocaleDateTimeFormat/index.ts +0 -3
@@ -1,4 +1,4 @@
1
- import { useEffect, useMemo, useRef } from 'react';
1
+ import { useEffect, useMemo } from 'react';
2
2
 
3
3
  import 'ulog';
4
4
  import {
@@ -10,14 +10,13 @@ import {
10
10
  } from '@tanstack/react-query';
11
11
  import { JsonDecoder } from 'ts.data.json';
12
12
  import anylogger from 'anylogger';
13
- import { has, includes, isNil, not, omit } from 'ramda';
13
+ import { has, includes, not, omit } from 'ramda';
14
14
 
15
15
  import { CatchErrorProps, customFetch, ResponseError } from '../customFetch';
16
16
  import useSnackbar from '../../Snackbar/useSnackbar';
17
17
  import { useDeepCompare } from '../../utils';
18
18
 
19
19
  export interface UseFetchQueryProps<T> {
20
- baseEndpoint?: string;
21
20
  catchError?: (props: CatchErrorProps) => void;
22
21
  decoder?: JsonDecoder.Decoder<T>;
23
22
  defaultFailureMessage?: string;
@@ -26,9 +25,7 @@ export interface UseFetchQueryProps<T> {
26
25
  getQueryKey: () => QueryKey;
27
26
  httpCodesBypassErrorSnackbar?: Array<number>;
28
27
  isPaginated?: boolean;
29
- queryOptions?: {
30
- suspense?: boolean;
31
- } & Omit<
28
+ queryOptions?: Omit<
32
29
  UseQueryOptions<T | ResponseError, Error, T | ResponseError, QueryKey>,
33
30
  'queryKey' | 'queryFn'
34
31
  >;
@@ -36,12 +33,11 @@ export interface UseFetchQueryProps<T> {
36
33
 
37
34
  export type UseFetchQueryState<T> = {
38
35
  data?: T;
39
- error: Omit<ResponseError, 'isError'> | null;
40
36
  fetchQuery: () => Promise<T | ResponseError>;
41
37
  prefetchNextPage: ({ page, getPrefetchQueryKey }) => void;
42
38
  prefetchPreviousPage: ({ page, getPrefetchQueryKey }) => void;
43
39
  prefetchQuery: ({ endpointParams, queryKey }) => void;
44
- } & Omit<QueryObserverBaseResult, 'data' | 'error'>;
40
+ } & Omit<QueryObserverBaseResult, 'data'>;
45
41
 
46
42
  export interface PrefetchEndpointParams {
47
43
  page: number;
@@ -58,17 +54,14 @@ const useFetchQuery = <T extends object>({
58
54
  fetchHeaders,
59
55
  isPaginated,
60
56
  queryOptions,
61
- httpCodesBypassErrorSnackbar = [],
62
- baseEndpoint
57
+ httpCodesBypassErrorSnackbar = []
63
58
  }: UseFetchQueryProps<T>): UseFetchQueryState<T> => {
64
- const dataRef = useRef<T | undefined>(undefined);
65
-
66
59
  const { showErrorMessage } = useSnackbar();
67
60
 
68
- const queryData = useQuery<T | ResponseError, Error>({
69
- queryFn: ({ signal }): Promise<T | ResponseError> =>
61
+ const queryData = useQuery<T | ResponseError, Error>(
62
+ getQueryKey(),
63
+ ({ signal }): Promise<T | ResponseError> =>
70
64
  customFetch<T>({
71
- baseEndpoint,
72
65
  catchError,
73
66
  decoder,
74
67
  defaultFailureMessage,
@@ -76,9 +69,10 @@ const useFetchQuery = <T extends object>({
76
69
  headers: new Headers(fetchHeaders),
77
70
  signal
78
71
  }),
79
- queryKey: getQueryKey(),
80
- ...queryOptions
81
- });
72
+ {
73
+ ...queryOptions
74
+ }
75
+ );
82
76
 
83
77
  const queryClient = useQueryClient();
84
78
 
@@ -98,19 +92,18 @@ const useFetchQuery = <T extends object>({
98
92
  };
99
93
 
100
94
  const prefetchQuery = ({ endpointParams, queryKey }): void => {
101
- queryClient.prefetchQuery({
102
- queryFn: ({ signal }): Promise<T | ResponseError> =>
95
+ queryClient.prefetchQuery(
96
+ queryKey,
97
+ ({ signal }): Promise<T | ResponseError> =>
103
98
  customFetch<T>({
104
- baseEndpoint,
105
99
  catchError,
106
100
  decoder,
107
101
  defaultFailureMessage,
108
102
  endpoint: getEndpoint(endpointParams),
109
103
  headers: new Headers(fetchHeaders),
110
104
  signal
111
- }),
112
- queryKey
113
- });
105
+ })
106
+ );
114
107
  };
115
108
 
116
109
  const prefetchNextPage = ({ page, getPrefetchQueryKey }): void => {
@@ -140,19 +133,18 @@ const useFetchQuery = <T extends object>({
140
133
  };
141
134
 
142
135
  const fetchQuery = (): Promise<T | ResponseError> => {
143
- return queryClient.fetchQuery({
144
- queryFn: ({ signal }): Promise<T | ResponseError> =>
136
+ return queryClient.fetchQuery(
137
+ getQueryKey(),
138
+ ({ signal }): Promise<T | ResponseError> =>
145
139
  customFetch<T>({
146
- baseEndpoint,
147
140
  catchError,
148
141
  decoder,
149
142
  defaultFailureMessage,
150
143
  endpoint: getEndpoint(),
151
144
  headers: new Headers(fetchHeaders),
152
145
  signal
153
- }),
154
- queryKey: getQueryKey()
155
- });
146
+ })
147
+ );
156
148
  };
157
149
 
158
150
  const data = useMemo(
@@ -161,28 +153,21 @@ const useFetchQuery = <T extends object>({
161
153
  [queryData.data]
162
154
  );
163
155
 
164
- if (!isNil(data)) {
165
- dataRef.current = data;
166
- }
167
-
168
156
  const errorData = queryData.data as ResponseError | undefined;
169
157
 
170
158
  useEffect(() => {
171
159
  return (): void => {
172
- queryClient.cancelQueries({ queryKey: getQueryKey() });
160
+ queryClient.cancelQueries(getQueryKey());
173
161
  };
174
162
  }, []);
175
163
 
176
- useEffect(
177
- () => {
178
- manageError();
179
- },
180
- useDeepCompare([queryData.data])
181
- );
164
+ useEffect(() => {
165
+ manageError();
166
+ }, useDeepCompare([queryData.data]));
182
167
 
183
168
  return {
184
- ...omit(['data', 'error'], queryData),
185
- data: dataRef.current,
169
+ ...omit(['data'], queryData),
170
+ data,
186
171
  error: errorData?.isError ? omit(['isError'], errorData) : null,
187
172
  fetchQuery,
188
173
  prefetchNextPage,
@@ -8,7 +8,7 @@ import {
8
8
  } from '@tanstack/react-query';
9
9
  import { JsonDecoder } from 'ts.data.json';
10
10
  import anylogger from 'anylogger';
11
- import { includes, omit } from 'ramda';
11
+ import { includes } from 'ramda';
12
12
 
13
13
  import { CatchErrorProps, customFetch, ResponseError } from '../customFetch';
14
14
  import useSnackbar from '../../Snackbar/useSnackbar';
@@ -23,7 +23,6 @@ export enum Method {
23
23
  }
24
24
 
25
25
  export type UseMutationQueryProps<T, TMeta> = {
26
- baseEndpoint?: string;
27
26
  catchError?: (props: CatchErrorProps) => void;
28
27
  decoder?: JsonDecoder.Decoder<T>;
29
28
  defaultFailureMessage?: string;
@@ -31,33 +30,14 @@ export type UseMutationQueryProps<T, TMeta> = {
31
30
  getEndpoint: (_meta: TMeta) => string;
32
31
  httpCodesBypassErrorSnackbar?: Array<number>;
33
32
  method: Method;
34
- onError?: (
35
- error: ResponseError,
36
- variables: T & { _meta: TMeta },
37
- context: unknown
38
- ) => unknown;
39
- onMutate?: (variables: T & { _meta: TMeta }) => Promise<unknown> | unknown;
40
- onSuccess?: (
41
- data: ResponseError | T,
42
- variables: T & {
43
- _meta: TMeta;
44
- },
45
- context: unknown
46
- ) => unknown;
47
- } & Omit<
48
- UseMutationOptions<T & { _meta?: TMeta }>,
49
- 'mutationFn' | 'onError' | 'onMutate' | 'onSuccess'
50
- >;
33
+ } & Omit<UseMutationOptions<T & { _meta?: TMeta }>, 'mutationFn'>;
51
34
 
52
35
  const log = anylogger('API Request');
53
36
 
54
- export type UseMutationQueryState<T> = Omit<
55
- UseMutationResult<T | ResponseError>,
56
- 'isError'
57
- > & {
37
+ export type UseMutationQueryState<T> = {
58
38
  isError: boolean;
59
39
  isMutating: boolean;
60
- };
40
+ } & UseMutationResult<T | ResponseError>;
61
41
 
62
42
  const useMutationQuery = <T extends object, TMeta>({
63
43
  getEndpoint,
@@ -69,8 +49,7 @@ const useMutationQuery = <T extends object, TMeta>({
69
49
  method,
70
50
  onMutate,
71
51
  onError,
72
- onSuccess,
73
- baseEndpoint
52
+ onSuccess
74
53
  }: UseMutationQueryProps<T, TMeta>): UseMutationQueryState<T> => {
75
54
  const { showErrorMessage } = useSnackbar();
76
55
 
@@ -78,14 +57,11 @@ const useMutationQuery = <T extends object, TMeta>({
78
57
  T | ResponseError,
79
58
  ResponseError,
80
59
  T & { _meta: TMeta }
81
- >({
82
- mutationFn: (
83
- _payload: T & { _meta: TMeta }
84
- ): Promise<T | ResponseError> => {
60
+ >(
61
+ (_payload: T & { _meta: TMeta }): Promise<T | ResponseError> => {
85
62
  const { _meta, ...payload } = _payload || {};
86
63
 
87
64
  return customFetch<T>({
88
- baseEndpoint,
89
65
  catchError,
90
66
  decoder,
91
67
  defaultFailureMessage,
@@ -99,10 +75,12 @@ const useMutationQuery = <T extends object, TMeta>({
99
75
  payload
100
76
  });
101
77
  },
102
- onError,
103
- onMutate,
104
- onSuccess
105
- });
78
+ {
79
+ onError,
80
+ onMutate,
81
+ onSuccess
82
+ }
83
+ );
106
84
 
107
85
  const manageError = (): void => {
108
86
  const data = queryData.data as ResponseError | undefined;
@@ -119,17 +97,14 @@ const useMutationQuery = <T extends object, TMeta>({
119
97
  }
120
98
  };
121
99
 
122
- useEffect(
123
- () => {
124
- manageError();
125
- },
126
- useDeepCompare([queryData.data])
127
- );
100
+ useEffect(() => {
101
+ manageError();
102
+ }, useDeepCompare([queryData.data]));
128
103
 
129
104
  return {
130
- ...omit(['isError'], queryData),
105
+ ...queryData,
131
106
  isError: (queryData.data as ResponseError | undefined)?.isError || false,
132
- isMutating: queryData.isPending
107
+ isMutating: queryData.isLoading
133
108
  };
134
109
  };
135
110
 
@@ -22,7 +22,7 @@ export interface DataTableItemProps {
22
22
  description?: string;
23
23
  hasActions?: boolean;
24
24
  hasCardAction?: boolean;
25
- labelsDelete?: {
25
+ labelsDelete: {
26
26
  cancel: string;
27
27
  confirm: {
28
28
  label: string;
@@ -76,7 +76,7 @@ const DataTableItem = forwardRef(
76
76
  {hasActions && (
77
77
  <MuiCardActions>
78
78
  <span>
79
- {onDelete && labelsDelete && (
79
+ {onDelete && (
80
80
  <ConfirmationTooltip
81
81
  confirmVariant="error"
82
82
  labels={labelsDelete}
@@ -7,8 +7,6 @@ import {
7
7
  RoleResource
8
8
  } from '../AccessRights.resource';
9
9
 
10
- faker.seed(42);
11
-
12
10
  export const rolesMock = (): Array<RoleResource> => [
13
11
  { role: 'viewer' },
14
12
  { role: 'editor' }
@@ -36,6 +36,6 @@ export const createInitialState = (
36
36
  contactAccessRight,
37
37
  state: 'unchanged',
38
38
  stateHistory: []
39
- }) as ContactAccessRightStateResource
39
+ } as ContactAccessRightStateResource)
40
40
  )
41
41
  .sort(sortOnAddedStateFirstAndContactName);
@@ -1,8 +1,7 @@
1
1
  import { ReactElement, useCallback, useMemo } from 'react';
2
2
 
3
- import { string, number, object } from 'yup';
3
+ import * as Yup from 'yup';
4
4
  import { useTranslation } from 'react-i18next';
5
- import { equals } from 'ramda';
6
5
 
7
6
  import { InputType } from '../../../Form/Inputs/models';
8
7
  import { Form, FormProps } from '../../../Form';
@@ -85,8 +84,8 @@ const DashboardForm = ({
85
84
  }
86
85
  ],
87
86
  submit: (values, bag) => onSubmit?.(values, bag),
88
- validationSchema: object({
89
- description: string()
87
+ validationSchema: Yup.object().shape({
88
+ description: Yup.string()
90
89
  .label(labels?.entity?.description || '')
91
90
  .max(
92
91
  180,
@@ -94,19 +93,17 @@ const DashboardForm = ({
94
93
  `${p.label} ${t(labelMustBeMost)} ${p.max} ${t(labelCharacters)}`
95
94
  )
96
95
  .nullable(),
97
- globalRefreshInterval: object({
98
- interval: number().when('type', ([type], schema) => {
99
- if (equals(type, 'manual')) {
100
- schema
101
- .min(1, ({ min }) => t(labelMustBeAtLeast, { min }))
102
- .required(t(labelRequired) as string);
103
- }
104
-
105
- return schema.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)
106
103
  }),
107
- type: string()
104
+ type: Yup.string()
108
105
  }),
109
- name: string()
106
+ name: Yup.string()
110
107
  .label(labels?.entity?.name)
111
108
  .min(3, ({ min, label }) => t(labelMustBeAtLeast, { label, min }))
112
109
  .max(50, ({ max, label }) => t(labelMustBeMost, { label, max }))
package/src/index.ts CHANGED
@@ -162,5 +162,4 @@ export * from './Graph/common/timeSeries';
162
162
 
163
163
  export { default as TimePeriods } from './TimePeriods';
164
164
  export { default as SimpleCustomTimePeriod } from './TimePeriods/CustomTimePeriod/SimpleCustomTimePeriod';
165
- export { default as DateTimePickerInput } from './TimePeriods/DateTimePickerInput';
166
165
  export * from './ParentSize';
@@ -1,4 +1,4 @@
1
- import { fromPairs, startsWith } from 'ramda';
1
+ import { fromPairs } from 'ramda';
2
2
 
3
3
  import { QueryParameter } from '../models';
4
4
 
@@ -25,10 +25,6 @@ const getUrlQueryParameters = <
25
25
 
26
26
  const entries = [...urlParams.entries()].map<[string, string]>(
27
27
  ([key, value]) => {
28
- if (startsWith('/', value)) {
29
- return [key, value];
30
- }
31
-
32
28
  return [key, JSON.parse(value)];
33
29
  }
34
30
  );
@@ -0,0 +1,108 @@
1
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
+ import React, { ReactElement } from 'react';
3
+
4
+ import { Meta } from '@storybook/react';
5
+
6
+ import {
7
+ Add as AddIcon,
8
+ Settings as SettingsIcon,
9
+ Share as ShareIcon
10
+ } from '@mui/icons-material';
11
+
12
+ import {
13
+ Button,
14
+ IconButton,
15
+ Menu,
16
+ PageHeader,
17
+ PageLayout
18
+ } from '../../components';
19
+
20
+ const meta: Meta = {
21
+ args: {
22
+ actions: {}
23
+ },
24
+ parameters: {
25
+ layout: 'fullscreen'
26
+ },
27
+ title: 'screens/Dashboards detail'
28
+ };
29
+
30
+ export default meta;
31
+
32
+ const DefaultView = (args): ReactElement => {
33
+ const { data } = args;
34
+
35
+ return (
36
+ <PageLayout>
37
+ <PageLayout.Header>
38
+ <PageHeader>
39
+ <PageHeader.Main>
40
+ <PageHeader.Menu>
41
+ <Menu>
42
+ <Menu.Button />
43
+ <Menu.Items>
44
+ <Menu.Item>Menu Item</Menu.Item>
45
+ <Menu.Item>Menu Item</Menu.Item>
46
+ <Menu.Item>Menu Item</Menu.Item>
47
+ <Menu.Divider />
48
+ <Menu.Item>
49
+ <Button
50
+ icon={<AddIcon />}
51
+ iconVariant="start"
52
+ variant="ghost"
53
+ >
54
+ Add item
55
+ </Button>
56
+ </Menu.Item>
57
+ </Menu.Items>
58
+ </Menu>
59
+ </PageHeader.Menu>
60
+ <PageHeader.Title
61
+ description={data.dashboard.description}
62
+ title={data.dashboard.name}
63
+ />
64
+ </PageHeader.Main>
65
+ </PageHeader>
66
+ </PageLayout.Header>
67
+ <PageLayout.Body>
68
+ <PageLayout.Actions>
69
+ <IconButton
70
+ aria-label="edit"
71
+ data-testid="edit"
72
+ icon={<SettingsIcon />}
73
+ size="small"
74
+ variant="ghost"
75
+ />
76
+ <IconButton
77
+ aria-label="share"
78
+ data-testid="share"
79
+ icon={<ShareIcon />}
80
+ size="small"
81
+ variant="ghost"
82
+ />
83
+ </PageLayout.Actions>
84
+ </PageLayout.Body>
85
+ </PageLayout>
86
+ );
87
+ };
88
+
89
+ export const Default = {
90
+ args: {
91
+ data: {
92
+ dashboard: {
93
+ description:
94
+ 'Description et culpa sit commodo ea enim excepteur elit. Velit irure velit tempor culpa commodo eu adipisicing eu proident ullamco.',
95
+ id: 1,
96
+ name: 'Dashboard 1'
97
+ }
98
+ }
99
+ },
100
+ render: DefaultView
101
+ };
102
+
103
+ export const AsEditLayoutState = {
104
+ args: {
105
+ ...Default.args
106
+ },
107
+ render: DefaultView
108
+ };