@centreon/ui 24.4.1-MON-24417-integrate-newman-collection-api-v2.4 → 24.4.1-MON-34691-improve-code-coverage.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.
Files changed (115) hide show
  1. package/package.json +6 -1
  2. package/public/mockServiceWorker.js +2 -2
  3. package/src/Button/Icon/index.stories.tsx +1 -1
  4. package/src/Button/Icon/index.tsx +1 -1
  5. package/src/Button/Save/index.tsx +9 -5
  6. package/src/Checkbox/Checkbox.tsx +2 -2
  7. package/src/Checkbox/CheckboxGroup/index.tsx +2 -2
  8. package/src/Dialog/index.tsx +1 -1
  9. package/src/FallbackPage/FallbackPage.tsx +3 -3
  10. package/src/Graph/LineChart/Legend/Legend.styles.ts +1 -1
  11. package/src/Graph/LineChart/Legend/LegendHeader.tsx +1 -1
  12. package/src/Graph/LineChart/Legend/index.tsx +7 -8
  13. package/src/Graph/LineChart/Legend/useInteractiveValues.ts +2 -2
  14. package/src/Graph/LineChart/LineChart.tsx +4 -1
  15. package/src/Graph/LineChart/index.tsx +5 -2
  16. package/src/Graph/index.ts +1 -0
  17. package/src/InputField/Number/Number.cypress.spec.tsx +85 -0
  18. package/src/InputField/Number/Number.stories.tsx +66 -0
  19. package/src/InputField/Number/Number.tsx +74 -0
  20. package/src/InputField/Search/index.tsx +2 -2
  21. package/src/InputField/Select/Autocomplete/Connected/index.tsx +12 -3
  22. package/src/InputField/Select/Autocomplete/index.tsx +121 -115
  23. package/src/InputField/Select/IconPopover/index.tsx +1 -1
  24. package/src/InputField/Text/index.tsx +40 -40
  25. package/src/Listing/ActionBar/index.tsx +1 -2
  26. package/src/Listing/Cell/DataCell.tsx +15 -1
  27. package/src/Listing/index.tsx +131 -117
  28. package/src/Module/LicensedModule/LicenseCheck/index.tsx +24 -9
  29. package/src/Module/LicensedModule/index.tsx +7 -1
  30. package/src/Module/Module.cypress.spec.tsx +129 -0
  31. package/src/Module/index.tsx +2 -4
  32. package/src/Panel/index.tsx +1 -1
  33. package/src/TimePeriods/CustomTimePeriod/CompactCustomTimePeriod.styles.ts +6 -7
  34. package/src/TimePeriods/DateTimePickerInput.tsx +12 -3
  35. package/src/TimePeriods/ResolutionTimePeriod.cypress.spec.tsx +12 -9
  36. package/src/api/useFetchQuery/index.ts +7 -1
  37. package/src/api/useGraphQuery/index.ts +26 -5
  38. package/src/api/useGraphQuery/models.ts +5 -0
  39. package/src/api/useMutationQuery/index.ts +8 -1
  40. package/src/components/CollapsibleItem/CollapsibleItem.cypress.spec.tsx +76 -0
  41. package/src/components/CollapsibleItem/CollapsibleItem.stories.tsx +26 -0
  42. package/src/components/CollapsibleItem/CollapsibleItem.tsx +43 -14
  43. package/src/components/CollapsibleItem/useCollapsibleItemStyles.ts +24 -1
  44. package/src/components/DataTable/Item/DataTableItem.tsx +2 -2
  45. package/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx +373 -0
  46. package/src/components/Form/AccessRights/AccessRights.stories.tsx +119 -0
  47. package/src/components/Form/AccessRights/AccessRights.styles.ts +10 -0
  48. package/src/components/Form/AccessRights/AccessRights.tsx +60 -0
  49. package/src/components/Form/AccessRights/Actions/Actions.styles.ts +14 -0
  50. package/src/components/Form/AccessRights/Actions/Actions.tsx +81 -0
  51. package/src/components/Form/AccessRights/Actions/useActions.ts +79 -0
  52. package/src/components/Form/AccessRights/List/Item.tsx +90 -0
  53. package/src/components/Form/AccessRights/List/List.styles.tsx +45 -0
  54. package/src/components/Form/AccessRights/List/List.tsx +52 -0
  55. package/src/components/Form/AccessRights/List/ListItemSkeleton.tsx +18 -0
  56. package/src/components/Form/AccessRights/List/ListSkeleton.tsx +22 -0
  57. package/src/components/Form/AccessRights/List/RemoveAccessRight.tsx +38 -0
  58. package/src/components/Form/AccessRights/List/StateChip.tsx +28 -0
  59. package/src/components/Form/AccessRights/List/useItem.ts +64 -0
  60. package/src/components/Form/AccessRights/Provider.tsx +15 -0
  61. package/src/components/Form/AccessRights/ShareInput/ContactSwitch.tsx +50 -0
  62. package/src/components/Form/AccessRights/ShareInput/ShareInput.styles.ts +17 -0
  63. package/src/components/Form/AccessRights/ShareInput/ShareInput.tsx +77 -0
  64. package/src/components/Form/AccessRights/ShareInput/useShareInput.tsx +113 -0
  65. package/src/components/Form/AccessRights/Stats/Stats.tsx +36 -0
  66. package/src/components/Form/AccessRights/atoms.ts +97 -0
  67. package/src/components/Form/AccessRights/common/RoleSelectField.styles.tsx +7 -0
  68. package/src/components/Form/AccessRights/common/RoleSelectField.tsx +45 -0
  69. package/src/components/Form/AccessRights/models.ts +55 -0
  70. package/src/components/Form/AccessRights/storiesData.ts +222 -0
  71. package/src/components/Form/AccessRights/useAccessRightsInitValues.ts +51 -0
  72. package/src/components/Form/index.ts +2 -1
  73. package/src/components/ItemComposition/Item.tsx +1 -1
  74. package/src/components/ItemComposition/ItemComposition.cypress.spec.tsx +113 -0
  75. package/src/components/ItemComposition/ItemComposition.stories.tsx +14 -0
  76. package/src/components/ItemComposition/ItemComposition.styles.ts +34 -1
  77. package/src/components/ItemComposition/ItemComposition.tsx +41 -17
  78. package/src/components/List/Item/ListItem.styles.ts +6 -0
  79. package/src/components/List/Item/ListItem.tsx +3 -1
  80. package/src/components/List/Item/Text.tsx +5 -3
  81. package/src/components/Tooltip/ConfirmationTooltip/ConfirmationTooltip.stories.tsx +3 -3
  82. package/src/components/Tooltip/ConfirmationTooltip/ConfirmationTooltip.tsx +1 -1
  83. package/src/components/Tooltip/ConfirmationTooltip/models.ts +1 -1
  84. package/src/index.ts +1 -0
  85. package/src/utils/index.ts +1 -0
  86. package/src/components/Form/AccessRights/AccessRights.resource.ts +0 -45
  87. package/src/components/Form/AccessRights/AccessRightsForm.stories.tsx +0 -59
  88. package/src/components/Form/AccessRights/AccessRightsForm.styles.ts +0 -21
  89. package/src/components/Form/AccessRights/AccessRightsForm.tsx +0 -67
  90. package/src/components/Form/AccessRights/AccessRightsFormActions.tsx +0 -80
  91. package/src/components/Form/AccessRights/Input/AddAction.tsx +0 -31
  92. package/src/components/Form/AccessRights/Input/ContactAccessRightInput.stories.tsx +0 -54
  93. package/src/components/Form/AccessRights/Input/ContactAccessRightInput.tsx +0 -72
  94. package/src/components/Form/AccessRights/Input/ContactAccessRightsInput.styles.ts +0 -22
  95. package/src/components/Form/AccessRights/Input/ContactInputField.tsx +0 -105
  96. package/src/components/Form/AccessRights/Input/RoleInputField.tsx +0 -29
  97. package/src/components/Form/AccessRights/List/ContactAccessRightsList.stories.tsx +0 -97
  98. package/src/components/Form/AccessRights/List/ContactAccessRightsList.styles.ts +0 -71
  99. package/src/components/Form/AccessRights/List/ContactAccessRightsList.tsx +0 -51
  100. package/src/components/Form/AccessRights/List/ContactAccessRightsListItem.stories.tsx +0 -116
  101. package/src/components/Form/AccessRights/List/ContactAccessRightsListItem.tsx +0 -118
  102. package/src/components/Form/AccessRights/List/ContactAccessRightsListItemSkeleton.tsx +0 -26
  103. package/src/components/Form/AccessRights/List/ContactAccessRightsListSkeleton.tsx +0 -28
  104. package/src/components/Form/AccessRights/Stats/AccessRightsStats.styles.ts +0 -18
  105. package/src/components/Form/AccessRights/Stats/AccessRightsStats.tsx +0 -41
  106. package/src/components/Form/AccessRights/__fixtures__/contactAccessRight.mock.ts +0 -54
  107. package/src/components/Form/AccessRights/common/GroupLabel.styles.ts +0 -18
  108. package/src/components/Form/AccessRights/common/GroupLabel.tsx +0 -15
  109. package/src/components/Form/AccessRights/common/Input.styles.ts +0 -48
  110. package/src/components/Form/AccessRights/common/RoleInputSelect.styles.ts +0 -11
  111. package/src/components/Form/AccessRights/common/RoleInputSelect.tsx +0 -57
  112. package/src/components/Form/AccessRights/index.ts +0 -3
  113. package/src/components/Form/AccessRights/useAccessRightsForm.test.tsx +0 -531
  114. package/src/components/Form/AccessRights/useAccessRightsForm.tsx +0 -282
  115. package/src/components/Form/AccessRights/useAccessRightsForm.utils.ts +0 -41
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centreon/ui",
3
- "version": "24.4.1-MON-24417-integrate-newman-collection-api-v2.4",
3
+ "version": "24.4.1-MON-34691-improve-code-coverage.0",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "eslint": "eslint ./src --ext .js,.jsx,.ts,.tsx --max-warnings 0",
@@ -85,6 +85,8 @@
85
85
  "identity-obj-proxy": "^3.0.0",
