clairo 3.1.2 → 3.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/cli.js +109 -98
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
an opinionated dashboard tui for github PRs, jira tickets, and daily logs.
|
|
4
4
|
|
|
5
|
-
<img width="1728" height="1056" alt="clairo" src="https://
|
|
5
|
+
<img width="1728" height="1056" alt="clairo" src="https://www.zzzzion.com/images/clairo.webp" />
|
|
6
6
|
|
|
7
7
|
## features
|
|
8
8
|
|
|
@@ -33,6 +33,7 @@ an opinionated dashboard tui for github PRs, jira tickets, and daily logs.
|
|
|
33
33
|
|
|
34
34
|
- Node.js 18+
|
|
35
35
|
- [GitHub CLI](https://cli.github.com/) (`gh`) installed and authenticated
|
|
36
|
+
- A [Nerd Font](https://www.nerdfonts.com/) is highly recommended for proper icon rendering
|
|
36
37
|
|
|
37
38
|
## usage
|
|
38
39
|
|
package/dist/cli.js
CHANGED
|
@@ -216,11 +216,11 @@ function resolveReviewDisplay(reviewDecision) {
|
|
|
216
216
|
}
|
|
217
217
|
function resolveMergeDisplay(pr) {
|
|
218
218
|
if (!pr) return { text: "Unknown", color: "yellow" };
|
|
219
|
-
if (pr.state === "MERGED") return { text: "Merged", color: "magenta" };
|
|
220
|
-
if (pr.state === "CLOSED") return { text: "Closed", color: "red" };
|
|
221
|
-
if (pr.isDraft) return { text: "Draft", color: "yellow" };
|
|
222
|
-
if (pr.mergeable === "MERGEABLE") return { text: "Open", color: "green" };
|
|
223
|
-
if (pr.mergeable === "CONFLICTING") return { text: "Conflicts", color: "red" };
|
|
219
|
+
if (pr.state === "MERGED") return { text: "\uE727 Merged", color: "magenta" };
|
|
220
|
+
if (pr.state === "CLOSED") return { text: "\uE726 Closed", color: "red" };
|
|
221
|
+
if (pr.isDraft) return { text: "\uE726 Draft", color: "yellow" };
|
|
222
|
+
if (pr.mergeable === "MERGEABLE") return { text: "\uE726 Open", color: "green" };
|
|
223
|
+
if (pr.mergeable === "CONFLICTING") return { text: "\uE726 Conflicts", color: "red" };
|
|
224
224
|
return { text: "Unknown", color: "yellow" };
|
|
225
225
|
}
|
|
226
226
|
async function isGhInstalled() {
|
|
@@ -1554,7 +1554,7 @@ ${detail}
|
|
|
1554
1554
|
|
|
1555
1555
|
// src/components/github/PRDetailsBox.tsx
|
|
1556
1556
|
import open from "open";
|
|
1557
|
-
import { useRef as useRef2 } from "react";
|
|
1557
|
+
import React, { useRef as useRef2 } from "react";
|
|
1558
1558
|
import { Box as Box4, Text as Text4, useInput } from "ink";
|
|
1559
1559
|
import { ScrollView } from "ink-scroll-view";
|
|
1560
1560
|
import Spinner from "ink-spinner";
|
|
@@ -1701,7 +1701,7 @@ function renderInlineToString(tokens) {
|
|
|
1701
1701
|
}
|
|
1702
1702
|
|
|
1703
1703
|
// src/components/ui/TitledBox.tsx
|
|
1704
|
-
import { Box as Box3,
|
|
1704
|
+
import { Box as Box3, Text as Text3, useStdout } from "ink";
|
|
1705
1705
|
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1706
1706
|
function TitledBox({
|
|
1707
1707
|
title,
|
|
@@ -1730,7 +1730,7 @@ function TitledBox({
|
|
|
1730
1730
|
] });
|
|
1731
1731
|
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", flexGrow: 1, children: [
|
|
1732
1732
|
topBorder,
|
|
1733
|
-
/* @__PURE__ */
|
|
1733
|
+
/* @__PURE__ */ jsx4(
|
|
1734
1734
|
Box3,
|
|
1735
1735
|
{
|
|
1736
1736
|
flexDirection: "column",
|
|
@@ -1740,13 +1740,10 @@ function TitledBox({
|
|
|
1740
1740
|
borderStyle: "round",
|
|
1741
1741
|
borderTop: false,
|
|
1742
1742
|
borderColor,
|
|
1743
|
-
children: [
|
|
1744
|
-
children,
|
|
1745
|
-
footer
|
|
1746
|
-
|
|
1747
|
-
footer
|
|
1748
|
-
] })
|
|
1749
|
-
]
|
|
1743
|
+
children: footer ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
1744
|
+
/* @__PURE__ */ jsx4(Box3, { flexDirection: "column", flexGrow: 1, flexBasis: 0, overflow: "hidden", children }),
|
|
1745
|
+
footer
|
|
1746
|
+
] }) : children
|
|
1750
1747
|
}
|
|
1751
1748
|
)
|
|
1752
1749
|
] });
|
|
@@ -1777,6 +1774,83 @@ function PRDetailsBox({ pr, loading, error, isActive, title = "[3] PR Details",
|
|
|
1777
1774
|
},
|
|
1778
1775
|
{ isActive }
|
|
1779
1776
|
);
|
|
1777
|
+
const sections = [];
|
|
1778
|
+
if (pr) {
|
|
1779
|
+
if ((((_a = pr.assignees) == null ? void 0 : _a.length) ?? 0) > 0) {
|
|
1780
|
+
sections.push({
|
|
1781
|
+
key: "assignees",
|
|
1782
|
+
content: /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
1783
|
+
/* @__PURE__ */ jsx5(Text4, { dimColor: true, children: "Assignees: " }),
|
|
1784
|
+
/* @__PURE__ */ jsx5(Text4, { children: pr.assignees.map((a) => a.login).join(", ") })
|
|
1785
|
+
] })
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
if ((((_b = pr.reviews) == null ? void 0 : _b.length) ?? 0) > 0 || (((_c = pr.reviewRequests) == null ? void 0 : _c.length) ?? 0) > 0) {
|
|
1789
|
+
sections.push({
|
|
1790
|
+
key: "reviews",
|
|
1791
|
+
content: /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
1792
|
+
/* @__PURE__ */ jsxs4(Box4, { children: [
|
|
1793
|
+
/* @__PURE__ */ jsx5(Text4, { dimColor: true, children: "Reviews: " }),
|
|
1794
|
+
/* @__PURE__ */ jsx5(Text4, { color: reviewDisplay.color, children: reviewDisplay.text })
|
|
1795
|
+
] }),
|
|
1796
|
+
(_d = pr.reviews) == null ? void 0 : _d.map((review, idx) => {
|
|
1797
|
+
const color = review.state === "APPROVED" ? "green" : review.state === "CHANGES_REQUESTED" ? "red" : review.state === "COMMENTED" ? "blue" : "yellow";
|
|
1798
|
+
const icon = review.state === "APPROVED" ? "\uF00C" : review.state === "CHANGES_REQUESTED" ? "\uF00D" : review.state === "COMMENTED" ? "\uF075" : "\uF10C";
|
|
1799
|
+
return /* @__PURE__ */ jsxs4(Text4, { color, children: [
|
|
1800
|
+
" ",
|
|
1801
|
+
icon,
|
|
1802
|
+
" ",
|
|
1803
|
+
review.author.login
|
|
1804
|
+
] }, idx);
|
|
1805
|
+
}),
|
|
1806
|
+
(_e = pr.reviewRequests) == null ? void 0 : _e.map((r, idx) => /* @__PURE__ */ jsxs4(Text4, { color: "yellow", children: [
|
|
1807
|
+
" ",
|
|
1808
|
+
"\u25CB ",
|
|
1809
|
+
r.login ?? r.name ?? r.slug ?? "Team",
|
|
1810
|
+
" ",
|
|
1811
|
+
/* @__PURE__ */ jsx5(Text4, { dimColor: true, children: "(pending)" })
|
|
1812
|
+
] }, `pending-${idx}`))
|
|
1813
|
+
] })
|
|
1814
|
+
});
|
|
1815
|
+
}
|
|
1816
|
+
if ((((_f = pr.statusCheckRollup) == null ? void 0 : _f.length) ?? 0) > 0) {
|
|
1817
|
+
sections.push({
|
|
1818
|
+
key: "checks",
|
|
1819
|
+
content: /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
1820
|
+
/* @__PURE__ */ jsx5(Text4, { dimColor: true, children: "Checks:" }),
|
|
1821
|
+
Array.from(
|
|
1822
|
+
((_g = pr.statusCheckRollup) == null ? void 0 : _g.reduce((acc, check) => {
|
|
1823
|
+
const key = check.name ?? check.context ?? "";
|
|
1824
|
+
const existing = acc.get(key);
|
|
1825
|
+
if (!existing || (check.startedAt ?? "") > (existing.startedAt ?? "")) {
|
|
1826
|
+
acc.set(key, check);
|
|
1827
|
+
}
|
|
1828
|
+
return acc;
|
|
1829
|
+
}, /* @__PURE__ */ new Map()).values()) ?? []
|
|
1830
|
+
).sort((a, b) => CHECK_SORT_ORDER[resolveCheckStatus(a)] - CHECK_SORT_ORDER[resolveCheckStatus(b)]).map((check, idx) => {
|
|
1831
|
+
const jobName = check.name ?? check.context;
|
|
1832
|
+
const displayName = check.workflowName ? `${check.workflowName} / ${jobName}` : jobName;
|
|
1833
|
+
const status = resolveCheckStatus(check);
|
|
1834
|
+
return /* @__PURE__ */ jsxs4(Text4, { color: CHECK_COLORS[status], children: [
|
|
1835
|
+
" ",
|
|
1836
|
+
CHECK_ICONS[status],
|
|
1837
|
+
" ",
|
|
1838
|
+
displayName
|
|
1839
|
+
] }, idx);
|
|
1840
|
+
})
|
|
1841
|
+
] })
|
|
1842
|
+
});
|
|
1843
|
+
}
|
|
1844
|
+
if (pr.body) {
|
|
1845
|
+
sections.push({
|
|
1846
|
+
key: "description",
|
|
1847
|
+
content: /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
1848
|
+
/* @__PURE__ */ jsx5(Text4, { dimColor: true, children: "Description:" }),
|
|
1849
|
+
/* @__PURE__ */ jsx5(Markdown, { children: pr.body })
|
|
1850
|
+
] })
|
|
1851
|
+
});
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1780
1854
|
return /* @__PURE__ */ jsx5(TitledBox, { title: displayTitle, borderColor, footer, children: /* @__PURE__ */ jsx5(Box4, { flexDirection: "column", flexGrow: 1, flexBasis: 0, overflow: "hidden", children: /* @__PURE__ */ jsx5(ScrollView, { ref: scrollRef, children: /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", paddingX: 1, children: [
|
|
1781
1855
|
loading && /* @__PURE__ */ jsxs4(Text4, { color: "yellow", children: [
|
|
1782
1856
|
/* @__PURE__ */ jsx5(Spinner, { type: "dots" }),
|
|
@@ -1798,9 +1872,9 @@ function PRDetailsBox({ pr, loading, error, isActive, title = "[3] PR Details",
|
|
|
1798
1872
|
" \u2190 ",
|
|
1799
1873
|
pr.headRefName,
|
|
1800
1874
|
" | by ",
|
|
1801
|
-
((
|
|
1875
|
+
((_h = pr.author) == null ? void 0 : _h.login) ?? "unknown",
|
|
1802
1876
|
" | ",
|
|
1803
|
-
((
|
|
1877
|
+
((_i = pr.commits) == null ? void 0 : _i.length) ?? 0,
|
|
1804
1878
|
" ",
|
|
1805
1879
|
"commits",
|
|
1806
1880
|
pr.createdAt && ` | opened ${timeAgo(pr.createdAt)}`,
|
|
@@ -1817,64 +1891,11 @@ function PRDetailsBox({ pr, loading, error, isActive, title = "[3] PR Details",
|
|
|
1817
1891
|
pr.deletions
|
|
1818
1892
|
] })
|
|
1819
1893
|
] }),
|
|
1820
|
-
(((
|
|
1821
|
-
/* @__PURE__ */
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
] }),
|
|
1826
|
-
((((_e = pr.reviews) == null ? void 0 : _e.length) ?? 0) > 0 || (((_f = pr.reviewRequests) == null ? void 0 : _f.length) ?? 0) > 0) && /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, flexDirection: "column", children: [
|
|
1827
|
-
/* @__PURE__ */ jsxs4(Box4, { children: [
|
|
1828
|
-
/* @__PURE__ */ jsx5(Text4, { dimColor: true, children: "Reviews: " }),
|
|
1829
|
-
/* @__PURE__ */ jsx5(Text4, { color: reviewDisplay.color, children: reviewDisplay.text })
|
|
1830
|
-
] }),
|
|
1831
|
-
(_g = pr.reviews) == null ? void 0 : _g.map((review, idx) => {
|
|
1832
|
-
const color = review.state === "APPROVED" ? "green" : review.state === "CHANGES_REQUESTED" ? "red" : review.state === "COMMENTED" ? "blue" : "yellow";
|
|
1833
|
-
const icon = review.state === "APPROVED" ? "\u2713" : review.state === "CHANGES_REQUESTED" ? "\u2717" : review.state === "COMMENTED" ? "\u{1F4AC}" : "\u25CB";
|
|
1834
|
-
return /* @__PURE__ */ jsxs4(Text4, { color, children: [
|
|
1835
|
-
" ",
|
|
1836
|
-
icon,
|
|
1837
|
-
" ",
|
|
1838
|
-
review.author.login
|
|
1839
|
-
] }, idx);
|
|
1840
|
-
}),
|
|
1841
|
-
(_h = pr.reviewRequests) == null ? void 0 : _h.map((r, idx) => /* @__PURE__ */ jsxs4(Text4, { color: "yellow", children: [
|
|
1842
|
-
" ",
|
|
1843
|
-
"\u25CB ",
|
|
1844
|
-
r.login ?? r.name ?? r.slug ?? "Team",
|
|
1845
|
-
" ",
|
|
1846
|
-
/* @__PURE__ */ jsx5(Text4, { dimColor: true, children: "(pending)" })
|
|
1847
|
-
] }, `pending-${idx}`))
|
|
1848
|
-
] }),
|
|
1849
|
-
(((_i = pr.statusCheckRollup) == null ? void 0 : _i.length) ?? 0) > 0 && /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, flexDirection: "column", children: [
|
|
1850
|
-
/* @__PURE__ */ jsx5(Divider, {}),
|
|
1851
|
-
/* @__PURE__ */ jsx5(Text4, { dimColor: true, children: "Checks:" }),
|
|
1852
|
-
Array.from(
|
|
1853
|
-
((_j = pr.statusCheckRollup) == null ? void 0 : _j.reduce((acc, check) => {
|
|
1854
|
-
const key = check.name ?? check.context ?? "";
|
|
1855
|
-
const existing = acc.get(key);
|
|
1856
|
-
if (!existing || (check.startedAt ?? "") > (existing.startedAt ?? "")) {
|
|
1857
|
-
acc.set(key, check);
|
|
1858
|
-
}
|
|
1859
|
-
return acc;
|
|
1860
|
-
}, /* @__PURE__ */ new Map()).values()) ?? []
|
|
1861
|
-
).sort((a, b) => CHECK_SORT_ORDER[resolveCheckStatus(a)] - CHECK_SORT_ORDER[resolveCheckStatus(b)]).map((check, idx) => {
|
|
1862
|
-
const jobName = check.name ?? check.context;
|
|
1863
|
-
const displayName = check.workflowName ? `${check.workflowName} / ${jobName}` : jobName;
|
|
1864
|
-
const status = resolveCheckStatus(check);
|
|
1865
|
-
return /* @__PURE__ */ jsxs4(Text4, { color: CHECK_COLORS[status], children: [
|
|
1866
|
-
" ",
|
|
1867
|
-
CHECK_ICONS[status],
|
|
1868
|
-
" ",
|
|
1869
|
-
displayName
|
|
1870
|
-
] }, idx);
|
|
1871
|
-
})
|
|
1872
|
-
] }),
|
|
1873
|
-
pr.body && /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, flexDirection: "column", children: [
|
|
1874
|
-
/* @__PURE__ */ jsx5(Divider, {}),
|
|
1875
|
-
/* @__PURE__ */ jsx5(Text4, { dimColor: true, children: "Description:" }),
|
|
1876
|
-
/* @__PURE__ */ jsx5(Markdown, { children: pr.body })
|
|
1877
|
-
] })
|
|
1894
|
+
(((_j = pr.labels) == null ? void 0 : _j.length) ?? 0) > 0 && /* @__PURE__ */ jsx5(Box4, { gap: 1, children: pr.labels.map((l) => /* @__PURE__ */ jsx5(Box4, { children: /* @__PURE__ */ jsx5(Badge, { color: "black", background: "gray", children: l.name }) }, l.name)) }),
|
|
1895
|
+
sections.map((section) => /* @__PURE__ */ jsxs4(React.Fragment, { children: [
|
|
1896
|
+
/* @__PURE__ */ jsx5(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx5(Divider, {}) }),
|
|
1897
|
+
section.content
|
|
1898
|
+
] }, section.key))
|
|
1878
1899
|
] })
|
|
1879
1900
|
] }) }) }) });
|
|
1880
1901
|
}
|
|
@@ -5705,18 +5726,14 @@ function AllPullRequestsView({ isActive, onModalChange }) {
|
|
|
5705
5726
|
const borderColor = isActive ? "yellow" : void 0;
|
|
5706
5727
|
const scrollRatio = isActive && prs.length > 1 ? highlightedIndex / (prs.length - 1) : null;
|
|
5707
5728
|
const stateColor = (pr) => {
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
});
|
|
5713
|
-
return display.color;
|
|
5729
|
+
if (pr.state === "MERGED") return "magenta";
|
|
5730
|
+
if (pr.state === "CLOSED") return "red";
|
|
5731
|
+
if (pr.isDraft) return "gray";
|
|
5732
|
+
return "green";
|
|
5714
5733
|
};
|
|
5715
|
-
const
|
|
5716
|
-
if (pr.
|
|
5717
|
-
|
|
5718
|
-
if (pr.state === "CLOSED") return "Closed";
|
|
5719
|
-
return "Open";
|
|
5734
|
+
const stateIcon = (pr) => {
|
|
5735
|
+
if (pr.state === "MERGED") return "\uE727";
|
|
5736
|
+
return "\uE726";
|
|
5720
5737
|
};
|
|
5721
5738
|
if (detailPR) {
|
|
5722
5739
|
const hintFooter = checkoutLoading ? /* @__PURE__ */ jsx24(Box22, { paddingX: 1, children: /* @__PURE__ */ jsxs22(Text21, { color: "yellow", children: [
|
|
@@ -5769,25 +5786,19 @@ function AllPullRequestsView({ isActive, onModalChange }) {
|
|
|
5769
5786
|
cursor,
|
|
5770
5787
|
" "
|
|
5771
5788
|
] }),
|
|
5772
|
-
/* @__PURE__ */ jsxs22(Text21, { children: [
|
|
5773
|
-
|
|
5774
|
-
pr.number
|
|
5775
|
-
] }),
|
|
5776
|
-
/* @__PURE__ */ jsxs22(Text21, { children: [
|
|
5777
|
-
" ",
|
|
5778
|
-
pr.title,
|
|
5789
|
+
/* @__PURE__ */ jsxs22(Text21, { color: stateColor(pr), children: [
|
|
5790
|
+
stateIcon(pr),
|
|
5779
5791
|
" "
|
|
5780
5792
|
] }),
|
|
5781
|
-
|
|
5782
|
-
"[",
|
|
5783
|
-
stateLabel(pr),
|
|
5784
|
-
"]"
|
|
5785
|
-
] })
|
|
5793
|
+
/* @__PURE__ */ jsx24(Text21, { children: pr.title })
|
|
5786
5794
|
] }),
|
|
5787
5795
|
/* @__PURE__ */ jsxs22(Box22, { children: [
|
|
5788
5796
|
/* @__PURE__ */ jsx24(Text21, { children: " " }),
|
|
5789
5797
|
/* @__PURE__ */ jsxs22(Text21, { dimColor: true, children: [
|
|
5790
5798
|
" ",
|
|
5799
|
+
"#",
|
|
5800
|
+
pr.number,
|
|
5801
|
+
" \xB7 ",
|
|
5791
5802
|
pr.author.login,
|
|
5792
5803
|
" \xB7 ",
|
|
5793
5804
|
timeAgo(pr.createdAt)
|