Skip to content

Graph enhancements #795

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Oct 10, 2024
Merged
4 changes: 2 additions & 2 deletions frontend/src/components/Graph/CheckboxSelection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const CheckboxSelection: React.FC<CheckboxSectionProps> = ({
graphType,
loading,
handleChange,
isgds,
isCommunity,
isDocChunk,
isEntity,
}) => (
Expand All @@ -29,7 +29,7 @@ const CheckboxSelection: React.FC<CheckboxSectionProps> = ({
onChange={() => handleChange('Entities')}
/>
)}
{isgds && (
{isCommunity && (
<Checkbox
checked={graphType.includes('Communities')}
label={graphLabels.community}
Expand Down
91 changes: 91 additions & 0 deletions frontend/src/components/Graph/GraphPropertiesPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { useMemo } from 'react';
import { ResizePanelDetails } from './ResizePanel';
import { BasicNode, BasicRelationship, GraphPropertiesPanelProps } from '../../types';
import { LegendsChip } from './LegendsChip';
import GraphPropertiesTable from './GraphPropertiesTable';


const sortAlphabetically = (a: string, b: string) => a.toLowerCase().localeCompare(b.toLowerCase());

const isNode = (item: BasicNode | BasicRelationship): item is BasicNode => {
return 'labels' in item && !('from' in item) && !('to' in item);
};

const GraphPropertiesPanel = ({ inspectedItem, newScheme }: GraphPropertiesPanelProps) => {
const inspectedItemType = isNode(inspectedItem) ? 'node' : 'relationship';
const properties = inspectedItemType === 'node'
? [
{
key: '<id>',
value: `${(inspectedItem as BasicNode).id}`,
type: 'String',
},
...Object.keys((inspectedItem as BasicNode).properties).map((key) => {
const value = (inspectedItem as BasicNode).properties[key];
return { key: key, value: value ?? '' };
}),
]
: [
{
key: '<element_id>',
value: `${(inspectedItem as BasicRelationship).id}`,
type: 'String',
},
{
key: '<from>',
value: `${(inspectedItem as BasicRelationship).from}`,
type: 'String',
},
{
key: '<to>',
value: `${(inspectedItem as BasicRelationship).to}`,
type: 'String',
},
{
key: '<caption>',
value: `${(inspectedItem as BasicRelationship).caption ?? ''}`,
type: 'String',
},
];
const labelsSorted = useMemo(() => {
if (isNode(inspectedItem)) {
return [...inspectedItem.labels].sort(sortAlphabetically);
}
return [];
}, [inspectedItem]);

return (
<>
<ResizePanelDetails.Title>
<h6 className="mr-auto">
{inspectedItemType === 'node' ? 'Node details' : 'Relationship details'}
</h6>
</ResizePanelDetails.Title>
<ResizePanelDetails.Content>
<div className="mx-4 flex flex-row flex-wrap gap-2">
{isNode(inspectedItem) ? (
labelsSorted.map((label) => (
<LegendsChip
type="node"
key={`node ${label}`}
label={label}
scheme={newScheme}
/>
))
) : (
<LegendsChip
type="relationship"
label={(inspectedItem as BasicRelationship).caption ?? ''}
key={`relationship ${(inspectedItem as BasicRelationship).id}`}
scheme={{}}
/>
)}
</div>
<div className="bg-palette-neutral-border-weak my-3 h-px w-full" />
<GraphPropertiesTable propertiesWithTypes={properties} />
</ResizePanelDetails.Content>
</>
);
}

export default GraphPropertiesPanel;
39 changes: 39 additions & 0 deletions frontend/src/components/Graph/GraphPropertiesTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { GraphLabel, Typography } from '@neo4j-ndl/react';
import { GraphPropertiesTableProps } from '../../types';

const GraphPropertiesTable = ({ propertiesWithTypes }: GraphPropertiesTableProps): JSX.Element => {
console.log('props', propertiesWithTypes);
return (
<div className="flex w-full flex-col break-all px-4 text-sm" data-testid="viz-details-pane-properties-table">
<div className="mb-1 flex flex-row pl-2">
<Typography variant="body-medium" className="basis-1/3">
Key
</Typography>
<Typography variant="body-medium">Value</Typography>
</div>
{propertiesWithTypes.map(({ key, value }, _) => {
return (
<div
key={key}
className="border-palette-neutral-border-weak flex border-t py-1 pl-2 first:border-none"
>
<div className="shrink basis-1/3 overflow-hidden whitespace-nowrap">
<GraphLabel
type="propertyKey"
tabIndex={-1}
className="pointer-events-none !max-w-full overflow-ellipsis"
>
{key}
</GraphLabel>
</div>
<div className={`ml-2 flex-1 whitespace-pre-wrap`}>
{value}
</div>
</div>
);
})}
</div>
);
};

export default GraphPropertiesTable;
Loading