1
1
import { create } from 'zustand' ;
2
2
import { Octokit } from '@octokit/rest' ;
3
3
import type { PullRequest , Repository } from '../types/github' ;
4
+ import { persist } from 'zustand/middleware' ;
4
5
5
6
interface GithubStore {
6
7
repository : Repository | null ;
7
8
pullRequests : PullRequest [ ] ;
8
9
isLoading : boolean ;
9
10
error : string | null ;
11
+ checkedPRs : Record < string , boolean > ;
10
12
setRepository : ( repoUrl : string ) => Promise < void > ;
11
13
fetchPullRequests : ( ) => Promise < void > ;
14
+ togglePRCheck : ( prUrl : string ) => void ;
12
15
}
13
16
14
17
const parseRepoUrl = ( url : string ) : Repository | null => {
@@ -34,100 +37,123 @@ const octokit = new Octokit({
34
37
} ,
35
38
} ) ;
36
39
37
- export const useGithubStore = create < GithubStore > ( ( set , get ) => ( {
38
- repository : null ,
39
- pullRequests : [ ] ,
40
- isLoading : false ,
41
- error : null ,
40
+ export const useGithubStore = create < GithubStore > ( ) (
41
+ persist (
42
+ ( set , get ) => ( {
43
+ repository : null ,
44
+ pullRequests : [ ] ,
45
+ isLoading : false ,
46
+ error : null ,
47
+ checkedPRs : { } ,
42
48
43
- setRepository : async ( repoUrl : string ) => {
44
- const repo = parseRepoUrl ( repoUrl ) ;
45
- if ( ! repo ) {
46
- set ( { error : 'Invalid repository URL' } ) ;
47
- return ;
48
- }
49
+ setRepository : async ( repoUrl : string ) => {
50
+ const repo = parseRepoUrl ( repoUrl ) ;
51
+ if ( ! repo ) {
52
+ set ( { error : 'Invalid repository URL' } ) ;
53
+ return ;
54
+ }
49
55
50
- set ( { repository : repo , error : null } ) ;
51
- await get ( ) . fetchPullRequests ( ) ;
52
- } ,
56
+ set ( ( state ) => ( {
57
+ repository : repo ,
58
+ error : null ,
59
+ checkedPRs : state . checkedPRs
60
+ } ) ) ;
61
+ await get ( ) . fetchPullRequests ( ) ;
62
+ } ,
53
63
54
- fetchPullRequests : async ( ) => {
55
- const { repository } = get ( ) ;
56
- if ( ! repository ) return ;
64
+ fetchPullRequests : async ( ) => {
65
+ const { repository } = get ( ) ;
66
+ if ( ! repository ) return ;
57
67
58
- set ( { isLoading : true , error : null } ) ;
68
+ set ( { isLoading : true , error : null } ) ;
59
69
60
- try {
61
- // Check rate limit first
62
- const { data : rateLimit } = await octokit . rateLimit . get ( ) ;
63
- if ( rateLimit . rate . remaining === 0 ) {
64
- const resetDate = new Date ( rateLimit . rate . reset * 1000 ) ;
65
- throw new Error ( `API rate limit exceeded. Resets at ${ resetDate . toLocaleTimeString ( ) } ` ) ;
66
- }
70
+ try {
71
+ // Check rate limit first
72
+ const { data : rateLimit } = await octokit . rateLimit . get ( ) ;
73
+ if ( rateLimit . rate . remaining === 0 ) {
74
+ const resetDate = new Date ( rateLimit . rate . reset * 1000 ) ;
75
+ throw new Error ( `API rate limit exceeded. Resets at ${ resetDate . toLocaleTimeString ( ) } ` ) ;
76
+ }
67
77
68
- const { data : prs } = await octokit . pulls . list ( {
69
- owner : repository . owner ,
70
- repo : repository . name ,
71
- state : 'all' ,
72
- sort : 'updated' ,
73
- direction : 'desc' ,
74
- per_page : 100 ,
75
- } ) ;
78
+ const { data : prs } = await octokit . pulls . list ( {
79
+ owner : repository . owner ,
80
+ repo : repository . name ,
81
+ state : 'all' ,
82
+ sort : 'updated' ,
83
+ direction : 'desc' ,
84
+ per_page : 100 ,
85
+ } ) ;
76
86
77
- // Fetch merged status and comments for each PR
78
- const prsWithDetails = await Promise . all (
79
- prs . map ( async ( pr ) => {
80
- try {
81
- const [ prDetails , reviewComments , issueComments ] = await Promise . all ( [
82
- pr . state === 'closed' ?
83
- octokit . pulls . get ( {
84
- owner : repository . owner ,
85
- repo : repository . name ,
86
- pull_number : pr . number ,
87
- } ) :
88
- Promise . resolve ( { data : { merged : false } } ) ,
89
- octokit . pulls . listReviewComments ( {
90
- owner : repository . owner ,
91
- repo : repository . name ,
92
- pull_number : pr . number ,
93
- per_page : 100 ,
94
- } ) ,
95
- octokit . issues . listComments ( {
96
- owner : repository . owner ,
97
- repo : repository . name ,
98
- issue_number : pr . number ,
99
- per_page : 100 ,
100
- } )
101
- ] ) ;
87
+ // Fetch merged status and comments for each PR
88
+ const prsWithDetails = await Promise . all (
89
+ prs . map ( async ( pr ) => {
90
+ try {
91
+ const [ prDetails , reviewComments , issueComments ] = await Promise . all ( [
92
+ pr . state === 'closed' ?
93
+ octokit . pulls . get ( {
94
+ owner : repository . owner ,
95
+ repo : repository . name ,
96
+ pull_number : pr . number ,
97
+ } ) :
98
+ Promise . resolve ( { data : { merged : false } } ) ,
99
+ octokit . pulls . listReviewComments ( {
100
+ owner : repository . owner ,
101
+ repo : repository . name ,
102
+ pull_number : pr . number ,
103
+ per_page : 100 ,
104
+ } ) ,
105
+ octokit . issues . listComments ( {
106
+ owner : repository . owner ,
107
+ repo : repository . name ,
108
+ issue_number : pr . number ,
109
+ per_page : 100 ,
110
+ } )
111
+ ] ) ;
102
112
103
- const totalComments = reviewComments . data . length + issueComments . data . length ;
113
+ const totalComments = reviewComments . data . length + issueComments . data . length ;
104
114
105
- return {
106
- ...pr ,
107
- merged : prDetails . data . merged || false ,
108
- comments : totalComments
109
- } as PullRequest ;
110
- } catch ( err ) {
111
- console . error ( `Error fetching details for PR #${ pr . number } :` , err ) ;
112
- return {
113
- ...pr ,
114
- merged : false ,
115
- comments : 0
116
- } as PullRequest ;
117
- }
118
- } )
119
- ) ;
115
+ return {
116
+ ...pr ,
117
+ merged : prDetails . data . merged || false ,
118
+ comments : totalComments
119
+ } as PullRequest ;
120
+ } catch ( err ) {
121
+ console . error ( `Error fetching details for PR #${ pr . number } :` , err ) ;
122
+ return {
123
+ ...pr ,
124
+ merged : false ,
125
+ comments : 0
126
+ } as PullRequest ;
127
+ }
128
+ } )
129
+ ) ;
120
130
121
- set ( { pullRequests : prsWithDetails , isLoading : false } ) ;
122
- } catch ( err ) {
123
- console . error ( 'Failed to fetch pull requests:' , err ) ;
124
- const errorMessage = err instanceof Error ? err . message : 'Failed to fetch pull requests' ;
125
- set ( {
126
- error : errorMessage . includes ( 'rate limit' ) ?
127
- errorMessage :
128
- 'Failed to fetch pull requests. Please check the repository URL and your access permissions.' ,
129
- isLoading : false
130
- } ) ;
131
+ set ( { pullRequests : prsWithDetails , isLoading : false } ) ;
132
+ } catch ( err ) {
133
+ console . error ( 'Failed to fetch pull requests:' , err ) ;
134
+ const errorMessage = err instanceof Error ? err . message : 'Failed to fetch pull requests' ;
135
+ set ( {
136
+ error : errorMessage . includes ( 'rate limit' ) ?
137
+ errorMessage :
138
+ 'Failed to fetch pull requests. Please check the repository URL and your access permissions.' ,
139
+ isLoading : false
140
+ } ) ;
141
+ }
142
+ } ,
143
+
144
+ togglePRCheck : ( prUrl : string ) =>
145
+ set ( ( state ) => ( {
146
+ checkedPRs : {
147
+ ...state . checkedPRs ,
148
+ [ prUrl ] : ! state . checkedPRs [ prUrl ]
149
+ }
150
+ } ) ) ,
151
+ } ) ,
152
+ {
153
+ name : 'github-store' ,
154
+ partialize : ( state ) => ( {
155
+ checkedPRs : state . checkedPRs ,
156
+ } ) ,
131
157
}
132
- } ,
133
- } ) ) ;
158
+ )
159
+ ) ;
0 commit comments