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
This commit is contained in:
2026-06-14 12:49:23 +04:00
parent b438e9a664
commit c28bd386ad
2 changed files with 46 additions and 4 deletions
+30
View File
@@ -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();
+16 -4
View File
@@ -20,7 +20,7 @@ const HUBS: Record<HubKey, HubSpec> = {
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<HubKey, HubSpec> = {
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<HubKey, HubSpec> = {
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<PublishedFlow[]> {
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<PublishedFlow[]> {
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,