Skip to content

Commit dea2f16

Browse files
committed
Use deep equal for atomFamily
1 parent af22b93 commit dea2f16

File tree

4 files changed

+218
-199
lines changed

4 files changed

+218
-199
lines changed

packages/graph-explorer/src/core/ConfigurationProvider/useConfiguration.ts

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
import type { ConfigurationContextProps } from "./types";
99
import { atomFamily } from "jotai/utils";
1010
import { atom, useAtomValue } from "jotai";
11+
import { isEqual } from "lodash";
1112

1213
const assembledConfigSelector = atom(get => {
1314
const configuration = get(mergedConfigurationSelector);
@@ -44,22 +45,25 @@ export const vertexTypeAttributesSelector = atomFamily(
4445
);
4546

4647
return attributesByNameMap.values().toArray();
47-
})
48+
}),
49+
isEqual
4850
);
4951

50-
export const edgeTypeAttributesSelector = atomFamily((edgeTypes: string[]) =>
51-
atom(get => {
52-
const attributesByNameMap = new Map(
53-
edgeTypes
54-
.values()
55-
.map(et => get(edgeTypeConfigSelector(et)))
56-
.filter(et => et != null)
57-
.flatMap(et => et.attributes)
58-
.map(attr => [attr.name, attr])
59-
);
60-
61-
return attributesByNameMap.values().toArray();
62-
})
52+
export const edgeTypeAttributesSelector = atomFamily(
53+
(edgeTypes: string[]) =>
54+
atom(get => {
55+
const attributesByNameMap = new Map(
56+
edgeTypes
57+
.values()
58+
.map(et => get(edgeTypeConfigSelector(et)))
59+
.filter(et => et != null)
60+
.flatMap(et => et.attributes)
61+
.map(attr => [attr.name, attr])
62+
);
63+
64+
return attributesByNameMap.values().toArray();
65+
}),
66+
isEqual
6367
);
6468

6569
export const vertexTypeConfigSelector = atomFamily((vertexType: string) =>
@@ -75,16 +79,18 @@ export function useVertexTypeConfig(vertexType: string) {
7579
return useAtomValue(vertexTypeConfigSelector(vertexType));
7680
}
7781

78-
const vertexTypeConfigsSelector = atomFamily((vertexTypes?: string[]) =>
79-
atom(get => {
80-
const allConfigs = get(allVertexTypeConfigsSelector);
81-
if (!vertexTypes) {
82-
return allConfigs.values().toArray();
83-
}
84-
return vertexTypes.map(
85-
type => allConfigs.get(type) ?? getDefaultVertexTypeConfig(type)
86-
);
87-
})
82+
const vertexTypeConfigsSelector = atomFamily(
83+
(vertexTypes?: string[]) =>
84+
atom(get => {
85+
const allConfigs = get(allVertexTypeConfigsSelector);
86+
if (!vertexTypes) {
87+
return allConfigs.values().toArray();
88+
}
89+
return vertexTypes.map(
90+
type => allConfigs.get(type) ?? getDefaultVertexTypeConfig(type)
91+
);
92+
}),
93+
isEqual
8894
);
8995

9096
/** Gets the matching vertex type configs or the generated default values. */
@@ -105,16 +111,18 @@ export function useEdgeTypeConfig(edgeType: string) {
105111
return useAtomValue(edgeTypeConfigSelector(edgeType));
106112
}
107113

108-
const edgeTypeConfigsSelector = atomFamily((edgeTypes?: string[]) =>
109-
atom(get => {
110-
const allConfigs = get(allEdgeTypeConfigsSelector);
111-
if (!edgeTypes) {
112-
return allConfigs.values().toArray();
113-
}
114-
return edgeTypes.map(
115-
type => allConfigs.get(type) ?? getDefaultEdgeTypeConfig(type)
116-
);
117-
})
114+
const edgeTypeConfigsSelector = atomFamily(
115+
(edgeTypes?: string[]) =>
116+
atom(get => {
117+
const allConfigs = get(allEdgeTypeConfigsSelector);
118+
if (!edgeTypes) {
119+
return allConfigs.values().toArray();
120+
}
121+
return edgeTypes.map(
122+
type => allConfigs.get(type) ?? getDefaultEdgeTypeConfig(type)
123+
);
124+
}),
125+
isEqual
118126
);
119127

120128
/** Gets the matching edge type configs or the generated default values. */

packages/graph-explorer/src/core/StateProvider/displayEdge.ts

Lines changed: 96 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
} from "@/utils";
2424
import { atom, useAtomValue } from "jotai";
2525
import { atomFamily } from "jotai/utils";
26+
import { isEqual } from "lodash";
2627

2728
/** Represents an edge's display information after all transformations have been applied. */
2829
export type DisplayEdge = {
@@ -70,101 +71,103 @@ export function useDisplayEdgeFromEdge(edge: Edge) {
7071
return useAtomValue(displayEdgeSelector(edge));
7172
}
7273

73-
const displayEdgeSelector = atomFamily((edge: Edge) =>
74-
atom(get => {
75-
const textTransform = get(textTransformSelector);
76-
const queryEngine = get(queryEngineSelector);
77-
const isSparql = queryEngine === "sparql";
78-
79-
// One type config used for shape, color, icon, etc.
80-
const typeConfig = get(displayEdgeTypeConfigSelector(edge.type));
81-
82-
// List all edge types for displaying
83-
const edgeTypes = [edge.type];
84-
const displayTypes = edgeTypes
85-
.map(type => get(displayEdgeTypeConfigSelector(type)).displayLabel)
86-
.join(", ");
87-
88-
// For SPARQL, display the edge type as the ID
89-
const rawStringId = String(getRawId(edge.id));
90-
const displayId = isSparql ? displayTypes : rawStringId;
91-
92-
const typeAttributes = get(edgeTypeAttributesSelector(edgeTypes));
93-
const sortedAttributes = getSortedDisplayAttributes(
94-
edge,
95-
typeAttributes,
96-
textTransform
97-
);
98-
99-
const sourceRawStringId = String(getRawId(edge.source));
100-
const targetRawStringId = String(getRawId(edge.target));
101-
const sourceDisplayId = isSparql
102-
? textTransform(sourceRawStringId)
103-
: sourceRawStringId;
104-
const targetDisplayId = isSparql
105-
? textTransform(targetRawStringId)
106-
: targetRawStringId;
107-
108-
const sourceDisplayTypes = edge.sourceTypes
109-
.map(
110-
type =>
111-
get(vertexTypeConfigSelector(type))?.displayLabel ||
112-
textTransform(type)
113-
)
114-
.join(", ");
115-
const targetDisplayTypes = edge.targetTypes
116-
.map(
117-
type =>
118-
get(vertexTypeConfigSelector(type))?.displayLabel ||
119-
textTransform(type)
120-
)
121-
.join(", ");
122-
123-
// Get the display name and description for the edge
124-
function getDisplayAttributeValueByName(name: string | undefined) {
125-
if (name === RESERVED_ID_PROPERTY) {
126-
return displayId;
127-
} else if (name === RESERVED_TYPES_PROPERTY) {
128-
return displayTypes;
129-
} else if (name) {
130-
return (
131-
sortedAttributes.find(attr => attr.name === name)?.displayValue ??
132-
MISSING_DISPLAY_VALUE
133-
);
74+
const displayEdgeSelector = atomFamily(
75+
(edge: Edge) =>
76+
atom(get => {
77+
const textTransform = get(textTransformSelector);
78+
const queryEngine = get(queryEngineSelector);
79+
const isSparql = queryEngine === "sparql";
80+
81+
// One type config used for shape, color, icon, etc.
82+
const typeConfig = get(displayEdgeTypeConfigSelector(edge.type));
83+
84+
// List all edge types for displaying
85+
const edgeTypes = [edge.type];
86+
const displayTypes = edgeTypes
87+
.map(type => get(displayEdgeTypeConfigSelector(type)).displayLabel)
88+
.join(", ");
89+
90+
// For SPARQL, display the edge type as the ID
91+
const rawStringId = String(getRawId(edge.id));
92+
const displayId = isSparql ? displayTypes : rawStringId;
93+
94+
const typeAttributes = get(edgeTypeAttributesSelector(edgeTypes));
95+
const sortedAttributes = getSortedDisplayAttributes(
96+
edge,
97+
typeAttributes,
98+
textTransform
99+
);
100+
101+
const sourceRawStringId = String(getRawId(edge.source));
102+
const targetRawStringId = String(getRawId(edge.target));
103+
const sourceDisplayId = isSparql
104+
? textTransform(sourceRawStringId)
105+
: sourceRawStringId;
106+
const targetDisplayId = isSparql
107+
? textTransform(targetRawStringId)
108+
: targetRawStringId;
109+
110+
const sourceDisplayTypes = edge.sourceTypes
111+
.map(
112+
type =>
113+
get(vertexTypeConfigSelector(type))?.displayLabel ||
114+
textTransform(type)
115+
)
116+
.join(", ");
117+
const targetDisplayTypes = edge.targetTypes
118+
.map(
119+
type =>
120+
get(vertexTypeConfigSelector(type))?.displayLabel ||
121+
textTransform(type)
122+
)
123+
.join(", ");
124+
125+
// Get the display name and description for the edge
126+
function getDisplayAttributeValueByName(name: string | undefined) {
127+
if (name === RESERVED_ID_PROPERTY) {
128+
return displayId;
129+
} else if (name === RESERVED_TYPES_PROPERTY) {
130+
return displayTypes;
131+
} else if (name) {
132+
return (
133+
sortedAttributes.find(attr => attr.name === name)?.displayValue ??
134+
MISSING_DISPLAY_VALUE
135+
);
136+
}
137+
138+
return MISSING_DISPLAY_VALUE;
134139
}
135140

136-
return MISSING_DISPLAY_VALUE;
137-
}
138-
139-
const displayName = getDisplayAttributeValueByName(
140-
typeConfig.displayNameAttribute
141-
);
142-
143-
const displayEdge: DisplayEdge = {
144-
entityType: "edge",
145-
id: edge.id,
146-
displayId,
147-
displayName,
148-
displayTypes,
149-
typeConfig,
150-
source: {
151-
id: edge.source,
152-
displayId: sourceDisplayId,
153-
displayTypes: sourceDisplayTypes,
154-
types: edge.sourceTypes,
155-
},
156-
target: {
157-
id: edge.target,
158-
displayId: targetDisplayId,
159-
displayTypes: targetDisplayTypes,
160-
types: edge.targetTypes,
161-
},
162-
attributes: sortedAttributes,
163-
// SPARQL does not have unique ID values for predicates, so the UI should hide them
164-
hasUniqueId: isSparql === false,
165-
};
166-
return displayEdge;
167-
})
141+
const displayName = getDisplayAttributeValueByName(
142+
typeConfig.displayNameAttribute
143+
);
144+
145+
const displayEdge: DisplayEdge = {
146+
entityType: "edge",
147+
id: edge.id,
148+
displayId,
149+
displayName,
150+
displayTypes,
151+
typeConfig,
152+
source: {
153+
id: edge.source,
154+
displayId: sourceDisplayId,
155+
displayTypes: sourceDisplayTypes,
156+
types: edge.sourceTypes,
157+
},
158+
target: {
159+
id: edge.target,
160+
displayId: targetDisplayId,
161+
displayTypes: targetDisplayTypes,
162+
types: edge.targetTypes,
163+
},
164+
attributes: sortedAttributes,
165+
// SPARQL does not have unique ID values for predicates, so the UI should hide them
166+
hasUniqueId: isSparql === false,
167+
};
168+
return displayEdge;
169+
}),
170+
isEqual
168171
);
169172

170173
const displayEdgesInCanvasSelector = atom(get => {

0 commit comments

Comments
 (0)