Feature - Onboarding route to allow users to easily create their first API Key and async or batch workload#1033
Open
aschkanAH wants to merge 16 commits into
Open
Feature - Onboarding route to allow users to easily create their first API Key and async or batch workload#1033aschkanAH wants to merge 16 commits into
aschkanAH wants to merge 16 commits into
Conversation
Adds /onboarding route shown immediately after native registration. The page renders inside the standard authenticated app shell (sidebar retained) but uses a slim header that only carries a 'Skip to Dashboard' affordance. Three interactive steps: 1. Live API key — calls the existing useCreateApiKey hook on mount so the user sees a real key (not a placeholder) and can copy it. 2. Workload runner — async vs batch toggle, browser vs CLI execution toggle, Python vs cURL language toggle. Browser mode pre-renders the payload and a Run Now button that uploads + creates a real batch via useCreateBatch / useUploadFileWithProgress while still cycling through idle → running → success on a 2.5s timer for predictable UX. CLI mode shows a 'Listening for request…' indicator that flips to success on click. Both flows redirect to /models 2s after success. 3. Team invite — POSTs the supplied email to the configured Zapier hook (no-cors, fire-and-forget) and surfaces a sent confirmation. Also fires a background 'Hello World' batch + toast on mount so users see data on the dashboard when they land. The post-signup default redirect from RegisterForm is now /onboarding; explicit ?redirect= and the server-driven onboarding_redirect_url still take priority. Co-authored-by: aschkanAH <aschkanAH@users.noreply.github.com>
mode: 'no-cors' silently downgrades Content-Type: application/json to text/plain because JSON isn't CORS-safelisted. Zapier Catch Hooks only auto-parse JSON when the request actually carries an application/json content-type, so the previous code was firing the webhook successfully but with all fields empty. Switching the body to URLSearchParams produces an application/x-www-form-urlencoded body (which IS CORS-safelisted) and which Zapier does parse into structured fields. Co-authored-by: aschkanAH <aschkanAH@users.noreply.github.com>
Replaces the hardcoded Zapier hook with VITE_INVITE_WEBHOOK_URL. The invite section is hidden entirely when the variable is unset so we don't collect emails with nowhere to send them; the submit handler also has a defensive guard for stale builds. Co-authored-by: aschkanAH <aschkanAH@users.noreply.github.com>
…gate race
Three fixes from review:
1. buildAsyncPayload, buildJsonlPayload, and the snippet generators were
interpolating the model alias into JSON / Python / cURL string
literals via raw template literals. Catalog aliases come from user-
controlled DB metadata and may legitimately contain quotes,
backslashes, or control characters, which would yield invalid JSON.
handleRunNow's JSON.parse(buildAsyncPayload(...)) would throw on such
aliases, yet the simulated 2.5s timer would still flip the UI to
'success' and redirect — falsely telling the user a workload was
queued.
Payloads are now built as objects and serialized via JSON.stringify
(JSONL/JSON cases), and code-snippet interpolations go through
escapeForLiteral which uses JSON.stringify's inner string form to
correctly escape both Python and shell-string literal special chars.
2. The CLI listener block exposed '(Click to simulate success)' to
desktop users. 'Simulate' is internal language that breaks the
illusion of the onboarding flow. Replaced with '(Click to continue)'
and updated the aria-label to match.
3. RegisterForm called navigate('/onboarding') unconditionally after
register(). When the server returns onboarding_redirect_url,
AuthProvider.checkAuthStatus has already initiated a hard navigation
via window.location.href — the new client-side push raced that and
could briefly mount the wrong route before the hard nav resolved.
We now read the just-populated current-user cache entry and skip
navigate() when an onboarding_redirect_url is present, deferring
cleanly to the server-driven redirect (matching the pre-onboarding
behaviour for that path).
Co-authored-by: aschkanAH <aschkanAH@users.noreply.github.com>
feat(dashboard): zero-friction onboarding page
Contributor
|
/build-staging |
|
Staging image |
Per growth-team revision: - 'You're ready to run at scale.' -> 'From zero to inference in seconds.' - Subheading rewritten to lead with provisioning + browser-side run. Co-authored-by: aschkanAH <aschkanAH@users.noreply.github.com>
The shadcn theme tokens for popover/border are stored as bare HSL component triplets (e.g. `0 0% 100%`), not full color values. The existing Toaster wired `--normal-bg: var(--popover)` directly, which resolves to `background: 0 0% 100%` — invalid CSS, so sonner falls back to its default semi-transparent surface and toasts render illegibly when overlaying page content (most visible on the onboarding 'Sample Batch Started' toast on top of the API key card). Wrap the tokens in `hsl(...)` so the resolved value is a valid opaque color. Co-authored-by: aschkanAH <aschkanAH@users.noreply.github.com>
fix(onboarding): hero copy revision + opaque toast background
|
/build-staging |
|
Staging image |
The background 'Hello World' batch and the Run-Now handler were both
reading from a single `modelAlias` value that fell back to a hard-coded
`medgemma-4b` while the catalog query was still loading. Because the
background effect fired immediately after auth resolved (well before
`useModels` returned), the visible payload would later re-render with
the catalog alias (e.g. 'deepseek') while the backend received
'medgemma-4b' — producing 'Model medgemma-4b has not been configured or
is not available to user' on every onboarding load in environments
without that model.
Split the alias into two values:
- displayModelAlias: always populated (real alias or placeholder) and
used only for rendering code samples so the UI is never blank.
- runnableModelAlias: undefined while the catalog is loading and when
the user has no accessible chat model. Used for outbound requests.
The background batch now waits for the catalog to resolve and bails
silently (no toast, no request) when there's no entitled chat model.
Run Now does the same in its IIFE so the simulated success timer still
fires while we skip the doomed network call.
Co-authored-by: aschkanAH <aschkanAH@users.noreply.github.com>
The previous split of displayModelAlias / runnableModelAlias still left 'medgemma-4b' visible in the rendered code samples for the brief window between mount and the useModels query resolving. Anyone reading the payload during that window would reasonably expect medgemma to be the model the backend is asked to run — exactly the divergence we set out to remove. Replace the hard-coded fallback with an obviously-non-runnable '<your-model-alias>' placeholder, and disable the Run Now button until runnableModelAlias is populated. The visible payload and the outbound payload now share a single source of truth: when there's a real alias, both reference it; when there isn't, the placeholder is shown and the button is disabled. Co-authored-by: aschkanAH <aschkanAH@users.noreply.github.com>
Previously the post-success auto-redirect always landed users on
/models — fine as a generic 'where would you like to go next' but it
hides the workload they just queued. Send them instead to the route
that will surface their job:
- /async when workloadType is 'async'
- /batches when workloadType is 'batch'
Both routes are config-gated by batches.enabled (and async further
gated by batches.async_requests.enabled), so we consult
useAuthorization().canAccessRoute and fall back to /models when the
preferred destination isn't accessible on this deployment, to avoid
ProtectedRoute bouncing the user mid-redirect.
The 'Skip to Dashboard' header button still lands on /models per the
original spec. The CLI listener path also stays on /models — that path
is the 'click to continue' simulation, not an actual workload, so
there's no specific job for the user to view.
Inline success-strip copy now reflects the destination ('Taking you to
your batch/async request…') so the redirect isn't surprising.
Co-authored-by: aschkanAH <aschkanAH@users.noreply.github.com>
Including browserSuccessRoute in the auto-redirect effect's deps caused a lost-redirect bug: if the value's identity changed during the 2s window (workloadType toggle, useAuthorization refetch race, config invalidation, …) the cleanup function ran clearTimeout, the effect re-ran, and the idempotency ref short-circuited it before a new timer could be scheduled. The user would see 'Taking you to your batch…' indefinitely without ever navigating. Move the destination into a ref that's updated on every render so the trigger effect captures the latest value at success-time without declaring a dep. Deps are now only the success triggers + navigate, none of which churn between idle and success, so the cleanup-cancel path is unreachable by construction. Co-authored-by: aschkanAH <aschkanAH@users.noreply.github.com>
fix(onboarding): harmonise outbound model alias with rendered payload
Collaborator
Author
|
/build-staging |
|
Staging image |
|
/build-staging |
|
Staging image |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a /onboarding route shown immediately after native registration. The page renders inside the existing authenticated app shell (sidebar retained) but uses a slim header that only carries a "Skip to Dashboard" affordance.
Notes:
The invite component is visible only if a zapier webhook is set in .env variables. Zapier webhook call is fire-and-forget (opaque response under no-cors); we can't detect transport failures from the browser. Move to native APIs when possible.
The "Run Now" UX intentionally simulates a 2.5s success regardless of the underlying batch outcome. If the real upload fails we log a warning but don't surface the error in the UI — the user is about to be redirected anyway, and they'll see the actual job state on /models.
Background API key creation runs on every visit to /onboarding. Combined with the "won't be shown again" copy, that's intentional for the first-visit flow but means revisiting the page for any reason will mint a new throwaway key. If we want to avoid that, follow-up work should gate this behind the same onboarding_completed_${userId} localStorage flag the auth context already uses or in the auth0 metadata.