Skip to content

Commit

Permalink
Merge branch 'main' into 186924285-is-active-legend
Browse files Browse the repository at this point in the history
  • Loading branch information
eireland committed Jan 29, 2024
2 parents ad1e49e + 23a9739 commit 94ddbb1
Show file tree
Hide file tree
Showing 11 changed files with 219 additions and 167 deletions.
2 changes: 1 addition & 1 deletion src/components/App.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.App {
padding: 12px;
box-sizing: content-box;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
Expand Down
14 changes: 3 additions & 11 deletions src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { adjustStationDataset, getWeatherStations } from "../utils/getWeatherSta
import { addNotificationHandler, createStationsDataset, guaranteeGlobal } from "../utils/codapHelpers";
import InfoIcon from "../assets/images/icon-info.svg";
import { useCODAPApi } from "../hooks/use-codap-api";
import { dataTypeStore } from "../utils/noaaDataTypes";
import { composeURL, formatData } from "../utils/noaaApiHelper";
import { IDataType } from "../types";

Check warning on line 14 in src/components/App.tsx

View workflow job for this annotation

GitHub Actions / Build & Run Tests

'IDataType' is defined but never used

Check warning on line 14 in src/components/App.tsx

View workflow job for this annotation

GitHub Actions / Build & Run Tests

'IDataType' is defined but never used

Check warning on line 14 in src/components/App.tsx

View workflow job for this annotation

GitHub Actions / Build & Run Tests

'IDataType' is defined but never used

Check warning on line 14 in src/components/App.tsx

View workflow job for this annotation

GitHub Actions / S3 Deploy

'IDataType' is defined but never used

Check warning on line 14 in src/components/App.tsx

View workflow job for this annotation

GitHub Actions / S3 Deploy

'IDataType' is defined but never used
import { StationDSName, globalMaxDate, globalMinDate } from "../constants";
Expand All @@ -23,7 +22,7 @@ const kPluginName = "NOAA Weather Station Data";
const kVersion = "0014";
const kInitialDimensions = {
width: 360,
height: 650
height: 670
};

export const App = () => {
Expand All @@ -49,6 +48,7 @@ export const App = () => {
draft.weatherStation = station;
draft.location = {name: locationName, latitude, longitude};
draft.weatherStationDistance = 0;
draft.zoomMap = false;
});
}
}
Expand Down Expand Up @@ -76,14 +76,6 @@ export const App = () => {
});
};

const getSelectedDataTypes = () => {
const { selectedFrequency } = state;
const attributes = state.frequencies[selectedFrequency].attrs.map(attr => attr.name);
return attributes.map((attr) => {
return dataTypeStore.findByName(attr);
}) as IDataType[];
};

