1+ import { Fragment , useEffect , useRef } from 'react' ;
2+
13import { Flex , Grid } from '@sentry/scraps/layout' ;
24
5+ import { DropdownMenu } from 'sentry/components/dropdownMenu' ;
6+ import { t } from 'sentry/locale' ;
37import type { Integration , IntegrationProvider } from 'sentry/types/integrations' ;
48import { getIntegrationIcon } from 'sentry/utils/integrationUtil' ;
9+ import { useOrganization } from 'sentry/utils/useOrganization' ;
10+ import { useAddIntegration } from 'sentry/views/settings/organizationIntegrations/addIntegration' ;
511import { IntegrationButton } from 'sentry/views/settings/organizationIntegrations/integrationButton' ;
612import { IntegrationContext } from 'sentry/views/settings/organizationIntegrations/integrationContext' ;
713
8- import { ScmProvidersDropdown } from './scmProvidersDropdown' ;
9-
1014/**
1115 * Provider keys shown as top-level pill buttons. Everything else is grouped
1216 * into the "More" dropdown to reduce visual clutter.
@@ -19,17 +23,24 @@ interface ScmProviderPillsProps {
1923}
2024
2125export function ScmProviderPills ( { providers, onInstall} : ScmProviderPillsProps ) {
26+ const flowMapRef = useRef < Map < string , ( ) => void > > ( new Map ( ) ) ;
2227 const primaryProviders = providers . filter ( p => PRIMARY_PROVIDER_KEYS . has ( p . key ) ) ;
2328 const moreProviders = providers . filter ( p => ! PRIMARY_PROVIDER_KEYS . has ( p . key ) ) ;
2429
30+ const columnPrimaryProviders = primaryProviders . length
31+ ? `repeat(${ primaryProviders . length } , 1fr)`
32+ : '' ;
33+ const columnMoreProviders = moreProviders . length ? 'min-content' : '' ;
34+ const columnSpacer = primaryProviders . length && moreProviders . length ? ' ' : '' ;
35+
36+ const columnsMd = `${ columnPrimaryProviders } ${ columnSpacer } ${ columnMoreProviders } ` ;
37+
2538 return (
2639 < Flex justify = "center" >
2740 < Grid
2841 columns = { {
2942 xs : '1fr 1fr' ,
30- md : primaryProviders . length
31- ? `repeat(${ primaryProviders . length } , 1fr) min-content`
32- : 'min-content' ,
43+ md : columnsMd ,
3344 } }
3445 rows = { { xs : 2 } }
3546 justify = "center"
@@ -60,9 +71,63 @@ export function ScmProviderPills({providers, onInstall}: ScmProviderPillsProps)
6071 </ IntegrationContext >
6172 ) ) }
6273 { moreProviders . length > 0 && (
63- < ScmProvidersDropdown providers = { moreProviders } onInstall = { onInstall } />
74+ < Fragment >
75+ { moreProviders . map ( provider => (
76+ < ScmProviderFlowSetup
77+ key = { provider . key }
78+ provider = { provider }
79+ onInstall = { onInstall }
80+ flowMapRef = { flowMapRef }
81+ />
82+ ) ) }
83+ < DropdownMenu
84+ triggerLabel = { t ( 'More' ) }
85+ position = "bottom-end"
86+ items = { moreProviders . map ( provider => ( {
87+ key : provider . key ,
88+ label : provider . name ,
89+ leadingItems : getIntegrationIcon ( provider . key , 'sm' ) ,
90+ onAction : ( ) => flowMapRef . current . get ( provider . key ) ?.( ) ,
91+ } ) ) }
92+ />
93+ </ Fragment >
6494 ) }
6595 </ Grid >
6696 </ Flex >
6797 ) ;
6898}
99+
100+ interface ScmProviderFlowSetupProps {
101+ flowMapRef : React . RefObject < Map < string , ( ) => void > > ;
102+ onInstall : ( data : Integration ) => void ;
103+ provider : IntegrationProvider ;
104+ }
105+
106+ /**
107+ * Invisible component that initializes {@link useAddIntegration} for a single
108+ * provider and registers the resulting `startFlow` function in a shared ref
109+ * map. This lets the parent's {@link DropdownMenu} trigger the correct
110+ * OAuth/pipeline flow from a data-driven menu item.
111+ */
112+ function ScmProviderFlowSetup ( {
113+ provider,
114+ onInstall,
115+ flowMapRef,
116+ } : ScmProviderFlowSetupProps ) {
117+ const organization = useOrganization ( ) ;
118+ const { startFlow} = useAddIntegration ( {
119+ provider,
120+ organization,
121+ onInstall,
122+ analyticsParams : {
123+ view : 'onboarding' ,
124+ already_installed : false ,
125+ } ,
126+ } ) ;
127+
128+ useEffect ( ( ) => {
129+ flowMapRef . current . set ( provider . key , startFlow ) ;
130+ } , [ flowMapRef , provider . key , startFlow ] ) ;
131+
132+ return null ;
133+ }
0 commit comments