Skip to content

Commit 1756ce7

Browse files
Merge pull request #1865 from carbon-design-system/1767-hotspot-datasource
1767 hotspot datasource
2 parents a7b97ef + c49ff4c commit 1756ce7

9 files changed

Lines changed: 1488 additions & 24 deletions

File tree

src/components/CardEditor/CardEditForm/CardEditFormItems/DataSeriesFormItemModal.jsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,8 @@ const DataSeriesFormItemModal = ({
314314
) : null}
315315
</div>
316316
<ThresholdsFormItem
317+
dataSourceId={editDataItem.dataSourceId}
318+
cardConfig={cardConfig}
317319
id={`${id}_thresholds`}
318320
thresholds={editDataItem.thresholds}
319321
selectedIcon={{ carbonIcon: <WarningAlt32 />, name: 'Warning alt' }}
@@ -339,13 +341,16 @@ const DataSeriesFormItemModal = ({
339341
? mergedI18n.dataItemEditorValueCardTitle
340342
: mergedI18n.dataItemEditorDataSeriesTitle,
341343
}}
342-
size="xs"
344+
size="sm"
343345
onSubmit={() => {
344-
const newCard = handleDataItemEdit(
345-
editDataItem,
346-
cardConfig,
347-
editDataSeries
348-
);
346+
const newCard =
347+
cardConfig.type === 'IMAGE'
348+
? editDataItem
349+
: handleDataItemEdit(
350+
editDataItem,
351+
cardConfig,
352+
editDataSeries
353+
);
349354
onChange(newCard);
350355
setShowEditor(false);
351356
setEditDataItem({});

src/components/CardEditor/CardEditForm/CardEditFormItems/ThresholdsFormItem.jsx

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,12 @@ const propTypes = {
7979
dataItemEditorDataItemThresholds: PropTypes.string,
8080
dataItemEditorDataItemAddThreshold: PropTypes.string,
8181
}),
82+
/** The current data item's id */
83+
dataSourceId: PropTypes.string,
8284
};
8385

