diff --git a/src/frontend/actions/api.ts b/src/frontend/actions/api.ts index cc732e2..0a2eedd 100644 --- a/src/frontend/actions/api.ts +++ b/src/frontend/actions/api.ts @@ -211,6 +211,35 @@ export async function createAsset(file: FileInfo): Promise { } } +export async function createPolicy(name: string, description: string): Promise { + try { + const response = await fetch('/api/createPolicy', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + name: name, + description: description + }) + }); + + if (!response.ok) { + throw new Error(`API call failed with status ${response.status}`); + } + + const data = await response.json(); + + if (data.error) { + throw new Error(data.error); + } + + return true; + } catch (err) { + throw new Error("Error creating policy: ", err); + } +} + export async function createContractDefinition(contractId: string, policyId: string, assetId: string): Promise { try { const response = await fetch('/api/createContractDefinition', { diff --git a/src/frontend/app/api/connector-functions.ts b/src/frontend/app/api/connector-functions.ts index 8440f17..38ee4e5 100644 --- a/src/frontend/app/api/connector-functions.ts +++ b/src/frontend/app/api/connector-functions.ts @@ -232,14 +232,16 @@ export async function registerDataplaneProvider(dataplaneId: string) { } }; -function generateCreatePolicy(policyId: string) { - // TODO: acutal policy with permission/prohibition/obligation +function generateCreatePolicy(name: string, description: string) { const createPolicy = { "@context": { "@vocab": "https://w3id.org/edc/v0.0.1/ns/", "odrl": "http://www.w3.org/ns/odrl/2/" }, - "@id": policyId, + "privateProperties": { + "name": name, + "description": description + }, "policy": { "@context": "http://www.w3.org/ns/odrl.jsonld", "@type": "Set", @@ -251,7 +253,7 @@ function generateCreatePolicy(policyId: string) { return createPolicy; }; -export async function createPolicy(policyId: string) { +export async function createPolicy(name: string, description: string) { try { const result = await fetch(connectorManagementUrl + "v2/policydefinitions", { method: 'POST', @@ -260,7 +262,7 @@ export async function createPolicy(policyId: string) { 'Content-Type': 'application/json', 'X-API-Key': authenticationPassword }, - body: JSON.stringify(generateCreatePolicy(policyId)), + body: JSON.stringify(generateCreatePolicy(name, description)), }); if (!result.ok) { throw new Error(`HTTP Error! Status: ${result.status}`); diff --git a/src/frontend/app/api/createPolicy/route.ts b/src/frontend/app/api/createPolicy/route.ts index 001e427..0953495 100644 --- a/src/frontend/app/api/createPolicy/route.ts +++ b/src/frontend/app/api/createPolicy/route.ts @@ -8,8 +8,8 @@ export const POST = auth(async function POST(req) { return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); } const body = await req.json(); - const { policyId } = body; - const result = await createPolicy(policyId); + const { name, description } = body; + const result = await createPolicy(name, description); return NextResponse.json(result); } catch (error) { return NextResponse.json({ error: error.message }, { status: 500 }); diff --git a/src/frontend/app/api/getPolicies/route.ts b/src/frontend/app/api/getPolicies/route.ts index 31149c3..de82039 100644 --- a/src/frontend/app/api/getPolicies/route.ts +++ b/src/frontend/app/api/getPolicies/route.ts @@ -9,7 +9,7 @@ export const GET = auth(async function GET(req) { } const data = await getPolicies(); const policies = data.map((item: any) => ({ - name: item.privateProperties?.name || 'Unnamed Policy', + name: item.privateProperties?.name || 'Default Policy', description: item.privateProperties?.description || 'No description provided', id: item["@id"] })); diff --git a/src/frontend/app/dashboard/upload/page.tsx b/src/frontend/app/dashboard/upload/page.tsx index a5ab845..366fd72 100644 --- a/src/frontend/app/dashboard/upload/page.tsx +++ b/src/frontend/app/dashboard/upload/page.tsx @@ -1,9 +1,11 @@ 'use client'; import React, { useState, useEffect } from 'react'; + import { ArrowPathIcon, TrashIcon, CloudArrowDownIcon, XCircleIcon, CheckCircleIcon } from '@heroicons/react/24/outline'; import { createAsset, createContractDefinition, getAssets, uploadFile, getPolicies, fetchCatalogItems, deleteAsset, deleteContractDefinition, deleteFile, getContractDefinitions } from '@/actions/api'; import { FileInfo, Policy, Asset, CatalogItem } from "@/data/interface/file"; import PolicyDropdown from './PolicyDropdown'; +import PolicyModal from './policyModal'; const MAX_FILE_SIZE_MB = 10; @@ -12,6 +14,7 @@ const UploadPage: React.FC = () => { const [title, setTitle] = useState(''); const [policy, setPolicy] = useState(null); const [showModal, setShowModal] = useState(false); + const [showPolicyModal, setShowPolicyModal] = useState(false); const [errorMessage, setErrorMessage] = useState(''); const [files, setFiles] = useState([]); const [contractDefinitions, setContractDefinitions] = useState<[]>([]); @@ -175,16 +178,19 @@ const UploadPage: React.FC = () => { return (
-
+
+
@@ -238,6 +244,8 @@ const UploadPage: React.FC = () => {
+ setShowPolicyModal(false)} /> + {showModal && (
@@ -289,6 +297,8 @@ const UploadPage: React.FC = () => {
+ + )}
); diff --git a/src/frontend/app/dashboard/upload/policyModal.tsx b/src/frontend/app/dashboard/upload/policyModal.tsx new file mode 100644 index 0000000..11ad517 --- /dev/null +++ b/src/frontend/app/dashboard/upload/policyModal.tsx @@ -0,0 +1,75 @@ +'use client'; +import { createPolicy } from '@/actions/api'; +import React, { useState, useEffect, FormEvent } from 'react'; + +interface PolicyModalProps { + isOpen: boolean; + onClose: () => void; +} + +const PolicyModal: React.FC = ({ isOpen, onClose }) => { + const [name, setName] = useState(""); + const [description, setDescription] = useState(""); + const [errorMessage, setErrorMessage] = useState(""); + + const handleCreate = async (e: FormEvent) => { + e.preventDefault(); + try { + setErrorMessage(""); + await createPolicy(name, description); + onClose(); + } catch(err) { + setErrorMessage("There was a problem creating the policy."); + } + } + + if(!isOpen) { + return null; + } + + return ( +
+
+
+
+ + setName(e.target.value)} + className="border border-gray-300 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:border-gray-600 dark:placeholder-gray-400 dark:focus:ring-blue-500 dark:focus:border-blue-500" + required + /> +
+
+ +