86
86
  "jest-transform-stub": "^2.0.0",
87
87
  "mochawesome": "^7.1.3",
88
+ "msw": "1.3.2",
89
+ "msw-storybook-addon": "^1.10.0",
88
90
  "puppeteer": "^13.7.0",
89
91
  "react": "^18.2.0",
90
92
  "react-dom": "^18.2.0",
@@ -157,5 +159,8 @@
157
159
  "jest-junit": {
158
160
  "suiteName": "jest tests",
159
161
  "output": "./junit.xml"
162
+ },
163
+ "msw": {
164
+ "workerDirectory": "public"
160
165
  }
161
166
  }
@@ -2,7 +2,7 @@
2
2
  /* tslint:disable */
3
3
 
4
4
  /**
5
- * Mock Service Worker (1.2.1).
5
+ * Mock Service Worker (1.3.2).
6
6
  * @see https://github.com/mswjs/msw
7
7
  * - Please do NOT modify this file.
8
8
  * - Please do NOT serve this file on production.
@@ -300,4 +300,4 @@ function sleep(timeMs) {
300
300
  async function respondWithMock(response) {
301
301
  await sleep(response.delay)
302
302
  return new Response(response.body, response)
303
- }
303
+ }
@@ -4,7 +4,7 @@ import { makeStyles } from 'tss-react/mui';
4
4
  import AccessibilityIcon from '@mui/icons-material/Accessibility';
5
5
  import { Theme } from '@mui/material';
6
6
 
7
- import IconButton from '.';
7
+ import { IconButton } from '.';
8
8
 
9
9
  const useStyles = makeStyles()((theme: Theme) => ({
10
10
  root: {
@@ -38,7 +38,7 @@ type Props = {
38
38
  | 'top-start';
39
39
  } & IconButtonProps;
40
40
 
41
- const IconButton = ({
41
+ export const IconButton = ({
42
42
  title = '',
43
43
  ariaLabel,
44
44
  className,
@@ -1,13 +1,13 @@
1
1
  import { any, isEmpty, isNil, not, or, pipe } from 'ramda';
2
2
  import { makeStyles } from 'tss-react/mui';
3
3
 
4
+ import { LoadingButton, LoadingButtonProps } from '@mui/lab';
4
5
  import { Theme, Tooltip } from '@mui/material';
5
- import { LoadingButton } from '@mui/lab';
6
6
 
7
7
  import { getNormalizedId } from '../../utils';
8
8
 
9
- import StartIcon from './StartIcon';
10
9
  import Content from './Content';
10
+ import StartIcon from './StartIcon';
11
11
 
12
12
  const useStyles = makeStyles()((theme: Theme) => ({
13
13
  loadingButton: {
@@ -15,13 +15,14 @@ const useStyles = makeStyles()((theme: Theme) => ({
15
15
  }
16
16
  }));
17
17
 
18
- interface Props extends Record<string, unknown> {
18
+ interface Props {
19
19
  className?: string;
20
20
  labelLoading?: string;
21
21
  labelSave?: string;
22
22
  labelSucceeded?: string;
23
23
  loading?: boolean;
24
24
  size?: 'small' | 'medium' | 'large';
25
+ startIcon?: boolean;
25
26
  succeeded?: boolean;
26
27
  tooltip?: string;
27
28
  tooltipLabel?: string;
@@ -45,8 +46,9 @@ const SaveButton = ({
45
46
  labelSave = '',
46
47
  size = 'small',
47
48
  className,
49
+ startIcon = true,
48
50
  ...rest
49
- }: Props): JSX.Element => {
51
+ }: Props & LoadingButtonProps): JSX.Element => {
50
52
  const { classes, cx } = useStyles();
51
53
  const hasLabel = hasValue([labelLoading, labelSave, labelSucceeded]);
52
54
 
@@ -73,7 +75,9 @@ const SaveButton = ({
73
75
  loading={loading}
74
76
  loadingPosition={labelLoading ? 'start' : 'center'}
75
77
  size={size}
76
- startIcon={<StartIcon startIconConfig={startIconConfig} />}
78
+ startIcon={
79
+ startIcon && <StartIcon startIconConfig={startIconConfig} />
80
+ }
77
81
  variant="contained"
78
82
  {...rest}
79
83
  >
@@ -2,7 +2,7 @@ import { makeStyles } from 'tss-react/mui';
2
2
  import { T, always, cond, equals } from 'ramda';
3
3
 
4
4
  import { SvgIconComponent } from '@mui/icons-material';
5
- import Typography, { TypographyTypeMap } from '@mui/material/Typography';
5
+ import Typography, { TypographyProps } from '@mui/material/Typography';
6
6
  import { FormControlLabel, Checkbox as MuiCheckbox, Box } from '@mui/material';
7
7
 
8
8
  export type LabelPlacement = 'bottom' | 'top' | 'end' | 'start' | undefined;
@@ -56,7 +56,7 @@ interface Props {
56
56
  disabled?: boolean;
57
57
  label: string;
58
58
  labelPlacement?: LabelPlacement;
59
- labelProps?: TypographyTypeMap['props'];
59
+ labelProps?: TypographyProps;
60
60
  onChange?: (e) => void;
61
61
  }
62
62
 
@@ -2,7 +2,7 @@ import { equals, includes } from 'ramda';
2
2
  import { makeStyles } from 'tss-react/mui';
3
3
 
4
4
  import FormGroup, { FormGroupProps } from '@mui/material/FormGroup';
5
- import { TypographyTypeMap } from '@mui/material/Typography';
5
+ import { TypographyProps } from '@mui/material/Typography';
6
6
 
7
7
  import Checkbox, { LabelPlacement } from '../Checkbox';
8
8
 
@@ -13,7 +13,7 @@ interface Props {
13
13
  disabled?: boolean;
14
14
  formGroupProps?: FormGroupProps;
15
15
  labelPlacement?: LabelPlacement;
16
- labelProps?: TypographyTypeMap['props'];
16
+ labelProps?: TypographyProps;
17
17
  onChange?: (e) => void;
18
18
  options: Array<string>;
19
19
  values: Array<string>;
@@ -43,7 +43,7 @@ export type Props = {
43
43
  dialogTitleClassName?: string;
44
44
  labelCancel?: string | null;
45
45
  labelConfirm?: string | null;
46
- labelTitle?: string | null;
46
+ labelTitle?: ReactNode;
47
47
  onCancel?: () => void;
48
48
  onClose?: () => void;
49
49
  onConfirm: (event, value?) => void;
@@ -17,7 +17,7 @@ const useStyles = makeStyles()((theme) => ({
17
17
  logo: {
18
18
  alignSelf: 'flex-end',
19
19
  height: theme.spacing(11),
20
- width: '22rem'
20
+ width: '239px'
21
21
  },
22
22
  message: {
23
23
  color: theme.palette.text.primary
@@ -66,9 +66,9 @@ export const FallbackPage: FC<FallbackPageProps> = typedMemo(
66
66
 
67
67
  return (
68
68
  <div className={classes.notAuthorizedContainer}>
69
- <section className={classes.logo}>
69
+ <div className={classes.logo}>
70
70
  <CentreonLogo />
71
- </section>
71
+ </div>
72
72
  <section className={classes.messageBlock}>
73
73
  <header>
74
74
  <Typography color="primary" fontWeight="bold" variant="h3">
@@ -8,7 +8,7 @@ interface MakeStylesProps {
8
8
 
9
9
  export const legendWidth = 21;
10
10
  const legendItemHeight = 5.25;
11
- const legendItemHeightCompact = 1.75;
11
+ const legendItemHeightCompact = 2;
12
12
 
13
13
  export const useStyles = makeStyles<MakeStylesProps>()(
14
14
  (theme, { limitLegendRows }) => ({
@@ -38,7 +38,7 @@ const LegendHeader = ({
38
38
 
39
39
  const getEndText = (): string => {
40
40
  if (value) {
41
- return `${value}${hasUnit ? ` ${unit}` : ''}`;
41
+ return value;
42
42
  }
43
43
 
44
44
  return hasUnit ? ` ${unitName}` : '';
@@ -7,7 +7,6 @@ import { Box, alpha, useTheme } from '@mui/material';
7
7
 
8
8
  import { useMemoComponent } from '@centreon/ui';
9
9
 
10
- import { maxLinesDisplayedLegend } from '../common';
11
10
  import { formatMetricValue } from '../../common/timeSeries';
12
11
  import { Line, TimeValue } from '../../common/timeSeries/models';
13
12
  import { labelAvg, labelMax, labelMin } from '../translatedLabels';
@@ -24,7 +23,7 @@ import LegendContent from './LegendContent';
24
23
  interface Props {
25
24
  base: number;
26
25
  displayAnchor?: boolean;
27
- limitLegendRows?: boolean;
26
+ limitLegend?: false | number;
28
27
  lines: Array<Line>;
29
28
  renderExtraComponent?: ReactNode;
30
29
  setLinesGraph: Dispatch<SetStateAction<Array<Line> | null>>;
@@ -39,14 +38,14 @@ const MainLegend = ({
39
38
  timeSeries,
40
39
  base,
41
40
  toggable = true,
42
- limitLegendRows = true,
41
+ limitLegend = false,
43
42
  renderExtraComponent,
44
43
  displayAnchor = true,
45
44
  setLinesGraph,
46
45
  xScale,
47
46
  shouldDisplayLegendInCompactMode
48
47
  }: Props): JSX.Element => {
49
- const { classes, cx } = useStyles({ limitLegendRows });
48
+ const { classes, cx } = useStyles({ limitLegendRows: Boolean(limitLegend) });
50
49
  const theme = useTheme();
51
50
 
52
51
  const { selectMetricLine, clearHighlight, highlightLine, toggleMetricLine } =
@@ -61,8 +60,8 @@ const MainLegend = ({
61
60
 
62
61
  const sortedData = sortBy(prop('metric_id'), lines);
63
62
 
64
- const displayedLines = limitLegendRows
65
- ? slice(0, maxLinesDisplayedLegend, sortedData)
63
+ const displayedLines = limitLegend
64
+ ? slice(0, limitLegend, sortedData)
66
65
  : sortedData;
67
66
 
68
67
  const getMetricValue = ({ value, unit }: GetMetricValueProps): string =>
@@ -174,7 +173,7 @@ const MainLegend = ({
174
173
  const Legend = (props: Props): JSX.Element => {
175
174
  const {
176
175
  toggable,
177
- limitLegendRows,
176
+ limitLegend,
178
177
  timeSeries,
179
178
  lines,
180
179
  base,
@@ -191,7 +190,7 @@ const Legend = (props: Props): JSX.Element => {
191
190
  lines,
192
191
  base,
193
192
  toggable,
194
- limitLegendRows,
193
+ limitLegend,
195
194
  displayAnchor,
196
195
  shouldDisplayLegendInCompactMode
197
196
  ]
@@ -5,7 +5,7 @@ import { equals, find, isNil } from 'ramda';
5
5
 
6
6
  import { mousePositionAtom } from '../InteractiveComponents/interactionWithGraphAtoms';
7
7
  import {
8
- formatMetricValue,
8
+ formatMetricValueWithUnit,
9
9
  getLineForMetric,
10
10
  getMetrics,
11
11
  getTimeValue
@@ -73,7 +73,7 @@ const useInteractiveValues = ({
73
73
  metric_id
74
74
  }) as Line;
75
75
 
76
- const formattedValue = formatMetricValue({
76
+ const formattedValue = formatMetricValueWithUnit({
77
77
  base,
78
78
  unit,
79
79
  value
@@ -43,6 +43,7 @@ interface Props extends LineChartProps {
43
43
  graphInterval: GraphInterval;
44
44
  graphRef: MutableRefObject<HTMLDivElement | null>;
45
45
  legend?: LegendModel;
46
+ limitLegend?: false | number;
46
47
  marginBottom: number;
47
48
  shapeLines?: GlobalAreaLines;
48
49
  thresholdUnit?: string;
@@ -73,7 +74,8 @@ const LineChart = ({
73
74
  curve,
74
75
  marginBottom,
75
76
  thresholds,
76
- thresholdUnit
77
+ thresholdUnit,
78
+ limitLegend
77
79
  }: Props): JSX.Element => {
78
80
  const { classes } = useStyles();
79
81
 
@@ -301,6 +303,7 @@ const LineChart = ({
301
303
  <Legend
302
304
  base={baseAxis}
303
305
  displayAnchor={displayAnchor?.displayGuidingLines ?? true}
306
+ limitLegend={limitLegend}
304
307
  lines={newLines}
305
308
  renderExtraComponent={legend?.renderExtraComponent}
306
309
  setLinesGraph={setLinesGraph}
@@ -28,6 +28,7 @@ interface Props extends Partial<LineChartProps> {
28
28
  data?: LineChartData;
29
29
  end: string;
30
30
  legend: LegendModel;
31
+ limitLegend?: false | number;
31
32
  loading: boolean;
32
33
  marginBottom?: number;
33
34
  shapeLines?: GlobalAreaLines;
@@ -55,7 +56,8 @@ const WrapperLineChart = ({
55
56
  curve = Curve.curveLinear,
56
57
  marginBottom = 0,
57
58
  thresholds,
58
- thresholdUnit
59
+ thresholdUnit,
60
+ limitLegend
59
61
  }: Props): JSX.Element | null => {
60
62
  const { adjustedData } = useLineChartData({ data, end, start });
61
63
  const lineChartRef = useRef<HTMLDivElement | null>(null);
@@ -76,7 +78,7 @@ const WrapperLineChart = ({
76
78
  return (
77
79
  <div
78
80
  ref={lineChartRef as MutableRefObject<HTMLDivElement>}
79
- style={{ height: '100%', width: '100%' }}
81
+ style={{ height: '100%', overflowY: 'hidden', width: '100%' }}
80
82
  >
81
83
  <ParentSize>
82
84
  {({
@@ -95,6 +97,7 @@ const WrapperLineChart = ({
95
97
  header={header}
96
98
  height={height || responsiveHeight}
97
99
  legend={legend}
100
+ limitLegend={limitLegend}
98
101
  loading={loading}
99
102
  marginBottom={marginBottom}
100
103
  shapeLines={shapeLines}
@@ -2,4 +2,5 @@ export { default as LineChart } from './LineChart';
2
2
  export { Gauge } from './Gauge';
3
3
  export { SingleBar } from './SingleBar';
4
4
  export { Text as GraphText } from './Text';
5
+
5
6
  export { HeatMap } from './HeatMap';
@@ -0,0 +1,85 @@
1
+ import NumberField, { NumberProps } from './Number';
2
+
3
+ const initialize = (props: NumberProps): void => {
4
+ cy.mount({
5
+ Component: <NumberField {...props} />
6
+ });
7
+ };
8
+
9
+ describe('Number field', () => {
10
+ it('displays the placeholder when the field has no default or fallback values', () => {
11
+ initialize({ dataTestId: 'test', onChange: cy.stub() });
12
+
13
+ cy.get('input').should('have.value', '');
14
+ cy.get('input').should('have.attr', 'placeholder', '0');
15
+
16
+ cy.makeSnapshot();
17
+ });
18
+
19
+ it('displays the fallback value as placeholder when the field as no default value', () => {
20
+ initialize({ dataTestId: 'test', fallbackValue: 25, onChange: cy.stub() });
21
+
22
+ cy.get('input').should('have.value', '');
23
+ cy.get('input').should('have.attr', 'placeholder', '25');
24
+
25
+ cy.makeSnapshot();
26
+ });
27
+
28
+ it('displays the default value as placeholder when the field as default value', () => {
29
+ initialize({ dataTestId: 'test', defaultValue: 25, onChange: cy.stub() });
30
+
31
+ cy.get('input').should('have.value', '25');
32
+
33
+ cy.makeSnapshot();
34
+ });
35
+
36
+ it('displays the fallback value when the field is cleared out', () => {
37
+ initialize({
38
+ dataTestId: 'test',
39
+ defaultValue: 25,
40
+ fallbackValue: 10,
41
+ onChange: cy.stub()
42
+ });
43
+
44
+ cy.get('input').should('have.value', '25');
45
+ cy.get('input').clear();
46
+ cy.get('input').should('have.value', '');
47
+ cy.get('input').should('have.attr', 'placeholder', '10');
48
+
49
+ cy.makeSnapshot();
50
+ });
51
+
52
+ it('displays the field using auto size', () => {
53
+ initialize({
54
+ autoSize: true,
55
+ dataTestId: 'test',
56
+ defaultValue: 25,
57
+ onChange: cy.stub()
58
+ });
59
+
60
+ cy.get('input').should('have.value', '25');
61
+
62
+ cy.get('input').type('0');
63
+
64
+ cy.makeSnapshot();
65
+ });
66
+
67
+ it('sets the value to the minimum value configured when a value less than the minimum value is typed in the field', () => {
68
+ initialize({
69
+ dataTestId: 'test',
70
+ defaultValue: 25,
71
+ inputProps: {
72
+ min: 2
73
+ },
74
+ onChange: cy.stub()
75
+ });
76
+
77
+ cy.get('input').should('have.value', '25');
78
+
79
+ cy.get('input').clear().type('-1');
80
+
81
+ cy.get('input').should('have.value', '2');
82
+
83
+ cy.makeSnapshot();
84
+ });
85
+ });
@@ -0,0 +1,66 @@
1
+ /* eslint-disable no-console */
2
+ import { Meta, StoryObj } from '@storybook/react';
3
+
4
+ import NumberField from './Number';
5
+
6
+ const meta: Meta<typeof NumberField> = {
7
+ argTypes: {
8
+ defaultValue: {
9
+ defaultValue: 0,
10
+ description:
11
+ 'The initial value which will be used by the input for the first render',
12
+ type: 'number'
13
+ },
14
+ fallbackValue: {
15
+ defaultValue: 0,
16
+ description: 'This value will be used when the input is cleared',
17
+ type: 'number'
18
+ },
19
+ onChange: {
20
+ description:
21
+ 'The change function with the actual value as parameter. This parameter will be the value when the input is filled but it will be the fallbackValue when the input is cleared out',
22
+ type: 'function'
23
+ }
24
+ },
25
+ component: NumberField
26
+ };
27
+
28
+ export default meta;
29
+ type Story = StoryObj<typeof NumberField>;
30
+
31
+ export const Default: Story = {
32
+ args: {
33
+ onChange: console.log
34
+ }
35
+ };
36
+
37
+ export const WithDefaultValue: Story = {
38
+ args: {
39
+ defaultValue: 25,
40
+ onChange: console.log
41
+ }
42
+ };
43
+
44
+ export const WithFallbackValue: Story = {
45
+ args: {
46
+ fallbackValue: 25,
47
+ onChange: console.log
48
+ }
49
+ };
50
+
51
+ export const WithFallbackValueAndDefaultValue: Story = {
52
+ args: {
53
+ defaultValue: 10,
54
+ fallbackValue: 25,
55
+ onChange: console.log
56
+ }
57
+ };
58
+
59
+ export const WithFallbackValueAndDefaultValueAutoSize: Story = {
60
+ args: {
61
+ autoSize: true,
62
+ defaultValue: 10,
63
+ fallbackValue: 25,
64
+ onChange: console.log
65
+ }
66
+ };
@@ -0,0 +1,74 @@
1
+ import { ChangeEvent, useState } from 'react';
2
+
3
+ import { T, always, cond, isEmpty, isNil } from 'ramda';
4
+
5
+ import TextField, { TextProps } from '../Text';
6
+
7
+ export interface NumberProps
8
+ extends Omit<TextProps, 'defaultValue' | 'onChange'> {
9
+ /**
10
+ * The initial value which will be used by the input for the first render
11
+ */
12
+ defaultValue?: number;
13
+ /**
14
+ * This value will be used when the input is cleared
15
+ */
16
+ fallbackValue?: number;
17
+ /**
18
+ * The change function with the actual value as parameter. This parameter will be the value when the input is filled but it will be the fallbackValue when the input is cleared out
19
+ */
20
+ onChange: (actualValue: number) => void;
21
+ }
22
+
23
+ const NumberField = ({
24
+ fallbackValue = 0,
25
+ defaultValue,
26
+ onChange,
27
+ ...props
28
+ }: NumberProps): JSX.Element => {
29
+ const [placeholder, setPlaceholder] = useState<string | undefined>();
30
+ const [actualValue, setActualValue] = useState(
31
+ defaultValue ? `${defaultValue}` : ''
32
+ );
33
+
34
+ const { inputProps } = props;
35
+
36
+ const changeValue = (event: ChangeEvent<HTMLInputElement>): void => {
37
+ const inputValue = event.target.value;
38
+
39
+ const number = Number(inputValue);
40
+ const campledNumber = cond([
41
+ [() => isEmpty(inputValue), always(fallbackValue)],
42
+ [() => Number.isNaN(number), always(number)],
43
+ [
44
+ T,
45
+ always(
46
+ Math.max(
47
+ !isNil(inputProps?.min) ? inputProps?.min : -Infinity,
48
+ number
49
+ )
50
+ )
51
+ ]
52
+ ])();
53
+
54
+ onChange(campledNumber);
55
+ setPlaceholder(isEmpty(inputValue) ? `${fallbackValue}` : undefined);
56
+ setActualValue(isEmpty(inputValue) ? inputValue : `${campledNumber}`);
57
+ };
58
+
59
+ return (
60
+ <TextField
61
+ defaultValue={defaultValue}
62
+ type="number"
63
+ value={actualValue}
64
+ onChange={changeValue}
65
+ {...props}
66
+ inputProps={inputProps}
67
+ placeholder={
68
+ placeholder || (!defaultValue ? `${fallbackValue}` : undefined)
69
+ }
70
+ />
71
+ );
72
+ };
73
+
74
+ export default NumberField;
@@ -1,8 +1,8 @@
1
1
  import IconSearch from '@mui/icons-material/Search';
