@@ -13,6 +13,7 @@ import {
1313 resolveCredentialDisplay ,
1414 resolveOAuthServiceForIntegration ,
1515} from '@/lib/integrations'
16+ import { getServiceAccountMetadata } from '@/lib/integrations/service-account-metadata'
1617import { credentialProviderMatchesService } from '@/lib/oauth'
1718import { ConnectOAuthModal } from '@/app/workspace/[workspaceId]/components/connect-oauth-modal'
1819import { RESOURCE_TILE_BASE } from '@/app/workspace/[workspaceId]/components/resource-tile'
@@ -40,6 +41,7 @@ import {
4041} from '@/blocks/registry'
4142import { useWorkspaceCredentials } from '@/hooks/queries/credentials'
4243import { useOAuthReturnRouter } from '@/hooks/use-oauth-return'
44+ import { usePermissionConfig } from '@/hooks/use-permission-config'
4345
4446/** Maximum number of overlapping icon tiles rendered per template row. */
4547const TEMPLATE_CLUSTER_MAX = 3 as const
@@ -64,6 +66,9 @@ export function IntegrationBlockDetail({ integration, workspaceId }: Integration
6466 const matchingTemplates = getTemplatesForBlock ( integration . type )
6567 const suggestedSkills = getSuggestedSkillsForBlock ( integration . type )
6668 const oauthService = resolveOAuthServiceForIntegration ( integration )
69+ const { integrationAvailability, isLoading : permissionConfigLoading } = usePermissionConfig ( )
70+ const availability = integrationAvailability . get ( integration . type . toLowerCase ( ) )
71+ const oauthAvailable = Boolean ( oauthService ) && ( availability ?. oauthAvailable ?? true )
6772 const [ oauthOpen , setOAuthOpen ] = useState ( false )
6873
6974 const { data : credentials = [ ] , isPending : credentialsLoading } = useWorkspaceCredentials ( {
@@ -93,40 +98,61 @@ export function IntegrationBlockDetail({ integration, workspaceId }: Integration
9398 serviceName : oauthService ?. serviceName ,
9499 serviceIcon : oauthService ?. serviceIcon ,
95100 } )
96- const hasServiceAccount = Boolean ( serviceAccountTarget ) && ! serviceAccountTarget ?. hidden
101+ const serviceAccountMetadata = integration . oauthServiceId
102+ ? getServiceAccountMetadata ( integration . oauthServiceId )
103+ : undefined
104+ const serviceAccountDeploymentAvailable =
105+ availability ?. state === 'ready' ||
106+ availability ?. state === 'limited' ||
107+ ( availability ?. state === 'unavailable' &&
108+ serviceAccountMetadata ?. deploymentRequirement === 'preview-gated' )
109+ const hasServiceAccount =
110+ serviceAccountDeploymentAvailable &&
111+ Boolean ( serviceAccountTarget ) &&
112+ ! serviceAccountTarget ?. hidden
97113 const serviceAccountConnectLabel = serviceAccountTarget ?. label ?? 'Add service account'
98114 const hasHandledConnectQueryRef = useRef ( false )
99115
100116 useEffect ( ( ) => {
101- if ( hasHandledConnectQueryRef . current ) return
102- if ( ! connectMode ) return
117+ if ( hasHandledConnectQueryRef . current || ! connectMode || permissionConfigLoading ) return
103118
104- let handled = false
105- if ( connectMode === CONNECT_MODE . oauth && oauthService ) {
119+ if ( connectMode === CONNECT_MODE . oauth && oauthService && oauthAvailable ) {
106120 setOAuthOpen ( true )
107- handled = true
108121 } else if ( connectMode === CONNECT_MODE . serviceAccount && hasServiceAccount ) {
109122 setServiceAccountOpen ( true )
110- handled = true
111123 }
112- if ( ! handled ) return
113124
114125 hasHandledConnectQueryRef . current = true
115126 void setConnectMode ( null , { history : 'replace' , scroll : false } )
116- } , [ connectMode , oauthService , hasServiceAccount , setConnectMode ] )
127+ } , [
128+ connectMode ,
129+ oauthService ,
130+ oauthAvailable ,
131+ hasServiceAccount ,
132+ permissionConfigLoading ,
133+ setConnectMode ,
134+ ] )
117135
118136 const connectOptions = oauthService
119137 ? [
120- {
121- value : CONNECT_MODE . oauth ,
122- label : 'Connect with OAuth' ,
123- icon : oauthService . serviceIcon ,
124- } ,
125- {
126- value : CONNECT_MODE . serviceAccount ,
127- label : serviceAccountConnectLabel ,
128- icon : serviceAccountTarget ?. serviceIcon ?? oauthService . serviceIcon ,
129- } ,
138+ ...( oauthAvailable
139+ ? [
140+ {
141+ value : CONNECT_MODE . oauth ,
142+ label : 'Connect with OAuth' ,
143+ icon : oauthService . serviceIcon ,
144+ } ,
145+ ]
146+ : [ ] ) ,
147+ ...( hasServiceAccount
148+ ? [
149+ {
150+ value : CONNECT_MODE . serviceAccount ,
151+ label : serviceAccountConnectLabel ,
152+ icon : serviceAccountTarget ?. serviceIcon ?? oauthService . serviceIcon ,
153+ } ,
154+ ]
155+ : [ ] ) ,
130156 ]
131157 : [ ]
132158
@@ -148,7 +174,7 @@ export function IntegrationBlockDetail({ integration, workspaceId }: Integration
148174 </ ChipLink >
149175 < div className = { cn ( 'ml-auto' , HEADER_ACTION_CLUSTER ) } >
150176 { oauthService ? (
151- hasServiceAccount ? (
177+ connectOptions . length > 1 ? (
152178 < ChipDropdown
153179 variant = 'primary'
154180 leftIcon = { Plus }
@@ -158,10 +184,16 @@ export function IntegrationBlockDetail({ integration, workspaceId }: Integration
158184 onChange = { handleSelectConnectOption }
159185 matchTriggerWidth = { false }
160186 />
161- ) : (
187+ ) : oauthAvailable ? (
162188 < Chip variant = 'primary' leftIcon = { Plus } onClick = { ( ) => setOAuthOpen ( true ) } >
163189 Add to Sim
164190 </ Chip >
191+ ) : hasServiceAccount ? (
192+ < Chip variant = 'primary' leftIcon = { Plus } onClick = { ( ) => setServiceAccountOpen ( true ) } >
193+ { serviceAccountConnectLabel }
194+ </ Chip >
195+ ) : (
196+ < Chip disabled > Unavailable</ Chip >
165197 )
166198 ) : isChatEnabled ? (
167199 < Chip variant = 'primary' leftIcon = { Plus } onClick = { handleAddInChat } >
@@ -170,7 +202,7 @@ export function IntegrationBlockDetail({ integration, workspaceId }: Integration
170202 ) : null }
171203 </ div >
172204 </ div >
173- { oauthService && (
205+ { oauthService && oauthAvailable && (
174206 < ConnectOAuthModal
175207 mode = 'connect'
176208 origin = 'integrations'
0 commit comments