.ts
TypeScript
(application/typescript)
// 1st-party
import type { ReactIsland } from "@ethicdevs/react-monolith";
// 3rd-party
import React from "react";
// app
import type {
  RepositoryFileDiff,
  RepositoryFileDiffChunk,
  WithThemeSchemeProp,
} from "../types";
import { AppRoute } from "../routes.defs";
import { Const } from "../const";
import { Card } from "../components/Card.styled";
import { Chip } from "../components/Chip";
import { Grid } from "../components/Grid";
import { NamedColors } from "../utils/style";
import { buildRouteLink } from "../utils/shared";
// app islands
import Code, { getThemedCodeCss } from "../islands/Code";

export interface RepositoryFilesDiffsList {
  filesDiffs: RepositoryFileDiff[];
  orgSlug: string;
  repoSlug: string;
  commitHash: string;
}

const getChunkContent = (chunk: RepositoryFileDiffChunk): string => {
  let sb = [] as string[];
  sb.push(chunk.content);
  chunk.changes.forEach((change) => sb.push(change.content));
  return `${sb.join("\n")}\n`;
};

const RepositoryFilesDiffsList: ReactIsland<
  RepositoryFilesDiffsList & WithThemeSchemeProp
> = ({ commitHash, filesDiffs, orgSlug, repoSlug, themeScheme }) => {
  let codeCounter = 0;
  return (
    <>
      {getThemedCodeCss(themeScheme)}
      <Grid.Col fluid>
        {filesDiffs.map(({ chunks, ...diff }, idx) => (
          <Card
            key={[diff.from, diff.to].join(":")}
            style={{ marginTop: idx > 0 ? 16 : 0, width: "100%", padding: 8 }}
            themeScheme={themeScheme}
          >
            <Grid.Col fluid nowrap>
              <Grid.Row fluid nowrap gap={12} alignItems={"center"}>
                {diff.from === "/dev/null" ? (
                  <Chip color={"rgb(43, 176, 90)"}>new file</Chip>
                ) : diff.to !== "/dev/null" ? (
                  <strong>{diff.from}</strong>
                ) : null}
                {diff.to !== diff.from && (
                  <>
                    {diff.to !== "/dev/null" && diff.from !== "/dev/null" && (
                      <span>{" -> "}</span>
                    )}
                    {diff.to === "/dev/null" ? (
                      <>
                        <Chip color={"rgb(215, 44, 44)"}>file deleted</Chip>
                        <strong>{diff.from}</strong>
                      </>
                    ) : (
                      <strong>{diff.to}</strong>
                    )}
                  </>
                )}
              </Grid.Row>
              <Grid.Row
                fluid
                nowrap
                alignItems={"center"}
                style={{ marginTop: 8 }}
                gap={16}
              >
                <div style={{ color: "rgb(43, 176, 90)" }}>
                  <strong>+</strong> <span>{diff.additions}</span>
                </div>
                <div style={{ color: "rgb(215, 44, 44)" }}>
                  <strong>-</strong> <span>{diff.deletions}</span>
                </div>
                <div>
                  <a
                    href={buildRouteLink(
                      AppRoute.REPOSITORY_BROWSER_WITH_PATH,
                      {
                        orgSlug,
                        repoSlug,
                        currentRef: commitHash,
                        "*": diff.to === "/dev/null" ? diff.from : diff.to,
                      }
                    )}
                  >
                    View file (current ref)
                  </a>
                  <a
                    href={buildRouteLink(
                      AppRoute.REPOSITORY_BROWSER_WITH_PATH,
                      {
                        orgSlug,
                        repoSlug,
                        currentRef: Const.PRIMARY_BRANCH_REF,
                        "*": diff.to === "/dev/null" ? diff.from : diff.to,
                      }
                    )}
                    style={{ marginLeft: 16 }}
                  >
                    View file (${Const.PRIMARY_BRANCH_REF})
                  </a>
                </div>
              </Grid.Row>
            </Grid.Col>
            <Grid.Col fluid style={{ marginTop: 8 }}>
              {chunks.map((chunk, subIdx) => (
                <div
                  data-islandid={`${Code.name}$$${codeCounter++}`}
                  key={[idx, subIdx, chunk.content].join(":")}
                  style={{ width: "100%" }}
                >
                  <Code
                    code={getChunkContent(chunk)}
                    language={"diff"}
                    themeScheme={themeScheme}
                    style={{
                      borderTopLeftRadius: subIdx === 0 ? 8 : 0,
                      borderTopRightRadius: subIdx === 0 ? 8 : 0,
                      borderBottomLeftRadius:
                        subIdx === chunks.length - 1 ? 8 : 0,
                      borderBottomRightRadius:
                        subIdx === chunks.length - 1 ? 8 : 0,
                    }}
                  />
                  {subIdx < chunks.length - 1 && (
                    <Grid.Row
                      fluid
                      alignItems={"center"}
                      style={{
                        height: 30,
                        width: "100%",
                        border: `1px solid ${NamedColors.BORDER_DEFAULT[themeScheme]}`,
                        padding: "0 10px",
                        opacity: 0.7,
                      }}
                    >
                      ...
                    </Grid.Row>
                  )}
                </div>
              ))}
            </Grid.Col>
          </Card>
        ))}
      </Grid.Col>
    </>
  );
};

RepositoryFilesDiffsList.displayName = "RepositoryFilesDiffsList";
export default RepositoryFilesDiffsList;