Skip to content

Commit bb102d1

Browse files
committed
feat: make attributes order configurable in CytoViz component
This commit adds an 'elementsMetadata' prop, that can be used to define the desired order of attributes when selecting a node or edge in the visualization tool. The expected format for this prop is: { attributesOrder: { nodes: { nodeType1: ['someImportantAttribute', 'attribute1', 'attribute2'] }, edges: { edgeType1: ['attributeA', 'attributeB']}}, } } If some attributes are missing in the list, they will be displayed after all the other attributes.
1 parent 1d7b590 commit bb102d1

File tree

2 files changed

+45
-6
lines changed

2 files changed

+45
-6
lines changed

src/charts/CytoViz/CytoViz.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export const CytoViz = (props) => {
5454
cytoscapeStylesheet,
5555
defaultSettings,
5656
elements,
57+
elementsMetadata,
5758
error,
5859
extraLayouts,
5960
getElementDetails,
@@ -81,7 +82,17 @@ export const CytoViz = (props) => {
8182
let getElementDetailsCallback = getElementDetails;
8283
if (!getElementDetailsCallback) {
8384
// eslint-disable-next-line react/display-name
84-
getElementDetailsCallback = (element) => <ElementData data={element.data()} labels={labels_.elementData} />;
85+
getElementDetailsCallback = (element) => {
86+
const elementType = element.classes && element.classes()?.[0];
87+
return (
88+
<ElementData
89+
data={element.data()}
90+
labels={labels_.elementData}
91+
metadata={elementsMetadata}
92+
type={elementType}
93+
/>
94+
);
95+
};
8596
getElementDetailsCallback.displayName = 'ElementData';
8697
}
8798

@@ -714,6 +725,18 @@ CytoViz.propTypes = {
714725
* Array of cytoscape elements to display
715726
*/
716727
elements: PropTypes.array.isRequired,
728+
/**
729+
* Optional array of metadata for cytoscape elements. Currently, it only takes an attributesOrder property to force
730+
* the order of attributes when entity details are displayed.
731+
* Expected format example:
732+
* {
733+
* attributesOrder: {
734+
* nodes: { nodeType1: ['someImportantAttribute', 'attribute1', 'attribute2', 'attribute3'] },
735+
* edges: { edgeType1: ['attributeA', 'attributeB']}},
736+
* }
737+
* }
738+
*/
739+
elementsMetadata: PropTypes.object,
717740
/**
718741
* Object of extra layouts to register in cytoscape. The keys of this object must be the layout names, and the values
719742
must be the extension object to provide to cytoscape.use(...). If you want to add a default cytoscape layout
@@ -829,6 +852,7 @@ CytoViz.defaultProps = {
829852
showStats: false,
830853
spacingFactor: 1,
831854
},
855+
elementsMetadata: {},
832856
extraLayouts: {},
833857
groups: {},
834858
labels: DEFAULT_LABELS,

src/charts/CytoViz/components/ElementData/ElementData.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,26 @@ const _generateAttributeDetails = (classes, labels, attributeName, attributeValu
6969
}
7070
};
7171

72+
const getSortedAttributeNames = (expectedKeys, allKeys) => {
73+
// Start with expected keys in desired order
74+
const sortedKeys = expectedKeys.filter((key) => allKeys.includes(key));
75+
allKeys.filter((key) => !expectedKeys.includes(key)).forEach((key) => sortedKeys.push(key)); // Add unknown keys
76+
return sortedKeys;
77+
};
78+
7279
const ElementData = (props) => {
7380
const classes = useStyles();
74-
const { data, labels } = props;
75-
if (!data) {
76-
return labels.noData;
77-
}
81+
const { data, labels, metadata, type } = props;
82+
if (!data) return labels.noData;
83+
84+
const attributesOrderConfig = metadata?.attributesOrder;
85+
const desiredAttributesOrder = type && (attributesOrderConfig?.nodes?.[type] ?? attributesOrderConfig?.edges?.[type]);
86+
87+
let sortedElementAttributeNames = Object.keys(data);
88+
if (desiredAttributesOrder != null)
89+
sortedElementAttributeNames = getSortedAttributeNames(desiredAttributesOrder, Object.keys(data));
7890

79-
let filteredElementAttributes = Object.keys(data)
91+
let filteredElementAttributes = sortedElementAttributeNames
8092
.map((key) => _generateAttributeDetails(classes, labels, key, data[key]))
8193
.filter((el) => el !== null);
8294
if (filteredElementAttributes.length === 0) {
@@ -89,10 +101,13 @@ const ElementData = (props) => {
89101
ElementData.propTypes = {
90102
data: PropTypes.object,
91103
labels: PropTypes.object,
104+
metadata: PropTypes.object,
105+
type: PropTypes.string,
92106
};
93107

94108
ElementData.defaultProps = {
95109
data: PropTypes.object,
110+
metadata: {},
96111
labels: {
97112
attributes: {},
98113
dictKey: 'Key',

0 commit comments

Comments
 (0)