Create file for link

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2025-05-03 17:54:29 -07:00
parent 45265457eb
commit 625343dada

View File

@@ -1096,8 +1096,6 @@ function MeasureViewContent({
}; };
const handleLinkEvidenceSubmit = () => { const handleLinkEvidenceSubmit = () => {
if (!taskForEvidence) return;
// Validate form // Validate form
if (!linkEvidenceName.trim()) { if (!linkEvidenceName.trim()) {
toast({ toast({
@@ -1117,40 +1115,71 @@ function MeasureViewContent({
return; return;
} }
// Get the evidence connection ID for this task try {
const evidenceConnectionId = getEvidenceConnectionId(taskForEvidence.id); console.log("Creating URI file with URL:", linkEvidenceUrl.trim());
// Use a default description if none is provided // Create a URI file with the link
const description = const linkContent = linkEvidenceUrl.trim();
linkEvidenceDescription.trim() || `Link to ${linkEvidenceUrl}`; const fileName = `${linkEvidenceName.trim()}.uri`;
const file = new File([linkContent], fileName, { type: "text/uri-list" });
// Use requestEvidence instead of createEvidence console.log("File created:", file.name, file.type, file.size);
requestEvidence({
// Show toast for add started
toast({
title: "Adding link evidence",
description: `Adding ${fileName}...`,
variant: "default",
});
// Use the measure evidence connection ID
const evidenceConnectionId = getMeasureEvidenceConnectionId();
console.log("Evidence connection ID:", evidenceConnectionId);
// Upload the URI file as evidence
uploadMeasureEvidence({
variables: { variables: {
input: { input: {
taskId: taskForEvidence.id, measureId: measureId,
name: linkEvidenceName, file: null,
type: "LINK",
description: description,
}, },
connections: evidenceConnectionId ? [evidenceConnectionId] : [], connections: evidenceConnectionId ? [evidenceConnectionId] : [],
}, },
onCompleted: () => { uploadables: {
"input.file": file,
},
onCompleted: (response) => {
console.log("Upload completed:", response);
setTaskForEvidence(null); setTaskForEvidence(null);
setEvidenceDialogOpen(false); setEvidenceDialogOpen(false);
// Reset form fields // Reset form fields
setLinkEvidenceName(""); setLinkEvidenceName("");
setLinkEvidenceUrl(""); setLinkEvidenceUrl("");
setLinkEvidenceDescription(""); setLinkEvidenceDescription("");
toast({
title: "Link evidence added",
description: "Link evidence has been added successfully.",
variant: "default",
});
}, },
onError: (error) => { onError: (error) => {
console.error("Error uploading URI file:", error);
toast({ toast({
title: "Error adding link evidence", title: "Error adding link evidence",
description: error.message, description: error.message || "Unknown error occurred",
variant: "destructive", variant: "destructive",
}); });
}, },
}); });
} catch (error) {
console.error("Error in handleLinkEvidenceSubmit:", error);
toast({
title: "Error creating URI file",
description: error instanceof Error ? error.message : "Unknown error occurred",
variant: "destructive",
});
}
}; };
const handleDragOver = (e: DragEvent<HTMLDivElement>, taskId: string) => { const handleDragOver = (e: DragEvent<HTMLDivElement>, taskId: string) => {
@@ -1245,7 +1274,7 @@ function MeasureViewContent({
// Function to get file icon based on mime type and evidence type // Function to get file icon based on mime type and evidence type
const getFileIcon = (mimeType: string, evidenceType: string) => { const getFileIcon = (mimeType: string, evidenceType: string) => {
if (evidenceType === "LINK") { if (evidenceType === "LINK" || mimeType === "text/uri-list" || mimeType === "text/uri") {
return <Link2 className="w-4 h-4 text-blue-600" />; return <Link2 className="w-4 h-4 text-blue-600" />;
} else if (mimeType.startsWith("image/")) { } else if (mimeType.startsWith("image/")) {
return <Image className="w-4 h-4 text-blue-500" />; return <Image className="w-4 h-4 text-blue-500" />;
@@ -1260,6 +1289,20 @@ function MeasureViewContent({
} }
}; };
// Function to get URL from URI file
const getUrlFromUriFile = async (fileUrl: string): Promise<string | null> => {
try {
const response = await fetch(fileUrl);
const text = await response.text();
// URI files typically have the URL on the first line
const firstLine = text.trim().split('\n')[0];
return firstLine || null;
} catch (error) {
console.error("Error extracting URL from URI file:", error);
return null;
}
};
// Simplified preview handler that opens the modal and sets the evidence // Simplified preview handler that opens the modal and sets the evidence
const handlePreviewEvidence = (evidence: { const handlePreviewEvidence = (evidence: {
id: string; id: string;
@@ -1285,6 +1328,20 @@ function MeasureViewContent({
if (!prev) return null; if (!prev) return null;
return { ...prev, fileUrl: data.node!.fileUrl }; return { ...prev, fileUrl: data.node!.fileUrl };
}); });
// If it's a URI file, fetch and extract the URL
if (evidence.mimeType === "text/uri-list" || evidence.mimeType === "text/uri") {
getUrlFromUriFile(data.node!.fileUrl!)
.then((url) => {
if (url) {
window.open(url, "_blank");
setIsPreviewModalOpen(false);
}
})
.catch((error) => {
console.error("Error handling URI file:", error);
});
}
} else { } else {
throw new Error("File URL not available in response"); throw new Error("File URL not available in response");
} }
@@ -1379,7 +1436,14 @@ function MeasureViewContent({
}; };
const handleFulfillEvidenceWithLink = () => { const handleFulfillEvidenceWithLink = () => {
if (!evidenceToFulfill) return; if (!evidenceToFulfill) {
toast({
title: "Error",
description: "No evidence to fulfill",
variant: "destructive",
});
return;
}
// Validate URL // Validate URL
if (!linkEvidenceUrl.trim()) { if (!linkEvidenceUrl.trim()) {
@@ -1391,6 +1455,20 @@ function MeasureViewContent({
return; return;
} }
try {
console.log("Creating URI file to fulfill evidence:", evidenceToFulfill.id);
// Create a URI file with the link
const linkContent = linkEvidenceUrl.trim();
// Use provided name or fallback to the original filename
const baseName = linkEvidenceName.trim()
? linkEvidenceName.trim()
: evidenceToFulfill.filename.replace(/\.[^/.]+$/, "");
const fileName = `${baseName}.uri`;
const file = new File([linkContent], fileName, { type: "text/uri-list" });
console.log("File created:", file.name, file.type, file.size);
// Get connection ID for the parent task // Get connection ID for the parent task
const task = tasks.find((task) => const task = tasks.find((task) =>
task.evidences?.edges.some( task.evidences?.edges.some(
@@ -1400,35 +1478,60 @@ function MeasureViewContent({
const evidenceConnectionId = task?.id const evidenceConnectionId = task?.id
? getEvidenceConnectionId(task.id) ? getEvidenceConnectionId(task.id)
: null; : getMeasureEvidenceConnectionId();
console.log("Using connection ID:", evidenceConnectionId);
console.log("Task found:", task?.id);
// Show toast for upload started
toast({
title: "Fulfilling evidence with link",
description: `Creating link file for ${fileName}...`,
variant: "default",
});
// Upload the URI file to fulfill the evidence
fulfillEvidence({ fulfillEvidence({
variables: { variables: {
input: { input: {
evidenceId: evidenceToFulfill.id, evidenceId: evidenceToFulfill.id,
url: linkEvidenceUrl, file: null,
}, },
connections: evidenceConnectionId ? [evidenceConnectionId] : [], connections: evidenceConnectionId ? [evidenceConnectionId] : [],
}, },
onCompleted: () => { uploadables: {
"input.file": file,
},
onCompleted: (response) => {
console.log("Evidence fulfilled successfully:", response);
setFulfillEvidenceDialogOpen(false); setFulfillEvidenceDialogOpen(false);
setEvidenceToFulfill(null); setEvidenceToFulfill(null);
setLinkEvidenceName("");
setLinkEvidenceUrl(""); setLinkEvidenceUrl("");
setLinkEvidenceDescription(""); setLinkEvidenceDescription("");
toast({ toast({
title: "Evidence updated", title: "Evidence fulfilled",
description: "Evidence has been fulfilled with link successfully.", description: "Evidence has been fulfilled with link successfully.",
variant: "default", variant: "default",
}); });
}, },
onError: (error) => { onError: (error) => {
console.error("Error fulfilling evidence:", error);
toast({ toast({
title: "Error updating evidence", title: "Error fulfilling evidence",
description: error.message, description: error.message || "Unknown error occurred",
variant: "destructive", variant: "destructive",
}); });
}, },
}); });
} catch (error) {
console.error("Error in handleFulfillEvidenceWithLink:", error);
toast({
title: "Error creating URI file",
description: error instanceof Error ? error.message : "Unknown error occurred",
variant: "destructive",
});
}
}; };
const confirmDeleteEvidence = () => { const confirmDeleteEvidence = () => {
@@ -2222,10 +2325,15 @@ function MeasureViewContent({
</div> </div>
</td> </td>
<td className="py-3 px-4 text-sm"> <td className="py-3 px-4 text-sm">
{evidence.type === "FILE" ? "Document" : "Link"} {evidence.type === "FILE" ?
(evidence.mimeType === "text/uri-list" || evidence.mimeType === "text/uri" ?
"Link" : "Document") :
"Link"}
</td> </td>
<td className="py-3 px-4 text-sm"> <td className="py-3 px-4 text-sm">
{evidence.type === "FILE" ? formatFileSize(evidence.size) : "-"} {evidence.type === "FILE" &&
!(evidence.mimeType === "text/uri-list" || evidence.mimeType === "text/uri") ?
formatFileSize(evidence.size) : "-"}
</td> </td>
<td className="py-3 px-4 text-sm"> <td className="py-3 px-4 text-sm">
{formatDate(evidence.createdAt)} {formatDate(evidence.createdAt)}
@@ -2247,7 +2355,15 @@ function MeasureViewContent({
</button> </button>
) : evidence.type === "FILE" ? ( ) : evidence.type === "FILE" ? (
<> <>
{evidence.mimeType.startsWith("image/") ? ( {evidence.mimeType === "text/uri-list" || evidence.mimeType === "text/uri" ? (
<button
onClick={() => handlePreviewEvidence(evidence)}
className="p-1.5 rounded-full hover:bg-white hover:shadow-sm transition-all"
title="Open Link"
>
<Link2 className="w-4 h-4 text-blue-600" />
</button>
) : evidence.mimeType.startsWith("image/") ? (
<button <button
onClick={() => handlePreviewEvidence(evidence)} onClick={() => handlePreviewEvidence(evidence)}
className="p-1.5 rounded-full hover:bg-white hover:shadow-sm transition-all" className="p-1.5 rounded-full hover:bg-white hover:shadow-sm transition-all"
@@ -2437,6 +2553,17 @@ function MeasureViewContent({
<TabsContent value="link" className="space-y-4 pt-4"> <TabsContent value="link" className="space-y-4 pt-4">
<div className="space-y-4"> <div className="space-y-4">
<div className="grid w-full items-center gap-1.5">
<Label htmlFor="evidence-name">Name</Label>
<Input
id="evidence-name"
value={linkEvidenceName}
onChange={(e) => setLinkEvidenceName(e.target.value)}
placeholder="Link name"
type="text"
/>
</div>
<div className="grid w-full items-center gap-1.5"> <div className="grid w-full items-center gap-1.5">
<Label htmlFor="evidence-url">URL</Label> <Label htmlFor="evidence-url">URL</Label>
<Input <Input
@@ -2446,6 +2573,9 @@ function MeasureViewContent({
placeholder="https://example.com" placeholder="https://example.com"
type="url" type="url"
/> />
<p className="text-xs text-secondary">
This will create a .uri file with the URL inside
</p>
</div> </div>
<div className="grid w-full items-center gap-1.5"> <div className="grid w-full items-center gap-1.5">
@@ -2472,7 +2602,7 @@ function MeasureViewContent({
Cancel Cancel
</Button> </Button>
{activeTab === "link" && ( {activeTab === "link" && (
<Button onClick={handleLinkEvidenceSubmit}>Add Link</Button> <Button onClick={handleLinkEvidenceSubmit}>Create URI File</Button>
)} )}
</DialogFooter> </DialogFooter>
</DialogContent> </DialogContent>
@@ -2670,27 +2800,31 @@ function MeasureViewContent({
<TabsContent value="link" className="space-y-4 pt-4"> <TabsContent value="link" className="space-y-4 pt-4">
<div className="space-y-4"> <div className="space-y-4">
<div className="grid w-full items-center gap-1.5"> <div className="grid w-full items-center gap-1.5">
<Label htmlFor="evidence-url">URL</Label> <Label htmlFor="fulfill-evidence-name">Name</Label>
<Input <Input
id="evidence-url" id="fulfill-evidence-name"
value={linkEvidenceName}
onChange={(e) => setLinkEvidenceName(e.target.value)}
placeholder="Link name (optional)"
type="text"
/>
<p className="text-xs text-secondary">
Optional - will use evidence name if not provided
</p>
</div>
<div className="grid w-full items-center gap-1.5">
<Label htmlFor="fulfill-evidence-url">URL</Label>
<Input
id="fulfill-evidence-url"
value={linkEvidenceUrl} value={linkEvidenceUrl}
onChange={(e) => setLinkEvidenceUrl(e.target.value)} onChange={(e) => setLinkEvidenceUrl(e.target.value)}
placeholder="https://example.com" placeholder="https://example.com"
type="url" type="url"
/> />
</div> <p className="text-xs text-secondary">
This will create a .uri file with the URL inside
<div className="grid w-full items-center gap-1.5"> </p>
<Label htmlFor="evidence-description">
Description (optional)
</Label>
<Textarea
id="evidence-description"
value={linkEvidenceDescription}
onChange={(e) => setLinkEvidenceDescription(e.target.value)}
placeholder="Describe this evidence (optional)"
className="min-h-[100px]"
/>
</div> </div>
</div> </div>
</TabsContent> </TabsContent>
@@ -2705,7 +2839,7 @@ function MeasureViewContent({
</Button> </Button>
{activeTab === "link" && ( {activeTab === "link" && (
<Button onClick={handleFulfillEvidenceWithLink}> <Button onClick={handleFulfillEvidenceWithLink}>
Submit Link Create URI File
</Button> </Button>
)} )}
</DialogFooter> </DialogFooter>