From c28bd386ade0618c87a7e8a3d259806e296c6fce Mon Sep 17 00:00:00 2001 From: shad Date: Sun, 14 Jun 2026 12:49:23 +0400 Subject: [PATCH] fix(hubs): exclude chat/wizard-step flows and tighten hub regexes - loadPublishedFlows: drop source_context EA2_CHAT_THREAD/_MSG and EA2_WIZARD_STEP so chat threads and wizard fragments don't leak into the business catalogue - procurement match: require word boundaries on PO/P2P; add requisition/ invoice - HR match: word-bound HR; add offboard/employee/payroll - IT match: word-bound IT; explicit access/laptop/password tokens; drop the over-broad bare 'service' and 'account' tokens --- qa/audit_hubs.mjs | 30 ++++++++++++++++++++++++++++++ src/scenes/Hub.tsx | 20 ++++++++++++++++---- 2 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 qa/audit_hubs.mjs diff --git a/qa/audit_hubs.mjs b/qa/audit_hubs.mjs new file mode 100644 index 0000000..79b117c --- /dev/null +++ b/qa/audit_hubs.mjs @@ -0,0 +1,30 @@ +import { chromium } from "playwright"; + +const URL = "https://canvas.flow-master.ai/"; +const args = ["--host-resolver-rules=MAP canvas.flow-master.ai 65.21.71.186", "--ignore-certificate-errors"]; + +const b = await chromium.launch({ headless: true, args }); +const p = await (await b.newContext({ viewport: { width: 1440, height: 900 } })).newPage(); + +await p.goto(URL, { waitUntil: "networkidle" }); +await p.waitForTimeout(800); +await p.locator(".persona-chip", { hasText: /Mariana/ }).click(); +await p.locator(".dev-login-btn").click(); +await p.waitForTimeout(2500); + +const chips = await p.locator(".hub-chip").allTextContents(); +console.log("[landing] hub chips:", chips); + +for (const hub of ["Procurement Hub", "People Hub", "IT Hub"]) { + await p.locator(".hub-chip", { hasText: hub }).click(); + await p.waitForTimeout(2200); + const title = await p.locator(".mc-hero-title").first().textContent(); + const quickActions = await p.locator(".hub-quick-title").allTextContents(); + const flowCards = await p.locator(".hub-flow-title").allTextContents(); + console.log(`\n[${hub}] title=${title?.trim()} | quick=${quickActions.length} | flows=${flowCards.length}`); + console.log(` flows visible (top 3): ${flowCards.slice(0, 3).join(" | ")}`); + // navigate back to landing + await p.locator(".tab", { hasText: /Home/ }).first().click().catch(() => {}); + await p.waitForTimeout(700); +} +await b.close(); diff --git a/src/scenes/Hub.tsx b/src/scenes/Hub.tsx index f8d6cac..bb1050d 100644 --- a/src/scenes/Hub.tsx +++ b/src/scenes/Hub.tsx @@ -20,7 +20,7 @@ const HUBS: Record = { eyebrow: "Purchase requests, vendor approvals, three-way match", intro: "Everything a store manager needs to buy something — from a laptop to a forklift — and watch it move through the approval chain.", - match: /procure|purchase|vendor|po\b|payment/i, + match: /procure|purchase|vendor|\bpo\b|\bp2p\b|requisition|payment|invoice/i, quickActions: [ { label: "Request a new laptop", subject: "store-204-laptop", processHint: "procurement" }, { label: "Submit a quote for review", subject: "vendor-quote-Q3", processHint: "procurement" }, @@ -31,7 +31,7 @@ const HUBS: Record = { eyebrow: "Hiring, onboarding, leave, performance", intro: "All people movements run here. Start an onboarding for a new hire, file a leave request, or kick off a review cycle.", - match: /onboard|leave|people|hr\b|hiring|payroll/i, + match: /onboard|offboard|leave|\bhr\b|hiring|payroll|employee|people operations/i, quickActions: [ { label: "Onboard a new hire", subject: "new-hire-2026Q3", processHint: "onboard" }, { label: "Request annual leave", subject: "leave-7d-may", processHint: "leave" }, @@ -42,7 +42,7 @@ const HUBS: Record = { eyebrow: "Tickets, access requests, incident response", intro: "When something breaks, request access, or you need a new account — file it here and route it to the right on-call.", - match: /it\b|ticket|incident|access|account|service/i, + match: /\bit\b|ticket|incident|service operations|access request|sap access|laptop request|hardware request|software request|password reset|account provisioning/i, quickActions: [ { label: "Open an incident", subject: "incident-store-204", processHint: "service" }, { label: "Request system access", subject: "access-sap-RW", processHint: "access" }, @@ -57,6 +57,12 @@ interface PublishedFlow { name?: string; } +const NON_BUSINESS_SOURCE_CONTEXTS = new Set([ + "EA2_CHAT_THREAD", + "EA2_CHAT_MSG", + "EA2_WIZARD_STEP", +]); + async function loadPublishedFlows(): Promise { const res = await fetch(`${api.config.baseUrl}/api/ea2/flow/processes?limit=200`, { headers: { Authorization: `Bearer ${sessionStorage.getItem("fm.mc.token.v1")}` }, @@ -64,7 +70,13 @@ async function loadPublishedFlows(): Promise { if (!res.ok) throw new Error(`processes ${res.status}`); const body = await res.json(); return ((body?.items || []) as any[]) - .filter((it) => it.status === "published" && it.kind === "definition" && it.display_name) + .filter( + (it) => + it.status === "published" && + it.kind === "definition" && + it.display_name && + !NON_BUSINESS_SOURCE_CONTEXTS.has(it.source_context) + ) .map((it) => ({ _key: it._key, display_name: it.display_name,