diff --git a/actions/azurestorage.js b/actions/azurestorage.js index a3c02dc0..2ecad913 100644 --- a/actions/azurestorage.js +++ b/actions/azurestorage.js @@ -1693,14 +1693,91 @@ export const listBlobHierarchical = async ( } } }; + +function formatTimeSince(date) { + if (!date) return "Unknown date"; + + const now = new Date(); + const diffMs = now - date; + const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); + + if (diffDays < 7) { + return `${diffDays} day${diffDays !== 1 ? "s" : ""} ago`; + } else { + const diffWeeks = Math.floor(diffDays / 7); + return `${diffWeeks} week${diffWeeks !== 1 ? "s" : ""} ago`; + } +} + +function formatDateDisplay(date) { + return date + ? `${date.toLocaleString("en-GB")} (${formatTimeSince(date)})` + : "Unknown"; +} + +function formatBlobDates(blob) { + const created = blob.createdOn ? new Date(blob.createdOn) : null; + const modified = blob.lastModified ? new Date(blob.lastModified) : null; + + if (!created && !modified) return "Unknown"; + + // If both exist and are the same + if (created && modified && created.getTime() === modified.getTime()) { + return `${created.toLocaleString("en-GB")} (${formatTimeSince( + created + )})`; + } + + // If modified exists and is newer than created + if (created && modified && modified.getTime() > created.getTime()) { + return `Created: ${created.toLocaleString("en-GB")} (${formatTimeSince( + created + )}), Modified: ${modified.toLocaleString("en-GB")} (${formatTimeSince( + modified + )})`; + } + + // Only one date exists + const date = modified || created; + return `${date.toLocaleString("en-GB")} (${formatTimeSince(date)})`; +} + export async function listBlobHierarchicalForUser(containerClient) { const blobNames = []; for await (const blob of containerClient.listBlobsFlat()) { - // blobNames.push(blob.name); + const lastModifiedDate = blob.properties?.lastModified || null; + const createdOnDate = blob.properties?.createdOn || null; + + let displayDate = ""; + + if (createdOnDate && lastModifiedDate) { + if ( + createdOnDate.toDateString() === lastModifiedDate.toDateString() + ) { + // Same day — show just one + displayDate = `Date: ${formatDateDisplay(lastModifiedDate)}`; + } else { + // Different days — show both + displayDate = `Created: ${formatDateDisplay( + createdOnDate + )}, Modified: ${formatDateDisplay(lastModifiedDate)}`; + } + } else if (lastModifiedDate) { + displayDate = `Modified: ${formatDateDisplay(lastModifiedDate)}`; + } else if (createdOnDate) { + displayDate = `Created: ${formatDateDisplay(createdOnDate)}`; + } else { + displayDate = "Unknown date"; + } blobNames.push({ name: blob.name, - size: blob.properties.contentLength || 0, // in bytes + size: blob.properties.contentLength || 0, + lastModified: lastModifiedDate + ? lastModifiedDate.toISOString() + : null, + createdOn: createdOnDate ? createdOnDate.toISOString() : null, + displayDate, }); } return blobNames; diff --git a/pages/storageAdmin.js b/pages/storageAdmin.js index 09eda695..c65167d9 100644 --- a/pages/storageAdmin.js +++ b/pages/storageAdmin.js @@ -1,3 +1,6 @@ +import CookieBanner from "../components/cookieBanner"; +import Footer from "../components/footer"; +import Header from "../components/header"; import { DefaultAzureCredential } from "@azure/identity"; import { BlobServiceClient, ContainerClient } from "@azure/storage-blob"; import { v4 as uuidv4 } from "uuid"; @@ -7,6 +10,7 @@ import { listBlobHierarchical, listContainersForUser, } from "../actions/azurestorage"; +import Head from "next/head"; import Link from "next/link"; import { PrismaClient } from "@prisma/client"; import { @@ -19,8 +23,10 @@ import { getIP, sendRepCompleteMessage, deleteMyRepresentationsFromBlob, + deleteAwaitingSubmissionsFromBlob, } from "../actions"; import CryptoJS from "crypto-js"; +import { useState } from "react"; function getUpToLastSlash(url) { let lastSlash = url.lastIndexOf("/"); @@ -47,6 +53,48 @@ async function streamToString(readableStream) { }); } +function formatTimeSince(date) { + if (!date) return "Unknown date"; + + const now = new Date(); + const diffMs = now - date; + const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); + + if (diffDays < 7) { + return `${diffDays} day${diffDays !== 1 ? "s" : ""} ago`; + } else { + const diffWeeks = Math.floor(diffDays / 7); + return `${diffWeeks} week${diffWeeks !== 1 ? "s" : ""} ago`; + } +} + +function formatBlobDates(blob) { + const created = blob.createdOn ? new Date(blob.createdOn) : null; + const modified = blob.lastModified ? new Date(blob.lastModified) : null; + + if (!created && !modified) return "Unknown"; + + // If both exist and are the same + if (created && modified && created.getTime() === modified.getTime()) { + return `${created.toLocaleString("en-GB")} (${formatTimeSince( + created + )})`; + } + + // If modified exists and is newer than created + if (created && modified && modified.getTime() > created.getTime()) { + return `Created: ${created.toLocaleString("en-GB")} (${formatTimeSince( + created + )}), Modified: ${modified.toLocaleString("en-GB")} (${formatTimeSince( + modified + )})`; + } + + // Only one date exists + const date = modified || created; + return `${date.toLocaleString("en-GB")} (${formatTimeSince(date)})`; +} + const deleteRepItem = (containerID, caseID, repfile) => { deleteMyRepresentationsFromBlob(containerID, caseID, repfile).then( (data) => { @@ -56,185 +104,312 @@ const deleteRepItem = (containerID, caseID, repfile) => { ); }; +const deleteCaseItem = (containerID, caseID) => { + deleteAwaitingSubmissionsFromBlob(containerID, caseID).then((data) => { + return data; + }); +}; + export default function StoragePage({ data }) { console.log(data); + + const [showRepJson, setShowRepJson] = useState(true); + const [showTmpFile, setShowTmpFile] = useState(true); + + const toggleAll = () => { + const newState = !(showRepJson || showTmpFile); + setShowRepJson(newState); + setShowTmpFile(newState); + }; return ( -
rep.json file found:{" "} {folder.repJsonBlob.name}
)} */} - {folder.hasRepJson && ( -