@centreon/ui 25.3.1 → 25.3.3
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 +49 -46
- package/public/mockServiceWorker.js +1 -1
- package/src/Button/Save/index.tsx +17 -35
- package/src/Button/Save/useSave.tsx +89 -0
- package/src/Form/Inputs/LoadingSkeleton.tsx +1 -1
- package/src/Form/Inputs/Radio.tsx +7 -5
- package/src/Form/Inputs/Switch.tsx +4 -2
- package/src/Graph/BarChart/BarChart.cypress.spec.tsx +2 -2
- package/src/Graph/BarChart/BarChart.stories.tsx +39 -0
- package/src/Graph/BarChart/BarStack.tsx +8 -2
- package/src/Graph/BarChart/ResponsiveBarChart.tsx +10 -8
- package/src/Graph/Chart/BasicComponents/Lines/StackedLines/index.tsx +41 -24
- package/src/Graph/Chart/BasicComponents/Lines/index.tsx +22 -37
- package/src/Graph/Chart/Chart.cypress.spec.tsx +104 -31
- package/src/Graph/Chart/Chart.stories.tsx +24 -2
- package/src/Graph/Chart/Chart.tsx +23 -18
- package/src/Graph/Chart/index.tsx +2 -0
- package/src/Graph/Chart/models.ts +4 -3
- package/src/Graph/SingleBar/ThresholdLine.tsx +2 -2
- package/src/Graph/Tree/Tree.stories.tsx +4 -1
- package/src/Graph/common/Axes/index.tsx +1 -1
- package/src/Graph/common/BaseChart/AdditionalLine.tsx +37 -0
- package/src/Graph/common/BaseChart/BaseChart.tsx +5 -1
- package/src/Graph/common/BaseChart/Header/index.tsx +5 -7
- package/src/Graph/common/BaseChart/Header/useHeaderStyles.ts +5 -1
- package/src/Graph/common/BaseChart/useComputeBaseChartDimensions.ts +9 -2
- package/src/Graph/common/Thresholds/ThresholdLine.tsx +2 -2
- package/src/Graph/common/models.ts +7 -0
- package/src/Graph/common/timeSeries/index.ts +1 -1
- package/src/Graph/common/utils.ts +22 -1
- package/src/Graph/mockedData/lastDayWithNullValues.json +6 -40
- package/src/Graph/mockedData/pingService.json +3 -3
- package/src/InputField/Select/index.tsx +11 -9
- package/src/Listing/Listing.cypress.spec.tsx +9 -11
- package/src/RichTextEditor/RichTextEditor.tsx +1 -1
- package/src/api/useMutationQuery/useMutationQuery.cypress.spec.tsx +0 -18
- package/src/components/Button/Button.tsx +19 -15
- package/src/components/CollapsibleItem/CollapsibleItem.cypress.spec.tsx +8 -8
- package/src/components/CopyCommand/CopyCommand.cypress.spec.tsx +11 -10
- package/src/Button/Save/Content.tsx +0 -34
- package/src/Button/Save/StartIcon.tsx +0 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@centreon/ui",
|
|
3
|
-
"version": "25.3.
|
|
3
|
+
"version": "25.3.3",
|
|
4
4
|
"description": "Centreon UI Components",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"update:deps": "pnpx npm-check-updates -i --format group",
|
|
@@ -16,7 +16,10 @@
|
|
|
16
16
|
"cypress:run:updateSnapshots": "cypress run --component --browser=chrome --env updateSnapshots=true",
|
|
17
17
|
"cypress:run:coverage": "cypress run --component --browser=chrome --env codeCoverageTasksRegistered=true",
|
|
18
18
|
"cypress:run": "cypress run --component --browser=chrome",
|
|
19
|
-
"
|
|
19
|
+
"cypress:install": "cypress install",
|
|
20
|
+
"cypress:cli": "./cypress/scripts/cypress-cli.sh",
|
|
21
|
+
"tokens:transform": "TS_NODE_PROJECT=tsconfig.node.json ts-node style-dictionary.transform.ts",
|
|
22
|
+
"install:arm:binaries": "pnpm i -D @swc/core-linux-arm64-gnu@1.6.6 @rspack/binding-linux-arm64-gnu@1.1.6 -w && pnpm remove @swc/core-linux-arm64-gnu @rspack/binding-linux-arm64-gnu"
|
|
20
23
|
},
|
|
21
24
|
"type": "module",
|
|
22
25
|
"sideEffects": false,
|
|
@@ -50,71 +53,71 @@
|
|
|
50
53
|
"test/*"
|
|
51
54
|
],
|
|
52
55
|
"devDependencies": {
|
|
53
|
-
"@cypress/react": "^
|
|
54
|
-
"@cypress/webpack-dev-server": "^
|
|
55
|
-
"@faker-js/faker": "^9.
|
|
56
|
+
"@cypress/react": "^9.0.0",
|
|
57
|
+
"@cypress/webpack-dev-server": "^4.0.1",
|
|
58
|
+
"@faker-js/faker": "^9.5.1",
|
|
56
59
|
"@mdx-js/react": "^3.1.0",
|
|
57
60
|
"@simonsmith/cypress-image-snapshot": "^9.1.0",
|
|
58
|
-
"@storybook/addon-a11y": "^8.
|
|
59
|
-
"@storybook/addon-docs": "^8.
|
|
60
|
-
"@storybook/addon-essentials": "^8.
|
|
61
|
-
"@storybook/addon-interactions": "^8.
|
|
62
|
-
"@storybook/addon-themes": "^8.
|
|
63
|
-
"@storybook/blocks": "^8.
|
|
64
|
-
"@storybook/manager-api": "^8.
|
|
61
|
+
"@storybook/addon-a11y": "^8.6.3",
|
|
62
|
+
"@storybook/addon-docs": "^8.6.3",
|
|
63
|
+
"@storybook/addon-essentials": "^8.6.3",
|
|
64
|
+
"@storybook/addon-interactions": "^8.6.3",
|
|
65
|
+
"@storybook/addon-themes": "^8.6.3",
|
|
66
|
+
"@storybook/blocks": "^8.6.3",
|
|
67
|
+
"@storybook/manager-api": "^8.6.3",
|
|
65
68
|
"@storybook/mdx2-csf": "^1.1.0",
|
|
66
|
-
"@storybook/preview-api": "^8.
|
|
67
|
-
"@storybook/react": "^8.
|
|
68
|
-
"@storybook/react-vite": "^8.
|
|
69
|
-
"@storybook/test": "^8.
|
|
70
|
-
"@storybook/test-runner": "^0.
|
|
71
|
-
"@storybook/theming": "^8.
|
|
72
|
-
"@testing-library/cypress": "^10.0.
|
|
69
|
+
"@storybook/preview-api": "^8.6.3",
|
|
70
|
+
"@storybook/react": "^8.6.3",
|
|
71
|
+
"@storybook/react-vite": "^8.6.3",
|
|
72
|
+
"@storybook/test": "^8.6.3",
|
|
73
|
+
"@storybook/test-runner": "^0.22.0",
|
|
74
|
+
"@storybook/theming": "^8.6.3",
|
|
75
|
+
"@testing-library/cypress": "^10.0.3",
|
|
73
76
|
"@testing-library/jest-dom": "^6.6.3",
|
|
74
|
-
"@testing-library/react": "^16.
|
|
77
|
+
"@testing-library/react": "^16.2.0",
|
|
75
78
|
"@testing-library/react-hooks": "^8.0.1",
|
|
76
79
|
"@types/jest": "^29.5.14",
|
|
77
80
|
"@types/mocha": "^10.0.10",
|
|
78
81
|
"@types/ramda": "^0.30.2",
|
|
79
|
-
"@types/react": "^
|
|
82
|
+
"@types/react": "^19.0.10",
|
|
80
83
|
"@types/testing-library__jest-dom": "^6.0.0",
|
|
81
84
|
"@vitejs/plugin-react": "^4.3.4",
|
|
82
|
-
"@vitejs/plugin-react-swc": "^3.
|
|
83
|
-
"chai": "^5.
|
|
84
|
-
"cypress": "^
|
|
85
|
+
"@vitejs/plugin-react-swc": "^3.8.0",
|
|
86
|
+
"chai": "^5.2.0",
|
|
87
|
+
"cypress": "^14.1.0",
|
|
85
88
|
"identity-obj-proxy": "^3.0.0",
|
|
86
89
|
"jest-transform-stub": "^2.0.0",
|
|
87
90
|
"mochawesome": "^7.1.3",
|
|
88
|
-
"msw": "2.
|
|
91
|
+
"msw": "2.7.3",
|
|
89
92
|
"msw-storybook-addon": "^2.0.4",
|
|
90
|
-
"react": "^
|
|
91
|
-
"react-dom": "^
|
|
93
|
+
"react": "^19.0.0",
|
|
94
|
+
"react-dom": "^19.0.0",
|
|
92
95
|
"react-test-renderer": "^19.0.0",
|
|
93
|
-
"remark-gfm": "^4.0.
|
|
96
|
+
"remark-gfm": "^4.0.1",
|
|
94
97
|
"speed-measure-vite-plugin": "^1.1.0",
|
|
95
|
-
"storybook": "^8.
|
|
98
|
+
"storybook": "^8.6.3",
|
|
96
99
|
"storybook-addon-mock": "^5.0.0",
|
|
97
100
|
"storybook-dark-mode": "^4.0.2",
|
|
98
|
-
"style-dictionary": "^4.3.
|
|
101
|
+
"style-dictionary": "^4.3.3",
|
|
99
102
|
"ts-node": "^10.9.2",
|
|
100
103
|
"use-resize-observer": "^9.1.0",
|
|
101
|
-
"vite": "^6.0
|
|
102
|
-
"vite-plugin-istanbul": "^
|
|
104
|
+
"vite": "^6.2.0",
|
|
105
|
+
"vite-plugin-istanbul": "^7.0.0",
|
|
103
106
|
"vite-plugin-svgr": "^4.3.0",
|
|
104
107
|
"vite-plugin-turbosnap": "^1.0.3"
|
|
105
108
|
},
|
|
106
109
|
"peerDependencies": {
|
|
107
|
-
"@centreon/ui-context": "
|
|
110
|
+
"@centreon/ui-context": "link:../ui-context"
|
|
108
111
|
},
|
|
109
112
|
"dependencies": {
|
|
110
|
-
"@lexical/html": "^0.
|
|
111
|
-
"@lexical/link": "^0.
|
|
112
|
-
"@lexical/list": "^0.
|
|
113
|
-
"@lexical/react": "^0.
|
|
114
|
-
"@lexical/rich-text": "^0.
|
|
115
|
-
"@lexical/selection": "^0.
|
|
116
|
-
"@lexical/utils": "^0.
|
|
117
|
-
"@mui/material": "^6.
|
|
113
|
+
"@lexical/html": "^0.27.0",
|
|
114
|
+
"@lexical/link": "^0.27.0",
|
|
115
|
+
"@lexical/list": "^0.27.0",
|
|
116
|
+
"@lexical/react": "^0.27.0",
|
|
117
|
+
"@lexical/rich-text": "^0.27.0",
|
|
118
|
+
"@lexical/selection": "^0.27.0",
|
|
119
|
+
"@lexical/utils": "^0.27.0",
|
|
120
|
+
"@mui/material": "^6.4.6",
|
|
118
121
|
"@react-spring/web": "^9.7.5",
|
|
119
122
|
"@visx/clip-path": "^3.12.0",
|
|
120
123
|
"@visx/curve": "^3.12.0",
|
|
@@ -133,18 +136,18 @@
|
|
|
133
136
|
"anylogger": "^1.0.11",
|
|
134
137
|
"d3-array": "3.2.4",
|
|
135
138
|
"dayjs": "^1.11.13",
|
|
136
|
-
"highlight.js": "^11.
|
|
137
|
-
"html-react-parser": "^5.2.
|
|
139
|
+
"highlight.js": "^11.11.1",
|
|
140
|
+
"html-react-parser": "^5.2.2",
|
|
138
141
|
"humanize-duration": "^3.32.1",
|
|
139
|
-
"lexical": "^0.
|
|
140
|
-
"notistack": "^3.0.
|
|
142
|
+
"lexical": "^0.27.0",
|
|
143
|
+
"notistack": "^3.0.2",
|
|
141
144
|
"numeral": "^2.0.6",
|
|
142
145
|
"ramda": "0.30.1",
|
|
143
146
|
"react-grid-layout": "^1.5.0",
|
|
144
147
|
"react-resizable": "^3.0.5",
|
|
145
148
|
"react-router": "7",
|
|
146
149
|
"react-transition-group": "^4.4.5",
|
|
147
|
-
"sanitize-html": "^2.
|
|
150
|
+
"sanitize-html": "^2.14.0",
|
|
148
151
|
"ulog": "^2.0.0-beta.19"
|
|
149
152
|
},
|
|
150
153
|
"jest-junit": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - Please do NOT serve this file on production.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
const PACKAGE_VERSION = '2.
|
|
11
|
+
const PACKAGE_VERSION = '2.7.3'
|
|
12
12
|
const INTEGRITY_CHECKSUM = '00729d72e3b82faf54ca8b9621dbb96f'
|
|
13
13
|
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
|
|
14
14
|
const activeClientIds = new Set()
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import { any, isEmpty, isNil, not, or, pipe } from 'ramda';
|
|
2
1
|
import { makeStyles } from 'tss-react/mui';
|
|
3
2
|
|
|
4
|
-
import { LoadingButton, LoadingButtonProps } from '@mui/lab';
|
|
5
3
|
import { Theme, Tooltip } from '@mui/material';
|
|
6
4
|
|
|
7
5
|
import { getNormalizedId } from '../../utils';
|
|
8
6
|
|
|
9
|
-
import
|
|
10
|
-
import
|
|
7
|
+
import { Button, ButtonProps } from '../../components';
|
|
8
|
+
import { useSave } from './useSave';
|
|
11
9
|
|
|
12
10
|
const useStyles = makeStyles()((theme: Theme) => ({
|
|
13
11
|
loadingButton: {
|
|
@@ -15,7 +13,7 @@ const useStyles = makeStyles()((theme: Theme) => ({
|
|
|
15
13
|
}
|
|
16
14
|
}));
|
|
17
15
|
|
|
18
|
-
interface Props {
|
|
16
|
+
export interface Props {
|
|
19
17
|
className?: string;
|
|
20
18
|
labelLoading?: string;
|
|
21
19
|
labelSave?: string;
|
|
@@ -28,15 +26,6 @@ interface Props {
|
|
|
28
26
|
tooltipLabel?: string;
|
|
29
27
|
}
|
|
30
28
|
|
|
31
|
-
interface StartIconConfigProps {
|
|
32
|
-
hasLabel: boolean;
|
|
33
|
-
loading: boolean;
|
|
34
|
-
succeeded: boolean;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const isNilOrEmpty = (value): boolean => or(isNil(value), isEmpty(value));
|
|
38
|
-
const hasValue = any(pipe(isNilOrEmpty, not));
|
|
39
|
-
|
|
40
29
|
const SaveButton = ({
|
|
41
30
|
succeeded = false,
|
|
42
31
|
loading = false,
|
|
@@ -48,20 +37,22 @@ const SaveButton = ({
|
|
|
48
37
|
className,
|
|
49
38
|
startIcon = true,
|
|
50
39
|
...rest
|
|
51
|
-
}: Props &
|
|
40
|
+
}: Props & Omit<ButtonProps, 'children'>): JSX.Element => {
|
|
52
41
|
const { classes, cx } = useStyles();
|
|
53
|
-
const hasLabel = hasValue([labelLoading, labelSave, labelSucceeded]);
|
|
54
42
|
|
|
55
|
-
const
|
|
56
|
-
|
|
43
|
+
const { content, startIconToDisplay, hasLabel } = useSave({
|
|
44
|
+
labelLoading,
|
|
45
|
+
labelSave,
|
|
46
|
+
labelSucceeded,
|
|
57
47
|
loading,
|
|
58
|
-
succeeded
|
|
59
|
-
|
|
48
|
+
succeeded,
|
|
49
|
+
startIcon
|
|
50
|
+
});
|
|
60
51
|
|
|
61
52
|
return (
|
|
62
53
|
<Tooltip placement="bottom" title={tooltipLabel}>
|
|
63
54
|
<div>
|
|
64
|
-
<
|
|
55
|
+
<Button
|
|
65
56
|
aria-label="save button"
|
|
66
57
|
className={cx(
|
|
67
58
|
{
|
|
@@ -69,26 +60,17 @@ const SaveButton = ({
|
|
|
69
60
|
},
|
|
70
61
|
className
|
|
71
62
|
)}
|
|
72
|
-
color="primary"
|
|
73
63
|
data-testid={labelSave}
|
|
74
64
|
id={getNormalizedId(labelSave)}
|
|
75
65
|
loading={loading}
|
|
76
|
-
loadingPosition={labelLoading ? 'start' :
|
|
66
|
+
loadingPosition={labelLoading ? 'start' : undefined}
|
|
77
67
|
size={size}
|
|
78
|
-
startIcon={
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
variant="contained"
|
|
68
|
+
startIcon={startIconToDisplay}
|
|
69
|
+
variant="primary"
|
|
82
70
|
{...rest}
|
|
83
71
|
>
|
|
84
|
-
{
|
|
85
|
-
|
|
86
|
-
labelSave,
|
|
87
|
-
labelSucceeded,
|
|
88
|
-
loading,
|
|
89
|
-
succeeded
|
|
90
|
-
})}
|
|
91
|
-
</LoadingButton>
|
|
72
|
+
{content}
|
|
73
|
+
</Button>
|
|
92
74
|
</div>
|
|
93
75
|
</Tooltip>
|
|
94
76
|
);
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import CheckIcon from '@mui/icons-material/Check';
|
|
2
|
+
import SaveIcon from '@mui/icons-material/Save';
|
|
3
|
+
import {
|
|
4
|
+
T,
|
|
5
|
+
always,
|
|
6
|
+
any,
|
|
7
|
+
cond,
|
|
8
|
+
isEmpty,
|
|
9
|
+
isNil,
|
|
10
|
+
not,
|
|
11
|
+
or,
|
|
12
|
+
pipe,
|
|
13
|
+
propEq
|
|
14
|
+
} from 'ramda';
|
|
15
|
+
import { useMemo } from 'react';
|
|
16
|
+
import { useTranslation } from 'react-i18next';
|
|
17
|
+
import { Props } from '.';
|
|
18
|
+
|
|
19
|
+
interface StartIconConfigProps {
|
|
20
|
+
hasLabel: boolean;
|
|
21
|
+
loading: boolean;
|
|
22
|
+
succeeded: boolean;
|
|
23
|
+
enabled: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const isNilOrEmpty = (value): boolean => or(isNil(value), isEmpty(value));
|
|
27
|
+
const hasValue = any(pipe(isNilOrEmpty, not));
|
|
28
|
+
|
|
29
|
+
interface UseSaveState {
|
|
30
|
+
content: string | JSX.Element;
|
|
31
|
+
startIconToDisplay: null | JSX.Element;
|
|
32
|
+
hasLabel: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const useSave = ({
|
|
36
|
+
labelLoading,
|
|
37
|
+
labelSave,
|
|
38
|
+
labelSucceeded,
|
|
39
|
+
loading,
|
|
40
|
+
succeeded,
|
|
41
|
+
startIcon
|
|
42
|
+
}: Pick<
|
|
43
|
+
Props,
|
|
44
|
+
| 'startIcon'
|
|
45
|
+
| 'succeeded'
|
|
46
|
+
| 'loading'
|
|
47
|
+
| 'labelSave'
|
|
48
|
+
| 'labelSucceeded'
|
|
49
|
+
| 'labelLoading'
|
|
50
|
+
>): UseSaveState => {
|
|
51
|
+
const { t } = useTranslation();
|
|
52
|
+
|
|
53
|
+
const hasLabel = hasValue([labelLoading, labelSave, labelSucceeded]);
|
|
54
|
+
|
|
55
|
+
const startIconConfig = {
|
|
56
|
+
hasLabel,
|
|
57
|
+
loading,
|
|
58
|
+
succeeded,
|
|
59
|
+
enabled: startIcon
|
|
60
|
+
} as StartIconConfigProps;
|
|
61
|
+
|
|
62
|
+
const content = useMemo(() => {
|
|
63
|
+
if (loading) {
|
|
64
|
+
return t(labelLoading || 'loading');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (succeeded) {
|
|
68
|
+
return labelSucceeded ? t(labelSucceeded) : <CheckIcon />;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return labelSave ? t(labelSave) : <SaveIcon />;
|
|
72
|
+
}, [labelLoading, labelSucceeded, labelSave, loading, succeeded]);
|
|
73
|
+
|
|
74
|
+
const startIconToDisplay = useMemo(() => {
|
|
75
|
+
return cond<Array<StartIconConfigProps>, JSX.Element | null>([
|
|
76
|
+
[propEq(true, 'enabled'), always(null)],
|
|
77
|
+
[pipe(propEq(true, 'hasLabel'), not), always(null)],
|
|
78
|
+
[propEq(true, 'succeeded'), always(<CheckIcon />)],
|
|
79
|
+
[propEq(true, 'loading'), always(<SaveIcon />)],
|
|
80
|
+
[T, always(<SaveIcon />)]
|
|
81
|
+
])(startIconConfig);
|
|
82
|
+
}, [startIconConfig]);
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
content,
|
|
86
|
+
startIconToDisplay,
|
|
87
|
+
hasLabel
|
|
88
|
+
};
|
|
89
|
+
};
|
|
@@ -80,11 +80,13 @@ const Radio = ({
|
|
|
80
80
|
data-testid={`${dataTestId} ${optionLabel}`}
|
|
81
81
|
disabled={disabled}
|
|
82
82
|
id={getNormalizedId(`${dataTestId}${optionLabel}`)}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
slotProps={{
|
|
84
|
+
input: {
|
|
85
|
+
'aria-label':
|
|
86
|
+
(equals(type(optionLabel), 'String') &&
|
|
87
|
+
t(optionLabel as string)) ||
|
|
88
|
+
''
|
|
89
|
+
}
|
|
88
90
|
}}
|
|
89
91
|
/>
|
|
90
92
|
}
|
|
@@ -58,8 +58,10 @@ const Switch = ({
|
|
|
58
58
|
data-testid={dataTestId}
|
|
59
59
|
disabled={disabled}
|
|
60
60
|
id={getNormalizedId(dataTestId || '')}
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
slotProps={{
|
|
62
|
+
input: {
|
|
63
|
+
'aria-label': t(label) || ''
|
|
64
|
+
}
|
|
63
65
|
}}
|
|
64
66
|
onChange={changeSwitchValue}
|
|
65
67
|
/>
|
|
@@ -83,7 +83,7 @@ describe('Bar chart', () => {
|
|
|
83
83
|
cy.contains('20').should('be.visible');
|
|
84
84
|
cy.contains(':40 AM').should('be.visible');
|
|
85
85
|
|
|
86
|
-
cy.findByTestId('stacked-bar-3-0-0.
|
|
86
|
+
cy.findByTestId('stacked-bar-3-0-0.08084').should('be.visible');
|
|
87
87
|
|
|
88
88
|
cy.makeSnapshot();
|
|
89
89
|
});
|
|
@@ -96,7 +96,7 @@ describe('Bar chart', () => {
|
|
|
96
96
|
cy.contains('20').should('be.visible');
|
|
97
97
|
cy.contains(':40 AM').should('be.visible');
|
|
98
98
|
|
|
99
|
-
cy.findByTestId('stacked-bar-3-0-0.
|
|
99
|
+
cy.findByTestId('stacked-bar-3-0-0.08084').should('be.visible');
|
|
100
100
|
|
|
101
101
|
cy.makeSnapshot();
|
|
102
102
|
});
|
|
@@ -195,6 +195,45 @@ export const customBarStyle: Story = {
|
|
|
195
195
|
render: Template
|
|
196
196
|
};
|
|
197
197
|
|
|
198
|
+
export const customBarStyleForABar: Story = {
|
|
199
|
+
args: {
|
|
200
|
+
...defaultArgs,
|
|
201
|
+
barStyle: [
|
|
202
|
+
{
|
|
203
|
+
opacity: 0.5,
|
|
204
|
+
radius: 0.5,
|
|
205
|
+
metricId: 10
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
opacity: 0.2,
|
|
209
|
+
radius: 0.3,
|
|
210
|
+
metricId: 1
|
|
211
|
+
}
|
|
212
|
+
]
|
|
213
|
+
},
|
|
214
|
+
render: Template
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
export const customBarStyleForABarStacked: Story = {
|
|
218
|
+
args: {
|
|
219
|
+
...defaultArgs,
|
|
220
|
+
data: dataPingServiceStacked,
|
|
221
|
+
barStyle: [
|
|
222
|
+
{
|
|
223
|
+
opacity: 0.5,
|
|
224
|
+
radius: 0.5,
|
|
225
|
+
metricId: 10
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
opacity: 0.2,
|
|
229
|
+
radius: 0.3,
|
|
230
|
+
metricId: 1
|
|
231
|
+
}
|
|
232
|
+
]
|
|
233
|
+
},
|
|
234
|
+
render: Template
|
|
235
|
+
};
|
|
236
|
+
|
|
198
237
|
export const mixedStacked: Story = {
|
|
199
238
|
args: {
|
|
200
239
|
...defaultArgs,
|
|
@@ -5,6 +5,7 @@ import { BarRounded } from '@visx/shape';
|
|
|
5
5
|
import { dec, equals, gt, pick } from 'ramda';
|
|
6
6
|
|
|
7
7
|
import { BarGroupBar, SeriesPoint, StackKey } from '@visx/shape/lib/types';
|
|
8
|
+
import { getStyle } from '../common/utils';
|
|
8
9
|
import { BarStyle } from './models';
|
|
9
10
|
import { UseBarStackProps, useBarStack } from './useBarStack';
|
|
10
11
|
|
|
@@ -112,6 +113,11 @@ const BarStack = ({
|
|
|
112
113
|
[isHorizontal ? 'top' : 'right']: shouldApplyRadiusOnTop
|
|
113
114
|
};
|
|
114
115
|
|
|
116
|
+
const style = getStyle({
|
|
117
|
+
style: barStyle,
|
|
118
|
+
metricId: Number(bar.key)
|
|
119
|
+
}) as BarStyle;
|
|
120
|
+
|
|
115
121
|
return (
|
|
116
122
|
<BarRounded
|
|
117
123
|
{...barRoundedProps}
|
|
@@ -133,8 +139,8 @@ const BarStack = ({
|
|
|
133
139
|
neutralValue
|
|
134
140
|
})}
|
|
135
141
|
key={`bar-stack-${barStack.index}-${bar.index}`}
|
|
136
|
-
opacity={
|
|
137
|
-
radius={barWidth *
|
|
142
|
+
opacity={style?.opacity || 1}
|
|
143
|
+
radius={style?.radius ? barWidth * style.radius : 0}
|
|
138
144
|
width={isHorizontal ? barWidth : Math.abs(bar.width)}
|
|
139
145
|
x={
|
|
140
146
|
isHorizontal
|
|
@@ -87,14 +87,15 @@ const ResponsiveBarChart = ({
|
|
|
87
87
|
secondUnit
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
-
const { legendRef, graphWidth, graphHeight } =
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
90
|
+
const { legendRef, graphWidth, graphHeight, titleRef } =
|
|
91
|
+
useComputeBaseChartDimensions({
|
|
92
|
+
hasSecondUnit: Boolean(secondUnit),
|
|
93
|
+
height,
|
|
94
|
+
legendDisplay: legend?.display,
|
|
95
|
+
legendPlacement: legend?.placement,
|
|
96
|
+
width,
|
|
97
|
+
maxAxisCharacters: maxRightAxisCharacters || maxLeftAxisCharacters
|
|
98
|
+
});
|
|
98
99
|
|
|
99
100
|
const thresholdValues = flatten([
|
|
100
101
|
pluck('value', thresholds?.warning || []),
|
|
@@ -192,6 +193,7 @@ const ResponsiveBarChart = ({
|
|
|
192
193
|
lines={linesGraph}
|
|
193
194
|
setLines={setLinesGraph}
|
|
194
195
|
title={title}
|
|
196
|
+
titleRef={titleRef}
|
|
195
197
|
>
|
|
196
198
|
<Tooltip
|
|
197
199
|
classes={{
|
|
@@ -1,15 +1,31 @@
|
|
|
1
1
|
import { Shape } from '@visx/visx';
|
|
2
2
|
import { ScaleLinear, ScaleTime } from 'd3-scale';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
path,
|
|
5
|
+
all,
|
|
6
|
+
equals,
|
|
7
|
+
isNil,
|
|
8
|
+
map,
|
|
9
|
+
not,
|
|
10
|
+
nth,
|
|
11
|
+
pipe,
|
|
12
|
+
prop,
|
|
13
|
+
type
|
|
14
|
+
} from 'ramda';
|
|
4
15
|
|
|
5
16
|
import { getDates, getTime } from '../../../../common/timeSeries';
|
|
6
17
|
import { Line, TimeValue } from '../../../../common/timeSeries/models';
|
|
7
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
getPointRadius,
|
|
20
|
+
getStrokeDashArray,
|
|
21
|
+
getStyle
|
|
22
|
+
} from '../../../../common/utils';
|
|
8
23
|
import StackedAnchorPoint, {
|
|
9
24
|
getYAnchorPoint
|
|
10
25
|
} from '../../../InteractiveComponents/AnchorPoint/StackedAnchorPoint';
|
|
11
26
|
import { StackValue } from '../../../InteractiveComponents/AnchorPoint/models';
|
|
12
27
|
import { getCurveFactory, getFillColor } from '../../../common';
|
|
28
|
+
import { LineStyle } from '../../../models';
|
|
13
29
|
import Point from '../Point';
|
|
14
30
|
|
|
15
31
|
interface Props {
|
|
@@ -26,6 +42,7 @@ interface Props {
|
|
|
26
42
|
timeSeries: Array<TimeValue>;
|
|
27
43
|
xScale: ScaleTime<number, number>;
|
|
28
44
|
yScale: ScaleLinear<number, number>;
|
|
45
|
+
lineStyle: LineStyle | Array<LineStyle>;
|
|
29
46
|
}
|
|
30
47
|
|
|
31
48
|
const StackLines = ({
|
|
@@ -34,19 +51,13 @@ const StackLines = ({
|
|
|
34
51
|
yScale,
|
|
35
52
|
xScale,
|
|
36
53
|
displayAnchor,
|
|
37
|
-
|
|
38
|
-
showPoints,
|
|
39
|
-
showArea,
|
|
40
|
-
areaTransparency,
|
|
41
|
-
lineWidth,
|
|
42
|
-
dashLength,
|
|
43
|
-
dashOffset,
|
|
44
|
-
dotOffset
|
|
54
|
+
lineStyle
|
|
45
55
|
}: Props): JSX.Element => {
|
|
46
|
-
const curveType = getCurveFactory(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
56
|
+
const curveType = getCurveFactory(
|
|
57
|
+
(equals(type(lineStyle), 'Array')
|
|
58
|
+
? lineStyle?.[0].curve
|
|
59
|
+
: lineStyle?.curve) || 'linear'
|
|
60
|
+
);
|
|
50
61
|
return (
|
|
51
62
|
<Shape.AreaStack
|
|
52
63
|
curve={curveType}
|
|
@@ -69,15 +80,21 @@ const StackLines = ({
|
|
|
69
80
|
const { areaColor, transparency, lineColor, highlight, metric_id } =
|
|
70
81
|
nth(index, lines) as Line;
|
|
71
82
|
|
|
72
|
-
const
|
|
83
|
+
const style = getStyle({
|
|
84
|
+
style: lineStyle,
|
|
85
|
+
metricId: metric_id
|
|
86
|
+
}) as LineStyle;
|
|
87
|
+
const formattedLineWidth = style?.lineWidth ?? 2;
|
|
88
|
+
|
|
89
|
+
const formattedTransparency = isNil(style?.areaTransparency)
|
|
73
90
|
? transparency || 80
|
|
74
|
-
: areaTransparency;
|
|
91
|
+
: style.areaTransparency;
|
|
75
92
|
|
|
76
93
|
return (
|
|
77
94
|
<g key={`stack-${prop('key', stack)}`}>
|
|
78
95
|
{displayAnchor && (
|
|
79
96
|
<StackedAnchorPoint
|
|
80
|
-
areaColor={areaColor}
|
|
97
|
+
areaColor={style?.areaColor}
|
|
81
98
|
lineColor={lineColor}
|
|
82
99
|
stackValues={stack as unknown as Array<StackValue>}
|
|
83
100
|
timeSeries={timeSeries}
|
|
@@ -86,13 +103,13 @@ const StackLines = ({
|
|
|
86
103
|
yScale={yScale}
|
|
87
104
|
/>
|
|
88
105
|
)}
|
|
89
|
-
{showPoints &&
|
|
106
|
+
{style?.showPoints &&
|
|
90
107
|
getDates(timeSeries).map((timeTick) => (
|
|
91
108
|
<Point
|
|
92
109
|
key={timeTick.toString()}
|
|
93
110
|
lineColor={lineColor}
|
|
94
111
|
metric_id={metric_id}
|
|
95
|
-
radius={getPointRadius(lineWidth)}
|
|
112
|
+
radius={getPointRadius(style?.lineWidth)}
|
|
96
113
|
timeSeries={timeSeries}
|
|
97
114
|
timeTick={timeTick}
|
|
98
115
|
xScale={xScale}
|
|
@@ -108,7 +125,7 @@ const StackLines = ({
|
|
|
108
125
|
d={linePath(stack) || ''}
|
|
109
126
|
data-metric={metric_id}
|
|
110
127
|
fill={
|
|
111
|
-
equals(showArea, false)
|
|
128
|
+
equals(style?.showArea, false)
|
|
112
129
|
? 'transparent'
|
|
113
130
|
: getFillColor({
|
|
114
131
|
areaColor: areaColor || lineColor,
|
|
@@ -118,10 +135,10 @@ const StackLines = ({
|
|
|
118
135
|
opacity={highlight === false ? 0.3 : 1}
|
|
119
136
|
stroke={lineColor}
|
|
120
137
|
strokeDasharray={getStrokeDashArray({
|
|
121
|
-
dashLength,
|
|
122
|
-
dashOffset,
|
|
123
|
-
dotOffset,
|
|
124
|
-
lineWidth:
|
|
138
|
+
dashLength: style?.dashLength,
|
|
139
|
+
dashOffset: style?.dashOffset,
|
|
140
|
+
dotOffset: style?.dotOffset,
|
|
141
|
+
lineWidth: style?.lineWidth ?? 2
|
|
125
142
|
})}
|
|
126
143
|
strokeWidth={
|
|
127
144
|
highlight
|