generated from coulomb/repo-seed
Add graph orientation details
This commit is contained in:
@@ -137,6 +137,10 @@ def graph_explorer_page() -> str:
|
||||
<div id="detail-pills"></div>
|
||||
<ul id="detail-list" class="detail-list"></ul>
|
||||
</section>
|
||||
<section class="section">
|
||||
<p id="orientation-title" class="meta">Select a service, interface, dependency, or registered-only repo.</p>
|
||||
<ul id="orientation-list" class="detail-list"></ul>
|
||||
</section>
|
||||
<section class="section">
|
||||
<div class="button-row">
|
||||
<button type="button" data-override="show">Show</button>
|
||||
@@ -181,6 +185,8 @@ def graph_explorer_page() -> str:
|
||||
const detailSummary = document.getElementById("detail-summary");
|
||||
const detailPills = document.getElementById("detail-pills");
|
||||
const detailList = document.getElementById("detail-list");
|
||||
const orientationTitle = document.getElementById("orientation-title");
|
||||
const orientationList = document.getElementById("orientation-list");
|
||||
const legend = document.getElementById("legend");
|
||||
let cy = null;
|
||||
let selected = null;
|
||||
@@ -268,6 +274,8 @@ def graph_explorer_page() -> str:
|
||||
detailSummary.textContent = "No selection";
|
||||
detailPills.innerHTML = "";
|
||||
detailList.innerHTML = "";
|
||||
orientationTitle.textContent = "Select a service, interface, dependency, or registered-only repo.";
|
||||
orientationList.innerHTML = "";
|
||||
return;
|
||||
}
|
||||
const data = element.data();
|
||||
@@ -291,6 +299,78 @@ def graph_explorer_page() -> str:
|
||||
.filter(([, value]) => value)
|
||||
.map(([key, value]) => `<li><strong>${escapeHtml(key)}</strong> ${escapeHtml(value)}</li>`)
|
||||
.join("");
|
||||
renderOrientation(element);
|
||||
};
|
||||
|
||||
const renderOrientation = (element) => {
|
||||
const data = element.data();
|
||||
const rows = [];
|
||||
if (data.kind === "Repository" && data.lifecycle === "registered-only") {
|
||||
orientationTitle.textContent = "Onboarding gap";
|
||||
rows.push(["repo", data.repo], ["next", "sync Fabric declarations or register a graph snapshot"]);
|
||||
} else if (data.kind === "InterfaceDeclaration") {
|
||||
orientationTitle.textContent = "Interface consumers";
|
||||
cy.edges().filter((edge) =>
|
||||
edge.data("target") === data.id && edge.data("edgeType") === "uses_interface"
|
||||
).forEach((edge) => {
|
||||
const dependency = edge.data("source");
|
||||
const consumerEdge = cy.edges().filter((candidate) =>
|
||||
candidate.data("target") === dependency && candidate.data("edgeType") === "consumes"
|
||||
)[0];
|
||||
const consumerId = consumerEdge ? consumerEdge.data("source") : "";
|
||||
const consumer = consumerId ? cy.getElementById(consumerId).data("name") || consumerId : "unknown";
|
||||
rows.push(["consumer", `${consumer} -> ${dependency}`]);
|
||||
});
|
||||
if (rows.length === 0) rows.push(["consumer", "no accepted consumers in current graph"]);
|
||||
} else if (data.kind === "ServiceDeclaration") {
|
||||
orientationTitle.textContent = "Dependency path";
|
||||
cy.edges().filter((edge) =>
|
||||
edge.data("source") === data.id && edge.data("edgeType") === "consumes"
|
||||
).forEach((edge) => {
|
||||
const dependency = edge.data("target");
|
||||
const providerEdges = cy.edges().filter((candidate) =>
|
||||
candidate.data("source") === dependency && String(candidate.data("edgeType")).startsWith("binds:")
|
||||
);
|
||||
if (providerEdges.length === 0) {
|
||||
rows.push(["requires", `${dependency} -> unresolved`]);
|
||||
return;
|
||||
}
|
||||
providerEdges.forEach((providerEdge) => {
|
||||
const target = providerEdge.data("target");
|
||||
const provider = cy.getElementById(target).data("name") || target;
|
||||
rows.push(["requires", `${dependency} -> ${provider} (${providerEdge.data("edgeType")})`]);
|
||||
});
|
||||
});
|
||||
if (rows.length === 0) rows.push(["requires", "no declared dependencies"]);
|
||||
} else if (data.kind === "DependencyDeclaration") {
|
||||
orientationTitle.textContent = "Dependency binding";
|
||||
cy.edges().filter((edge) =>
|
||||
edge.data("source") === data.id && (
|
||||
String(edge.data("edgeType")).startsWith("binds:") ||
|
||||
edge.data("edgeType") === "uses_interface"
|
||||
)
|
||||
).forEach((edge) => {
|
||||
const target = edge.data("target");
|
||||
const targetName = cy.getElementById(target).data("name") || target;
|
||||
rows.push([edge.data("edgeType"), targetName]);
|
||||
});
|
||||
if (rows.length === 0) rows.push(["binding", "no provider binding in current graph"]);
|
||||
} else if (data.kind === "CapabilityDeclaration") {
|
||||
orientationTitle.textContent = "Provider surface";
|
||||
cy.edges().filter((edge) =>
|
||||
edge.data("target") === data.id && edge.data("edgeType") === "provides"
|
||||
).forEach((edge) => rows.push(["service", cy.getElementById(edge.data("source")).data("name") || edge.data("source")]));
|
||||
cy.edges().filter((edge) =>
|
||||
edge.data("source") === data.id && edge.data("edgeType") === "available_via"
|
||||
).forEach((edge) => rows.push(["interface", cy.getElementById(edge.data("target")).data("name") || edge.data("target")]));
|
||||
if (rows.length === 0) rows.push(["surface", "no provider surface in current graph"]);
|
||||
} else {
|
||||
orientationTitle.textContent = "Graph context";
|
||||
rows.push(["neighbors", `${element.neighborhood().nodes().length} connected nodes`]);
|
||||
}
|
||||
orientationList.innerHTML = rows
|
||||
.map(([key, value]) => `<li><strong>${escapeHtml(key)}</strong> ${escapeHtml(value)}</li>`)
|
||||
.join("");
|
||||
};
|
||||
|
||||
const applyFocus = () => {
|
||||
|
||||
Reference in New Issue
Block a user