diff --git a/package-lock.json b/package-lock.json index 63e3623..f12d84e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,8 @@ "dependencies": { "@mui/icons-material": "^5.14.14", "@mui/material": "^5.14.14", + "@types/date-fns": "^2.6.0", + "date-fns": "^2.30.0", "mapbox-gl": "^2.15.0", "next": "13.5.4", "react": "^18", @@ -1148,6 +1150,15 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/date-fns": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@types/date-fns/-/date-fns-2.6.0.tgz", + "integrity": "sha512-9DSw2ZRzV0Tmpa6PHHJbMcZn79HHus+BBBohcOaDzkK/G3zMjDUDYjJIWBFLbkh+1+/IOS0A59BpQfdr37hASg==", + "deprecated": "This is a stub types definition for date-fns (https://github.com/date-fns/date-fns). date-fns provides its own type definitions, so you don't need @types/date-fns installed!", + "dependencies": { + "date-fns": "*" + } + }, "node_modules/@types/geojson": { "version": "7946.0.12", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.12.tgz", @@ -1982,6 +1993,21 @@ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", diff --git a/package.json b/package.json index 670b390..a14aa31 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,8 @@ "dependencies": { "@mui/icons-material": "^5.14.14", "@mui/material": "^5.14.14", + "@types/date-fns": "^2.6.0", + "date-fns": "^2.30.0", "mapbox-gl": "^2.15.0", "next": "13.5.4", "react": "^18", diff --git a/src/app/components/Markers.tsx b/src/app/components/Markers.tsx index a444191..a202528 100644 --- a/src/app/components/Markers.tsx +++ b/src/app/components/Markers.tsx @@ -1,7 +1,7 @@ import React, { useMemo, useState, useEffect } from "react"; import { Marker } from "react-map-gl"; import { School } from "@mui/icons-material"; -import { Feature } from "../../../types/mapTypes"; +import { Feature, TypedFeatures } from "../../../types/mapTypes"; import Features from "../../../public/features.json"; import { getFacilityEsData } from "@/app/institutions/elasticQuery.js"; @@ -33,7 +33,7 @@ const Markers: React.FC = ({ onMarkerClick }) => { return null; } - const typedFeature: Feature = { + const typedFeature: TypedFeatures = { type: feature.type, properties: { "Institution Name": institutionName, @@ -46,7 +46,8 @@ const Markers: React.FC = ({ onMarkerClick }) => { feature.geometry.coordinates[1] ] as [number, number] }, - id: feature.id + id: feature.id, + dataState: esInfo.gpuProvided > 0 ? true : false }; return ( diff --git a/src/app/components/MarkersComponent.tsx b/src/app/components/MarkersComponent.tsx index 717ab9f..85a6e1b 100644 --- a/src/app/components/MarkersComponent.tsx +++ b/src/app/components/MarkersComponent.tsx @@ -1,17 +1,17 @@ import React, { useState } from "react"; -import { Feature } from "../../../types/mapTypes"; +import { Feature, TypedFeatures } from "../../../types/mapTypes"; import Sidebar from "./Sidebar"; import Markers from "./Markers"; - const MarkersComponent: React.FC = () => { - const [selectedMarker, setSelectedMarker] = useState(null); + const [selectedMarker, setSelectedMarker] = useState(null); const [facultyName, setFacultyName] = useState(""); const handleMarkerClick = (feature: Feature) => { setSelectedMarker(feature); convertName(feature); }; + const convertName = (feature: Feature) => { const originalName = feature.properties["Institution Name"]; const convertedName = originalName.replace(/\s+/g, '+'); @@ -25,7 +25,7 @@ const MarkersComponent: React.FC = () => { return ( <> - {selectedMarker && } + {selectedMarker && } ); }; diff --git a/src/app/components/Sidebar.tsx b/src/app/components/Sidebar.tsx index 0f7c83b..1f7d844 100644 --- a/src/app/components/Sidebar.tsx +++ b/src/app/components/Sidebar.tsx @@ -1,12 +1,14 @@ import React from 'react'; -import { Box, Grid, IconButton, Typography, useMediaQuery } from '@mui/material'; +import { Box, IconButton, Typography, useMediaQuery } from '@mui/material'; import { Close as CloseIcon } from '@mui/icons-material'; import useTheme from '@mui/material/styles/useTheme'; +import { sub } from 'date-fns'; type SidebarProps = { onClose: () => void; header: string; facultyName: string; + dataState?: boolean; } type HTMLContentProps = { html: string; @@ -40,15 +42,15 @@ const GrafanaPanel: React.FC = ({ panelId, panelUrl, start, e ); } -const Sidebar: React.FC = ({ onClose, header, facultyName }) => { +const Sidebar: React.FC = ({ onClose, header, facultyName, dataState}) => { const theme = useTheme(); const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm')); const data = { panelId:[12, 16, 8, 6, 2], - panelUrl: `https://gracc.opensciencegrid.org/d-solo/hfZQzo2Vk/ospool-facility`, - start: 1667402917814, - end: 1698938917814, + panelUrl: `https://gracc.opensciencegrid.org/d-solo/axV4YtN4k/facility`, + start: sub(new Date(), { years: 1 }).getTime(), + end: new Date().getTime(), orgId: 1 } return ( @@ -73,7 +75,7 @@ const Sidebar: React.FC = ({ onClose, header, facultyName }) => { - = ({ onClose, header, facultyName }) => { /> + { dataState ? = ({ onClose, header, facultyName }) => { end={data.end} orgId={data.orgId} facultyName={facultyName} - /> + /> : undefined + } ); diff --git a/src/app/institutions/elasticQuery.js b/src/app/institutions/elasticQuery.js index 1d5f52f..90b122c 100644 --- a/src/app/institutions/elasticQuery.js +++ b/src/app/institutions/elasticQuery.js @@ -3,13 +3,14 @@ * * This endpoint uses Elasticsearch */ +import { subYears, subMonths } from 'date-fns'; const SUMMARY_INDEX = "gracc.osg.summary" const ENDPOINT = "https://gracc.opensciencegrid.org/q" const DEBUG=true const DATE_RANGE = { - oneYearAgo: new Date(new Date().setDate(new Date().getDate()-365)).getTime(), // Gets last years timestamp - threeMonthsAgo: new Date(new Date().setDate(new Date().getDate()-90)).getTime(), // Gets date object 90 days in advance + oneYearAgo: subYears(new Date(), 1).getTime(), + threeMonthsAgo: subMonths(new Date(), 3).getTime(), now: new Date().getTime() } diff --git a/src/app/institutions/facilityData.js b/src/app/institutions/facilityData.js deleted file mode 100644 index 3e4fc2f..0000000 --- a/src/app/institutions/facilityData.js +++ /dev/null @@ -1,62 +0,0 @@ -async function getFacilityEsData(ospoolOnly = false){ - - let es = new ElasticSearchQuery(SUMMARY_INDEX, ENDPOINT) - - // Query ES and ask for Sites that have provided resources in the last year - let response = await es.search({ - "size": 0, - "query": { - "bool": { - "filter": [ - {"term": {"ResourceType": "Payload"}}, - {"range": {"EndTime": {"lte": DATE_RANGE['now'], "gte": DATE_RANGE['oneYearAgo']}}}, - ...(ospoolOnly ? [OSPOOL_FILTER] : []) // Cryptic but much cleaner - ], - "must_not": [ - { "term" : {"ProjectName" : "GLOW"} }, - ] - } - }, - "aggs": { - "fieldsOfScience": { "cardinality": { "field": "OIM_FieldOfScience" }, }, - "jobsRan": { "sum": { "field": "Count" } }, - "projects": { "cardinality": { "field": "ProjectName" } }, - "facilities": { - "terms": { - "field": "OIM_Facility", "size": 99999999 - }, - "aggs": { - "facilityCpuProvided": {"sum": {"field": "CoreHours"}}, - "facilityJobsRan": {"sum": {"field": "Count"}}, - "facilityGpuProvided": {"sum": {"field": "GPUHours"}}, - "countProjectsImpacted": {"cardinality": {"field": "ProjectName"}}, - "countFieldsOfScienceImpacted": {"cardinality": {"field": "OIM_FieldOfScience"}}, - "countOrganizationImpacted": {"cardinality": {"field": "OIM_Organization"}}, - "gpu_bucket_filter": { - "bucket_selector": { - "buckets_path": {"totalGPU": "facilityGpuProvided", "totalCPU": "facilityCpuProvided"}, - "script": "params.totalGPU > 0 || params.totalCPU > 0" - } - } - } - } - } - }) - - // Decompose this data into information we want, if they provided GPU or CPU - let facilityBuckets = response.aggregations.facilities.buckets - let facilityData = facilityBuckets.reduce((p, v) => { - p[v['key']] = { - name: v['key'], - jobsRan: v['facilityJobsRan']['value'], - cpuProvided: v['facilityCpuProvided']['value'], - gpuProvided: v['facilityGpuProvided']['value'], - numProjects: v['countProjectsImpacted']['value'], - numFieldsOfScience: v['countFieldsOfScienceImpacted']['value'], - numOrganizations: v['countOrganizationImpacted']['value'], - } - return p - }, {}) - console.log(facilityData) - return facilityData -} \ No newline at end of file diff --git a/types/mapTypes.ts b/types/mapTypes.ts index 6774199..d1b5bf2 100644 --- a/types/mapTypes.ts +++ b/types/mapTypes.ts @@ -18,4 +18,7 @@ export type Geometry = { export type FeaturesType = { features: Feature[]; }; - \ No newline at end of file + + export type TypedFeatures = Feature & { + dataState?: boolean; + } \ No newline at end of file