.ts
TypeScript
(application/typescript)
// 1st-party
import type { ReactView } from "@ethicdevs/react-monolith";
// 3rd-party
import React from "react";
// generated via script[generate:prisma]
import type { Organization, PullRequest, User } from "@prisma/client";
// app
import type {
  CommonProps,
  RepositoryFileDiff,
  RepositoryObject,
  RepositoryWithForkedFromRepo,
} from "../../types";
import { AppRoute } from "../../routes.defs";
import { buildRouteLink } from "../../utils/shared";
import {
  Card,
  Grid,
  InlineCode,
  IslandWrapper,
  Layout,
  MarkdownToJsx,
  PageWrapper,
} from "../../components";
// app islands
import RepositoryFilesDiffsList from "../../islands/RepositoryFilesDiffsList";
import RepositoryHero from "../../islands/RepositoryHero";

export interface RepositoryPullRequestDetailsViewProps extends CommonProps {
  filesDiffs: RepositoryFileDiff[];
  lastCommit: RepositoryObject | null;
  pullRequest: PullRequest;
  pullRequestAuthor: User;
  sourceParentOrg: Organization;
  sourceRepo: RepositoryWithForkedFromRepo;
  targetParentOrg: Organization;
  targetRepo: RepositoryWithForkedFromRepo;
  isCurrentUserAllowedToMerge?: boolean;
}

