@ethicdevs/gitfoss | Show object: 76fa798d00614f356f12b47b1582c87780ea9288 ∙ GitFOSS
refactor: move redondant code + fix bugs
+ 197
- 209
@@ -1,5 +1,5 @@
 {
-  "_generatedAtUnix": 1778816347541,
+  "_generatedAtUnix": 1778824305007,
   "_hashAlgorithm": "sha1",
   "_version": 2,
   "assets": {

...
@@ -138,7 +138,7 @@
       "pathSource": "./app/views/pipelines/PipelineStagesView.tsx"
     },
     "PipelinesView": {
-      "hash": "8d672f194ee7d56ba6cae6b0cc7f5d96f6514ab7",
+      "hash": "01cd834642b220a0047844a5fdd724d0dbf1fa37",
       "pathSource": "./app/views/pipelines/PipelinesView.tsx"
     },
     "RepositoryBrowserView": {

...
@@ -182,7 +182,7 @@
       "pathSource": "./app/views/repositoryPullRequests/RepositoryPullRequestDetailsView.tsx"
     },
     "RepositoryPullRequestsView": {
-      "hash": "48e8ba878f5afa28544a6722e5ce675eef5000b5",
+      "hash": "6a5fb0057478583375f6806704ec8206e93f86a5",
       "pathSource": "./app/views/repositoryPullRequests/RepositoryPullRequestsView.tsx"
     },
     "SettingsKeyAddView": {

app/components/Button.styled.ts
@@ -1,6 +1,5 @@
 // 3rd-party
 import styled, { css } from "styled-components";
-// import styledContainerQuery from "styled-container-query";
 // app
 import { breakpoints, Colors } from "../utils/style";
 

new file
app/components/CountersRow.tsx
@@ -0,0 +1,72 @@
+// 3rd-party
+import React from "react";
+import styled, { css } from "styled-components";
+// app
+import type { WithThemeSchemeProp } from "../types";
+import { NamedColors } from "../utils/style";
+// app components
+import { Chip } from "./Chip";
+import { Grid } from "./Grid";
+
+export interface CountersRowProps {
+  labels: Array<{
+    label: string;
+    counter: number;
+    href?: string;
+    active?: boolean;
+  }>;
+}
+
+export const CountersRow = ({
+  themeScheme,
+  labels,
+}: WithThemeSchemeProp & CountersRowProps) => {
+  return (
+    <Grid.Col
+      fluid
+      style={{
+        padding: "12px 0",
+        borderBottom: `1px solid ${NamedColors.BORDER_DEFAULT[themeScheme]}`,
+      }}
+    >
+      <Grid.Row
+        fluid
+        alignItems={"center"}
+        gap={12}
+        style={{ padding: "0 8px" }}
+      >
+        {labels.map(({ label, counter, href = "#", active = false }) => (
+          <StyledLabelAnchor
+            href={href}
+            active={active}
+            themeScheme={themeScheme}
+          >
+            <Grid.Row nowrap gap={8} alignItems={"center"}>
+              <StyledLabelText themeScheme={themeScheme}>
+                {label}
+              </StyledLabelText>
+              <Chip themeScheme={themeScheme}>{counter}</Chip>
+            </Grid.Row>
+          </StyledLabelAnchor>
+        ))}
+      </Grid.Row>
+    </Grid.Col>
+  );
+};
+
+const StyledLabelAnchor = styled.a<WithThemeSchemeProp & { active?: boolean }>`
+  ${({ themeScheme, active = false }) => css`
+    font-weight: ${active ? "bold" : "normal"};
+    text-decoration: ${active ? "underline" : "none"};
+
+    & ${Chip} {
+      color: ${NamedColors.TEXT_MUTED[themeScheme]};
+      background-color: ${NamedColors.CARD_OVERLAY[themeScheme]};
+      text-decoration: none !important;
+    }
+  `}
+`;
+
+const StyledLabelText = styled.span<WithThemeSchemeProp & { active?: boolean }>`
+  white-space: nowrap;
+`;

app/components/DrawerPrimary.tsx
@@ -344,7 +344,7 @@ const StyledDrawerPrimary = styled.aside<
         top: 0;
         left: 0;
         bottom: 0;
-        z-index: 10000;
+        z-index: 12000;
         width: 85vw;
         max-width: 320px;
         transition: transform 140ms cubic-bezier(0, 0, 0.2, 1);

app/components/DrawerSettings.tsx
@@ -217,7 +217,7 @@ const StyledDrawerSettings = styled.aside<
         top: 0;
         left: 0;
         bottom: 0;
-        z-index: 10000;
+        z-index: 12000;
         width: 85vw;
         max-width: 320px;
         transition: transform 140ms cubic-bezier(0, 0, 0.2, 1);

app/utils/style/Colors.ts
@@ -21,6 +21,7 @@ const Colors = {
   GRAY_DARK_06: "#B6B6B6",
   WHITE_ALPHA_50: "rgba(255, 255, 255, 0.5)",
   WHITE_01: "#FFFFFF",
+  WHITE_02: "#f7f7f7",
   WHITE_ALPHA_01: "#FFFFFFa1",
   BLACK_ALPHA_01: "#000000a1",
   BLACK_ALPHA_50: "rgba(0, 0, 0, 0.5)",

app/utils/style/NamedColors.ts
@@ -46,7 +46,7 @@ const NamedColors = {
     dark: Colors.BLACK_TRANSPARENT,
   },
   DRAWER: {
-    light: Colors.WHITE_ALPHA_01,
+    light: Colors.WHITE_02,
     dark: Colors.GRAY_DARK_05,
   },
   INPUT: {

app/views/pipelines/PipelinesView.tsx
@@ -8,12 +8,13 @@ import type { Organization, Pipeline } from "@prisma/client";
 import type { CommonProps, RepositoryWithForkedFromRepo } from "../../types";
 import { AppRoute } from "../../routes.defs";
 import { Card } from "../../components/Card.styled";
+import { CountersRow } from "../../components/CountersRow";
 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";
+import { Colors } from "../../utils/style";
 // app islands
 import { IslandWrapper } from "../../components/IslandWrapper.styled";
 import RepositoryHero from "../../islands/RepositoryHero";

...
@@ -78,123 +79,73 @@ const PipelinesView: ReactView<PipelinesViewProps> = ({
             )}
           />
         </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>
+
+        <CountersRow
+          themeScheme={commonProps.themeScheme}
+          labels={[
+            {
+              label: "All",
+              counter: pipelines.length,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PIPELINES, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=all`,
+              active: pipelinesFilter == "all",
+            },
+            {
+              label: "Pending",
+              counter: 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PIPELINES, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=pending`,
+              active: pipelinesFilter == "pending",
+            },
+            {
+              label: "Running",
+              counter: 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PIPELINES, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=running`,
+              active: pipelinesFilter == "running",
+            },
+            {
+              label: "Passed",
+              counter: 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PIPELINES, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=passed`,
+              active: pipelinesFilter == "passed",
+            },
+            {
+              label: "Failed",
+              counter: 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PIPELINES, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=failed`,
+              active: pipelinesFilter == "failed",
+            },
+            {
+              label: "Canceled",
+              counter: 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PIPELINES, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=canceled`,
+              active: pipelinesFilter == "canceled",
+            },
+          ]}
+        />
+
         <Grid.Col fluid gap={4} style={{ marginTop: 12 }}>
           {pipelines != null && pipelines.length >= 1 ? (
             pipelines.map((pipeline) => (

refactor: move redondant code + fix bugs
+ 197
- 209
@@ -1,5 +1,5 @@
 {
-  "_generatedAtUnix": 1778816347541,
+  "_generatedAtUnix": 1778824305007,
   "_hashAlgorithm": "sha1",
   "_version": 2,
   "assets": {

...
@@ -138,7 +138,7 @@
       "pathSource": "./app/views/pipelines/PipelineStagesView.tsx"
     },
     "PipelinesView": {
-      "hash": "8d672f194ee7d56ba6cae6b0cc7f5d96f6514ab7",
+      "hash": "01cd834642b220a0047844a5fdd724d0dbf1fa37",
       "pathSource": "./app/views/pipelines/PipelinesView.tsx"
     },
     "RepositoryBrowserView": {

...
@@ -182,7 +182,7 @@
       "pathSource": "./app/views/repositoryPullRequests/RepositoryPullRequestDetailsView.tsx"
     },
     "RepositoryPullRequestsView": {
-      "hash": "48e8ba878f5afa28544a6722e5ce675eef5000b5",
+      "hash": "6a5fb0057478583375f6806704ec8206e93f86a5",
       "pathSource": "./app/views/repositoryPullRequests/RepositoryPullRequestsView.tsx"
     },
     "SettingsKeyAddView": {

app/components/Button.styled.ts
@@ -1,6 +1,5 @@
 // 3rd-party
 import styled, { css } from "styled-components";
-// import styledContainerQuery from "styled-container-query";
 // app
 import { breakpoints, Colors } from "../utils/style";
 

new file
app/components/CountersRow.tsx
@@ -0,0 +1,72 @@
+// 3rd-party
+import React from "react";
+import styled, { css } from "styled-components";
+// app
+import type { WithThemeSchemeProp } from "../types";
+import { NamedColors } from "../utils/style";
+// app components
+import { Chip } from "./Chip";
+import { Grid } from "./Grid";
+
+export interface CountersRowProps {
+  labels: Array<{
+    label: string;
+    counter: number;
+    href?: string;
+    active?: boolean;
+  }>;
+}
+
+export const CountersRow = ({
+  themeScheme,
+  labels,
+}: WithThemeSchemeProp & CountersRowProps) => {
+  return (
+    <Grid.Col
+      fluid
+      style={{
+        padding: "12px 0",
+        borderBottom: `1px solid ${NamedColors.BORDER_DEFAULT[themeScheme]}`,
+      }}
+    >
+      <Grid.Row
+        fluid
+        alignItems={"center"}
+        gap={12}
+        style={{ padding: "0 8px" }}
+      >
+        {labels.map(({ label, counter, href = "#", active = false }) => (
+          <StyledLabelAnchor
+            href={href}
+            active={active}
+            themeScheme={themeScheme}
+          >
+            <Grid.Row nowrap gap={8} alignItems={"center"}>
+              <StyledLabelText themeScheme={themeScheme}>
+                {label}
+              </StyledLabelText>
+              <Chip themeScheme={themeScheme}>{counter}</Chip>
+            </Grid.Row>
+          </StyledLabelAnchor>
+        ))}
+      </Grid.Row>
+    </Grid.Col>
+  );
+};
+
+const StyledLabelAnchor = styled.a<WithThemeSchemeProp & { active?: boolean }>`
+  ${({ themeScheme, active = false }) => css`
+    font-weight: ${active ? "bold" : "normal"};
+    text-decoration: ${active ? "underline" : "none"};
+
+    & ${Chip} {
+      color: ${NamedColors.TEXT_MUTED[themeScheme]};
+      background-color: ${NamedColors.CARD_OVERLAY[themeScheme]};
+      text-decoration: none !important;
+    }
+  `}
+`;
+
+const StyledLabelText = styled.span<WithThemeSchemeProp & { active?: boolean }>`
+  white-space: nowrap;
+`;

app/components/DrawerPrimary.tsx
@@ -344,7 +344,7 @@ const StyledDrawerPrimary = styled.aside<
         top: 0;
         left: 0;
         bottom: 0;
-        z-index: 10000;
+        z-index: 12000;
         width: 85vw;
         max-width: 320px;
         transition: transform 140ms cubic-bezier(0, 0, 0.2, 1);

app/components/DrawerSettings.tsx
@@ -217,7 +217,7 @@ const StyledDrawerSettings = styled.aside<
         top: 0;
         left: 0;
         bottom: 0;
-        z-index: 10000;
+        z-index: 12000;
         width: 85vw;
         max-width: 320px;
         transition: transform 140ms cubic-bezier(0, 0, 0.2, 1);

app/utils/style/Colors.ts
@@ -21,6 +21,7 @@ const Colors = {
   GRAY_DARK_06: "#B6B6B6",
   WHITE_ALPHA_50: "rgba(255, 255, 255, 0.5)",
   WHITE_01: "#FFFFFF",
+  WHITE_02: "#f7f7f7",
   WHITE_ALPHA_01: "#FFFFFFa1",
   BLACK_ALPHA_01: "#000000a1",
   BLACK_ALPHA_50: "rgba(0, 0, 0, 0.5)",

app/utils/style/NamedColors.ts
@@ -46,7 +46,7 @@ const NamedColors = {
     dark: Colors.BLACK_TRANSPARENT,
   },
   DRAWER: {
-    light: Colors.WHITE_ALPHA_01,
+    light: Colors.WHITE_02,
     dark: Colors.GRAY_DARK_05,
   },
   INPUT: {

app/views/pipelines/PipelinesView.tsx
@@ -8,12 +8,13 @@ import type { Organization, Pipeline } from "@prisma/client";
 import type { CommonProps, RepositoryWithForkedFromRepo } from "../../types";
 import { AppRoute } from "../../routes.defs";
 import { Card } from "../../components/Card.styled";
+import { CountersRow } from "../../components/CountersRow";
 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";
+import { Colors } from "../../utils/style";
 // app islands
 import { IslandWrapper } from "../../components/IslandWrapper.styled";
 import RepositoryHero from "../../islands/RepositoryHero";

...
@@ -78,123 +79,73 @@ const PipelinesView: ReactView<PipelinesViewProps> = ({
             )}
           />
         </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>
+
+        <CountersRow
+          themeScheme={commonProps.themeScheme}
+          labels={[
+            {
+              label: "All",
+              counter: pipelines.length,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PIPELINES, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=all`,
+              active: pipelinesFilter == "all",
+            },
+            {
+              label: "Pending",
+              counter: 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PIPELINES, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=pending`,
+              active: pipelinesFilter == "pending",
+            },
+            {
+              label: "Running",
+              counter: 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PIPELINES, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=running`,
+              active: pipelinesFilter == "running",
+            },
+            {
+              label: "Passed",
+              counter: 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PIPELINES, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=passed`,
+              active: pipelinesFilter == "passed",
+            },
+            {
+              label: "Failed",
+              counter: 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PIPELINES, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=failed`,
+              active: pipelinesFilter == "failed",
+            },
+            {
+              label: "Canceled",
+              counter: 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PIPELINES, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=canceled`,
+              active: pipelinesFilter == "canceled",
+            },
+          ]}
+        />
+
         <Grid.Col fluid gap={4} style={{ marginTop: 12 }}>
           {pipelines != null && pipelines.length >= 1 ? (
             pipelines.map((pipeline) => (

app/views/repositoryPullRequests/RepositoryPullRequestsView.tsx
@@ -8,12 +8,13 @@ import type { Organization, PullRequest } from "@prisma/client";
 import type { CommonProps, RepositoryWithForkedFromRepo } from "../../types";
 import { AppRoute } from "../../routes.defs";
 import { Card } from "../../components/Card.styled";
+import { CountersRow } from "../../components/CountersRow";
 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";
+import { Colors } from "../../utils/style";
 // app islands
 import { IslandWrapper } from "../../components/IslandWrapper.styled";
 import RepositoryHero from "../../islands/RepositoryHero";

...
@@ -73,89 +74,53 @@ const RepositoryPullRequestsView: ReactView<
             )}
           />
         </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: pullRequestsFilter === "all" ? "bold" : "normal",
-                textDecoration:
-                  pullRequestsFilter === "all" ? "underline" : "none",
-              }}
-              href={`/${parentOrg.slug}/${repo.slug}/pulls?filter=${
-                "all" as PullRequestsFilter
-              }`}
-            >
-              <Grid.Row nowrap gap={8} alignItems={"center"}>
-                <span>All</span>
-                <Chip themeScheme={commonProps.themeScheme}>
-                  {commonProps.layoutCounters!.pullsTotal}
-                </Chip>
-              </Grid.Row>
-            </a>
-            <a
-              style={{
-                fontWeight: pullRequestsFilter === "open" ? "bold" : "normal",
-                textDecoration:
-                  pullRequestsFilter === "open" ? "underline" : "none",
-              }}
-              href={`/${parentOrg.slug}/${repo.slug}/pulls?filter=${
-                "open" as PullRequestsFilter
-              }`}
-            >
-              <Grid.Row nowrap gap={8} alignItems={"center"}>
-                <span>Open</span>
-                <Chip themeScheme={commonProps.themeScheme}>
-                  {commonProps.layoutCounters!.pullsOpen}
-                </Chip>
-              </Grid.Row>
-            </a>
-            <a
-              style={{
-                fontWeight: pullRequestsFilter === "merged" ? "bold" : "normal",
-                textDecoration:
-                  pullRequestsFilter === "merged" ? "underline" : "none",
-              }}
-              href={`/${parentOrg.slug}/${repo.slug}/pulls?filter=${
-                "merged" as PullRequestsFilter
-              }`}
-            >
-              <Grid.Row nowrap gap={8} alignItems={"center"}>
-                <span>Merged</span>
-                <Chip themeScheme={commonProps.themeScheme}>
-                  {commonProps.layoutCounters!.pullsMerged}
-                </Chip>
-              </Grid.Row>
-            </a>
-            <a
-              style={{
-                fontWeight: pullRequestsFilter === "closed" ? "bold" : "normal",
-                textDecoration:
-                  pullRequestsFilter === "closed" ? "underline" : "none",
-              }}
-              href={`/${parentOrg.slug}/${repo.slug}/pulls?filter=${
-                "closed" as PullRequestsFilter
-              }`}
-            >
-              <Grid.Row nowrap gap={8} alignItems={"center"}>
-                <span>Closed</span>
-                <Chip themeScheme={commonProps.themeScheme}>
-                  {commonProps.layoutCounters!.pullsClosed}
-                </Chip>
-              </Grid.Row>
-            </a>
-          </Grid.Row>
-        </Grid.Col>
+
+        <CountersRow
+          themeScheme={commonProps.themeScheme}
+          labels={[
+            {
+              label: "All",
+              counter: commonProps.layoutCounters!.pullsTotal || 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PULL_REQUESTS, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=all`,
+              active: pullRequestsFilter == "all",
+            },
+            {
+              label: "Open",
+              counter: commonProps.layoutCounters!.pullsOpen || 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PULL_REQUESTS, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=open`,
+              active: pullRequestsFilter == "open",
+            },
+            {
+              label: "Closed",
+              counter: commonProps.layoutCounters!.pullsClosed || 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PULL_REQUESTS, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=closed`,
+              active: pullRequestsFilter == "closed",
+            },
+            {
+              label: "Merged",
+              counter: commonProps.layoutCounters!.pullsMerged || 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PULL_REQUESTS, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=merged`,
+              active: pullRequestsFilter == "merged",
+            },
+          ]}
+        />
+
         <Grid.Col fluid gap={4} style={{ marginTop: 12 }}>
           {pullRequests != null && pullRequests.length >= 1 ? (
             pullRequests.map((pr) => (

app/views/repositoryPullRequests/RepositoryPullRequestsView.tsx
@@ -8,12 +8,13 @@ import type { Organization, PullRequest } from "@prisma/client";
 import type { CommonProps, RepositoryWithForkedFromRepo } from "../../types";
 import { AppRoute } from "../../routes.defs";
 import { Card } from "../../components/Card.styled";
+import { CountersRow } from "../../components/CountersRow";
 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";
+import { Colors } from "../../utils/style";
 // app islands
 import { IslandWrapper } from "../../components/IslandWrapper.styled";
 import RepositoryHero from "../../islands/RepositoryHero";

...
@@ -73,89 +74,53 @@ const RepositoryPullRequestsView: ReactView<
             )}
           />
         </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: pullRequestsFilter === "all" ? "bold" : "normal",
-                textDecoration:
-                  pullRequestsFilter === "all" ? "underline" : "none",
-              }}
-              href={`/${parentOrg.slug}/${repo.slug}/pulls?filter=${
-                "all" as PullRequestsFilter
-              }`}
-            >
-              <Grid.Row nowrap gap={8} alignItems={"center"}>
-                <span>All</span>
-                <Chip themeScheme={commonProps.themeScheme}>
-                  {commonProps.layoutCounters!.pullsTotal}
-                </Chip>
-              </Grid.Row>
-            </a>
-            <a
-              style={{
-                fontWeight: pullRequestsFilter === "open" ? "bold" : "normal",
-                textDecoration:
-                  pullRequestsFilter === "open" ? "underline" : "none",
-              }}
-              href={`/${parentOrg.slug}/${repo.slug}/pulls?filter=${
-                "open" as PullRequestsFilter
-              }`}
-            >
-              <Grid.Row nowrap gap={8} alignItems={"center"}>
-                <span>Open</span>
-                <Chip themeScheme={commonProps.themeScheme}>
-                  {commonProps.layoutCounters!.pullsOpen}
-                </Chip>
-              </Grid.Row>
-            </a>
-            <a
-              style={{
-                fontWeight: pullRequestsFilter === "merged" ? "bold" : "normal",
-                textDecoration:
-                  pullRequestsFilter === "merged" ? "underline" : "none",
-              }}
-              href={`/${parentOrg.slug}/${repo.slug}/pulls?filter=${
-                "merged" as PullRequestsFilter
-              }`}
-            >
-              <Grid.Row nowrap gap={8} alignItems={"center"}>
-                <span>Merged</span>
-                <Chip themeScheme={commonProps.themeScheme}>
-                  {commonProps.layoutCounters!.pullsMerged}
-                </Chip>
-              </Grid.Row>
-            </a>
-            <a
-              style={{
-                fontWeight: pullRequestsFilter === "closed" ? "bold" : "normal",
-                textDecoration:
-                  pullRequestsFilter === "closed" ? "underline" : "none",
-              }}
-              href={`/${parentOrg.slug}/${repo.slug}/pulls?filter=${
-                "closed" as PullRequestsFilter
-              }`}
-            >
-              <Grid.Row nowrap gap={8} alignItems={"center"}>
-                <span>Closed</span>
-                <Chip themeScheme={commonProps.themeScheme}>
-                  {commonProps.layoutCounters!.pullsClosed}
-                </Chip>
-              </Grid.Row>
-            </a>
-          </Grid.Row>
-        </Grid.Col>
+
+        <CountersRow
+          themeScheme={commonProps.themeScheme}
+          labels={[
+            {
+              label: "All",
+              counter: commonProps.layoutCounters!.pullsTotal || 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PULL_REQUESTS, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=all`,
+              active: pullRequestsFilter == "all",
+            },
+            {
+              label: "Open",
+              counter: commonProps.layoutCounters!.pullsOpen || 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PULL_REQUESTS, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=open`,
+              active: pullRequestsFilter == "open",
+            },
+            {
+              label: "Closed",
+              counter: commonProps.layoutCounters!.pullsClosed || 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PULL_REQUESTS, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=closed`,
+              active: pullRequestsFilter == "closed",
+            },
+            {
+              label: "Merged",
+              counter: commonProps.layoutCounters!.pullsMerged || 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PULL_REQUESTS, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=merged`,
+              active: pullRequestsFilter == "merged",
+            },
+          ]}
+        />
+
         <Grid.Col fluid gap={4} style={{ marginTop: 12 }}>
           {pullRequests != null && pullRequests.length >= 1 ? (
             pullRequests.map((pr) => (

app/views/repositoryPullRequests/RepositoryPullRequestsView.tsx
@@ -8,12 +8,13 @@ import type { Organization, PullRequest } from "@prisma/client";
 import type { CommonProps, RepositoryWithForkedFromRepo } from "../../types";
 import { AppRoute } from "../../routes.defs";
 import { Card } from "../../components/Card.styled";
+import { CountersRow } from "../../components/CountersRow";
 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";
+import { Colors } from "../../utils/style";
 // app islands
 import { IslandWrapper } from "../../components/IslandWrapper.styled";
 import RepositoryHero from "../../islands/RepositoryHero";

...
@@ -73,89 +74,53 @@ const RepositoryPullRequestsView: ReactView<
             )}
           />
         </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: pullRequestsFilter === "all" ? "bold" : "normal",
-                textDecoration:
-                  pullRequestsFilter === "all" ? "underline" : "none",
-              }}
-              href={`/${parentOrg.slug}/${repo.slug}/pulls?filter=${
-                "all" as PullRequestsFilter
-              }`}
-            >
-              <Grid.Row nowrap gap={8} alignItems={"center"}>
-                <span>All</span>
-                <Chip themeScheme={commonProps.themeScheme}>
-                  {commonProps.layoutCounters!.pullsTotal}
-                </Chip>
-              </Grid.Row>
-            </a>
-            <a
-              style={{
-                fontWeight: pullRequestsFilter === "open" ? "bold" : "normal",
-                textDecoration:
-                  pullRequestsFilter === "open" ? "underline" : "none",
-              }}
-              href={`/${parentOrg.slug}/${repo.slug}/pulls?filter=${
-                "open" as PullRequestsFilter
-              }`}
-            >
-              <Grid.Row nowrap gap={8} alignItems={"center"}>
-                <span>Open</span>
-                <Chip themeScheme={commonProps.themeScheme}>
-                  {commonProps.layoutCounters!.pullsOpen}
-                </Chip>
-              </Grid.Row>
-            </a>
-            <a
-              style={{
-                fontWeight: pullRequestsFilter === "merged" ? "bold" : "normal",
-                textDecoration:
-                  pullRequestsFilter === "merged" ? "underline" : "none",
-              }}
-              href={`/${parentOrg.slug}/${repo.slug}/pulls?filter=${
-                "merged" as PullRequestsFilter
-              }`}
-            >
-              <Grid.Row nowrap gap={8} alignItems={"center"}>
-                <span>Merged</span>
-                <Chip themeScheme={commonProps.themeScheme}>
-                  {commonProps.layoutCounters!.pullsMerged}
-                </Chip>
-              </Grid.Row>
-            </a>
-            <a
-              style={{
-                fontWeight: pullRequestsFilter === "closed" ? "bold" : "normal",
-                textDecoration:
-                  pullRequestsFilter === "closed" ? "underline" : "none",
-              }}
-              href={`/${parentOrg.slug}/${repo.slug}/pulls?filter=${
-                "closed" as PullRequestsFilter
-              }`}
-            >
-              <Grid.Row nowrap gap={8} alignItems={"center"}>
-                <span>Closed</span>
-                <Chip themeScheme={commonProps.themeScheme}>
-                  {commonProps.layoutCounters!.pullsClosed}
-                </Chip>
-              </Grid.Row>
-            </a>
-          </Grid.Row>
-        </Grid.Col>
+
+        <CountersRow
+          themeScheme={commonProps.themeScheme}
+          labels={[
+            {
+              label: "All",
+              counter: commonProps.layoutCounters!.pullsTotal || 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PULL_REQUESTS, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=all`,
+              active: pullRequestsFilter == "all",
+            },
+            {
+              label: "Open",
+              counter: commonProps.layoutCounters!.pullsOpen || 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PULL_REQUESTS, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=open`,
+              active: pullRequestsFilter == "open",
+            },
+            {
+              label: "Closed",
+              counter: commonProps.layoutCounters!.pullsClosed || 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PULL_REQUESTS, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=closed`,
+              active: pullRequestsFilter == "closed",
+            },
+            {
+              label: "Merged",
+              counter: commonProps.layoutCounters!.pullsMerged || 0,
+              href:
+                buildRouteLink(AppRoute.REPOSITORY_PULL_REQUESTS, {
+                  orgSlug: parentOrg.slug,
+                  repoSlug: repo.slug,
+                }) + `?filter=merged`,
+              active: pullRequestsFilter == "merged",
+            },
+          ]}
+        />
+
         <Grid.Col fluid gap={4} style={{ marginTop: 12 }}>
           {pullRequests != null && pullRequests.length >= 1 ? (
             pullRequests.map((pr) => (

GitFOSS • v0.2.0 (#8f4aa2e) • MIT License