Show all PR check counts in hover card (#993)
This commit is contained in:
@@ -8,18 +8,10 @@ import {
|
||||
type ReactElement,
|
||||
type ReactNode,
|
||||
} from "react";
|
||||
import {
|
||||
Dimensions,
|
||||
Platform,
|
||||
Text,
|
||||
View,
|
||||
type StyleProp,
|
||||
type TextStyle,
|
||||
type ViewStyle,
|
||||
} from "react-native";
|
||||
import { Dimensions, Platform, Text, View } from "react-native";
|
||||
import Animated, { FadeIn, FadeOut } from "react-native-reanimated";
|
||||
import { StyleSheet, withUnistyles } from "react-native-unistyles";
|
||||
import { ExternalLink } from "lucide-react-native";
|
||||
import { CircleCheck, CircleDot, CircleX, ExternalLink } from "lucide-react-native";
|
||||
import { GitHubIcon } from "@/components/icons/github-icon";
|
||||
import type { Theme } from "@/styles/theme";
|
||||
import { DiffStat } from "@/components/diff-stat";
|
||||
@@ -316,9 +308,62 @@ function WorkspaceHoverCardContent({
|
||||
|
||||
const ThemedExternalLink = withUnistyles(ExternalLink);
|
||||
const ThemedGitHubIcon = withUnistyles(GitHubIcon);
|
||||
const ThemedCircleCheck = withUnistyles(CircleCheck);
|
||||
const ThemedCircleDot = withUnistyles(CircleDot);
|
||||
const ThemedCircleX = withUnistyles(CircleX);
|
||||
|
||||
const foregroundColorMapping = (theme: Theme) => ({ color: theme.colors.foreground });
|
||||
const foregroundMutedColorMapping = (theme: Theme) => ({ color: theme.colors.foregroundMuted });
|
||||
const successColorMapping = (theme: Theme) => ({ color: theme.colors.statusSuccess });
|
||||
const warningColorMapping = (theme: Theme) => ({ color: theme.colors.statusWarning });
|
||||
const dangerColorMapping = (theme: Theme) => ({ color: theme.colors.statusDanger });
|
||||
|
||||
function getChecksSummaryCounts(checks: NonNullable<PrHint["checks"]>) {
|
||||
return checks.reduce(
|
||||
(counts, check) => {
|
||||
if (check.status === "success") counts.passed += 1;
|
||||
else if (check.status === "failure") counts.failed += 1;
|
||||
else if (check.status !== "skipped" && check.status !== "cancelled") counts.pending += 1;
|
||||
return counts;
|
||||
},
|
||||
{ passed: 0, failed: 0, pending: 0 },
|
||||
);
|
||||
}
|
||||
|
||||
function ChecksSummaryPill({
|
||||
count,
|
||||
kind,
|
||||
}: {
|
||||
count: number;
|
||||
kind: "passed" | "failed" | "pending";
|
||||
}) {
|
||||
if (count === 0) return null;
|
||||
|
||||
if (kind === "passed") {
|
||||
return (
|
||||
<View style={styles.checksSummaryPill}>
|
||||
<ThemedCircleCheck size={12} uniProps={successColorMapping} />
|
||||
<Text style={styles.checksStatusTextPassed}>{count}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (kind === "failed") {
|
||||
return (
|
||||
<View style={styles.checksSummaryPill}>
|
||||
<ThemedCircleX size={12} uniProps={dangerColorMapping} />
|
||||
<Text style={styles.checksStatusTextFailed}>{count}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.checksSummaryPill}>
|
||||
<ThemedCircleDot size={12} uniProps={warningColorMapping} />
|
||||
<Text style={styles.checksStatusTextPending}>{count}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
function ChecksSummaryContent({
|
||||
checks,
|
||||
@@ -327,26 +372,7 @@ function ChecksSummaryContent({
|
||||
checks: NonNullable<PrHint["checks"]>;
|
||||
hovered: boolean;
|
||||
}) {
|
||||
const failed = checks.filter((c) => c.status === "failure").length;
|
||||
const pending = checks.filter((c) => c.status === "pending").length;
|
||||
|
||||
let badgeLabel: string;
|
||||
let dotStyle: StyleProp<ViewStyle>;
|
||||
let statusTextStyle: StyleProp<TextStyle>;
|
||||
|
||||
if (failed > 0) {
|
||||
badgeLabel = `${failed} failed`;
|
||||
dotStyle = styles.checksDotFailed;
|
||||
statusTextStyle = styles.checksStatusTextFailed;
|
||||
} else if (pending > 0) {
|
||||
badgeLabel = `${pending} running`;
|
||||
dotStyle = styles.checksDotPending;
|
||||
statusTextStyle = styles.checksStatusTextPending;
|
||||
} else {
|
||||
badgeLabel = `${checks.length} passed`;
|
||||
dotStyle = styles.checksDotPassed;
|
||||
statusTextStyle = styles.checksStatusTextPassed;
|
||||
}
|
||||
const { passed, failed, pending } = getChecksSummaryCounts(checks);
|
||||
|
||||
const labelStyle = hovered ? checksSummaryLabelHoveredCombined : styles.checksSummaryLabel;
|
||||
const iconUniProps = hovered ? foregroundColorMapping : foregroundMutedColorMapping;
|
||||
@@ -360,8 +386,9 @@ function ChecksSummaryContent({
|
||||
)}
|
||||
<Text style={labelStyle}>Checks</Text>
|
||||
<View style={styles.checksSummaryCounts}>
|
||||
<View style={dotStyle} />
|
||||
<Text style={statusTextStyle}>{badgeLabel}</Text>
|
||||
<ChecksSummaryPill count={passed} kind="passed" />
|
||||
<ChecksSummaryPill count={failed} kind="failed" />
|
||||
<ChecksSummaryPill count={pending} kind="pending" />
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
@@ -465,42 +492,29 @@ const styles = StyleSheet.create((theme) => ({
|
||||
checksSummaryCounts: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 4,
|
||||
gap: theme.spacing[2],
|
||||
flex: 1,
|
||||
justifyContent: "flex-end",
|
||||
},
|
||||
checksDotFailed: {
|
||||
width: 6,
|
||||
height: 6,
|
||||
borderRadius: 3,
|
||||
backgroundColor: theme.colors.palette.red[500],
|
||||
},
|
||||
checksDotPending: {
|
||||
width: 6,
|
||||
height: 6,
|
||||
borderRadius: 3,
|
||||
backgroundColor: theme.colors.palette.amber[500],
|
||||
},
|
||||
checksDotPassed: {
|
||||
width: 6,
|
||||
height: 6,
|
||||
borderRadius: 3,
|
||||
backgroundColor: theme.colors.palette.green[500],
|
||||
checksSummaryPill: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 3,
|
||||
},
|
||||
checksStatusTextFailed: {
|
||||
fontSize: theme.fontSize.xs,
|
||||
fontWeight: theme.fontWeight.normal,
|
||||
color: theme.colors.palette.red[500],
|
||||
color: theme.colors.statusDanger,
|
||||
},
|
||||
checksStatusTextPending: {
|
||||
fontSize: theme.fontSize.xs,
|
||||
fontWeight: theme.fontWeight.normal,
|
||||
color: theme.colors.palette.amber[500],
|
||||
color: theme.colors.statusWarning,
|
||||
},
|
||||
checksStatusTextPassed: {
|
||||
fontSize: theme.fontSize.xs,
|
||||
fontWeight: theme.fontWeight.normal,
|
||||
color: theme.colors.palette.green[500],
|
||||
color: theme.colors.statusSuccess,
|
||||
},
|
||||
}));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user