22 <Panel
33 class =" bg-transparent border-none"
44 header =" Lychee Pull Requests"
5- :pt:header:class =" 'justify-center text-3xl font-bold mb-8'"
5+ :pt:header:class =" 'justify-center text-4xl font-bold mb-8'"
66 >
7- <div class =" flex flex-col" >
8- <div class =" flex justify-center text-left" >
9- <div v-if =" pullRequests" class =" flex flex-col gap-2" >
10- <div
11- v-for =" pr in pullRequests"
12- :key =" pr.id"
13- :class =" {
14- 'flex justify-between gap-16': true,
15- 'transition-opacity duration-100 ease-in-out opacity-50 hover:opacity-100':
16- pr.draft,
17- }"
18- >
19- <div class =" flex flex-col" >
20- <div class =" flex items-center gap-2 grow-1" >
21- <a
22- :href =" pr.html_url"
23- target =" _blank"
24- :class =" {
25- 'font-bold hover:text-sky-400': true,
26- 'text-muted-color': pr.draft,
27- }"
28- >
29- {{ pr.title }}
30- </a >
31- <Tag
32- v-for =" label in pr.labels"
33- :value =" label.name"
34- :key =" `${label.id}`"
35- v-tooltip =" label.description"
36- :pt:label:class =" 'text-2xs'"
37- :dt =" {
38- padding: '0.15rem 0.5rem',
39- }"
40- :style =" {
41- backgroundColor: `#${label.color}`,
42- color: getFrontColor(`#${label.color}`),
43- }"
44- ></Tag >
45- </div >
46-
47- <div class =" text-muted-color text-xs w-full" >
48- <span class =" text-muted-color-emphasis" >#{{ pr.number }}</span >
49- opened by <UserTag :user =" pr.user" />
50- <span v-if =" pr.base.ref !== 'master'" class =" ml-2" >
51- &rArr ;
52- <span class =" ml-2 text-primary-emphasis" >{{
53- pr.base.ref
54- }}</span >
55- </span >
56- </div >
57- </div >
7+ <div class =" flex flex-col max-w-4xl mx-auto gap-4 text-left" >
8+ <template v-if =" pullRequests " >
9+ <template v-if =" pullRequests .length === 1 " >
10+ <PrList v-if =" pullRequests" :pull-requests =" pullRequests[0].data" />
11+ </template >
12+ <template v-else >
13+ <div v-for =" (group, idx) in pullRequests" :key =" idx" class =" group" >
5814 <div
59- v-if =" pr.review && pr.review.changes_requested"
60- class =" text-red-400 font-bold"
61- >
62- Changes requested.
63- </div >
64- <div v-else-if =" pr.review && pr.review.approved" class =" flex flex-col" >
65- <div class =" text-green-500 text-right" >Approved</div >
66- <div class =" text-xs" >
67- by
68- <UserTag
69- v-for =" (user, idx) in pr.review.by"
70- :user =" user"
71- :key =" `u${pr.id}-${idx}`"
72- />
73- </div >
74- </div >
75- <div
76- v-else-if =" !pr.draft"
7715 :class =" {
78- 'shrink-1': true,
79- 'text-orange-400': !pr.draft && isMoreThanXdays(pr.created_at, 7),
80- 'text-red-400': !pr.draft && isMoreThanXdays(pr.created_at, 14),
81- '': pr.draft,
16+ 'opacity-50 group-hover:opacity-100 transition-opacity duration-100 ease-in-out':
17+ allDrafts(group.data),
18+ 'mb-4 text-xl font-bold text-primary-emphasis border-b border-dashed border-surface-400': true,
8219 }"
8320 >
84- {{ computeHowLongAgo(pr.created_at) }}
85- <!-- <span v-if="isMoreThanXdays(pr.created_at, 30)">😭</span>
86- <span v-else-if="isMoreThanXdays(pr.created_at, 14)">😢</span>
87- <span v-else-if="isMoreThanXdays(pr.created_at, 7)">🥹</span>
88- <span v-else-if="isMoreThanXdays(pr.created_at, 2)">🙂</span>
89- <span v-else>😄</span> -->
90- </div >
91- <div v-else-if =" pr.draft" class =" text-muted-color" >
92- {{ computeHowLongAgo(pr.created_at) }}
93- <!-- <span>🫣</span> -->
21+ {{ group.header }}
9422 </div >
23+ <PrList :pull-requests =" group.data" />
9524 </div >
96- </div >
97- < div v-else >
98- < p >Loading...</ p >
99- </ div >
25+ </template >
26+ </ template >
27+ < div v-else >
28+ <p class = " text-center text-primary-emphasis " >Loading...</ p >
10029 </div >
10130 </div >
10231 </Panel >
10635import { Octokit } from ' octokit' ;
10736import { ref } from ' vue' ;
10837import { onMounted } from ' vue' ;
109- import Tag from ' primevue/tag' ;
11038import { Panel } from ' primevue' ;
11139import {
11240 type PullRequest ,
@@ -117,48 +45,24 @@ import {
11745 CHANGES_REQUESTED ,
11846 CONTRIBUTOR ,
11947} from ' ./ResponsesTypes.ts' ;
120- import UserTag from ' ./components/UserTag.vue' ;
48+ import { useSplitter } from ' ./composables/splitter' ;
49+ import { computed } from ' vue' ;
50+ import PrList from ' ./components/PrList.vue' ;
12151
122- const pullRequests = ref <(PullRequest & ReviewStatus )[] | undefined >(undefined );
52+ const { spliter } = useSplitter ();
53+ const pullRequestsData = ref <(PullRequest & ReviewStatus )[] | undefined >(undefined );
54+ const pullRequests = computed (() => {
55+ if (! pullRequestsData .value ) return undefined ;
56+ return spliter (pullRequestsData .value , prToGroup , prToGroup );
57+ });
12358const octokit = new Octokit ();
12459
125- function colorIsDarkSimple(bgColor : string ): boolean {
126- // Simple check for dark color based on luminance
127- const color = bgColor .charAt (0 ) === ' #' ? bgColor .substring (1 , 7 ) : bgColor ;
128- const r = parseInt (color .substring (0 , 2 ), 16 ); // hexToR
129- const g = parseInt (color .substring (2 , 4 ), 16 ); // hexToG
130- const b = parseInt (color .substring (4 , 6 ), 16 ); // hexToB
131- return r * 0.299 + g * 0.587 + b * 0.114 <= 186 ;
132- }
133-
134- function getFrontColor(bgColor : string ): string {
135- if (colorIsDarkSimple (bgColor )) {
136- return ' #ffffff' ; // white for dark backgrounds
60+ function prToGroup(pr : PullRequest ): string {
61+ if (! pr .head .ref .includes (' /' )) {
62+ return ' standalone' ;
13763 }
138- return ' #000000' ; // black for light backgrounds
139- }
140-
141- function computeHowLongAgo(dateString : string ): string {
142- const date = new Date (dateString );
143- const now = new Date ();
144- const diff = now .getTime () - date .getTime ();
145- const seconds = Math .floor (diff / 1000 );
146- const minutes = Math .floor (seconds / 60 );
147- const hours = Math .floor (minutes / 60 );
148- const days = Math .floor (hours / 24 );
149-
150- if (days > 0 ) return ` ${days } day${days > 1 ? ' s' : ' ' } ago ` ;
151- if (hours > 0 ) return ` ${hours } hour${hours > 1 ? ' s' : ' ' } ago ` ;
152- if (minutes > 0 ) return ` ${minutes } minute${minutes > 1 ? ' s' : ' ' } ago ` ;
153- return ` ${seconds } second${seconds > 1 ? ' s' : ' ' } ago ` ;
154- }
155-
156- function isMoreThanXdays(dateString : string , x : number ): boolean {
157- const date = new Date (dateString );
158- const now = new Date ();
159- const diff = now .getTime () - date .getTime ();
160- const days = Math .floor (diff / (1000 * 60 * 60 * 24 ));
161- return days > x ;
64+ // select the part before the first dash
65+ return pr .head .ref .split (' /' )[0 ] || ' standalone' ;
16266}
16367
16468async function getPrs(): Promise <void > {
@@ -168,20 +72,20 @@ async function getPrs(): Promise<void> {
16872 repo: ' Lychee' ,
16973 })
17074 .then ((response ) => {
171- pullRequests .value = response .data as unknown as PullRequest [];
75+ pullRequestsData .value = response .data as unknown as PullRequest [];
17276 })
17377 .catch ((error ) => {
17478 console .error (' Error fetching pull requests:' , error );
17579 });
17680}
17781
17882async function getStatuses() {
179- if (! pullRequests .value || pullRequests .value .length === 0 ) {
83+ if (! pullRequestsData .value || pullRequestsData .value .length === 0 ) {
18084 console .warn (' No pull requests available to fetch statuses for.' );
18185 return ;
18286 }
18387
184- pullRequests .value .forEach (async (pr , idx ) => {
88+ pullRequestsData .value .forEach (async (pr , idx ) => {
18589 await octokit .rest .pulls
18690 .listReviews ({
18791 owner: ' LycheeOrg' ,
@@ -193,12 +97,14 @@ async function getStatuses() {
19397 ` Pull request reviews for PR #${pr .number } fetched successfully: ` ,
19498 response .data ,
19599 );
196- if (! pullRequests .value ) {
197- console .warn (' pullRequests.value is undefined, cannot update review status.' );
100+ if (! pullRequestsData .value ) {
101+ console .warn (
102+ ' pullRequestsData.value is undefined, cannot update review status.' ,
103+ );
198104 return ;
199105 }
200106
201- pullRequests .value [idx ].review = extractStatusForPr (
107+ pullRequestsData .value [idx ].review = extractStatusForPr (
202108 response .data as PullRequestReview [],
203109 ).review ;
204110 })
@@ -208,6 +114,10 @@ async function getStatuses() {
208114 });
209115}
210116
117+ function allDrafts(prs : PullRequest []): boolean {
118+ return prs .every ((pr ) => pr .draft );
119+ }
120+
211121function extractStatusForPr(reviews : PullRequestReview []): ReviewStatus {
212122 // Loop through the reviews.
213123 // Ignore all the reviews that are not from the contributors.
0 commit comments