diff --git a/apps/console/src/pages/organizations/frameworks/FrameworkListView.tsx b/apps/console/src/pages/organizations/frameworks/FrameworkListView.tsx index 56a70e4f2..a63ee336b 100644 --- a/apps/console/src/pages/organizations/frameworks/FrameworkListView.tsx +++ b/apps/console/src/pages/organizations/frameworks/FrameworkListView.tsx @@ -10,7 +10,7 @@ import { Link, useParams } from "react-router"; import type { FrameworkListViewQuery as FrameworkListViewQueryType } from "./__generated__/FrameworkListViewQuery.graphql"; import { PageTemplate } from "@/components/PageTemplate"; import { FrameworkListViewSkeleton } from "./FrameworkListPage"; -import { FrameworkImportDropdown } from "./ImportFrameworkDialog"; +import { FrameworkImportDropdown, FrameworkImportButton } from "./ImportFrameworkDialog"; const FrameworkListViewQuery = graphql` query FrameworkListViewQuery($organizationId: ID!) { @@ -44,7 +44,12 @@ function FrameworkListViewContent({ } + actions={ +
+ + +
+ } >
diff --git a/apps/console/src/pages/organizations/frameworks/ImportFrameworkDialog.tsx b/apps/console/src/pages/organizations/frameworks/ImportFrameworkDialog.tsx index 7ff650b2f..6fcfff59c 100644 --- a/apps/console/src/pages/organizations/frameworks/ImportFrameworkDialog.tsx +++ b/apps/console/src/pages/organizations/frameworks/ImportFrameworkDialog.tsx @@ -10,7 +10,7 @@ import { useNavigate, useParams } from "react-router"; import { ConnectionHandler, graphql, useMutation } from "react-relay"; import { useToast } from "@/hooks/use-toast"; import { ImportFrameworkDialogImportFrameworkMutation } from "./__generated__/ImportFrameworkDialogImportFrameworkMutation.graphql"; -import { useState } from "react"; +import { useState, useRef } from "react"; const AVAILABLE_FRAMEWORKS = [ { id: "ISO27001-2022", name: "ISO/IEC 27001:2022" }, @@ -158,3 +158,104 @@ export function FrameworkImportDropdown() { ); } + +export function FrameworkImportButton() { + const { organizationId } = useParams(); + const { toast } = useToast(); + const fileInputRef = useRef(null); + const [isImporting, setIsImporting] = useState(false); + const [commit] = useMutation( + importFrameworkMutation + ); + + const handleFileChange = (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (!file) return; + + setIsImporting(true); + + const connectionId = ConnectionHandler.getConnectionID( + organizationId!, + "FrameworkListView_frameworks" + ); + + commit({ + variables: { + input: { + organizationId: organizationId!, + file: null, + }, + connections: [connectionId], + }, + uploadables: { + "input.file": file, + }, + onCompleted(data, errors) { + setIsImporting(false); + if (errors) { + const error = errors[0]; + let errorMessage = error.message || "Failed to import framework"; + + if (error?.message?.includes("already exists")) { + errorMessage = `A framework with this name already exists. Please choose a different name.`; + } + + toast({ + title: "Error", + description: errorMessage, + variant: "destructive", + }); + return; + } + + toast({ + title: "Success", + description: "Framework imported successfully", + }); + if (fileInputRef.current) { + fileInputRef.current.value = ""; + } + }, + onError(error) { + setIsImporting(false); + let errorMessage = error.message || "Failed to import framework"; + + if (error.message?.includes("already exists")) { + errorMessage = `A framework with this name already exists. Please choose a different name.`; + } + + toast({ + title: "Error", + description: errorMessage, + variant: "destructive", + }); + }, + }); + }; + + return ( + <> + + + + ); +}