From 3f2b7554ef907c54007dd51392968fd396b8f972 Mon Sep 17 00:00:00 2001 From: Colin Slater Date: Fri, 26 Sep 2025 13:59:00 -0700 Subject: [PATCH 1/5] Apply automatic formatting to _lib and _components. --- app/_components/AddCollectionSelectServer.js | 34 +- app/_components/TabNav.js | 69 ++-- app/_components/addCollectionSelect.js | 134 ++++--- app/_components/bandSelector.js | 50 +-- app/_components/dualPlotPager.js | 53 ++- app/_components/listPager.js | 154 ++++---- app/_components/plotDisplay.js | 72 ++-- app/_components/plotPager.js | 320 ++++++++++------- app/_components/selectionDropdown.js | 53 ++- app/_lib/dataIdFuncs.js | 55 +-- app/_lib/summaries.js | 352 ++++++++++--------- 11 files changed, 746 insertions(+), 600 deletions(-) diff --git a/app/_components/AddCollectionSelectServer.js b/app/_components/AddCollectionSelectServer.js index 453dc68..b3e01af 100644 --- a/app/_components/AddCollectionSelectServer.js +++ b/app/_components/AddCollectionSelectServer.js @@ -1,25 +1,23 @@ - -'use server' +"use server"; export async function pollJob(jobId) { - - console.log(`pollJob ${jobId}`) - let res = await fetch(`http://production-tools/plot-navigator/cache/job/${jobId}`) - let data = await res.json() - console.log(res.json()) - return data + console.log(`pollJob ${jobId}`); + let res = await fetch( + `http://production-tools/plot-navigator/cache/job/${jobId}`, + ); + let data = await res.json(); + console.log(res.json()); + return data; } export async function putCollection(repo, collectionName) { + let res = await fetch("http://production-tools/plot-navigator/cache/", { + method: "PUT", + body: JSON.stringify({ repo: repo, collection: collectionName }), + headers: { "Content-Type": "application/json" }, + }); + let data = await res.json(); + console.log(`putCollection ${JSON.stringify(data)}`); - let res = await fetch("http://production-tools/plot-navigator/cache/", - {method: "PUT", - body: JSON.stringify({repo: repo, collection: collectionName}), - headers: {"Content-Type": "application/json"}} - ) - let data = await res.json() - console.log(`putCollection ${JSON.stringify(data)}`) - - return data.jobId - + return data.jobId; } diff --git a/app/_components/TabNav.js b/app/_components/TabNav.js index be920d8..beb2d19 100644 --- a/app/_components/TabNav.js +++ b/app/_components/TabNav.js @@ -1,40 +1,39 @@ -'use client' +"use client"; -import React from 'react' -import { useState } from 'react' +import React from "react"; +import { useState } from "react"; import Link from "next/link"; import { useSearchParams } from "next/navigation"; - -export default function TabNav({panes}) { - const searchParams = useSearchParams(); - - const [currentPane, setCurrentPane] = useState(searchParams.get("t") || 0) - - - const buttonClass = "p-2 border-t-2 border-x-2 float-left w-48 text-center hover:underline hover:cursor-pointer mx-2" - const buttons = panes.map((pane, n) => ( - setCurrentPane(n)}> -
- {pane.title} -
- - )) - - return ( -
-
- {buttons} -
-
- {panes[currentPane].content} -
-
- - ) - - +export default function TabNav({ panes }) { + const searchParams = useSearchParams(); + + const [currentPane, setCurrentPane] = useState(searchParams.get("t") || 0); + + const buttonClass = + "p-2 border-t-2 border-x-2 float-left w-48 text-center hover:underline hover:cursor-pointer mx-2"; + const buttons = panes.map((pane, n) => ( + setCurrentPane(n)} + > +
+ {pane.title} +
+ + )); + + return ( +
+
{buttons}
+
+ {panes[currentPane].content} +
+
+ ); } - - - diff --git a/app/_components/addCollectionSelect.js b/app/_components/addCollectionSelect.js index 5beee6d..80437ef 100644 --- a/app/_components/addCollectionSelect.js +++ b/app/_components/addCollectionSelect.js @@ -1,68 +1,88 @@ -'use client' +"use client"; -import React from 'react'; -import { useState, useEffect } from 'react' +import React from "react"; +import { useState, useEffect } from "react"; -import {putCollection, pollJob} from './AddCollectionSelectServer.js' +import { putCollection, pollJob } from "./AddCollectionSelectServer.js"; -export default function AddCollectionSelect({repos}) { +export default function AddCollectionSelect({ repos }) { + const [repo, setRepo] = useState(repos[0]); + const [collectionName, setCollectionName] = useState(""); + const [jobId, setJobId] = useState(""); + const [statusMessage, setStatusMessage] = useState(""); + const [statusClasses, setStatusClasses] = useState(""); + const [resultMessage, setResultMessage] = useState(""); - const [repo, setRepo] = useState(repos[0]); - const [collectionName, setCollectionName] = useState(""); - const [jobId, setJobId] = useState(""); - const [statusMessage, setStatusMessage] = useState(""); - const [statusClasses, setStatusClasses] = useState(""); - const [resultMessage, setResultMessage] = useState(""); - - const pollUpdates = async () => { - if(jobId == "") { - return - } - await new Promise(r => setTimeout(r, 5000)); - console.log(`Polling ${jobId}`) - const res = await pollJob(jobId) - setStatusMessage(res.status.replace("_", " ")) - bounceText() - setStatusClasses("bg-sky-500/10") - if(res.status == "in_progress") { - await pollUpdates() - } else if(res.status == "complete") { - setResultMessage(res.result) - } + const pollUpdates = async () => { + if (jobId == "") { + return; } - useEffect(() => {pollUpdates(jobId)}, [jobId]) - - const submitForm = async () => { - const jobId = await putCollection(repo, collectionName) - setJobId(jobId) - setStatusMessage("Started") - setResultMessage("") - + await new Promise((r) => setTimeout(r, 5000)); + console.log(`Polling ${jobId}`); + const res = await pollJob(jobId); + setStatusMessage(res.status.replace("_", " ")); + bounceText(); + setStatusClasses("bg-sky-500/10"); + if (res.status == "in_progress") { + await pollUpdates(); + } else if (res.status == "complete") { + setResultMessage(res.result); } + }; + useEffect(() => { + pollUpdates(jobId); + }, [jobId]); - const bounceText = () => { - setStatusClasses("bg-sky-500/10") - } + const submitForm = async () => { + const jobId = await putCollection(repo, collectionName); + setJobId(jobId); + setStatusMessage("Started"); + setResultMessage(""); + }; + + const bounceText = () => { + setStatusClasses("bg-sky-500/10"); + }; - useEffect(() => {setStatusClasses("duration-1000")}, [statusClasses]) + useEffect(() => { + setStatusClasses("duration-1000"); + }, [statusClasses]); - return ( -
- - setCollectionName(e.target.value)} /> - -
{statusMessage}
-
{resultMessage}
- { /* + return ( +
+ + setCollectionName(e.target.value)} + /> + +
+ {statusMessage} +
+
{resultMessage}
+ {/* - */ } -
- ) + */} +
+ ); } - diff --git a/app/_components/bandSelector.js b/app/_components/bandSelector.js index 405790d..13bc6a1 100644 --- a/app/_components/bandSelector.js +++ b/app/_components/bandSelector.js @@ -1,26 +1,32 @@ +"use client"; -'use client' +import React from "react"; +import { useState } from "react"; -import React from 'react'; -import { useState } from 'react' - -export default function BandSelector({selectedBands, onBandUpdated}) { - - const bandOrder = ['u', 'g', 'r', 'i', 'z', 'y'] - - return ( -
- { bandOrder.map((band, n) => - - )} -
- ) +export default function BandSelector({ selectedBands, onBandUpdated }) { + const bandOrder = ["u", "g", "r", "i", "z", "y"]; + return ( +
+ {bandOrder.map((band, n) => ( + + ))} +
+ ); } diff --git a/app/_components/dualPlotPager.js b/app/_components/dualPlotPager.js index dc9b9f7..5fed6ca 100644 --- a/app/_components/dualPlotPager.js +++ b/app/_components/dualPlotPager.js @@ -3,8 +3,7 @@ import React from "react"; import { useState, useEffect } from "react"; import BandSelector from "./bandSelector.js"; -import { DataIdSortFunc } from '@/lib/dataIdFuncs' - +import { DataIdSortFunc } from "@/lib/dataIdFuncs"; /* * TODO: @@ -52,19 +51,25 @@ export default function DualPlotPager({ ); const indexedEntries = uniqDataIds - .filter((dataId) => 'band' in dataId ? selectedBands[dataId.band] : true) - .map((dataId, n) => ({ - dataId: dataId, - index: n, - plotA: - plotEntriesA[dataIdStringsA.findIndex((x) => x === JSON.stringify(dataId))]?.plot ?? - null, - plotB: - plotEntriesB[dataIdStringsB.findIndex((x) => x === JSON.stringify(dataId))]?.plot ?? - null, - })); + .filter((dataId) => + "band" in dataId ? selectedBands[dataId.band] : true, + ) + .map((dataId, n) => ({ + dataId: dataId, + index: n, + plotA: + plotEntriesA[ + dataIdStringsA.findIndex((x) => x === JSON.stringify(dataId)) + ]?.plot ?? null, + plotB: + plotEntriesB[ + dataIdStringsB.findIndex((x) => x === JSON.stringify(dataId)) + ]?.plot ?? null, + })); - const sortedEntries = indexedEntries.sort((a,b) => DataIdSortFunc(a.dataId, b.dataId)) + const sortedEntries = indexedEntries.sort((a, b) => + DataIdSortFunc(a.dataId, b.dataId), + ); return sortedEntries; }; @@ -185,12 +190,22 @@ export default function DualPlotPager({
{collectionA}
{collectionB}
- {plotEntriesA.length == 0 || plotEntriesB.length == 0 ? -
-
{plotEntriesA.length == 0 ? "No plots of this type in this collection" : ""}
-
{plotEntriesB.length == 0 ? "No plots of this type in this collection" : ""}
+ {plotEntriesA.length == 0 || plotEntriesB.length == 0 ? ( +
+
+ {plotEntriesA.length == 0 + ? "No plots of this type in this collection" + : ""}
- : "" } +
+ {plotEntriesB.length == 0 + ? "No plots of this type in this collection" + : ""} +
+
+ ) : ( + "" + )}
{getSlice(currentPage).map((indexedEntry, n) => (
diff --git a/app/_components/listPager.js b/app/_components/listPager.js index 603ab4c..de2cedc 100644 --- a/app/_components/listPager.js +++ b/app/_components/listPager.js @@ -1,74 +1,104 @@ +"use client"; +import Link from "next/link"; +import React from "react"; +import { useState } from "react"; -'use client' +export default function ListPager({ + listEntries, + entriesPerPage = 10, + showRepo = true, +}) { + const [currentPage, setCurrentPage] = useState(1); -import Link from 'next/link' -import React from 'react'; -import { useState } from 'react' + const totalPages = () => { + return Math.ceil(listEntries.length / entriesPerPage); + }; -export default function ListPager({listEntries, entriesPerPage = 10, showRepo = true}) { - - const [currentPage, setCurrentPage] = useState(1) - - const totalPages = () => { - return Math.ceil(listEntries.length/entriesPerPage) - } - - const previousPage = () => { - if(currentPage > 1) { - setCurrentPage(currentPage - 1) - } + const previousPage = () => { + if (currentPage > 1) { + setCurrentPage(currentPage - 1); } + }; - const nextPage = () => { - if(currentPage < totalPages()) { - setCurrentPage(currentPage + 1) - } + const nextPage = () => { + if (currentPage < totalPages()) { + setCurrentPage(currentPage + 1); } + }; - const getSlice = (currentPage) => { + const getSlice = (currentPage) => { + return listEntries.slice( + (currentPage - 1) * entriesPerPage, + currentPage * entriesPerPage, + ); + }; + const cellClassNames = "px-2 py-3"; - return listEntries.slice((currentPage - 1) * entriesPerPage, currentPage * entriesPerPage) - } - const cellClassNames = "px-2 py-3" - - return ( -
-
- - - - - { showRepo ? - - : ""} - - - - - {getSlice(currentPage).map((summary, n) => - ( - { showRepo ? - - : "" } - - ))} - -
CollectionRepoLast Updated
{summary.collection}{summary.repo}{summary.lastModified.toDateString()}
+ return ( +
+
+ + + + + {showRepo ? : ""} + + + + + {getSlice(currentPage).map((summary, n) => ( + + + {showRepo ? ( + + ) : ( + "" + )} + + + ))} + +
CollectionRepoLast Updated
+ + {summary.collection} + + {summary.repo} + {summary.lastModified.toDateString()} +
-
-
- { currentPage > 1 ? : -
Prev
} -
-
Page {currentPage}/{totalPages()}
-
- { currentPage < totalPages() ? : -
Next
} -
-
+
+
+ {currentPage > 1 ? ( + + ) : ( +
Prev
+ )} +
+
+ Page {currentPage}/{totalPages()} +
+
+ {currentPage < totalPages() ? ( + + ) : ( +
Next
+ )} +
-
- ) - +
+
+ ); } diff --git a/app/_components/plotDisplay.js b/app/_components/plotDisplay.js index 524d542..b4a2cd0 100644 --- a/app/_components/plotDisplay.js +++ b/app/_components/plotDisplay.js @@ -1,33 +1,51 @@ +import React from "react"; -import React from 'react'; +export default async function PlotDisplay({ + plotEntry, + showDataId = true, + showDatasetType = false, + showPermalink = false, +}) { + const { instrument, skymap, ...dataId } = JSON.parse(plotEntry.dataId); + const uuid = plotEntry.id; + const imgUrl = plotEntry.url; + const repo = plotEntry.repo; + const permalink = plotEntry.permalink ?? ""; + const datasetType = plotEntry.datasetType ?? ""; -export default async function PlotDisplay({plotEntry, showDataId = true, showDatasetType = false, showPermalink = false}) { + const splitType = [...datasetType.matchAll(/[a-zA-Z0-9]*(_|$)/g)].map( + (x) => x[0], + ); + const typeWithWbr = splitType.join("\u00ad"); - const {instrument, skymap, ...dataId} = JSON.parse(plotEntry.dataId) - const uuid = plotEntry.id - const imgUrl = plotEntry.url - const repo = plotEntry.repo - const permalink = plotEntry.permalink ?? '' - const datasetType = plotEntry.datasetType ?? '' + const dataIdString = Object.entries(dataId) + .map(([k, v]) => `${k}: ${v}`) + .join(", "); - const splitType = [...datasetType.matchAll(/[a-zA-Z0-9]*(_|$)/g)].map((x) => x[0]) - const typeWithWbr = splitType.join('\u00ad') - - const dataIdString = Object.entries(dataId).map(([k,v]) => `${k}: ${v}`).join(', ') - - return ( -
-
- { showDataId ? dataIdString : "" } - { showDatasetType ? typeWithWbr : "" } -
- { showPermalink ? : "" } - { uuid ? - - : - - } + return ( +
+
+ {showDataId ? dataIdString : ""} + {showDatasetType ? typeWithWbr : ""} +
+ {showPermalink ? ( + - - ) + ) : ( + "" + )} + {uuid ? ( + + ) : ( + + )} +
+ ); } diff --git a/app/_components/plotPager.js b/app/_components/plotPager.js index 9d5c5f7..a931812 100644 --- a/app/_components/plotPager.js +++ b/app/_components/plotPager.js @@ -1,143 +1,199 @@ - -'use client' - -import React from 'react'; -import { useState, useEffect } from 'react' -import BandSelector from './bandSelector.js' - -export default function PlotPager({plotEntries, plotsPerPage = 10}) { - - const [selectedBands, setSelectedBands] = useState({u: true, g: true, r: true, i: true, z: true, y: true}) - - const [currentPage, setCurrentPage] = useState(1) - const [inLightbox, setInLightbox] = useState(false) - const [displayedEntry, setDisplayedEntry] = useState(0) - - const getFilteredEntries = () => { - - const indexedEntries = plotEntries.map((entry, n) => ({dataId: entry.dataId, plot: entry.plot, index: n})) - return indexedEntries.filter( - (indexedEntry) => selectedBands[indexedEntry.dataId.band] || !('band' in indexedEntry.dataId) ) +"use client"; + +import React from "react"; +import { useState, useEffect } from "react"; +import BandSelector from "./bandSelector.js"; + +export default function PlotPager({ plotEntries, plotsPerPage = 10 }) { + const [selectedBands, setSelectedBands] = useState({ + u: true, + g: true, + r: true, + i: true, + z: true, + y: true, + }); + + const [currentPage, setCurrentPage] = useState(1); + const [inLightbox, setInLightbox] = useState(false); + const [displayedEntry, setDisplayedEntry] = useState(0); + + const getFilteredEntries = () => { + const indexedEntries = plotEntries.map((entry, n) => ({ + dataId: entry.dataId, + plot: entry.plot, + index: n, + })); + return indexedEntries.filter( + (indexedEntry) => + selectedBands[indexedEntry.dataId.band] || + !("band" in indexedEntry.dataId), + ); + }; + + const totalPages = () => { + return Math.ceil(getFilteredEntries().length / plotsPerPage); + }; + + const onBandUpdated = (band, value) => { + setSelectedBands({ ...selectedBands, [band]: event.target.checked }); + }; + + useEffect(() => { + if (currentPage > totalPages()) { + setCurrentPage(totalPages()); } - - const totalPages = () => { - return Math.ceil(getFilteredEntries().length/plotsPerPage) + if (currentPage == 0 && totalPages() > 0) { + setCurrentPage(1); } - - const onBandUpdated = (band, value) => { - setSelectedBands({...selectedBands, [band]: event.target.checked}) - } - - useEffect(() => { - if(currentPage > totalPages()) { - setCurrentPage(totalPages()) - } - if(currentPage == 0 && totalPages() > 0) { - setCurrentPage(1) - } - }, [selectedBands]) - - const displayBandSelector = () => { - const dimensions = new Set(plotEntries.map((entry) => Object.keys(entry.dataId)).flat()) - return (dimensions.has('band')) + }, [selectedBands]); + + const displayBandSelector = () => { + const dimensions = new Set( + plotEntries.map((entry) => Object.keys(entry.dataId)).flat(), + ); + return dimensions.has("band"); + }; + + const previousPage = () => { + if (currentPage > 1) { + setCurrentPage(currentPage - 1); } + }; - const previousPage = () => { - if(currentPage > 1) { - setCurrentPage(currentPage - 1) - } + const nextPage = () => { + if (currentPage < totalPages()) { + setCurrentPage(currentPage + 1); } - - const nextPage = () => { - if(currentPage < totalPages()) { - setCurrentPage(currentPage + 1) - } + }; + + const showLightboxEntry = (entry) => { + setDisplayedEntry(entry); + setInLightbox(true); + }; + + const exitLightbox = () => { + setInLightbox(false); + }; + const doNothing = (e) => { + e.stopPropagation(); + }; + + const advanceLeft = (e) => { + e.stopPropagation(); + if (displayedEntry > 0) { + setDisplayedEntry(displayedEntry - 1); } + }; - const showLightboxEntry = (entry) => { - setDisplayedEntry(entry) - setInLightbox(true) - } - - const exitLightbox = () => { - setInLightbox(false) - } - const doNothing = (e) => { - e.stopPropagation(); + const advanceRight = (e) => { + e.stopPropagation(); + if (displayedEntry < plotEntries.length - 1) { + setDisplayedEntry(displayedEntry + 1); } - - const advanceLeft = (e) => { - e.stopPropagation(); - if(displayedEntry > 0) { - setDisplayedEntry(displayedEntry - 1) - } - } - - const advanceRight = (e) => { - e.stopPropagation(); - if(displayedEntry < (plotEntries.length - 1)) { - setDisplayedEntry(displayedEntry + 1) - } - } - - - const getSlice = (currentPage) => { - - return getFilteredEntries().slice((currentPage - 1) * plotsPerPage, currentPage * plotsPerPage) - } - - - return ( -
-
-
-
-
- { currentPage > 1 ? : -
Prev
} -
-
Page {currentPage}/{totalPages()}
-
- { currentPage < totalPages() ? : -
Next
} -
-
-
- { displayBandSelector() ? : "" } -
-
-
- {getSlice(currentPage).map((indexedEntry, n) => -
showLightboxEntry(indexedEntry.index)}> - {indexedEntry.plot} -
- )} + }; + + const getSlice = (currentPage) => { + return getFilteredEntries().slice( + (currentPage - 1) * plotsPerPage, + currentPage * plotsPerPage, + ); + }; + + return ( +
+
+
+
+
+ {currentPage > 1 ? ( + + ) : ( +
Prev
+ )} +
+
+ Page {currentPage}/{totalPages()} +
+
+ {currentPage < totalPages() ? ( + + ) : ( +
Next
+ )} +
+
+
+ {displayBandSelector() ? ( + + ) : ( + "" + )} +
+
+
+ {getSlice(currentPage).map((indexedEntry, n) => ( +
showLightboxEntry(indexedEntry.index)} + > + {indexedEntry.plot} +
+ ))} +
+ {inLightbox ? ( +
+
+
+ {displayedEntry > 0 ? ( +
+
<<
+
+ ) : ( + "" + )} +
+
+
+ {plotEntries[displayedEntry].plot}
- { inLightbox ? -
-
-
- {displayedEntry > 0 ? -
-
<<
-
- : "" } -
-
-
- {plotEntries[displayedEntry].plot} -
-
-
- {displayedEntry < (plotEntries.length - 1) ? -
-
>>
-
- : "" } -
-
- : ""} +
+
+ {displayedEntry < plotEntries.length - 1 ? ( +
+
>>
+
+ ) : ( + "" + )} +
- ) - + ) : ( + "" + )} +
+ ); } diff --git a/app/_components/selectionDropdown.js b/app/_components/selectionDropdown.js index b77350a..2a512d8 100644 --- a/app/_components/selectionDropdown.js +++ b/app/_components/selectionDropdown.js @@ -1,30 +1,25 @@ -'use client' - - -import React from 'react' -import {useState} from 'react' - - -export default function SelectionDropdown({contents, title, initiallyOpen = false}) { - - const [showContents, setShowContents] = useState(initiallyOpen) - - - const toggle = () => { - setShowContents(!showContents) - } - - - return ( -
-
- {title} -
- {showContents ? - contents - : ""} -
- ) - +"use client"; + +import React from "react"; +import { useState } from "react"; + +export default function SelectionDropdown({ + contents, + title, + initiallyOpen = false, +}) { + const [showContents, setShowContents] = useState(initiallyOpen); + + const toggle = () => { + setShowContents(!showContents); + }; + + return ( +
+
+ {title} +
+ {showContents ? contents : ""} +
+ ); } - diff --git a/app/_lib/dataIdFuncs.js b/app/_lib/dataIdFuncs.js index 5f25101..49c1cb0 100644 --- a/app/_lib/dataIdFuncs.js +++ b/app/_lib/dataIdFuncs.js @@ -1,38 +1,39 @@ - export default function DataIdSortFunc(dataIdA, dataIdB) { + const bandsOrder = ["u", "g", "r", "i", "z", "y"]; - const bandsOrder = ['u', 'g', 'r', 'i', 'z', 'y'] - - if('tract' in dataIdA && 'tract' in dataIdB) { - const tract_comparison = dataIdA.tract - dataIdB.tract - if(tract_comparison != 0) { - return tract_comparison - } + if ("tract" in dataIdA && "tract" in dataIdB) { + const tract_comparison = dataIdA.tract - dataIdB.tract; + if (tract_comparison != 0) { + return tract_comparison; } + } - if('visit' in dataIdA && 'visit' in dataIdB) { - const visit_comparison = dataIdA.visit - dataIdB.visit - if(visit_comparison != 0) { - return visit_comparison - } + if ("visit" in dataIdA && "visit" in dataIdB) { + const visit_comparison = dataIdA.visit - dataIdB.visit; + if (visit_comparison != 0) { + return visit_comparison; } + } - if('band' in dataIdA && 'band' in dataIdB) { - const band_comparison = bandsOrder.indexOf(dataIdA.band) - bandsOrder.indexOf(dataIdB.band) - if(band_comparison != 0) { - return band_comparison - } + if ("band" in dataIdA && "band" in dataIdB) { + const band_comparison = + bandsOrder.indexOf(dataIdA.band) - bandsOrder.indexOf(dataIdB.band); + if (band_comparison != 0) { + return band_comparison; } - - if('physical_filter' in dataIdA && 'physical_filter' in dataIdB) { - const physical_filter_comparison = bandsOrder.indexOf(dataIdA.physical_filter[0]) - bandsOrder.indexOf(dataIdB.physical_filter[0]) - if(physical_filter_comparison != 0) { - return physical_filter_comparison - } + } + + if ("physical_filter" in dataIdA && "physical_filter" in dataIdB) { + const physical_filter_comparison = + bandsOrder.indexOf(dataIdA.physical_filter[0]) - + bandsOrder.indexOf(dataIdB.physical_filter[0]); + if (physical_filter_comparison != 0) { + return physical_filter_comparison; } + } - /* if none of these dimensions are available */ - return 0 + /* if none of these dimensions are available */ + return 0; } -export { DataIdSortFunc } +export { DataIdSortFunc }; diff --git a/app/_lib/summaries.js b/app/_lib/summaries.js index 01e34a3..f553ab8 100644 --- a/app/_lib/summaries.js +++ b/app/_lib/summaries.js @@ -1,12 +1,13 @@ +import { + S3Client, + ListObjectsV2Command, + GetObjectCommand, +} from "@aws-sdk/client-s3"; +const fs = require("fs"); +const zlib = require("zlib"); -import { S3Client, ListObjectsV2Command, GetObjectCommand} from "@aws-sdk/client-s3" - -const fs = require('fs'); -const zlib = require('zlib'); - -const { readFile } = require("fs/promises") - +const { readFile } = require("fs/promises"); /* * This function defines which repo names are "special" such that users should be sent to the "More @@ -15,206 +16,213 @@ const { readFile } = require("fs/promises") * */ function GetCollectionListURLFromRepo(repoName) { + const moreRepos = ["decasu"]; - const moreRepos = ['decasu'] - - return moreRepos.includes(repoName) ? '/more' : '' - + return moreRepos.includes(repoName) ? "/more" : ""; } function GetButlerURL(repoName) { + const repoUrls = (() => { + try { + return JSON.parse(process.env.REPO_URLS); + } catch (err) { + console.error(`Could not parse REPO_URLS env var, ${err}`); + console.error(`REPO_URLS='${process.env.REPO_URLS}'`); + return {}; + } + })(); - const repoUrls = (() => { - try { - return JSON.parse(process.env.REPO_URLS) - } catch (err) { - console.error(`Could not parse REPO_URLS env var, ${err}`) - console.error(`REPO_URLS='${process.env.REPO_URLS}'`) - return {} - } - })() - - return repoUrls[repoName] - + return repoUrls[repoName]; } function GetClient() { - - const client = new S3Client({ - endpoint: process.env.BUCKET_URL, - region: "s3dfrgw", - forcePathStyle: true, - credentials: { - accessKeyId: process.env.S3_KEY, - secretAccessKey: process.env.S3_SECRET, - }, - }) - - return client + const client = new S3Client({ + endpoint: process.env.BUCKET_URL, + region: "s3dfrgw", + forcePathStyle: true, + credentials: { + accessKeyId: process.env.S3_KEY, + secretAccessKey: process.env.S3_SECRET, + }, + }); + + return client; } async function _GetSummaryS3(repoName, collectionName) { - - const client = GetClient() - const command = new GetObjectCommand({ - Bucket: process.env.BUCKET_NAME, - Key: `${encodeURIComponent(repoName)}/collection_${encodeURIComponent(collectionName)}.json.gz` - }) - - try { - const response = await client.send(command) - const gzData = await response.Body.transformToByteArray() - const collectionData = JSON.parse(zlib.gunzipSync(gzData)) - return collectionData - - } catch (err) { - console.error(err) - return {} - } - + const client = GetClient(); + const command = new GetObjectCommand({ + Bucket: process.env.BUCKET_NAME, + Key: `${encodeURIComponent(repoName)}/collection_${encodeURIComponent(collectionName)}.json.gz`, + }); + + try { + const response = await client.send(command); + const gzData = await response.Body.transformToByteArray(); + const collectionData = JSON.parse(zlib.gunzipSync(gzData)); + return collectionData; + } catch (err) { + console.error(err); + return {}; + } } async function GetSummary(repoName, collectionName) { - - if(!process.env.ENABLE_TEST_IMAGES) { - return await _GetSummaryS3(repoName, collectionName) - - } else { - const gzData = await readFile(`test_assets/summaries/${encodeURIComponent(repoName)}/collection_${encodeURIComponent(collectionName)}.json.gz`) - const collectionData = JSON.parse(zlib.gunzipSync(gzData)) - return collectionData - } - + if (!process.env.ENABLE_TEST_IMAGES) { + return await _GetSummaryS3(repoName, collectionName); + } else { + const gzData = await readFile( + `test_assets/summaries/${encodeURIComponent(repoName)}/collection_${encodeURIComponent(collectionName)}.json.gz`, + ); + const collectionData = JSON.parse(zlib.gunzipSync(gzData)); + return collectionData; + } } async function _ListSummariesS3(repoName) { - - const client = GetClient() - const command = new ListObjectsV2Command({ - Bucket: process.env.BUCKET_NAME, - Prefix: `${encodeURIComponent(repoName)}/`, - }); - - try { - let isTruncated = true; - - let filenameArrays = [] - - while (isTruncated) { - const { Contents, IsTruncated, NextContinuationToken } = - await client.send(command) - if(Contents) { - filenameArrays.push(Contents) - } - isTruncated = IsTruncated - command.input.ContinuationToken = NextContinuationToken - } - return filenameArrays.flat() - } catch (err) { - console.log(err) - return [] + const client = GetClient(); + const command = new ListObjectsV2Command({ + Bucket: process.env.BUCKET_NAME, + Prefix: `${encodeURIComponent(repoName)}/`, + }); + + try { + let isTruncated = true; + + let filenameArrays = []; + + while (isTruncated) { + const { Contents, IsTruncated, NextContinuationToken } = + await client.send(command); + if (Contents) { + filenameArrays.push(Contents); + } + isTruncated = IsTruncated; + command.input.ContinuationToken = NextContinuationToken; } - + return filenameArrays.flat(); + } catch (err) { + console.log(err); + return []; + } } async function _ListSummariesFilesystem(repoName) { - const repoDir = `test_assets/summaries/${encodeURIComponent(repoName)}` - try { - console.log(fs.readdirSync(repoDir)) - return fs.readdirSync(repoDir).filter( - (filename) => filename.match("^collection_(.*).json.gz$")); - } catch (error) { - return [] - } + const repoDir = `test_assets/summaries/${encodeURIComponent(repoName)}`; + try { + console.log(fs.readdirSync(repoDir)); + return fs + .readdirSync(repoDir) + .filter((filename) => filename.match("^collection_(.*).json.gz$")); + } catch (error) { + return []; + } } async function ListSummaries(repo) { + const decodeFilename = (filename) => { + const uriEncodedCollection = filename.match("collection_(.*).json.gz")[1]; + return decodeURIComponent(uriEncodedCollection); + }; - const decodeFilename = (filename) => { - const uriEncodedCollection = filename.match("collection_(.*).json.gz")[1] - return decodeURIComponent(uriEncodedCollection) - } - - const repoUrls = (() => { - try { - return JSON.parse(process.env.REPO_URLS) - } catch (err) { - console.error(`Could not parse REPO_URLS env var, ${err}`) - console.error(`REPO_URLS='${process.env.REPO_URLS}'`) - return {} - } - })() - - const repos = repo ? [repo] : Object.keys(repoUrls) - - if(!process.env.ENABLE_TEST_IMAGES) { - const res = await Promise.all(repos.map(repo => - { - return _ListSummariesS3(repo).then((entries) => entries.map(entry => ({repo: repo, collection: decodeFilename(entry.Key), filename: entry.Key, lastModified: entry.LastModified}))) - })) - return res.flat() - } else { - const res = await Promise.all( - repos.map(repo => _ListSummariesFilesystem(repo) - .then((filenames) => filenames.map(filename => ({repo: repo, collection: decodeFilename(filename), filename: filename, - lastModified: new Date(2025, 2, 10, 2, 30)})))) - ) - return res.flat() + const repoUrls = (() => { + try { + return JSON.parse(process.env.REPO_URLS); + } catch (err) { + console.error(`Could not parse REPO_URLS env var, ${err}`); + console.error(`REPO_URLS='${process.env.REPO_URLS}'`); + return {}; } - + })(); + + const repos = repo ? [repo] : Object.keys(repoUrls); + + if (!process.env.ENABLE_TEST_IMAGES) { + const res = await Promise.all( + repos.map((repo) => { + return _ListSummariesS3(repo).then((entries) => + entries.map((entry) => ({ + repo: repo, + collection: decodeFilename(entry.Key), + filename: entry.Key, + lastModified: entry.LastModified, + })), + ); + }), + ); + return res.flat(); + } else { + const res = await Promise.all( + repos.map((repo) => + _ListSummariesFilesystem(repo).then((filenames) => + filenames.map((filename) => ({ + repo: repo, + collection: decodeFilename(filename), + filename: filename, + lastModified: new Date(2025, 2, 10, 2, 30), + })), + ), + ), + ); + return res.flat(); + } } async function ListReports() { - return [] + return []; - const client = GetClient() + const client = GetClient(); - const command = new ListObjectsV2Command({ - Bucket: process.env.BUCKET_NAME, - Prefix: `reports/` - }); + const command = new ListObjectsV2Command({ + Bucket: process.env.BUCKET_NAME, + Prefix: `reports/`, + }); - try { - let isTruncated = true; - - let filenameArrays = [] - - while (isTruncated) { - const { Contents, IsTruncated, NextContinuationToken } = - await client.send(command) - if(Contents) { - filenameArrays.push(Contents.map((entry) => entry.Key)) - } - isTruncated = IsTruncated - command.input.ContinuationToken = NextContinuationToken - } - return filenameArrays.flat() - } catch (err) { - console.log(err) - return [] - } - -} - -async function GetReport(filename) { + try { + let isTruncated = true; - const client = GetClient() - const command = new GetObjectCommand({ - Bucket: process.env.BUCKET_NAME, - Key: `reports/${filename}` - }) + let filenameArrays = []; - try { - const response = await client.send(command) - const gzData = await response.Body.transformToByteArray() - const collectionData = JSON.parse(zlib.gunzipSync(gzData)) - return collectionData - - } catch (err) { - console.error(err) - return {} + while (isTruncated) { + const { Contents, IsTruncated, NextContinuationToken } = + await client.send(command); + if (Contents) { + filenameArrays.push(Contents.map((entry) => entry.Key)); + } + isTruncated = IsTruncated; + command.input.ContinuationToken = NextContinuationToken; } + return filenameArrays.flat(); + } catch (err) { + console.log(err); + return []; + } +} +async function GetReport(filename) { + const client = GetClient(); + const command = new GetObjectCommand({ + Bucket: process.env.BUCKET_NAME, + Key: `reports/${filename}`, + }); + + try { + const response = await client.send(command); + const gzData = await response.Body.transformToByteArray(); + const collectionData = JSON.parse(zlib.gunzipSync(gzData)); + return collectionData; + } catch (err) { + console.error(err); + return {}; + } } -export {GetCollectionListURLFromRepo, ListSummaries, GetSummary, ListReports, GetReport, GetButlerURL, GetClient} +export { + GetCollectionListURLFromRepo, + ListSummaries, + GetSummary, + ListReports, + GetReport, + GetButlerURL, + GetClient, +}; From 8890ab672bb5ddaf2ca61bfa8adbfe758714c16a Mon Sep 17 00:00:00 2001 From: Colin Slater Date: Fri, 26 Sep 2025 14:00:40 -0700 Subject: [PATCH 2/5] Ignore formatting commit. --- app/.git-blame-ignore-revs | 1 + 1 file changed, 1 insertion(+) create mode 100644 app/.git-blame-ignore-revs diff --git a/app/.git-blame-ignore-revs b/app/.git-blame-ignore-revs new file mode 100644 index 0000000..d5ca552 --- /dev/null +++ b/app/.git-blame-ignore-revs @@ -0,0 +1 @@ +3f2b7554ef907c54007dd51392968fd396b8f972 From 009df9a17cd466aaf9c4eb2a910ecae5121f1361 Mon Sep 17 00:00:00 2001 From: Colin Slater Date: Fri, 26 Sep 2025 14:01:30 -0700 Subject: [PATCH 3/5] Fix react key in pager. --- app/_components/plotPager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/_components/plotPager.js b/app/_components/plotPager.js index a931812..3934d71 100644 --- a/app/_components/plotPager.js +++ b/app/_components/plotPager.js @@ -147,7 +147,7 @@ export default function PlotPager({ plotEntries, plotsPerPage = 10 }) {
{getSlice(currentPage).map((indexedEntry, n) => (
showLightboxEntry(indexedEntry.index)} > From 15649d68b5ff17ff53af6907072bba02c950fbcd Mon Sep 17 00:00:00 2001 From: Colin Slater Date: Sat, 27 Sep 2025 20:23:57 -0700 Subject: [PATCH 4/5] Add input box for page number. --- app/_components/plotPager.js | 16 +++++++++++++--- app/_lib/summaries.js | 1 - 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app/_components/plotPager.js b/app/_components/plotPager.js index 3934d71..b1021b2 100644 --- a/app/_components/plotPager.js +++ b/app/_components/plotPager.js @@ -57,13 +57,13 @@ export default function PlotPager({ plotEntries, plotsPerPage = 10 }) { const previousPage = () => { if (currentPage > 1) { - setCurrentPage(currentPage - 1); + setCurrentPage(Number(currentPage) - 1); } }; const nextPage = () => { if (currentPage < totalPages()) { - setCurrentPage(currentPage + 1); + setCurrentPage(Number(currentPage) + 1); } }; @@ -118,7 +118,14 @@ export default function PlotPager({ plotEntries, plotsPerPage = 10 }) { )}
- Page {currentPage}/{totalPages()} + Page + setCurrentPage(e.target.value)} + /> + /{totalPages()}
{currentPage < totalPages() ? ( @@ -145,6 +152,9 @@ export default function PlotPager({ plotEntries, plotsPerPage = 10 }) {
+ {currentPage >= 1 && currentPage <= totalPages() + ? "" + : "Invalid page number"} {getSlice(currentPage).map((indexedEntry, n) => (
filename.match("^collection_(.*).json.gz$")); From 6fb6e72789c6ce577db2685e84b8e44dc57a49d1 Mon Sep 17 00:00:00 2001 From: Colin Slater Date: Sat, 27 Sep 2025 21:00:36 -0700 Subject: [PATCH 5/5] Show only filtered entries in lightbox. --- app/_components/plotPager.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/app/_components/plotPager.js b/app/_components/plotPager.js index b1021b2..77e2396 100644 --- a/app/_components/plotPager.js +++ b/app/_components/plotPager.js @@ -19,16 +19,17 @@ export default function PlotPager({ plotEntries, plotsPerPage = 10 }) { const [displayedEntry, setDisplayedEntry] = useState(0); const getFilteredEntries = () => { - const indexedEntries = plotEntries.map((entry, n) => ({ - dataId: entry.dataId, - plot: entry.plot, - index: n, - })); - return indexedEntries.filter( - (indexedEntry) => - selectedBands[indexedEntry.dataId.band] || - !("band" in indexedEntry.dataId), - ); + return plotEntries + .filter( + (indexedEntry) => + selectedBands[indexedEntry.dataId.band] || + !("band" in indexedEntry.dataId), + ) + .map((entry, n) => ({ + dataId: entry.dataId, + plot: entry.plot, + index: n, + })); }; const totalPages = () => { @@ -88,7 +89,7 @@ export default function PlotPager({ plotEntries, plotsPerPage = 10 }) { const advanceRight = (e) => { e.stopPropagation(); - if (displayedEntry < plotEntries.length - 1) { + if (displayedEntry < getFilteredEntries().length - 1) { setDisplayedEntry(displayedEntry + 1); } }; @@ -185,7 +186,7 @@ export default function PlotPager({ plotEntries, plotsPerPage = 10 }) {
- {plotEntries[displayedEntry].plot} + {getFilteredEntries()[displayedEntry].plot}