feat(pipelines): add PipelinesView
+ 274
- 27
app/views/pipelines/PipelinesView.tsx
@@ -2,41 +2,288 @@
 import type { ReactView } from "@ethicdevs/react-monolith";
 // 3rd-party
 import React from "react";
-// generated via script[prisma:generate]
-import type { Pipeline } from "@prisma/client";
+// generated via script[generate:prisma]
+import type { Organization, Pipeline } from "@prisma/client";
 // app
-import type { CommonProps } from "../../types";
-// import { AppRoute } from "../../routes.defs";
+import type { CommonProps, RepositoryWithForkedFromRepo } from "../../types";
+import { AppRoute } from "../../routes.defs";
+import { Card } from "../../components/Card.styled";
+import { Chip } from "../../components/Chip";
+import { Grid } from "../../components/Grid";
+import { Layout } from "../../components/Layout";
+import { PageWrapper } from "../../components/PageWrapper";
+import { buildRouteLink } from "../../utils/shared";
+import { Colors, NamedColors } from "../../utils/style";
+// app islands
+import { IslandWrapper } from "../../components/IslandWrapper.styled";
+import RepositoryHero from "../../islands/RepositoryHero";
 
-export interface PipelinesViewProps extends CommonProps {
+type PipelinesFilter = "all" | "pending" | "running" | "failed" | "canceled";
+
+export interface RepositoryPipelinesViewProps extends CommonProps {
+  parentOrg: Organization;
   pipelines: Pipeline[];
-  orgSlug: string;
-  repoSlug: string;
+  repo: RepositoryWithForkedFromRepo;
+  pipelinesFilter?: PipelinesFilter;
 }
 
-const PipelinesView: ReactView<PipelinesViewProps> = ({
-  // commonProps,
+const RepositoryPipelinesView: ReactView<RepositoryPipelinesViewProps> = ({
+  commonProps,
+  parentOrg,
   pipelines,
-  orgSlug,
-  repoSlug,
+  repo,
+  pipelinesFilter = "success",
 }) => {
   return (
-    <div>
-      <h2>
-        Pipelines for {orgSlug}/{repoSlug}
-      </h2>
-      <ul>
-        {pipelines.map((p) => (
-          <li key={p.id}>
-            <span>
-              {p.name ?? `Pipeline ${p.id}`} — status: {p.status ?? "unknown"}
-            </span>
-          </li>
-        ))}
-      </ul>
-    </div>
+    <Layout
+      {...commonProps}
+      showDrawerPrimary
+      orgSlug={parentOrg.slug}
+      repoSlug={repo.slug}
+    >
+      <PageWrapper>
+        <IslandWrapper data-islandid={`${RepositoryHero.name}$$0`}>
+          <RepositoryHero
+            themeScheme={commonProps.themeScheme}
+            forkedFromRepo={repo.forkedFromRepo}
+            forksCount={repo.forks.length}
+            parentOrg={parentOrg}
+            path={`Pipelines`}
+            repo={repo}
+            showForkButton={false}
+            showNewButton
+            newButtonText={"Trigger Pipeline"}
+            // newButtonText={
+            //   <>
+            //     <span>New Pull Request</span>
+            //     <GitPullIcon
+            //       color={Colors.WHITE_01}
+            //       size={24}
+            //     />
+            //   </>
+            // }
+            newButtonUrl={buildRouteLink(
+              AppRoute.REPOSITORY_PIPELINE_TRIGGER_ACTION,
+              {
+                orgSlug: parentOrg.slug,
+                repoSlug: repo.slug,
+                pipelineId: "", // @fixme: ???
+              },
+            )}
+          />
+        </IslandWrapper>
+        <Grid.Col
+          fluid
+          style={{
+            padding: "12px 0",
+            borderBottom: `1px solid ${NamedColors.BORDER_DEFAULT[commonProps.themeScheme]}`,
+          }}
+        >
+          <Grid.Row
+            fluid
+            alignItems={"center"}
+            gap={12}
+            style={{ padding: "0 8px" }}
+          >
+            <a
+              style={{
+                fontWeight: pipelinesFilter === "all" ? "bold" : "normal",
+                textDecoration:
+                  pipelinesFilter === "all" ? "underline" : "none",
+              }}
+              href={`/${parentOrg.slug}/${repo.slug}/pipelines?filter=${
+                "all" as PipelinesFilter
+              }`}
+            >
+              <Grid.Row nowrap gap={8} alignItems={"center"}>
+                <span>All</span>
+                <Chip themeScheme={commonProps.themeScheme}>
+                  {commonProps.layoutCounters!.pullsTotal}
+                </Chip>
+              </Grid.Row>
+            </a>
+            <a
+              style={{
+                fontWeight: pipelinesFilter === "passed" ? "bold" : "normal",
+                textDecoration:
+                  pipelinesFilter === "passed" ? "underline" : "none",
+              }}
+              href={`/${parentOrg.slug}/${repo.slug}/pipelines?filter=${
+                "passed" as PipelinesFilter
+              }`}
+            >
+              <Grid.Row nowrap gap={8} alignItems={"center"}>
+                <span>Passed!</span>
+                <Chip themeScheme={commonProps.themeScheme}>
+                  {commonProps.layoutCounters!.pullsOpen}
+                </Chip>
+              </Grid.Row>
+            </a>
+            <a
+              style={{
+                fontWeight: pipelinesFilter === "pending" ? "bold" : "normal",
+                textDecoration:
+                  pipelinesFilter === "pending" ? "underline" : "none",
+              }}
+              href={`/${parentOrg.slug}/${repo.slug}/pipelines?filter=${
+                "pending" as PipelinesFilter
+              }`}
+            >
+              <Grid.Row nowrap gap={8} alignItems={"center"}>
+                <span>Pending</span>
+                <Chip themeScheme={commonProps.themeScheme}>
+                  {commonProps.layoutCounters!.pullsMerged}
+                </Chip>
+              </Grid.Row>
+            </a>
+            <a
+              style={{
+                fontWeight: pipelinesFilter === "running" ? "bold" : "normal",
+                textDecoration:
+                  pipelinesFilter === "running" ? "underline" : "none",
+              }}
+              href={`/${parentOrg.slug}/${repo.slug}/pipelines?filter=${
+                "running" as PipelinesFilter
+              }`}
+            >
+              <Grid.Row nowrap gap={8} alignItems={"center"}>
+                <span>Closed</span>
+                <Chip themeScheme={commonProps.themeScheme}>
+                  {commonProps.layoutCounters!.pullsClosed}
+                </Chip>
+              </Grid.Row>
+            </a>
+            <a
+              style={{
+                fontWeight: pipelinesFilter === "failed" ? "bold" : "normal",
+                textDecoration:
+                  pipelinesFilter === "failed" ? "underline" : "none",
+              }}
+              href={`/${parentOrg.slug}/${repo.slug}/pipelines?filter=${
+                "failed" as PipelinesFilter
+              }`}
+            >
+              <Grid.Row nowrap gap={8} alignItems={"center"}>
+                <span>Failed</span>
+                <Chip themeScheme={commonProps.themeScheme}>
+                  {commonProps.layoutCounters!.pullsClosed}
+                </Chip>
+              </Grid.Row>
+            </a>
+            <a
+              style={{
+                fontWeight: pipelinesFilter === "canceled" ? "bold" : "normal",
+                textDecoration:
+                  pipelinesFilter === "canceled" ? "underline" : "none",
+              }}
+              href={`/${parentOrg.slug}/${repo.slug}/pipelines?filter=${
+                "canceled" as PipelinesFilter
+              }`}
+            >
+              <Grid.Row nowrap gap={8} alignItems={"center"}>
+                <span>Canceled</span>
+                <Chip themeScheme={commonProps.themeScheme}>
+                  {commonProps.layoutCounters!.pullsClosed}
+                </Chip>
+              </Grid.Row>
+            </a>
+          </Grid.Row>
+        </Grid.Col>
+        <Grid.Col fluid gap={4} style={{ marginTop: 12 }}>
+          {pipelines != null && pipelines.length >= 1 ? (
+            pipelines.map((pipeline) => (
+              <Card
+                key={pipeline.id}
+                themeScheme={commonProps.themeScheme}
+                style={{ width: "100%", padding: 8 }}
+              >
+                <Grid.Col fluid>
+                  <a
+                    style={{ width: "100%" }}
+                    href={buildRouteLink(AppRoute.REPOSITORY_PIPELINE_DETAILS, {
+                      orgSlug: parentOrg.slug,
+                      repoSlug: repo.slug,
+                      pipelineId: pipeline.id,
+                    })}
+                  >
+                    <Grid.Row fluid alignItems={"center"} gap={4}>
+                      <span>id: {pipeline.id}</span>
+                      <span>&bull;</span>
+                      <span style={{ flex: 1 }}>{pipeline.name}</span>
+                      <Chip
+                        themeScheme={commonProps.themeScheme}
+                        color={
+                          {
+                            PENDING: Colors.PRIMARY_01,
+                            RUNNING: Colors.CYAN_01,
+                            PASSED: Colors.GREEN_01,
+                            FAILED: Colors.RED_01,
+                            CANCELED: Colors.BLACK_01,
+                          }[pipeline.status]
+                        }
+                      >
+                        {
+                          {
+                            PENDING: "Pending",
+                            RUNNING: "Running",
+                            PASSED: "Passed",
+                            FAILED: "Failed",
+                            CANCELED: "Canceled",
+                          }[pipeline.status]
+                        }
+                      </Chip>
+                    </Grid.Row>
+                  </a>
+                  <Grid.Row
+                    fluid
+                    nowrap
+                    gap={8}
+                    alignItems={"center"}
+                    style={{ opacity: 0.67 }}
+                  >
+                    triggered by
+                    <Chip
+                      themeScheme={commonProps.themeScheme}
+                      style={{ textTransform: "none" }}
+                    >
+                      <code>{""}</code>
+                    </Chip>
+                  </Grid.Row>
+                </Grid.Col>
+              </Card>
+            ))
+          ) : (
+            <Grid.Col
+              fluid
+              nowrap
+              justifyContent={"center"}
+              alignItems={"center"}
+              style={{ minHeight: "70vh" }}
+            >
+              <h1 style={{ margin: 0 }}>No Pull Request Yet</h1>
+              <p style={{ maxWidth: "62%", textAlign: "center" }}>
+                <span>Be the change you want to see, </span>
+                <a
+                  href={buildRouteLink(
+                    AppRoute.REPOSITORY_PIPELINE_TRIGGER_ACTION,
+                    {
+                      orgSlug: parentOrg.slug,
+                      repoSlug: repo.slug,
+                      pipelineId: "", // @fixme: ???
+                    },
+                  )}
+                >
+                  trigger the first Pipeline run
+                </a>
+                <span> to this repository 🚀.</span>
+              </p>
+            </Grid.Col>
+          )}
+        </Grid.Col>
+      </PageWrapper>
+    </Layout>
   );
 };
 
-PipelinesView.displayName = "PipelinesView";
-export default PipelinesView;
+RepositoryPipelinesView.displayName = "RepositoryPipelinesView";
+export default RepositoryPipelinesView;