mirror of
https://github.com/hanzoai/calendar.git
synced 2026-10-30 14:46:43 +00:00
* feat: Add routing trace presenters Add domain-specific presenters (SalesforceRoutingTracePresenter, RoutingFormTracePresenter) that format trace steps into human-readable strings, and a core RoutingTracePresenter that delegates to them based on step domain. Includes unit tests for all presenters. Co-Authored-By: Claude Opus 4.5 <[email protected]> * feat: Add findByBookingUid to RoutingTraceRepository Add method to look up a routing trace by booking UID, needed by the routing trace presenter tRPC endpoint. Co-Authored-By: Claude Opus 4.5 <[email protected]> * feat: Add getRoutingTrace tRPC endpoint Expose routing trace data for a booking via viewer.bookings.getRoutingTrace. Tries the permanent RoutingTrace first (round robin bookings), then falls back to PendingRoutingTrace via the booking's form response relation. Co-Authored-By: Claude Opus 4.5 <[email protected]> * feat: Add routing trace side sheet to booking list item Add a route icon button on booking list items that came from routing forms. Clicking it opens a side sheet displaying the full routing trace as human-readable steps. Adds RoutingTraceSheet component, store state, and translation key. Co-Authored-By: Claude Opus 4.5 <[email protected]> * refactor: Move routing trace action to dropdown menu Move the routing trace button from a standalone icon on the booking list item into the actions dropdown menu alongside "Report wrong assignment". The RoutingTraceSheet is now rendered from BookingActionsDropdown. Co-Authored-By: Claude Opus 4.5 <[email protected]> * fix: Improve routing trace UI and handle unnamed routes - Redesign RoutingTraceSheet with vertical timeline layout, domain badges, skeleton loading state, and millisecond timestamps - Use Salesforce app-store icon for Salesforce steps - Fall back to "Unnamed route" when route name is missing or matches route ID - Fix dropdown menu icon to git-merge (valid icon, unique in menu) Co-Authored-By: Claude Opus 4.5 <[email protected]> * test: Add tests for getRoutingTrace handler and findByBookingUid repository method Co-Authored-By: [email protected] <[email protected]> * Abstract functions * Fix build error * Add permission check * fix: Update getRoutingTrace tests to include ctx and mock BookingAccessService Co-Authored-By: [email protected] <[email protected]> --------- Co-authored-by: Claude Opus 4.5 <[email protected]> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
52 lines
2.9 KiB
TypeScript
52 lines
2.9 KiB
TypeScript
import type { RoutingStep } from "../repositories/RoutingTraceRepository.interface";
|
|
|
|
export class SalesforceRoutingTracePresenter {
|
|
static present(step: RoutingStep): string {
|
|
const d = step.data;
|
|
switch (step.step) {
|
|
case "searching_by_website_value":
|
|
return `Searching for Salesforce account by website matching domain "${d.emailDomain}"`;
|
|
case "account_found_by_website":
|
|
return `Account found by website "${d.website}" (Account ID: ${d.accountId})`;
|
|
case "searching_by_contact_email_domain":
|
|
return `Searching contacts with email domain "${d.emailDomain}" (${d.contactCount} contacts found)`;
|
|
case "account_selected_by_most_contacts":
|
|
return `Account selected with most contacts: ${d.accountId} (${d.contactCount} contacts)`;
|
|
case "no_account_found":
|
|
return `No account found for ${d.email}: ${d.reason}`;
|
|
case "lookup_field_query":
|
|
return `Querying lookup field "${d.fieldName}" on ${d.salesforceObject}${d.accountId ? ` (Account: ${d.accountId})` : ""}`;
|
|
case "user_query_from_lookup_field":
|
|
return `Lookup field resolved to user ${d.userEmail} (User ID: ${d.lookupFieldUserId})`;
|
|
case "contact_owner_lookup":
|
|
return `Contact owner lookup: ${d.ownerEmail} (Contact: ${d.contactId})`;
|
|
case "lead_owner_lookup":
|
|
return `Lead owner lookup: ${d.ownerEmail} (Lead: ${d.leadId})`;
|
|
case "account_owner_lookup":
|
|
return `Account owner lookup: ${d.ownerEmail} (Account: ${d.accountId})`;
|
|
case "owner_validated":
|
|
return `Owner ${d.ownerEmail} validated as team member: ${d.isTeamMember}`;
|
|
case "owner_lookup_skipped":
|
|
return `Owner lookup skipped: ${d.reason}${d.email ? ` (${d.email})` : ""}`;
|
|
case "contact_owner_check_skipped":
|
|
return `Contact owner check skipped: ${d.reason}`;
|
|
case "graphql_query_initiated":
|
|
return `GraphQL account resolution initiated for ${d.email} (domain: ${d.emailDomain})`;
|
|
case "graphql_existing_contact_found":
|
|
return `Existing contact found via GraphQL: ${d.contactId} (Account: ${d.accountId}, Owner: ${d.ownerEmail})`;
|
|
case "graphql_account_found_by_website":
|
|
return `Account found by website via GraphQL: ${d.accountId} (Owner: ${d.ownerEmail})`;
|
|
case "graphql_searching_by_contact_domain":
|
|
return `Searching contacts by domain via GraphQL: "${d.emailDomain}" (${d.contactCount} contacts)`;
|
|
case "graphql_dominant_account_selected":
|
|
return `Dominant account selected via GraphQL: ${d.accountId} (${d.contactCount} contacts, Owner: ${d.ownerEmail})`;
|
|
case "graphql_no_account_found":
|
|
return `No account found via GraphQL for ${d.email}: ${d.reason}`;
|
|
case "salesforce_assignment":
|
|
return `Salesforce assignment: ${d.email} via ${d.recordType} (ID: ${d.recordId})`;
|
|
default:
|
|
return `Salesforce: ${step.step}`;
|
|
}
|
|
}
|
|
}
|