@@ -13,35 +13,29 @@ import {
1313import { Button } from "@unkey/ui" ;
1414import { useParams , useRouter } from "next/navigation" ;
1515import { parseAsString , useQueryStates } from "nuqs" ;
16- import { useProjectData } from "../(overview)/data-provider" ;
1716
1817const searchParamsParsers = {
19- branch : parseAsString . withDefault ( "" ) ,
20- sha : parseAsString . withDefault ( "" ) ,
21- sender : parseAsString . withDefault ( "" ) ,
22- message : parseAsString . withDefault ( "" ) ,
23- repo : parseAsString . withDefault ( "" ) ,
18+ deploymentId : parseAsString . withDefault ( "" ) ,
2419} ;
2520
2621export default function AuthorizeDeploymentPage ( ) {
2722 const params = useParams < { workspaceSlug : string ; projectId : string } > ( ) ;
2823 const router = useRouter ( ) ;
29- const { project } = useProjectData ( ) ;
3024
31- const [ { branch, sha, sender, message, repo } ] = useQueryStates ( searchParamsParsers ) ;
25+ const [ { deploymentId } ] = useQueryStates ( searchParamsParsers ) ;
26+
27+ const deployment = trpc . deploy . deployment . getById . useQuery (
28+ { deploymentId } ,
29+ { enabled : ! ! deploymentId } ,
30+ ) ;
3231
3332 const authorize = trpc . deploy . deployment . authorize . useMutation ( {
3433 onSuccess : ( ) => {
3534 router . push ( `/${ params . workspaceSlug } /projects/${ params . projectId } /deployments` ) ;
3635 } ,
3736 } ) ;
3837
39- const shortSha = sha . slice ( 0 , 7 ) ;
40- const commitURL = `https://github.com/${ repo } /commit/${ sha } ` ;
41- const branchURL = `https://github.com/${ repo } /tree/${ branch } ` ;
42- const senderURL = `https://github.com/${ sender } ` ;
43-
44- if ( ! branch || ! sha || ! / ^ [ 0 - 9 a - f ] { 40 } $ / . test ( sha ) ) {
38+ if ( ! deploymentId ) {
4539 return (
4640 < div className = "flex items-center justify-center min-h-[60vh]" >
4741 < div className = "text-center space-y-2" >
@@ -55,82 +49,79 @@ export default function AuthorizeDeploymentPage() {
5549 ) ;
5650 }
5751
58- const isStaleCommit = authorize . error ?. message ?. includes ( "no longer the HEAD" ) ;
59- const newHead = isStaleCommit ? parseNewHead ( authorize . error ?. message ) : null ;
52+ if ( deployment . isLoading ) {
53+ return (
54+ < div className = "flex items-center justify-center min-h-[60vh]" >
55+ < div className = "text-center space-y-2" >
56+ < p className = "text-sm text-content-subtle" > Loading deployment details...</ p >
57+ </ div >
58+ </ div >
59+ ) ;
60+ }
6061
61- if ( authorize . isSuccess ) {
62+ if ( deployment . error ) {
63+ return (
64+ < div className = "flex items-center justify-center min-h-[60vh]" >
65+ < div className = "text-center space-y-2" >
66+ < CircleXMark iconSize = "2xl-thin" className = "text-error-9 mx-auto" />
67+ < h2 className = "text-lg font-semibold text-content" > Deployment not found</ h2 >
68+ < p className = "text-content-subtle text-sm" > { deployment . error . message } </ p >
69+ </ div >
70+ </ div >
71+ ) ;
72+ }
73+
74+ const data = deployment . data ;
75+
76+ // Already authorized — deployment is no longer awaiting approval
77+ if ( data . status !== "awaiting_approval" ) {
78+ const isSuccess = data . status !== "failed" ;
6279 return (
6380 < div className = "flex items-center justify-center min-h-[60vh]" >
6481 < div className = "text-center space-y-3" >
65- < CircleCheck iconSize = "2xl-thin" className = "text-success-9 mx-auto" />
66- < h2 className = "text-lg font-semibold text-content" > Deployment Authorized</ h2 >
82+ { isSuccess ? (
83+ < CircleCheck iconSize = "2xl-thin" className = "text-success-9 mx-auto" />
84+ ) : (
85+ < CircleXMark iconSize = "2xl-thin" className = "text-error-9 mx-auto" />
86+ ) }
87+ < h2 className = "text-lg font-semibold text-content" >
88+ { isSuccess ? "Deployment Already Authorized" : "Deployment Failed" }
89+ </ h2 >
6790 < p className = "text-content-subtle text-sm" >
68- The deployment has been authorized and is now in progress.
91+ { isSuccess
92+ ? "This deployment has already been authorized and is in progress."
93+ : "This deployment has failed." }
6994 </ p >
95+ < Button
96+ variant = "outline"
97+ size = "xlg"
98+ onClick = { ( ) =>
99+ router . push ( `/${ params . workspaceSlug } /projects/${ params . projectId } /deployments` )
100+ }
101+ >
102+ View Deployments
103+ </ Button >
70104 </ div >
71105 </ div >
72106 ) ;
73107 }
74108
75- if ( isStaleCommit && newHead ) {
76- const newAuthorizeURL = `/${ params . workspaceSlug } /projects/${ params . projectId } /authorize?${ new URLSearchParams (
77- {
78- branch,
79- sha : newHead . sha ,
80- sender : newHead . author ,
81- message : newHead . message ,
82- repo,
83- } ,
84- ) . toString ( ) } `;
85-
109+ if ( authorize . isSuccess ) {
86110 return (
87111 < div className = "flex items-center justify-center min-h-[60vh]" >
88- < div className = "w-full max-w-md space-y-6" >
89- < div className = "text-center space-y-3" >
90- < ShieldAlert iconSize = "2xl-thin" className = "text-warning-9 mx-auto" />
91- < h2 className = "text-lg font-semibold text-content" > Commit is outdated</ h2 >
92- < p className = "text-sm text-content-subtle" >
93- The branch < strong className = "text-content font-mono" > { branch } </ strong > has new
94- commits since this link was created. The latest commit is{ " " }
95- < a
96- href = { `https://github.com/${ repo } /commit/${ newHead . sha } ` }
97- target = "_blank"
98- rel = "noopener noreferrer"
99- className = "font-mono text-accent-11 hover:text-accent-12"
100- >
101- { newHead . sha . slice ( 0 , 7 ) }
102- </ a >
103- .
104- </ p >
105- </ div >
106- < div className = "flex gap-3" >
107- < Button
108- variant = "primary"
109- size = "xlg"
110- className = "flex-1"
111- onClick = { ( ) => {
112- authorize . reset ( ) ;
113- router . push ( newAuthorizeURL ) ;
114- } }
115- >
116- View Latest Commit
117- </ Button >
118- < Button
119- variant = "outline"
120- size = "xlg"
121- className = "flex-1"
122- onClick = { ( ) =>
123- router . push ( `/${ params . workspaceSlug } /projects/${ params . projectId } /deployments` )
124- }
125- >
126- Dismiss
127- </ Button >
128- </ div >
112+ < div className = "text-center space-y-3" >
113+ < CircleCheck iconSize = "2xl-thin" className = "text-success-9 mx-auto" />
114+ < h2 className = "text-lg font-semibold text-content" > Deployment Authorized</ h2 >
115+ < p className = "text-content-subtle text-sm" >
116+ The deployment has been authorized and is now in progress.
117+ </ p >
129118 </ div >
130119 </ div >
131120 ) ;
132121 }
133122
123+ const shortSha = data . gitCommitSha ?. slice ( 0 , 7 ) ?? "" ;
124+
134125 return (
135126 < div className = "flex items-center justify-center min-h-[60vh]" >
136127 < div className = "w-full max-w-md space-y-6" >
@@ -153,57 +144,53 @@ export default function AuthorizeDeploymentPage() {
153144 < div className = "text-center space-y-2" >
154145 < h1 className = "text-xl font-semibold text-content" > Authorization Required</ h1 >
155146 < p className = "text-sm text-content-subtle" >
156- An external contributor pushed to{ " " }
157- < strong className = "text-content" > { project ?. name ?? "this project" } </ strong > . A team
158- member must authorize this deployment before it can proceed.
147+ An external contributor pushed a commit. A team member must authorize this deployment
148+ before it can proceed.
159149 </ p >
160150 </ div >
161151
162152 { /* Commit details */ }
163153 < div className = "border border-border rounded-lg divide-y divide-border" >
164- < div className = "flex items-center gap-3 px-4 py-3" >
165- < CodeBranch iconSize = "md-thin" className = "text-content-subtle shrink-0" />
166- < span className = "text-sm text-content-subtle" > Branch</ span >
167- < a
168- href = { branchURL }
169- target = "_blank"
170- rel = "noopener noreferrer"
171- className = "ml-auto text-sm font-mono text-accent-11 hover:text-accent-12 bg-background-subtle px-2 py-0.5 rounded"
172- >
173- { branch }
174- </ a >
175- </ div >
154+ { data . gitBranch && (
155+ < div className = "flex items-center gap-3 px-4 py-3" >
156+ < CodeBranch iconSize = "md-thin" className = "text-content-subtle shrink-0" />
157+ < span className = "text-sm text-content-subtle" > Branch</ span >
158+ < span className = "ml-auto text-sm font-mono text-content bg-background-subtle px-2 py-0.5 rounded" >
159+ { data . gitBranch }
160+ </ span >
161+ </ div >
162+ ) }
176163
177- < div className = "flex items-center gap-3 px-4 py-3" >
178- < CodeCommit iconSize = "md-thin" className = "text-content-subtle shrink-0" />
179- < span className = "text-sm text-content-subtle" > Commit</ span >
180- < a
181- href = { commitURL }
182- target = "_blank"
183- rel = "noopener noreferrer"
184- className = "ml-auto text-sm font-mono text-accent-11 hover:text-accent-12 bg-background-subtle px-2 py-0.5 rounded"
185- >
186- { shortSha }
187- </ a >
188- </ div >
164+ { shortSha && (
165+ < div className = "flex items-center gap-3 px-4 py-3" >
166+ < CodeCommit iconSize = "md-thin" className = "text-content-subtle shrink-0" />
167+ < span className = "text-sm text-content-subtle" > Commit</ span >
168+ < span className = "ml-auto text-sm font-mono text-content bg-background-subtle px-2 py-0.5 rounded" >
169+ { shortSha }
170+ </ span >
171+ </ div >
172+ ) }
189173
190- { message && (
174+ { data . gitCommitMessage && (
191175 < div className = "px-4 py-3" >
192- < p className = "text-sm text-content truncate" > { message } </ p >
176+ < p className = "text-sm text-content truncate" > { data . gitCommitMessage } </ p >
193177 </ div >
194178 ) }
195179
196- < div className = "flex items-center gap-3 px-4 py-3" >
197- < User iconSize = "md-thin" className = "text-content-subtle shrink-0" />
198- < a
199- href = { senderURL }
200- target = "_blank"
201- rel = "noopener noreferrer"
202- className = "text-sm text-accent-11 hover:text-accent-12"
203- >
204- { sender }
205- </ a >
206- </ div >
180+ { data . gitCommitAuthorHandle && (
181+ < div className = "flex items-center gap-3 px-4 py-3" >
182+ { data . gitCommitAuthorAvatarUrl ? (
183+ < img
184+ src = { data . gitCommitAuthorAvatarUrl }
185+ alt = { data . gitCommitAuthorHandle }
186+ className = "w-5 h-5 rounded-full shrink-0"
187+ />
188+ ) : (
189+ < User iconSize = "md-thin" className = "text-content-subtle shrink-0" />
190+ ) }
191+ < span className = "text-sm text-content" > { data . gitCommitAuthorHandle } </ span >
192+ </ div >
193+ ) }
207194 </ div >
208195
209196 { /* Error */ }
@@ -221,13 +208,7 @@ export default function AuthorizeDeploymentPage() {
221208 size = "xlg"
222209 className = "flex-1"
223210 loading = { authorize . isLoading }
224- onClick = { ( ) =>
225- authorize . mutate ( {
226- projectId : params . projectId ,
227- branch,
228- commitSha : sha ,
229- } )
230- }
211+ onClick = { ( ) => authorize . mutate ( { deploymentId } ) }
231212 >
232213 Authorize Deployment
233214 </ Button >
@@ -251,24 +232,3 @@ export default function AuthorizeDeploymentPage() {
251232 </ div >
252233 ) ;
253234}
254-
255- function parseNewHead (
256- errorMessage : string | undefined ,
257- ) : { sha : string ; message : string ; author : string } | null {
258- if ( ! errorMessage ) {
259- return null ;
260- }
261- const shaMatch = errorMessage . match ( / c u r r e n t _ h e a d _ s h a = ( [ 0 - 9 a - f ] { 40 } ) / ) ;
262- const messageMatch = errorMessage . match (
263- / c u r r e n t _ h e a d _ m e s s a g e = ( .+ ?) (?: \s + c u r r e n t _ h e a d _ a u t h o r = | $ ) / ,
264- ) ;
265- const authorMatch = errorMessage . match ( / c u r r e n t _ h e a d _ a u t h o r = ( \S + ) / ) ;
266- if ( ! shaMatch ) {
267- return null ;
268- }
269- return {
270- sha : shaMatch [ 1 ] ,
271- message : messageMatch ?. [ 1 ] ?? "" ,
272- author : authorMatch ?. [ 1 ] ?? "" ,
273- } ;
274- }
0 commit comments