@@ -10,7 +10,9 @@ import {
1010 CircularProgress ,
1111 Box ,
1212 Typography ,
13+ Link ,
1314} from '@material-ui/core' ;
15+ import { NotificationBanner } from '@openchoreo/backstage-plugin-react' ;
1416import {
1517 useApi ,
1618 discoveryApiRef ,
@@ -230,13 +232,16 @@ export const BuildWorkflowPicker = ({
230232 // eslint-disable-next-line react-hooks/exhaustive-deps
231233 } , [ namespaceName , isClusterComponentType ] ) ;
232234
235+ const hasAllowedWorkflows =
236+ Array . isArray ( allowedWorkflows ) && allowedWorkflows . length > 0 ;
237+
233238 // Separate filtering from fetching so that allowedWorkflows changes are
234239 // reflected without triggering a full re-fetch.
235240 const filteredOptions = useMemo ( ( ) => {
236- if ( ! allowedWorkflows || allowedWorkflows . length === 0 ) {
237- return workflowOptions ;
241+ if ( ! hasAllowedWorkflows ) {
242+ return [ ] ;
238243 }
239- const normalizedAllowed = allowedWorkflows . map ( w => ( {
244+ const normalizedAllowed = allowedWorkflows ! . map ( w => ( {
240245 kind : ( w . kind as WorkflowKind | undefined ) ?? defaultWorkflowKind ,
241246 name : w . name ,
242247 } ) ) ;
@@ -245,7 +250,12 @@ export const BuildWorkflowPicker = ({
245250 aw => aw . name === opt . name && aw . kind === opt . kind ,
246251 ) ,
247252 ) ;
248- } , [ workflowOptions , allowedWorkflows , defaultWorkflowKind ] ) ;
253+ } , [
254+ workflowOptions ,
255+ allowedWorkflows ,
256+ hasAllowedWorkflows ,
257+ defaultWorkflowKind ,
258+ ] ) ;
249259
250260 const handleDropdownChange = ( event : ChangeEvent < { value : unknown } > ) => {
251261 const key = event . target . value as string ;
@@ -260,54 +270,84 @@ export const BuildWorkflowPicker = ({
260270
261271 // Standard dropdown for non-buildpack workflows
262272 return (
263- < FormControl
264- fullWidth
265- margin = "normal"
266- variant = "outlined"
267- error = { ! ! rawErrors ?. length || ! ! error }
268- required = { required }
269- >
270- < InputLabel id = { `${ idSchema ?. $id } -label` } > { label } </ InputLabel >
271- < Select
272- labelId = { `${ idSchema ?. $id } -label` }
273- label = { label }
274- value = { selectedKey || '' }
275- onChange = { handleDropdownChange }
276- disabled = { loading || filteredOptions . length === 0 }
273+ < >
274+ { ! hasAllowedWorkflows && ! loading && (
275+ < NotificationBanner
276+ variant = "warning"
277+ showIcon
278+ message = {
279+ < >
280+ This component type does not have any build workflows configured.
281+ To enable building from source, configure allowed workflows in the
282+ component type definition.{ ' ' }
283+ < Link
284+ href = "https://openchoreo.dev/docs/reference/api/platform/componenttype/#workflowref"
285+ target = "_blank"
286+ rel = "noopener noreferrer"
287+ >
288+ Learn more
289+ </ Link >
290+ </ >
291+ }
292+ />
293+ ) }
294+ < FormControl
295+ fullWidth
296+ margin = "normal"
297+ variant = "outlined"
298+ error = { ! ! rawErrors ?. length || ! ! error }
299+ required = { required }
277300 >
278- { loading && (
279- < MenuItem disabled >
280- < CircularProgress size = { 20 } style = { { marginRight : 8 } } />
281- Loading workflows...
282- </ MenuItem >
283- ) }
284- { ! loading && filteredOptions . length === 0 && (
285- < MenuItem disabled > No workflows available</ MenuItem >
286- ) }
287- { ! loading &&
288- filteredOptions . map ( workflow => (
289- < MenuItem key = { workflowKey ( workflow ) } value = { workflowKey ( workflow ) } >
290- < Box display = "flex" flexDirection = "column" >
291- < Typography variant = "body1" >
292- { getWorkflowDisplayName ( workflow ) }
293- </ Typography >
294- { workflow . description && (
295- < Typography variant = "body2" color = "textSecondary" >
296- { workflow . description }
297- </ Typography >
298- ) }
299- </ Box >
301+ < InputLabel id = { `${ idSchema ?. $id } -label` } > { label } </ InputLabel >
302+ < Select
303+ labelId = { `${ idSchema ?. $id } -label` }
304+ label = { label }
305+ value = { selectedKey || '' }
306+ onChange = { handleDropdownChange }
307+ disabled = { loading }
308+ >
309+ { loading && (
310+ < MenuItem disabled >
311+ < CircularProgress size = { 20 } style = { { marginRight : 8 } } />
312+ Loading workflows...
300313 </ MenuItem >
301- ) ) }
302- </ Select >
303- { error && < FormHelperText error > { error } </ FormHelperText > }
304- { rawErrors ?. length ? (
305- < FormHelperText error > { rawErrors . join ( ', ' ) } </ FormHelperText >
306- ) : null }
307- { schema . description && ! rawErrors ?. length && ! error && (
308- < FormHelperText > { schema . description } </ FormHelperText >
309- ) }
310- </ FormControl >
314+ ) }
315+ { ! loading && ! hasAllowedWorkflows && (
316+ < MenuItem disabled >
317+ No build workflows are allowed for this component type
318+ </ MenuItem >
319+ ) }
320+ { ! loading && hasAllowedWorkflows && filteredOptions . length === 0 && (
321+ < MenuItem disabled > No workflows available</ MenuItem >
322+ ) }
323+ { ! loading &&
324+ filteredOptions . map ( workflow => (
325+ < MenuItem
326+ key = { workflowKey ( workflow ) }
327+ value = { workflowKey ( workflow ) }
328+ >
329+ < Box display = "flex" flexDirection = "column" >
330+ < Typography variant = "body1" >
331+ { getWorkflowDisplayName ( workflow ) }
332+ </ Typography >
333+ { workflow . description && (
334+ < Typography variant = "body2" color = "textSecondary" >
335+ { workflow . description }
336+ </ Typography >
337+ ) }
338+ </ Box >
339+ </ MenuItem >
340+ ) ) }
341+ </ Select >
342+ { error && < FormHelperText error > { error } </ FormHelperText > }
343+ { rawErrors ?. length ? (
344+ < FormHelperText error > { rawErrors . join ( ', ' ) } </ FormHelperText >
345+ ) : null }
346+ { schema . description && ! rawErrors ?. length && ! error && (
347+ < FormHelperText > { schema . description } </ FormHelperText >
348+ ) }
349+ </ FormControl >
350+ </ >
311351 ) ;
312352} ;
313353
0 commit comments