fix(rnetwork): trust data renders for spaces without CRM token
- Restructure graph API so trust enrichment runs regardless of whether Twenty CRM token is configured (demo space has no CRM token) - Add missing listActiveDelegations import in encryptid server Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
7ecb6f0417
commit
5d019566f3
|
|
@ -199,95 +199,57 @@ routes.get("/api/graph", async (c) => {
|
||||||
return c.json(cached.data);
|
return c.json(cached.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Start with CRM data if available, otherwise demo placeholders
|
||||||
|
const nodes: Array<{ id: string; label: string; type: string; data: unknown }> = [];
|
||||||
|
const edges: Array<{ source: string; target: string; type: string; weight?: number }> = [];
|
||||||
|
const nodeIds = new Set<string>();
|
||||||
|
let isDemoData = false;
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return c.json({
|
isDemoData = true;
|
||||||
nodes: [
|
nodes.push(
|
||||||
{ id: "demo-1", label: "Alice", type: "person", data: {} },
|
{ id: "demo-1", label: "Alice", type: "person", data: {} },
|
||||||
{ id: "demo-2", label: "Bob", type: "person", data: {} },
|
{ id: "demo-2", label: "Bob", type: "person", data: {} },
|
||||||
{ id: "demo-3", label: "Acme Corp", type: "company", data: {} },
|
{ id: "demo-3", label: "Acme Corp", type: "company", data: {} },
|
||||||
],
|
);
|
||||||
edges: [
|
edges.push(
|
||||||
{ source: "demo-1", target: "demo-3", type: "works_at" },
|
{ source: "demo-1", target: "demo-3", type: "works_at" },
|
||||||
{ source: "demo-2", target: "demo-3", type: "works_at" },
|
{ source: "demo-2", target: "demo-3", type: "works_at" },
|
||||||
{ source: "demo-1", target: "demo-2", type: "contact_of" },
|
{ source: "demo-1", target: "demo-2", type: "contact_of" },
|
||||||
],
|
);
|
||||||
demo: true,
|
for (const n of nodes) nodeIds.add(n.id);
|
||||||
});
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const data = await twentyQuery(`{
|
const data = await twentyQuery(`{
|
||||||
people(first: 200) {
|
people(first: 200) {
|
||||||
edges {
|
edges { node { id name { firstName lastName } emails { primaryEmail } city company { id name } } }
|
||||||
node {
|
|
||||||
id
|
|
||||||
name { firstName lastName }
|
|
||||||
emails { primaryEmail }
|
|
||||||
city
|
|
||||||
company { id name }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
companies(first: 200) {
|
companies(first: 200) {
|
||||||
edges {
|
edges { node { id name domainName { primaryLinkUrl } employees address { addressCity addressCountry } } }
|
||||||
node {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
domainName { primaryLinkUrl }
|
|
||||||
employees
|
|
||||||
address { addressCity addressCountry }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
opportunities(first: 200) {
|
opportunities(first: 200) {
|
||||||
edges {
|
edges { node { id name stage amount { amountMicros currencyCode } company { id name } pointOfContact { id name { firstName lastName } } } }
|
||||||
node {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
stage
|
|
||||||
amount { amountMicros currencyCode }
|
|
||||||
company { id name }
|
|
||||||
pointOfContact { id name { firstName lastName } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}`, undefined, dataSpace);
|
}`, undefined, dataSpace);
|
||||||
|
|
||||||
if (!data) return c.json({ nodes: [], edges: [], error: "Twenty API error" });
|
if (data) {
|
||||||
|
|
||||||
const d = data as any;
|
const d = data as any;
|
||||||
const nodes: Array<{ id: string; label: string; type: string; data: unknown }> = [];
|
|
||||||
const edges: Array<{ source: string; target: string; type: string }> = [];
|
|
||||||
const nodeIds = new Set<string>();
|
|
||||||
|
|
||||||
// People → nodes
|
|
||||||
for (const { node: p } of d.people?.edges || []) {
|
for (const { node: p } of d.people?.edges || []) {
|
||||||
const label = [p.name?.firstName, p.name?.lastName].filter(Boolean).join(" ") || "Unknown";
|
const label = [p.name?.firstName, p.name?.lastName].filter(Boolean).join(" ") || "Unknown";
|
||||||
nodes.push({ id: p.id, label, type: "person", data: { email: p.emails?.primaryEmail, location: p.city } });
|
nodes.push({ id: p.id, label, type: "person", data: { email: p.emails?.primaryEmail, location: p.city } });
|
||||||
nodeIds.add(p.id);
|
nodeIds.add(p.id);
|
||||||
|
if (p.company?.id) edges.push({ source: p.id, target: p.company.id, type: "works_at" });
|
||||||
// Person → Company edge
|
|
||||||
if (p.company?.id) {
|
|
||||||
edges.push({ source: p.id, target: p.company.id, type: "works_at" });
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Companies → nodes
|
|
||||||
for (const { node: co } of d.companies?.edges || []) {
|
for (const { node: co } of d.companies?.edges || []) {
|
||||||
nodes.push({ id: co.id, label: co.name || "Unknown", type: "company", data: { domain: co.domainName?.primaryLinkUrl, employees: co.employees, location: co.address?.addressCity } });
|
nodes.push({ id: co.id, label: co.name || "Unknown", type: "company", data: { domain: co.domainName?.primaryLinkUrl, employees: co.employees, location: co.address?.addressCity } });
|
||||||
nodeIds.add(co.id);
|
nodeIds.add(co.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opportunities → nodes + edges
|
|
||||||
for (const { node: opp } of d.opportunities?.edges || []) {
|
for (const { node: opp } of d.opportunities?.edges || []) {
|
||||||
nodes.push({ id: opp.id, label: opp.name || "Opportunity", type: "opportunity", data: { stage: opp.stage, amount: opp.amount } });
|
nodes.push({ id: opp.id, label: opp.name || "Opportunity", type: "opportunity", data: { stage: opp.stage, amount: opp.amount } });
|
||||||
nodeIds.add(opp.id);
|
nodeIds.add(opp.id);
|
||||||
|
if (opp.company?.id && nodeIds.has(opp.company.id)) edges.push({ source: opp.id, target: opp.company.id, type: "involves" });
|
||||||
if (opp.company?.id && nodeIds.has(opp.company.id)) {
|
if (opp.pointOfContact?.id && nodeIds.has(opp.pointOfContact.id)) edges.push({ source: opp.pointOfContact.id, target: opp.id, type: "involved_in" });
|
||||||
edges.push({ source: opp.id, target: opp.company.id, type: "involves" });
|
|
||||||
}
|
}
|
||||||
if (opp.pointOfContact?.id && nodeIds.has(opp.pointOfContact.id)) {
|
|
||||||
edges.push({ source: opp.pointOfContact.id, target: opp.id, type: "involved_in" });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -342,7 +304,7 @@ routes.get("/api/graph", async (c) => {
|
||||||
} catch (e) { console.error("[Network] Trust enrichment error:", e); }
|
} catch (e) { console.error("[Network] Trust enrichment error:", e); }
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = { nodes, edges, demo: false };
|
const result = { nodes, edges, demo: isDemoData && !includeTrust };
|
||||||
graphCaches.set(cacheKey, { data: result, ts: Date.now() });
|
graphCaches.set(cacheKey, { data: result, ts: Date.now() });
|
||||||
c.header("Cache-Control", "public, max-age=60");
|
c.header("Cache-Control", "public, max-age=60");
|
||||||
return c.json(result);
|
return c.json(result);
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,7 @@ import {
|
||||||
getDelegation,
|
getDelegation,
|
||||||
listDelegationsFrom,
|
listDelegationsFrom,
|
||||||
listDelegationsTo,
|
listDelegationsTo,
|
||||||
|
listActiveDelegations,
|
||||||
updateDelegation,
|
updateDelegation,
|
||||||
revokeDelegation,
|
revokeDelegation,
|
||||||
getTotalDelegatedWeight,
|
getTotalDelegatedWeight,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue