Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
42 linesCodeBlameRaw
1/**
2 * Getting started, for the owner signed in: what the dialog reads when it
3 * is opened from a page that did not load it (Settings, the AI page), and
4 * where it saves what the person chose. `intent` dismiss (closing it or
5 * finishing it: it no longer opens by itself), skip or unskip (with
6 * `step`). Identity keeps it (`set_onboarding`); whether a step is done is
7 * never saved, only read (lib/onboarding.server.ts). Adding a provider and
8 * choosing Ask's model post to the AI page's own action instead.
9 */
10import { data } from "react-router";
11
12import { ONBOARDING_STEPS, type OnboardingStep } from "@g1t/contracts";
13
14import type { Route } from "./+types/onboarding";
15import { guideIsFor, loadOnboarding, saveOnboarding, skipStep } from "../../lib/onboarding.server";
16import { assertSameOrigin, getViewer, requireUser } from "../../lib/session.server";
17
18export async function loader({ params, context }: Route.LoaderArgs) {
19 const view = await loadOnboarding(getViewer(context), params.owner.toLowerCase());
20 if (!view) throw data(null, { status: 404 });
21 return { onboarding: view };
22}
23
24function isStep(value: unknown): value is OnboardingStep {
25 return typeof value === "string" && (ONBOARDING_STEPS as readonly string[]).includes(value);
26}
27
28export async function action({ request, params, context }: Route.ActionArgs) {
29 assertSameOrigin(request);
30 const user = requireUser(context, request);
31 const slug = params.owner.toLowerCase();
32 if (!guideIsFor(user, slug)) return data({ error: "Getting started is for the workspace's owners." }, { status: 403 });
33 const form = await request.formData();
34 const intent = form.get("intent");
35 if (intent === "dismiss") return saveOnboarding(user, slug, { dismissed: true });
36 if (intent === "skip" || intent === "unskip") {
37 const step = form.get("step");
38 if (!isStep(step)) return data({ error: "That isn't a step of Getting started." }, { status: 400 });
39 return skipStep(user, slug, step, intent === "skip");
40 }
41 return data({ error: "Nothing to do." }, { status: 400 });
42}