const fetchSuccessHandler = async (data: any) => {
const {startDate, endDate, units, selectedFrequency,
weatherStation, timezone} = state;
Expand All @@ -104,7 +96,7 @@ export const App = () => {
const items = Array.isArray(dataRecords) ? dataRecords : [dataRecords];
const filteredItems = filterItems(items);
setStatusMessage("Sending weather records to CODAP");
await createNOAAItems(filteredItems, getSelectedDataTypes()).then(
await createNOAAItems(filteredItems).then(
function (result: any) {
setIsFetching(false);
setStatusMessage(`Retrieved ${filteredItems.length} cases`);
Expand Down
8 changes: 6 additions & 2 deletions src/components/attribute-filter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,13 @@ const FilterModal = ({attr, position, targetFilterBottom, setShowFilterModal, se
} else if (operator === "aboveMean" || operator === "belowMean") {
return null;
} else if (operator === "top" || operator === "bottom") {
return <input ref={filterValueTopBottomInputElRef} key={`${operator}-${units}`} className="filter-value" defaultValue={`${currentFilterValue || "100"}`}></input>;
return <input ref={filterValueTopBottomInputElRef} key={`${operator}-${units}`} className="filter-value"
defaultValue={`${Array.isArray(currentFilterValue) ? currentFilterValue[0] : "100"}`}>
</input>;
} else {
return <input ref={filterValueInputElRef} key={`${operator}-${units}`} className="filter-value" defaultValue={`${currentFilterValue} ${currentAttr?.unit[units]}`}></input>;
return <input ref={filterValueInputElRef} key={`${operator}-${units}`} className="filter-value"
defaultValue={`${Array.isArray(currentFilterValue) ? currentFilterValue[0] : "100"} ${currentAttr?.unit[units]}`}>
</input>;
}
};

Expand Down
4 changes: 2 additions & 2 deletions src/components/attribute-selector.scss
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@
}
}

.attribute-selection{
.attribute-selection {
display: flex;
flex-wrap: wrap;
margin: 8px 0 11px 0;
margin: 8px 12px 11px 12px;

.attribute-button {
display: flex;
Expand Down
37 changes: 28 additions & 9 deletions src/components/date-range/calendars.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
import React from "react";
import "./calendars.scss";
import React, { useEffect, useState } from "react";
import { Calendar } from "./calendar";
import { useStateContext } from "../../hooks/use-state";

import "./calendars.scss";

interface ICalendarsProps {
selectedCalendar: string | undefined;
handleSelectCalendar: (calendar: string) => void;
closeCalendars: () => void;
}

export const Calendars = ({selectedCalendar, handleSelectCalendar, closeCalendars}: ICalendarsProps) => {
const {state} = useStateContext();
const {weatherStation} = state;
const { state } = useStateContext();
const { weatherStation } = state;
const [activeDates, setActiveDates] = useState<{from: string, to: string}>({from: "", to: ""});

useEffect(() => {
if (weatherStation) {
const {mindate, maxdate} = weatherStation; //"1973-01-01"
const formatDate = (date: string) => {
const [year, month, day] = date.split("-");
return `${month}/${day}/${year}`;
};
const from = formatDate(mindate);
const to = maxdate === "present" ? "present" : formatDate(maxdate);
setActiveDates({from, to});
}
}, [weatherStation]);

return (
<div className="modal">
Expand All @@ -24,12 +39,16 @@ export const Calendars = ({selectedCalendar, handleSelectCalendar, closeCalendar
</div>
</div>
<div className="calendar-footer">
<div className="station-information">
<div className="station-name">{weatherStation?.name || "WEATHER STATION"}</div>
<div className="station-dates">
<span>MM/DD/YYYY</span> - <span>MM/DD/YYYY</span>
<div className="station-information">
{ weatherStation &&
<>
<div className="station-name">{weatherStation?.name || "WEATHER STATION"}</div>
<div className="station-dates">
<span>{activeDates.from}</span> - <span>{activeDates.to}</span>
</div>
</>
}
</div>
</div>
<button className="close-calendar" onClick={closeCalendars}>Done</button>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/date-range/date-range.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
.date-range-container {
height: 73px;
padding: 8px 0px;
width:s $inner-container-width;
width: $inner-container-width;
background-color: #fff;

.date-range-header {
Expand Down
143 changes: 90 additions & 53 deletions src/hooks/use-codap-api.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,76 @@
import { Attribute, Collection, DataContext, IDataType, IItem } from "../types";
import { IResult, codapInterface, createItems, getDataContext } from "@concord-consortium/codap-plugin-api";
import { DSCollection1, DSCollection2, DSName, kStationsDatasetName } from "../constants";
import { useEffect, useState } from "react";
import { useStateContext } from "./use-state";
import { useEffect } from "react";
import { createMap, selectStations } from "../utils/codapHelpers";
import { Attribute, Collection, DataContext, ICODAPItem, IDataType, IItem } from "../types";
import { IResult, codapInterface, createItems, getAllItems, getDataContext } from "@concord-consortium/codap-plugin-api";
import { DSCollection1, DSCollection2, DSName, kStationsCollectionName } from "../constants";
import { clearData, createMap, selectStations } from "../utils/codapHelpers";
import { dataTypeStore } from "../utils/noaaDataTypes";

export const useCODAPApi = () => {
const {state} = useStateContext();
const [ selectedDataTypes, setSelectedDataTypes ] = useState<IDataType[]>([]);
const { frequencies, selectedFrequency, weatherStation, units, isMapOpen, zoomMap } = state;
const { attrs } = frequencies[selectedFrequency];

useEffect(() => {
if (state.weatherStation && state.isMapOpen) {
const zoom = state.zoomMap ? 7 : null;
createMap(kStationsDatasetName, {width: 500, height: 350}, [state.weatherStation.latitude, state.weatherStation.longitude], zoom);
selectStations([state.weatherStation.name]);
if (weatherStation && isMapOpen) {
const zoom = zoomMap ? 7 : null;
createMap(kStationsCollectionName, {width: 500, height: 350}, [weatherStation.latitude, weatherStation.longitude], zoom);
selectStations([weatherStation.name]);
}
}, [state.isMapOpen, state.weatherStation, state.zoomMap]);
}, [isMapOpen, weatherStation, zoomMap]);

useEffect(() => {
const attributes = frequencies[selectedFrequency].attrs.map(attr => attr.name);
const dataTypes = attributes.map((attr) => {
return dataTypeStore.findByName(attr);
}) as IDataType[];
setSelectedDataTypes(dataTypes);
}, [selectedFrequency, frequencies, attrs]);

const createNOAAItems = async (items: IItem[]) => {
await updateWeatherDataset(selectedDataTypes);
// eslint-disable-next-line no-console
console.log("noaa-cdo ... createNOAAItems with " + items.length + " case(s)");
await createItems(DSName, items);
await codapInterface.sendRequest({
"action": "create",
"resource": "component",
"values": {
"type": "caseTable",
"dataContext": DSName,
"horizontalScrollOffset": 500
}
});
};

useEffect(() => {
const updateUnitsInCODAP = async () => {
let doesDataCtxExist = await getDataContext(DSName);
if (!doesDataCtxExist || !doesDataCtxExist.success) {
return;
}
const oldUnits = units === "metric" ? "standard" : "metric";
// fetch existing items in existing dataset
let allItemsRes = await getAllItems(DSName);
let allItems = allItemsRes.values.map((item: {id: string, values: ICODAPItem}) => item.values);
// convert from old units to new units
allItems.forEach(function (item: ICODAPItem) {
Object.keys(item).forEach(function (attrName) {
let dataType = dataTypeStore.findByAbbr(attrName);
if (dataType && dataType.convertUnits) {
item[attrName] = dataType.convertUnits(dataType.units[oldUnits], dataType.units[units], item[attrName]);
}
});
});
// clear dataset
await clearData(DSName);
// insert items
await createNOAAItems(allItems);
};
updateUnitsInCODAP();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [units]);

const getNoaaDataContextSetupObject = () => {
return {
Expand Down Expand Up @@ -69,14 +125,13 @@ export const useCODAPApi = () => {
};

const createAttribute = (datasetName: string, collectionName: string, dataType: IDataType) => {
const {units} = state;
return codapInterface.sendRequest({
action: "create",
resource: "dataContext[" + datasetName + "].collection[" + collectionName + "].attribute",
values: {
name: dataType.name,
unit: dataType.units[units],
description: dataType.description
action: "create",
resource: "dataContext[" + datasetName + "].collection[" + collectionName + "].attribute",
values: {
name: dataType.name,
unit: dataType.units[units],
description: dataType.description
}
});
};
Expand All @@ -101,7 +156,6 @@ export const useCODAPApi = () => {
};

const updateWeatherDataset = async (dataTypes: IDataType[]) => {
const {units} = state;
let result = await getDataContext(DSName);

if (!result || !result.success) {
Expand All @@ -123,34 +177,33 @@ export const useCODAPApi = () => {
const attrDefs: Attribute[] = [];

dataSetDef.collections.forEach(function (collection: Collection) {
collection.attrs.forEach(function (attr) {
attrDefs.push(attr);
});
collection.attrs.forEach(function (attr) {
attrDefs.push(attr);
});
});

const lastCollection = dataSetDef.collections[dataSetDef.collections.length - 1];
const promises = dataTypes.map(function (dataType) {
const attrName = dataType.name;
const attrDef = attrDefs.find(function (ad) {
return ad.name === attrName;
});
if (!attrDef) {
return createAttribute(DSName, lastCollection.name, dataType);
} else {
let unit = dataType.units[units];
if (attrDef.unit !== unit) {
return updateAttributeUnit(dataSetDef, attrName, unit);
} else {
return Promise.resolve("Unknown attribute.");
}
}
const attrName = dataType.name;
const attrDef = attrDefs.find(function (ad) {
return ad.name === attrName;
});
if (!attrDef) {
return createAttribute(DSName, lastCollection.name, dataType);
} else {
let unit = dataType.units[units];
if (attrDef.unit !== unit) {
return updateAttributeUnit(dataSetDef, attrName, unit);
} else {
return Promise.resolve("Unknown attribute.");
}
}
});
return Promise.all(promises);
};

const filterItems = (items: IItem[]) => {
const { selectedFrequency, frequencies } = state;
const { attrs, filters } = frequencies[selectedFrequency];
const { filters } = frequencies[selectedFrequency];
const filteredItems = items.filter((item: IItem) => {
const allFiltersMatch: boolean[] = [];
filters.forEach((filter) => {
Expand Down Expand Up @@ -192,22 +245,6 @@ export const useCODAPApi = () => {
return filteredItems;
};

const createNOAAItems = async (items: IItem[], dataTypes: IDataType[]) => {
await updateWeatherDataset(dataTypes);
// eslint-disable-next-line no-console
console.log("noaa-cdo ... createNOAAItems with " + items.length + " case(s)");
await createItems(DSName, items);
await codapInterface.sendRequest({
"action": "create",
"resource": "component",
"values": {
"type": "caseTable",
"dataContext": DSName,
"horizontalScrollOffset": 500
}
});
};

return {
filterItems,
createNOAAItems
Expand Down
4 changes: 4 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,3 +255,7 @@ export interface IRecord {
export interface IItem {
[key: string]: string;
}

export interface ICODAPItem {
[key: string]: any;
}
Loading

0 comments on commit 94ddbb1

Please sign in to comment.