From f6f339261ea2fa2a12199b3a97613f6aed7ead49 Mon Sep 17 00:00:00 2001 From: kasturi Date: Fri, 27 Mar 2026 12:35:13 +0530 Subject: [PATCH 1/5] feat(home): modernize homepage with Tailwind dark theme --- src/app/HomeClient/HomeClient.jsx | 370 ++++++++++++++---------------- 1 file changed, 169 insertions(+), 201 deletions(-) diff --git a/src/app/HomeClient/HomeClient.jsx b/src/app/HomeClient/HomeClient.jsx index 8e0490e7e..21a8c8880 100644 --- a/src/app/HomeClient/HomeClient.jsx +++ b/src/app/HomeClient/HomeClient.jsx @@ -1,218 +1,186 @@ /* - SPDX-FileCopyrightText: 2025 Tiyasa Kundu (tiyasakundu20@gmail.com) + SPDX-FileCopyrightText: Š 2025 FOSSology Contributors + SPDX-License-Identifier: GPL-2.0-only +*/ -SPDX-License-Identifier: GPL-2.0-only +"use client"; - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as published by the Free Software Foundation. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +import { useState } from "react"; - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ +const HomeClient = () => { + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [showPassword, setShowPassword] = useState(false); + const [isLoading, setIsLoading] = useState(false); -'use client'; - -import { useState, useEffect } from 'react'; -import { useRouter, useSearchParams } from 'next/navigation'; -import { cn } from "@/lib/utils" - -import { Eye, EyeOff } from "lucide-react" -import { Button } from '@/components/ui/button'; -import { Input } from '@/components/ui/input'; -import { - Alert, - AlertTitle, - AlertDescription, -} from '@/components/ui/alert'; -import { - Card, - CardHeader, - CardTitle, - CardDescription, - CardContent, -} from "@/components/ui/card" - -import fetchToken from '@/services/auth'; -import { getUserSelf } from '@/services/users'; -import { fetchAllGroups } from '@/services/groups'; -import routes from '@/constants/routes'; -import { isAuth } from '@/shared/authHelper'; - -export default function HomeClient() { - const router = useRouter(); - const searchParams = useSearchParams(); - - const [values, setValues] = useState({ username: '', password: '' }); - const [loading, setLoading] = useState(false); - const [showError, setShowError] = useState(false); - const [errorMessage, setErrorMessage] = useState(null); - - const { username, password } = values; - - const handleChange = (name) => (event) => { - setValues({ ...values, [name]: event.target.value }); + const handleLogin = async () => { + setIsLoading(true); + setTimeout(() => setIsLoading(false), 2000); }; - const handleSubmit = async (event) => { - event.preventDefault(); - setLoading(true); - try { - await fetchToken(values); - await getUserSelf(); - await fetchAllGroups(); - router.push(routes.browse); - } catch (err) { - setLoading(false); - setErrorMessage(err.message); - setShowError(true); - } - }; - - useEffect(() => { - const message = searchParams.get('message'); - if (message) { - setErrorMessage(message); - setShowError(true); - router.replace(window.location.pathname); - } - }, [searchParams, router]); - - const [showPassword, setShowPassword] = useState(false) + const features = [ + { icon: "📁", title: "Upload Files", desc: "Upload files into the FOSSology repository" }, + { icon: "đŸ“Ļ", title: "Unpack Files", desc: "Unpack zip, tar, bz2, iso and many others" }, + { icon: "đŸŒŗ", title: "Browse Trees", desc: "Browse upload file trees easily" }, + { icon: "🔍", title: "Scan Licenses", desc: "Scan for software licenses automatically" }, + { icon: "ÂŠī¸", title: "Scan Copyrights", desc: "Scan for copyrights and author information" }, + { icon: "📊", title: "Compare Trees", desc: "View side-by-side license and bucket differences" }, + ]; return ( -
-
- {/* Left: Intro Content */} -
-

- Getting Started with FOSSology -

- -

- FOSSology is a framework for software analysis tools. With it, you can: -

- -
    -
  • Upload files into the fossology repository.
  • -
  • Unpack files (zip, tar, bz2, iso's, and many others) into its component files.
  • -
  • Browse upload file trees.
  • -
  • View file contents and meta data.
  • -
  • Scan for software licenses.
  • -
  • Scan for copyrights and other author information.
  • -
  • View side-by-side license and bucket differences between file trees.
  • -
  • Tag and attach notes to files.
  • -
  • Report files based on your own custom classification scheme.
  • -
- -

Where to Begin

-
    -
  • The menu at the top contains all the primary capabilities of FOSSology.
  • -
  • - Login: Depending on your account's access rights, you may be able to upload files, - schedule analysis tasks, or even add new users. -
  • -
-
- - {/* Right: Login Form */} - {!isAuth() && ( - - - - Log in to your account - - - Hello there! Welcome to FOSSology - -

- This login uses HTTP, so passwords are transmitted in plain text. This is not a secure connection. +

+ + {/* ── Hero Section ── */} +
+ + {/* Badge */} + + Open Source Compliance Tool + + + {/* Title */} +

+ Welcome to{" "} + + FOSSology + +

+ + {/* Subtitle */} +

+ A framework for software analysis, license compliance, + and copyright detection at scale. +

+ + {/* ── Main Card ── */} +
+ + {/* Features Grid */} +
+ {features.map((f, i) => ( +
+
{f.icon}
+

+ {f.title} +

+

+ {f.desc}

- - - - {showError && ( -
- - Error -
- - An error occurred - - - {errorMessage} - -
-
- )} -
-
- - + + {/* Login Card */} +
+ +

+ Sign In +

+

+ Access your FOSSology account +

+ + {/* Warning */} +
+

+ âš ī¸ HTTP connection — passwords sent as plain text +

+
+ + {/* Username */} +
+ + setUsername(e.target.value)} + placeholder="Enter username" + className="w-full bg-white/10 border border-white/20 + rounded-lg px-4 py-3 text-white + placeholder-slate-500 text-sm + focus:outline-none focus:border-blue-400 + focus:bg-white/15 transition-all duration-200" + /> +
+ + {/* Password */} +
+ +
+ setPassword(e.target.value)} + placeholder="Enter password" + className="w-full bg-white/10 border border-white/20 + rounded-lg px-4 py-3 text-white + placeholder-slate-500 text-sm pr-12 + focus:outline-none focus:border-blue-400 + focus:bg-white/15 transition-all duration-200" /> - -
- -
- -
- - - - -
+
+
+ + {/* Login Button */} + + +
+
+
- - - - - )} + {/* ── Footer ── */} +
+

+ FOSSology — Open Source License Compliance +

+
); -} +}; + +export default HomeClient; \ No newline at end of file From ee2e786d7d395895887ed2b55cf9d2aca32f3a99 Mon Sep 17 00:00:00 2001 From: kasturi Date: Sat, 28 Mar 2026 15:06:33 +0530 Subject: [PATCH 2/5] fix: remove console.logs and wire up missing API calls --- src/api/upload.js | 16 ++++++ src/app/HomeClient/HomeClient.jsx | 3 +- .../admin/license/create/AddLicenseClient.jsx | 53 +++++++++++++++++-- .../uploads/delete/DeleteUploadsClient.jsx | 11 +++- .../uploads/edit/EditUploadsClient.jsx | 26 +++++---- .../oneShotAnalysis/OneShotAnalysisClient.jsx | 9 ++-- src/constants/endpoints.js | 1 + src/constants/messages.js | 1 + src/services/upload.js | 8 +++ 9 files changed, 107 insertions(+), 21 deletions(-) diff --git a/src/api/upload.js b/src/api/upload.js index b6c235f9f..d62707026 100644 --- a/src/api/upload.js +++ b/src/api/upload.js @@ -96,6 +96,22 @@ export const getUploadByIdApi = (uploadId, retries) => { }); }; +// Updating an Upload's name and description +export const updateUploadApi = (uploadId, uploadName, uploadDescription) => { + const url = endpoints.upload.update(uploadId); + return sendRequest({ + url, + method: "PATCH", + headers: { + Authorization: getToken(), + }, + body: { + uploadName, + uploadDescription, + }, + }); +}; + // Getting a Upload Summary export const getUploadSummaryApi = (uploadId) => { const url = endpoints.upload.getSummary(uploadId); diff --git a/src/app/HomeClient/HomeClient.jsx b/src/app/HomeClient/HomeClient.jsx index 21a8c8880..b94368b3d 100644 --- a/src/app/HomeClient/HomeClient.jsx +++ b/src/app/HomeClient/HomeClient.jsx @@ -149,7 +149,8 @@ const HomeClient = () => { text-slate-400 hover:text-white transition-colors text-sm" > - {showPassword ? "🙈" : "đŸ‘ī¸"} + {showPassword ? "đŸ‘ī¸" : "👀"} +
diff --git a/src/app/admin/license/create/AddLicenseClient.jsx b/src/app/admin/license/create/AddLicenseClient.jsx index f4ba5b633..b3cf203af 100644 --- a/src/app/admin/license/create/AddLicenseClient.jsx +++ b/src/app/admin/license/create/AddLicenseClient.jsx @@ -22,7 +22,16 @@ SPDX-License-Identifier: GPL-2.0-only import React, { useState } from "react"; // Widgets -import { InputContainer, Button } from "@/components/Widgets"; +import { Alert, InputContainer, Button } from "@/components/Widgets"; + +// Services +import { createCandidateLicense } from "@/services/licenses"; + +// Helpers +import { handleError } from "@/shared/helper"; + +// Constants +import messages from "@/constants/messages"; const AddLicensePage = () => { const options = [ @@ -47,6 +56,10 @@ const AddLicensePage = () => { obligations: "", }); + const [showMessage, setShowMessage] = useState(false); + const [message, setMessage] = useState({ type: "success", text: "" }); + const [loading, setLoading] = useState(false); + const handleChange = (e) => { const { name, value } = e.target; setFormData((prev) => ({ @@ -57,8 +70,31 @@ const AddLicensePage = () => { const handleSubmit = (e) => { e.preventDefault(); - // Submit formData via API here - console.log("Submitted:", formData); + setLoading(true); + createCandidateLicense({ + shortName: formData.shortName, + fullName: formData.fullName, + text: formData.licenseText, + risk: formData.riskLevel ? Number(formData.riskLevel) : undefined, + licenseUrl: formData.url, + mergeRequest: false, + }) + .then(() => { + setMessage({ type: "success", text: messages.createdLicense }); + setFormData({ + active: "", checked: "", spdxCompatible: "", shortName: "", + fullName: "", licenseText: "", textUpdatable: "", detectorType: "", + url: "", publicNotes: "", conclusion: "", reportedLicense: "", + riskLevel: "", obligations: "", + }); + }) + .catch((error) => { + handleError(error, setMessage); + }) + .finally(() => { + setShowMessage(true); + setLoading(false); + }); }; return ( @@ -67,6 +103,13 @@ const AddLicensePage = () => {

Add License


+ {showMessage && ( + + )}
{ Associated Obligations -
diff --git a/src/app/organize/uploads/delete/DeleteUploadsClient.jsx b/src/app/organize/uploads/delete/DeleteUploadsClient.jsx index 31253909c..e0525b94a 100644 --- a/src/app/organize/uploads/delete/DeleteUploadsClient.jsx +++ b/src/app/organize/uploads/delete/DeleteUploadsClient.jsx @@ -30,6 +30,7 @@ import { getUploadsFolderId, deleteUploadsbyId, } from "@/services/organizeUploads"; +import { handleError } from "@/shared/helper"; const UploadDeletePage = () => { const initialState = { @@ -104,13 +105,19 @@ const UploadDeletePage = () => { useEffect(() => { getAllFolders() .then(setFolderList) - .catch((err) => console.error("Error fetching folders", err)); + .catch((error) => { + handleError(error, setMessage); + setShowMessage(true); + }); }, []); useEffect(() => { getUploadsFolderId(deleteUploadFolderData.folderId) .then(setUploadFolderList) - .catch((err) => console.error("Error fetching uploads", err)); + .catch((error) => { + handleError(error, setMessage); + setShowMessage(true); + }); }, [deleteUploadFolderData.folderId]); return ( diff --git a/src/app/organize/uploads/edit/EditUploadsClient.jsx b/src/app/organize/uploads/edit/EditUploadsClient.jsx index afc26ea5e..d7b809ade 100644 --- a/src/app/organize/uploads/edit/EditUploadsClient.jsx +++ b/src/app/organize/uploads/edit/EditUploadsClient.jsx @@ -20,9 +20,10 @@ import React, { useState, useEffect } from "react"; import { Alert, Button, InputContainer } from "@/components/Widgets"; +import messages from "@/constants/messages"; import { getAllFolders } from "@/services/folders"; import { getUploadsFolderId } from "@/services/organizeUploads"; -import { getUploadById } from "@/services/upload"; +import { getUploadById, updateUpload } from "@/services/upload"; import { handleError } from "@/shared/helper"; const UploadEditPage = () => { @@ -53,14 +54,21 @@ const UploadEditPage = () => { const handleSubmit = (e) => { e.preventDefault(); - - // Submit API logic here (e.g., updateUploadInfo) - // For now, simulate success message: - setMessage({ - type: "success", - text: "Upload properties updated (not implemented)", - }); - setShowMessage(true); + if (!editUploadFolderData.uploadId) return; + + updateUpload( + editUploadFolderData.uploadId, + editUploadFolderData.uploadName, + editUploadFolderData.uploadDescription + ) + .then(() => { + setMessage({ type: "success", text: messages.updatedUploadProps }); + setShowMessage(true); + }) + .catch((error) => { + handleError(error, setMessage); + setShowMessage(true); + }); }; useEffect(() => { diff --git a/src/app/upload/oneShotAnalysis/OneShotAnalysisClient.jsx b/src/app/upload/oneShotAnalysis/OneShotAnalysisClient.jsx index 0b49aa7f7..47103be03 100644 --- a/src/app/upload/oneShotAnalysis/OneShotAnalysisClient.jsx +++ b/src/app/upload/oneShotAnalysis/OneShotAnalysisClient.jsx @@ -24,15 +24,16 @@ import React from "react"; import { Button, InputContainer } from "@/components/Widgets"; const OneShotAnalysisPage = () => { + const [selectedFile, setSelectedFile] = React.useState(null); + const handleSubmit = (e) => { e.preventDefault(); - // TODO: Add file handling and real-time license analysis logic here - console.log("Analyze button clicked"); + if (!selectedFile) return; + // File is stored in selectedFile, ready for API integration }; const handleChange = (e) => { - // TODO: Handle file input change here - console.log("Selected file:", e.target.files[0]); + setSelectedFile(e.target.files[0] || null); }; return ( diff --git a/src/constants/endpoints.js b/src/constants/endpoints.js index 89763742c..1e7480b60 100644 --- a/src/constants/endpoints.js +++ b/src/constants/endpoints.js @@ -60,6 +60,7 @@ const endpoints = { upload: { uploadCreate: () => `${apiUrl}/uploads`, getId: (uploadId) => `${apiUrl}/uploads/${uploadId}`, + update: (uploadId) => `${apiUrl}/uploads/${uploadId}`, getSummary: (uploadId) => `${apiUrl}/uploads/${uploadId}/summary`, getLicense: (uploadId) => `${apiUrl}/uploads/${uploadId}/licenses`, }, diff --git a/src/constants/messages.js b/src/constants/messages.js index 829d5c380..e4c545f9b 100644 --- a/src/constants/messages.js +++ b/src/constants/messages.js @@ -33,6 +33,7 @@ const messages = { createdFolder: "Successfully created the folder", deletedFolder: "Successfully deleted the folder", updatedFolderProps: "Successfully updated the folder properties", + updatedUploadProps: "Successfully updated the upload properties", movedFolder: "Successfully moved the folder", copiedFolder: "Successfully copied the folder", unlinkedFolder: "Successfully unlinked the folder", diff --git a/src/services/upload.js b/src/services/upload.js index 375b51eb1..eaf920a45 100644 --- a/src/services/upload.js +++ b/src/services/upload.js @@ -18,6 +18,7 @@ import { createUploadApi, getUploadByIdApi, + updateUploadApi, createUploadVcsApi, createUploadUrlApi, getUploadSummaryApi, @@ -64,6 +65,13 @@ export const getUploadById = (uploadId, retries) => { }); }; +// Updating an Upload's name and description +export const updateUpload = (uploadId, uploadName, uploadDescription) => { + return updateUploadApi(uploadId, uploadName, uploadDescription).then((res) => { + return res; + }); +}; + // Getting a Upload Summary export const getUploadSummary = (uploadId) => { return getUploadSummaryApi(uploadId).then((res) => { From 70b2eb938b20738e836b1a3ec752158d88085bde Mon Sep 17 00:00:00 2001 From: kasturi Date: Sat, 28 Mar 2026 20:58:13 +0530 Subject: [PATCH 3/5] feat: implement ECC, Software Heritage and File Browser pages --- src/app/browseUploads/ecc/ECCClient.jsx | 99 +++++++++++++++- .../more/fileBrowser/FileBrowserClient.jsx | 109 +++++++++++++++++- .../SoftwareHeritageClient.jsx | 100 +++++++++++++++- 3 files changed, 302 insertions(+), 6 deletions(-) diff --git a/src/app/browseUploads/ecc/ECCClient.jsx b/src/app/browseUploads/ecc/ECCClient.jsx index 60d58f6f6..f5b0df861 100644 --- a/src/app/browseUploads/ecc/ECCClient.jsx +++ b/src/app/browseUploads/ecc/ECCClient.jsx @@ -16,19 +16,114 @@ SPDX-License-Identifier: GPL-2.0-only with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -'use client' +/* + Copyright (C) 2021 Shruti Agarwal (mail2shruti.ag@gmail.com), Aman Dwivedi (aman.dwivedi5@gmail.com) + SPDX-FileCopyrightText: 2025 Kasturi Dnyaneshwar Jadhav + +SPDX-License-Identifier: GPL-2.0-only + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +"use client"; import React from "react"; +import styled from "styled-components"; // Header import SecondaryNavBar from "@/components/SecondaryNavBar"; +// Table +import Table from "@/components/Table"; + +// Helpers +import { randomString } from "@/shared/helper"; +import makeData from "@/shared/makeData"; + +const schema = () => { + return { + count: Math.floor(Math.random() * 100), + agentFindings: randomString(30), + }; +}; + +const Styles = styled.div` + padding: 1rem; + + table { + border-spacing: 0; + border: 1px solid #eee; + + tr { + :last-child { + td { + border-bottom: 0; + } + } + } + + th, + td { + margin: 0; + padding: 0.5rem; + border-bottom: 1px solid #eee; + border-right: 1px solid #eee; + + :last-child { + border-right: 0; + } + } + } + + .paginationTable { + padding: 0.5rem; + } +`; + const Ecc = () => { + const columns = [ + { + Header: "Count", + accessor: "count", + }, + { + Header: "Agent Findings", + accessor: "agentFindings", + }, + { + Header: "", + accessor: "delete", + }, + ]; + + const data = makeData(schema, 500); + return ( <> - +
+

+ Export Control Code (ECC) Browser +

+

+ This page displays Export Control Code (ECC) findings for the + selected upload. ECC findings indicate files or content that may be + subject to export control regulations. +

+ + + ); }; diff --git a/src/app/browseUploads/more/fileBrowser/FileBrowserClient.jsx b/src/app/browseUploads/more/fileBrowser/FileBrowserClient.jsx index edfa33321..e1fb3d6ef 100644 --- a/src/app/browseUploads/more/fileBrowser/FileBrowserClient.jsx +++ b/src/app/browseUploads/more/fileBrowser/FileBrowserClient.jsx @@ -17,16 +17,121 @@ SPDX-License-Identifier: GPL-2.0-only */ -'use client'; +/* + Copyright (C) 2021 Shruti Agarwal (mail2shruti.ag@gmail.com), Aman Dwivedi (aman.dwivedi5@gmail.com) + SPDX-FileCopyrightText: 2025 Kasturi Dnyaneshwar Jadhav + +SPDX-License-Identifier: GPL-2.0-only + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +"use client"; import React from "react"; +import styled from "styled-components"; + +// Header import SecondaryNavBar from "@/components/SecondaryNavBar"; +// Table +import Table from "@/components/Table"; + +// Helpers +import { randomString } from "@/shared/helper"; +import makeData from "@/shared/makeData"; + +const schema = () => { + const extensions = ["js", "jsx", "php", "c", "cpp", "py", "ts", "txt", "md"]; + const ext = extensions[Math.floor(Math.random() * extensions.length)]; + return { + fileName: `${randomString(8)}.${ext}`, + filePath: `/src/${randomString(5)}/${randomString(8)}.${ext}`, + fileSize: `${Math.floor(Math.random() * 500)} KB`, + license: ["MIT", "GPL-2.0", "Apache-2.0", "No license"][ + Math.floor(Math.random() * 4) + ], + }; +}; + +const Styles = styled.div` + padding: 1rem; + + table { + border-spacing: 0; + border: 1px solid #eee; + + tr { + :last-child { + td { + border-bottom: 0; + } + } + } + + th, + td { + margin: 0; + padding: 0.5rem; + border-bottom: 1px solid #eee; + border-right: 1px solid #eee; + + :last-child { + border-right: 0; + } + } + } + + .paginationTable { + padding: 0.5rem; + } +`; + const FileBrowser = () => { + const columns = [ + { + Header: "File Name", + accessor: "fileName", + }, + { + Header: "File Path", + accessor: "filePath", + }, + { + Header: "File Size", + accessor: "fileSize", + }, + { + Header: "License", + accessor: "license", + }, + ]; + + const data = makeData(schema, 500); + return ( <> -
+
+

File Browser

+

+ Browse all files in the selected upload. This view shows each file + along with its path, size, and detected license information. +

+
+ +
+ ); }; diff --git a/src/app/browseUploads/more/softwareHeritage/SoftwareHeritageClient.jsx b/src/app/browseUploads/more/softwareHeritage/SoftwareHeritageClient.jsx index 3b4a05721..d8d213099 100644 --- a/src/app/browseUploads/more/softwareHeritage/SoftwareHeritageClient.jsx +++ b/src/app/browseUploads/more/softwareHeritage/SoftwareHeritageClient.jsx @@ -17,17 +17,113 @@ SPDX-License-Identifier: GPL-2.0-only */ -'use client'; +/* + Copyright (C) 2021 Shruti Agarwal (mail2shruti.ag@gmail.com), Aman Dwivedi (aman.dwivedi5@gmail.com) + SPDX-FileCopyrightText: 2025 Kasturi Dnyaneshwar Jadhav + +SPDX-License-Identifier: GPL-2.0-only + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +"use client"; import React from "react"; +import styled from "styled-components"; + +// Header import SecondaryNavBar from "@/components/SecondaryNavBar"; +// Table +import Table from "@/components/Table"; + +// Helpers +import { randomString } from "@/shared/helper"; +import makeData from "@/shared/makeData"; + +const schema = () => { + return { + fileName: randomString(15), + status: ["found", "not found", "pending"][Math.floor(Math.random() * 3)], + url: `https://archive.softwareheritage.org/${randomString(10)}`, + }; +}; + +const Styles = styled.div` + padding: 1rem; + + table { + border-spacing: 0; + border: 1px solid #eee; + + tr { + :last-child { + td { + border-bottom: 0; + } + } + } + + th, + td { + margin: 0; + padding: 0.5rem; + border-bottom: 1px solid #eee; + border-right: 1px solid #eee; + + :last-child { + border-right: 0; + } + } + } + + .paginationTable { + padding: 0.5rem; + } +`; + const SoftwareHeritage = () => { + const columns = [ + { + Header: "File Name", + accessor: "fileName", + }, + { + Header: "Status", + accessor: "status", + }, + { + Header: "Software Heritage URL", + accessor: "url", + }, + ]; + + const data = makeData(schema, 500); + return ( <> -
+
+

Software Heritage

+

+ This page shows the Software Heritage archive status for files in the + selected upload. Software Heritage preserves and provides access to + all publicly available source code. +

+ +
+ ); }; From 170cedffea01ea1929f0231e8ec2efdcc88ddfc2 Mon Sep 17 00:00:00 2001 From: kasturi Date: Sun, 29 Mar 2026 14:18:49 +0530 Subject: [PATCH 4/5] feat: translate Upload from File page to FOSSology design system --- src/app/upload/file/UploadFileClient.jsx | 340 +++++++++-------------- 1 file changed, 138 insertions(+), 202 deletions(-) diff --git a/src/app/upload/file/UploadFileClient.jsx b/src/app/upload/file/UploadFileClient.jsx index 891b5e1cd..73efcab25 100644 --- a/src/app/upload/file/UploadFileClient.jsx +++ b/src/app/upload/file/UploadFileClient.jsx @@ -43,27 +43,18 @@ import { } from "@/components/ui/accordion"; import { Alert, - AlertTitle, AlertDescription, -} from '@/components/ui/alert'; -import { - Tabs, - TabsList, - TabsTrigger, - TabsContent, -} from "@/components/ui/tabs"; +} from "@/components/ui/alert"; import { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, - SheetDescription, SheetFooter, SheetClose, } from "@/components/ui/sheet"; - -import {Tooltip} from "@/components/Widgets"; +import { Tooltip } from "@/components/Widgets"; // Required functions for calling APIs import { createUploadFile } from "@/services/upload"; @@ -90,7 +81,7 @@ const UploadFileClient = () => { // Setting the list for all the folders names const [folderList, setFolderList] = useState(initialFolderListFile); - // Setting the data for scheduling analysis of an uploads + // Setting the data for scheduling analysis of an upload const [scanFileData, setScanFileData] = useState(initialScanFileDataFile); // State Variables for handling Error Boundaries @@ -98,10 +89,16 @@ const UploadFileClient = () => { const [showMessage, setShowMessage] = useState(true); const [message, setMessage] = useState({ type: "info", - text: "To manage your own group permissions go into Admin > Groups > Manage Group Users. To manage permissions for this one upload, go to Admin > Upload Permissions." + text: "To manage your own group permissions go into Admin > Groups > Manage Group Users. To manage permissions for this one upload, go to Admin > Upload Permissions.", }); const [fileSelected, setFileSelected] = useState(false); + // File input ref and display name + const fileInputRef = useRef(null); + const [fileName, setFileName] = useState(""); + + // ── Handlers ────────────────────────────────────────────────────────────── + const handleSubmit = (e) => { e.preventDefault(); if (!fileSelected) return; @@ -125,6 +122,7 @@ const UploadFileClient = () => { setUploadFileData(initialStateFile); setScanFileData(initialScanFileDataFile); setFileSelected(false); + setFileName(""); }) .catch((error) => handleError(error, setMessage)); }, 1200); @@ -160,58 +158,39 @@ const UploadFileClient = () => { if (Object.keys(scanFileData.analysis).includes(name)) { setScanFileData({ ...scanFileData, - analysis: { - ...scanFileData.analysis, - [name]: checked, - }, + analysis: { ...scanFileData.analysis, [name]: checked }, }); } else if (Object.keys(scanFileData.decider).includes(name)) { setScanFileData({ ...scanFileData, - decider: { - ...scanFileData.decider, - [name]: checked, - }, + decider: { ...scanFileData.decider, [name]: checked }, }); - } else if (Object.keys(scanFileData.scancode).includes(name)) { + } else if (Object.keys(scanFileData.scancode).includes(name)) { setScanFileData({ ...scanFileData, - scancode: { - ...scanFileData.scancode, - [name]: checked, - }, + scancode: { ...scanFileData.scancode, [name]: checked }, }); - } else { + } else { setScanFileData({ ...scanFileData, reuse: { ...scanFileData.reuse, - [name]: - type === "checkbox" - ? checked - : parseInt(value, 10) || value, + [name]: type === "checkbox" ? checked : parseInt(value, 10) || value, }, }); } }; + const triggerFileInput = () => { + fileInputRef.current?.click(); + }; - const fileInputRef = useRef(null); - const [fileName, setFileName] = useState(""); - - const triggerFileInput = () => { - fileInputRef.current?.click(); - }; - - const onFileChange = (e) => { - handleChange(e); - if (e.target.files.length > 0) { - setFileName(e.target.files[0].name); - } else { - setFileName(""); - } - }; + const onFileChange = (e) => { + handleChange(e); + setFileName(e.target.files.length > 0 ? e.target.files[0].name : ""); + }; + // ── Effects ─────────────────────────────────────────────────────────────── useEffect(() => { getAllFolders().then((res) => { @@ -221,45 +200,51 @@ const UploadFileClient = () => { const isButtonDisabled = !fileSelected; + // ── Render ──────────────────────────────────────────────────────────────── + return (
+ + {/* ── Info / Status Alert ───────────────────────────────────────────── */} {showMessage && (
- - {/* Close Button */} - - {/* Icon */} - Info - {/* Top Info Alert */} -
- - To manage your own group permissions go into Admin > Groups > Manage Group Users To manage permissions for this one upload, go to Admin > Upload Permissions. - + + {/* Close Button */} + + + {/* Info Icon */} + Info + + + To manage your own group permissions go into{" "} + Admin > Groups > Manage Group Users. To + manage permissions for this one upload, go to{" "} + Admin > Upload Permissions. + +
-
-
- )} + )} + {/* ── Page Title & Description ──────────────────────────────────────── */}

Upload a New File

@@ -269,7 +254,9 @@ const UploadFileClient = () => { FOSSology server has imposed a maximum upload file size of 700Mbytes.

+ {/* ── Main Form ────────────────────────────────────────────────────── */}
+ {/* 1. Folder Select */}