Skip to content

feat(onboarding,ui): trust-first onboarding + Button primitive + honest privacy surface#759

Merged
senamakel merged 4 commits into
tinyhumansai:mainfrom
jwalin-shah:feat/frontend-overhaul
Apr 22, 2026
Merged

feat(onboarding,ui): trust-first onboarding + Button primitive + honest privacy surface#759
senamakel merged 4 commits into
tinyhumansai:mainfrom
jwalin-shah:feat/frontend-overhaul

Conversation

@jwalin-shah
Copy link
Copy Markdown
Contributor

Summary

  • New reusable <Button variant size> primitive (4 variants × 5 sizes) with focus ring baked in — foundation for future UI consolidation.
  • New WhatLeavesMyComputerSheet + WhatLeavesLink privacy surface, reused in onboarding footer and Settings → Privacy & Security. Copy is intentionally conservative and matches what the backend actually does.
  • ContextGatheringStep no longer auto-runs the Rust-side LinkedIn enrichment pipeline on mount. It is now user-driven: an intro card explains what will happen, with "Start when ready" and "Skip for now" controls.
  • WelcomeStep slide 1 rewritten to the design handoff copy (mono eyebrow, display-font title, honest subtitle). Carousel slides 2/3 preserved.
  • E2E login-flow.spec.ts updated to match the new ContextGatheringStep headings and prefer "Skip for now" so the real enrichment pipeline stays out of E2E.

Problem

Two trust-shaped gaps in the current onboarding:

  1. Silent surveillance shape. ContextGatheringStep kicked off a Gmail → LinkedIn scrape pipeline inside useEffect on mount, before the user had seen what was about to happen. That is exactly the "nothing ever leaves your computer" lie the README explicitly rejects.
  2. Privacy copy was either missing or overclaiming. No consistent way to see "what actually leaves my computer" near the moments a network call is about to happen. The existing PrivacyPanel only surfaced the analytics toggle.

A third, lower-level gap: there was no shared Button component, so every flow reinvented the same Tailwind utilities slightly differently.

Solution

UI primitive (app/src/components/ui/Button.tsx)
Matches the design handoff spec exactly: 4 variants (primary / secondary / ghost / danger) × 5 sizes (xs / sm / md / lg / xl). forwardRef, default type="button", focus-visible ring applied by default on every instance. Intentionally not ripping existing ad-hoc buttons in this PR — it lands the primitive cleanly and leaves adoption incremental.

Privacy surface (app/src/features/privacy/)
whatLeavesItems.ts is the single source of truth: 5 items that really do leave the laptop (model downloads; cloud provider calls; skill sync summaries to the memory service; crash reports; sign-in / billing / chat routing). WhatLeavesMyComputerSheet is a portal modal with backdrop, Escape-to-close, aria-modal. WhatLeavesLink is a tiny underlined trigger for any screen that might hit the network. PrivacyPanel in Settings now surfaces the same list above the analytics toggle.

Copy audit was intentional before commit — three lines were softened because they were slightly stronger than what the backend actually supports (skill data does sync to our memory service per 17-skills-memory-inference-flow.md; chat messages are routed through our backend to the selected model per chat.rs; the LinkedIn pipeline uses Apify, not a user-chosen scraper).

Onboarding honesty pass

  • WelcomeStep slide 1: eyebrow OPENHUMAN · LOCAL BY DEFAULT + display-font "Hi. I'm OpenHuman." + honest subtitle ("routes to the cloud when you pick a cloud model"). Footer has WhatLeavesLink. Slides 2/3 untouched.
  • ContextGatheringStep: the pipeline now fires only from an explicit user click. Intro card describes what gets read, and "skip this and nothing is read" is finally a true statement. The running UI keeps its existing progress visualization, plus WhatLeavesLink. Body copy is softened throughout.

Intentional deferrals (keeping the bar high on overpromise):

  • No sourcesSlice — would duplicate the existing draft.connectedSources state in Onboarding.tsx.
  • No MirrorMomentStep — no Rust-side scan_sources / observation generator exists, so any stub would fake the payoff and undercut everything else this PR is trying to do. Gate hard = don't create.

