Import framework from json

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2025-05-29 16:22:25 -07:00
parent ca90664f56
commit f60f7c237c
2 changed files with 109 additions and 3 deletions

View File

@@ -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({
<PageTemplate
title="Frameworks"
description="Manage your compliance frameworks"
actions={<FrameworkImportDropdown />}
actions={
<div className="flex gap-4">
<FrameworkImportButton />
<FrameworkImportDropdown />
</div>
}
>
<div className="space-y-6">
<Card>

View File

@@ -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() {
</DropdownMenu>
);
}
export function FrameworkImportButton() {
const { organizationId } = useParams();
const { toast } = useToast();
const fileInputRef = useRef<HTMLInputElement>(null);
const [isImporting, setIsImporting] = useState(false);
const [commit] = useMutation<ImportFrameworkDialogImportFrameworkMutation>(
importFrameworkMutation
);
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
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 (
<>
<input
type="file"
ref={fileInputRef}
onChange={handleFileChange}
style={{ display: "none" }}
accept=".json"
/>
<Button
variant="secondary"
onClick={() => fileInputRef.current?.click()}
disabled={isImporting}
>
{isImporting ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Importing...
</>
) : (
"Import Framework"
)}
</Button>
</>
);
}