@@ -32,6 +32,8 @@ import { KeyboardArrowDown } from "@mui/icons-material";
3232import { ReactComponent as GreyDownArrowIcon } from "../../../assets/icons/chevron-down-grey.svg" ;
3333import { useModalKeyHandling } from "../../../../application/hooks/useModalKeyHandling" ;
3434import modelInventoryOptions from "../../../utils/model-inventory.json" ;
35+ import { getAllProjects } from "../../../../application/repository/project.repository"
36+ import { Project } from "../../../../domain/types/Project" ;
3537
3638interface NewModelInventoryProps {
3739 isOpen : boolean ;
@@ -51,10 +53,11 @@ interface NewModelInventoryFormValues {
5153 security_assessment : boolean ;
5254 status : ModelInventoryStatus ;
5355 status_date : string ;
54- reference_link : string ,
55- biases : string ,
56- limitations : string ,
57- hosting_provider : string ,
56+ reference_link : string ;
57+ biases : string ;
58+ limitations : string ;
59+ hosting_provider : string ;
60+ used_in_projects : string [ ]
5861}
5962
6063interface NewModelInventoryFormErrors {
@@ -66,6 +69,7 @@ interface NewModelInventoryFormErrors {
6669 capabilities ?: string ;
6770 status ?: string ;
6871 status_date ?: string ;
72+ used_in_projects ?: string ;
6973}
7074
7175const initialState : NewModelInventoryFormValues = {
@@ -82,6 +86,7 @@ const initialState: NewModelInventoryFormValues = {
8286 biases : "" ,
8387 limitations : "" ,
8488 hosting_provider : "" ,
89+ used_in_projects : [ ] ,
8590} ;
8691
8792const statusOptions = [
@@ -170,6 +175,41 @@ const NewModelInventory: FC<NewModelInventoryProps> = ({
170175 }
171176 } ;
172177
178+ const [ projectList , setProjects ] = useState < Project [ ] > ( [ ] ) ;
179+ const [ , setProjectsLoading ] = useState ( true ) ;
180+
181+ useEffect ( ( ) => {
182+ const fetchProjects = async ( ) => {
183+ try {
184+ setProjectsLoading ( true ) ;
185+ const response = await getAllProjects ( ) ;
186+ if ( response ?. data ) {
187+ setProjects ( response . data ) ;
188+ }
189+ } catch ( error ) {
190+ console . error ( "Error fetching projects:" , error ) ;
191+ } finally {
192+ setProjectsLoading ( false ) ;
193+ }
194+ } ;
195+
196+ fetchProjects ( ) ;
197+ } , [ ] ) ;
198+
199+ const combinedList = useMemo ( ( ) => {
200+ const targetFrameworks = [ "ISO 42001" , "ISO 27001" ] ;
201+
202+ return projectList . flatMap ( ( project ) => {
203+ // Get enabled framework names for this project
204+ const enabledFrameworks = project . framework ?. map ( ( f ) => f . name ) || [ ] ;
205+
206+ // Only include target frameworks that are enabled
207+ return targetFrameworks
208+ . filter ( ( fw ) => enabledFrameworks . includes ( fw ) )
209+ . map ( ( fw ) => `${ project . project_title . trim ( ) } - ${ fw } ` ) ;
210+ } ) ;
211+ } , [ projectList ] ) ;
212+
173213 // Transform users to the format expected by SelectComponent
174214 const userOptions = useMemo ( ( ) => {
175215 return users . map ( ( user ) => ( {
@@ -219,6 +259,14 @@ const NewModelInventory: FC<NewModelInventoryProps> = ({
219259 [ ]
220260 ) ;
221261
262+ const handleSelectUsedInProjectChange = useCallback (
263+ ( _event : React . SyntheticEvent , newValue : string [ ] ) => {
264+ setValues ( ( prev ) => ( { ...prev , used_in_projects : newValue } ) ) ;
265+ setErrors ( ( prev ) => ( { ...prev , used_in_projects : "" } ) ) ;
266+ } ,
267+ [ ]
268+ ) ;
269+
222270 const handleDateChange = useCallback ( ( newDate : Dayjs | null ) => {
223271 if ( newDate ?. isValid ( ) ) {
224272 setValues ( ( prev ) => ( {
@@ -664,6 +712,68 @@ const NewModelInventory: FC<NewModelInventoryProps> = ({
664712 ) }
665713 </ Stack >
666714
715+ < Stack >
716+ < Typography
717+ sx = { {
718+ fontSize : 13 ,
719+ fontWeight : 400 ,
720+ mb : theme . spacing ( 2 ) ,
721+ color : theme . palette . text . secondary ,
722+ } }
723+ >
724+ Used in projects
725+ </ Typography >
726+ < Autocomplete
727+ multiple
728+ id = "projects-framework"
729+ size = "small"
730+ value = { values . used_in_projects }
731+ options = { combinedList }
732+ onChange = { handleSelectUsedInProjectChange }
733+ getOptionLabel = { ( option ) => option }
734+ noOptionsText = {
735+ values . used_in_projects . length === combinedList . length
736+ ? "All projects selected"
737+ : "No options"
738+ }
739+ renderOption = { ( props , option ) => (
740+ < Box component = "li" { ...props } >
741+ < Typography sx = { { fontSize : 13 , fontWeight : 400 } } >
742+ { option }
743+ </ Typography >
744+ </ Box >
745+ ) }
746+ filterSelectedOptions
747+ popupIcon = { < GreyDownArrowIcon /> }
748+ renderInput = { ( params ) => (
749+ < TextField
750+ { ...params }
751+ error = { ! ! errors . used_in_projects }
752+ placeholder = "Select projects-framework"
753+ sx = { capabilitiesRenderInputStyle }
754+ />
755+ ) }
756+ sx = { {
757+ backgroundColor : theme . palette . background . main ,
758+ ...capabilitiesSxStyle ,
759+ } }
760+ slotProps = { capabilitiesSlotProps }
761+ />
762+ { errors . used_in_projects && (
763+ < Typography
764+ variant = "caption"
765+ sx = { {
766+ mt : 1 ,
767+ color : "#f04438" ,
768+ fontWeight : 300 ,
769+ fontSize : 11 ,
770+ } }
771+ >
772+ { errors . used_in_projects }
773+ </ Typography >
774+ ) }
775+ </ Stack >
776+
667777 < Stack
668778 direction = { "row" }
669779 gap = { theme . spacing ( 8 ) }
0 commit comments