Double-click on the user nodes to request more data from the API.
You can use a function like the one in the data tab to convert the output of a GraphQL API call into the ReGraph format.
The data source for this demo relies on the server at regraph.io and is not available locally.
See also
import React, { useEffect, useState } from "react";
import { createRoot } from "react-dom/client";
import { Chart } from "regraph";
import { convertToReGraphFormat } from "./data";
const API_URL = "/graphql/github";
const GET_REPO_QUERY = `
query getRepo($ownerUsername: String!, $repoName: String!) {
repo(ownerUsername: $ownerUsername, name: $repoName) {
type: __typename
id
name
commits(limit: 100) {
author {
type: __typename
... on GithubUser {
id
name: login
image: avatar_url
}
}
}
}
}
`;
const GET_USER_QUERY = `
query getUser($username: String!) {
user(username: $username) {
id
name: login
image: avatar_url
type: __typename
repos {
id
name
}
}
}
`;
async function fetchData(query, variables) {
const result = await fetch(API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({ query, variables }),
});
return result.json();
}
export const Demo = () => <Fetch />;
function Fetch() {
const [items, setItems] = useState({});
useEffect(() => {
fetchData(GET_REPO_QUERY, { ownerUsername: "facebook", repoName: "react" }).then((response) =>
setItems(convertToReGraphFormat(response))
);
}, []);
async function expand({ id, itemType }) {
if (itemType !== "node" || items[id].data.type !== "GithubUser") {
return;
}
const { name } = items[id].data;
const data = await fetchData(GET_USER_QUERY, { username: name });
setItems((currentItems) => ({ ...currentItems, ...convertToReGraphFormat(data) }));
}
return (
<Chart
animation={{ time: 1000 }}
items={items}
options={{
labels: { maxLength: 20 },
}}
onDoubleClick={expand}
/>
);
}
const root = createRoot(document.getElementById("regraph"));
root.render(<Demo />); import { style } from "@ci/theme/rg/js/storyStyles";
const colors = {
transparent: "rgba(0,0,0,0)",
red: style.colors.red2,
};
function makeNode({ name, image, type, color = style.primary1.color }) {
return {
color: image ? colors.transparent : color,
label: [
{
text: name,
...style.darkLabelLow,
fontSize: 10,
},
],
size: image ? 1.2 : 1,
cutout: true,
image,
data: { type, name },
};
}
function makeLink(id1, id2) {
return { id1, id2, width: 3 };
}
function convertRepo(repo) {
const { id: repoId, commits } = repo;
const items = { [repoId]: makeNode(repo) };
commits.forEach((commit) => {
const { author } = commit;
const { id: authorId, type } = author;
if (type !== "GithubUser") {
return;
}
items[authorId] = makeNode(author);
items[`${repoId}-${authorId}`] = makeLink(repoId, authorId);
});
return items;
}
function convertUser(user) {
const { id: userId, repos } = user;
const items = { [userId]: makeNode(user) };
repos.forEach((repo) => {
const { id: repoId } = repo;
items[repoId] = makeNode(repo);
items[`${userId}-${repoId}`] = makeLink(repoId, userId);
});
return items;
}
export function convertToReGraphFormat({ data }) {
if (data == null) {
return { error: makeNode({ name: "Could not load data", color: colors.red }) };
}
if (data.errors) {
return {
error: makeNode({
name: `Endpoint Error:\n${JSON.stringify(data.errors[0].message)}`,
color: colors.red,
}),
};
}
const { repo, user } = data;
if (repo != null) {
return convertRepo(repo);
}
if (user != null) {
return convertUser(user);
}
return {
error: makeNode({
name: "Data did not contain `repo` nor `user` field",
color: colors.red,
}),
};
} <!doctype html>
<html>
<body>
<div id="regraph" style="height: 100vh"></div>
<script type="module" src="./code.jsx"></script>
</body>
</html>