in packages/graph-explorer/src/hooks/useExpandNode.tsx [36:164]
export default function useExpandNode() {
const queryClient = useQueryClient();
const explorer = useExplorer();
const addToGraph = useAddToGraph();
const getFetchedNeighbors = useFetchedNeighborsCallback();
const { enqueueNotification, clearNotification } = useNotification();
const remoteLogger = useAtomValue(loggerSelector);
const { isPending, mutate } = useMutation({
mutationFn: async (
expandNodeRequest: ExpandNodeRequest
): Promise<NeighborsResponse | null> => {
// Get neighbors that have already been added so they can be excluded
const excludedNeighbors = getFetchedNeighbors(expandNodeRequest.vertexId);
// Calculate the expansion limit based on the connection limit and the request limit
const limit = (() => {
if (!explorer.connection.nodeExpansionLimit) {
return expandNodeRequest.filters?.limit;
}
if (!expandNodeRequest.filters?.limit) {
return explorer.connection.nodeExpansionLimit;
}
// If both exists then use the smaller of the two
return Math.min(
explorer.connection.nodeExpansionLimit,
expandNodeRequest.filters.limit
);
})();
// Perform the query when a request exists
const request: NeighborsRequest | null = expandNodeRequest && {
vertexId: expandNodeRequest.vertexId,
vertexTypes: expandNodeRequest.vertexTypes,
excludedVertices: excludedNeighbors,
...expandNodeRequest.filters,
limit,
};
if (!request) {
return null;
}
return await explorer.fetchNeighbors(request);
},
onSuccess: async data => {
if (!data) {
return;
}
// Update the vertex and edge details caches
updateVertexDetailsCache(explorer, queryClient, data.vertices);
updateEdgeDetailsCache(explorer, queryClient, data.edges);
// Update nodes and edges in the graph
await addToGraph(data);
},
onError: error => {
remoteLogger.error(`Failed to expand node: ${error.message}`);
const displayError = createDisplayError(error);
// Notify the user of the error
enqueueNotification({
title: "Expanding Node Failed",
message: displayError.message,
type: "error",
});
},
});
// Show a loading message to the user
useEffect(() => {
if (!isPending) {
return;
}
const notificationId = enqueueNotification({
title: "Expanding Node",
message: "Expanding neighbors for the given node.",
stackable: true,
});
return () => clearNotification(notificationId);
}, [clearNotification, enqueueNotification, isPending]);
// Build the expand node callback
const neighborCallback = useNeighborsCallback();
const expandNode = useCallback(
async (
vertexId: VertexId,
vertexTypes: Vertex["types"],
filters?: ExpandNodeFilters
) => {
const neighbor = await neighborCallback(vertexId);
if (!neighbor) {
enqueueNotification({
title: "No neighbor information available",
message: "This vertex's neighbor data has not been retrieved yet.",
});
return;
}
const request: ExpandNodeRequest = {
vertexId,
vertexTypes,
filters,
};
// Only allow expansion if we are not busy with another expansion
if (isPending) {
return;
}
if (neighbor.unfetched <= 0) {
enqueueNotification({
title: "No more neighbors",
message:
"This vertex has been fully expanded or it does not have connections",
});
return;
}
mutate(request);
},
[enqueueNotification, isPending, mutate, neighborCallback]
);
return {
expandNode,
isPending,
};
}