const RepositoryPullRequestDetailsView: ReactView<RepositoryPullRequestDetailsViewProps> =
  ({
    commonProps,
    filesDiffs,
    lastCommit,
    pullRequest: pr,
    pullRequestAuthor: prAuthor,
    sourceParentOrg,
    sourceRepo,
    targetParentOrg: parentOrg,
    targetRepo: repo,
    isCurrentUserAllowedToMerge = false,
  }) => {
    return (
      <Layout {...commonProps}>
        <PageWrapper>
          <IslandWrapper data-islandid={`${RepositoryHero.name}$$0`}>
            <RepositoryHero
              forkedFromRepo={repo.forkedFromRepo}
              forksCount={repo.forks.length}
              parentOrg={parentOrg}
              path={`Pull Request / ${pr.uid}`}
              repo={repo}
            />
          </IslandWrapper>
          <Grid.Col fluid style={{ marginTop: 32 }}>
            <Grid.Col key={pr.id} fluid>
              <span>
                <InlineCode themeScheme={commonProps.themeScheme}>
                  {`[${pr.state}]`}
                </InlineCode>
              </span>
              <h1 style={{ margin: 0, marginTop: 8 }}>
                #{pr.uid} - {pr.summary}
              </h1>
              <span style={{ opacity: 0.67, marginTop: 8 }}>
                <a
                  href={buildRouteLink(
                    AppRoute.USER_DETAILS,
                    {
                      username: prAuthor.username,
                    },
                    { encodeURIComponent: false }
                  )}
                >
                  {prAuthor.displayName || prAuthor.username}
                </a>
              </span>
              <span style={{ opacity: 0.67, marginTop: 8 }}>
                {"wants to merge branch "}
                <InlineCode themeScheme={commonProps.themeScheme}>
                  {pr.sourceBranch}
                </InlineCode>
                {" from repository "}
                <InlineCode themeScheme={commonProps.themeScheme}>
                  {`${sourceParentOrg.slug}/${sourceRepo.slug}`}
                </InlineCode>
                {" (source) "}
              </span>
              <span style={{ opacity: 0.67, marginTop: 8 }}>
                {" into branch "}
                <InlineCode themeScheme={commonProps.themeScheme}>
                  {pr.targetBranch}
                </InlineCode>
                {" of repository "}
                <InlineCode themeScheme={commonProps.themeScheme}>
                  {`${parentOrg.slug}/${repo.slug}`}
                </InlineCode>
                {" (target) "}
              </span>
              <Grid.Row
                fluid
                alignItems={"center"}
                style={{ opacity: 0.67, marginTop: 8 }}
              >
                {new Date(pr.createdAt).getTime() <=
                  new Date(pr.updatedAt).getTime() && (
                  <span>
                    opened on {new Date(pr.createdAt).toLocaleString()}
                  </span>
                )}
                {((pr.closedAt == null &&
                  new Date(pr.updatedAt).getTime() >
                    new Date(pr.createdAt).getTime()) ||
                  (pr.closedAt != null &&
                    new Date(pr.updatedAt).getTime() <
                      new Date(pr.closedAt).getTime())) && (
                  <span>
                    updated on {new Date(pr.updatedAt).toLocaleString()}
                  </span>
                )}
                {pr.closedAt != null && (
                  <span>
                    closed on
                    {new Date(pr.closedAt).toLocaleString()}
                  </span>
                )}
              </Grid.Row>
            </Grid.Col>
            <Grid.Col fluid style={{ marginTop: 32 }}>
              <Grid.Row fluid>
                <Grid.Col fluid>
                  <a
                    href={buildRouteLink(
                      AppRoute.REPOSITORY_PULL_REQUEST_UPDATE_ACTION,
                      {
                        orgSlug: parentOrg.slug,
                        repoSlug: repo.slug,
                        pullUid: pr.uid,
                      }
                    )}
                  >
                    Edit PR
                  </a>
                  <a
                    href={buildRouteLink(
                      AppRoute.REPOSITORY_PULL_REQUEST_DELETE_ACTION,
                      {
                        orgSlug: parentOrg.slug,
                        repoSlug: repo.slug,
                        pullUid: pr.uid,
                      }
                    )}
                  >
                    Delete PR
                  </a>
                </Grid.Col>
                {isCurrentUserAllowedToMerge && (
                  <Grid.Col>
                    <form
                      method={"POST"}
                      action={buildRouteLink(
                        AppRoute.REPOSITORY_PULL_REQUEST_MERGE_ACTION,
                        {
                          orgSlug: parentOrg.slug,
                          repoSlug: repo.slug,
                          pullUid: pr.uid,
                        }
                      )}
                    >
                      <Grid.Row fluid nowrap>
                        <input
                          type={"text"}
                          name={"merge_summary"}
                          placeholder={
                            "Enter a short description of the merged code..."
                          }
                        />
                        <textarea
                          name={"merge_message"}
                          placeholder={
                            "Describe what this merge will bring when merged in target repository..."
                          }
                        ></textarea>
                        <button type={"submit"} name={"merge_default"}>
                          Merge
                        </button>
                        <button type={"submit"} name={"merge_squash"}>
                          Merge w/ Squash
                        </button>
                        <button type={"submit"} name={"merge_rebase"}>
                          Merge w/ Rebase
                        </button>
                      </Grid.Row>
                    </form>
                  </Grid.Col>
                )}
              </Grid.Row>
            </Grid.Col>
            <Grid.Col fluid style={{ marginTop: 24 }}>
              <Card
                style={{ width: "100%" }}
                themeScheme={commonProps.themeScheme}
              >
                <MarkdownToJsx
                  markdown={
                    pr.textMd == null || pr.textMd.trim() === ""
                      ? "> &lt;no_description_yet /&gt;"
                      : pr.textMd
                  }
                  themeScheme={commonProps.themeScheme}
                />
              </Card>
            </Grid.Col>
            <Grid.Col
              fluid
              data-islandid={`${RepositoryFilesDiffsList.name}$$0`}
              style={{ marginTop: 24 }}
            >
              <RepositoryFilesDiffsList
                filesDiffs={filesDiffs}
                themeScheme={commonProps.themeScheme}
                orgSlug={parentOrg.slug}
                repoSlug={repo.slug}
                commitHash={lastCommit != null ? lastCommit.commit : "HEAD"}
              />
            </Grid.Col>
          </Grid.Col>
        </PageWrapper>
      </Layout>
    );
  };

RepositoryPullRequestDetailsView.displayName =
  "RepositoryPullRequestDetailsView";
export default RepositoryPullRequestDetailsView;