Matthew Meszaros
|
71e04c00dd
|
feat: roll dithered charts across the dashboard: the shared DailyBars becomes DailyTrend (smoothed dithered area graph) powering campaign overview, analytics, and deliverability over-time charts with per-metric tones, deliverability provider placement rows use DitherStack, the mailbox warmup chart becomes a dithered bar chart with target ghost bars and tap-to-pin day selection, API-key traffic uses DitherColumns, and the content score, campaign send progress, credits meter, and unibox queue bars all move to DitherMeter
|
2026-07-19 14:01:53 +02:00 |
|
Matthew Meszaros
|
7502b0f2b4
|
feat: grow the dither kit for the analytics surfaces: a violet tone, area-chart tooltips anchored to the hovered dot (flipping below near the top edge), ghost reference bars + tap-to-pin selection on DitherBarChart, DitherColumns stacked vertical columns with per-part tones and hover callback, and DitherStack horizontal share bars with a left-to-right reveal
|
2026-07-19 14:01:53 +02:00 |
|
Matthew Meszaros
|
e7144a439d
|
feat: upgrade the AI usage view: the daily bars become a smoothed dithered area graph with a 7d/30d/90d range switcher (breakdowns follow the range, previous data held while the new range loads so nothing flashes), and limit cells drop the boxy stepper input for a big inline-editable value with a dashed-underline affordance, the dithered slider, quiet text presets, and a No cap idle state
|
2026-07-19 13:50:03 +02:00 |
|
Matthew Meszaros
|
e4ad9e3661
|
feat: make billing tabs real URL paths: the route becomes billing/:tab? with /app/settings/billing/plans, /ai-credits, and /payment slugs (unknown slugs normalize to the overview), Stripe checkout and topup return URLs point at the tab they left from, the header credits meter deep-links to /ai-credits, the settings topbar subtitle matches nested billing paths, and the document title covers the sub-paths
|
2026-07-19 13:50:03 +02:00 |
|
Matthew Meszaros
|
f0b9c5f49c
|
feat: add DitherAreaChart to the dither kit: a monotone-cubic smoothed line with a dithered area fill fading to the baseline, left-to-right draw-in reveal, and a hover crosshair with dashed guide, line-anchored dot, and tooltip — a real graph, not bars
|
2026-07-19 13:50:03 +02:00 |
|
Matthew Meszaros
|
7524d1ea37
|
feat: redesign the AI spend-control experience: each workspace and per-member limit is a cell with an animated expand, a dithered slider with window-sized presets and an exact number field, and a live spent-vs-limit meter; edits collect into a floating Reset/Save bar instead of writing eagerly; the 30-day chart, spend stats, and breakdowns move to dithered canvas fills with tooltips and animated counts, the credits balance ring goes dithered, and the ai-credits guide notes the new tab and limit controls
|
2026-07-19 13:39:07 +02:00 |
|
Matthew Meszaros
|
587bda2039
|
feat: split the billing settings page into browsable tabs (Overview, Plans, AI & credits, Payment) with an animated sky underline and per-tab fade transition, sync the active tab to ?tab= so Stripe topup returns land back on the AI tab and the header credits meter deep-links to it, route the current-plan button to the Plans tab, and render the usage rows with dithered meters and animated counts
|
2026-07-19 13:39:07 +02:00 |
|
Matthew Meszaros
|
98cb220147
|
feat: add hand-rolled dithered canvas primitives in web/src/components/ui/dither.tsx: Bayer-4x4 ordered-dither bar chart with staggered entrance and hover tooltip, progress meter with a dithered leading edge, donut ring with a dithered sweep tip, a pointer+keyboard slider on a dithered track, and a rAF AnimatedNumber — the dither-kit look with zero new dependencies and prefers-reduced-motion fallbacks
|
2026-07-19 13:39:07 +02:00 |
|
Matthew Meszaros
|
f7a1027367
|
feat: add workspace-shared assistant history: a manage_settings toggle on the organization (assistant_shared_history, off by default) makes every conversation visible to and continuable by every member with the use-AI permission — the service resolves a session to its owner's rows so open/continue/approve/delete all work cross-member while credits still charge the acting member, the org-wide listing joins owner names for attribution in the history rail, the workspace settings page gains the AI assistant section with the toggle and an explicit exposure warning, and the assistant guide's access and privacy sections describe both modes
|
2026-07-19 13:22:56 +02:00 |
|
Matthew Meszaros
|
68e3ca6b6b
|
feat: extend the per-member AI limit to all three windows: member_limit_daily and member_limit_weekly join the monthly ceiling on org_ai_settings, MemberSpentInWindows sums the acting member's debits per window in one query, checkSpendLimits enforces day/week/month member ceilings with window-specific 429 messages, and the billing card's Per-member limits row grows the same three fields as the workspace caps
|
2026-07-19 13:22:56 +02:00 |
|
Matthew Meszaros
|
458234cd5d
|
feat: add clear-all assistant history: DELETE /ai/sessions wipes every conversation the member owns in the workspace (transcripts cascade, count returned, audited as an ai_session delete with clear_history metadata), the history rail gains a Clear history footer action behind the in-app confirm that also closes all session-backed tabs, and the assistant guide documents access gating, per-member limits, privacy, and both delete paths
|
2026-07-19 11:05:18 +02:00 |
|
Matthew Meszaros
|
f4014b8b73
|
feat: add a per-member monthly AI credit limit to the org spend controls: new member_limit_monthly on org_ai_settings flows through the settings repo, PATCH endpoint, and billing UI (its own Per-member limit field on the AI usage card), and checkSpendLimits enforces it by summing the acting member's debits this calendar month via the ledger's actor attribution (new MemberSpentSince query on the partial index from migration 000073), returning a 429-mapped member-limit error while unattributed scheduled work stays exempt
|
2026-07-19 11:05:18 +02:00 |
|
Matthew Meszaros
|
7ef7d90d8c
|
feat: introduce the Use AI organization permission (bit 15, the last of the 16-bit mask) gating every AI surface: assistant session routes, generation write/edit, and the compose and reply draft endpoints get a member-permission layer (API keys re-check their existing bit), migration 000073 backfills the bit onto all existing roles and member overrides so nobody loses access, defaults grant it to admin and manager but not viewer, and the web mirrors it in the permission catalog with gating on the header spark button, Cmd+I, the panel itself, and the AI drafting caret (plus team-roles and endpoint-map docs)
|
2026-07-19 11:04:58 +02:00 |
|
Matthew Meszaros
|
bacbf5552f
|
feat: upgrade the assistant's full-screen history rail: conversations group under Today/Yesterday/This week/Earlier sections, a search field filters them by title, each row gets a hover (always-visible on touch) delete action behind the in-app confirm that also closes the conversation's open tab and invalidates the list, the New chat button shows its Alt+N kbd chip, and the guide documents deletion and search
|
2026-07-19 10:50:33 +02:00 |
|
Matthew Meszaros
|
8eb2824ac4
|
feat: render the assistant's stream like a live agent and surface its keybindings in the panel: text_delta chunks append to a live-flagged trailing block that the closing full-text event replaces, the trailing block of a running turn types itself out through a rAF SmoothText typewriter with the blinking caret so even chunky providers read as continuous generation, and the empty state gains kbd chips for toggle, new chat, pop out, and minimize plus an all-shortcuts link into the shortcuts dialog
|
2026-07-19 10:42:10 +02:00 |
|
Matthew Meszaros
|
ab938575d3
|
feat: give the AI assistant a floating window mode on desktop: pop out via the header button, Alt+P, or tearing the docked header off its edge, then drag it anywhere by the header and resize from any edge or corner (360-920 wide, min 400 tall, always clamped fully on screen), with the geometry persisted alongside side and width, a dock-back button targeting the remembered edge, and the assistant guide updated
|
2026-07-19 10:31:20 +02:00 |
|
Matthew Meszaros
|
633615c341
|
feat: move the compose-drafts invalidation from useMutation onSuccess into the mutationFn promise chain, because closing the composer fires the save and unmounts in the same tick and observer callbacks are skipped after unmount, which left the rail's Drafts list stale until a full reload
|
2026-07-19 10:31:20 +02:00 |
|
Matthew Meszaros
|
b866d2b99d
|
feat: harden the From menu's tag filter and search field: tag chips now derive from the store's mailbox directory sorted by position instead of the candidates fetch (so they show even while candidates load), the search input gets a real slate border instead of the invisible white-on-white fill, and the panel clamps against clientWidth so its right edge cannot slip under a scrollbar
|
2026-07-19 10:21:25 +02:00 |
|
Matthew Meszaros
|
b06be51783
|
feat: raise the shared tooltip layer from z-50 to z-150 so hover tooltips (like the AI caret's Write with AI hint) render above the docked compose window at z-70 instead of hiding behind it, while staying under the confirm dialog at z-200
|
2026-07-19 10:21:25 +02:00 |
|
Matthew Meszaros
|
f333260b0f
|
feat: derive unibox search params synchronously from the URL scope (lazy initial state plus a render-phase reset keyed on scope and resolved tag accounts) instead of a post-paint effect, so reloading a scoped URL no longer fires and paints the default all-mail query first and then flashes the thread list over to the scoped result
|
2026-07-19 10:02:43 +02:00 |
|
Matthew Meszaros
|
17635a99cc
|
feat: restore the app store's mailbox and tag slices by syncing them in DataSyncProvider (paged /emails directory query under the audit-spine-invalidated ['emails','list'] key plus profile tag definitions), un-breaking every surface that resolves mailbox-to-tag membership from the store: the compose From picker's tag filter chips, the unibox filter sheet's tag resolution, and the tag scope in the rail
|
2026-07-19 10:02:43 +02:00 |
|
Matthew Meszaros
|
018ce89b79
|
feat: make the recipient autocomplete category-aware in both composers: suggestion rows show each contact's category chips with their colors, typing a category name offers it as a filter row (enter or click applies it as a removable chip in the field, backspace or escape clears it), and an active category narrows the suggestions to that group via the search endpoint's category_ids
|
2026-07-19 09:26:02 +02:00 |
|
Matthew Meszaros
|
c3977d30d4
|
feat: give the reply composer's To/Cc/Bcc fields the same contact autocomplete as compose by swapping the plain chip editor for the shared ContactRecipientField (type to search existing contacts by name, email, or company; raw addresses still commit with Enter) and delete the now-unused local RecipientField
|
2026-07-19 09:22:17 +02:00 |
|
Matthew Meszaros
|
1da0a932fa
|
feat: shrink the From mailbox menu into a compact searchable list: single-line h-8 rows (auth dot, address, history count, sent/limit budget, best marker) with the name and score reasons moved into the tooltip, a search box that filters as you type, tag filter chips built from the org's mailbox tags (only tags actually in use are offered), an inline Auto row, and a no-match empty state
|
2026-07-19 09:22:17 +02:00 |
|
Matthew Meszaros
|
4bbbf57bb2
|
feat: serialize the AI draft bar's phase transitions with AnimatePresence mode wait so the clarifying-question card no longer enters beside the exiting busy pill, gets shoved off-center, and jumps back when the pill unmounts
|
2026-07-19 09:16:55 +02:00 |
|
Matthew Meszaros
|
22fddad234
|
feat: stop the dashboard-wide reload flashing: the reconnect catch-up invalidated every query on any socket RE-connect, so a flapping websocket refetch-stormed the whole app; now it only fires after a real outage (over 5s down) and at most once every 30s
|
2026-07-19 09:16:55 +02:00 |
|
Matthew Meszaros
|
a3339fe0b3
|
feat: update the reply composer's layout doc comment to describe the new target strip and row order
|
2026-07-19 08:56:21 +02:00 |
|
Matthew Meszaros
|
50701af000
|
feat: align the reply composer's horizontal rhythm: body textarea and signature preview blocks share the px-4 left edge with the header rows instead of drifting between px-5 and mx-3/mx-5
|
2026-07-19 08:56:08 +02:00 |
|
Matthew Meszaros
|
3c4738e065
|
feat: rebuild the reply composer header rows in the compose window's language: To first with quiet Cc/Bcc toggles on its right, plain inline labels with hairlines instead of the uppercase label lane and vertical divider column, the From mailbox as calm text without the boxed mono chip, and an unlabelled slightly heavier subject line
|
2026-07-19 08:55:40 +02:00 |
|
Matthew Meszaros
|
5c3b6aab10
|
feat: replace the reply composer's target-message preview card (round icon badge, uppercase kicker, three stacked lines) with the compose window's quiet single-line bar: Reply/Forward to name and subject on a slate-100 strip with a muted corner icon (violet when forwarding) and a ghost close button
|
2026-07-19 08:54:35 +02:00 |
|
Matthew Meszaros
|
6f8db3ae05
|
feat: de-template the cold-email humanizer (drop the quotable example asks and subject that models parroted verbatim, add a VARIATION section mandating a fresh skeleton per email and capping punchy standalone lines at one) and add compose drafts: autosaved per-user working copies (client-generated ids, idempotent PUT on a 1.2s debounce, migration 000072) with Saving/Saved in the window header, close-keeps-draft instead of the discard confirm, delete on send or when emptied, and a Drafts list under the rail Compose button to resume or delete, documented in the guide and endpoints scope map
|
2026-07-19 08:52:56 +02:00 |
|
Matthew Meszaros
|
e6b11f8d07
|
feat: fix compose draft quality and review chrome: a compose-specific humanizer frame (BuildComposeRules) that bans copywriting rhythm outright (no standalone punch lines, no problem-agitate-pitch, no market generalizations, 40-70 words, plain first sentence) and gives no example phrasings for the model to parrot, clear the grounding report and voice-profile nudge when the draft flow ends instead of lingering after Keep, restructure the Draft ready card into breathing rows (title plus usage, grounding line, right-aligned action row), and portal the From mailbox menu to the body with viewport-aware flip so the compose window's overflow clipping can't cut it off
|
2026-07-19 08:45:47 +02:00 |
|
Matthew Meszaros
|
6ce5ebe900
|
feat: make compose AI drafting grounded and agentic: POST /unibox/compose/draft assembles the recipient's contact 360, the full correspondence history with the address, and the org voice profile into the prompt (2-credit minimum, reason compose_draft, usage settle, refund on provider failure), and when the purpose is genuinely unknowable the model returns a clarifying question instead of inventing a pitch; the draft bar gains a question phase (answer inline and it writes), the review card reports exactly what the draft was grounded in, and the composer nudges to Settings > Workspace with a link when no voice profile is set; docs cover the endpoint, credits row, and guide behavior
|
2026-07-19 08:37:39 +02:00 |
|
Matthew Meszaros
|
0c4e63ab01
|
feat: make the compose window behave like a real docked draft: minimize to a compact corner bar (draft state stays mounted while you browse other pages, header click or chevron restores, n or any openCompose restores instead of clobbering the draft), a serious single-icon header that reads New email to <name>, <company> as the recipient resolves, and the body textarea aligned to the same horizontal padding as the subject and header rows
|
2026-07-19 08:31:53 +02:00 |
|
Matthew Meszaros
|
a5982808fd
|
feat: stop the inbox flashing on scope and route switches by keeping previous unibox search pages as placeholder data while the new key loads (no more full-pane skeleton flash) and holding overview counts in cache for 30 minutes so the header stats stop rolling up from zero, and flatten the compose header to a quiet single-line bar that shows just the recipient (or New email) with the icon chip and subtitle removed
|
2026-07-19 08:25:06 +02:00 |
|
Matthew Meszaros
|
112f75a23d
|
feat: fix the in-composer AI layers rendering behind the docked compose window by raising the portaled sparkle/pill/menu z-indexes above window chrome (still under the confirm layer), give the compose header a proper identity (sky pen chip plus two-line title with the recipient or draft state), add the Template picker and booking-link tools to the compose action bar by extracting TemplatePickerContent and InsertBookingLink out of ReplyComposer into shared unibox components, and make Compose the house primary sky button in the rail and mobile header
|
2026-07-19 08:22:26 +02:00 |
|
Matthew Meszaros
|
26bb5a1746
|
feat: soften the compose chrome from black-on-white to grayish: the window header becomes a slate-50 bar with a hairline and muted controls, the rail and mobile Compose buttons become white bordered buttons with a sky pen icon, and the History panel's active tab uses a slate-200 fill instead of the inverted slate-900 pill
|
2026-07-19 08:17:33 +02:00 |
|
Matthew Meszaros
|
8260094d46
|
feat: redesign the compose window chrome: dark slate header bar with icon-only history/close, Gmail-style header rows (quiet inline labels and hairlines instead of the uppercase label lane and vertical divider), unlabelled heavier subject line, Cc/Bcc toggles on the To row, calmer AI presence (neutral auto chip on the From picker with the reason kept in the dropdown, contextual Suggest ghost that only appears when the subject is empty and a body exists, plain body placeholder), plus a proper Compose button at the top of the unibox scope rail with the header button kept as the mobile-only entry
|
2026-07-19 07:56:04 +02:00 |
|
Matthew Meszaros
|
6790eabd74
|
feat: wire compose entry points: mount the window globally in the app layout, add the Compose button with an n shortcut tooltip to the unibox header, register the global n key (and update the shortcuts modal entry), and add an Email action to the contact drawer that opens compose prefilled with the contact's address
|
2026-07-19 07:38:48 +02:00 |
|
Matthew Meszaros
|
5e2d4ae832
|
feat: build the compose window: a docked bottom-right popup with an Auto mailbox picker that shows the backend's pick and reason plus per-mailbox budget bars, history badges, and auth dots, a contact-autocomplete recipient field, AI subject suggestion, the full in-composer AI experience (caret menu, selection edit, sheen + typewriter draft bar grounded in the recipient's contact record), suppression blocking before send, schedule presets, signature status, and a slide-out History panel with Conversations/Sent tabs, subject search, and mailbox-affinity line that opens real threads in the unibox
|
2026-07-19 07:38:48 +02:00 |
|
Matthew Meszaros
|
44bfe7840f
|
feat: add the compose web API layer (candidates + send clients, hooks with unibox invalidation, address/direction params on unibox search), a global useComposeStore zustand store so any surface can open the composer, and configurable draft row label/cost on TextareaAICaret so compose can say Draft this email with AI instead of the reply wording
|
2026-07-19 07:38:48 +02:00 |
|
Matthew Meszaros
|
47232aef3c
|
feat: fix the draft review card to a fixed width so the Adjust input spans it fully with the send button flush right, make the header credits meter foresight-first (ring plus plan left/allowance, or spent/limit today|wk|mo when a spend limit is configured, plus a +N for purchased credits, all without opening the panel), and surface keybindings across the AI flow: the selection pill shows an inline mod+J kbd chip and mod+J with a selection actually opens the editor, the caret companion keeps mod+J for the collapsed caret, and both popovers show enter/esc hints including esc-to-cancel while generating
|
2026-07-18 16:40:07 +02:00 |
|
Matthew Meszaros
|
ea85dbc1cf
|
feat: seed labels into the sandbox org (folders/tags/categories for sandbox@warmbly.test bound to mailboxes, campaigns, contacts, and four inbox threads, idempotent with a dedicated UUID namespace) and restyle the thread label dropdown to the house picker language: assigned labels show as colored chips right in the trigger with a +N overflow, the panel gets a search-or-create header, a removable assigned-chips row, color-dotted checkbox rows with an assigned marker, a friendly empty state, and a footer noting the shared category registry and the c shortcut
|
2026-07-18 16:35:36 +02:00 |
|
Matthew Meszaros
|
1823f03a80
|
feat: live usage-based credit feedback — every fresh debit publishes BILLING_CREDITS_CHANGED through the creditwatch monitor so the header meter counts down in real time (AnimatedNumber tween, plus client-side invalidation on write/edit/draft success), generation responses now return the real credits_charged and tokens_used from the usage settle and every AI surface shows the true cost instead of flat labels, and the composer AI became overlay-based: the draft bar floats over the body instead of pushing layout, a sky sheen sweeps the input while the model writes, and the selection being rewritten is painted with pulsing highlight rects that grow as the rewrite types in
|
2026-07-18 16:30:05 +02:00 |
|
Matthew Meszaros
|
cb6b58d462
|
feat: add a reusable ShortcutTooltip (themed tooltip with a platform-aware kbd chip, mod renders as cmd on Apple and Ctrl elsewhere) and use it on the caret AI sparkle (mod+J) and the header assistant button (mod+I) so fast keys are discoverable instead of hiding in native title attributes
|
2026-07-18 15:31:59 +02:00 |
|
Matthew Meszaros
|
09bb526a6c
|
feat: move the inbox composer's AI to the cursor — remove the Draft reply and Write with AI buttons from the action bar and replace them with a caret companion: a faint sparkle rides the line you're typing on (or press cmd+J) and opens a menu at the caret to ask AI to write and insert there, draft a full reply from the thread, or continue writing, with typewriter insertion plus Undo/Again/Done and the unibox guide updated to match
|
2026-07-18 12:11:14 +02:00 |
|
Matthew Meszaros
|
ec53089232
|
feat: document the in-composer AI editing — selection-edit cost row in the AI credits guide, the unibox guide now covers the draft review bar (Keep/Adjust/Retry/Discard) and the Edit with AI selection pill, and the billing usage/transaction views label the new writing_edit reason
|
2026-07-18 11:59:18 +02:00 |
|
Matthew Meszaros
|
c075a74ad5
|
feat: agent panel motion polish — streaming assistant text ends in a blinking caret, the Working indicator becomes a pulsing agent mark with shimmer text, user bubbles and tool-step chips spring in, done checkmarks pop, and the minimized dock's response-ready dot pings
|
2026-07-18 11:57:37 +02:00 |
|
Matthew Meszaros
|
5178acd874
|
feat: in-composer AI writing experience — select text in the unibox reply textarea or the campaign TipTap editor and a floating Edit-with-AI pill opens quick actions (improve, shorten, expand, fix grammar, friendlier, more formal) plus free instructions backed by a new fenced /generation/edit endpoint (1 credit, idempotent, refund on failure, prompt-injection fencing around the passage), rewrites type themselves in with undo/again/done review, and Draft reply now runs through an inline draft bar with staged shimmer status and Keep/Adjust/Retry/Discard instead of a toast
|
2026-07-18 11:55:37 +02:00 |
|
Matthew Meszaros
|
ac3a904d8c
|
feat: restyle the header CreditsMeter to blend with the chrome — no pill background or blue tint, just a neutral slate ring gauge and count that matches the search/bell controls, coloring amber/red only when low or empty, with a number-forward panel (big balance, slate progress bars, status dot, quieter auto top-up note) instead of the sky-tinted card look
|
2026-07-18 11:30:07 +02:00 |
|