@centreon/ui 24.4.67 → 24.4.68

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centreon/ui",
3
- "version": "24.4.67",
3
+ "version": "24.4.68",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "update:deps": "pnpx npm-check-updates -i --format group",
@@ -65,6 +65,7 @@ const DescendantNodes = <TData extends BaseProp>({
65
65
  <Group key={key} left={left} top={top}>
66
66
  <foreignObject
67
67
  height={nodeSize.height}
68
+ style={{ userSelect: 'none' }}
68
69
  width={nodeSize.width}
69
70
  x={-nodeSize.width / 2}
70
71
  y={-nodeSize.height / 2}
@@ -1,5 +1,10 @@
1
- import { LinkHorizontal } from '@visx/shape';
1
+ import {
2
+ LinkHorizontal,
3
+ LinkHorizontalStep,
4
+ LinkHorizontalLine
5
+ } from '@visx/shape';
2
6
  import { HierarchyPointLink } from '@visx/hierarchy/lib/types';
7
+ import { always, cond, equals, T } from 'ramda';
3
8
 
4
9
  import { useTheme } from '@mui/material';
5
10
 
@@ -9,6 +14,12 @@ interface Props<TData> extends Pick<TreeProps<TData>, 'treeLink'> {
9
14
  links: Array<HierarchyPointLink<Node<TData>>>;
10
15
  }
11
16
 
17
+ const getLinkComponent = cond([
18
+ [equals('line'), always(LinkHorizontalLine)],
19
+ [equals('step'), always(LinkHorizontalStep)],
20
+ [T, always(LinkHorizontal)]
21
+ ]);
22
+
12
23
  const Links = <TData extends BaseProp>({
13
24
  links,
14
25
  treeLink
@@ -24,10 +35,12 @@ const Links = <TData extends BaseProp>({
24
35
  .descendants()
25
36
  .map((ancestor) => ancestor.data.data.id);
26
37
 
38
+ const LinkComponent = getLinkComponent(treeLink?.type);
39
+
27
40
  const key = `${link.source.data.data.id}-${link.source.data.data.name}-${ancestorIds}_${link.target.data.data.id}-${link.target.data.data.name}-${descendantIds}`;
28
41
 
29
42
  return (
30
- <LinkHorizontal
43
+ <LinkComponent
31
44
  data={link}
32
45
  data-testid={`${link.source.data.data.id}_to_${link.target.data.data.id}`}
33
46
  fill="none"
@@ -168,4 +168,28 @@ describe('Complex data tree', () => {
168
168
 
169
169
  cy.makeSnapshot();
170
170
  });
171
+
172
+ it('displays the tree with step links when a prop is set', () => {
173
+ initializeStandaloneTree({
174
+ treeLink: {
175
+ type: 'step'
176
+ }
177
+ });
178
+
179
+ cy.contains('T').should('be.visible');
180
+
181
+ cy.makeSnapshot();
182
+ });
183
+
184
+ it('displays the tree with line links when a prop is set', () => {
185
+ initializeStandaloneTree({
186
+ treeLink: {
187
+ type: 'line'
188
+ }
189
+ });
190
+
191
+ cy.contains('T').should('be.visible');
192
+
193
+ cy.makeSnapshot();
194
+ });
171
195
  });
@@ -82,6 +82,21 @@ export const WithDefaultExpandFilter: Story = {
82
82
  render: StandaloneTreeTemplate
83
83
  };
84
84
 
85
+ export const WithStepLink: Story = {
86
+ args: {
87
+ children: SimpleContent,
88
+ node: {
89
+ height: 90,
90
+ width: 90
91
+ },
92
+ tree: simpleData,
93
+ treeLink: {
94
+ type: 'step'
95
+ }
96
+ },
97
+ render: StandaloneTreeTemplate
98
+ };
99
+
85
100
  export const WithCustomLinks: Story = {
86
101
  args: {
87
102
  children: SimpleContent,
@@ -95,7 +110,8 @@ export const WithCustomLinks: Story = {
95
110
  getStrokeDasharray: ({ target }) =>
96
111
  target.status === 'ok' ? '5,5' : '0',
97
112
  getStrokeOpacity: ({ target }) => (target.status === 'ok' ? 0.8 : 1),
98
- getStrokeWidth: ({ target }) => (target.status === 'ok' ? 1 : 2)
113
+ getStrokeWidth: ({ target }) => (target.status === 'ok' ? 1 : 2),
114
+ type: 'line'
99
115
  }
100
116
  },
101
117
  render: StandaloneTreeTemplate
@@ -14,6 +14,8 @@ export interface BaseProp {
14
14
  name: string;
15
15
  }
16
16
 
17
+ export type Link = 'curve' | 'line' | 'step';
18
+
17
19
  export interface ChildrenProps<TData> {
18
20
  ancestors: Array<Node<TData>>;
19
21
  depth: number;
@@ -48,5 +50,6 @@ export interface TreeProps<TData> {
48
50
  ) => string | number | undefined;
49
51
  getStrokeOpacity?: (props: LinkProps<TData>) => string | number | undefined;
50
52
  getStrokeWidth?: (props: LinkProps<TData>) => string | number | undefined;
53
+ type?: Link;
51
54
  };
52
55
  }
@@ -16,6 +16,7 @@ interface Props extends Omit<UseMinimapProps, 'minimapScale' | 'scale'> {
16
16
  left: number;
17
17
  top: number;
18
18
  };
19
+ id?: number | string;
19
20
  isDraggingFromContainer: boolean;
20
21
  }
21
22
 
@@ -26,7 +27,8 @@ const Minimap = ({
26
27
  width,
27
28
  contentClientRect,
28
29
  isDraggingFromContainer,
29
- diffBetweenContentAndSvg
30
+ diffBetweenContentAndSvg,
31
+ id
30
32
  }: Props): JSX.Element => {
31
33
  const { classes } = useZoomStyles();
32
34
 
@@ -82,7 +84,7 @@ const Minimap = ({
82
84
  );
83
85
 
84
86
  return (
85
- <g className={classes.minimap} clipPath="url(#zoom-clip)">
87
+ <g className={classes.minimap} clipPath={`url(#zoom-clip-${id})`}>
86
88
  <rect
87
89
  className={classes.minimapBackground}
88
90
  height={finalHeight}
@@ -63,7 +63,7 @@ describe('Zoom', () => {
63
63
  it('displays the minimap when the prop is set', () => {
64
64
  initialize({ showMinimap: true });
65
65
 
66
- cy.get('g[clip-path="url(#zoom-clip)"]').should('be.visible');
66
+ cy.get('g[clip-path="url(#zoom-clip-0)"]').should('be.visible');
67
67
 
68
68
  cy.makeSnapshot();
69
69
  });
@@ -72,7 +72,7 @@ describe('Zoom', () => {
72
72
  initialize({ showMinimap: true });
73
73
 
74
74
  cy.get('g[transform="matrix(1, 0, 0, 1, 0, 0)"]');
75
- cy.get('g[clip-path="url(#zoom-clip)"]').should('be.visible');
75
+ cy.get('g[clip-path="url(#zoom-clip-0)"]').should('be.visible');
76
76
 
77
77
  cy.findByTestId('zoom in').click();
78
78
  cy.findByTestId('zoom-content')
@@ -86,7 +86,7 @@ describe('Zoom', () => {
86
86
  initialize({ showMinimap: true });
87
87
 
88
88
  cy.get('g[transform="matrix(1, 0, 0, 1, 0, 0)"]');
89
- cy.get('g[clip-path="url(#zoom-clip)"]').should('be.visible');
89
+ cy.get('g[clip-path="url(#zoom-clip-0)"]').should('be.visible');
90
90
 
91
91
  cy.findByTestId('zoom out').click();
92
92
 
@@ -101,7 +101,7 @@ describe('Zoom', () => {
101
101
  initialize({ showMinimap: true });
102
102
 
103
103
  cy.get('g[transform="matrix(1, 0, 0, 1, 0, 0)"]');
104
- cy.get('g[clip-path="url(#zoom-clip)"]').should('be.visible');
104
+ cy.get('g[clip-path="url(#zoom-clip-0)"]').should('be.visible');
105
105
 
106
106
  cy.findByTestId('zoom-content').realMouseWheel({ deltaY: 20 });
107
107
 
@@ -116,7 +116,7 @@ describe('Zoom', () => {
116
116
  initialize({ showMinimap: true });
117
117
 
118
118
  cy.get('g[transform="matrix(1, 0, 0, 1, 0, 0)"]');
119
- cy.get('g[clip-path="url(#zoom-clip)"]').should('be.visible');
119
+ cy.get('g[clip-path="url(#zoom-clip-0)"]').should('be.visible');
120
120
 
121
121
  cy.findByTestId('zoom-content').realMouseWheel({ deltaY: -20 });
122
122
 
@@ -131,7 +131,7 @@ describe('Zoom', () => {
131
131
  initialize({ showMinimap: true });
132
132
 
133
133
  cy.get('g[transform="matrix(1, 0, 0, 1, 0, 0)"]');
134
- cy.get('g[clip-path="url(#zoom-clip)"]').should('be.visible');
134
+ cy.get('g[clip-path="url(#zoom-clip-0)"]').should('be.visible');
135
135
 
136
136
  cy.findByTestId('zoom-content').realMouseWheel({ deltaY: -20 });
137
137
 
@@ -150,7 +150,7 @@ describe('Zoom', () => {
150
150
  initialize({ showMinimap: false });
151
151
 
152
152
  cy.get('g[transform="matrix(1, 0, 0, 1, 0, 0)"]');
153
- cy.get('g[clip-path="url(#zoom-clip)"]').should('not.exist');
153
+ cy.get('g[clip-path="url(#zoom-clip-0)"]').should('not.exist');
154
154
 
155
155
  cy.makeSnapshot();
156
156
  });
@@ -158,7 +158,7 @@ describe('Zoom', () => {
158
158
  it('zooms in when the minimap is scrolled up', () => {
159
159
  initialize({ showMinimap: true });
160
160
 
161
- cy.get('g[clip-path="url(#zoom-clip)"]').should('be.visible');
161
+ cy.get('g[clip-path="url(#zoom-clip-0)"]').should('be.visible');
162
162
 
163
163
  cy.findByTestId('minimap-interaction').realMouseWheel({ deltaY: -20 });
164
164
 
@@ -172,7 +172,7 @@ describe('Zoom', () => {
172
172
  it('zooms out when the minimap is scrolled down', () => {
173
173
  initialize({ showMinimap: true });
174
174
 
175
- cy.get('g[clip-path="url(#zoom-clip)"]').should('be.visible');
175
+ cy.get('g[clip-path="url(#zoom-clip-0)"]').should('be.visible');
176
176
 
177
177
  cy.findByTestId('minimap-interaction').realMouseWheel({ deltaY: 20 });
178
178
 
@@ -186,7 +186,7 @@ describe('Zoom', () => {
186
186
  it('moves the view when the mouse is hover the content with the corresponding button pressed down', () => {
187
187
  initialize({ showMinimap: true });
188
188
 
189
- cy.get('g[clip-path="url(#zoom-clip)"]').should('be.visible');
189
+ cy.get('g[clip-path="url(#zoom-clip-0)"]').should('be.visible');
190
190
  cy.get('svg').should('have.attr', 'height', '400');
191
191
 
192
192
  cy.findByTestId('zoom-container')
@@ -205,7 +205,7 @@ describe('Zoom', () => {
205
205
  it('displays the minimap in the bottom right when the prop to the corresponding value', () => {
206
206
  initialize({ minimapPosition: 'bottom-right', showMinimap: true });
207
207
 
208
- cy.get('g[clip-path="url(#zoom-clip)"]').should('be.visible');
208
+ cy.get('g[clip-path="url(#zoom-clip-0)"]').should('be.visible');
209
209
  cy.get('svg').should('have.attr', 'height', '400');
210
210
 
211
211
  cy.makeSnapshot();
@@ -214,7 +214,7 @@ describe('Zoom', () => {
214
214
  it('applies a scale down on the minimap when the content is higher than the original height', () => {
215
215
  initialize({ showMinimap: true, template: ContentWithMultipleShapes });
216
216
 
217
- cy.get('g[clip-path="url(#zoom-clip)"]').should('be.visible');
217
+ cy.get('g[clip-path="url(#zoom-clip-0)"]').should('be.visible');
218
218
  cy.get('svg').should('have.attr', 'height', '400');
219
219
 
220
220
  cy.findByTestId('minimap-interaction')
@@ -232,7 +232,7 @@ describe('Zoom', () => {
232
232
  template: ContentWithMultipleShapesWithNegativeTranslations
233
233
  });
234
234
 
235
- cy.get('g[clip-path="url(#zoom-clip)"]').should('be.visible');
235
+ cy.get('g[clip-path="url(#zoom-clip-0)"]').should('be.visible');
236
236
  cy.get('svg').should('have.attr', 'height', '400');
237
237
 
238
238
  cy.findByTestId('minimap-interaction')
@@ -7,6 +7,7 @@ import { MinimapPosition } from './models';
7
7
 
8
8
  export interface ZoomProps {
9
9
  children: JSX.Element | (({ width, height }) => JSX.Element);
10
+ id?: number | string;
10
11
  minimapPosition?: MinimapPosition;
11
12
  scaleMax?: number;
12
13
  scaleMin?: number;
@@ -27,7 +28,8 @@ const Zoom = ({
27
28
  scaleMin = 0.5,
28
29
  scaleMax = 4,
29
30
  showMinimap = false,
30
- minimapPosition = 'top-left'
31
+ minimapPosition = 'top-left',
32
+ id = 0
31
33
  }: ZoomProps): JSX.Element => {
32
34
  return (
33
35
  <ParentSize>
@@ -44,6 +46,7 @@ const Zoom = ({
44
46
  {(zoom) => (
45
47
  <ZoomContent
46
48
  height={height}
49
+ id={id}
47
50
  minimapPosition={minimapPosition}
48
51
  showMinimap={showMinimap}
49
52
  width={width}
@@ -18,6 +18,7 @@ import { ChildrenProps, MinimapPosition, ZoomState } from './models';
18
18
  export interface Props {
19
19
  children: ({ width, height, transformMatrix }: ChildrenProps) => JSX.Element;
20
20
  height: number;
21
+ id?: number | string;
21
22
  minimapPosition: MinimapPosition;
22
23
  showMinimap?: boolean;
23
24
  width: number;
@@ -30,7 +31,8 @@ const ZoomContent = ({
30
31
  height,
31
32
  children,
32
33
  showMinimap,
33
- minimapPosition
34
+ minimapPosition,
35
+ id
34
36
  }: Props): JSX.Element => {
35
37
  const { classes } = useZoomStyles();
36
38
  const contentRef = useRef<SVGGElement | null>(null);
@@ -92,7 +94,7 @@ const ZoomContent = ({
92
94
  >
93
95
  <RectClipPath
94
96
  height={Math.max(contentClientRect?.height || 0, height)}
95
- id="zoom-clip"
97
+ id={`zoom-clip-${id}`}
96
98
  rx={radius}
97
99
  width={Math.max(contentClientRect?.width || 0, width)}
98
100
  />
@@ -124,6 +126,7 @@ const ZoomContent = ({
124
126
  diffBetweenContentAndSvg || { left: 0, top: 0 }
125
127
  }
126
128
  height={height}
129
+ id={id}
127
130
  isDraggingFromContainer={isDragging}
128
131
  width={width}
129
132
  zoom={zoom}
@@ -22,3 +22,4 @@ export * from './centreonBaseURL';
22
22
  export * from './usePluralizedTranslation';
23
23
  export * from './useResizeObserver';
24
24
  export * from './useFullscreen';
25
+ export * from './resourcesStatusURL';
@@ -0,0 +1,166 @@
1
+ import {
2
+ always,
3
+ cond,
4
+ equals,
5
+ flatten,
6
+ groupBy,
7
+ identity,
8
+ includes,
9
+ map,
10
+ pipe,
11
+ T
12
+ } from 'ramda';
13
+
14
+ import { SelectEntry } from '..';
15
+
16
+ import { centreonBaseURL } from './centreonBaseURL';
17
+
18
+ export interface Resource {
19
+ resourceType: string;
20
+ resources: Array<SelectEntry>;
21
+ }
22
+
23
+ interface GetResourcesUrlProps {
24
+ allResources: Array<Resource>;
25
+ isForOneResource: boolean;
26
+ resource?;
27
+ states: Array<string>;
28
+ statuses: Array<string>;
29
+ type: string;
30
+ }
31
+
32
+ export const getDetailsPanelQueriers = ({ resource, type }): object => {
33
+ const { id, parentId, uuid } = resource;
34
+
35
+ const resourcesDetailsEndpoint = cond([
36
+ [
37
+ equals('host'),
38
+ always(`${centreonBaseURL}/api/latest/monitoring/resources/hosts/${id}`)
39
+ ],
40
+ [
41
+ equals('service'),
42
+ always(
43
+ `${centreonBaseURL}/api/latest/monitoring/resources/hosts/${parentId}/services/${id}`
44
+ )
45
+ ],
46
+ [
47
+ equals('metaservice'),
48
+ always(
49
+ `${centreonBaseURL}/api/latest/monitoring/resources/metaservices/${id}`
50
+ )
51
+ ],
52
+ [
53
+ equals('anomaly-detection'),
54
+ always(
55
+ `${centreonBaseURL}/api/latest/monitoring/resources/anomaly-detection/${id}`
56
+ )
57
+ ]
58
+ ])(type);
59
+
60
+ const queryParameters = {
61
+ id,
62
+ resourcesDetailsEndpoint,
63
+ selectedTimePeriodId: 'last_24_h',
64
+ tab: 'details',
65
+ tabParameters: {},
66
+ uuid
67
+ };
68
+
69
+ return queryParameters;
70
+ };
71
+
72
+ export const getResourcesUrl = ({
73
+ type,
74
+ statuses,
75
+ states,
76
+ allResources,
77
+ isForOneResource,
78
+ resource
79
+ }: GetResourcesUrlProps): string => {
80
+ const resourcesCriterias = equals(type, 'all')
81
+ ? {
82
+ name: 'resource_types',
83
+ value: [
84
+ { id: 'service', name: 'Service' },
85
+ { id: 'host', name: 'Host' }
86
+ ]
87
+ }
88
+ : {
89
+ name: 'resource_types',
90
+ value: [
91
+ { id: type, name: `${type.charAt(0).toUpperCase()}${type.slice(1)}` }
92
+ ]
93
+ };
94
+
95
+ const formattedStatuses = pipe(
96
+ flatten,
97
+ map((status: string) => {
98
+ return {
99
+ id: status.toLocaleUpperCase(),
100
+ name: `${status.charAt(0).toUpperCase()}${status.slice(1)}`
101
+ };
102
+ })
103
+ )(statuses);
104
+
105
+ const formattedStates = states.map((state) => {
106
+ return {
107
+ id: state,
108
+ name: `${state.charAt(0).toUpperCase()}${state.slice(1)}`
109
+ };
110
+ });
111
+
112
+ const groupedResources = groupBy(
113
+ ({ resourceType }) => resourceType,
114
+ allResources
115
+ );
116
+
117
+ const resourcesFilters = Object.entries(groupedResources).map(
118
+ ([resourceType, res]) => {
119
+ const name = cond<Array<string>, string>([
120
+ [equals('host'), always('parent_name')],
121
+ [equals('service'), always('name')],
122
+ [T, identity]
123
+ ])(resourceType);
124
+
125
+ return {
126
+ name: name.replace('-', '_'),
127
+ value: flatten(
128
+ (res || []).map(({ resources: subResources }) => {
129
+ return subResources.map(({ name: resourceName }) => ({
130
+ id: includes(name, ['name', 'parent_name'])
131
+ ? `\\b${resourceName}\\b`
132
+ : resourceName,
133
+ name: resourceName
134
+ }));
135
+ })
136
+ )
137
+ };
138
+ }
139
+ );
140
+
141
+ const filterQueryParameter = {
142
+ criterias: [
143
+ resourcesCriterias,
144
+ { name: 'statuses', value: formattedStatuses },
145
+ { name: 'states', value: formattedStates },
146
+ ...resourcesFilters,
147
+ { name: 'search', value: '' }
148
+ ]
149
+ };
150
+
151
+ const encodedFilterParams = encodeURIComponent(
152
+ JSON.stringify(filterQueryParameter)
153
+ );
154
+
155
+ if (!isForOneResource) {
156
+ return `/monitoring/resources?filter=${encodedFilterParams}&fromTopCounter=true`;
157
+ }
158
+
159
+ const detailsPanelQueriers = getDetailsPanelQueriers({ resource, type });
160
+
161
+ const encodedDetailsParams = encodeURIComponent(
162
+ JSON.stringify(detailsPanelQueriers)
163
+ );
164
+
165
+ return `/monitoring/resources?details=${encodedDetailsParams}&filter=${encodedFilterParams}&fromTopCounter=true`;
166
+ };