implement API key alert
This commit is contained in:
231
lightrag_webui/src/components/graph/PropertiesView.tsx
Normal file
231
lightrag_webui/src/components/graph/PropertiesView.tsx
Normal file
@@ -0,0 +1,231 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useGraphStore, RawNodeType, RawEdgeType } from '@/stores/graph'
|
||||
import Text from '@/components/ui/Text'
|
||||
import useLightragGraph from '@/hooks/useLightragGraph'
|
||||
|
||||
/**
|
||||
* Component that view properties of elements in graph.
|
||||
*/
|
||||
const PropertiesView = () => {
|
||||
const { getNode, getEdge } = useLightragGraph()
|
||||
const selectedNode = useGraphStore.use.selectedNode()
|
||||
const focusedNode = useGraphStore.use.focusedNode()
|
||||
const selectedEdge = useGraphStore.use.selectedEdge()
|
||||
const focusedEdge = useGraphStore.use.focusedEdge()
|
||||
|
||||
const [currentElement, setCurrentElement] = useState<NodeType | EdgeType | null>(null)
|
||||
const [currentType, setCurrentType] = useState<'node' | 'edge' | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
let type: 'node' | 'edge' | null = null
|
||||
let element: RawNodeType | RawEdgeType | null = null
|
||||
if (focusedNode) {
|
||||
type = 'node'
|
||||
element = getNode(focusedNode)
|
||||
} else if (selectedNode) {
|
||||
type = 'node'
|
||||
element = getNode(selectedNode)
|
||||
} else if (focusedEdge) {
|
||||
type = 'edge'
|
||||
element = getEdge(focusedEdge, true)
|
||||
} else if (selectedEdge) {
|
||||
type = 'edge'
|
||||
element = getEdge(selectedEdge, true)
|
||||
}
|
||||
|
||||
if (element) {
|
||||
if (type == 'node') {
|
||||
setCurrentElement(refineNodeProperties(element as any))
|
||||
} else {
|
||||
setCurrentElement(refineEdgeProperties(element as any))
|
||||
}
|
||||
setCurrentType(type)
|
||||
} else {
|
||||
setCurrentElement(null)
|
||||
setCurrentType(null)
|
||||
}
|
||||
}, [
|
||||
focusedNode,
|
||||
selectedNode,
|
||||
focusedEdge,
|
||||
selectedEdge,
|
||||
setCurrentElement,
|
||||
setCurrentType,
|
||||
getNode,
|
||||
getEdge
|
||||
])
|
||||
|
||||
if (!currentElement) {
|
||||
return <></>
|
||||
}
|
||||
return (
|
||||
<div className="bg-background/80 max-w-xs rounded-lg border-2 p-2 text-xs backdrop-blur-lg">
|
||||
{currentType == 'node' ? (
|
||||
<NodePropertiesView node={currentElement as any} />
|
||||
) : (
|
||||
<EdgePropertiesView edge={currentElement as any} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
type NodeType = RawNodeType & {
|
||||
relationships: {
|
||||
type: string
|
||||
id: string
|
||||
label: string
|
||||
}[]
|
||||
}
|
||||
|
||||
type EdgeType = RawEdgeType & {
|
||||
sourceNode?: RawNodeType
|
||||
targetNode?: RawNodeType
|
||||
}
|
||||
|
||||
const refineNodeProperties = (node: RawNodeType): NodeType => {
|
||||
const state = useGraphStore.getState()
|
||||
const relationships = []
|
||||
|
||||
if (state.sigmaGraph && state.rawGraph) {
|
||||
for (const edgeId of state.sigmaGraph.edges(node.id)) {
|
||||
const edge = state.rawGraph.getEdge(edgeId, true)
|
||||
if (edge) {
|
||||
const isTarget = node.id === edge.source
|
||||
const neighbourId = isTarget ? edge.target : edge.source
|
||||
const neighbour = state.rawGraph.getNode(neighbourId)
|
||||
if (neighbour) {
|
||||
relationships.push({
|
||||
type: isTarget ? 'Target' : 'Source',
|
||||
id: neighbourId,
|
||||
label: neighbour.labels.join(', ')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
...node,
|
||||
relationships
|
||||
}
|
||||
}
|
||||
|
||||
const refineEdgeProperties = (edge: RawEdgeType): EdgeType => {
|
||||
const state = useGraphStore.getState()
|
||||
const sourceNode = state.rawGraph?.getNode(edge.source)
|
||||
const targetNode = state.rawGraph?.getNode(edge.target)
|
||||
return {
|
||||
...edge,
|
||||
sourceNode,
|
||||
targetNode
|
||||
}
|
||||
}
|
||||
|
||||
const PropertyRow = ({
|
||||
name,
|
||||
value,
|
||||
onClick,
|
||||
tooltip
|
||||
}: {
|
||||
name: string
|
||||
value: any
|
||||
onClick?: () => void
|
||||
tooltip?: string
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<label className="text-primary/60 tracking-wide">{name}</label>:
|
||||
<Text
|
||||
className="hover:bg-primary/20 rounded p-1 text-ellipsis"
|
||||
tooltipClassName="max-w-80"
|
||||
text={value}
|
||||
tooltip={tooltip || value}
|
||||
side="left"
|
||||
onClick={onClick}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const NodePropertiesView = ({ node }: { node: NodeType }) => {
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-md pl-1 font-bold tracking-wide text-sky-300">Node</label>
|
||||
<div className="bg-primary/5 max-h-96 overflow-auto rounded p-1">
|
||||
<PropertyRow name={'Id'} value={node.id} />
|
||||
<PropertyRow
|
||||
name={'Labels'}
|
||||
value={node.labels.join(', ')}
|
||||
onClick={() => {
|
||||
useGraphStore.getState().setSelectedNode(node.id, true)
|
||||
}}
|
||||
/>
|
||||
<PropertyRow name={'Degree'} value={node.degree} />
|
||||
</div>
|
||||
<label className="text-md pl-1 font-bold tracking-wide text-yellow-400/90">Properties</label>
|
||||
<div className="bg-primary/5 max-h-96 overflow-auto rounded p-1">
|
||||
{Object.keys(node.properties)
|
||||
.sort()
|
||||
.map((name) => {
|
||||
return <PropertyRow key={name} name={name} value={node.properties[name]} />
|
||||
})}
|
||||
</div>
|
||||
{node.relationships.length > 0 && (
|
||||
<>
|
||||
<label className="text-md pl-1 font-bold tracking-wide text-teal-600/90">
|
||||
Relationships
|
||||
</label>
|
||||
<div className="bg-primary/5 max-h-96 overflow-auto rounded p-1">
|
||||
{node.relationships.map(({ type, id, label }) => {
|
||||
return (
|
||||
<PropertyRow
|
||||
key={id}
|
||||
name={type}
|
||||
value={label}
|
||||
onClick={() => {
|
||||
useGraphStore.getState().setSelectedNode(id, true)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const EdgePropertiesView = ({ edge }: { edge: EdgeType }) => {
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-md pl-1 font-bold tracking-wide text-teal-600">Relationship</label>
|
||||
<div className="bg-primary/5 max-h-96 overflow-auto rounded p-1">
|
||||
<PropertyRow name={'Id'} value={edge.id} />
|
||||
{edge.type && <PropertyRow name={'Type'} value={edge.type} />}
|
||||
<PropertyRow
|
||||
name={'Source'}
|
||||
value={edge.sourceNode ? edge.sourceNode.labels.join(', ') : edge.source}
|
||||
onClick={() => {
|
||||
useGraphStore.getState().setSelectedNode(edge.source, true)
|
||||
}}
|
||||
/>
|
||||
<PropertyRow
|
||||
name={'Target'}
|
||||
value={edge.targetNode ? edge.targetNode.labels.join(', ') : edge.target}
|
||||
onClick={() => {
|
||||
useGraphStore.getState().setSelectedNode(edge.target, true)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<label className="text-md pl-1 font-bold tracking-wide text-yellow-400/90">Properties</label>
|
||||
<div className="bg-primary/5 max-h-96 overflow-auto rounded p-1">
|
||||
{Object.keys(edge.properties)
|
||||
.sort()
|
||||
.map((name) => {
|
||||
return <PropertyRow key={name} name={name} value={edge.properties[name]} />
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PropertiesView
|
Reference in New Issue
Block a user