-
Notifications
You must be signed in to change notification settings - Fork 73
Fetch frameworks from backend #1312
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| import { useState, useEffect, useCallback } from "react"; | ||
| import { Framework } from "../../domain/types/Framework"; | ||
| import { getAllFrameworks } from "../repository/entity.repository"; | ||
|
|
||
| interface UseFrameworksResult { | ||
| frameworks: Framework[]; | ||
| loading: boolean; | ||
| error: string | null; | ||
| refreshFrameworks: () => Promise<void>; | ||
| } | ||
|
|
||
| const useFrameworks = (): UseFrameworksResult => { | ||
| const [frameworks, setFrameworks] = useState<Framework[]>([]); | ||
| const [loading, setLoading] = useState(true); | ||
| const [error, setError] = useState<string | null>(null); | ||
|
|
||
| const fetchFrameworks = useCallback(async () => { | ||
| try { | ||
| setLoading(true); | ||
| const response = await getAllFrameworks({ routeUrl: "/frameworks" }); | ||
| if (response?.data) { | ||
| setFrameworks(response.data); | ||
| setError(null); | ||
| } else { | ||
| throw new Error("Invalid response format"); | ||
| } | ||
| } catch (err) { | ||
| const errorMessage = err instanceof Error ? err.message : "Failed to fetch frameworks"; | ||
| setError(errorMessage); | ||
| console.error("Error fetching frameworks:", errorMessage); | ||
| } finally { | ||
| setLoading(false); | ||
| } | ||
| }, []); | ||
|
|
||
| useEffect(() => { | ||
| fetchFrameworks(); | ||
| }, [fetchFrameworks]); | ||
|
|
||
| return { | ||
| frameworks, | ||
| loading, | ||
| error, | ||
| refreshFrameworks: fetchFrameworks | ||
| }; | ||
| }; | ||
|
|
||
| export default useFrameworks; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,8 @@ | ||
| export type Framework = { | ||
| id: string; | ||
| is_demo: boolean; | ||
| project_id: string; | ||
| id: number; | ||
| name: string; | ||
| description: string; | ||
| created_at: string; | ||
| is_demo?: boolean; | ||
| project_id?: string; | ||
| }; |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,14 +1,14 @@ | ||||||||||||||||||||||||||||||||||||
| import { useState } from "react"; | ||||||||||||||||||||||||||||||||||||
| import { Box, Button, Tab } from "@mui/material"; | ||||||||||||||||||||||||||||||||||||
| import TabList from "@mui/lab/TabList"; | ||||||||||||||||||||||||||||||||||||
| import TabPanel from "@mui/lab/TabPanel"; | ||||||||||||||||||||||||||||||||||||
| import TabContext from "@mui/lab/TabContext"; | ||||||||||||||||||||||||||||||||||||
| import { tabStyle, tabPanelStyle } from "../V1.0ProjectView/style"; | ||||||||||||||||||||||||||||||||||||
| import VWSkeleton from "../../../vw-v2-components/Skeletons"; | ||||||||||||||||||||||||||||||||||||
| import ComplianceTracker from "../../../pages/ComplianceTracker/1.0ComplianceTracker"; | ||||||||||||||||||||||||||||||||||||
| import { Project } from "../../../../domain/types/Project"; | ||||||||||||||||||||||||||||||||||||
| import AssessmentTracker from "../../Assessment/1.0AssessmentTracker"; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| import { useState, useEffect, useMemo } from 'react'; | ||||||||||||||||||||||||||||||||||||
| import { Box, Button, Tab, Typography, Stack, Alert } from '@mui/material'; | ||||||||||||||||||||||||||||||||||||
| import TabList from '@mui/lab/TabList'; | ||||||||||||||||||||||||||||||||||||
| import TabPanel from '@mui/lab/TabPanel'; | ||||||||||||||||||||||||||||||||||||
| import TabContext from '@mui/lab/TabContext'; | ||||||||||||||||||||||||||||||||||||
| import { tabStyle, tabPanelStyle } from '../V1.0ProjectView/style'; | ||||||||||||||||||||||||||||||||||||
| import VWSkeleton from '../../../vw-v2-components/Skeletons'; | ||||||||||||||||||||||||||||||||||||
| import ComplianceTracker from '../../../pages/ComplianceTracker/1.0ComplianceTracker'; | ||||||||||||||||||||||||||||||||||||
| import { Project } from '../../../../domain/types/Project'; | ||||||||||||||||||||||||||||||||||||
| import AssessmentTracker from '../../Assessment/1.0AssessmentTracker'; | ||||||||||||||||||||||||||||||||||||
| import useFrameworks from '../../../../application/hooks/useFrameworks'; | ||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||
| containerStyle, | ||||||||||||||||||||||||||||||||||||
| headerContainerStyle, | ||||||||||||||||||||||||||||||||||||
|
|
@@ -20,51 +20,117 @@ import { | |||||||||||||||||||||||||||||||||||
| import ISO42001Annex from "../../ISO/Annex"; | ||||||||||||||||||||||||||||||||||||
| import ISO42001Clauses from "../../ISO/Clause"; | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
20
to
21
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove unused imports The -import ISO42001Annex from "../../ISO/Annex";
-import ISO42001Clauses from "../../ISO/Clause";
🧰 Tools🪛 GitHub Actions: Frontend Checks[error] 20-20: TypeScript error TS6133: 'ISO42001Annex' is declared but its value is never read. |
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const frameworks = [ | ||||||||||||||||||||||||||||||||||||
| { label: "EU AI Act", value: "eu-ai-act" }, | ||||||||||||||||||||||||||||||||||||
| { label: "ISO 42001", value: "iso-42001" }, | ||||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const trackerTabs = [ | ||||||||||||||||||||||||||||||||||||
| { label: "Compliance tracker", value: "compliance" }, | ||||||||||||||||||||||||||||||||||||
| { label: "Assessment tracker", value: "assessment" }, | ||||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const iso42001Tabs = [ | ||||||||||||||||||||||||||||||||||||
| { label: "Clauses", value: "clauses" }, | ||||||||||||||||||||||||||||||||||||
| { label: "Annexs", value: "annexs" }, | ||||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||||
| const ComingSoonMessage = () => ( | ||||||||||||||||||||||||||||||||||||
| <Stack | ||||||||||||||||||||||||||||||||||||
| sx={{ | ||||||||||||||||||||||||||||||||||||
| height: 400, | ||||||||||||||||||||||||||||||||||||
| display: 'flex', | ||||||||||||||||||||||||||||||||||||
| alignItems: 'center', | ||||||||||||||||||||||||||||||||||||
| justifyContent: 'center', | ||||||||||||||||||||||||||||||||||||
| backgroundColor: '#F5F6F6', | ||||||||||||||||||||||||||||||||||||
| borderRadius: 2, | ||||||||||||||||||||||||||||||||||||
| p: 4 | ||||||||||||||||||||||||||||||||||||
| }} | ||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||
| <Typography variant="h6" sx={{ color: '#13715B', mb: 2 }}> | ||||||||||||||||||||||||||||||||||||
| Coming Soon! | ||||||||||||||||||||||||||||||||||||
| </Typography> | ||||||||||||||||||||||||||||||||||||
| <Typography sx={{ color: '#232B3A', textAlign: 'center' }}> | ||||||||||||||||||||||||||||||||||||
| We're currently working on implementing this framework. | ||||||||||||||||||||||||||||||||||||
| <br /> | ||||||||||||||||||||||||||||||||||||
| Please check back later for updates. | ||||||||||||||||||||||||||||||||||||
| </Typography> | ||||||||||||||||||||||||||||||||||||
| </Stack> | ||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const ProjectFrameworks = ({ project }: { project: Project }) => { | ||||||||||||||||||||||||||||||||||||
| const [framework, setFramework] = useState("eu-ai-act"); | ||||||||||||||||||||||||||||||||||||
| const [tracker, setTracker] = useState("compliance"); | ||||||||||||||||||||||||||||||||||||
| const [isoTab, setIsoTab] = useState("clauses"); | ||||||||||||||||||||||||||||||||||||
| const { frameworks, loading, error, refreshFrameworks } = useFrameworks(); | ||||||||||||||||||||||||||||||||||||
| const [selectedFrameworkId, setSelectedFrameworkId] = useState<number | null>(null); | ||||||||||||||||||||||||||||||||||||
| const [tracker, setTracker] = useState('compliance'); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Set initial framework when frameworks are loaded | ||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||
| if (frameworks.length > 0 && !selectedFrameworkId) { | ||||||||||||||||||||||||||||||||||||
| setSelectedFrameworkId(frameworks[0].id); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| }, [frameworks, selectedFrameworkId]); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
Comment on lines
+56
to
+62
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Handle framework list changes & invalid selections
-useEffect(() => {
- if (frameworks.length > 0 && !selectedFrameworkId) {
- setSelectedFrameworkId(frameworks[0].id);
- }
-}, [frameworks, selectedFrameworkId]);
+useEffect(() => {
+ if (frameworks.length === 0) return;
+
+ // If nothing is selected **or** the selected framework disappeared,
+ // default to the first framework.
+ const frameworkExists = frameworks.some(fw => fw.id === selectedFrameworkId);
+ if (selectedFrameworkId === null || !frameworkExists) {
+ setSelectedFrameworkId(frameworks[0].id);
+ }
+}, [frameworks, selectedFrameworkId]);📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||
| // Memoize the current framework to avoid unnecessary re-renders | ||||||||||||||||||||||||||||||||||||
| const currentFramework = useMemo(() => | ||||||||||||||||||||||||||||||||||||
| frameworks.find(fw => fw.id === selectedFrameworkId), | ||||||||||||||||||||||||||||||||||||
| [frameworks, selectedFrameworkId] | ||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const handleFrameworkChange = (frameworkId: number) => { | ||||||||||||||||||||||||||||||||||||
| setSelectedFrameworkId(frameworkId); | ||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const renderFrameworkContent = () => { | ||||||||||||||||||||||||||||||||||||
| if (!project) { | ||||||||||||||||||||||||||||||||||||
| return <VWSkeleton variant="rectangular" width="100%" height={400} />; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const currentTabs = framework === "iso-42001" ? iso42001Tabs : trackerTabs; | ||||||||||||||||||||||||||||||||||||
| const currentValue = framework === "iso-42001" ? isoTab : tracker; | ||||||||||||||||||||||||||||||||||||
| const setCurrentValue = framework === "iso-42001" ? setIsoTab : setTracker; | ||||||||||||||||||||||||||||||||||||
| if (!currentFramework) { | ||||||||||||||||||||||||||||||||||||
| return <ComingSoonMessage />; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| const isEUAIAct = currentFramework.id === 1; // EU AI Act framework ID | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||
| <> | ||||||||||||||||||||||||||||||||||||
| {isEUAIAct ? ( | ||||||||||||||||||||||||||||||||||||
| tracker === 'compliance' ? ( | ||||||||||||||||||||||||||||||||||||
| <ComplianceTracker project={project} /> | ||||||||||||||||||||||||||||||||||||
| ) : ( | ||||||||||||||||||||||||||||||||||||
| <AssessmentTracker project={project} /> | ||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||
| ) : ( | ||||||||||||||||||||||||||||||||||||
| <ComingSoonMessage /> | ||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||
| </> | ||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| if (error) { | ||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||
| <Box sx={containerStyle}> | ||||||||||||||||||||||||||||||||||||
| <Alert severity="error" sx={{ mb: 2 }}> | ||||||||||||||||||||||||||||||||||||
| {error} | ||||||||||||||||||||||||||||||||||||
| </Alert> | ||||||||||||||||||||||||||||||||||||
| <Button onClick={refreshFrameworks} variant="contained"> | ||||||||||||||||||||||||||||||||||||
| Retry | ||||||||||||||||||||||||||||||||||||
| </Button> | ||||||||||||||||||||||||||||||||||||
| </Box> | ||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||
| <Box sx={containerStyle}> | ||||||||||||||||||||||||||||||||||||
| {/* Framework Tabs and Add Button */} | ||||||||||||||||||||||||||||||||||||
| <Box sx={headerContainerStyle}> | ||||||||||||||||||||||||||||||||||||
| {/* Framework Tabs as classic tabs, not buttons */} | ||||||||||||||||||||||||||||||||||||
| <Box sx={frameworkTabsContainerStyle}> | ||||||||||||||||||||||||||||||||||||
| {frameworks.map((fw, idx) => { | ||||||||||||||||||||||||||||||||||||
| const isActive = framework === fw.value; | ||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||
| <Box | ||||||||||||||||||||||||||||||||||||
| key={fw.value} | ||||||||||||||||||||||||||||||||||||
| onClick={() => setFramework(fw.value)} | ||||||||||||||||||||||||||||||||||||
| sx={getFrameworkTabStyle( | ||||||||||||||||||||||||||||||||||||
| isActive, | ||||||||||||||||||||||||||||||||||||
| idx === frameworks.length - 1 | ||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||
| {fw.label} | ||||||||||||||||||||||||||||||||||||
| </Box> | ||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||
| })} | ||||||||||||||||||||||||||||||||||||
| {loading ? ( | ||||||||||||||||||||||||||||||||||||
| <VWSkeleton variant="rectangular" width={200} height={40} /> | ||||||||||||||||||||||||||||||||||||
| ) : ( | ||||||||||||||||||||||||||||||||||||
| frameworks.map((fw, idx) => { | ||||||||||||||||||||||||||||||||||||
| const isActive = selectedFrameworkId === fw.id; | ||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||
| <Box | ||||||||||||||||||||||||||||||||||||
| key={fw.id} | ||||||||||||||||||||||||||||||||||||
| onClick={() => handleFrameworkChange(fw.id)} | ||||||||||||||||||||||||||||||||||||
| sx={getFrameworkTabStyle(isActive, idx === frameworks.length - 1)} | ||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||
| {fw.name} | ||||||||||||||||||||||||||||||||||||
| </Box> | ||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||
| </Box> | ||||||||||||||||||||||||||||||||||||
| <Button variant="contained" sx={addButtonStyle}> | ||||||||||||||||||||||||||||||||||||
| Add new framework | ||||||||||||||||||||||||||||||||||||
|
|
@@ -90,41 +156,12 @@ const ProjectFrameworks = ({ project }: { project: Project }) => { | |||||||||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||||||||||
| </TabList> | ||||||||||||||||||||||||||||||||||||
| </Box> | ||||||||||||||||||||||||||||||||||||
| {framework === "iso-42001" ? ( | ||||||||||||||||||||||||||||||||||||
| <> | ||||||||||||||||||||||||||||||||||||
| <TabPanel value="clauses" sx={tabPanelStyle}> | ||||||||||||||||||||||||||||||||||||
| {project ? ( | ||||||||||||||||||||||||||||||||||||
| <ISO42001Clauses /> | ||||||||||||||||||||||||||||||||||||
| ) : ( | ||||||||||||||||||||||||||||||||||||
| <VWSkeleton variant="rectangular" width="100%" height={400} /> | ||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||
| </TabPanel> | ||||||||||||||||||||||||||||||||||||
| <TabPanel value="annexs" sx={tabPanelStyle}> | ||||||||||||||||||||||||||||||||||||
| {project ? ( | ||||||||||||||||||||||||||||||||||||
| <ISO42001Annex /> | ||||||||||||||||||||||||||||||||||||
| ) : ( | ||||||||||||||||||||||||||||||||||||
| <VWSkeleton variant="rectangular" width="100%" height={400} /> | ||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||
| </TabPanel> | ||||||||||||||||||||||||||||||||||||
| </> | ||||||||||||||||||||||||||||||||||||
| ) : ( | ||||||||||||||||||||||||||||||||||||
| <> | ||||||||||||||||||||||||||||||||||||
| <TabPanel value="compliance" sx={tabPanelStyle}> | ||||||||||||||||||||||||||||||||||||
| {project ? ( | ||||||||||||||||||||||||||||||||||||
| <ComplianceTracker project={project} /> | ||||||||||||||||||||||||||||||||||||
| ) : ( | ||||||||||||||||||||||||||||||||||||
| <VWSkeleton variant="rectangular" width="100%" height={400} /> | ||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||
| </TabPanel> | ||||||||||||||||||||||||||||||||||||
| <TabPanel value="assessment" sx={tabPanelStyle}> | ||||||||||||||||||||||||||||||||||||
| {project ? ( | ||||||||||||||||||||||||||||||||||||
| <AssessmentTracker project={project} /> | ||||||||||||||||||||||||||||||||||||
| ) : ( | ||||||||||||||||||||||||||||||||||||
| <VWSkeleton variant="rectangular" width="100%" height={400} /> | ||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||
| </TabPanel> | ||||||||||||||||||||||||||||||||||||
| </> | ||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||
| <TabPanel value="compliance" sx={tabPanelStyle}> | ||||||||||||||||||||||||||||||||||||
| {renderFrameworkContent()} | ||||||||||||||||||||||||||||||||||||
| </TabPanel> | ||||||||||||||||||||||||||||||||||||
| <TabPanel value="assessment" sx={tabPanelStyle}> | ||||||||||||||||||||||||||||||||||||
| {renderFrameworkContent()} | ||||||||||||||||||||||||||||||||||||
| </TabPanel> | ||||||||||||||||||||||||||||||||||||
| </TabContext> | ||||||||||||||||||||||||||||||||||||
| </Box> | ||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Missing error handling in getAllFrameworks function.
The function doesn't have any error handling, unlike other similar functions in this file that use try/catch blocks to log errors and rethrow them.
Add error handling for consistency with other repository functions:
export async function getAllFrameworks({ authToken = getAuthToken(), }: RequestParams): Promise<any> { + try { const response = await apiServices.get("/frameworks", { headers: { Authorization: `Bearer ${authToken}` }, }); return response.data; + } catch (error) { + console.error("Error fetching frameworks:", error); + throw error; + } }📝 Committable suggestion