import type { ReactIsland } from "@ethicdevs/react-monolith";
import React from "react";
import type { Organization, Repository } from "@prisma/client";
import type { RepositoryForkedFromRepoMeta } from "../types";
import { Grid } from "../components/Grid";
export enum PullRequestFormState {
CONFIGURE = "configure",
COMPARE = "compare",
DETAILS = "input_details",
ERROR = "error",
}
export interface RepositoryPullRequestCreateFormPropsCommon {
errorMessage?: string | null;
}
export interface RepositoryPullRequestTarget {
parentOrg: Organization;
repo: Repository;
branch: string;
}
export type RepositoryPullRequestCreateFormPropsByState<
S extends PullRequestFormState = PullRequestFormState
> = S extends PullRequestFormState.CONFIGURE
? {
source: {
branches: string[];
parentOrg: Organization;
repo: Repository;
isFork: boolean;
forkedFromRepoMetas?: RepositoryForkedFromRepoMeta;
};
initialTarget?: RepositoryPullRequestTarget;
}
: S extends PullRequestFormState.COMPARE
? {
source: RepositoryPullRequestTarget;
target: RepositoryPullRequestTarget;
}
: S extends PullRequestFormState.DETAILS
? {
canCurrentUserSubmitPullRequest: boolean;
}
: S extends PullRequestFormState.ERROR
? {
errorMessage: string;
}
: never;
export type RepositoryPullRequestCreateFormVariant =
| {
state: PullRequestFormState.CONFIGURE;
data: RepositoryPullRequestCreateFormPropsByState<PullRequestFormState.CONFIGURE>;
}
| {
state: PullRequestFormState.COMPARE;
data: RepositoryPullRequestCreateFormPropsByState<PullRequestFormState.COMPARE>;
}
| {
state: PullRequestFormState.DETAILS;
data: RepositoryPullRequestCreateFormPropsByState<PullRequestFormState.DETAILS>;
}
| {
state: PullRequestFormState.ERROR;
data: RepositoryPullRequestCreateFormPropsByState<PullRequestFormState.ERROR>;
};
export interface RepositoryPullRequestCreateFormProps
extends RepositoryPullRequestCreateFormPropsCommon {
variant: RepositoryPullRequestCreateFormVariant;
}
const isConfigureState = (
s: PullRequestFormState
): s is PullRequestFormState.CONFIGURE =>
typeof s !== "undefined" && s != null && s === PullRequestFormState.CONFIGURE;
const isConfigureStateData = (
s: PullRequestFormState,
i: unknown
): i is RepositoryPullRequestCreateFormPropsByState<PullRequestFormState.CONFIGURE> =>
typeof i !== "undefined" && i != null && s === PullRequestFormState.CONFIGURE;
const isCompareState = (
s: PullRequestFormState
): s is PullRequestFormState.COMPARE =>
typeof s !== "undefined" && s != null && s === PullRequestFormState.COMPARE;
const isCompareStateData = (
s: PullRequestFormState,
i: unknown
): i is RepositoryPullRequestCreateFormPropsByState<PullRequestFormState.COMPARE> =>
typeof i !== "undefined" && i != null && s === PullRequestFormState.COMPARE;
const isDetailsState = (
s: PullRequestFormState
): s is PullRequestFormState.DETAILS =>
typeof s !== "undefined" && s != null && s === PullRequestFormState.DETAILS;
const isDetailsStateData = (
s: PullRequestFormState,
i: unknown
): i is RepositoryPullRequestCreateFormPropsByState<PullRequestFormState.DETAILS> =>
typeof i !== "undefined" && i != null && s === PullRequestFormState.DETAILS;
const isErrorState = (
s: PullRequestFormState
): s is PullRequestFormState.ERROR =>
typeof s !== "undefined" && s != null && s === PullRequestFormState.ERROR;
const isErrorStateData = (
s: PullRequestFormState,
i: unknown
): i is RepositoryPullRequestCreateFormPropsByState<PullRequestFormState.ERROR> =>
typeof i !== "undefined" && i != null && s === PullRequestFormState.ERROR;
const RepositoryPullRequestCreateForm: ReactIsland<RepositoryPullRequestCreateFormProps> =
({ variant: { state, data } }) => {
if (isConfigureState(state) && isConfigureStateData(state, data)) {
return (
<Grid.Col fluid nowrap>
<h1>Configure input and output (org, repo, branch)</h1>
<form
method={"POST"}
action={`/${data.source.parentOrg.slug}/${data.source.repo.slug}/pulls/new`}
>
<input type={"hidden"} name={"state_from"} value={state} />
<input
type={"hidden"}
name={"state_dest"}
value={PullRequestFormState.COMPARE}
/>
<input
type={"hidden"}
name={"source_parent_org_slug"}
value={data.source.parentOrg.slug}
/>
<input
type={"hidden"}
name={"source_repository_slug"}
value={data.source.repo.slug}
/>
<div>
<span>Source:</span>
</div>
<input
disabled
type={"text"}
name={"source_parent_org_display_name"}
value={
data.source.parentOrg.displayName || data.source.parentOrg.slug
}
/>
{" / "}
<input
disabled
type={"text"}
name={"source_repository_display_name"}
value={data.source.repo.displayName || data.source.repo.slug}
/>
{" / "}
<select name={"source_repository_from_branch"}>
{data.source.branches.map((branch, idx) => (
<option key={[branch, idx].join(":")} value={branch}>
{branch}
</option>
))}
</select>
{}
<div>
<span>Target:</span>
</div>
<input
disabled
type={"text"}
name={"target_parent_org_display_name"}
value={
data.initialTarget?.parentOrg.displayName ||
data.initialTarget?.parentOrg.slug ||
data.source.parentOrg.displayName ||
data.source.parentOrg.slug
}
/>
{" / "}
<input
disabled
type={"text"}
name={"target_repository_display_name"}
value={
data.initialTarget?.repo.displayName ||
data.initialTarget?.repo.slug ||
data.source.repo.displayName ||
data.source.repo.slug
}
/>
{" / "}
<select
name={"target_repository_from_branch"}
defaultValue={
data.initialTarget != null
? data.initialTarget.branch
: data.source.branches.length >= 1
? data.source.branches[0]
: undefined
}
>
{data.initialTarget != null && (
<option
key={data.initialTarget.branch}
value={data.initialTarget.branch}
>
{data.initialTarget.branch}
</option>
)}
{data.source.branches.map((branch, idx) => (
<option key={[branch, idx].join(":")} value={branch}>
{branch}
</option>
))}
</select>
<button type={"submit"}>Go to COMPARE step</button>
</form>
<div>
<pre>
<code>{JSON.stringify(data, null, 2)}</code>
</pre>
</div>
</Grid.Col>
);
}
if (isCompareState(state) && isCompareStateData(state, data)) {
return (
<Grid.Col fluid nowrap>
<h1>Compare input and output (org, repo, branch)</h1>
<form
method={"POST"}
action={`/${data.source.parentOrg.slug}/${data.source.repo.slug}/pulls/new`}
>
<input type={"hidden"} name={"state_from"} value={state} />
<input
type={"hidden"}
name={"state_dest"}
value={PullRequestFormState.DETAILS}
/>
<button type={"submit"}>Go to DETAILS step</button>
</form>
<div>
<pre>
<code>{JSON.stringify(data, null, 2)}</code>
</pre>
</div>
</Grid.Col>
);
}
if (isDetailsState(state) && isDetailsStateData(state, data)) {
return (
<Grid.Col fluid nowrap>
<h1>Add details about the Pull Request:</h1>
<form
method={"POST"}
>
<input type={"hidden"} name={"state_from"} value={state} />
<button type={"submit"}>Submit the Pull Request</button>
</form>
<div>
<pre>
<code>{JSON.stringify(data, null, 2)}</code>
</pre>
</div>
</Grid.Col>
);
}
if (isErrorState(state) && isErrorStateData(state, data)) {
const { errorMessage } = data;
return (
<Grid.Col fluid nowrap>
<h1>Woops, an error occurred:</h1>
<div>{errorMessage}</div>
</Grid.Col>
);
}
return null;
};
RepositoryPullRequestCreateForm.displayName = "RepositoryPullRequestCreateForm";
export default RepositoryPullRequestCreateForm;