8486
const defaultProps = {
87+
dataSourceId: null,
8588
cardConfig: {},
8689
onChange: null,
8790
thresholds: [],
@@ -97,6 +100,7 @@ const defaultProps = {
97100
};
98101

99102
const ThresholdsFormItem = ({
103+
dataSourceId,
100104
cardConfig,
101105
thresholds: thresholdsProp,
102106
icons,
@@ -249,25 +253,23 @@ const ThresholdsFormItem = ({
249253
size="small"
250254
renderIcon={Add16}
251255
onClick={() => {
252-
onChange([
253-
...thresholds,
254-
{
255-
comparison: '>',
256-
value: 0,
257-
icon: selectedIcon?.name || 'Warning alt',
258-
color: selectedColor?.carbonColor || red60,
259-
},
260-
]);
256+
let newThreshold = {
257+
comparison: '>',
258+
value: 0,
259+
icon: selectedIcon?.name || 'Warning alt',
260+
color: selectedColor?.carbonColor || red60,
261+
};
262+
if (dataSourceId) {
263+
newThreshold = { dataSourceId, ...newThreshold };
264+
}
261265
setThresholds([
262266
...thresholds,
263267
{
264268
id: uuid.v4(),
265-
comparison: '>',
266-
value: 0,
267-
icon: selectedIcon?.name || 'Warning alt',
268-
color: selectedColor?.carbonColor || red60,
269+
...newThreshold,
269270
},
270271
]);
272+
onChange([...thresholds, newThreshold]);
271273
}}>
272274
{mergedI18n.dataItemEditorDataItemAddThreshold}
273275
</Button>

src/components/DashboardEditor/editorUtils.jsx

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -620,11 +620,13 @@ export const formatAttributes = (selectedItems, cardConfig) => {
620620
export const handleDataSeriesChange = (
621621
selectedItems,
622622
cardConfig,
623-
setEditDataSeries
623+
setEditDataSeries,
624+
hotspotIndex
624625
) => {
625626
const { type } = cardConfig;
626627
let series;
627628
let attributes;
629+
let dataSection;
628630

629631
switch (type) {
630632
case CARD_TYPES.VALUE:
@@ -641,20 +643,35 @@ export const handleDataSeriesChange = (
641643
...cardConfig,
642644
content: { ...cardConfig.content, series },
643645
};
646+
case CARD_TYPES.IMAGE:
647+
dataSection = [...(cardConfig.content?.hotspots || [])];
648+
dataSection[hotspotIndex].content = {
649+
...dataSection[hotspotIndex].content,
650+
attributes: selectedItems,
651+
};
652+
return {
653+
...cardConfig,
654+
content: {
655+
...cardConfig.content,
656+
hotspots: dataSection,
657+
},
658+
};
644659
default:
645660
return cardConfig;
646661
}
647662
};
648663

649664
/**
650665
* updates the dataSection on edit of a dataItem based on card type
651-
* @param {array} editDataItem
666+
* @param {object} editDataItem
652667
* @param {object} cardConfig
668+
* @param {string} title
653669
*/
654670
export const handleDataItemEdit = (
655671
editDataItem,
656672
cardConfig,
657-
editDataSeries
673+
editDataSeries,
674+
hotspotIndex
658675
) => {
659676
const { type, content } = cardConfig;
660677
let dataSection;
@@ -682,6 +699,34 @@ export const handleDataItemEdit = (
682699
...cardConfig,
683700
content: { ...content, series: dataSection },
684701
};
702+
case CARD_TYPES.IMAGE:
703+
dataSection = [...(content.hotspots || [])];
704+
705+
editDataItemIndex = dataSection[
706+
hotspotIndex
707+
].content.attributes.findIndex(
708+
(dataItem) => dataItem.dataSourceId === editDataItem.dataSourceId
709+
);
710+
dataSection[hotspotIndex].content.attributes[editDataItemIndex] = omit(
711+
editDataItem,
712+
'thresholds'
713+
);
714+
if (cardConfig.thresholds || editDataItem.thresholds) {
715+
return {
716+
...cardConfig,
717+
content: { ...content, hotspots: dataSection },
718+
thresholds: [
719+
...(cardConfig.thresholds?.filter(
720+
(thresh) => thresh.dataSourceId !== editDataItem.dataSourceId
721+
) || []),
722+
...editDataItem.thresholds,
723+
].map((thresh) => omit(thresh, 'id')),
724+
};
725+
}
726+
return {
727+
...cardConfig,
728+
content: { ...content, hotspots: dataSection },
729+
};
685730
default:
686731
return cardConfig;
687732
}

src/components/DashboardEditor/editorUtils.test.jsx

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import omit from 'lodash/omit';
2+
13
import { CARD_TYPES, BAR_CHART_TYPES } from '../..';
24

35
import {
@@ -266,6 +268,14 @@ describe('editorUtils', () => {
266268
});
267269
});
268270
describe('handleDataSeriesChange', () => {
271+
it('should just return cardConfig if there is no Type', () => {
272+
const newCard = handleDataSeriesChange(
273+
[],
274+
omit(mockTimeSeriesCard, 'type')
275+
);
276+
expect(newCard).toEqual(omit(mockTimeSeriesCard, 'type'));
277+
});
278+
269279
it('should correctly format the data in Timeseries', () => {
270280
const selectedItems = [
271281
{ id: 'key1', text: 'Key 1' },
@@ -322,8 +332,184 @@ describe('editorUtils', () => {
322332
type: 'VALUE',
323333
});
324334
});
335+
336+
it('should correctly format the data in Image Card', () => {
337+
const mockImageCard = {
338+
type: CARD_TYPES.IMAGE,
339+
content: {
340+
hotspots: [
341+
{
342+
title: 'elevators',
343+
content: {
344+
attributes: [
345+
{
346+
dataSourceId: 'temp_last',
347+
label: '{high} temp',
348+
unit: '{unitVar}',
349+
},
350+
{
351+
dataSourceId: 'elevators',
352+
label: 'Elevators',
353+
unit: 'floor',
354+
},
355+
],
356+
},
357+
},
358+
],
359+
},
360+
thresholds: [
361+
{
362+
dataSourceId: 'temp_last',
363+
comparison: '>=',
364+
color: '#da1e28',
365+
icon: 'Checkmark',
366+
value: 98,
367+
},
368+
],
369+
};
370+
const selectedItems = [
371+
{ dataSourceId: 'temp_last', label: '{high} temp', unit: '{unitVar}' },
372+
{ dataSourceId: 'elevators', label: 'Elevators', unit: '°' },
373+
{ dataSourceId: 'pressure', label: 'Pressure', unit: 'psi' },
374+
];
375+
const newCard = handleDataSeriesChange(
376+
selectedItems,
377+
mockImageCard,
378+
null,
379+
0
380+
);
381+
382+
expect(newCard).toEqual({
383+
type: CARD_TYPES.IMAGE,
384+
content: {
385+
hotspots: [
386+
{
387+
title: 'elevators',
388+
content: {
389+
attributes: [
390+
{
391+
dataSourceId: 'temp_last',
392+
label: '{high} temp',
393+
unit: '{unitVar}',
394+
},
395+
{
396+
dataSourceId: 'elevators',
397+
label: 'Elevators',
398+
unit: '°',
399+
},
400+
{
401+
dataSourceId: 'pressure',
402+
label: 'Pressure',
403+
unit: 'psi',
404+
},
405+
],
406+
},
407+
},
408+
],
409+
},
410+
thresholds: [
411+
{
412+
dataSourceId: 'temp_last',
413+
comparison: '>=',
414+
color: '#da1e28',
415+
icon: 'Checkmark',
416+
value: 98,
417+
},
418+
],
419+
});
420+
});
325421
});
326422
describe('handleDataItemEdit', () => {
423+
it('should correctly format the data in Image Card', () => {
424+
const mockImageCard = {
425+
type: CARD_TYPES.IMAGE,
426+
content: {
427+
hotspots: [
428+
{
429+
title: 'elevators',
430+
content: {
431+
attributes: [
432+
{
433+
dataSourceId: 'temp_last',
434+
label: '{high} temp',
435+
unit: '{unitVar}',
436+
},
437+
],
438+
},
439+
},
440+
],
441+
},
442+
};
443+
const editDataItem = {
444+
dataSourceId: 'temp_last',
445+
label: '{high} temps',
446+
unit: 'degrees',
447+
thresholds: [
448+
{
449+
dataSourceId: 'temp_last',
450+
comparison: '>',
451+
color: '#da1e28',
452+
icon: 'Checkmark',
453+
value: 98,
454+
},
455+
{
456+
dataSourceId: 'temp_last',
457+
comparison: '=',
458+
color: '#ffffff',
459+
icon: 'Checkmark',
460+
value: 100,
461+
},
462+
],
463+
};
464+
let newCard = handleDataItemEdit(editDataItem, mockImageCard, null, 0);
465+
466+
expect(newCard).toEqual({
467+
type: CARD_TYPES.IMAGE,
468+
content: {
469+
hotspots: [
470+
{
471+
title: 'elevators',
472+
content: {
473+
attributes: [
474+
{
475+
dataSourceId: 'temp_last',
476+
label: '{high} temps',
477+
unit: 'degrees',
478+
},
479+
],
480+
},
481+
},
482+
],
483+
},
484+
thresholds: [
485+
{
486+
dataSourceId: 'temp_last',
487+
comparison: '>',
488+
color: '#da1e28',
489+
icon: 'Checkmark',
490+
value: 98,
491+
},
492+
{
493+
dataSourceId: 'temp_last',
494+
comparison: '=',
495+
color: '#ffffff',
496+
icon: 'Checkmark',
497+
value: 100,
498+
},
499+
],
500+
});
501+
502+
const withoutThresholds = omit(mockImageCard, 'thresholds');
503+
newCard = handleDataSeriesChange(
504+
editDataItem,
505+
withoutThresholds,
506+
null,
507+
0
508+
);
509+
510+
expect(newCard).toEqual(withoutThresholds);
511+
});
512+
327513
it('should correctly format the data in Timeseries', () => {
328514
const editDataItem = {
329515
dataSourceId: 'torque',

0 commit comments

Comments
 (0)