feat(repository): add RepositoryPullRequestCreate view/action controllers
+ 245
- 1
@@ -1,5 +1,5 @@
 {
-  "_generatedAtUnix": 1665016052550,
+  "_generatedAtUnix": 1665017412010,
   "_hashAlgorithm": "sha1",
   "_version": 2,
   "islands": {

...
@@ -113,6 +113,10 @@
       "hash": "9c254e18e9a1f3f502e4ac71639bc80caff178e5",
       "pathSource": "./app/views/repository/RepositoryForkView.tsx"
     },
+    "RepositoryPullRequestCreateView": {
+      "hash": "4fac956fc1de8340ad13b037dab93ad2ef2eca89",
+      "pathSource": "./app/views/repository/RepositoryPullRequestCreateView.tsx"
+    },
     "RepositoryPullRequestsView": {
       "hash": "c5683b936b94a3ece6412ae3cec1dabedddd3952",
       "pathSource": "./app/views/repository/RepositoryPullRequestsView.tsx"

new file
app/controllers/repository/getRepositoryPullRequestCreateView.ts
@@ -0,0 +1,42 @@
+// 1st-party
+import { ReqHandler } from "@ethicdevs/react-monolith";
+// app
+import { AppRoute, AppRoutesParams } from "../../routes";
+// app services
+import { makeOrganizationService } from "../../services/organization";
+import { makeRepositoryService } from "../../services/repository";
+// app views
+import RepositoryPullRequestCreateView, {
+  RepositoryPullRequestCreateViewProps,
+} from "../../views/repository/RepositoryPullRequestCreateView";
+
+const getRepositoryPullRequestCreateView: ReqHandler = async (
+  request,
+  reply
+) => {
+  const { orgSlug, repoSlug } =
+    request.params as AppRoutesParams[AppRoute.REPOSITORY_PULL_REQUEST_CREATE]["params"];
+
+  const orgService = makeOrganizationService({ request });
+  const repoService = makeRepositoryService({ request });
+
+  const parentOrg = await orgService.getOrganizationBySlug(orgSlug);
+  const repo = await repoService.getRepository(orgSlug, repoSlug);
+
+  if (parentOrg == null || repo == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  const reqHandler = reply.makeRequestHandler(request, reply);
+  return reqHandler<RepositoryPullRequestCreateViewProps>(
+    RepositoryPullRequestCreateView.name,
+    {
+      errorMessage: null,
+      initialValues: {},
+      parentOrg,
+      repo,
+    }
+  );
+};
+
+export default getRepositoryPullRequestCreateView;

app/controllers/repository/index.ts
@@ -5,10 +5,12 @@ import { default as getRepositoryCreateView } from "./getRepositoryCreateView";
 import { default as getRepositoryDetailsView } from "./getRepositoryDetailsView";
 import { default as getRepositoryExploreView } from "./getRepositoryExploreView";
 import { default as getRepositoryForkView } from "./getRepositoryForkView";
+import { default as getRepositoryPullRequestCreateView } from "./getRepositoryPullRequestCreateView";
 import { default as getRepositoryPullRequestsView } from "./getRepositoryPullRequestsView";
 import { default as getRepositoryShowObjectView } from "./getRepositoryShowObjectView";
 import { default as postRepositoryCreateAction } from "./postRepositoryCreateAction";
 import { default as postRepositoryForkAction } from "./postRepositoryForkAction";
+import { default as postRepositoryPullRequestCreateAction } from "./postRepositoryPullRequestCreateAction";
 
 export const RepositoryController = {
   getRepositoryBrowserView,

...
@@ -18,8 +20,10 @@ export const RepositoryController = {
   getRepositoryDetailsView,
   getRepositoryExploreView,
   getRepositoryForkView,
+  getRepositoryPullRequestCreateView,
   getRepositoryPullRequestsView,
   getRepositoryShowObjectView,
   postRepositoryCreateAction,
   postRepositoryForkAction,
+  postRepositoryPullRequestCreateAction,
 };

new file
app/controllers/repository/postRepositoryPullRequestCreateAction.ts
@@ -0,0 +1,42 @@
+// 1st-party
+import { ReqHandler } from "@ethicdevs/react-monolith";
+// app
+import { AppRoute, AppRoutesParams } from "../../routes";
+// app services
+import { makeOrganizationService } from "../../services/organization";
+import { makeRepositoryService } from "../../services/repository";
+// app views
+import RepositoryPullRequestCreateView, {
+  RepositoryPullRequestCreateViewProps,
+} from "../../views/repository/RepositoryPullRequestCreateView";
+
+const postRepositoryPullRequestCreateAction: ReqHandler = async (
+  request,
+  reply
+) => {
+  const { orgSlug, repoSlug } =
+    request.params as AppRoutesParams[AppRoute.REPOSITORY_PULL_REQUEST_CREATE]["params"];
+
+  const orgService = makeOrganizationService({ request });
+  const repoService = makeRepositoryService({ request });
+
+  const parentOrg = await orgService.getOrganizationBySlug(orgSlug);
+  const repo = await repoService.getRepository(orgSlug, repoSlug);
+
+  if (parentOrg == null || repo == null) {
+    return reply.status(404).callNotFound();
+  }
+
+  const reqHandler = reply.makeRequestHandler(request, reply);
+  return reqHandler<RepositoryPullRequestCreateViewProps>(
+    RepositoryPullRequestCreateView.name,
+    {
+      errorMessage: null,
+      initialValues: {},
+      parentOrg,
+      repo,
+    }
+  );
+};
+
+export default postRepositoryPullRequestCreateAction;

@@ -40,6 +40,8 @@ export enum AppRoute {
   REPOSITORY_EXPLORE = "repository.explore",
   REPOSITORY_FORK = "repository.fork",
   REPOSITORY_FORK_ACTION = "repository.fork.action",
+  REPOSITORY_PULL_REQUEST_CREATE = "repository.pull_request.create",
+  REPOSITORY_PULL_REQUEST_CREATE_ACTION = "repository.pull_request.create.action",
   REPOSITORY_PULL_REQUESTS = "repository.pull_requests",
   REPOSITORY_SHOW_OBJECT = "repository.show_object",
   SYNTAX_HIGHLIGHT_HIGHLIGHT_CODE_ACTION = "syntax_highlight.highlight_code.action",

...
@@ -143,6 +145,28 @@ export interface AppRoutesParams extends IRouteParams {
       target_repo_visibility: ResourceVisibility;
     };
   };
+  [AppRoute.REPOSITORY_PULL_REQUEST_CREATE]: {
+    params: {
+      orgSlug: string;
+      repoSlug: string;
+    };
+  };
+  [AppRoute.REPOSITORY_PULL_REQUEST_CREATE_ACTION]: {
+    params: {
+      orgSlug: string;
+      repoSlug: string;
+    };
+    body: {
+      summary: string;
+      description: string;
+      source_parent_org_slug: string;
+      source_repository_slug: string;
+      source_repository_from_branch: string;
+      target_parent_org_slug: string;
+      target_repository_slug: string;
+      target_repository_dest_branch: string;
+    };
+  };
   [AppRoute.REPOSITORY_PULL_REQUESTS]: {
     params: {
       orgSlug: string;

...
@@ -430,6 +454,75 @@ export const AppRoutesSchemas: Record<AppRoute, undefined | FastifySchema> = {
       },
     },
   },
+  [AppRoute.REPOSITORY_PULL_REQUEST_CREATE]: {
+    params: {
+      type: "object",
+      required: ["orgSlug", "repoSlug"],
+      additionalProperties: false,
+      properties: {
+        orgSlug: {
+          type: "string",
+        },
+        repoSlug: {
+          type: "string",
+        },
+      },
+    },
+  },
+  [AppRoute.REPOSITORY_PULL_REQUEST_CREATE_ACTION]: {
+    params: {
+      type: "object",
+      required: ["orgSlug", "repoSlug"],
+      additionalProperties: false,
+      properties: {
+        orgSlug: {
+          type: "string",
+        },
+        repoSlug: {
+          type: "string",
+        },
+      },
+    },
+    body: {
+      type: "object",
+      required: [
+        "summary",
+        "source_parent_org_slug",
+        "source_repository_slug",
+        "source_repository_from_branch",
+        "target_parent_org_slug",
+        "target_repository_slug",
+        "target_repository_dest_branch",
+      ],
+      additionalProperties: false,
+      properties: {
+        summary: {
+          type: "string",
+        },
+        description: {
+          type: "string",
+        },
+        source_parent_org_slug: {
+          type: "string",
+        },
+        source_repository_slug: {
+          type: "string",
+        },
+        source_repository_from_branch: {
+          type: "string",
+        },
+        target_parent_org_slug: {
+          type: "string",
+        },
+        target_repository_slug: {
+          type: "string",
+        },
+        target_repository_dest_branch: {
+          type: "string",
+        },
+      },
+    },
+  },
   [AppRoute.REPOSITORY_PULL_REQUESTS]: {
     params: {
       type: "object",

...
@@ -647,14 +740,34 @@ const RootAppRouter: AppRouter = () => {
           name={AppRoute.REPOSITORY_FORK}
           method={"GET"}
           path={"/:orgSlug/:repoSlug/fork"}
+          preHandler={loggedOrLoginRedirect}
           handler={RepositoryController.getRepositoryForkView}
         />
         <Router.Route
           name={AppRoute.REPOSITORY_FORK_ACTION}
           method={"POST"}
           path={"/:orgSlug/:repoSlug/fork"}
+          preHandler={loggedOrLoginRedirect}
           handler={RepositoryController.postRepositoryForkAction}
         />
+        <Router.Route
+          name={AppRoute.REPOSITORY_PULL_REQUEST_CREATE}
+          method={"GET"}
+          path={"/:orgSlug/:repoSlug/pulls/new"}
+          schema={AppRoutesSchemas[AppRoute.REPOSITORY_PULL_REQUEST_CREATE]}
+          preHandler={loggedOrLoginRedirect}
+          handler={RepositoryController.getRepositoryPullRequestCreateView}
+        />
+        <Router.Route
+          name={AppRoute.REPOSITORY_PULL_REQUEST_CREATE_ACTION}
+          method={"POST"}
+          path={"/:orgSlug/:repoSlug/pulls/new"}
+          schema={
+            AppRoutesSchemas[AppRoute.REPOSITORY_PULL_REQUEST_CREATE_ACTION]
+          }
+          preHandler={loggedOrLoginRedirect}
+          handler={RepositoryController.postRepositoryPullRequestCreateAction}
+        />
         <Router.Route
           name={AppRoute.REPOSITORY_PULL_REQUESTS}
           method={"GET"}

new file
app/views/repository/RepositoryPullRequestCreateView.tsx
@@ -0,0 +1,39 @@
+// 1st-party
+import type { ReactView } from "@ethicdevs/react-monolith";
+// 3rd-party
+import React from "react";
+// generated via script[generate:prisma]
+import type { Organization, PullRequest, Repository } from "@prisma/client";
+// app
+import type { CommonProps } from "../../types";
+import { Grid, IslandWrapper, Layout, PageWrapper } from "../../components";
+// app islands
+import RepositoryHero from "../../islands/RepositoryHero";
+
+export interface RepositoryPullRequestCreateViewProps extends CommonProps {
+  errorMessage?: string | null;
+  initialValues?: PullRequest;
+  parentOrg: Organization;
+  repo: Repository;
+}
+
+const RepositoryPullRequestCreateView: ReactView<RepositoryPullRequestCreateViewProps> =
+  ({ commonProps, parentOrg, repo }) => {
+    return (
+      <Layout {...commonProps}>
+        <PageWrapper>
+          <IslandWrapper data-islandid={`${RepositoryHero.name}$$0`}>
+            <RepositoryHero
+              parentOrg={parentOrg}
+              path={`Pull Requests / New`}
+              repo={repo}
+            />
+          </IslandWrapper>
+          <Grid.Col fluid style={{ marginTop: 32 }}></Grid.Col>
+        </PageWrapper>
+      </Layout>
+    );
+  };
+
+RepositoryPullRequestCreateView.displayName = "RepositoryPullRequestCreateView";
+export default RepositoryPullRequestCreateView;