22
33import { useState } from 'react'
44import { useRouter , useSearchParams } from 'next/navigation'
5- import { AccountAuthorization } from '@/platform/app/(shell)/integrations/_components/account-authorization/account-authorization '
5+ import { ConnectionAccess } from '@/platform/app/(shell)/integrations/_components/connection-access/connection-access '
66import styles from '@/platform/app/(shell)/integrations/_components/integration-details/integration-details.module.css'
77import { ToolPermissions } from '@/platform/app/(shell)/integrations/_components/tool-permissions/tool-permissions'
88import {
99 ActionMenu ,
1010 ActivityRow ,
11- Button ,
1211 Chip ,
1312 EmptyState ,
1413 Modal ,
1514} from '@/platform/design-system/components'
15+ import { ConnectionPrompt } from '@/platform/design-system/components/connection-prompt/connection-prompt'
1616import {
1717 SettingsRow ,
1818 SettingsSurface ,
@@ -24,26 +24,23 @@ interface IntegrationDetailsProps {
2424 onChange : ( next : OrganizationIntegration ) => void
2525}
2626
27- type AccountAction =
28- | { kind : 'connect' }
29- | { kind : 'reconnect' | 'disconnect' ; account : IntegrationAccount }
30-
3127function accountStatus ( account : IntegrationAccount ) {
3228 return account . status === 'active' ? 'Connected' : 'Reconnect needed'
3329}
3430
3531export function IntegrationDetails ( { integration, onChange } : IntegrationDetailsProps ) {
3632 const router = useRouter ( )
3733 const search = useSearchParams ( )
38- const [ action , setAction ] = useState < AccountAction | null > ( null )
34+ const [ removing , setRemoving ] = useState < IntegrationAccount | null > ( null )
3935 const { accounts, providerId, connectableMethod } = integration
4036 const requested = search . get ( 'account' )
4137 const selected = requested
4238 ? accounts . find ( ( entry ) => entry . id === requested )
4339 : accounts . length === 1
4440 ? accounts [ 0 ]
4541 : undefined
46- const canConnect = integration . availability === 'ready' && connectableMethod !== null
42+ const canConnect =
43+ ! accounts . length && integration . availability === 'ready' && connectableMethod !== null
4744 const candidate = integration . connectionCandidate
4845 const canAttach =
4946 integration . fixtureAuthorization &&
@@ -59,6 +56,26 @@ export function IntegrationDetails({ integration, onChange }: IntegrationDetails
5956 return `/integrations/${ encodeURIComponent ( providerId ) } ${ next . size ? `?${ next } ` : '' } `
6057 }
6158
59+ function connect ( ) {
60+ if ( ! canAttach || ! candidate ) return
61+ onChange ( {
62+ ...integration ,
63+ accounts : [ candidate ] ,
64+ connectableMethod : null ,
65+ connectionCandidate : undefined ,
66+ } )
67+ }
68+
69+ function reconnect ( account : IntegrationAccount ) {
70+ if ( ! integration . fixtureAuthorization || ! account . canReconnect ) return
71+ onChange ( {
72+ ...integration ,
73+ accounts : accounts . map ( ( item ) =>
74+ item . id === account . id ? { ...item , status : 'active' } : item
75+ ) ,
76+ } )
77+ }
78+
6279 function disconnect ( account : IntegrationAccount ) {
6380 const restore = integration . availability === 'ready' && account . canReconnect
6481 onChange ( {
@@ -95,27 +112,16 @@ export function IntegrationDetails({ integration, onChange }: IntegrationDetails
95112 )
96113 }
97114 if ( integration . availability === 'managed' && ! accounts . length ) {
98- return (
99- < EmptyState
100- title = 'Organization managed'
101- description = 'Your access follows your GitLab project permissions.'
102- />
103- )
115+ return < EmptyState title = 'Organization managed' description = { integration . accessDescription } />
104116 }
105117
118+ const accountHeading = ! selected && accounts . length > 1 ? 'Accounts' : 'Account'
106119 return (
107120 < div className = { styles . sections } >
108- < section className = { styles . account } aria-label = { selected ? 'Account' : 'Accounts' } >
121+ < section className = { styles . account } aria-label = { accountHeading } >
109122 < header className = { styles . header } >
110- < h2 data-type = 'T093' > { selected ? 'Account' : 'Accounts' } </ h2 >
111- < div className = { styles . actions } >
112- { selected && accounts . length > 1 && < Chip href = { accountHref ( ) } > All accounts</ Chip > }
113- { canConnect && accounts . length > 0 && (
114- < Button size = 'compact' onClick = { ( ) => setAction ( { kind : 'connect' } ) } >
115- Add account
116- </ Button >
117- ) }
118- </ div >
123+ < h2 data-type = 'T093' > { accountHeading } </ h2 >
124+ { selected && accounts . length > 1 && < Chip href = { accountHref ( ) } > All accounts</ Chip > }
119125 </ header >
120126 { selected ? (
121127 < SettingsSurface >
@@ -131,7 +137,8 @@ export function IntegrationDetails({ integration, onChange }: IntegrationDetails
131137 {
132138 id : 'reconnect' ,
133139 label : 'Reconnect account' ,
134- onSelect : ( ) => setAction ( { kind : 'reconnect' , account : selected } ) ,
140+ disabled : ! integration . fixtureAuthorization ,
141+ onSelect : ( ) => reconnect ( selected ) ,
135142 } ,
136143 ]
137144 : [ ] ) ,
@@ -140,7 +147,7 @@ export function IntegrationDetails({ integration, onChange }: IntegrationDetails
140147 label : 'Disconnect account' ,
141148 destructive : true ,
142149 separatorBefore : selected . canReconnect ,
143- onSelect : ( ) => setAction ( { kind : 'disconnect' , account : selected } ) ,
150+ onSelect : ( ) => setRemoving ( selected ) ,
144151 } ,
145152 ] }
146153 />
@@ -157,18 +164,21 @@ export function IntegrationDetails({ integration, onChange }: IntegrationDetails
157164 />
158165 ) ) }
159166 </ ul >
160- ) : (
161- < EmptyState
162- title = 'No accounts connected'
163- action = {
164- canConnect ? (
165- < Button size = 'compact' onClick = { ( ) => setAction ( { kind : 'connect' } ) } >
166- Connect account
167- </ Button >
168- ) : undefined
169- }
167+ ) : canConnect ? (
168+ < ConnectionPrompt
169+ title = { `Connect your ${ integration . name } account` }
170+ options = { [
171+ {
172+ label : integration . name ,
173+ icon : { providerId : integration . providerId } ,
174+ onConnect : canAttach ? connect : undefined ,
175+ } ,
176+ ] }
170177 />
178+ ) : (
179+ < EmptyState title = 'No accounts connected' description = { integration . accessDescription } />
171180 ) }
181+ < ConnectionAccess integration = { integration } />
172182 </ section >
173183 { selected ?. permissions && (
174184 < ToolPermissions
@@ -185,56 +195,16 @@ export function IntegrationDetails({ integration, onChange }: IntegrationDetails
185195 }
186196 />
187197 ) }
188- { action ?. kind === 'disconnect' && (
198+ { removing && (
189199 < Modal
190200 open
191- onOpenChange = { ( ) => setAction ( null ) }
201+ onOpenChange = { ( ) => setRemoving ( null ) }
192202 title = 'Disconnect account?'
193203 variant = 'confirm'
194204 destructive
195- description = { `Sim will lose access to ${ action . account . label } .` }
205+ description = { `Sim will lose access to ${ removing . label } .` }
196206 confirmLabel = 'Disconnect'
197- onConfirm = { ( ) => disconnect ( action . account ) }
198- />
199- ) }
200- { action ?. kind === 'connect' && canConnect && connectableMethod && (
201- < AccountAuthorization
202- provider = { integration . name }
203- method = { connectableMethod }
204- candidateLabel = { candidate ?. label }
205- onClose = { ( ) => setAction ( null ) }
206- onAuthorize = {
207- canAttach && candidate
208- ? ( ) => {
209- onChange ( {
210- ...integration ,
211- accounts : [ ...accounts , candidate ] ,
212- connectableMethod : null ,
213- connectionCandidate : undefined ,
214- } )
215- router . replace ( accountHref ( candidate . id ) , { scroll : false } )
216- }
217- : undefined
218- }
219- />
220- ) }
221- { action ?. kind === 'reconnect' && action . account . canReconnect && (
222- < AccountAuthorization
223- provider = { integration . name }
224- method = { action . account . method }
225- account = { action . account }
226- onClose = { ( ) => setAction ( null ) }
227- onAuthorize = {
228- integration . fixtureAuthorization
229- ? ( ) =>
230- onChange ( {
231- ...integration ,
232- accounts : accounts . map ( ( entry ) =>
233- entry . id === action . account . id ? { ...entry , status : 'active' } : entry
234- ) ,
235- } )
236- : undefined
237- }
207+ onConfirm = { ( ) => disconnect ( removing ) }
238208 />
239209 ) }
240210 </ div >
0 commit comments