Drift commit (9f7e43fe): the pre-push hook surfaced two unrelated items already drifting on main (cargo fmt ordering in src-tauri/src/lib.rs, one-line wrap in webview_accounts/mod.rs, Cargo.lock version 0.52.27 → 0.52.28 to match package.json). Picked up here so this PR can push cleanly rather than ride --no-verify.

Submission Checklist

  • Unit tests — 24 new Vitest tests: 10 Button, 6 privacy sheet/link, 4 WelcomeStep, 4 ContextGatheringStep. Full yarn test:unit green (498 passed, 2 pre-existing skips).
  • E2E / integrationlogin-flow.spec.ts updated to match new ContextGatheringStep heading markers and to prefer "Skip for now" so the real Rust enrichment pipeline stays out of E2E. No new E2E file.
  • Doc commentswhatLeavesItems.ts carries a short rationale block explaining why the list exists and why copy must not soften. Privacy components are small and self-evident.
  • Inline comments — Added only where flow is not obvious (e.g. E2E spec comment block explaining why we prefer Skip).

Impact

  • Runtime: desktop only. No change to Tauri commands, core sidecar, or JSON-RPC surface. All changes are frontend.
  • User-visible: (1) ContextGatheringStep now requires an explicit click to start — meaningful UX change; the step no longer auto-completes on reachable users. (2) New "What leaves my computer?" affordance visible on WelcomeStep and ContextGatheringStep. (3) Settings → Privacy & Security now explains what leaves the machine in addition to the analytics toggle.
  • Security / privacy: strictly tightens trust posture — removes silent network behavior and makes privacy claims conservative and capability-backed where possible.
  • Migration: none.
  • Follow-ups: (a) longer term, the static privacy list should become capability-backed so the UI can't drift from reality; (b) ad-hoc buttons across the app can migrate to the new <Button> primitive incrementally.

Related

  • Design handoff: openhumanclaudedesign.zip (v2 onboarding pass).
  • Issue(s): none filed — this is a design-directed pass.
  • Follow-up PR(s)/TODOs: capability-backed privacy list; incremental <Button> adoption.

@jwalin-shah jwalin-shah requested a review from a team April 22, 2026 06:15
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 22, 2026

Warning

Rate limit exceeded

@senamakel has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 23 minutes and 40 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 23 minutes and 40 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9b7fe3fa-1e4f-4b7d-bf5e-9c2bf8fc7ee5

📥 Commits

Reviewing files that changed from the base of the PR and between 7961a32 and bd6030d.

📒 Files selected for processing (18)
  • app/src/components/settings/panels/PrivacyPanel.tsx
  • app/src/components/settings/panels/__tests__/PrivacyPanel.test.tsx
  • app/src/components/ui/Button.test.tsx
  • app/src/components/ui/Button.tsx
  • app/src/features/privacy/WhatLeavesLink.tsx
  • app/src/features/privacy/WhatLeavesMyComputerSheet.test.tsx
  • app/src/features/privacy/WhatLeavesMyComputerSheet.tsx
  • app/src/features/privacy/whatLeavesItems.ts
  • app/src/pages/onboarding/Onboarding.tsx
  • app/src/pages/onboarding/steps/ContextGatheringStep.tsx
  • app/src/pages/onboarding/steps/WelcomeStep.tsx
  • app/src/pages/onboarding/steps/__tests__/ContextGatheringStep.test.tsx
  • app/src/pages/onboarding/steps/__tests__/WelcomeStep.test.tsx
  • app/src/utils/tauriCommands/aboutApp.ts
  • app/test/e2e/helpers/artifacts.ts
  • app/test/e2e/specs/agent-review.spec.ts
  • app/test/e2e/specs/login-flow.spec.ts
  • app/test/wdio.conf.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

senamakel
senamakel previously approved these changes Apr 22, 2026
jwalinsshah and others added 4 commits April 22, 2026 14:31
…surface

Adds a reusable <Button variant size> primitive (4 variants × 5 sizes) with
focus ring baked in, and an honest privacy disclosure surface so trust claims
are visible at the moments they matter.

