Updated the calendar to improve opportunity display and navigation
This commit is contained in:
@@ -37,13 +37,11 @@ function setup(items = [synthetic()], localStorage) {
|
||||
getElementById: id => id === app.contracts.OPPORTUNITIES_TABLE_ID ? table : null };
|
||||
const app = loadApplication("content", { document, Intl, Date, localStorage });
|
||||
app.currentUser.allowsCrmActivities = () => true;
|
||||
const summaries = [];
|
||||
app.aiSummaryContent.requestGenerateAiSummary = number => summaries.push(number);
|
||||
app.opportunitiesTable.setOpportunitiesTableState({ status: "ready", items });
|
||||
const rows = () => table.children.find(child => child.tag === "tbody").children;
|
||||
const cell = (key, index = 0) => rows()[index].children.find(child => child.attributes["data-column"] === key);
|
||||
const headers = () => table.children.find(child => child.tag === "thead").children[0].children;
|
||||
return { app, table, rows, cell, headers, summaries };
|
||||
return { app, table, rows, cell, headers };
|
||||
}
|
||||
|
||||
test("Overview restores independent column and direction preferences across reloads and new data", () => {
|
||||
@@ -104,7 +102,7 @@ test("ramp months preserve zero and flag missing values beside the product count
|
||||
[[0], "0"], [[0, "3", null, " 6 ", 3], "0 | 3 | N/A | 6 | 3"]
|
||||
]) {
|
||||
h.app.productsContentState.opptyProductsByNumber.set("TEST-1", {
|
||||
fromCache: true, items: values.map(RampMonths_c => ({ RampMonths_c }))
|
||||
fromCache: true, items: values.map(RampMonths_c => ({ RampMonths_c, WorkloadName_c: "Synthetic workload" }))
|
||||
});
|
||||
h.app.opportunitiesTable.renderOpportunitiesTable();
|
||||
if (expected === null) assert.equal(badge(), undefined);
|
||||
@@ -121,12 +119,11 @@ test("ramp months preserve zero and flag missing values beside the product count
|
||||
}
|
||||
});
|
||||
|
||||
test("products remain expandable with AI summary and a ten-column detail row after sorting", () => {
|
||||
test("products remain expandable with a ten-column detail row after sorting", () => {
|
||||
const h = setup([synthetic("B", "Zulu"), synthetic("A", "Alpha")]);
|
||||
h.app.productsContentState.opptyProductsByNumber.set("B", { items: [{ ProdGroupName: "Cloud", RevnAmount: "10" }] });
|
||||
h.app.opportunitiesTable.renderOpportunitiesTable();
|
||||
findClass(h.cell("name"), "opportunities-extension-products-count").click();
|
||||
assert.deepEqual(h.summaries, ["B"]);
|
||||
assert.equal(h.rows()[1].className, "opportunities-extension-products-detail-row");
|
||||
assert.equal(h.rows()[1].children[0].colSpan, 10);
|
||||
assert.ok(findClass(h.rows()[1], "opportunities-extension-products-table"));
|
||||
@@ -136,7 +133,6 @@ test("products remain expandable with AI summary and a ten-column detail row aft
|
||||
assert.equal(h.rows()[2].children[0].colSpan, 10);
|
||||
findClass(h.cell("name", 1), "opportunities-extension-products-count").click();
|
||||
assert.equal(h.rows().length, 2);
|
||||
assert.deepEqual(h.summaries, ["B"], "collapsing does not generate another summary");
|
||||
});
|
||||
|
||||
test("product labels support multiple digits without changing their tooltip", () => {
|
||||
@@ -149,7 +145,7 @@ test("product labels support multiple digits without changing their tooltip", ()
|
||||
assert.equal(count.attributes["aria-label"], "12 products for opportunity TEST-1");
|
||||
});
|
||||
|
||||
test("opportunity projection alert is last and aggregates only divergent products", () => {
|
||||
test("opportunity projection alert follows the ramp and aggregates only divergent products", () => {
|
||||
const h = setup();
|
||||
const alert = () => findClass(h.cell("name"), "opportunities-extension-opportunity-projection-alert");
|
||||
const product = amount => ({ RampMonths_c: 0, workload: { adjustedACR: 1200, consumptionStartDate: "2026-10-01",
|
||||
@@ -159,17 +155,15 @@ test("opportunity projection alert is last and aggregates only divergent product
|
||||
h.app.opportunitiesTable.renderOpportunitiesTable();
|
||||
assert.equal(alert().title, "Consumption forecast differs in 2 products. View products.");
|
||||
const actions = findClass(h.cell("name"), "opportunities-extension-cell-actions");
|
||||
assert.equal(actions.children.at(-1), alert());
|
||||
assert.equal(actions.children[2], alert());
|
||||
assert.equal(alert().tag, "button");
|
||||
assert.equal(alert().attributes["aria-expanded"], "false");
|
||||
alert().click();
|
||||
assert.equal(h.rows()[1].className, "opportunities-extension-products-detail-row");
|
||||
assert.equal(alert().attributes["aria-expanded"], "true");
|
||||
assert.equal(walk(h.rows()[1]).filter(node => node.attributes["aria-haspopup"] === "dialog").length, 2);
|
||||
assert.deepEqual(h.summaries, ["TEST-1"]);
|
||||
alert().click();
|
||||
assert.equal(h.rows()[1].className, "opportunities-extension-products-detail-row", "clicking again never collapses the list");
|
||||
assert.deepEqual(h.summaries, ["TEST-1"], "already expanded list is not reloaded");
|
||||
h.app.productsContentState.opptyProductsByNumber.set("TEST-1", { items: [product(100), {}] });
|
||||
h.app.opportunitiesTable.renderOpportunitiesTable();
|
||||
assert.equal(alert(), undefined);
|
||||
@@ -200,7 +194,7 @@ test("CRM SR badge follows Ramp Months and remains visible while product data is
|
||||
await h.app.opportunityCrmServiceRequests.load("synthetic", h.app.opportunitiesQueryState.periodRequestVersion);
|
||||
h.app.opportunitiesTable.renderOpportunitiesTable();
|
||||
assert.equal(findClass(h.cell("name"), "opportunities-extension-crm-sr-badge").textContent, "0h");
|
||||
h.app.productsContentState.opptyProductsByNumber.set("TEST-1", { items: [{ RampMonths_c: 3 }] });
|
||||
h.app.productsContentState.opptyProductsByNumber.set("TEST-1", { items: [{ RampMonths_c: 3, WorkloadName_c: "Synthetic workload" }] });
|
||||
h.app.opportunitiesTable.renderOpportunitiesTable();
|
||||
const actions = h.cell("name").children[0].children[1];
|
||||
assert.deepEqual(actions.children.map(child => child.textContent), ["1", "3", "0h", "?"]);
|
||||
@@ -319,6 +313,35 @@ test("table styles reserve compact widths, prioritize Name/Customer and keep nes
|
||||
assert.ok(remaining > 0);
|
||||
assert.ok(remaining / 2 >= 12 + 114, "four customer controls fit after the left inset");
|
||||
}
|
||||
const allCss = ["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", "src/features/manage-time/styles.css", "src/features/products/ramp-projection.css", "src/features/org-chart/styles.css", "src/content/styles/tables.css"].map(read).join("\n");
|
||||
const allCss = ["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", "src/features/manage-time/styles.css", "src/features/products/ramp-projection.css", "src/features/org-chart/styles.css", "src/content/styles/tables.css", "src/content/styles/dialogs.css"].map(read).join("\n");
|
||||
assert.ok(composeScript("content").includes(`const redwoodStyles = ${JSON.stringify(allCss)};`));
|
||||
});
|
||||
|
||||
test("Booking replaces ramp only when every product has no Workload name", () => {
|
||||
const h = setup();
|
||||
for (const value of [undefined, null, "", " ", "-"]) {
|
||||
const badge = h.app.productsDetails.createProductsRampBadge({items:[{WorkloadName_c:value},{WorkloadName_c:" - "}]}, {});
|
||||
assert.equal(badge.textContent,"Booking");
|
||||
assert.equal(badge.tag,"span");
|
||||
assert.equal(badge.attributes["aria-haspopup"],undefined);
|
||||
}
|
||||
const mixed = h.app.productsDetails.createProductsRampBadge({items:[{WorkloadName_c:"-",RampMonths_c:2},{WorkloadName_c:"Migration",RampMonths_c:3}]},{});
|
||||
assert.equal(mixed.textContent,"2 | 3");
|
||||
assert.equal(mixed.tag,"button");
|
||||
});
|
||||
test("Booking and Workload filters use product names and compose with shared opportunity filtering", () => {
|
||||
const h = setup();
|
||||
const selected = h.app.opportunitiesFilterState.selectedProductTypes;
|
||||
const result = { items: [{ WorkloadName_c: "-" }, { WorkloadName_c: "" }] };
|
||||
h.app.productsContentState.opptyProductsByNumber.set("TEST-1", result);
|
||||
selected.delete("Workload");
|
||||
assert.equal(h.app.opportunitiesFilters.getSortedOpportunities().length, 1);
|
||||
selected.clear(); selected.add("Workload");
|
||||
assert.equal(h.app.opportunitiesFilters.getSortedOpportunities().length, 0);
|
||||
result.items[1].WorkloadName_c = "Migration";
|
||||
assert.equal(h.app.opportunitiesFilters.getSortedOpportunities().length, 1);
|
||||
selected.clear();
|
||||
assert.equal(h.app.opportunitiesFilters.getSortedOpportunities().length, 0);
|
||||
selected.add("Booking"); selected.add("Workload");
|
||||
assert.equal(h.app.opportunitiesFilters.getSortedOpportunities().length, 1);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user