e4ca2b92c9
11 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| e4ca2b92c9 |
Revert "console: redesign the UI — one card language, icons, filters, live trail"
This reverts commit
|
|||
| e90e4204ec |
console: redesign the UI — one card language, icons, filters, live trail
Visual and information-architecture pass across every screen. No API call, payload, poll, permission rule or workflow mirror changes; forms still render from the live schema and the timeline's merge/grouping is unchanged (only the display order is reversible). Design language - Ground + white cards with one hairline and one radius; sentence-case headings; shared primitives in index.css (.card .pill .btn .avatar .live). - One inline icon set (components/Icon.jsx); no more filled navy/red tiles. - Read-side labels in api/display.js: roles and enum tokens humanized, customer initials/tones, money and date formatters. Nothing sent changes. Shell - 56px header with brand, global lead search (portfolio rows, "/" to focus) and identity chip with a human role label. - Sidebar rows carry icons and a clear active bar; AI roster at the foot, each opening its remit card. Login - Operator copy instead of retail copy; centred sign-in card with show/hide password; demo persona picker that fills the EMAIL only. Overview - "Who holds the work" as four quiet cards that warm only when owed. - Pipeline flow bar with every stage named beneath it; KPI strip in a card. - Action rows with chevron / view-only eye; expiry bands filter the table. Queues - Filter bar (search, product, channel, expiry band, stalled, hide closed) and sortable columns, all client-side on the fetched page. - Avatars, product/channel chips, stage chips for closed leads, tinted stalled rows, count inline with the title. Lead - Avatar + chips in the header; metrics card with the stage rail inside, and a branch node for Referred / Parked / Lost / Declined. - Timeline newest-first by default (toggle), the worker's face as the node, one footer row per entry, AI markdown rendered as bold. - "AI team on this lead" panel with per-agent step counts; PDF tags on docs. Forms & dialogs - Required marked with an asterisk + legend; "Select…" placeholder; dd Mon yyyy hint under date inputs; open activity form in a titled panel; one-line dialog footnotes. Fixes: horizontal overflow at 1024px, boxed "in N days" figure, raw tokens (sme_underwriter, verbal_call, Rsa), findings cut at "1.". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
|||
| a49ae3d86c |
console: the story is the page; the reference is the rail
The audit trail is the record of work nobody watched happen — it is what this product is for — and it sat in a 384px gutter with its own inner scrollbar beside a full-width panel of form fields. That said, in layout, that the AI's work was a footnote to the data entry. Exactly backwards. Swapped. The trail takes the wide column and scrolls with the page under a heading that says what it is: "What happened". The reference data — customer, vehicle, documents, the call, the stage's own facts — moves to a 340px sticky rail, where short key/value pairs belong. The crew who worked the lead sits at the top of that rail as its own small panel. The overview now opens on who holds the work rather than on money: four large numbers on navy — with the AI, waiting on a person, with the customer, renewals at risk. A live person-queue or a lapsed renewal warms its cell; the rest stay cool. Money is the outcome; this is the state, and it is the sentence the whole console exists to say. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
|||
| ea2b56e332 |
console: the file reads as facts, and filing a lead stays on the page
The lead file put seven AI paragraphs in the same flow as "Mobile", each with the weight the audit trail gives it, so the card was mostly quotations with the facts lost between them — and the same prose sat in the trail two feet to the right. Facts group at the top now; the reasoning is a caption, two lines and a link to the dialog that already held it. Pairs go side by side rather than stacked, and the CSS columns become a grid: column flow read top-to-bottom-then- across, so groups landed in an order nobody could predict and tore raggedly between 2-field and 12-field groups. New lead was a route. Pressing it cost you your place in the queue you were working through and left you three navigations away. It is a dialog over the page now, with the same modal furniture as the conversation and reasoning ones. Three of its boxes were answered by the system before anyone saw them — the channel, the partner code and the submitting agent, all stamped by prefill from the signed-in identity. They are hidden at RENDER only: `fields` still holds them, so they validate and submit exactly as before. Filtering them out of `fields` would have dropped the attribution and 400'd on the mandatory channel. A stamped field that comes back empty is drawn anyway, so a prefill that does not resolve cannot fail validation against a box that is not on screen. Business Name is scoped to SME. An INIT form has no lead to filter on, so visibility reads the live answer to Product Line first and the saved lead second — the form narrows as it is filled, and a motor renewal drops from twelve boxes to nine. It is optional, so hiding it cannot block a submission. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
|||
| de8b158ca9 |
console: the nav navigates, and the screens act
"New lead" sat in the sidebar. A sidebar is for moving between places; filing a lead is an action, and an action in a list of destinations is the one item that does not behave like its neighbours — everything above and below it changes what you are looking at, and it did something. It now sits on the overview and on every queue, beside the lists it adds to, which is also where somebody is standing when they realise they have a lead to file. Same role gate as before: shown only to a user who holds an entry door. The sidebar's own button CSS went with it rather than being left for someone to wonder about. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
|||
| 171aa4c2fa |
console: a live trail, faces for the agents, and the thread as a thread
Five of the six asks. The sixth — the whole row as the click target —
shipped in
|
|||
| 5ff74ea22d |
console: numbers in the navigation, and reasoning behind one click
THE SIDEBAR NOW CARRIES COUNTS. It deliberately did not, on the argument
that a tally could only come from a second full list call that would then
disagree with the queue's own total. Right about the cost, wrong about
the conclusion: with no numbers the only way to learn whether anything
was waiting on you was to open all nine queues in turn, which is the
question navigation exists to answer.
There is no second call. The overview's existing fetch moved into a
PortfolioProvider that both surfaces read, so this is one call fewer than
before and the two agree by construction. Bounded at 200 rows, as the
overview always was; past that the honest answer is an aggregate
endpoint, not a bigger limit.
What the badge counts is what needs a PERSON — phaseOf again, so a lead
whose documents are in and whose AI chain is running is reported beside
the badge rather than inside it. An amber dot marks a queue holding a
renewal inside a week, which is the only reason to open one queue before
another and was previously invisible. Zero is shown rather than hidden:
"nothing here" is an answer, and a queue that disappears when it empties
makes the sidebar move under the cursor.
Closed is folded into a summary. Three of the twelve queues, opened about
once a week, and at equal weight they made the live ones harder to find.
REASONING OPENS IN A DIALOG, NOT INLINE. The audit rail is 320px wide
with one entry per step, and a 1,500-character rationale expanding in
place pushed a lead's whole history off screen to read one sentence of
it. Nobody reads a paragraph in a sidebar. The finding — the AI's own
first sentence, which is already the conclusion — stays on the line; the
working is one click away and one Escape back, headed by what is being
read ("Call — Log Contact") rather than by nothing. Escape closes, the
page behind does not scroll, and focus returns to the button that opened
it so a keyboard reader keeps their place.
Two headings that described the container rather than the contents:
Record → "Lead file", and the audit trail's subtitle now says what a
reader gets from it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|||
| d6756b4d2e |
console: show what the workflow actually did, and when it stopped
Traced the console against the workflow it renders. Five gaps, all of which made a working chain look like a broken one. THE AUDIT TRAIL WAS READING THE WRONG KEYS. An audit row's data is keyed by the ACTIVITY's field ids, which carry a per-form suffix — the call notes arrive as contact_notes_2, the document request as documents_notes_3 — and the timeline matched the unsuffixed global ids. Almost nothing ever matched, so the trail was a list of activity names with the agents' reasoning invisible behind it. The one narrative line that did appear was an accident. It now reads the platform's own typed `fields[]` (label, data_type, value) and matches on the base id. That is also what lets it answer the question that was asked: an upload now renders as "3 documents received" with each one named and openable, instead of a bare "Collect Documents". DATA_UPDATE ROWS WERE CLASSED AS AGENT WORK. A bookkeeping row inherits the roles of whoever caused it, and the AI check ran first — so an AI's field write appeared in the trail as an entry titled "Data updated", while the toggle underneath still offered to reveal the others. The activity id says a row is bookkeeping; the roles say who triggered it. DOCUMENT PENDING IS TWO SITUATIONS. Before the upload a person has to act; after it the lead stays in the same state while three AI steps run. Both rendered as "waiting on the partner agent", so a lead that had just been served showed an Upload documents button under a panel saying the documents had been received, and counted against the Action-required queue. phaseOf() derives the difference once, from documents_status, and the header, the queue count, the row status and the action list all read it. The upload demotes to recovery — "Replace or add a document", folded away with the other levers. A STOPPED CHAIN LOOKED IDENTICAL TO A RUNNING ONE. The rating engine refuses to price without an IDV and writes so into quoted_breakup; Engage then declines to raise a quote it would have to fabricate. Both are right, and nobody was told: the refusal sat in a field on a tab and the lead never moved again. blockedOn() surfaces it as an amber strip that names the missing value and opens the form that carries it. THE STALL MEASURE WAS DATED FROM THE WRONG COLUMN. progress() fell back to created_at when updated_at was absent — which it always was, because neither view returned it — so every lead older than half an hour would have reported stalled. It reads updated_at only; the view supplies it as of 76. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
|||
| 704afe170e |
console: the row is the control, and the agent says what it is doing
Two changes to the queue and overview tables. The row is the click target. An "Open" button was a 90px destination inside a 1000px row that already reads as one object, and it put a second tab stop on every line. The row now carries the click, Enter/Space, a focus ring and the hover tint; the button column is gone, along with its CSS. The column it freed shows what is actually happening. This workflow is run by agents and watched by a person, so the question a queue has to answer is not "which stage" — inside a queue every row shares it — but "is it moving". An automated stage now reports working (under 3 minutes), waiting (under 30), or stalled with the elapsed time, with a pulse on the live one and a red left edge on the stuck one. Thresholds are generous on purpose: an employee wake takes a minute or two and a scheduled retry can be hours out, so stalled means "longer than any normal step", not "longer than average". Before this, a lead three hours into "Calling the customer…" looked identical to one thirty seconds in — which is the failure this console exists to catch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
|||
| aca5d1a043 |
console: role-scoped access, portfolio analytics, enterprise register
Four things, and the first is the one that mattered.
ROLE-BASED ACCESS. The console showed every action to everyone on
purpose — "the refusal is the demo" — and the workflow refused
server-side. That is a defensible engineering position and a poor
product: an underwriter saw a row of six buttons, five of which 403.
src/api/permissions.js now mirrors tbl_wf_activity_permissions, and the
session already carries user.roles, so nothing new had to be fetched.
Action buttons, sidebar queues and the entry doors are all filtered.
It remains presentation only — the platform still refuses, and a role
added there but missing here hides a button that would have worked,
which is the failure mode to watch.
Each role's app now looks like their job. Ops sees the whole board and
still cannot clear a referral. An underwriter sees one queue and two
buttons. Agents see the three queues they work in. Reporting is NOT
gated: the overview counts the whole portfolio for everyone, because an
agent tracking leads they filed is reasonable and acting on them is not.
One deliberate divergence from the workflow, commented where it lives:
the two scheduled activities carry no roles at all, because that is the
only configuration under which the scheduler can perform them. Open to
the SYSTEM is not open to everyone signing in, so the UI narrows them —
otherwise an underwriter is offered "Send Document Reminder".
ANALYTICS. The overview was three lists. It is now a measured page:
open leads, pipeline value, written premium, conversion, commission —
then renewal exposure in three buckets, the queues needing a person with
the age of the oldest item in each, and stage distribution as bars.
Checked against the live book rather than assumed, which found a real
bug before it shipped: Policy Issued is written business AND not yet
terminal, so its premium was counted in pipeline and production both.
₹42,912 double counted on 37 leads. Pipeline now excludes anything
already on risk.
The lead page gained the same treatment: renewal countdown, lead age,
time in current stage, premium, commission, AI confidence. Age and
dwell are computed — neither is on the record, and they are the two
figures that answer "is this moving?", which no field could.
TERMINOLOGY. The previous pass over-corrected: fixing builder jargon
("the workflow decides, server-side") produced chat ("What you can do",
"The agents have it", "Nothing here right now"). Neither is how an
operations console reads. Now: Actions · Record · Audit trail · Action
required · Customer response · Automated · Scheduled · Document
collection · Underwriting referral · Premium confirmation.
LAYOUT. Prose subtitles cut to one line or removed. Measures render as
tabular figures in a bordered strip instead of label/value pairs. The
overview splits into work on the left and distribution on the right.
Stage bars replace a wall of equal-weight cards.
Pre-existing lint errors unchanged at 11; none in the new files.
|
|||
| 4c210c7e09 |
console: a page to monitor from, and words an operator would use
Three problems, and the first one is the reason the other two were hard to see. THERE WAS NO DASHBOARD. "/" redirected to the underwriting queue — one stage, usually empty, and belonging to somebody else. Every screen in the app answered "show me this queue"; none answered "how is the book doing, and is anything waiting on me?", which is the only question a person has before they have picked a queue. So: a Today page. Three blocks, in the order somebody cares about them. What is waiting on a person, as three cards that colour only when they have something in them. Renewals running out, worst first, capped at 30 days because a renewal six months away is not a thing to look at today. Then every stage with its count, zeroes included — a stage quietly receiving nothing is only visible if its zero is on screen. It is one list call, counted in the browser. That is honest at this size and it is the same call the queues already make. If the book outgrows it the answer is a counts endpoint, not a bigger page. THE WORDS WERE WRITTEN FOR WHOEVER BUILT THE WORKFLOW. "What happens next" was followed by "these are the only activities this state allows — but the workflow decides, server-side, whether you may". A failed list said "this queue has no record view yet". Panels were called "Flow details". A closed lead read "nothing runs from here". None of that is wrong; all of it is addressed to the wrong reader. Now: "What you can do", "Lead details", "History", "This queue could not be loaded". Queue names say what they want — "Documents needed", "Underwriter to review", "Payment to confirm". The sidebar group called "Not yet" says "Not due yet", and "Running by itself" says "The agents have it", which is the actual claim being made. THE QUEUE HAD NINE COLUMNS AND LED WITH THE WRONG ONE. Two were internal vocabulary: attribution status renders "clear" or "contested" and means nothing to an operator, and the channel is background rather than something anyone scans a queue for. Both fold into a subtitle under the customer. That leaves six columns and puts the renewal countdown — the number that decides whether to act today — second instead of fifth. Also: the timeline printed a raw slug when a step came back without a name. It is the screen this product is demonstrated on, so a "zk-act-doc-reminder" in the middle of an otherwise readable story is expensive. It now reads as English. |