127 lines
3.9 KiB
TypeScript
127 lines
3.9 KiB
TypeScript
import { Input } from "@kandev/ui/input";
|
|
import { Label } from "@kandev/ui/label";
|
|
import { RadioGroup, RadioGroupItem } from "@kandev/ui/radio-group";
|
|
import { Textarea } from "@kandev/ui/textarea";
|
|
import type { GitHubAppOwnerType, GitHubAppVisibility } from "@/lib/types/github";
|
|
import type { AppSetupErrors } from "./github-app-onboarding-model";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
export type GitHubAppImportValues = {
|
|
displayName: string;
|
|
ownerLogin: string;
|
|
ownerType: GitHubAppOwnerType;
|
|
publicBaseUrl: string;
|
|
visibility: GitHubAppVisibility;
|
|
appId: string;
|
|
clientId: string;
|
|
clientSecret: string;
|
|
privateKey: string;
|
|
webhookSecret: string;
|
|
slug: string;
|
|
};
|
|
|
|
type Update = (name: keyof GitHubAppImportValues, value: string) => void;
|
|
|
|
export function GitHubAppImportIdentityFields({
|
|
values,
|
|
errors,
|
|
update,
|
|
}: {
|
|
values: GitHubAppImportValues;
|
|
errors: AppSetupErrors;
|
|
update: Update;
|
|
}) {
|
|
const { t } = useTranslation();
|
|
return (
|
|
<div className="space-y-3">
|
|
<div className="grid gap-3 sm:grid-cols-2">
|
|
<Field label={t("github:nameInKandev")} error={errors.displayName}>
|
|
<Input
|
|
value={values.displayName}
|
|
onChange={(e) => update("displayName", e.target.value)}
|
|
/>
|
|
</Field>
|
|
<Field label={t("github:githubAppSlug")} error={errors.slug}>
|
|
<Input value={values.slug} onChange={(e) => update("slug", e.target.value)} />
|
|
</Field>
|
|
<Field label={t("github:githubOwnerLogin")} error={errors.ownerLogin}>
|
|
<Input value={values.ownerLogin} onChange={(e) => update("ownerLogin", e.target.value)} />
|
|
</Field>
|
|
</div>
|
|
<RadioGroup
|
|
value={values.ownerType}
|
|
onValueChange={(value) => update("ownerType", value)}
|
|
className="flex min-h-11 flex-wrap items-center gap-5"
|
|
>
|
|
<Label className="flex cursor-pointer items-center gap-2">
|
|
<RadioGroupItem value="Organization" /> {t("github:organization")}
|
|
</Label>
|
|
<Label className="flex cursor-pointer items-center gap-2">
|
|
<RadioGroupItem value="User" /> {t("github:personalAccount")}
|
|
</Label>
|
|
</RadioGroup>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function GitHubAppImportSecretFields({
|
|
values,
|
|
errors,
|
|
update,
|
|
}: {
|
|
values: GitHubAppImportValues;
|
|
errors: AppSetupErrors;
|
|
update: Update;
|
|
}) {
|
|
const { t } = useTranslation();
|
|
// Keys are the value/error field names; only the labels are copy. Resolved
|
|
// here rather than at module scope so they follow a locale switch.
|
|
const labels = {
|
|
appId: t("github:appId"),
|
|
clientId: t("github:clientId"),
|
|
clientSecret: t("github:clientSecret"),
|
|
webhookSecret: t("github:webhookSecret"),
|
|
} as const;
|
|
return (
|
|
<div className="grid gap-3 sm:grid-cols-2">
|
|
{(Object.keys(labels) as (keyof typeof labels)[]).map((name) => (
|
|
<Field key={name} label={labels[name]} error={errors[name]}>
|
|
<Input
|
|
type={name.includes("Secret") || name === "webhookSecret" ? "password" : "text"}
|
|
autoComplete="off"
|
|
value={values[name]}
|
|
onChange={(event) => update(name, event.target.value)}
|
|
/>
|
|
</Field>
|
|
))}
|
|
<div className="sm:col-span-2">
|
|
<Field label={t("github:privateKeyPem", { extension: ".pem" })} error={errors.privateKey}>
|
|
<Textarea
|
|
className="min-h-28 font-mono text-xs"
|
|
value={values.privateKey}
|
|
onChange={(event) => update("privateKey", event.target.value)}
|
|
/>
|
|
</Field>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function Field({
|
|
label,
|
|
error,
|
|
children,
|
|
}: {
|
|
label: string;
|
|
error?: string;
|
|
children: React.ReactNode;
|
|
}) {
|
|
return (
|
|
<Label className="block space-y-1.5">
|
|
<span>{label}</span>
|
|
{children}
|
|
{error && <span className="block text-xs font-normal text-destructive">{error}</span>}
|
|
</Label>
|
|
);
|
|
}
|