diff --git a/src/charts/CytoViz/CytoViz.js b/src/charts/CytoViz/CytoViz.js
index 10f0a7cd..22cf5b93 100644
--- a/src/charts/CytoViz/CytoViz.js
+++ b/src/charts/CytoViz/CytoViz.js
@@ -54,6 +54,7 @@ export const CytoViz = (props) => {
cytoscapeStylesheet,
defaultSettings,
elements,
+ elementsMetadata,
error,
extraLayouts,
getElementDetails,
@@ -81,7 +82,17 @@ export const CytoViz = (props) => {
let getElementDetailsCallback = getElementDetails;
if (!getElementDetailsCallback) {
// eslint-disable-next-line react/display-name
- getElementDetailsCallback = (element) => ;
+ getElementDetailsCallback = (element) => {
+ const elementType = element.classes && element.classes()?.[0];
+ return (
+
+ );
+ };
getElementDetailsCallback.displayName = 'ElementData';
}
@@ -714,6 +725,18 @@ CytoViz.propTypes = {
* Array of cytoscape elements to display
*/
elements: PropTypes.array.isRequired,
+ /**
+ * Optional array of metadata for cytoscape elements. Currently, it only takes an attributesOrder property to force
+ * the order of attributes when entity details are displayed.
+ * Expected format example:
+ * {
+ * attributesOrder: {
+ * nodes: { nodeType1: ['someImportantAttribute', 'attribute1', 'attribute2', 'attribute3'] },
+ * edges: { edgeType1: ['attributeA', 'attributeB']}},
+ * }
+ * }
+ */
+ elementsMetadata: PropTypes.object,
/**
* Object of extra layouts to register in cytoscape. The keys of this object must be the layout names, and the values
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 = {
showStats: false,
spacingFactor: 1,
},
+ elementsMetadata: {},
extraLayouts: {},
groups: {},
labels: DEFAULT_LABELS,
diff --git a/src/charts/CytoViz/components/ElementData/ElementData.js b/src/charts/CytoViz/components/ElementData/ElementData.js
index 8117e2fe..87c4c020 100644
--- a/src/charts/CytoViz/components/ElementData/ElementData.js
+++ b/src/charts/CytoViz/components/ElementData/ElementData.js
@@ -69,14 +69,26 @@ const _generateAttributeDetails = (classes, labels, attributeName, attributeValu
}
};
+const getSortedAttributeNames = (expectedKeys, allKeys) => {
+ // Start with expected keys in desired order
+ const sortedKeys = expectedKeys.filter((key) => allKeys.includes(key));
+ allKeys.filter((key) => !expectedKeys.includes(key)).forEach((key) => sortedKeys.push(key)); // Add unknown keys
+ return sortedKeys;
+};
+
const ElementData = (props) => {
const classes = useStyles();
- const { data, labels } = props;
- if (!data) {
- return labels.noData;
- }
+ const { data, labels, metadata, type } = props;
+ if (!data) return labels.noData;
+
+ const attributesOrderConfig = metadata?.attributesOrder;
+ const desiredAttributesOrder = type && (attributesOrderConfig?.nodes?.[type] ?? attributesOrderConfig?.edges?.[type]);
+
+ let sortedElementAttributeNames = Object.keys(data);
+ if (desiredAttributesOrder != null)
+ sortedElementAttributeNames = getSortedAttributeNames(desiredAttributesOrder, Object.keys(data));
- let filteredElementAttributes = Object.keys(data)
+ let filteredElementAttributes = sortedElementAttributeNames
.map((key) => _generateAttributeDetails(classes, labels, key, data[key]))
.filter((el) => el !== null);
if (filteredElementAttributes.length === 0) {
@@ -89,10 +101,13 @@ const ElementData = (props) => {
ElementData.propTypes = {
data: PropTypes.object,
labels: PropTypes.object,
+ metadata: PropTypes.object,
+ type: PropTypes.string,
};
ElementData.defaultProps = {
data: PropTypes.object,
+ metadata: {},
labels: {
attributes: {},
dictKey: 'Key',