Skip to content

Commit c4c7727

Browse files
Vivek Domadiyasimson1
authored andcommitted
feat: add hierarchy data item support to image card
1 parent 63d8f4e commit c4c7727

File tree

3 files changed

+118
-37
lines changed

3 files changed

+118
-37
lines changed

packages/react/src/components/DashboardEditor/DashboardEditor.story.jsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,7 +1204,6 @@ export const I18N = () => (
12041204
yCoordinateDropdownLabelText: 'yCoordinateDropdownLabelText',
12051205
selectDataItemsText: 'selectDataItemsText',
12061206
dataItemText: 'dataItemText',
1207-
editText: 'editText',
12081207
// Hotspot Text Style Tab fields
12091208
textTypeStyleInfoText: 'textTypeStyleInfoText',
12101209
fontColorLabelText: 'fontColorLabelText',
@@ -1547,11 +1546,16 @@ export const withHierarchyDataItems = () => {
15471546
handleHierarchyDataItemChange(hierarchyDataItems),
15481547
dataSeriesFormActions: {
15491548
...commonActions.dataSeriesFormActions,
1550-
hasHierarchyDataItemsEnabled: (card) =>
1551-
card.type === CARD_TYPES.TIMESERIES ||
1552-
card.type === CARD_TYPES.BAR ||
1553-
card.type === CARD_TYPES.VALUE ||
1554-
card.type === CARD_TYPES.TABLE,
1549+
hasHierarchyDataItemsEnabled: (card) => {
1550+
const allowCardTypes = [
1551+
CARD_TYPES.TIMESERIES,
1552+
CARD_TYPES.BAR,
1553+
CARD_TYPES.VALUE,
1554+
CARD_TYPES.TABLE,
1555+
CARD_TYPES.IMAGE,
1556+
];
1557+
return allowCardTypes.includes(card.type);
1558+
},
15551559
},
15561560
};
15571561

packages/react/src/components/HotspotEditorModal/HotspotEditorDataSourceTab/HotspotEditorDataSourceTab.jsx

Lines changed: 107 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import React, { useState, useCallback } from 'react';
1+
import React, { useState, useCallback, useMemo } from 'react';
22
import PropTypes from 'prop-types';
33
import { Edit } from '@carbon/react/icons';
44
import { MultiSelect } from '@carbon/react';
55
import { isEmpty } from 'lodash-es';
6+
import { v4 as uuidv4 } from 'uuid';
7+
import { MisuseOutline } from '@carbon/icons-react';
68

79
import DataSeriesFormItemModal from '../../CardEditor/CardEditForm/CardEditFormItems/DataSeriesFormItemModal';
810
import List from '../../List/List';
@@ -13,6 +15,9 @@ import {
1315
DashboardEditorActionsPropTypes,
1416
defaultDashboardEditorActionsProps,
1517
} from '../../DashboardEditor/editorUtils';
18+
import HierarchyDataFormItems, {
19+
isHierarchyDataItem,
20+
} from '../../CardEditor/CardEditForm/CardEditFormItems/HierarchyDataFormItems/HierarchyDataFormItems';
1621

1722
const { iotPrefix } = settings;
1823

@@ -47,7 +52,8 @@ const propTypes = {
4752
i18n: PropTypes.shape({
4853
selectDataItemsText: PropTypes.string,
4954
dataItemText: PropTypes.string,
50-
editText: PropTypes.string,
55+
edit: PropTypes.string,
56+
remove: PropTypes.string,
5157
dataItemEditorDataItemTitle: PropTypes.string,
5258
dataItemEditorDataItemCustomLabel: PropTypes.string,
5359
dataItemEditorDataItemUnit: PropTypes.string,
@@ -85,7 +91,8 @@ const defaultProps = {
8591
i18n: {
8692
selectDataItemsText: 'Select data items',
8793
dataItemText: 'Data items',
88-
editText: 'Edit',
94+
edit: 'Edit',
95+
remove: 'Remove',
8996
dataItemEditorDataItemTitle: 'Data items',
9097
dataItemEditorDataItemCustomLabel: 'Custom label',
9198
dataItemEditorDataItemUnit: 'Unit',
@@ -102,10 +109,12 @@ const defaultProps = {
102109
};
103110

104111
export const formatDataItemsForDropdown = (dataItems) =>
105-
dataItems?.map(({ dataSourceId, label }) => ({
106-
id: dataSourceId,
107-
label,
108-
}));
112+
dataItems
113+
?.filter((dataItem) => !isHierarchyDataItem(dataItem)) // filter hierarchy data items
114+
?.map(({ dataSourceId, label }) => ({
115+
id: dataSourceId,
116+
label,
117+
}));
109118

110119
const HotspotEditorDataSourceTab = ({
111120
hotspot,
@@ -127,15 +136,14 @@ const HotspotEditorDataSourceTab = ({
127136
const selectedItemsArray = hotspot.content?.attributes || [];
128137

129138
const baseClassName = `${iotPrefix}--card-edit-form`;
130-
const initialSelectedItems = formatDataItemsForDropdown(selectedItemsArray);
131139
const { onEditDataItem } = actions;
132140

133141
const handleSelectionChange = ({ selectedItems }) => {
134142
const newArray = [];
135143
// loop through selected Items and find their selectedItemsArray object or the dataItem object with same id
136144
selectedItems.forEach((item) => {
137145
const containedItem = selectedItemsArray.find(
138-
(selectedItem) => selectedItem.dataItemId === item.id
146+
(selectedItem) => selectedItem.dataSourceId === item.id
139147
);
140148
const containedDataItem = dataItems.find(
141149
(selectedItem) => selectedItem.dataItemId === item.id
@@ -146,17 +154,37 @@ const HotspotEditorDataSourceTab = ({
146154
newArray.push(containedDataItem);
147155
}
148156
});
157+
158+
// Add existing hierarchy data items
159+
newArray.push(...selectedItemsArray.filter((item) => isHierarchyDataItem(item)));
160+
149161
onChange({ attributes: newArray });
150162
};
151163

164+
const handleHierarchyDataItemChange = useCallback(
165+
(items) => {
166+
const updatedItems = items?.map((item) => ({
167+
...item,
168+
// create a unique dataSourceId
169+
dataSourceId: `${item.dataItemId}_${uuidv4()}`,
170+
}));
171+
172+
const selectedItems = [...selectedItemsArray, ...updatedItems];
173+
174+
onChange({ attributes: selectedItems });
175+
},
176+
[onChange, selectedItemsArray]
177+
);
178+
152179
// MultiSelect
153-
// For the initial selection to work the objects in prop "initialSelectedItems"
180+
// For the initial selection to work the objects in prop "selectedItemsArray"
154181
// must be identical to the objects in prop "items". It is not enough that the
155182
// ids are the same. Therefore, we must adjust the labels in "items" if they have
156-
// been modified in the "initialSelectedItems".
183+
// been modified in the "selectedItemsArray".
157184
const multiSelectItems = formatDataItemsForDropdown(dataItems).map((item) => ({
158185
...item,
159-
label: initialSelectedItems.find((selected) => selected.id === item.id)?.label ?? item.label,
186+
label:
187+
selectedItemsArray.find((selected) => selected.dataSourceId === item.id)?.label ?? item.label,
160188
}));
161189

162190
const handleEditButton = useCallback(
@@ -182,6 +210,64 @@ const HotspotEditorDataSourceTab = ({
182210
[cardConfig, onEditDataItem, dataItems]
183211
);
184212

213+
const handleRemoveButton = useCallback(
214+
(selectedItem) => {
215+
const newArray = selectedItemsArray.filter(
216+
(item) => item.dataSourceId !== selectedItem.dataSourceId
217+
);
218+
219+
onChange({ attributes: newArray });
220+
},
221+
[selectedItemsArray, onChange]
222+
);
223+
224+
const generateListItems = useCallback(
225+
(data, isHierarchy = false) =>
226+
data
227+
?.filter((dataItem) => isHierarchyDataItem(dataItem) === isHierarchy)
228+
?.map((dataItem) => ({
229+
id: dataItem.dataSourceId,
230+
content: {
231+
value: dataItem.label,
232+
rowActions: () => [
233+
<Button
234+
key={`data-item-${dataItem.dataSourceId}`}
235+
renderIcon={Edit}
236+
hasIconOnly
237+
kind="ghost"
238+
size="sm"
239+
onClick={() => handleEditButton(dataItem)}
240+
iconDescription={mergedI18n.edit}
241+
tooltipPosition="left"
242+
tooltipAlignment="center"
243+
/>,
244+
<Button
245+
key={`data-item-${dataItem.dataSourceId}_remove`}
246+
renderIcon={MisuseOutline}
247+
hasIconOnly
248+
kind="ghost"
249+
size="sm"
250+
onClick={() => handleRemoveButton(dataItem)}
251+
iconDescription={mergedI18n.remove}
252+
tooltipPosition="left"
253+
tooltipAlignment="center"
254+
/>,
255+
],
256+
},
257+
})),
258+
[handleEditButton, handleRemoveButton, mergedI18n.edit, mergedI18n.remove]
259+
);
260+
261+
const dataListItems = useMemo(
262+
() => generateListItems(selectedItemsArray),
263+
[selectedItemsArray, generateListItems]
264+
);
265+
266+
const hierarchyDataListItems = useMemo(
267+
() => generateListItems(selectedItemsArray, true),
268+
[selectedItemsArray, generateListItems]
269+
);
270+
185271
return (
186272
<div data-testid={testID || testId}>
187273
<DataSeriesFormItemModal
@@ -211,7 +297,7 @@ const HotspotEditorDataSourceTab = ({
211297
id={`${cardConfig.id}_dataSourceIds`}
212298
label={mergedI18n.selectDataItemsText}
213299
direction="bottom"
214-
initialSelectedItems={initialSelectedItems}
300+
selectedItems={formatDataItemsForDropdown(selectedItemsArray)}
215301
items={multiSelectItems}
216302
light
217303
onChange={handleSelectionChange}
@@ -225,23 +311,14 @@ const HotspotEditorDataSourceTab = ({
225311
emptyState={<div />}
226312
testId={`${testId}-data-source-list`}
227313
title=""
228-
items={selectedItemsArray?.map((dataItem) => ({
229-
id: dataItem.dataSourceId,
230-
content: {
231-
value: dataItem.label,
232-
rowActions: () => [
233-
<Button
234-
key={`data-item-${dataItem.dataSourceId}`}
235-
renderIcon={Edit}
236-
hasIconOnly
237-
kind="ghost"
238-
size="sm"
239-
onClick={() => handleEditButton(dataItem)}
240-
iconDescription={mergedI18n.editText}
241-
/>,
242-
],
243-
},
244-
}))}
314+
items={dataListItems}
315+
/>
316+
<HierarchyDataFormItems
317+
cardConfig={cardConfig}
318+
hierarchyDataItemListItems={hierarchyDataListItems}
319+
handleHierarchyDataItemChange={handleHierarchyDataItemChange}
320+
i18n={i18n}
321+
actions={actions}
245322
/>
246323
</div>
247324
);

packages/react/src/components/HotspotEditorModal/HotspotEditorDataSourceTab/HotspotEditorDataSourceTabREADME.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ These props can also be passed as part of the i18n prop of the HotspotModalEdito
125125
| :--------------------------------- | :----- | :------------------ | :---------- |
126126
| selectDataItemsText | string | 'Select data items' | |
127127
| dataItemText | string | 'Data items' | |
128-
| editText | string | 'Edit' | |
128+
| edit | string | 'Edit' | |
129129
| dataItemEditorDataItemTitle | string | 'Data items' | |
130130
| dataItemEditorDataItemCustomLabel | string | 'Custom label' | |
131131
| dataItemEditorDataItemUnit | string | 'Unit' | |

0 commit comments

Comments
 (0)