- Button primitive matches the design handoff spec exactly, includes forwarded
  ref, defaults type=button, focus-visible ring on every interaction.
- WhatLeavesMyComputerSheet lists the five things that actually leave the
  laptop (model downloads, cloud providers, skill sync summaries, crash
  reports, account/billing/chat routing). Copy is intentionally conservative
  to not overpromise: chat routing goes through our backend, skill sync
  summaries go to the memory service.
- WhatLeavesLink is a tiny reusable trigger to drop near any network-touching
  action.
- PrivacyPanel (Settings → Privacy & Security) surfaces the same list above
  the existing analytics toggle, so the full story has a settled home.

Tests: 10 Button tests, 6 sheet/link tests. yarn compile + yarn lint clean.
ContextGatheringStep previously ran the Rust-side learning.linkedin_enrichment
pipeline silently in useEffect on mount. That is exactly the "surveillance"
shape OpenHuman is positioned against. This change gates the pipeline behind
an explicit user click and surfaces what will happen before it happens.

- Removed silent auto-run. New intro card explains what the step does, what
  will be read, and what happens if you skip ("nothing is read" — now a true
  statement).
- Two controls on the intro: primary "Start when ready" (or "Continue" when
  no Gmail to read) and ghost "Skip for now".
- WhatLeavesLink visible on both the intro and the running view.
- Body copy softened throughout to describe what is actually happening
  (third-party LinkedIn scraper, local profile file) without overclaiming.
- WelcomeStep slide 1 rewritten to handoff copy (mono eyebrow, display title,
  honest subtitle) with WhatLeavesLink in the footer. Carousel slides 2/3
  preserved. Subtitle copy is deliberately conservative: chat routing does
  go through our backend, so the line describes the routing truthfully.
- E2E login-flow spec updated: new heading markers ("Getting to know you" /
  "Reading your connected accounts" / "Context Ready"), expanded candidate
  actions to include "Skip for now" and "Start when ready". Prefers Skip so
  the real Rust enrichment pipeline stays out of E2E.

Tests: 4 WelcomeStep tests (copy, privacy link, CTA, disabled/loading);
4 ContextGatheringStep tests (user-driven gate does not auto-run, no-Gmail
branch marks skipped without RPC, Skip invokes onNext, Start fires pipeline
exactly once with correct method). Full yarn test:unit suite green
(498 passed, 2 pre-existing skips).
… WelcomeStep test

- Rebase onto upstream/main (20 commits since PR merge base)
- Resolve PrivacyPanel.tsx conflict: keep upstream capability-backed dynamic
  privacy list (PR tinyhumansai#760) rather than the static whatLeavesItems fallback —
  the dynamic system supersedes the static one
- Resolve WelcomeStep.tsx conflict: keep simplified interface from upstream
  (nextDisabled/nextLoading/nextLoadingLabel removed) plus WhatLeavesLink
  footer from this PR
- Resolve login-flow.spec.ts conflict: remove ReferralApplyStep comment
  (step was removed in upstream PR tinyhumansai#772), keep ContextGatheringStep
  user-driven gate copy from this PR
- Fix WelcomeStep.test.tsx: remove test that passes now-removed props
  (nextDisabled, nextLoading, nextLoadingLabel) — update to verify CTA
  is always enabled in simplified interface
- Apply Prettier formatting across files reformatted post-rebase
- All quality checks pass: typecheck clean, lint 0 errors, format
  unchanged, 534 unit tests passed (2 pre-existing skips)
@senamakel senamakel force-pushed the feat/frontend-overhaul branch from 9f7e43f to bd6030d Compare April 22, 2026 21:38
@senamakel senamakel merged commit 83aa016 into tinyhumansai:main Apr 22, 2026
8 of 9 checks passed
AusAgentSmith pushed a commit to AusAgentSmith/openhuman that referenced this pull request May 23, 2026
…st privacy surface (tinyhumansai#759)

Co-authored-by: Jwalin Shah <jshah1331@gmail.com>
Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants