Implemented the Organization Chart feature to create customer organizational

This commit is contained in:
2026-10-26 18:15:32 -03:00
parent bf48ed1dcb
commit 3229ce9c41
41 changed files with 4099 additions and 63 deletions

View File

@@ -20,6 +20,18 @@ function fixture() {
return { ...dom, app, add, nodes, tab, ids, select };
}
test("debug renders opportunities lookup before HTTP headers exist and preserves failed resolution details", () => {
const h = fixture();
const entry = h.app.debugContentLog.logRequestStart({ name: "requestOpportunitiesByContact", method: "GET", url: "https://example.invalid/opportunities",
metadata: { httpRequestSent: false, phase: "Resolving contact PartyNumber" } });
h.app.debugContentLog.logRequestFailure(entry, "Contact PartyNumber unavailable. HTTP request was not sent.");
assert.ok(h.nodes().some(node => node.textContent === "Debug Requests"));
assert.equal(h.ids().length, 1);
assert.equal(h.app.debugContentLog.formatHeaderBlock(undefined), "(none)");
assert.equal(h.app.debugContentLog.formatMetadataBlock(null), "(none)");
assert.match(h.app.debugContentLog.formatMetadataBlock({httpRequestSent:false, offset:0}), /httpRequestSent: false\noffset: 0/);
});
test("catalog and identity secrets are revealed exactly by the eye button and hidden again", () => {
const h = fixture();
const body = JSON.stringify({ result: "catalog-exact-secret", detail: "Preserved" });
@@ -89,7 +101,8 @@ test("request categories cover every current family and unknown requests stay vi
for (const [name, category] of Object.entries({
requestTokenRelay: "authentication", requestTokenRelaySalesCommon: "authentication",
requestConsumerTokenService: "authentication", requestCustomerTokenService: "authentication",
requestOpportunities: "opportunities", requestOpportunitiesSavedSearch: "opportunities", requestOpptyProducts: "products", requestGenerateAiSummary: "ai",
requestOpportunities: "opportunities", requestOpportunitiesSavedSearch: "opportunities", requestOpportunitiesByContact: "opportunities", requestOpptyProducts: "products", requestGenerateAiSummary: "ai",
requestQueryAccountContact: "contacts", requestPersistContact: "contacts",
requestAccountSummary: "consumption", requestAccountPlans: "consumption",
requestInstallBase: "installBase", requestCustomerServiceRequest: "serviceRequests", requestSRInfo: "serviceRequests",
requestConsumptionPlanDetail: "consumption",
@@ -177,8 +190,11 @@ test("full-page debug opens with close focus, closes via Escape/button/shortcut
trigger.isConnected = true;
trigger.focus();
h.panel.hidden = true;
h.panel.inert = true;
h.app.debugContentView.toggleDebugPanel();
assert.equal(h.panel.hidden, false);
assert.equal(h.panel.inert, false);
assert.ok(h.modal.children.includes(h.panel), "debug escapes nested modal containers");
assert.equal(h.panel.getAttribute("role"), "dialog");
assert.equal(h.document.activeElement.getAttribute("aria-label"), "Close debug");
h.add("p", "requestOpptyProducts", 1, "pending");
@@ -292,7 +308,7 @@ test("full-page debug CSS defines responsive bounds and readable semantic colors
test("scoped debug styles are packaged after the unchanged main stylesheet", () => {
const root = path.join(__dirname, "..");
const css = ["src/content/styles/redwood.css", "src/features/debug/styles.css", "src/features/opportunities/styles.css", "src/features/install-base/styles.css", "src/features/service-requests/styles.css", "src/features/consumption/plan-detail.css", "src/features/ratecard/styles.css", "src/features/opportunities/customer-table-search.css", "src/features/opportunities/calendar.css"]
.concat("src/features/manage-time/styles.css", "src/features/products/ramp-projection.css")
.concat("src/features/manage-time/styles.css", "src/features/products/ramp-projection.css", "src/features/org-chart/styles.css")
.map(file => fs.readFileSync(path.join(root, file), "utf8")).join("\n");
assert.ok(composeScript("content").includes(`const redwoodStyles = ${JSON.stringify(css)};`));
assert.ok(!composeScript("background").includes("opportunities-extension-debug-tabs"));