2
2
 
3
- import TextField, { Props as TextFieldProps } from '../Text';
3
+ import TextField, { TextProps } from '../Text';
4
4
 
5
- type Props = Omit<TextFieldProps, 'StartAdornment'>;
5
+ type Props = Omit<TextProps, 'StartAdornment'>;
6
6
 
7
7
  const SearchAdornment = (): JSX.Element => <IconSearch />;
8
8
 
@@ -33,6 +33,7 @@ import useFetchQuery from '../../../../api/useFetchQuery';
33
33
  export interface ConnectedAutoCompleteFieldProps<TData> {
34
34
  allowUniqOption?: boolean;
35
35
  baseEndpoint?: string;
36
+ changeIdValue: (item: TData) => number | string;
36
37
  conditionField?: keyof SelectEntry;
37
38
  field: string;
38
39
  getEndpoint: ({ search, page }) => string;
@@ -62,6 +63,7 @@ const ConnectedAutocompleteField = (
62
63
  queryKey,
63
64
  allowUniqOption,
64
65
  baseEndpoint,
66
+ changeIdValue,
65
67
  ...props
66
68
  }: ConnectedAutoCompleteFieldProps<TData> &
67
69
  Omit<AutocompleteFieldProps, 'options'>): JSX.Element => {
@@ -238,17 +240,24 @@ const ConnectedAutocompleteField = (
238
240
 
239
241
  const moreOptions = page > 1 ? options : [];
240
242
 
243
+ const formattedList = changeIdValue
244
+ ? newOptions.result.map((item) => ({
245
+ ...item,
246
+ id: changeIdValue(item)
247
+ }))
248
+ : newOptions.result;
249
+
241
250
  if (!isEmpty(labelKey) && !isNil(labelKey)) {
242
- const list = newOptions.result.map((item) =>
251
+ const list = formattedList.map((item) =>
243
252
  renameKey({ key: labelKey, newKey: 'name', object: item })
244
253
  );
245
254
  setOptions(moreOptions.concat(list as Array<TData>));
246
255
 
247
256
  return;
248
257
  }
249
- setOptions(moreOptions.concat(newOptions.result));
258
+ setOptions(moreOptions.concat(formattedList));
250
259
 
251
- setOptions(moreOptions.concat(newOptions.result as Array<TData>));
260
+ setOptions(moreOptions.concat(formattedList as Array<TData>));
252
261
 
253
262
  const total = prop('total', newOptions.meta) || 1;
254
263
  const limit = prop('limit', newOptions.meta) || 1;