import { createFileRoute, useNavigate } from "@tanstack/react-router"; import { z } from "zod"; import { deleteOwnerValue, getOwnerActionsConfig, listActionsOwners, setOwnerValue } from "~/fns/action-config"; import { useAction } from "~/hooks/use-action"; import { ConfigValueList } from "~/components/ConfigValueList"; import { SelectField, TextField } from "~/ui/Field"; import { Heading } from "~/ui/Heading"; const VISIBILITY = [ { value: "all", label: "All repositories" }, { value: "private", label: "Private repositories" }, { value: "selected", label: "Selected repositories" }, ] as const; const visibilitySchema = z.enum(["all", "private", "selected"]); export const Route = createFileRoute("/settings/actions")({ validateSearch: z.object({ owner: z.string().optional() }), loaderDeps: ({ search }) => search, loader: async ({ deps }) => { const owners = await listActionsOwners(); const owner = deps.owner && owners.includes(deps.owner) ? deps.owner : owners[0]; return { owners, config: await getOwnerActionsConfig({ data: { owner } }) }; }, component: OwnerActionsPage, }); function describe(visibility: string, repos: string[]): string { if (visibility === "selected") return repos.length ? `Repos: ${repos.join(", ")}` : "No repositories"; return visibility === "private" ? "Private repositories" : "All repositories"; } function AccessFields({ repos, listId }: { repos: string[]; listId: string }) { return (
{repos.map((repo) => (
); } function OwnerActionsPage() { const { owners, config } = Route.useLoaderData(); const navigate = useNavigate(); const save = useAction(setOwnerValue); const remove = useAction(deleteOwnerValue); const saver = (kind: "secret" | "variable") => async (name: string, value: string, form: FormData) => { const visibility = visibilitySchema.parse(form.get("visibility") ?? "all"); const repos = String(form.get("repos") ?? "") .split(",") .map((repo) => repo.trim()) .filter(Boolean); return Boolean(await save.run({ data: { owner: config.owner, kind, name, value, visibility, repos } })); }; return (
Actions secrets and variables

Shared by repositories owned by this account, with per-value repository access policies.

{owners.length > 1 && ( ({ value: owner, label: owner }))} onValueChange={(value) => navigate({ to: "/settings/actions", search: { owner: value } })} /> )}
({ ...secret, detail: describe(secret.visibility, secret.repos), keep: { visibility: secret.visibility, repos: secret.repos.join(", ") }, }))} pending={save.pending} error={save.error ?? remove.error} onSave={saver("secret")} onDelete={(name) => remove.run({ data: { owner: config.owner, kind: "secret", name } })} extraFields={} /> ({ ...variable, detail: describe(variable.visibility, variable.repos), keep: { visibility: variable.visibility, repos: variable.repos.join(", ") }, }))} pending={save.pending} error={save.error ?? remove.error} onSave={saver("variable")} onDelete={(name) => remove.run({ data: { owner: config.owner, kind: "variable", name } })} extraFields={} />
); }