Skip to content
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

Refactor to use display entities #698

Merged
merged 23 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 36 additions & 8 deletions packages/graph-explorer/src/core/StateProvider/displayEdge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { Edge, EdgeId, VertexId } from "@/@types/entities";
import { selector, selectorFamily, useRecoilValue } from "recoil";
import { textTransformSelector } from "@/hooks/useTextTransform";
import {
edgeTypeConfigSelector,
vertexTypeAttributesSelector,
vertexTypeConfigSelector,
} from "../ConfigurationProvider/useConfiguration";
Expand All @@ -16,17 +15,24 @@ import {
displayEdgeTypeConfigSelector,
} from "./displayTypeConfigs";
import { queryEngineSelector } from "../connector";
import {
MISSING_DISPLAY_VALUE,
RESERVED_ID_PROPERTY,
RESERVED_TYPES_PROPERTY,
} from "@/utils/constants";

/** Represents an edge's display information after all transformations have been applied. */
export type DisplayEdge = {
entityType: "edge";
id: EdgeId;
displayId: string | null;
displayId: string;
displayName: string;
displayTypes: string;
typeConfig: DisplayEdgeTypeConfig;
source: EdgeVertex;
target: EdgeVertex;
attributes: DisplayAttribute[];
hasUniqueId: boolean;
};

type EdgeVertex = {
Expand Down Expand Up @@ -82,13 +88,12 @@ const displayEdgeSelector = selectorFamily({
// List all edge types for displaying
const edgeTypes = [edge.type];
const displayTypes = edgeTypes
.map(
type =>
get(edgeTypeConfigSelector(type))?.displayLabel ||
textTransform(type)
)
.map(type => get(displayEdgeTypeConfigSelector(type)).displayLabel)
.join(", ");

// For SPARQL, display the edge type as the ID
const displayId = isSparql ? displayTypes : edge.id;

const typeAttributes = get(vertexTypeAttributesSelector(edgeTypes));
const sortedAttributes = getSortedDisplayAttributes(
edge,
Expand Down Expand Up @@ -120,10 +125,31 @@ const displayEdgeSelector = selectorFamily({
)
.join(", ");

// Get the display name and description for the vertex
function getDisplayAttributeValueByName(name: string | undefined) {
if (name === RESERVED_ID_PROPERTY) {
return displayId;
} else if (name === RESERVED_TYPES_PROPERTY) {
return displayTypes;
} else if (name) {
return (
sortedAttributes.find(attr => attr.name === name)?.displayValue ??
MISSING_DISPLAY_VALUE
);
}

return MISSING_DISPLAY_VALUE;
}

const displayName = getDisplayAttributeValueByName(
typeConfig.displayNameAttribute
);

const displayEdge: DisplayEdge = {
entityType: "edge",
id: edge.id,
displayId: isSparql ? null : edge.id,
displayId,
displayName,
displayTypes,
typeConfig,
source: {
Expand All @@ -137,6 +163,8 @@ const displayEdgeSelector = selectorFamily({
displayTypes: targetDisplayTypes,
},
attributes: sortedAttributes,
// SPARQL does not have unique ID values for predicates, so the UI should hide them
hasUniqueId: isSparql === false,
};
return displayEdge;
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
} from "../ConfigurationProvider";
import { ArrowStyle, LineStyle } from "./userPreferences";
import { sanitizeText } from "@/utils";
import { RESERVED_TYPES_PROPERTY } from "@/utils/constants";

export type DisplayVertexStyle = {
color: string;
Expand Down Expand Up @@ -47,6 +48,7 @@ export type DisplayEdgeTypeConfig = {
displayLabel: string;
attributes: DisplayConfigAttribute[];
style: DisplayEdgeStyle;
displayNameAttribute: string;
};

export type DisplayConfigAttribute = {
Expand Down Expand Up @@ -195,6 +197,8 @@ export function mapToDisplayEdgeTypeConfig(
displayLabel,
attributes,
style,
displayNameAttribute:
typeConfig.displayNameAttribute || RESERVED_TYPES_PROPERTY,
};
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const EdgeDetail = ({ edge }: EdgeDetailProps) => {
</div>
<div className={"content"}>
<div className={"title"}>{edge.displayTypes}</div>
{edge.displayId && <div>{edge.displayId}</div>}
{edge.hasUniqueId ? <div>{edge.displayId}</div> : null}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious why this check is preferred to the original check for displayId? Is there still value in setting the displayId on the EdgeDetail for SPARQL if it's not shown?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I honestly don't remember why I made that change. If I had to guess it was to make sure no properties were optional on the model. But that's not a good enough reason.

I reverted the change.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I take it all back. After reverting the change and seeing some errors I now remember why. It is about optionality, but specifically around the logic to get the "display name" value. Since displayId is an option on non-sparql databases if it was optional it would require display name to be optional, which I do not want.

</div>
</div>
<div className={cn("header", "source-vertex")}>
Expand Down
22 changes: 10 additions & 12 deletions packages/graph-explorer/src/modules/GraphViewer/useGraphStyles.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import Color from "color";
import { useEffect, useState } from "react";
import { Edge } from "@/types/entities";
import { EdgeId } from "@/types/entities";
import type { GraphProps } from "@/components";
import useTextTransform from "@/hooks/useTextTransform";
import { renderNode } from "./renderNode";
import {
useEdgeTypeConfigs,
useVertexTypeConfigs,
} from "@/core/ConfigurationProvider/useConfiguration";
import { useDisplayEdgesInCanvas } from "@/core";
import { MISSING_DISPLAY_VALUE } from "@/utils/constants";

const LINE_PATTERN = {
solid: undefined,
Expand All @@ -20,6 +22,7 @@ const useGraphStyles = () => {
const etConfigs = useEdgeTypeConfigs();
const textTransform = useTextTransform();
const [styles, setStyles] = useState<GraphProps["styles"]>({});
const displayEdges = useDisplayEdgesInCanvas();

useEffect(() => {
(async () => {
Expand Down Expand Up @@ -61,16 +64,11 @@ const useGraphStyles = () => {

styles[`edge[type="${et}"]`] = {
label: (el: cytoscape.EdgeSingular) => {
const edgeData = el.data() as Edge;

let currentLabel = etConfig.displayLabel || label;

if (etConfig.displayNameAttribute) {
const attr = edgeData.attributes[etConfig.displayNameAttribute];
currentLabel = attr != null ? String(attr) : currentLabel;
}

return currentLabel;
const edgeId = el.id() as EdgeId;
const displayEdge = displayEdges.get(edgeId);
return displayEdge
? displayEdge.displayName
: MISSING_DISPLAY_VALUE;
},
color: new Color(etConfig?.labelColor || "#17457b").isDark()
? "#FFFFFF"
Expand Down Expand Up @@ -98,7 +96,7 @@ const useGraphStyles = () => {

setStyles(styles);
})();
}, [etConfigs, textTransform, vtConfigs]);
}, [displayEdges, etConfigs, textTransform, vtConfigs]);

return styles;
};
Expand Down