From 3f96d74a5350bdb3cf5122f20602cceec11c4127 Mon Sep 17 00:00:00 2001 From: Brett Edwards Date: Wed, 11 Oct 2023 12:04:38 -0700 Subject: [PATCH] Decommission MoreCast 1 (#3155) - Removes all unused code from MoreCast (except maps) - Reroutes MoreCast to MoreCast 2.0 - Moves code that's still needed for other applications in the repo --- codecov.yml | 2 +- web/cypress/e2e/morecast-page.cy.ts | 454 ------ web/package.json | 2 - web/src/app/Routes.tsx | 17 +- web/src/app/rootReducer.ts | 38 - .../{fireWeather/pages => }/NoMatchPage.tsx | 0 web/src/features/fbaCalculator/RowManager.ts | 2 +- .../fbaCalculator/components/FBATable.tsx | 3 +- .../fbaCalculator/components/FBATableHead.tsx | 2 +- .../components/AccuracyColorLegend.tsx | 247 --- .../components/ExpandableContainer.tsx | 99 -- .../components/GetWxDataButton.tsx | 33 - .../components/NetworkErrorMessages.tsx | 84 - .../fireWeather/components/SidePanel.tsx | 76 - .../components/StationAccuracyForDate.tsx | 77 - .../components/TimeOfInterestPicker.tsx | 37 - .../fireWeather/components/WxDataDisplays.tsx | 291 ---- .../fireWeather/components/WxDataForm.tsx | 100 -- .../components/WxStationDropdown.tsx | 103 -- .../components/graphs/PrecipitationGraph.tsx | 139 -- .../components/graphs/TempRHGraph.tsx | 244 --- .../components/graphs/WindGraph.tsx | 180 --- .../components/graphs/WxDataGraph.tsx | 165 -- .../components/graphs/WxDataGraphToggles.tsx | 205 --- .../components/graphs/plotlyHelper.ts | 664 -------- .../components/graphs/useGraphToggles.ts | 27 - .../components/tables/ComparisonTableRow.tsx | 348 ---- .../components/tables/NoonForecastTable.tsx | 206 --- .../components/tables/NoonWxValueTables.tsx | 105 -- .../components/tables/ObservationTable.tsx | 95 -- .../tables/SortableTableByDatetime.tsx | 208 --- .../tables/StationComparisonTable.tsx | 210 --- .../fireWeather/pages/MoreCastPage.tsx | 226 --- .../slices/forecastSummariesSlice.ts | 61 - .../fireWeather/slices/forecastsSlice.ts | 92 -- .../slices/highResModelSummariesSlice.ts | 61 - .../fireWeather/slices/highResModelsSlice.ts | 70 - .../fireWeather/slices/modelSummariesSlice.ts | 60 - .../fireWeather/slices/modelsSlice.ts | 74 - .../fireWeather/slices/observationsSlice.ts | 63 - .../slices/parseModelValuesHelper.ts | 40 - .../slices/regionalModelSummariesSlice.ts | 61 - .../fireWeather/slices/regionalModelsSlice.ts | 69 - web/src/features/landingPage/toolInfo.tsx | 16 - web/src/utils/constants.ts | 4 +- web/src/utils/table.test.data.ts | 251 --- web/src/utils/table.test.ts | 134 -- web/src/utils/table.ts | 239 --- web/yarn.lock | 1423 +---------------- 49 files changed, 26 insertions(+), 7381 deletions(-) delete mode 100644 web/cypress/e2e/morecast-page.cy.ts rename web/src/features/{fireWeather/pages => }/NoMatchPage.tsx (100%) delete mode 100644 web/src/features/fireWeather/components/AccuracyColorLegend.tsx delete mode 100644 web/src/features/fireWeather/components/ExpandableContainer.tsx delete mode 100644 web/src/features/fireWeather/components/GetWxDataButton.tsx delete mode 100644 web/src/features/fireWeather/components/NetworkErrorMessages.tsx delete mode 100644 web/src/features/fireWeather/components/SidePanel.tsx delete mode 100644 web/src/features/fireWeather/components/StationAccuracyForDate.tsx delete mode 100644 web/src/features/fireWeather/components/TimeOfInterestPicker.tsx delete mode 100644 web/src/features/fireWeather/components/WxDataDisplays.tsx delete mode 100644 web/src/features/fireWeather/components/WxDataForm.tsx delete mode 100644 web/src/features/fireWeather/components/WxStationDropdown.tsx delete mode 100644 web/src/features/fireWeather/components/graphs/PrecipitationGraph.tsx delete mode 100644 web/src/features/fireWeather/components/graphs/TempRHGraph.tsx delete mode 100644 web/src/features/fireWeather/components/graphs/WindGraph.tsx delete mode 100644 web/src/features/fireWeather/components/graphs/WxDataGraph.tsx delete mode 100644 web/src/features/fireWeather/components/graphs/WxDataGraphToggles.tsx delete mode 100644 web/src/features/fireWeather/components/graphs/plotlyHelper.ts delete mode 100644 web/src/features/fireWeather/components/graphs/useGraphToggles.ts delete mode 100644 web/src/features/fireWeather/components/tables/ComparisonTableRow.tsx delete mode 100644 web/src/features/fireWeather/components/tables/NoonForecastTable.tsx delete mode 100644 web/src/features/fireWeather/components/tables/NoonWxValueTables.tsx delete mode 100644 web/src/features/fireWeather/components/tables/ObservationTable.tsx delete mode 100644 web/src/features/fireWeather/components/tables/SortableTableByDatetime.tsx delete mode 100644 web/src/features/fireWeather/components/tables/StationComparisonTable.tsx delete mode 100644 web/src/features/fireWeather/pages/MoreCastPage.tsx delete mode 100644 web/src/features/fireWeather/slices/forecastSummariesSlice.ts delete mode 100644 web/src/features/fireWeather/slices/forecastsSlice.ts delete mode 100644 web/src/features/fireWeather/slices/highResModelSummariesSlice.ts delete mode 100644 web/src/features/fireWeather/slices/highResModelsSlice.ts delete mode 100644 web/src/features/fireWeather/slices/modelSummariesSlice.ts delete mode 100644 web/src/features/fireWeather/slices/modelsSlice.ts delete mode 100644 web/src/features/fireWeather/slices/observationsSlice.ts delete mode 100644 web/src/features/fireWeather/slices/parseModelValuesHelper.ts delete mode 100644 web/src/features/fireWeather/slices/regionalModelSummariesSlice.ts delete mode 100644 web/src/features/fireWeather/slices/regionalModelsSlice.ts delete mode 100644 web/src/utils/table.test.data.ts delete mode 100644 web/src/utils/table.test.ts delete mode 100644 web/src/utils/table.ts diff --git a/codecov.yml b/codecov.yml index 8207eb5c0..8ef723599 100644 --- a/codecov.yml +++ b/codecov.yml @@ -34,4 +34,4 @@ coverage: paths: - web/src # web isn't quite amazing yet - would be nice to push it up to 80% - target: 80% + target: 75% diff --git a/web/cypress/e2e/morecast-page.cy.ts b/web/cypress/e2e/morecast-page.cy.ts deleted file mode 100644 index c097102c7..000000000 --- a/web/cypress/e2e/morecast-page.cy.ts +++ /dev/null @@ -1,454 +0,0 @@ -import { FIRE_WEATHER_ROUTE, FULL_WIDTH, MORECAST_ROUTE, PARTIAL_WIDTH } from '../../src/utils/constants' -import { stationCodeQueryKey, timeOfInterestQueryKey } from '../../src/utils/url' -const stationCode = 328 -const stationCode2 = 380 -const numOfObservations = 119 -const numOfForecasts = 6 - -const interceptData = () => { - cy.intercept('POST', 'api/observations/', { fixture: 'weather-data/observations' }) - cy.intercept('POST', 'api/forecasts/noon/', { fixture: 'weather-data/noon-forecasts' }) - cy.intercept('POST', 'api/forecasts/noon/summaries/', { fixture: 'weather-data/noon-forecast-summaries' }) - cy.intercept('POST', 'api/weather_models/GDPS/predictions/most_recent', {fixture:'weather-data/models-with-bias-adjusted'}) // prettier-ignore - cy.intercept('POST', 'api/weather_models/GDPS/predictions/summaries/', { - fixture: 'weather-data/model-summaries' - }) - cy.intercept('POST', 'api/weather_models/HRDPS/predictions/most_recent', {fixture:'weather-data/hr-models-with-bias-adjusted'}) // prettier-ignore - cy.intercept('POST', 'api/weather_models/HRDPS/predictions/summaries', {fixture:'weather-data/high-res-model-summaries'}) // prettier-ignore - cy.intercept('POST', 'api/weather_models/RDPS/predictions/most_recent', {fixture:'weather-data/regional-models-with-bias-adjusted'}) // prettier-ignore - cy.intercept('POST', 'api/weather_models/RDPS/predictions/summaries', { - fixture: 'weather-data/regional-model-summaries' - }) -} - -describe('MoreCast Page', () => { - beforeEach(() => { - cy.intercept('GET', 'api/stations/*', { fixture: 'weather-stations.json' }).as('getStations') - cy.intercept('GET', 'api/stations/details/*', { fixture: 'weather-stations-details.json' }).as('getStationsDetails') - }) - - it('Should redirect to /morecast when accessing /fire-weather', () => { - cy.visit(FIRE_WEATHER_ROUTE) - cy.url().should('contain', MORECAST_ROUTE) - }) - - it('Should display error messages when network errors occurred', () => { - cy.visit(MORECAST_ROUTE) - cy.intercept('POST', 'api/weather_models/RDPS/predictions/summaries').as('getRdpsSummaries') - cy.intercept('POST', 'api/weather_models/RDPS/predictions/most_recent/', { statusCode: 500 }).as('getRdps') - cy.intercept('POST', 'api/observations/', { statusCode: 500 }).as('getHourlyObservations') - cy.intercept('POST', 'api/forecasts/noon/', { statusCode: 500 }).as('getNoonForecasts') - cy.intercept('POST', 'api/forecasts/noon/summaries/', { statusCode: 500 }).as('getNoonForecastSummaries') - cy.intercept('POST', 'api/weather_models/HRDPS/predictions/most_recent/', { statusCode: 500 }).as('getHrdps') - cy.intercept('POST', 'api/weather_models/HRDPS/predictions/summaries/', { statusCode: 500 }).as('getHrdpsSummaries') - cy.intercept('POST', 'api/weather_models/GDPS/predictions/most_recent/', { statusCode: 500 }).as('getGdps') - cy.intercept('POST', 'api/weather_models/GDPS/predictions/summaries/', { statusCode: 500 }).as('getGdpsSummaries') - cy.wait('@getStationsDetails') - - cy.selectStationInDropdown(stationCode) - const timeOfInterest = '2021-02-01T12:00:00-08:00' - cy.getByTestId('time-of-interest-picker').type(timeOfInterest.slice(0, 16)) // yyyy-MM-ddThh:mm - - cy.getByTestId('get-wx-data-button').click({ force: true }) - cy.url() - .should('contain', `${stationCodeQueryKey}=${stationCode}`) - .and('contain', `${timeOfInterestQueryKey}=${timeOfInterest}`) - - cy.wait('@getHourlyObservations') - cy.checkErrorMessage('Error occurred (while fetching hourly observations).') - cy.wait('@getGdps') - cy.checkErrorMessage('Error occurred (while fetching GDPS).') - cy.wait('@getGdpsSummaries') - cy.checkErrorMessage('Error occurred (while fetching GDPS summaries).') - cy.wait('@getNoonForecasts') - cy.checkErrorMessage('Error occurred (while fetching noon forecasts).') - cy.wait('@getNoonForecastSummaries') - cy.checkErrorMessage('Error occurred (while fetching noon forecast summaries).') - cy.wait('@getHrdps') - cy.checkErrorMessage('Error occurred (while fetching HRDPS).') - cy.wait('@getHrdpsSummaries') - cy.checkErrorMessage('Error occurred (while fetching HRDPS summaries).') - cy.wait('@getRdps') - cy.checkErrorMessage('Error occurred (while fetching RDPS).') - cy.wait('@getRdpsSummaries') - cy.checkErrorMessage('Error occurred (while fetching RDPS summaries).') - - cy.contains('Data is not available.') - }) - - xit('Should display a map with OpenLayers', () => { - cy.visit(MORECAST_ROUTE) - - // Should be able to find its zoom control - cy.getByTestId('map').find('.ol-zoom') - - // Should be able to find an attribution for the base map layer - cy.getByTestId('map').find('.ol-attribution').click() - }) - - it('Should display the station accuracy for date label', () => { - cy.visit(MORECAST_ROUTE) - - const timeOfInterest = '2021-02-01T12:00:00-08:00' - cy.getByTestId('time-of-interest-picker').type(timeOfInterest.slice(0, 16)) // yyyy-MM-ddThh:mm - - cy.getByTestId('get-wx-data-button').click({ force: true }) - cy.getByTestId('station-forecast-accuracy-for-date').should('have.text', timeOfInterest.slice(0, 10)) - cy.url().should('contain', `${timeOfInterestQueryKey}=${timeOfInterest}`) - }) - - describe('When loading a single station from url', () => { - beforeEach(() => { - interceptData() - - cy.visit(`${MORECAST_ROUTE}?codes=${stationCode}`) - cy.wait('@getStationsDetails') - }) - - it('should load with an observation table', () => { - cy.getByTestId(`observations-table-${stationCode}`).find('tbody > tr').should('have.length', numOfObservations) - - // expect the sidepanel to be partially expanded (we compare the calculated width, and expect - // it to match the width of our browser window) - cy.getByTestId('expandable-container-content') - .invoke('css', 'width') - .then(str => parseInt(str)) - .should('be.lte', PARTIAL_WIDTH) - }) - - it('should load a table comparing forecasts to noon observations', () => { - cy.getByTestId(`noon-forecasts-obs-table-${stationCode}`).find('tbody > tr').should('have.length', numOfForecasts) - - cy.getByTestId(`expand-collapse-button`).click({ force: true }) - cy.getByTestId(`noon-forecasts-obs-table-${stationCode}`) - .invoke('css', 'width') - .then(str => parseInt(str)) - .should('be.lte', 790) - }) - }) - - describe('When loading multiple stations from url', () => { - beforeEach(() => { - interceptData() - - cy.visit(`${MORECAST_ROUTE}?codes=${stationCode},${stationCode2}`) - cy.wait('@getStationsDetails') - }) - - it('Should display station comparison table', () => { - // expect Station Comparison to be selected - cy.getByTestId('station-comparison-button').should('have.attr', 'aria-pressed', 'true') - - // expect the table to exist. - cy.getByTestId('station-comparison-table').should('exist') - - // expect the sidepanel to be fully expanded (we compare the calculated width, and expect - // it to match the width of our browser window) - cy.getByTestId('expandable-container-content').invoke('width').should('be.gte', FULL_WIDTH) - }) - }) - - describe('When wx data for multiple stations fetched', () => { - beforeEach(() => { - interceptData() - - cy.visit(MORECAST_ROUTE) - - cy.wait('@getStationsDetails') - - // Request the weather data - cy.selectStationInDropdown(stationCode) - cy.selectStationInDropdown(stationCode2) - const timeOfInterest = '2021-01-22T12:00:00-08:00' - cy.getByTestId('time-of-interest-picker').type(timeOfInterest.slice(0, 16)) // yyyy-MM-ddThh:mm - cy.getByTestId('get-wx-data-button').click({ force: true }) - }) - }) - - describe('When wx data successfully fetched', () => { - const numOfGdps = 131 - const numOfHrdps = 159 - const numOfRdps = 195 - - beforeEach(() => { - interceptData() - - cy.visit(MORECAST_ROUTE) - - cy.wait('@getStationsDetails') - - // Request the weather data - cy.selectStationInDropdown(stationCode) - cy.getByTestId('get-wx-data-button').click({ force: true }) - }) - - it('Observation, noon forecast, and noon GDPS should be displayed in tables in default active tab', () => { - const checkMaxTempFormattingAndLength = (tableName: string) => { - cy.getByTestId(`${tableName}-${stationCode}`) - .getByTestId('max-temperature-td') - .should('have.css', 'background-color', 'rgb(255, 179, 179)') - .should('have.length.at.least', 1) - } - - const checkMinTempFormattingAndLength = (tableName: string) => { - cy.getByTestId(`${tableName}-${stationCode}`) - .getByTestId('min-temperature-td') - .should('have.css', 'background-color', 'rgb(132, 184, 231)') - .should('have.length.at.least', 1) - } - - const checkMinRHFormattingAndLength = (tableName: string) => { - cy.getByTestId(`${tableName}-${stationCode}`) - .getByTestId('min-RH-td') - .should('have.css', 'background-color', 'rgb(242, 153, 74)') - .should('have.length.at.least', 1) - } - - const checkMaxPrecipFormattingAndLength = (tableName: string) => { - cy.getByTestId(`${tableName}-${stationCode}`) - .getByTestId('max-precipitation-td') - .should('have.css', 'border', '1px solid rgba(0, 0, 0, 0.87)') - } - - const checkMaxWindSpeedFormattingAndLength = (tableName: string) => { - cy.getByTestId(`${tableName}-${stationCode}`) - .getByTestId('max-wind-speed-td') - .should('have.css', 'border-right', '1px solid rgba(0, 0, 0, 0.87)') - .should('have.css', 'border-left-width', '0px') - } - - const checkWindDirectionFormattingAndLength = (tableName: string) => { - cy.getByTestId(`${tableName}-${stationCode}`) - .getByTestId('direction-max-wind-speed-td') - .should('have.css', 'border-left', '1px solid rgba(0, 0, 0, 0.87)') - .should('have.css', 'border-right-width', '0px') - } - - const checkTableCellHighlighting = (tableName: string) => { - checkMaxTempFormattingAndLength(tableName) - checkMinTempFormattingAndLength(tableName) - checkMinRHFormattingAndLength(tableName) - checkMaxPrecipFormattingAndLength(tableName) - checkMaxWindSpeedFormattingAndLength(tableName) - checkWindDirectionFormattingAndLength(tableName) - } - - cy.getByTestId(`observations-table-${stationCode}`).find('tbody > tr').should('have.length', numOfObservations) - - // Check if the sorting functionality works - const day = 26 - const earliestDate = `2021-01-${day - 5}` - const latestDate = `2021-01-${day}` - cy.getByTestId(`observations-table-${stationCode}`) - .find('tbody > tr:first > td:first') - .should('contain', latestDate) - cy.getByTestId(`observations-table-${stationCode}`).find('.MuiTableSortLabel-icon').click() // prettier-ignore - cy.getByTestId(`observations-table-${stationCode}`) - .find('tbody > tr:first > td:first') - .should('contain', earliestDate) - cy.getByTestId(`observations-table-${stationCode}`).find('.MuiTableSortLabel-icon').click() // prettier-ignore - cy.getByTestId(`observations-table-${stationCode}`) - .find('tbody > tr:first > td:first') - .should('contain', latestDate) - - checkTableCellHighlighting('observations-table') - - // Check num of interpolated noon GDPS rows - cy.getByTestId(`noon-gdps-table-${stationCode}`).find('tbody > tr').should('have.length', 14) - checkTableCellHighlighting('noon-gdps-table') - - // Check num of noon forecasts rows - cy.getByTestId(`noon-forecasts-obs-table-${stationCode}`).find('tbody > tr').should('have.length', numOfForecasts) - - // Check that collapse and expand functionality works - cy.getByTestId(`observations-table-${stationCode}-accordion`).click() // Collapse Observations table - cy.wait(500) - cy.getByTestId(`observations-table-${stationCode}`).find('.MuiTableSortLabel-icon').should('not.be.visible') - - cy.getByTestId(`noon-gdps-table-${stationCode}-accordion`).click() // Collapse Interpolated GDPS noon values table - cy.wait(500) - cy.getByTestId(`noon-gdps-table-${stationCode}`).find('.MuiTableContainer-root').should('not.be.visible') - }) - it('Should show the legend', () => { - cy.getByTestId('legend').should('be.visible') - }) - it('Should expand the side panel when it is collapsed, and hide the legend', () => { - cy.getByTestId(`expand-collapse-button`).click({ force: true }) - cy.getByTestId('expandable-container-content').invoke('width').should('be.lte', PARTIAL_WIDTH) - - cy.getByTestId('legend').should('not.exist') - }) - it('Should collapse the side panel when it is expanded and the legend should be visible', () => { - cy.getByTestId(`expand-collapse-button`).click({ force: true }).click({ force: true }) - cy.getByTestId('expandable-container-content').invoke('width').should('be.lte', PARTIAL_WIDTH) - - cy.getByTestId('legend').should('be.visible') - }) - it('Should close the side panel and the legend should be visible', () => { - cy.get(`[value=close]`).click({ force: true }) - cy.getByTestId('legend').should('be.visible') - }) - - describe('When graphs tab is clicked', () => { - beforeEach(() => { - cy.contains('Graphs').click() - }) - it('Temp & RH Graph should be displayed', () => { - const checkNumOfTempDewpointMarkers = (num: number) => { - cy.getByTestId('temp-rh-graph') - .find(`.cartesianlayer > .subplot > .plot > .scatterlayer > .trace > .points > .point`) - .should('have.length', num) - } - const checkTempPlume = (shouldBeDisplayed: boolean) => { - cy.getByTestId('temp-rh-graph') - .find(`.cartesianlayer > .subplot > .plot > .scatterlayer > .trace`) - .should('have.length', shouldBeDisplayed ? 3 : 1) // 2 more traces that make up the plume - } - const checkTempDewpointTraces = (shouldBeDisplayed: boolean) => { - cy.getByTestId('temp-rh-graph') - .find(`.cartesianlayer > .subplot > .plot > .scatterlayer > .trace`) - .should('have.length', shouldBeDisplayed ? 4 : 2) // 2 more traces that make up plume - } - const checkNumOfRHMarkers = (num: number) => { - cy.getByTestId('temp-rh-graph') - .find('.cartesianlayer > .subplot > .overplot > .xy2 > .scatterlayer > .trace > .points > .point') - .should('have.length', num) - } - const checkRHPlume = (shouldBeDisplayed: boolean) => { - cy.getByTestId('temp-rh-graph') - .find('.cartesianlayer > .subplot > .overplot > .xy2 > .scatterlayer > .trace') - .should('have.length', shouldBeDisplayed ? 4 : 2) // 2 more traces that make up the plume - } - const checkNumOfLegends = (num: number) => { - cy.getByTestId('temp-rh-graph') - .find('.infolayer > .legend > .scrollbox > .groups > .traces') - .should('have.length', num) - } - - // the 10 Legend items should be: - // Observed Dew Point, Observed Temp, Observed RH, Forecast Temp, Forecast RH, HRDPS Temp, HRDPS RH, - // HRDPS Temp 5th - 90th percentile, HRDPS RH 5th - 90th percentile, Time of Interest - checkNumOfLegends(10) - - cy.getByTestId('wx-graph-hrdps-toggle').click() - cy.getByTestId('wx-graph-forecast-toggle').click() - checkNumOfTempDewpointMarkers(2 * numOfObservations - 1) - checkNumOfRHMarkers(numOfObservations) - checkTempDewpointTraces(false) - checkRHPlume(false) - cy.getByTestId('wx-graph-observation-toggle').click() - - cy.getByTestId('wx-graph-forecast-toggle').click() - checkNumOfTempDewpointMarkers(numOfForecasts) - checkNumOfRHMarkers(numOfForecasts) - cy.getByTestId('wx-graph-forecast-toggle').click() - - cy.getByTestId('wx-graph-hrdps-toggle').click() - checkNumOfTempDewpointMarkers(numOfHrdps) - checkNumOfRHMarkers(numOfHrdps) - checkTempPlume(true) - checkRHPlume(true) - cy.getByTestId('wx-graph-hrdps-toggle').click() - - cy.getByTestId('wx-graph-rdps-toggle').click() - checkNumOfTempDewpointMarkers(numOfRdps) - checkNumOfRHMarkers(numOfRdps) - checkTempPlume(true) - checkRHPlume(true) - cy.getByTestId('wx-graph-rdps-toggle').click() - - cy.getByTestId('wx-graph-gdps-toggle').click() - checkNumOfTempDewpointMarkers(numOfGdps) - checkNumOfRHMarkers(numOfGdps) - checkTempPlume(true) - checkRHPlume(true) - cy.getByTestId('wx-graph-gdps-toggle').click() - - cy.getByTestId('wx-graph-bias-adjusted-gdps-toggle').click() - checkNumOfTempDewpointMarkers(numOfGdps) - checkNumOfRHMarkers(numOfGdps) - checkTempPlume(false) - checkRHPlume(false) - - checkNumOfLegends(3) - }) - - it('Precipitation graph should be displayed', () => { - const checkNumOfBars = (num: number) => { - cy.getByTestId('precipitation-graph') - .find(`.cartesianlayer > .subplot > .plot > .barlayer > .trace > .points > .point`) - .should('have.length', num) - } - const checkNumOfLegends = (num: number) => { - cy.getByTestId('precipitation-graph') - .find('.infolayer > .legend > .scrollbox > .groups > .traces') - .should('have.length', num) - } - - checkNumOfLegends(7) - - cy.getByTestId('wx-graph-hrdps-toggle').click() - checkNumOfBars(12) - cy.getByTestId('wx-graph-observation-toggle').click() - - checkNumOfBars(6) - cy.getByTestId('wx-graph-forecast-toggle').click() - - cy.getByTestId('wx-graph-hrdps-toggle').click() - checkNumOfBars(8) - cy.getByTestId('wx-graph-hrdps-toggle').click() - - // Note: No idea why this fails in GH action (WTH) - // cy.getByTestId('wx-graph-rdps-toggle').click() - // checkNumOfBars(9) // counts 10 instead of 9 - // cy.getByTestId('wx-graph-rdps-toggle').click() - - // cy.getByTestId('wx-graph-gdps-toggle').click() - // checkNumOfBars(16) // counts 15 instead of 6 - - checkNumOfLegends(1) - }) - - it('Wind speed & direction graph should be displayed', () => { - const checkNumOfArrows = (num: number) => { - cy.getByTestId('wind-spd-dir-graph') - .find(`.layer-above > .shapelayer > .shape-group > path`) - .should('have.length', num) - } - const checkNumOfLegends = (num: number) => { - cy.getByTestId('wind-spd-dir-graph') - .find('.infolayer > .legend > .scrollbox > .groups > .traces') - .should('have.length', num) - } - - checkNumOfLegends(4) - - cy.getByTestId('wx-graph-hrdps-toggle').click() - cy.getByTestId('wx-graph-forecast-toggle').click() - checkNumOfArrows(numOfObservations) - cy.getByTestId('wx-graph-observation-toggle').click() - - cy.getByTestId('wx-graph-hrdps-toggle').click() - checkNumOfArrows(numOfHrdps) - cy.getByTestId('wx-graph-hrdps-toggle').click() - - cy.getByTestId('wx-graph-rdps-toggle').click() - checkNumOfArrows(numOfRdps) - cy.getByTestId('wx-graph-rdps-toggle').click() - - cy.getByTestId('wx-graph-gdps-toggle').click() - checkNumOfArrows(numOfGdps) - cy.getByTestId('wx-graph-gdps-toggle').click() - - cy.getByTestId('wx-graph-forecast-toggle').click() - checkNumOfArrows(numOfForecasts) - - checkNumOfLegends(2) - }) - it('Can toggle back to tables', () => { - cy.contains('Tables').click() - cy.getByTestId(`observations-table-${stationCode}`).find('tbody > tr').should('have.length', numOfObservations) - }) - }) - }) -}) diff --git a/web/package.json b/web/package.json index e0563b727..9f8526d60 100644 --- a/web/package.json +++ b/web/package.json @@ -46,11 +46,9 @@ "match-sorter": "^6.3.1", "ol": "^8.0.0", "ol-pmtiles": "^0.3.0", - "plotly.js": "^2.5.1", "prettier": "^2.4.1", "react": "^17.0.2", "react-dom": "^17.0.2", - "react-plotly.js": "^2.5.1", "react-redux": "^8.0.0", "react-router-dom": "^6.0.0", "recharts": "^2.1.8", diff --git a/web/src/app/Routes.tsx b/web/src/app/Routes.tsx index 494e1e1ce..0ecd8ecdd 100644 --- a/web/src/app/Routes.tsx +++ b/web/src/app/Routes.tsx @@ -10,17 +10,15 @@ const HfiCalculatorPage = lazy(() => import('features/hfiCalculator/pages/HfiCal const CHainesPage = lazy(() => import('features/cHaines/pages/CHainesPage')) import { PERCENTILE_CALC_ROUTE, - FIRE_WEATHER_ROUTE, - MORECAST_ROUTE, HFI_CALC_ROUTE, + MORECAST_ROUTE, C_HAINES_ROUTE, FIRE_BEHAVIOR_CALC_ROUTE, FIRE_BEHAVIOUR_ADVISORY_ROUTE, LANDING_PAGE_ROUTE, MORE_CAST_2_ROUTE } from 'utils/constants' -const MoreCastPage = lazy(() => import('features/fireWeather/pages/MoreCastPage')) -import { NoMatchPage } from 'features/fireWeather/pages/NoMatchPage' +import { NoMatchPage } from 'features/NoMatchPage' const FireBehaviourCalculator = lazy(() => import('features/fbaCalculator/pages/FireBehaviourCalculatorPage')) const FireBehaviourAdvisoryPage = lazy(() => import('features/fba/pages/FireBehaviourAdvisoryPage')) const LandingPage = lazy(() => import('features/landingPage/pages/LandingPage')) @@ -40,15 +38,6 @@ const WPSRoutes: React.FunctionComponent = () => { path={PERCENTILE_CALC_ROUTE} element={} /> - } /> - - - - } - /> { } /> } /> - { } /> + } /> state.cHainesPredi export const selectAuthentication = (state: RootState) => state.authentication export const selectWf1Authentication = (state: RootState) => state.wf1Authentication export const selectToken = (state: RootState) => state.authentication.token -export const selectModels = (state: RootState) => state.models -export const selectObservations = (state: RootState) => state.observations -export const selectForecasts = (state: RootState) => state.forecasts -export const selectModelSummaries = (state: RootState) => state.modelSummaries -export const selectForecastSummaries = (state: RootState) => state.forecastSummaries export const selectFireBehaviourCalcResult = (state: RootState) => state.fbaCalculatorResults -export const selectHighResModels = (state: RootState) => state.highResModels -export const selectHighResModelSummaries = (state: RootState) => state.highResModelSummaries -export const selectRegionalModels = (state: RootState) => state.regionalModels -export const selectRegionalModelSummaries = (state: RootState) => state.regionalModelSummaries export const selectHFIStations = (state: RootState) => state.hfiStations export const selectFireCenters = (state: RootState) => state.fireCenters export const selectFireZoneAreas = (state: RootState) => state.fireZoneAreas @@ -96,17 +69,6 @@ export const selectValueAtCoordinate = (state: RootState) => state.valueAtCoordi export const selectHFIFuelTypes = (state: RootState) => state.hfiFuelTypes export const selectFireZoneElevationInfo = (state: RootState) => state.fireZoneElevationInfo -export const selectWxDataLoading = (state: RootState): boolean => - state.observations.loading || - state.models.loading || - state.modelSummaries.loading || - state.forecasts.loading || - state.forecastSummaries.loading || - state.highResModels.loading || - state.highResModelSummaries.loading || - state.regionalModels.loading || - state.regionalModelSummaries.loading -export const selectFireWeatherStationsLoading = (state: RootState): boolean => state.fireWeatherStations.loading export const selectHFIDailiesLoading = (state: RootState): boolean => state.hfiCalculatorDailies.fireCentresLoading export const selectHFICalculatorState = (state: RootState): HFICalculatorState => state.hfiCalculatorDailies export const selectHFIStationsLoading = (state: RootState): boolean => state.hfiStations.loading diff --git a/web/src/features/fireWeather/pages/NoMatchPage.tsx b/web/src/features/NoMatchPage.tsx similarity index 100% rename from web/src/features/fireWeather/pages/NoMatchPage.tsx rename to web/src/features/NoMatchPage.tsx diff --git a/web/src/features/fbaCalculator/RowManager.ts b/web/src/features/fbaCalculator/RowManager.ts index 2841a0875..318508111 100644 --- a/web/src/features/fbaCalculator/RowManager.ts +++ b/web/src/features/fbaCalculator/RowManager.ts @@ -4,7 +4,7 @@ import { formatCrownFractionBurned } from 'features/fbaCalculator/components/Cro import { formatCriticalHoursAsString } from 'features/fbaCalculator/components/CriticalHoursCell' import { FuelTypes } from 'features/fbaCalculator/fuelTypes' import _, { isNull, isUndefined, merge } from 'lodash' -import { Order } from 'utils/table' +import { Order } from 'utils/constants' export enum SortByColumn { Zone, Station, diff --git a/web/src/features/fbaCalculator/components/FBATable.tsx b/web/src/features/fbaCalculator/components/FBATable.tsx index bb7959f09..0f09bf3b9 100644 --- a/web/src/features/fbaCalculator/components/FBATable.tsx +++ b/web/src/features/fbaCalculator/components/FBATable.tsx @@ -10,7 +10,7 @@ import WeatherStationCell from 'features/fbaCalculator/components/WeatherStation import FuelTypeCell from 'features/fbaCalculator/components/FuelTypeCell' import GrassCureCell from 'features/fbaCalculator/components/GrassCureCell' import WindSpeedCell from 'features/fbaCalculator/components/WindSpeedCell' -import { Order } from 'utils/table' +import { Order, PST_UTC_OFFSET } from 'utils/constants' import { FBATableRow, RowManager, SortByColumn } from 'features/fbaCalculator/RowManager' import { GeoJsonStation, getStations, StationSource } from 'api/stationAPI' import { selectFireWeatherStations, selectFireBehaviourCalcResult } from 'app/rootReducer' @@ -36,7 +36,6 @@ import FBATableHead from 'features/fbaCalculator/components/FBATableHead' import FireTable from 'components/FireTable' import FBATableInstructions from 'features/fbaCalculator/components/FBATableInstructions' import FilterColumnsModal from 'components/FilterColumnsModal' -import { PST_UTC_OFFSET } from 'utils/constants' import WPSDatePicker from 'components/WPSDatePicker' import { AppDispatch } from 'app/store' import { StyledFormControl } from 'components/StyledFormControl' diff --git a/web/src/features/fbaCalculator/components/FBATableHead.tsx b/web/src/features/fbaCalculator/components/FBATableHead.tsx index 588666c89..defaa0250 100644 --- a/web/src/features/fbaCalculator/components/FBATableHead.tsx +++ b/web/src/features/fbaCalculator/components/FBATableHead.tsx @@ -7,7 +7,7 @@ import StickyCell from 'components/StickyCell' import { FBATableRow, SortByColumn } from 'features/fbaCalculator/RowManager' import { isUndefined } from 'lodash' import React from 'react' -import { Order } from 'utils/table' +import { Order } from 'utils/constants' import { ColumnLabel } from 'features/fbaCalculator/components/FBATable' const PREFIX = 'FBATableHead' diff --git a/web/src/features/fireWeather/components/AccuracyColorLegend.tsx b/web/src/features/fireWeather/components/AccuracyColorLegend.tsx deleted file mode 100644 index 601deb035..000000000 --- a/web/src/features/fireWeather/components/AccuracyColorLegend.tsx +++ /dev/null @@ -1,247 +0,0 @@ -import React from 'react' -import { styled } from '@mui/material/styles' -import { AccuracyWeatherVariableEnum } from 'features/fireWeather/components/AccuracyVariablePicker' -import { - darkGreenColor, - middleGreenColor, - lightGreenColor, - neutralColor, - yellowColor, - middleOrangeColor, - darkOrangeColor, - darkRedColor, - mediumRedColor, - pinkColor, - lightBlueColor, - mediumBlueColor, - darkBlueColor -} from 'features/fireWeather/components/maps/stationAccuracy' - -const PREFIX = 'AccuracyColorLegend' - -const classes = { - root: `${PREFIX}-root`, - title: `${PREFIX}-title`, - leftLabel: `${PREFIX}-leftLabel`, - label: `${PREFIX}-label`, - rightLabel: `${PREFIX}-rightLabel`, - rowContainer: `${PREFIX}-rowContainer`, - labelContainer: `${PREFIX}-labelContainer`, - darkGreen: `${PREFIX}-darkGreen`, - middleGreen: `${PREFIX}-middleGreen`, - lightGreen: `${PREFIX}-lightGreen`, - neutral: `${PREFIX}-neutral`, - lightestOrange: `${PREFIX}-lightestOrange`, - middleOrange: `${PREFIX}-middleOrange`, - darkOrange: `${PREFIX}-darkOrange`, - darkestRed: `${PREFIX}-darkestRed`, - mediumRed: `${PREFIX}-mediumRed`, - lightRed: `${PREFIX}-lightRed`, - lightBlue: `${PREFIX}-lightBlue`, - mediumBlue: `${PREFIX}-mediumBlue`, - darkBlue: `${PREFIX}-darkBlue` -} - -const Root = styled('div')({ - [`&.${classes.root}`]: { - display: 'flex', - height: '70px', - flexDirection: 'column', - padding: '5px' - }, - [`& .${classes.title}`]: { - height: '20px', - fontSize: '0.875rem', - width: '260px', - color: 'white', - textAlign: 'center' - }, - [`& .${classes.leftLabel}`]: { - height: '15px', - width: '80px', - fontSize: '10px', - color: 'white', - justifyContent: 'flex-start' - }, - [`& .${classes.label}`]: { - height: '15px', - width: '105px', - fontSize: '10px', - color: 'white', - justifyContent: 'center' - }, - [`& .${classes.rightLabel}`]: { - height: '15px', - width: '20px', - fontSize: '10px', - color: 'white', - justifyContent: 'flex-end' - }, - [`& .${classes.rowContainer}`]: { - display: 'flex', - flexDirection: 'row', - width: '300px', - 'div:nth-child(3n)': { - marginRight: 0 - } - }, - [`& .${classes.labelContainer}`]: { - display: 'flex', - flexDirection: 'row', - width: '260px', - 'div:nth-child(3n)': { - marginRight: 0 - }, - justifyContent: 'space-evenly' - }, - [`& .${classes.darkGreen}`]: { - backgroundColor: darkGreenColor, - borderTop: '2px solid white', - borderLeft: '2px solid white', - borderBottom: '2px solid white', - borderRadius: '2px 0px 0px 2px', - height: 27, - width: 32 - }, - [`& .${classes.middleGreen}`]: { - backgroundColor: middleGreenColor, - borderTop: '2px solid white', - borderBottom: '2px solid white', - height: 27, - width: 32 - }, - [`& .${classes.lightGreen}`]: { - backgroundColor: lightGreenColor, - borderTop: '2px solid white', - borderBottom: '2px solid white', - height: 27, - width: 32 - }, - [`& .${classes.neutral}`]: { - backgroundColor: neutralColor, - borderTop: '2px solid white', - borderBottom: '2px solid white', - height: 27, - width: 64 - }, - [`& .${classes.lightestOrange}`]: { - backgroundColor: yellowColor, - borderTop: '2px solid white', - borderBottom: '2px solid white', - height: 27, - width: 32 - }, - [`& .${classes.middleOrange}`]: { - backgroundColor: middleOrangeColor, - borderTop: '2px solid white', - borderBottom: '2px solid white', - height: 27, - width: 32 - }, - [`& .${classes.darkOrange}`]: { - backgroundColor: darkOrangeColor, - borderTop: '2px solid white', - borderRight: '2px solid white', - borderBottom: '2px solid white', - borderRadius: '0px 2px 2px 0px', - height: 27, - width: 32 - }, - [`& .${classes.darkestRed}`]: { - backgroundColor: darkRedColor, - borderTop: '2px solid white', - borderLeft: '2px solid white', - borderBottom: '2px solid white', - borderRadius: '2px 0px 0px 2px', - height: 27, - width: 32 - }, - [`& .${classes.mediumRed}`]: { - backgroundColor: mediumRedColor, - borderTop: '2px solid white', - borderBottom: '2px solid white', - height: 27, - width: 32 - }, - [`& .${classes.lightRed}`]: { - backgroundColor: pinkColor, - borderTop: '2px solid white', - borderBottom: '2px solid white', - height: 27, - width: 32 - }, - [`& .${classes.lightBlue}`]: { - backgroundColor: lightBlueColor, - borderTop: '2px solid white', - borderBottom: '2px solid white', - height: 27, - width: 32 - }, - [`& .${classes.mediumBlue}`]: { - backgroundColor: mediumBlueColor, - borderTop: '2px solid white', - borderBottom: '2px solid white', - height: 27, - width: 32 - }, - [`& .${classes.darkBlue}`]: { - backgroundColor: darkBlueColor, - borderTop: '2px solid white', - borderRight: '2px solid white', - borderBottom: '2px solid white', - borderRadius: '0px 2px 2px 0px', - height: 27, - width: 32 - } -}) - -interface Props { - selectedWxVariable: AccuracyWeatherVariableEnum -} - -const AccuracyColorLegend = (props: Props) => { - if (props.selectedWxVariable === AccuracyWeatherVariableEnum['Relative Humidity']) { - return ( - -
Observed RH
-
-
-
-
-
-
-
-
-
-
-
+12%
-
+/-3%
-
-12%
-
-
- ) - } else { - // assume Temperature has been selected - return ( -
-
Observed Temperature
-
-
-
-
-
-
-
-
-
-
-
+8°C
-
+/-2°C
-
-8°C
-
-
- ) - } -} - -export default React.memo(AccuracyColorLegend) diff --git a/web/src/features/fireWeather/components/ExpandableContainer.tsx b/web/src/features/fireWeather/components/ExpandableContainer.tsx deleted file mode 100644 index a1eebfbb8..000000000 --- a/web/src/features/fireWeather/components/ExpandableContainer.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import React from 'react' -import { styled } from '@mui/material/styles' - -import IconButton from '@mui/material/IconButton' -import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos' -import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos' -import CloseIcon from '@mui/icons-material/Close' -import { PARTIAL_WIDTH } from 'utils/constants' - -const PREFIX = 'ExpandableContainer' - -const classes = { - root: `${PREFIX}-root`, - ordering: `${PREFIX}-ordering`, - expandCollapse: `${PREFIX}-expandCollapse`, - content: `${PREFIX}-content` -} - -const Root = styled('div')>(({ open, currentWidth }) => ({ - [`& .${classes.root}`]: { - order: 0, - width: getRootWidth(open, currentWidth), - overflowX: 'hidden', - boxShadow: '0px 3px 3px -2px rgb(0 0 0 / 20%), 0px 3px 4px 0px rgb(0 0 0 / 14%), 0px 1px 8px 0px rgb(0 0 0 / 12%)' - }, - [`& .${classes.ordering}`]: { - display: 'flex', - flexDirection: 'row' - }, - [`& .${classes.expandCollapse}`]: { - display: 'flex', - flexDirection: 'column', - justifyContent: 'center' - }, - [`& .${classes.content}`]: { - width: getRootWidth(open, currentWidth), - position: 'relative' - } -})) - -const getRootWidth = (open: boolean, currentWidth: number) => { - if (open) { - return currentWidth > PARTIAL_WIDTH ? '100%' : currentWidth - } - return 0 -} -interface Props { - expand: () => void - collapse: () => void - close: () => void - currentWidth: number - open: boolean - children: React.ReactNode -} - -const ExpandableContainer = (props: Props) => { - const collapsed = props.currentWidth === PARTIAL_WIDTH - return ( - - { - props.close() - }} - size="large" - > - - -
-
{ - collapsed || !props.open ? props.expand() : props.collapse() - }} - > - { - collapsed ? props.expand() : props.collapse() - }} - size="large" - > - {collapsed ? : } - -
-
- {props.children} -
-
-
- ) -} - -export default React.memo(ExpandableContainer) diff --git a/web/src/features/fireWeather/components/GetWxDataButton.tsx b/web/src/features/fireWeather/components/GetWxDataButton.tsx deleted file mode 100644 index 6d1bf3512..000000000 --- a/web/src/features/fireWeather/components/GetWxDataButton.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react' -import { useSelector } from 'react-redux' - -import { Button } from 'components' -import { RootState } from 'app/rootReducer' - -interface Props { - onBtnClick: () => void - selector: (root: RootState) => boolean - disabled?: boolean - buttonLabel?: string -} - -const GetWxDataButton = ({ onBtnClick, selector, disabled, buttonLabel }: Props) => { - const wxDataLoading = useSelector(selector) - const label = buttonLabel ? buttonLabel : 'Get Weather Data' - - return ( - - ) -} - -export default React.memo(GetWxDataButton) diff --git a/web/src/features/fireWeather/components/NetworkErrorMessages.tsx b/web/src/features/fireWeather/components/NetworkErrorMessages.tsx deleted file mode 100644 index 926f78fb6..000000000 --- a/web/src/features/fireWeather/components/NetworkErrorMessages.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import React from 'react' -import { styled } from '@mui/material/styles' -import { useSelector } from 'react-redux' - -import { ErrorMessage } from 'components' -import { - selectObservations, - selectModels, - selectModelSummaries, - selectForecasts, - selectForecastSummaries, - selectHighResModels, - selectHighResModelSummaries, - selectRegionalModels, - selectRegionalModelSummaries -} from 'app/rootReducer' - -const PREFIX = 'NetworkErrorMessages' - -const classes = { - root: `${PREFIX}-root` -} - -const Root = styled('div')({ - [`&.${classes.root}`]: { - paddingTop: 12 - } -}) - -const NetworkErrorMessages = () => { - const { error: errFetchingObservations } = useSelector(selectObservations) - const { error: errFetchingModels } = useSelector(selectModels) - const { error: errFetchingModelSummaries } = useSelector(selectModelSummaries) - const { error: errFetchingForecasts } = useSelector(selectForecasts) - const { error: errFetchingForecastSummaries } = useSelector(selectForecastSummaries) - const { error: errFetchingHighResModels } = useSelector(selectHighResModels) - const { error: errFetchingHighResModelSummaries } = useSelector(selectHighResModelSummaries) - const { error: errFetchingRegionalModels } = useSelector(selectRegionalModels) - const { error: errFetchingRegionalModelSummaries } = useSelector(selectRegionalModelSummaries) - - return ( - - {errFetchingObservations && ( - - )} - - {errFetchingModels && } - - {errFetchingModelSummaries && ( - - )} - - {errFetchingForecasts && ( - - )} - - {errFetchingForecastSummaries && ( - - )} - - {errFetchingHighResModels && ( - - )} - - {errFetchingHighResModelSummaries && ( - - )} - - {errFetchingRegionalModels && ( - - )} - - {errFetchingRegionalModelSummaries && ( - - )} - - ) -} - -export default React.memo(NetworkErrorMessages) diff --git a/web/src/features/fireWeather/components/SidePanel.tsx b/web/src/features/fireWeather/components/SidePanel.tsx deleted file mode 100644 index 923441fc3..000000000 --- a/web/src/features/fireWeather/components/SidePanel.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import React from 'react' -import { styled } from '@mui/material/styles' -import { ToggleButton, ToggleButtonGroup } from '@mui/material' - -const PREFIX = 'SidePanel' - -const classes = { - root: `${PREFIX}-root`, - content: `${PREFIX}-content`, - actions: `${PREFIX}-actions`, - closeBtn: `${PREFIX}-closeBtn` -} - -const Root = styled('div')({ - [`&.${classes.root}`]: { - order: 2, - overflowX: 'hidden' - }, - [`& .${classes.content}`]: { - position: 'relative' - }, - [`& .${classes.actions}`]: { - display: 'flex', - flexDirection: 'row', - alignItems: 'flex-start' - }, - [`& .${classes.closeBtn}`]: { - marginRight: 10, - fontSize: 28, - cursor: 'pointer', - fontWeight: 'bold' - } -}) - -export enum SidePanelEnum { - Tables = 'tables', - Graphs = 'graphs', - Comparison = 'comparison' -} - -interface Props { - handleToggleView: (_: React.MouseEvent, newDataView: SidePanelEnum) => void - showTableView: string - stationCodes: number[] - children: React.ReactNode -} - -const SidePanel = (props: Props) => { - return ( - -
-
- - Tables - Graphs - {props.stationCodes.length > 1 && ( - - Station comparison - - )} - -
- {props.children} -
-
- ) -} - -export default React.memo(SidePanel) diff --git a/web/src/features/fireWeather/components/StationAccuracyForDate.tsx b/web/src/features/fireWeather/components/StationAccuracyForDate.tsx deleted file mode 100644 index a9bdb1ef6..000000000 --- a/web/src/features/fireWeather/components/StationAccuracyForDate.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import React from 'react' -import { styled } from '@mui/material/styles' -import { CircularProgress } from '@mui/material' -import { useSelector } from 'react-redux' -import { selectFireWeatherStationsLoading } from 'app/rootReducer' - -const PREFIX = 'StationAccuracyForDate' - -const classes = { - root: `${PREFIX}-root`, - title: `${PREFIX}-title`, - time: `${PREFIX}-time`, - rowContainer: `${PREFIX}-rowContainer`, - spinner: `${PREFIX}-spinner` -} - -const Root = styled('div')(({ theme }) => ({ - [`&.${classes.root}`]: { - display: 'flex', - height: '70px', - flexDirection: 'column', - padding: '5px' - }, - - [`& .${classes.title}`]: { - fontSize: '0.875rem', - height: '20px', - width: '205px', - color: 'white' - }, - - [`& .${classes.time}`]: { - fontSize: '0.875rem', - height: '20px', - width: '205px', - color: 'white', - textAlign: 'center' - }, - - [`& .${classes.rowContainer}`]: { - display: 'flex', - flexDirection: 'row', - width: '300px', - justifyContent: 'flex-start' - }, - - [`& .${classes.spinner}`]: { - color: theme.palette.primary.light - } -})) - -interface Props { - toiFromQuery: string -} - -const StationAccuracyForDate = (props: Props) => { - const isLoading = useSelector(selectFireWeatherStationsLoading) - - return ( - - {isLoading ? ( - - ) : ( -
-
-
Stations forecast accuracy for:
-
-
-
{props.toiFromQuery.slice(0, 10)}
-
-
- )} -
- ) -} - -export default React.memo(StationAccuracyForDate) diff --git a/web/src/features/fireWeather/components/TimeOfInterestPicker.tsx b/web/src/features/fireWeather/components/TimeOfInterestPicker.tsx deleted file mode 100644 index e8ab8b863..000000000 --- a/web/src/features/fireWeather/components/TimeOfInterestPicker.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react' -import TextField from '@mui/material/TextField' - -interface Props { - className?: string - timeOfInterest: string - onChange: (d: string) => void -} - -const TimeOfInterestPicker = (props: Props) => { - return ( - { - const value = e.currentTarget.value - - if (value) { - props.onChange(`${value}:00-08:00`) // Append seconds and timezone (PST) at the end - } - }} - /> - ) -} - -export default React.memo(TimeOfInterestPicker) diff --git a/web/src/features/fireWeather/components/WxDataDisplays.tsx b/web/src/features/fireWeather/components/WxDataDisplays.tsx deleted file mode 100644 index d5d980b91..000000000 --- a/web/src/features/fireWeather/components/WxDataDisplays.tsx +++ /dev/null @@ -1,291 +0,0 @@ -import React from 'react' -import { styled } from '@mui/material/styles' -import { useSelector } from 'react-redux' -import { Typography } from '@mui/material' - -import ObservationTable from 'features/fireWeather/components/tables/ObservationTable' -import { NoonModelTable } from 'features/fireWeather/components/tables/NoonWxValueTables' -import StationComparisonTable from 'features/fireWeather/components/tables/StationComparisonTable' -import NoonForecastTable from 'features/fireWeather/components/tables/NoonForecastTable' -import WxDataGraph from 'features/fireWeather/components/graphs/WxDataGraph' -import { ErrorBoundary } from 'components' -import { - selectObservations, - selectModels, - selectModelSummaries, - selectForecasts, - selectWxDataLoading, - selectForecastSummaries, - selectHighResModels, - selectHighResModelSummaries, - selectRegionalModels, - selectRegionalModelSummaries, - selectFireWeatherStations -} from 'app/rootReducer' -import { GeoJsonStation } from 'api/stationAPI' -import { ObservedValue } from 'api/observationAPI' -import { ModelSummary, ModelValue } from 'api/modelAPI' -import { ForecastSummary, NoonForecastValue } from 'api/forecastAPI' -import { SidePanelEnum } from 'features/fireWeather/components/SidePanel' -import { RedrawCommand } from 'features/map/Map' - -const PREFIX = 'WxDataDisplaysWrapper' - -const classes = { - displays: `${PREFIX}-displays`, - display: `${PREFIX}-display`, - title: `${PREFIX}-title`, - noDataAvailable: `${PREFIX}-noDataAvailable` -} - -interface WxDataDisplaysProps { - showTableView: string - timeOfInterest: string - expandedOrCollapsed?: RedrawCommand - stationCodes: number[] - wxDataLoading: boolean - stationsByCode: Record - observationsByStation: Record - allModelsByStation: Record - noonModelsByStation: Record - modelSummariesByStation: Record - allNoonForecastsByStation: Record - forecastSummariesByStation: Record - allHighResModelsByStation: Record - highResModelSummariesByStation: Record - allRegionalModelsByStation: Record - regionalModelSummariesByStation: Record -} - -interface FragmentProps { - view: string - code: number - noonOnlyGdpsModels: ModelValue[] | undefined - observations: ObservedValue[] | undefined - noonForecasts: NoonForecastValue[] | undefined - station: GeoJsonStation - expandedOrCollapsed?: { redraw: boolean } - timeOfInterest: string - noonForecastSummaries: ForecastSummary[] | undefined - hrdpsModels: ModelValue[] | undefined - hrdpsSummaries: ModelSummary[] | undefined - rdpsModels: ModelValue[] | undefined - rdpsSummaries: ModelSummary[] | undefined - gdpsModels: ModelValue[] | undefined - gdpsSummaries: ModelSummary[] | undefined -} - -interface TableFragmentProps { - code: number - noonOnlyGdpsModels: ModelValue[] | undefined - observations: ObservedValue[] | undefined - noonForecasts: NoonForecastValue[] | undefined -} - -const TableFragment = (props: TableFragmentProps) => { - // Tables for a single station. - const { code, noonOnlyGdpsModels, observations, noonForecasts } = props - return ( - - - - - - - - - - - - ) -} - -const SingleStationFragment = (props: FragmentProps) => { - const { - view, - code, - noonOnlyGdpsModels, - observations, - noonForecasts, - station, - timeOfInterest, - expandedOrCollapsed, - noonForecastSummaries, - hrdpsModels, - hrdpsSummaries, - rdpsModels, - rdpsSummaries, - gdpsModels, - gdpsSummaries - } = props - switch (view) { - case SidePanelEnum.Tables: - return ( - - ) - case SidePanelEnum.Graphs: - default: - return ( - - - - ) - } -} - -export const WxDataDisplays = React.memo(function _(props: WxDataDisplaysProps) { - return ( -
- {props.wxDataLoading && 'Loading...'} - - {!props.wxDataLoading && props.showTableView === SidePanelEnum.Comparison && ( - - )} - - {!props.wxDataLoading && - (props.showTableView === SidePanelEnum.Tables || props.showTableView === SidePanelEnum.Graphs) && - props.stationCodes.map(code => { - const station = props.stationsByCode[code] - if (!station) return null - - const observations = props.observationsByStation[code] - const noonForecasts = props.allNoonForecastsByStation[code] - const noonForecastSummaries = props.forecastSummariesByStation[code] - const gdpsModels = props.allModelsByStation[code] - const gdpsSummaries = props.modelSummariesByStation[code] - const noonOnlyGdpsModels = props.noonModelsByStation[code] - const hrdpsModels = props.allHighResModelsByStation[code] - const hrdpsSummaries = props.highResModelSummariesByStation[code] - const rdpsModels = props.allRegionalModelsByStation[code] - const rdpsSummaries = props.regionalModelSummariesByStation[code] - const nothingToDisplay = !observations && !noonForecasts && !gdpsModels && !hrdpsModels && !rdpsModels - - return ( -
- - {`${station.properties.name} (${station.properties.code})`} - - {nothingToDisplay && ( - - Data is not available. - - )} - -
- ) - })} -
- ) -}) - -const StyledWxDataDisplays = styled(WxDataDisplays)({ - [`& .${classes.displays}`]: { - marginTop: 4 - }, - [`& .${classes.display}`]: { - marginBottom: 16 - }, - [`& .${classes.title}`]: { - fontSize: '1.2rem', - paddingBottom: 8 - }, - [`& .${classes.noDataAvailable}`]: { - paddingBottom: 8 - } -}) - -interface WxDataDisplaysWrapperProps { - showTableView: string - timeOfInterest: string - expandedOrCollapsed?: { redraw: boolean } - stationCodes: number[] -} - -const WxDataDisplaysWrapper: React.FunctionComponent = props => { - const { stationsByCode } = useSelector(selectFireWeatherStations) - const { observationsByStation } = useSelector(selectObservations) - const { allModelsByStation, noonModelsByStation } = useSelector(selectModels) - const { modelSummariesByStation } = useSelector(selectModelSummaries) - const { allNoonForecastsByStation } = useSelector(selectForecasts) - const { forecastSummariesByStation } = useSelector(selectForecastSummaries) - const { allHighResModelsByStation } = useSelector(selectHighResModels) - const { highResModelSummariesByStation } = useSelector(selectHighResModelSummaries) - const { allRegionalModelsByStation } = useSelector(selectRegionalModels) - const { regionalModelSummariesByStation } = useSelector(selectRegionalModelSummaries) - const wxDataLoading = useSelector(selectWxDataLoading) - - return ( - - ) -} - -export default WxDataDisplaysWrapper diff --git a/web/src/features/fireWeather/components/WxDataForm.tsx b/web/src/features/fireWeather/components/WxDataForm.tsx deleted file mode 100644 index 28692cf75..000000000 --- a/web/src/features/fireWeather/components/WxDataForm.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import React, { useState, useEffect } from 'react' -import { styled } from '@mui/material/styles' -import { useSelector } from 'react-redux' -import { useNavigate, useLocation } from 'react-router-dom' - -import TimeOfInterestPicker from 'features/fireWeather/components/TimeOfInterestPicker' -import GetWxDataButton from 'features/fireWeather/components/GetWxDataButton' -import { stationCodeQueryKey, timeOfInterestQueryKey } from 'utils/url' -import WxStationDropdown from 'features/fireWeather/components/WxStationDropdown' -import { selectStations } from 'features/stations/slices/stationsSlice' -import { selectWxDataLoading, selectFireWeatherStationsLoading, selectFireWeatherStations } from 'app/rootReducer' - -const PREFIX = 'WxDataForm' - -const classes = { - form: `${PREFIX}-form`, - stationDropdown: `${PREFIX}-stationDropdown`, - timeOfInterest: `${PREFIX}-timeOfInterest` -} - -const Root = styled('form')({ - [`&.${classes.form}`]: { - display: 'flex', - alignItems: 'center', - flexWrap: 'wrap', - - '& fieldset, label, input': { - color: 'white !important', - borderColor: 'white !important' - }, - '& .MuiChip-root': { - background: '#f0f0f0' - } - }, - [`& .${classes.stationDropdown}`]: { - marginRight: 16 - }, - [`& .${classes.timeOfInterest}`]: { - marginRight: 16 - } -}) - -interface Props { - className?: string - stationCodesQuery: number[] - toiFromQuery: string - setSidePanelState: (show: boolean) => void -} - -const WxDataForm = ({ stationCodesQuery, toiFromQuery, setSidePanelState }: Props) => { - const navigate = useNavigate() - const location = useLocation() - - const { selectedStationsByCode } = useSelector(selectFireWeatherStations) - - selectStations(stationCodesQuery) - - const [timeOfInterest, setTimeOfInterest] = useState(toiFromQuery) - const hasSelectedCodes = selectedStationsByCode.length > 0 - - useEffect(() => { - // Update local state to match with the query url - selectStations(selectedStationsByCode) - setTimeOfInterest(toiFromQuery) - }, [location]) // eslint-disable-line react-hooks/exhaustive-deps - - const handleSubmit = () => { - let potentialCodes = '' - if (hasSelectedCodes) { - // Open the side panel - setSidePanelState(true) - potentialCodes = `${stationCodeQueryKey}=${selectedStationsByCode.join(',')}&` - } else { - // Close side panel if we do not care about specific stations - setSidePanelState(false) - } - - // Update the url query with the new station codes and time of interest - navigate({ - search: potentialCodes + `${timeOfInterestQueryKey}=${timeOfInterest}` - }) - } - - return ( - - - - - - ) -} - -export default React.memo(WxDataForm) diff --git a/web/src/features/fireWeather/components/WxStationDropdown.tsx b/web/src/features/fireWeather/components/WxStationDropdown.tsx deleted file mode 100644 index f4c790a4f..000000000 --- a/web/src/features/fireWeather/components/WxStationDropdown.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import React, { useEffect } from 'react' -import { styled } from '@mui/material/styles' -import { useSelector, useDispatch } from 'react-redux' -import { useLocation } from 'react-router-dom' -import Autocomplete from '@mui/material/Autocomplete' -import { TextField } from '@mui/material' - -import { selectFireWeatherStations } from 'app/rootReducer' -import { getStationCodesFromUrl } from 'utils/url' -import { getSelectedStationOptions } from 'utils/dropdown' -import { GeoJsonStation } from 'api/stationAPI' -import { selectStations } from 'features/stations/slices/stationsSlice' - -const PREFIX = 'WxStationDropdown' - -const classes = { - autocomplete: `${PREFIX}-autocomplete`, - wrapper: `${PREFIX}-wrapper` -} - -const Root = styled('div')({ - [`& .${classes.autocomplete}`]: { - width: '100%' - }, - [`& .${classes.wrapper}`]: { - display: 'flex', - alignItems: 'flex-start', - minWidth: 300 - } -}) - -export interface Option { - name: string - code: number -} - -interface Props { - className?: string - stationCodes: number[] -} - -const WxStationDropdown = (props: Props) => { - const dispatch = useDispatch() - const location = useLocation() - const { selectedStationsByCode } = useSelector(selectFireWeatherStations) - - const { - loading: fetchingStations, - stations, - stationsByCode, - error: errorFetchingStations - } = useSelector(selectFireWeatherStations) - - const { isThereUnknownCode, selectedStationOptions } = getSelectedStationOptions( - selectedStationsByCode, - stationsByCode - ) - const isThereError = !fetchingStations && (Boolean(errorFetchingStations) || isThereUnknownCode) - const allStationOptions: Option[] = (stations as GeoJsonStation[]).map((station: GeoJsonStation) => ({ - name: station.properties.name, - code: station.properties.code - })) - - useEffect(() => { - const codesFromQuery = getStationCodesFromUrl(location.search) - if (codesFromQuery.length > 0) { - dispatch(selectStations(codesFromQuery)) - } - }, [dispatch, location]) - - return ( - -
- `${option.name} (${option.code})`} - isOptionEqualToValue={(option, value) => option.code === value.code} - onChange={(_, options) => { - dispatch(selectStations(options.map(s => s.code))) - }} - size="small" - value={selectedStationOptions} - renderInput={params => ( - - )} - /> -
-
- ) -} - -export default React.memo(WxStationDropdown) diff --git a/web/src/features/fireWeather/components/graphs/PrecipitationGraph.tsx b/web/src/features/fireWeather/components/graphs/PrecipitationGraph.tsx deleted file mode 100644 index a9e9371f2..000000000 --- a/web/src/features/fireWeather/components/graphs/PrecipitationGraph.tsx +++ /dev/null @@ -1,139 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -import React, { useEffect, useState } from 'react' -import Plot from 'react-plotly.js' - -import { ObservedValue } from 'api/observationAPI' -import { ModelValue } from 'api/modelAPI' -import { NoonForecastValue } from 'api/forecastAPI' -import { ToggleValues } from 'features/fireWeather/components/graphs/useGraphToggles' -import { GeoJsonStation } from 'api/stationAPI' -import { - getLayoutConfig, - findMaxNumber, - populateGraphDataForPrecip, - populateTimeOfInterestLineData, - rangeSliderConfig -} from 'features/fireWeather/components/graphs/plotlyHelper' -import { RedrawCommand } from 'features/map/Map' - -const observedPrecipColor = '#4291FF' -const forecastPrecipColor = '#1200DE' -const hrdpsPrecipColor = '#B86BFF' -const rdpsPrecipColor = '#FF64DD' -const gdpsPrecipColor = '#7556CA' - -interface Props { - station: GeoJsonStation - timeOfInterest: string - expandedOrCollapsed?: RedrawCommand - sliderRange: [string, string] - toggleValues: ToggleValues - observations: ObservedValue[] - noonForecasts: NoonForecastValue[] - hrdpsModels: ModelValue[] - rdpsModels: ModelValue[] - gdpsModels: ModelValue[] -} - -const PrecipitationGraph = (props: Props) => { - const { - station, - timeOfInterest, - expandedOrCollapsed, - sliderRange, - toggleValues, - observations, - noonForecasts, - gdpsModels, - rdpsModels, - hrdpsModels - } = props - - const observationData = populateGraphDataForPrecip( - observations, - 'Observation', - observedPrecipColor, - toggleValues.showObservations - ) - const forecastData = populateGraphDataForPrecip( - noonForecasts, - 'Forecast', - forecastPrecipColor, - toggleValues.showForecasts - ) - const hrdpsData = populateGraphDataForPrecip(hrdpsModels, 'HRDPS', hrdpsPrecipColor, toggleValues.showHrdps) - const gdpsData = populateGraphDataForPrecip(gdpsModels, 'GDPS', gdpsPrecipColor, toggleValues.showGdps) - const rdpsData = populateGraphDataForPrecip(rdpsModels, 'RDPS', rdpsPrecipColor, toggleValues.showRdps) - - const maxY = findMaxNumber([ - observationData.maxAccumPrecip, - forecastData.maxAccumPrecip, - hrdpsData.maxAccumPrecip, - gdpsData.maxAccumPrecip, - rdpsData.maxAccumPrecip - ]) - const y2Range = [0, maxY] - const timeOfInterestLine = populateTimeOfInterestLineData(timeOfInterest, y2Range[0], y2Range[1], 'y2') - - // Update plotly revision to trigger re-drawing of the plot - const setRevision = useState(0)[1] - - useEffect(() => { - setRevision(revision => revision + 1) - }, [expandedOrCollapsed, setRevision]) - - return ( -
- -
- ) -} - -export default React.memo(PrecipitationGraph) diff --git a/web/src/features/fireWeather/components/graphs/TempRHGraph.tsx b/web/src/features/fireWeather/components/graphs/TempRHGraph.tsx deleted file mode 100644 index 3bd803b75..000000000 --- a/web/src/features/fireWeather/components/graphs/TempRHGraph.tsx +++ /dev/null @@ -1,244 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -import React, { useEffect, useState } from 'react' -import Plot from 'react-plotly.js' - -import { ObservedValue } from 'api/observationAPI' -import { ModelValue, ModelSummary } from 'api/modelAPI' -import { NoonForecastValue, ForecastSummary } from 'api/forecastAPI' -import { GeoJsonStation } from 'api/stationAPI' -import { ToggleValues } from 'features/fireWeather/components/graphs/useGraphToggles' -import { - getLayoutConfig, - populateGraphDataForTempAndRH, - TempRHGraphProperties, - populateTimeOfInterestLineData, - rangeSliderConfig -} from 'features/fireWeather/components/graphs/plotlyHelper' -import { RedrawCommand } from 'features/map/Map' - -const observedTempColor = '#4291FF' -const observedRHColor = '#EB5757' -const observedDewpointColor = '#949494' -const forecastTempColor = '#1200DE' -const forecastRHColor = '#910000' -const hrdpsTempColor = '#B86BFF' -const hrdpsRHColor = '#229B56' -const hrdpsTempPlumeColor = 'rgba(184, 107, 255, 0.2)' -const hrdpsRHPlumeColor = 'rgba(34, 155, 86, 0.2)' -const rdpsTempColor = '#FF64DD' -const rdpsRHColor = '#285777' -const rdpsTempPlumeColor = 'rgba(255, 100, 221, 0.2)' -const rdpsRHPlumeColor = 'rgba(40, 87, 119, 0.2)' -const gdpsTempColor = '#7556CA' -const gdpsRHColor = '#F2994A' -const gdpsTempPlumeColor = 'rgba(117, 86, 202, 0.2)' -const gdpsRHPlumeColor = 'rgba(242, 153, 74, 0.2)' -const biasGdpsTempColor = '#840DA2' -const biasGdpsRHColor = '#937D65' - -interface Props { - station: GeoJsonStation - timeOfInterest: string - expandedOrCollapsed?: RedrawCommand - sliderRange: [string, string] - toggleValues: ToggleValues - observations: ObservedValue[] - noonForecasts: NoonForecastValue[] - NoonForecastSummaries: ForecastSummary[] - hrdpsModels: ModelValue[] - hrdpsSummaries: ModelSummary[] - rdpsModels: ModelValue[] - rdpsSummaries: ModelSummary[] - gdpsModels: ModelValue[] - gdpsSummaries: ModelSummary[] - hoverMode: 'closest' | 'x' | 'x unified' -} - -const TempRHGraph = (props: Props) => { - const { - station, - timeOfInterest, - expandedOrCollapsed, - sliderRange, - toggleValues, - observations, - noonForecasts, - NoonForecastSummaries, - hrdpsModels, - hrdpsSummaries, - gdpsModels, - gdpsSummaries, - rdpsModels, - rdpsSummaries, - hoverMode - } = props - - const obsGraphProperties: TempRHGraphProperties = { - values: observations, - tempName: 'Observed Temp', - rhName: 'Observed RH', - show: toggleValues.showObservations, - symbol: 'circle', // https://plotly.com/javascript/reference/scatter/#scatter-marker-symbol - dash: 'solid', - tempColor: observedTempColor, - rhColor: observedRHColor, - dewpointName: 'Observed Dew Point', - dewpointColor: observedDewpointColor - } - const observationData = populateGraphDataForTempAndRH(obsGraphProperties) - - const forecastGraphProperties: TempRHGraphProperties = { - values: [...noonForecasts, ...NoonForecastSummaries], - tempName: 'Forecast Temp', - rhName: 'Forecast RH', - show: toggleValues.showForecasts, - symbol: 'pentagon', - dash: 'solid', - tempColor: forecastTempColor, - rhColor: forecastRHColor - } - const forecastData = populateGraphDataForTempAndRH(forecastGraphProperties) - - const hrdpsGraphProperties: TempRHGraphProperties = { - values: [...hrdpsModels, ...hrdpsSummaries], - tempName: 'HRDPS Temp', - rhName: 'HRDPS RH', - show: toggleValues.showHrdps, - symbol: 'square', - dash: 'dash', - tempColor: hrdpsTempColor, - rhColor: hrdpsRHColor, - tempPlumeColor: hrdpsTempPlumeColor, - rhPlumeColor: hrdpsRHPlumeColor - } - const hrdpsData = populateGraphDataForTempAndRH(hrdpsGraphProperties) - - const gdpsGraphProperties: TempRHGraphProperties = { - values: [...gdpsModels, ...gdpsSummaries], - tempName: 'GDPS Temp', - rhName: 'GDPS RH', - show: toggleValues.showGdps, - symbol: 'triangle-up', - dash: 'dashdot', - tempColor: gdpsTempColor, - rhColor: gdpsRHColor, - tempPlumeColor: gdpsTempPlumeColor, - rhPlumeColor: gdpsRHPlumeColor - } - const gdpsData = populateGraphDataForTempAndRH(gdpsGraphProperties) - - const rdpsGraphProperties: TempRHGraphProperties = { - values: [...rdpsModels, ...rdpsSummaries], - tempName: 'RDPS Temp', - rhName: 'RDPS RH', - show: toggleValues.showRdps, - symbol: 'diamond', - dash: 'longdash', - tempColor: rdpsTempColor, - rhColor: rdpsRHColor, - tempPlumeColor: rdpsTempPlumeColor, - rhPlumeColor: rdpsRHPlumeColor - } - const rdpsData = populateGraphDataForTempAndRH(rdpsGraphProperties) - - const biasAdjGDPSGraphProperties: TempRHGraphProperties = { - values: gdpsModels, - tempName: 'Bias Adjusted GDPS Temp', - rhName: 'Bias Adjusted GDPS RH', - show: toggleValues.showBiasAdjGdps, - symbol: 'star', - dash: 'longdashdot', - tempColor: biasGdpsTempColor, - rhColor: biasGdpsRHColor - } - const biasAdjGdpsData = populateGraphDataForTempAndRH(biasAdjGDPSGraphProperties) - - const y2Range = [0, 102] - const timeOfInterestLine = populateTimeOfInterestLineData(timeOfInterest, y2Range[0], y2Range[1], 'y2') - - // Update plotly revision to trigger re-drawing of the plot - const setRevision = useState(0)[1] - - useEffect(() => { - setRevision(revision => revision + 1) - }, [expandedOrCollapsed, setRevision]) - - return ( -
- -
- ) -} - -export default React.memo(TempRHGraph) diff --git a/web/src/features/fireWeather/components/graphs/WindGraph.tsx b/web/src/features/fireWeather/components/graphs/WindGraph.tsx deleted file mode 100644 index ab9708e02..000000000 --- a/web/src/features/fireWeather/components/graphs/WindGraph.tsx +++ /dev/null @@ -1,180 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -import React, { useEffect, useState } from 'react' -import Plot from 'react-plotly.js' - -import { ObservedValue } from 'api/observationAPI' -import { NoonForecastValue } from 'api/forecastAPI' -import { ModelValue } from 'api/modelAPI' -import { ToggleValues } from 'features/fireWeather/components/graphs/useGraphToggles' -import { GeoJsonStation } from 'api/stationAPI' -import { - getLayoutConfig, - findMaxNumber, - findMinNumber, - populateGraphDataForWind, - populateTimeOfInterestLineData, - rangeSliderConfig -} from 'features/fireWeather/components/graphs/plotlyHelper' -import { RedrawCommand } from 'features/map/Map' - -export interface Props { - station: GeoJsonStation - timeOfInterest: string - expandedOrCollapsed?: RedrawCommand - sliderRange: [string, string] - toggleValues: ToggleValues - observations: ObservedValue[] - noonForecasts: NoonForecastValue[] - hrdpsModels: ModelValue[] - rdpsModels: ModelValue[] - gdpsModels: ModelValue[] -} - -const observationLineColor = '#005f87' -const observationArrowColor = observationLineColor -const hrdpsLineColor = '#3ac417' -const hrdpsArrowColor = hrdpsLineColor -const rdpsLineColor = '#026200' -const rdpsArrowColor = rdpsLineColor -const gdpsLineColor = '#32e7e7' -const gdpsArrowColor = gdpsLineColor -const forecastLineColor = '#a50b41' -const forecastArrowColor = forecastLineColor - -const WindGraph = (props: Props) => { - const { - station, - timeOfInterest, - expandedOrCollapsed, - sliderRange, - toggleValues, - observations, - noonForecasts, - gdpsModels, - rdpsModels, - hrdpsModels - } = props - const { showObservations, showForecasts, showGdps, showRdps, showHrdps } = toggleValues - - const observationData = populateGraphDataForWind( - observations, - 'Observation', - showObservations, - observationLineColor, - observationArrowColor - ) - const forecastData = populateGraphDataForWind( - noonForecasts, - 'Noon Forecasts', - showForecasts, - forecastLineColor, - forecastArrowColor - ) - const hrdpsData = populateGraphDataForWind(hrdpsModels, 'HRDPS', showHrdps, hrdpsLineColor, hrdpsArrowColor) - const rdpsData = populateGraphDataForWind(rdpsModels, 'RDPS', showRdps, rdpsLineColor, rdpsArrowColor) - const gdpsData = populateGraphDataForWind(gdpsModels, 'GDPS', showGdps, gdpsLineColor, gdpsArrowColor) - - const maxWindSpd = findMaxNumber([ - observationData.maxWindSpd, - forecastData.maxWindSpd, - gdpsData.maxWindSpd, - rdpsData.maxWindSpd, - hrdpsData.maxWindSpd - ]) - const minWindSpd = findMinNumber([ - observationData.minWindSpd, - forecastData.minWindSpd, - gdpsData.minWindSpd, - rdpsData.minWindSpd, - hrdpsData.minWindSpd - ]) - const timeOfInterestLine = populateTimeOfInterestLineData(timeOfInterest, minWindSpd, maxWindSpd) - - // Update plotly revision to trigger re-drawing of the plot - const setRevision = useState(0)[1] - - useEffect(() => { - setRevision(revision => revision + 1) - }, [expandedOrCollapsed, setRevision]) - - return ( -
- { - // We cannot group the shapes (arrows) with the legend (https://github.com/plotly/plotly.js/issues/98) - // So we loop through the corresponding shapes (arrows) to toggle them on and off. - // It's not very fast, but it works. - // NOTE: The alternative would be to just make this function return false, thus disabling - // toggling of layers using the legend. - - const dataIndex = event.expandedIndex // determined by the order of the data array - - let clickedLegend: string | undefined = undefined - - switch (dataIndex) { - case 1: - clickedLegend = 'GDPS' - break - case 2: - clickedLegend = 'RDPS' - break - case 3: - clickedLegend = 'HRDPS' - break - case 4: - clickedLegend = 'Noon Forecasts' - break - case 5: - clickedLegend = 'Observation' - break - default: - break - } - - event.layout.shapes?.forEach(shape => { - if (clickedLegend && clickedLegend === shape.name) { - shape.visible = !shape.visible - } - }) - - return true - }} - data={[ - timeOfInterestLine, - gdpsData.windSpdLine, - rdpsData.windSpdLine, - hrdpsData.windSpdLine, - forecastData.windSpdLine, - observationData.windSpdLine - ]} - layout={{ - ...getLayoutConfig(`Wind Speed & Direction - ${station.properties.name} (${station.properties.code})`), - xaxis: { - range: sliderRange, - rangeslider: rangeSliderConfig, - hoverformat: '%I:00%p, %a, %b %e (PST)', // https://github.com/d3/d3-3.x-api-reference/blob/master/Time-Formatting.md#format - tickfont: { size: 14 }, - type: 'date', - dtick: 86400000.0 // Set the interval between ticks to one day: https://plotly.com/javascript/reference/#scatter-marker-colorbar-dtick - }, - yaxis: { - title: 'Wind Speed (km/h)', - tickfont: { size: 14 }, - fixedrange: true - }, - shapes: [ - ...gdpsData.windDirArrows, - ...rdpsData.windDirArrows, - ...hrdpsData.windDirArrows, - ...forecastData.windDirArrows, - ...observationData.windDirArrows - ] - }} - /> -
- ) -} - -export default React.memo(WindGraph) diff --git a/web/src/features/fireWeather/components/graphs/WxDataGraph.tsx b/web/src/features/fireWeather/components/graphs/WxDataGraph.tsx deleted file mode 100644 index db29118dc..000000000 --- a/web/src/features/fireWeather/components/graphs/WxDataGraph.tsx +++ /dev/null @@ -1,165 +0,0 @@ -import React, { useState } from 'react' -import { styled } from '@mui/material/styles' -import { DateTime } from 'luxon' - -import { GeoJsonStation } from 'api/stationAPI' -import { ModelSummary, ModelValue } from 'api/modelAPI' -import { ObservedValue } from 'api/observationAPI' -import { NoonForecastValue, ForecastSummary } from 'api/forecastAPI' -import WxDataGraphToggles from 'features/fireWeather/components/graphs/WxDataGraphToggles' -import { useGraphToggles } from 'features/fireWeather/components/graphs/useGraphToggles' -import PrecipitationGraph from 'features/fireWeather/components/graphs/PrecipitationGraph' -import WindGraph from 'features/fireWeather/components/graphs/WindGraph' -import TempRHGraph from 'features/fireWeather/components/graphs/TempRHGraph' -import { formatDatetimeInPST } from 'utils/date' -import { RedrawCommand } from 'features/map/Map' -import { SelectChangeEvent } from '@mui/material/Select' - -const PREFIX = 'WxDataGraph' - -const classes = { - display: `${PREFIX}-display` -} - -const Root = styled('div')({ - [`&.${classes.display}`]: { - paddingTop: 8 - } -}) - -interface Props { - station: GeoJsonStation - timeOfInterest: string - expandedOrCollapsed?: RedrawCommand - observations: ObservedValue[] | undefined - noonForecasts: NoonForecastValue[] | undefined - noonForecastSummaries: ForecastSummary[] | undefined - hrdpsModels: ModelValue[] | undefined - hrdpsSummaries: ModelSummary[] | undefined - rdpsModels: ModelValue[] | undefined - rdpsSummaries: ModelSummary[] | undefined - gdpsModels: ModelValue[] | undefined - gdpsSummaries: ModelSummary[] | undefined -} - -const WxDataGraph = ({ - station, - timeOfInterest, - expandedOrCollapsed, - observations = [], - noonForecasts = [], - noonForecastSummaries = [], - hrdpsModels = [], - hrdpsSummaries = [], - rdpsModels = [], - rdpsSummaries = [], - gdpsModels = [], - gdpsSummaries = [] -}: Props) => { - const hasObservations = observations.length !== 0 - const hasModels = gdpsModels.length !== 0 - const hasForecasts = noonForecasts.length !== 0 - const hasBiasAdjModels = - gdpsModels.filter(v => v.bias_adjusted_temperature || v.bias_adjusted_relative_humidity).length !== 0 - const hasHighResModels = hrdpsModels.length !== 0 - const hasRegionalModels = rdpsModels.length !== 0 - - /* Note: Plotly isn't updating its props in a correct way - * (Plot component may mutate its layout and data props in response to user input, going against React rules) https://github.com/plotly/react-plotly.js#api-reference - * This creates a weird/annoying behavior - Plotly modifying our state `sliderRange` directly, - * therefore state `sliderRange` automatically keeps track of the range change triggered by user interactions. - * (This is bad by the way since it makes impossible for us to capture the change of the state) - */ - const initialXAxisRange: [string, string] = [ - formatDatetimeInPST(DateTime.fromISO(timeOfInterest).minus({ days: 2 })), // prettier-ignore - formatDatetimeInPST(DateTime.fromISO(timeOfInterest).plus({ days: 2 })) // prettier-ignore - ] - const [sliderRange] = useState(initialXAxisRange) - - const [toggleValues, setToggleValues] = useGraphToggles({ - showObservations: hasObservations, - showForecasts: hasForecasts, - showHrdps: hasHighResModels, - showRdps: false, - showGdps: false, - showBiasAdjGdps: false - }) - - const [hoverMode, setHoverMode] = useState<'closest' | 'x' | 'x unified'>('closest') - - const handleHoverModeChange = (event: SelectChangeEvent) => { - switch (event.target.value) { - case 'closest': - case 'x': - case 'x unified': - setHoverMode(event.target.value) - } - } - - if (!hasObservations && !hasForecasts && !hasModels && !hasBiasAdjModels && !hasHighResModels && !hasRegionalModels) { - return null - } - - return ( - - - - - - - - - - ) -} - -export default React.memo(WxDataGraph) diff --git a/web/src/features/fireWeather/components/graphs/WxDataGraphToggles.tsx b/web/src/features/fireWeather/components/graphs/WxDataGraphToggles.tsx deleted file mode 100644 index 61a44648d..000000000 --- a/web/src/features/fireWeather/components/graphs/WxDataGraphToggles.tsx +++ /dev/null @@ -1,205 +0,0 @@ -import React from 'react' -import { styled } from '@mui/material/styles' -import Typography from '@mui/material/Typography' -import FormGroup from '@mui/material/FormGroup' -import FormControlLabel from '@mui/material/FormControlLabel' -import FormControl from '@mui/material/FormControl' -import Select, { SelectChangeEvent } from '@mui/material/Select' -import MenuItem from '@mui/material/MenuItem' -import Switch from '@mui/material/Switch' - -import { ToggleValues, SetToggleValues } from 'features/fireWeather/components/graphs/useGraphToggles' - -const PREFIX = 'WxDataGraphToggles' - -const classes = { - root: `${PREFIX}-root`, - switchControl: `${PREFIX}-switchControl`, - switchLabel: `${PREFIX}-switchLabel`, - selectControl: `${PREFIX}-selectControl` -} - -const StyledFormGroup = styled(FormGroup)({ - [`&.${classes.root}`]: { - marginBottom: 5 - }, - [`& .${classes.switchControl}`]: { - marginLeft: -5 - }, - [`& .${classes.switchLabel}`]: { - marginLeft: 2 - }, - [`& .${classes.selectControl}`]: { - minWidth: 85, - marginRight: 15 - } -}) - -interface Props { - toggleValues: ToggleValues - setToggleValues: SetToggleValues - hasObservations: boolean - hasModels: boolean - hasForecasts: boolean - hasBiasAdjModels: boolean - hasHighResModels: boolean - hasRegionalModels: boolean - handleHoverModeChange: (event: SelectChangeEvent) => void - hoverMode: 'closest' | 'x' | 'x unified' -} - -const WxDataToggles = ({ - toggleValues, - setToggleValues, - hasObservations, - hasModels, - hasForecasts, - hasBiasAdjModels, - hasHighResModels, - hasRegionalModels, - handleHoverModeChange, - hoverMode -}: Props) => { - const handleSwitch = (e: React.ChangeEvent<{ name: string }>, checked: boolean) => { - setToggleValues(e.target.name as keyof ToggleValues, checked) - } - - return ( - - - } - label={ - - Observations - - } - /> - - - } - label={ - - Noon Forecasts - - } - /> - - - } - label={ - - HRDPS - - } - /> - - - } - label={ - - RDPS - - } - /> - - - } - label={ - - GDPS - - } - /> - - - } - label={ - - Bias Adjusted GDPS - - } - /> - -
- - Hover mode:{' '} - - - - -
-
- ) -} - -export default React.memo(WxDataToggles) diff --git a/web/src/features/fireWeather/components/graphs/plotlyHelper.ts b/web/src/features/fireWeather/components/graphs/plotlyHelper.ts deleted file mode 100644 index 36737c486..000000000 --- a/web/src/features/fireWeather/components/graphs/plotlyHelper.ts +++ /dev/null @@ -1,664 +0,0 @@ -import { DateTime } from 'luxon' -import { Data, Shape, Layout, RangeSlider, PlotData, BoxPlotData } from 'plotly.js' -import { WIND_SPEED_VALUES_DECIMAL, PST_UTC_OFFSET } from 'utils/constants' -import { formatWindDirection } from 'utils/format' -import { formatDatetimeInPST } from 'utils/date' - -export const findMaxNumber = (arr: number[]): number => { - if (arr.length === 0) { - return 0 - } - - return Math.max(...arr) -} - -export const findMinNumber = (arr: number[]): number => { - if (arr.length === 0) { - return 0 - } - - return Math.min(...arr) -} - -export const rangeSliderConfig: Partial = { - visible: true, - bgcolor: '#dbdbdb', - thickness: 0.1 -} - -export const getLayoutConfig = (title: string): Partial => ({ - dragmode: 'pan', - autosize: true, - height: 600, - margin: { pad: 10 }, - legend: { orientation: 'h', yanchor: 'top', y: -0.35, traceorder: 'reversed' }, // Locate the legend at the bottom of the graph - title: { - text: title, - yanchor: 'middle' - } -}) - -export const populateTimeOfInterestLineData = (x: string, y0: number, y1: number, yaxis?: string): Data => { - return { - x: [x, x], - y: [y0, y1], - mode: 'lines', - name: 'Time of Interest', - line: { - color: 'green', - width: 2, - dash: 'dot' - }, - showlegend: true, - hoverinfo: 'skip', - yaxis - } -} - -/* -------------------------- Temp & RH -------------------------- */ - -interface TempRHValue { - datetime: string - temperature?: number | null - relative_humidity?: number | null - dewpoint?: number | null - tmp_tgl_2_5th?: number - tmp_tgl_2_90th?: number - rh_tgl_2_5th?: number - rh_tgl_2_90th?: number - tmp_max?: number - tmp_min?: number - rh_max?: number - rh_min?: number - bias_adjusted_temperature?: number | null - bias_adjusted_relative_humidity?: number | null -} - -export interface TempRHGraphProperties { - values: TempRHValue[] - tempName: string - rhName: string - show: boolean - symbol: string - dash: 'solid' | 'dot' | 'dash' | 'longdash' | 'dashdot' | 'longdashdot' - tempColor: string - rhColor: string - dewpointName?: string - dewpointColor?: string - tempPlumeColor?: string - rhPlumeColor?: string -} - -export const populateGraphDataForTempAndRH = ( - graphProps: TempRHGraphProperties -): { - tempDots: Partial - tempVerticalLines: Data[] - biasAdjTempLine: Partial - tempLine: Partial - temp5thLine: Partial - temp90thLine: Partial - rhDots: Partial - rhVerticalLines: Data[] - biasAdjRHLine: Partial - rhLine: Partial - rh5thLine: Partial - rh90thLine: Partial - dewpointDots: Partial - dewpointLine: Partial - maxTempDewpoint: number - minTempDewpoint: number -} => { - const tempDates: string[] = [] - const rhDates: string[] = [] - const dewpointDates: string[] = [] - const tempValues: number[] = [] - const rhValues: number[] = [] - const dewpointValues: number[] = [] - - const tempMinMaxDates: string[] = [] - const tempMinMaxValues: [number, number][] = [] - const rhMinMaxDates: string[] = [] - const rhMinMaxValues: [number, number][] = [] - - const tempPercentileDates: string[] = [] - const temp5thValues: number[] = [] - const temp90thValues: number[] = [] - const rhPercentileDates: string[] = [] - const rh5thValues: number[] = [] - const rh90thValues: number[] = [] - const biasAdjTempDates: string[] = [] - const biasAdjRHDates: string[] = [] - const biasAdjTempValues: number[] = [] - const biasAdjRHValues: number[] = [] - - graphProps.values.forEach(value => { - const { - datetime, - temperature, - relative_humidity, - dewpoint, - tmp_max, - tmp_min, - rh_max, - rh_min, - tmp_tgl_2_5th, - tmp_tgl_2_90th, - rh_tgl_2_5th, - rh_tgl_2_90th, - bias_adjusted_temperature, - bias_adjusted_relative_humidity - } = value - const date = formatDatetimeInPST(datetime) - - if (temperature != null) { - tempDates.push(date) - tempValues.push(temperature) - } - if (relative_humidity != null) { - rhDates.push(date) - rhValues.push(relative_humidity) - } - if (dewpoint != null) { - dewpointDates.push(date) - dewpointValues.push(dewpoint) - } - - // From forecast min & max - if (tmp_min && tmp_max) { - tempMinMaxDates.push(date) - tempMinMaxValues.push([tmp_min, tmp_max]) - } - if (rh_min && rh_max) { - rhMinMaxDates.push(date) - rhMinMaxValues.push([rh_min, rh_max]) - } - - // From model summaries - if (tmp_tgl_2_5th && tmp_tgl_2_90th) { - tempPercentileDates.push(date) - temp5thValues.push(tmp_tgl_2_5th) - temp90thValues.push(tmp_tgl_2_90th) - } - if (rh_tgl_2_5th && rh_tgl_2_90th) { - rhPercentileDates.push(date) - rh5thValues.push(rh_tgl_2_5th) - rh90thValues.push(rh_tgl_2_90th) - } - - // From bias adjusted models - if (bias_adjusted_temperature != null) { - biasAdjTempDates.push(date) - biasAdjTempValues.push(bias_adjusted_temperature) - } - if (bias_adjusted_relative_humidity != null) { - biasAdjRHDates.push(date) - biasAdjRHValues.push(bias_adjusted_relative_humidity) - } - }) - - const tempDots: Data = { - x: graphProps.show ? tempDates : [], - y: graphProps.show ? tempValues : [], - name: graphProps.tempName, - mode: 'markers', - type: 'scatter', - marker: { color: graphProps.tempColor, symbol: graphProps.symbol }, - hovertemplate: `%{y:.2f} (°C)${graphProps.tempName}, %{x}` - } - const tempVerticalLines: Data[] = tempMinMaxDates.map((date, idx) => ({ - x: graphProps.show ? [date, date] : [], - y: graphProps.show ? tempMinMaxValues[idx] : [], // Temp min & max pair - mode: 'lines', - name: graphProps.tempName, - line: { - color: graphProps.tempColor, - width: 3 - }, - hoverinfo: 'skip', - showlegend: false - })) - const biasAdjTempLine: Data = { - x: graphProps.show ? biasAdjTempDates : [], - y: graphProps.show ? biasAdjTempValues : [], - name: graphProps.tempName, - mode: 'lines+markers', - type: 'scatter', - marker: { symbol: graphProps.symbol }, - line: { - color: graphProps.tempColor, - width: 2, - dash: graphProps.dash - }, - hovertemplate: `%{y:.2f} (°C)${graphProps.tempName}, %{x}` - } - const tempLine: Data = { - x: graphProps.show ? tempDates : [], - y: graphProps.show ? tempValues : [], - name: graphProps.tempName, - mode: 'lines+markers', - type: 'scatter', - marker: { symbol: graphProps.symbol }, - line: { - color: graphProps.tempColor, - width: 2, - dash: graphProps.dash - }, - hovertemplate: `%{y:.2f} (°C)${graphProps.tempName}, %{x}` - } - const temp5thLine: Data = { - x: graphProps.show ? tempPercentileDates : [], - y: graphProps.show ? temp5thValues : [], - name: `${graphProps.tempName} 5th percentile`, - mode: 'lines', - type: 'scatter', - line: { width: 0 }, - marker: { color: '444' }, - hoverinfo: 'skip', - showlegend: false - } - const temp90thLine: Data = { - x: graphProps.show ? tempPercentileDates : [], - y: graphProps.show ? temp90thValues : [], - name: `${graphProps.tempName} 5th - 90th percentile`, - mode: 'lines', - type: 'scatter', - line: { width: 0 }, - marker: { color: '444' }, - fill: 'tonexty', - fillcolor: graphProps.tempPlumeColor, - hoverinfo: 'skip' - } - - const dewpointDots: Data = { - x: graphProps.show ? dewpointDates : [], - y: graphProps.show ? dewpointValues : [], - name: graphProps.dewpointName, - mode: 'markers', - type: 'scatter', - marker: { color: graphProps.dewpointColor, symbol: graphProps.symbol }, - hovertemplate: `%{y:.2f} (°C)${graphProps.dewpointName}, %{x}` - } - const dewpointLine: Data = { - x: graphProps.show ? dewpointDates : [], - y: graphProps.show ? dewpointValues : [], - name: graphProps.dewpointName, - mode: 'lines+markers', - type: 'scatter', - marker: { symbol: graphProps.symbol }, - line: { - color: graphProps.dewpointColor, - width: 2, - dash: graphProps.dash - }, - hovertemplate: `%{y:.2f} (°C)${graphProps.dewpointName}, %{x}` - } - - const rhDots: Data = { - x: graphProps.show ? rhDates : [], - y: graphProps.show ? rhValues : [], - name: graphProps.rhName, - yaxis: 'y2', - mode: 'markers', - type: 'scatter', - showlegend: graphProps.show, - marker: { color: graphProps.rhColor, symbol: graphProps.symbol }, - hovertemplate: `%{y:.2f} (%)${graphProps.rhName}, %{x}` - } - const rhVerticalLines: Data[] = rhMinMaxDates.map((date, idx) => ({ - x: graphProps.show ? [date, date] : [], - y: graphProps.show ? rhMinMaxValues[idx] : [], // Temp min & max pair - mode: 'lines', - name: graphProps.rhName, - yaxis: 'y2', - line: { - color: graphProps.rhColor, - width: 3 - }, - hoverinfo: 'skip', - showlegend: false - })) - const biasAdjRHLine: Data = { - x: graphProps.show ? biasAdjRHDates : [], - y: graphProps.show ? biasAdjRHValues : [], - name: graphProps.rhName, - yaxis: 'y2', - mode: 'lines+markers', - type: 'scatter', - marker: { symbol: graphProps.symbol }, - line: { - color: graphProps.rhColor, - width: 2, - dash: graphProps.dash - }, - hovertemplate: `%{y:.2f} (%)${graphProps.rhName}, %{x}` - } - const rhLine: Data = { - x: graphProps.show ? rhDates : [], - y: graphProps.show ? rhValues : [], - name: graphProps.rhName, - yaxis: 'y2', - mode: 'lines+markers', - type: 'scatter', - marker: { symbol: graphProps.symbol }, - line: { - color: graphProps.rhColor, - width: 2, - dash: graphProps.dash - }, - hovertemplate: `%{y:.2f} (%)${graphProps.rhName}, %{x}` - } - const rh5thLine: Data = { - x: graphProps.show ? rhPercentileDates : [], - y: graphProps.show ? rh5thValues : [], - name: `${graphProps.rhName} 5th percentile`, - yaxis: 'y2', - mode: 'lines', - type: 'scatter', - line: { width: 0 }, - marker: { color: '444' }, - hoverinfo: 'skip', - showlegend: false - } - const rh90thLine: Data = { - x: graphProps.show ? rhPercentileDates : [], - y: graphProps.show ? rh90thValues : [], - name: `${graphProps.rhName} 5th - 90th percentile`, - yaxis: 'y2', - mode: 'lines', - type: 'scatter', - line: { width: 0 }, - marker: { color: '444' }, - fill: 'tonexty', - fillcolor: graphProps.rhPlumeColor, - hoverinfo: 'skip' - } - - const maxTempDewpoint = findMaxNumber([...tempValues, ...dewpointValues]) - const minTempDewpoint = findMinNumber([...tempValues, ...dewpointValues]) - - return { - tempDots, - tempVerticalLines, - biasAdjTempLine, - tempLine, - temp5thLine, - temp90thLine, - rhDots, - rhVerticalLines, - biasAdjRHLine, - rhLine, - rh5thLine, - rh90thLine, - dewpointDots, - dewpointLine, - maxTempDewpoint, - minTempDewpoint - } -} - -/* -------------------------- Precipitation -------------------------- */ - -const getMidnightDate = (formattedDate: string): string => { - return DateTime.fromISO(formattedDate) - .setZone(`UTC${PST_UTC_OFFSET}`) - .set({ hour: 0, minute: 0 }) - .toFormat('yyyy-MM-dd HH:mm') -} - -interface PrecipValue { - datetime: string - precipitation?: number | null - delta_precipitation?: number | null - total_precipitation?: number | null -} - -export const getDailyAndAccumPrecips = ( - values: PrecipValue[] -): { - dates: string[] - dailyPrecips: number[] - accumPrecips: number[] -} => { - const dates: string[] = [] - const dailyPrecips: number[] = [] - const shouldAggregate = - values.length > 0 && (values[0].precipitation !== undefined || values[0].delta_precipitation !== undefined) - - // if the type of the value is observation or one of weather models, then aggregate hourly data to daily - if (shouldAggregate) { - const aggregatedPrecips: { [k: string]: number } = {} - values.forEach(({ datetime, precipitation, delta_precipitation }) => { - const date = DateTime.fromISO(datetime).setZone(`UTC${PST_UTC_OFFSET}`).toFormat('yyyy-MM-dd') - let precip = 0 - - if (precipitation != null) { - precip = precipitation - } else if (delta_precipitation != null) { - precip = delta_precipitation - } - - if (!aggregatedPrecips[date]) { - aggregatedPrecips[date] = precip - } else { - aggregatedPrecips[date] = aggregatedPrecips[date] + precip - } - }) - - Object.entries(aggregatedPrecips).forEach(([formattedDate, totalPrecip]) => { - const midnightOfTheDay = getMidnightDate(formattedDate) - dates.push(midnightOfTheDay) - dailyPrecips.push(totalPrecip) - }) - } else { - values.forEach(({ datetime, total_precipitation }) => { - if (total_precipitation !== undefined) { - const midnightOfTheDay = getMidnightDate(datetime) - dates.push(midnightOfTheDay) - dailyPrecips.push(Number(total_precipitation)) - } - }) - } - - // Create a list of accumulated precips for each day in time - const accumPrecips: number[] = [] - dailyPrecips.forEach((daily, idx) => { - if (idx === 0) { - return accumPrecips.push(daily) - } - - const prevAccum = accumPrecips[accumPrecips.length - 1] - accumPrecips.push(prevAccum + daily) - }) - - return { dates, dailyPrecips, accumPrecips } -} - -export const populateGraphDataForPrecip = ( - values: PrecipValue[], - name: string, - color: string, - show: boolean -): { - dailyPrecipsBar: Partial - accumPrecipsline: Partial | Partial - maxAccumPrecip: number -} => { - const { dates, dailyPrecips, accumPrecips } = getDailyAndAccumPrecips(values) - - const dailyPrecipsBar: Data = { - x: show ? dates : [], - y: show ? dailyPrecips : [], - name, - type: 'bar', - marker: { - color: show ? color : 'transparent' - }, - hoverinfo: show ? 'y' : 'skip', - hovertemplate: show ? `${name}: %{y:.2f} (mm)` : undefined - } - - const accumPrecipsline: Data = { - x: show ? dates : [], - y: show ? accumPrecips : [], - name: `Accumulated ${name}`, - mode: 'lines', - yaxis: 'y2', - marker: { - color - }, - line: { - width: 2.5 - }, - hoverinfo: 'y', - hovertemplate: show ? `Accumulated ${name}: %{y:.2f} (mm)` : undefined - } - - const maxAccumPrecip = findMaxNumber(accumPrecips) - - return { - dailyPrecipsBar, - accumPrecipsline, - maxAccumPrecip - } -} - -/* -------------------------- Wind -------------------------- */ - -/** - * Basic arrow shape (before any transformations) - * - * "front" - * ^ - * / \ - * "leftEnd" / | \ "rightEnd" - * | - * | - * | - * "back" - * - */ -type Point = [number, number] -const front: Point = [0, 8] -const back: Point = [0, -10] -const leftEnd: Point = [5, 0] -const rightEnd: Point = [-5, 0] -const arrowPoints = [front, back, leftEnd, rightEnd] - -const buildArrowShapePath = (arrowShape: Point[]): string => { - return `M${arrowShape[0][0]} ${arrowShape[0][1]} \ - L${arrowShape[2][0]} ${arrowShape[2][1]} \ - M${arrowShape[0][0]} ${arrowShape[0][1]} \ - L${arrowShape[3][0]} ${arrowShape[3][1]} \ - M${arrowShape[0][0]} ${arrowShape[0][1]} \ - L${arrowShape[1][0]} ${arrowShape[1][1]}` -} - -const rotatePoints = (points: Point[], angle: number, cw = true): Point[] => { - /** - * https://academo.org/demos/rotation-about-point/ - * To rotate points around the origin, - * to coordinates of the new point would be located at (x',y') - * - * x' = xcos(theta) - ysin(theta) - * y' = ycos(theta) + xsin(theta) - * - * Where theta is the angle of rotation - */ - - // We need to rotate the arrow by 180 degrees (the degrees indiciate the origin of the wind, - // not the direction) - let theta = (Math.PI / 180) * ((angle + 180) % 360) // Turn the angle(number) into degree - - if (cw) { - theta = -theta - } - - return points.map(point => [ - point[0] * Math.cos(theta) - point[1] * Math.sin(theta), - point[1] * Math.cos(theta) + point[0] * Math.sin(theta) - ]) -} - -const createPath = ( - arrowShape: Point[], - name: string, - show: boolean, - datetime: string, - wind_speed: number, - colour: string -): Partial => { - return { - type: 'path', - path: buildArrowShapePath(arrowShape), - visible: show, - layer: 'above', - name, - xref: 'x', // By setting a reference to the wind spd scale (x & y), - yref: 'y', // we can position these arrows with wind spd values using xanchor & yanchor - xsizemode: 'pixel', // https://plotly.com/javascript/reference/layout/shapes/#layout-shapes-items-shape-xsizemode - ysizemode: 'pixel', - xanchor: formatDatetimeInPST(datetime), - yanchor: wind_speed, - line: { - color: show ? colour : 'transparent' - } - } -} - -interface WindValue { - datetime: string - wind_direction?: number | null - wind_speed?: number | null -} - -export const populateGraphDataForWind = ( - values: WindValue[], - name: string, - show: boolean, - lineColor: string, - arrowColor: string -): { - windSpdLine: Partial - windDirArrows: Partial[] - maxWindSpd: number - minWindSpd: number -} => { - const dates: string[] = [] - const windSpds: number[] = [] - const windSpdsTexts: string[] = [] - const windDirArrows: Partial[] = [] - - values.forEach(({ wind_direction, wind_speed, datetime }) => { - if (wind_speed != null) { - dates.push(formatDatetimeInPST(datetime)) - windSpds.push(wind_speed) - windSpdsTexts.push(wind_direction != null ? `${formatWindDirection(wind_direction)}` : '-') - - if (wind_direction != null && show) { - const arrowShape = rotatePoints(arrowPoints, wind_direction) - const path = createPath(arrowShape, name, show, datetime, wind_speed, arrowColor) - windDirArrows.push(path) - } - } - }) - - const windSpdLine: Data = { - x: show ? dates : [], - y: show ? windSpds : [], - name, - mode: 'lines', - type: 'scatter', - line: { - color: lineColor, - width: 2 - }, - text: windSpdsTexts, - hovertemplate: `${name}: %{y:.${WIND_SPEED_VALUES_DECIMAL}f} km/h, %{text}°` - } - - const maxWindSpd = findMaxNumber(windSpds) - const minWindSpd = findMinNumber(windSpds) - - return { windSpdLine, windDirArrows, maxWindSpd, minWindSpd } -} diff --git a/web/src/features/fireWeather/components/graphs/useGraphToggles.ts b/web/src/features/fireWeather/components/graphs/useGraphToggles.ts deleted file mode 100644 index f048c44f3..000000000 --- a/web/src/features/fireWeather/components/graphs/useGraphToggles.ts +++ /dev/null @@ -1,27 +0,0 @@ -// Custom React Hook for the temp & rh graph toggle state -import { useState } from 'react' - -export interface ToggleValues { - showObservations: boolean - showGdps: boolean - showForecasts: boolean - showBiasAdjGdps: boolean - showHrdps: boolean - showRdps: boolean -} - -export type SetToggleValues = (key: keyof ToggleValues, value: ValueOf) => void - -export const useGraphToggles = (initialValues: ToggleValues): [ToggleValues, SetToggleValues] => { - const [values, setValues] = useState(initialValues) - - return [ - values, - (key, value) => { - setValues(prevValues => ({ - ...prevValues, - [key]: value - })) - } - ] -} diff --git a/web/src/features/fireWeather/components/tables/ComparisonTableRow.tsx b/web/src/features/fireWeather/components/tables/ComparisonTableRow.tsx deleted file mode 100644 index 6e9a01656..000000000 --- a/web/src/features/fireWeather/components/tables/ComparisonTableRow.tsx +++ /dev/null @@ -1,348 +0,0 @@ -import React, { ReactElement } from 'react' -import { styled } from '@mui/material/styles' -import TableCell from '@mui/material/TableCell' -import TableRow from '@mui/material/TableRow' -import ToolTip from '@mui/material/Tooltip' -import { ModelValue } from 'api/modelAPI' -import { NoonForecastValue } from 'api/forecastAPI' -import { ObservedValue } from 'api/observationAPI' -import { - formatWindDirection as formatWindDirectionValue, - formatWindSpeed as formatWindSpeedValue, - formatTemperature as formatTemperatureValue, - formatForecastWindSpeed as formatForecastWindSpeedValue, - formatRelativeHumidity as formatRelativeHumidityValue, - formatPrecipitation as formatPrecipitationValue, - formatDewPoint as formatDewPointValue -} from 'utils/format' -import { AccumulatedPrecipitation } from 'utils/table' - -const PREFIX = 'ComparisonTableRow' - -const classes = { - paper: `${PREFIX}-paper`, - lightColumnHeader: `${PREFIX}-lightColumnHeader`, - darkColumnHeader: `${PREFIX}-darkColumnHeader`, - darkColumn: `${PREFIX}-darkColumn`, - lightColumn: `${PREFIX}-lightColumn`, - windSpeedValue: `${PREFIX}-windSpeedValue`, - relativeHumidityValue: `${PREFIX}-relativeHumidityValue`, - windDirectionValue: `${PREFIX}-windDirectionValue`, - precipitationValue: `${PREFIX}-precipitationValue` -} - -const StyledTableRow = styled(TableRow)({ - [`& .${classes.paper}`]: { - width: '100%' - }, - [`& .${classes.lightColumnHeader}`]: { - textAlign: 'center', - padding: '2px', - minWidth: '60px' - }, - [`& .${classes.darkColumnHeader}`]: { - backgroundColor: 'rgb(240, 240, 240)', - textAlign: 'center', - padding: '2px', - minWidth: '60px' - }, - [`& .${classes.darkColumn}`]: { - backgroundColor: '#fafafa', - padding: '2px', - paddingRight: '6px', - textAlign: 'right' - }, - [`& .${classes.lightColumn}`]: { - textAlign: 'right', - padding: '2px', - paddingRight: '6px' - }, - [`& .${classes.windSpeedValue}`]: { - whiteSpace: 'nowrap' - }, - [`& .${classes.relativeHumidityValue}`]: { - whiteSpace: 'nowrap' - }, - [`& .${classes.windDirectionValue}`]: { - whiteSpace: 'nowrap' - }, - [`& .${classes.precipitationValue}`]: { - whiteSpace: 'nowrap' - } -}) - -export type DataSource = 'Observed' | 'Forecast' | 'HRDPS' | 'RDPS' | 'GDPS' - -export type WeatherVariable = - | 'Temperature' - | 'Relative Humidity' - | 'Wind Speed' - | 'Wind Direction' - | 'Precipitation' - | 'Dew point' - -interface CellFormattingInfo { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - formatFn: (source: any, valueClassName: string[]) => ReactElement | void - data: NoonForecastValue | ObservedValue | ModelValue | AccumulatedPrecipitation | number | undefined - styling: string[] -} - -interface Props { - index: ReactElement - headers: WeatherVariable[] - subheaders: DataSource[][] - forecast?: NoonForecastValue - observation?: ObservedValue - accumulatedObsPrecip?: AccumulatedPrecipitation - highResModel?: ModelValue - accumulatedHRDPSPrecip?: AccumulatedPrecipitation - regionalModel?: ModelValue - accumulatedRDPSPrecip?: AccumulatedPrecipitation - globalModel?: ModelValue - accumulatedGDPSPrecip?: AccumulatedPrecipitation - testId?: string - testIdRowNumber?: number -} - -const formatWindSpeedForecast = (source: NoonForecastValue | undefined, valueClassName: string[]): ReactElement => { - return
{formatForecastWindSpeedValue(source?.wind_speed)}
-} - -const formatWindSpeed = (source: ObservedValue | ModelValue | undefined, valueClassName: string[]): ReactElement => { - return
{formatWindSpeedValue(source?.wind_speed)}
-} - -const formatWindDirection = ( - source: NoonForecastValue | ObservedValue | ModelValue | undefined, - valueClassName: string[] -): ReactElement => { - return
{formatWindDirectionValue(source?.wind_direction)}
-} - -const formatTemperature = (source: NoonForecastValue | ObservedValue | ModelValue | undefined): ReactElement => { - return
{formatTemperatureValue(source?.temperature)}
-} - -const formatRelativeHumidity = ( - source: NoonForecastValue | ObservedValue | ModelValue | undefined, - valueClassName: string[] -): ReactElement => { - return
{formatRelativeHumidityValue(source?.relative_humidity)}
-} - -const formatPrecipitation = (precipitation: number | null | undefined, valueClassName: string[]): ReactElement => { - return
{formatPrecipitationValue(precipitation)}
-} - -const formatDewPoint = (observation: ObservedValue | undefined) => { - const dewpoint = observation?.dewpoint - return
{formatDewPointValue(dewpoint)}
-} - -const formatModelTemperature = (source: ModelValue): ReactElement => { - if (source === undefined) { - return
- } - const tooltip = source.model_run_datetime - return ( - source && ( - - {formatTemperature(source)} - - ) - ) -} - -const formatModelRelativeHumidity = (source: ModelValue | undefined, valueClassName: string[]): ReactElement => { - const tooltip = (source as ModelValue)?.model_run_datetime - return ( - - {formatRelativeHumidity(source, valueClassName)} - - ) -} - -const formatAccumulatedPrecipitation = ( - precipitation: AccumulatedPrecipitation, - precipitationClassName: string[] -): ReactElement => { - const title: JSX.Element[] = [] - precipitation?.values.forEach((value, index) => { - if ('delta_precipitation' in value && 'model_run_datetime' in value) { - title.push( -
- prediction: {value.datetime}, precipitation: {formatPrecipitationValue(value.delta_precipitation)} (model:{' '} - {value.model_run_datetime}) -
- ) - } else if ('precipitation' in value) { - title.push( -
- observation: {value.datetime}, precipitation: {formatPrecipitationValue(value.precipitation)} -
- ) - } - }) - return ( - -
{formatPrecipitationValue(precipitation?.precipitation)}
-
- ) -} - -const ComparisonTableRow = (props: Props) => { - const formattingMap: Record> = { - Temperature: { - Observed: { formatFn: formatTemperature, data: props.observation, styling: [] }, - Forecast: { formatFn: formatTemperature, data: props.forecast, styling: [] }, - HRDPS: { formatFn: formatModelTemperature, data: props.highResModel, styling: [] }, - RDPS: { formatFn: formatModelTemperature, data: props.regionalModel, styling: [] }, - GDPS: { formatFn: formatModelTemperature, data: props.globalModel, styling: [] } - }, - 'Relative Humidity': { - Observed: { - formatFn: formatRelativeHumidity, - data: props.observation, - styling: [classes.relativeHumidityValue] - }, - Forecast: { - formatFn: formatRelativeHumidity, - data: props.forecast, - styling: [classes.relativeHumidityValue] - }, - HRDPS: { - formatFn: formatModelRelativeHumidity, - data: props.highResModel, - styling: [classes.relativeHumidityValue] - }, - RDPS: { - formatFn: formatModelRelativeHumidity, - data: props.regionalModel, - styling: [classes.relativeHumidityValue] - }, - GDPS: { - formatFn: formatModelRelativeHumidity, - data: props.globalModel, - styling: [classes.relativeHumidityValue] - } - }, - 'Wind Speed': { - Observed: { - formatFn: formatWindSpeed, - data: props.observation, - styling: [classes.windSpeedValue] - }, - Forecast: { - formatFn: formatWindSpeedForecast, - data: props.forecast, - styling: [classes.windSpeedValue] - }, - HRDPS: { - formatFn: formatWindSpeed, - data: props.highResModel, - styling: [classes.windSpeedValue] - }, - RDPS: { - formatFn: formatWindSpeed, - data: props.regionalModel, - styling: [classes.windSpeedValue] - }, - GDPS: { - formatFn: formatWindSpeed, - data: props.globalModel, - styling: [classes.windSpeedValue] - } - }, - 'Wind Direction': { - Observed: { - formatFn: formatWindDirection, - data: props.observation, - styling: [classes.windDirectionValue] - }, - Forecast: { - formatFn: formatWindDirection, - data: props.forecast, - styling: [classes.windDirectionValue] - }, - HRDPS: { - formatFn: formatWindDirection, - data: props.highResModel, - styling: [classes.windDirectionValue] - }, - RDPS: { - formatFn: formatWindDirection, - data: props.regionalModel, - styling: [classes.windDirectionValue] - }, - GDPS: { - formatFn: formatWindDirection, - data: props.globalModel, - styling: [classes.windDirectionValue] - } - }, - Precipitation: { - Observed: { - formatFn: formatAccumulatedPrecipitation, - data: props.accumulatedObsPrecip, - styling: [classes.precipitationValue] - }, - Forecast: { - formatFn: formatPrecipitation, - data: props.forecast?.total_precipitation, - styling: [classes.precipitationValue] - }, - HRDPS: { - formatFn: formatAccumulatedPrecipitation, - data: props.accumulatedHRDPSPrecip, - styling: [classes.precipitationValue] - }, - RDPS: { - formatFn: formatAccumulatedPrecipitation, - data: props.accumulatedRDPSPrecip, - styling: [classes.precipitationValue] - }, - GDPS: { - formatFn: formatAccumulatedPrecipitation, - data: props.accumulatedGDPSPrecip, - styling: [classes.precipitationValue] - } - }, - 'Dew point': { - Observed: { formatFn: formatDewPoint, data: props.observation, styling: [] }, - Forecast: { formatFn: () => undefined, data: undefined, styling: [] }, - HRDPS: { formatFn: () => undefined, data: undefined, styling: [] }, - RDPS: { formatFn: () => undefined, data: undefined, styling: [] }, - GDPS: { formatFn: () => undefined, data: undefined, styling: [] } - } - } - - return ( - - {props.index} - {props.headers.map((variable: WeatherVariable, idx: number) => { - const colStyle = idx % 2 === 0 ? classes.darkColumn : classes.lightColumn - return props.subheaders[idx].map((source: DataSource) => { - const formattingInfo = formattingMap[variable][source] - const cellContent = formattingInfo.formatFn(formattingInfo.data, formattingInfo.styling) - - if (cellContent instanceof Object) { - return ( - - {cellContent} - - ) - } else { - return null - } - }) - })} - - ) -} - -export default React.memo(ComparisonTableRow) diff --git a/web/src/features/fireWeather/components/tables/NoonForecastTable.tsx b/web/src/features/fireWeather/components/tables/NoonForecastTable.tsx deleted file mode 100644 index 1e61f2ad9..000000000 --- a/web/src/features/fireWeather/components/tables/NoonForecastTable.tsx +++ /dev/null @@ -1,206 +0,0 @@ -import React, { useState } from 'react' -import { styled } from '@mui/material/styles' - -import { NoonForecastValue } from 'api/forecastAPI' -import { formatDatetimeInPST, formatDateInUTC00Suffix } from 'utils/date' -import { - Accordion, - AccordionDetails, - AccordionSummary, - Paper, - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableRow, - TableSortLabel, - Typography -} from '@mui/material' -import { ObservedValue } from 'api/observationAPI' -import { getDatetimeComparator, Order, calculateAccumulatedPrecip } from 'utils/table' -import ExpandMoreIcon from '@mui/icons-material/ExpandMore' -import ComparisonTableRow, { DataSource, WeatherVariable } from './ComparisonTableRow' - -const PREFIX = 'NoonForecastTable' - -const classes = { - paper: `${PREFIX}-paper`, - typography: `${PREFIX}-typography`, - lightColumnHeader: `${PREFIX}-lightColumnHeader`, - lightColumn: `${PREFIX}-lightColumn`, - windSpeedValue: `${PREFIX}-windSpeedValue`, - relativeHumidityValue: `${PREFIX}-relativeHumidityValue`, - windDirectionValue: `${PREFIX}-windDirectionValue`, - precipitationValue: `${PREFIX}-precipitationValue`, - darkColumn: `${PREFIX}-darkColumn`, - darkColumnHeader: `${PREFIX}-darkColumnHeader` -} - -const StyledAccordion = styled(Accordion)({ - [`& .${classes.paper}`]: { - padding: '5px', - // There's a formating issues that causes the last cell in the table to be cut off - // when in 100%, on a small screen. Setting the width to 95% is a workaround, as the - // true source of the problem remains a mystery. (suspicion: it's something to do with using - // flex boxes, and having a table that needs to scroll.) - width: '95%' - }, - [`& .${classes.typography}`]: {}, - [`& .${classes.lightColumnHeader}`]: { - textAlign: 'center', - padding: '2px', - minWidth: '60px' - }, - [`& .${classes.lightColumn}`]: { - textAlign: 'right', - padding: '2px' - }, - [`& .${classes.windSpeedValue}`]: { - whiteSpace: 'nowrap' - }, - [`& .${classes.relativeHumidityValue}`]: { - whiteSpace: 'nowrap' - }, - [`& .${classes.windDirectionValue}`]: { - whiteSpace: 'nowrap' - }, - [`& .${classes.precipitationValue}`]: { - whiteSpace: 'nowrap' - }, - [`& .${classes.darkColumn}`]: { - backgroundColor: '#fafafa', - padding: '2px', - textAlign: 'right' - }, - [`& .${classes.darkColumnHeader}`]: { - backgroundColor: 'rgb(240, 240, 240)', - textAlign: 'center', - padding: '2px', - minWidth: '60px' - } -}) - -interface NoonForecastTableProps { - testId?: string - noonForecasts: NoonForecastValue[] | undefined - noonObservations: ObservedValue[] | undefined -} - -const NoonForecastTable = (props: NoonForecastTableProps) => { - const [order, setOrder] = useState('desc') - - if (props.noonForecasts === undefined || props.noonObservations === undefined) { - return null - } - - if (props.noonForecasts.length === 0 && props.noonObservations.length === 0) { - return null - } - - const forecastRowsSortedByDatetime = [...props.noonForecasts].sort(getDatetimeComparator(order)) - const observationsRowsSortedByDatetime = [...props.noonObservations].sort(getDatetimeComparator(order)) - const toggleDatetimeOrder = () => { - setOrder(order === 'asc' ? 'desc' : 'asc') - } - const headers: WeatherVariable[] = [ - 'Temperature', - 'Relative Humidity', - 'Wind Speed', - 'Wind Direction', - 'Precipitation' - ] - const subheaders: DataSource[][] = [ - ['Forecast', 'Observed'], - ['Forecast', 'Observed'], - ['Forecast', 'Observed'], - ['Forecast', 'Observed'], - ['Forecast', 'Observed'] - ] - - return ( - - }> - - Forecast and Observed noon weather: - - - - - - - - - - - Temperature (°C) - - - Relative Humidity (%) - - - Wind Speed (km/h) - - - Wind Direction (°) - - - Precipitation (mm) - - - - - - Date (PST) - - - {/* Temperature */} - FCST - OBS - {/* Relative Humidity */} - FCST - OBS - {/* Wind Speed */} - FCST - OBS - {/* Wind Direction */} - FCST - OBS - {/* Precip */} - FCST - OBS - - - - {forecastRowsSortedByDatetime.map((forecast: NoonForecastValue, idx: number) => { - const observation = observationsRowsSortedByDatetime.find(obs => obs.datetime === forecast.datetime) - const forecastDatetime = formatDateInUTC00Suffix(forecast.datetime) - - const accumPrecip = calculateAccumulatedPrecip(forecastDatetime, observationsRowsSortedByDatetime) - - const indexCell = {formatDatetimeInPST(forecast.datetime)} - - return ( - - ) - })} - -
-
-
-
-
- ) -} - -export default React.memo(NoonForecastTable) diff --git a/web/src/features/fireWeather/components/tables/NoonWxValueTables.tsx b/web/src/features/fireWeather/components/tables/NoonWxValueTables.tsx deleted file mode 100644 index 30c544113..000000000 --- a/web/src/features/fireWeather/components/tables/NoonWxValueTables.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import React from 'react' - -import { ModelValue } from 'api/modelAPI' -import { NoonForecastValue } from 'api/forecastAPI' -import { - formatTemperature, - formatWindSpeed, - formatWindDirection, - formatRelativeHumidity, - formatPrecipitation -} from 'utils/format' -import { formatDatetimeInPST } from 'utils/date' -import SortableTableByDatetime, { Column } from 'features/fireWeather/components/tables/SortableTableByDatetime' - -/** - * Reusable component used to display noon forecasts (issued by forecasters) - * and/or model forecasts (generated by computer-run models) in table format - */ - -const sharedColumns: Column[] = [ - { - id: 'datetime', - label: 'Date (PST)', - minWidth: 120, - align: 'left', - formatDt: (value: string): string => formatDatetimeInPST(value) - }, - { - id: 'temperature', - label: 'Temp (°C)', - align: 'right', - format: formatTemperature, - maxWidth: 70 - }, - { - id: 'relative_humidity', - label: 'RH (%)', - align: 'right', - format: formatRelativeHumidity, - maxWidth: 70 - }, - { - id: 'wind_direction', - label: 'Wind Dir (10m) (°)', - align: 'right', - format: formatWindDirection, - maxWidth: 70 - }, - { - id: 'wind_speed', - label: 'Wind Spd (10m) (km/h)', - maxWidth: 70, - align: 'right', - format: formatWindSpeed - } -] - -export const noonModelTableColumns: Column[] = [ - ...sharedColumns, - { - id: 'delta_precipitation', - label: 'Precip (mm)', - maxWidth: 70, - align: 'right', - format: formatPrecipitation - }, - { - id: 'model_run_datetime', - label: 'Model Run (UTC)', - minWidth: 120, - align: 'right', - formatDt: (value: string): string => value.slice(0, 13) - } -] - -interface NoonModelTableProps { - testId: string - title: string - rows: ModelValue[] | undefined -} - -export const NoonModelTable = React.memo(function _(props: NoonModelTableProps) { - return -}) - -interface NoonForecastTableProps { - testId: string - title: string - rows: NoonForecastValue[] | undefined -} - -export const noonForecastTableColumns: Column[] = [ - ...sharedColumns, - { - id: 'total_precipitation', - label: 'Precip (mm)', - maxWidth: 70, - align: 'right', - format: formatPrecipitation - } -] - -export const NoonForecastTable = React.memo(function _(props: NoonForecastTableProps) { - return -}) diff --git a/web/src/features/fireWeather/components/tables/ObservationTable.tsx b/web/src/features/fireWeather/components/tables/ObservationTable.tsx deleted file mode 100644 index 6442c1cb5..000000000 --- a/web/src/features/fireWeather/components/tables/ObservationTable.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import React from 'react' - -import { ObservedValue } from 'api/observationAPI' -import SortableTableByDatetime, { Column } from 'features/fireWeather/components/tables/SortableTableByDatetime' -import { FFMC_VALUES_DECIMAL, ISI_VALUES_DECIMAL } from 'utils/constants' -import { - formatWindDirection, - formatWindSpeed, - formatTemperature, - formatRelativeHumidity, - formatPrecipitation -} from 'utils/format' -import { formatDatetimeInPST } from 'utils/date' - -export const columns: Column[] = [ - { - id: 'datetime', - label: 'Date (PST)', - minWidth: 135, - align: 'left', - formatDt: (value: string): string => formatDatetimeInPST(value) - }, - { - id: 'temperature', - label: 'Temp (°C)', - align: 'right', - format: formatTemperature, - maxWidth: 70 - }, - { - id: 'relative_humidity', - label: 'RH (%)', - align: 'right', - format: formatRelativeHumidity, - maxWidth: 70 - }, - { - id: 'dewpoint', - label: 'Dew Point (°C)', - align: 'right', - maxWidth: 70, - format: formatTemperature - }, - { - id: 'wind_direction', - label: 'Wind Dir (°)', - align: 'right', - format: formatWindDirection, - maxWidth: 70 - }, - { - id: 'wind_speed', - label: 'Wind Spd (km/h)', - align: 'right', - maxWidth: 70, - format: formatWindSpeed - }, - { - id: 'precipitation', - label: 'Precip (mm)', - align: 'right', - maxWidth: 70, - format: formatPrecipitation - }, - { - id: 'ffmc', - label: 'FFMC', - align: 'right', - format: (value: number): string => value.toFixed(FFMC_VALUES_DECIMAL) - }, - { - id: 'isi', - label: 'ISI', - align: 'right', - format: (value: number): string => value.toFixed(ISI_VALUES_DECIMAL) - }, - { - id: 'fwi', - label: 'FWI', - align: 'right', - format: (value: number): string => value.toFixed(FFMC_VALUES_DECIMAL) - } -] - -interface Props { - testId: string - title: string - rows: ObservedValue[] | undefined -} - -const ObservationTable = (props: Props) => { - return -} - -export default React.memo(ObservationTable) diff --git a/web/src/features/fireWeather/components/tables/SortableTableByDatetime.tsx b/web/src/features/fireWeather/components/tables/SortableTableByDatetime.tsx deleted file mode 100644 index 6d1f0f3c5..000000000 --- a/web/src/features/fireWeather/components/tables/SortableTableByDatetime.tsx +++ /dev/null @@ -1,208 +0,0 @@ -import React, { useState } from 'react' -import { styled } from '@mui/material/styles' -import Table from '@mui/material/Table' -import TableBody from '@mui/material/TableBody' -import TableCell from '@mui/material/TableCell' -import TableContainer from '@mui/material/TableContainer' -import TableRow from '@mui/material/TableRow' -import TableHead from '@mui/material/TableHead' -import TableSortLabel from '@mui/material/TableSortLabel' -import Paper from '@mui/material/Paper' -import Typography from '@mui/material/Typography' -import Accordion from '@mui/material/Accordion' -import AccordionSummary from '@mui/material/AccordionSummary' -import AccordionDetails from '@mui/material/AccordionDetails' -import ExpandMoreIcon from '@mui/icons-material/ExpandMore' - -import { - getDatetimeComparator, - getMinMaxValueCalculator, - Order, - MinMaxValues, - RowIdsOfMinMaxValues, - getMinMaxValuesRowIds, - getCellClassNameAndTestId -} from 'utils/table' - -const PREFIX = 'SortableTableByDatetime' - -const classes = { - display: `${PREFIX}-display`, - paper: `${PREFIX}-paper`, - tableContainer: `${PREFIX}-tableContainer`, - maxTemperature: `${PREFIX}-maxTemperature`, - minTemperature: `${PREFIX}-minTemperature`, - minRH: `${PREFIX}-minRH`, - maxPrecipitation: `${PREFIX}-maxPrecipitation`, - maxWindSpeed: `${PREFIX}-maxWindSpeed`, - directionOfMaxWindSpeed: `${PREFIX}-directionOfMaxWindSpeed` -} - -const Root = styled('div')({ - [`&.${classes.display}`]: { - paddingBottom: 12, - - '& .MuiTableCell-sizeSmall': { - padding: '3px 6px 3px 2px' - } - }, - [`& .${classes.paper}`]: { - width: '100%' - }, - [`& .${classes.tableContainer}`]: { - maxHeight: 280 - }, - [`& .${classes.maxTemperature}`]: { - background: '#ffb3b3' - }, - [`& .${classes.minTemperature}`]: { - background: '#84b8e7' - }, - [`& .${classes.minRH}`]: { - background: '#f2994a' - }, - [`& .${classes.maxPrecipitation}`]: { - fontWeight: 'bold', - borderColor: 'rgba(0, 0, 0, 0.87)', - borderStyle: 'solid', - borderWidth: '1px' - }, - [`& .${classes.maxWindSpeed}`]: { - fontWeight: 'bold', - borderColor: 'rgba(0, 0, 0, 0.87)', - borderStyle: 'solid', - borderTopWidth: '1px', - borderBottomWidth: '1px', - borderRightWidth: '1px', - borderLeftWidth: '0px' - }, - [`& .${classes.directionOfMaxWindSpeed}`]: { - fontWeight: 'bold', - borderColor: 'rgba(0, 0, 0, 0.87)', - borderStyle: 'solid', - borderTopWidth: '1px', - borderBottomWidth: '1px', - borderLeftWidth: '1px', - borderRightWidth: '0px' - } -}) - -export interface WeatherValue { - datetime: string - temperature?: number | null - relative_humidity?: number | null - dewpoint?: number | null - wind_direction?: number | null - wind_speed?: number | null - precipitation?: number | null - delta_precipitation?: number | null - total_precipitation?: number | null - ffmc?: number | null - isi?: number | null - fwi?: number | null - model_run_datetime?: string | null -} - -export interface Column { - id: keyof WeatherValue - label: string - minWidth?: number - maxWidth?: number - align?: 'left' | 'right' | 'center' - format?: (value: number) => string | number | undefined - formatDt?: (dt: string) => string -} - -interface Props { - testId: string - title: string - rows: R[] | undefined - columns: Column[] -} - -function SortableTableByDatetime(props: Props) { - const [order, setOrder] = useState('desc') - - if (!props.rows || props.rows.length === 0) { - return null - } - - const rowsSortedByDatetime = [...props.rows].sort(getDatetimeComparator(order)) - const toggleDatetimeOrder = () => { - setOrder(order === 'asc' ? 'desc' : 'asc') - } - - const minMaxValuesToHighlight: MinMaxValues = getMinMaxValueCalculator(rowsSortedByDatetime) - const rowIds: RowIdsOfMinMaxValues = getMinMaxValuesRowIds(rowsSortedByDatetime, minMaxValuesToHighlight) - - return ( - - - }> - - {props.title} - - - - - - - - - - {props.columns.map(column => { - const canSort = column.id === 'datetime' - return ( - - {canSort ? ( - - {column.label} - - ) : ( - column.label - )} - - ) - })} - - - - - {rowsSortedByDatetime.map((row, idx) => ( - - {props.columns.map(column => { - const value = row[column.id] - let display = null - const { className, testId } = getCellClassNameAndTestId(column, rowIds, idx, classes) - - if (typeof value === 'string' && column.formatDt) { - display = column.formatDt(value) - } - if (typeof value === 'number' && column.format) { - display = column.format(value) - } - - return ( - - {display} - - ) - })} - - ))} - -
-
-
-
-
-
- ) -} - -export default React.memo(SortableTableByDatetime) diff --git a/web/src/features/fireWeather/components/tables/StationComparisonTable.tsx b/web/src/features/fireWeather/components/tables/StationComparisonTable.tsx deleted file mode 100644 index e71247a45..000000000 --- a/web/src/features/fireWeather/components/tables/StationComparisonTable.tsx +++ /dev/null @@ -1,210 +0,0 @@ -import React from 'react' -import { styled } from '@mui/material/styles' -import Paper from '@mui/material/Paper' -import Typography from '@mui/material/Typography' -import Table from '@mui/material/Table' -import TableBody from '@mui/material/TableBody' -import TableCell from '@mui/material/TableCell' -import TableContainer from '@mui/material/TableContainer' -import TableRow from '@mui/material/TableRow' -import TableHead from '@mui/material/TableHead' -import { GeoJsonStation } from 'api/stationAPI' -import { ObservedValue } from 'api/observationAPI' -import { NoonForecastValue } from 'api/forecastAPI' -import { ModelValue } from 'api/modelAPI' -import { formatDateInUTC00Suffix, formatDatetimeInPST } from 'utils/date' -import { calculateAccumulatedPrecip } from 'utils/table' -import ComparisonTableRow, { DataSource, WeatherVariable } from './ComparisonTableRow' - -const PREFIX = 'StationComparisonTable' - -const classes = { - paper: `${PREFIX}-paper`, - typography: `${PREFIX}-typography`, - lightColumnHeader: `${PREFIX}-lightColumnHeader`, - darkColumnHeader: `${PREFIX}-darkColumnHeader` -} - -const StyledPaper = styled(Paper)({ - [`&.${classes.paper}`]: { - padding: '5px', - // There's a formating issues that causes the last cell in the table to be cut off - // when in 100%, on a small screen. Setting the width to 95% is a workaround, as the - // true source of the problem remains a mystery. (suspicion: it's something to do with using - // flex boxes, and having a table that needs to scroll.) - width: '95%' - }, - [`& .${classes.typography}`]: {}, - [`& .${classes.lightColumnHeader}`]: { - textAlign: 'center', - padding: '2px', - minWidth: '60px' - }, - [`& .${classes.darkColumnHeader}`]: { - backgroundColor: 'rgb(240, 240, 240)', - textAlign: 'center', - padding: '2px', - minWidth: '60px' - } -}) - -interface Props { - timeOfInterest: string - stationCodes: number[] - stationsByCode: Record - allNoonForecastsByStation: Record - observationsByStation: Record - allHighResModelsByStation: Record - allRegionalModelsByStation: Record - allModelsByStation: Record -} - -const findNoonMatch = (noonDate: string, collection: ModelValue[] | undefined): ModelValue | undefined => { - return collection?.find((item: ModelValue) => item.datetime === noonDate) -} - -const DataColumnHeading = styled(TableCell, { - shouldForwardProp: prop => prop !== 'isEven' -})<{ isEven: boolean }>(({ isEven }) => ({ - textAlign: 'center', - padding: '2px', - minWidth: '60px', - borderLeft: !isEven ? 'rgb(240, 240, 240)' : undefined -})) - -const SubHeadings = (value: string, index: number) => { - const isEven = index % 2 === 0 - return [ - - Observed - , - - Forecast - , - - HRDPS - , - - RDPS - , - - GDPS - - ] -} - -const StationComparisonTable = (props: Props) => { - // format the date to match the ISO format in the API for easy comparison. - const noonDate = formatDateInUTC00Suffix(props.timeOfInterest) - return ( - - - Station comparison for {formatDatetimeInPST(noonDate)} PDT - - - - - - - - - Temperature (°C) - - - Relative Humidity (%) - - - Wind Speed (km/h) - - - Wind Direction (°) - - - Precipitation (mm) - - Dew point (°C) - - - Weather Stations - {['temp', 'rh', 'wind speed', 'wind direction', 'precip'].map((value, index) => { - return SubHeadings(value, index) - })} - {/* Dew Point */} - Observed - - - - {props.stationCodes.map((stationCode: number, idx: number) => { - const station = props.stationsByCode[stationCode] - const noonForecasts = props.allNoonForecastsByStation[stationCode] - const noonForecast = noonForecasts?.find(forecast => forecast.datetime === noonDate) - const observations = props.observationsByStation[stationCode] - const observation = observations?.find(item => item.datetime === noonDate) - const accumulatedObservedPrecipitation = calculateAccumulatedPrecip(noonDate, observations) - const hrdpsModelPrediction = findNoonMatch(noonDate, props.allHighResModelsByStation[stationCode]) - const accumulatedHRDPSPrecipitation = calculateAccumulatedPrecip( - noonDate, - props.allHighResModelsByStation[stationCode] - ) - const rdpsModelPrediction = findNoonMatch(noonDate, props.allRegionalModelsByStation[stationCode]) - const accumulatedRDPSPrecipitation = calculateAccumulatedPrecip( - noonDate, - props.allRegionalModelsByStation[stationCode] - ) - const gdpsModelPrediction = findNoonMatch(noonDate, props.allModelsByStation[stationCode]) - const accumulatedGDPSPrecipitation = calculateAccumulatedPrecip( - noonDate, - props.allModelsByStation[stationCode] - ) - const indexCell = ( - - {station?.properties.name} ({stationCode}) - - ) - - const headers: WeatherVariable[] = [ - 'Temperature', - 'Relative Humidity', - 'Wind Speed', - 'Wind Direction', - 'Precipitation', - 'Dew point' - ] - const subheaders: DataSource[][] = [ - ['Observed', 'Forecast', 'HRDPS', 'RDPS', 'GDPS'], - ['Observed', 'Forecast', 'HRDPS', 'RDPS', 'GDPS'], - ['Observed', 'Forecast', 'HRDPS', 'RDPS', 'GDPS'], - ['Observed', 'Forecast', 'HRDPS', 'RDPS', 'GDPS'], - ['Observed', 'Forecast', 'HRDPS', 'RDPS', 'GDPS'], - ['Observed'] - ] - - return ( - - ) - })} - -
-
-
-
- ) -} - -export default React.memo(StationComparisonTable) diff --git a/web/src/features/fireWeather/pages/MoreCastPage.tsx b/web/src/features/fireWeather/pages/MoreCastPage.tsx deleted file mode 100644 index 0c3a48942..000000000 --- a/web/src/features/fireWeather/pages/MoreCastPage.tsx +++ /dev/null @@ -1,226 +0,0 @@ -import React, { useState, useEffect } from 'react' -import { styled } from '@mui/material/styles' -import { useDispatch } from 'react-redux' -import { useLocation } from 'react-router-dom' - -import { GeneralHeader } from 'components' -import { getStationCodesFromUrl, getTimeOfInterestFromUrl } from 'utils/url' -import { fetchWxStations } from 'features/stations/slices/stationsSlice' -import { fetchGlobalModelsWithBiasAdj } from 'features/fireWeather/slices/modelsSlice' -import { fetchObservations } from 'features/fireWeather/slices/observationsSlice' -import { fetchForecasts } from 'features/fireWeather/slices/forecastsSlice' -import { fetchGlobalModelSummaries } from 'features/fireWeather/slices/modelSummariesSlice' -import { fetchForecastSummaries } from 'features/fireWeather/slices/forecastSummariesSlice' -import { fetchHighResModels } from 'features/fireWeather/slices/highResModelsSlice' -import { fetchHighResModelSummaries } from 'features/fireWeather/slices/highResModelSummariesSlice' -import { fetchRegionalModels } from 'features/fireWeather/slices/regionalModelsSlice' -import { fetchRegionalModelSummaries } from 'features/fireWeather/slices/regionalModelSummariesSlice' -import WxDataDisplays from 'features/fireWeather/components/WxDataDisplays' -import WxDataForm from 'features/fireWeather/components/WxDataForm' -import AccuracyColorLegend from 'features/fireWeather/components/AccuracyColorLegend' -import SidePanel, { SidePanelEnum } from 'features/fireWeather/components/SidePanel' -import NetworkErrorMessages from 'features/fireWeather/components/NetworkErrorMessages' -import WeatherMap from 'features/fireWeather/components/maps/WeatherMap' -import ExpandableContainer from 'features/fireWeather/components/ExpandableContainer' -import { getDetailedStations, StationSource } from 'api/stationAPI' -import { MORECAST_DOC_TITLE, MORE_CAST_NAME, PARTIAL_WIDTH, FULL_WIDTH, CENTER_OF_BC } from 'utils/constants' -import { RedrawCommand } from 'features/map/Map' -import StationAccuracyForDate from 'features/fireWeather/components/StationAccuracyForDate' -import AccuracyVariablePicker, { - AccuracyWeatherVariableEnum -} from 'features/fireWeather/components/AccuracyVariablePicker' -import { AppDispatch } from 'app/store' - -const PREFIX = 'MoreCastPage' - -const classes = { - main: `${PREFIX}-main`, - nav: `${PREFIX}-nav`, - content: `${PREFIX}-content`, - map: `${PREFIX}-map`, - legend: `${PREFIX}-legend` -} - -const Root = styled('main')(({ theme }) => ({ - [`&.${classes.main}`]: { - display: 'flex', - flexDirection: 'column', - height: '100vh' - }, - - [`& .${classes.nav}`]: { - background: theme.palette.primary.light, - color: theme.palette.primary.contrastText, - minHeight: 60, - display: 'flex', - flexWrap: 'wrap', - alignItems: 'center', - paddingLeft: 25, - paddingRight: 25 - }, - - [`& .${classes.content}`]: { - flexGrow: 1, - display: 'flex', - overflowY: 'auto' - }, - - [`& .${classes.map}`]: { - order: 0, - flexGrow: 1, - display: 'flex', - justifyContent: 'center', - alignItems: 'center' - }, - - [`& .${classes.legend}`]: { - display: 'flex', - alignItems: 'flex-end', - backgroundColor: theme.palette.primary.light - } -})) - -const calculateSidePanelWidth = (codesFromQuery: number[]) => { - return codesFromQuery.length > 1 ? FULL_WIDTH : PARTIAL_WIDTH -} - -const MoreCastPage = () => { - const location = useLocation() - - // We base our station & toi list entirely from the URL. - const codesFromQuery = getStationCodesFromUrl(location.search) - const toiFromQuery = getTimeOfInterestFromUrl(location.search) - - const shouldInitiallyShowSidePanel = codesFromQuery.length > 0 - const [showSidePanel, setShowSidePanel] = useState(shouldInitiallyShowSidePanel) - const [sidePanelWidth, setSidePanelWidth] = useState(calculateSidePanelWidth(codesFromQuery)) - const [selectedAccuracyWxVariable, setSelectedAccuracyWxVariable] = useState( - AccuracyWeatherVariableEnum['Relative Humidity'] - ) - const accuracyWxVariableChangeHandler = (event: React.ChangeEvent<{ value: AccuracyWeatherVariableEnum }>) => { - setSelectedAccuracyWxVariable(event.target.value) - } - - const [mapCenter, setMapCenter] = useState(CENTER_OF_BC) - const expandSidePanel = () => setSidePanelWidth(FULL_WIDTH) - const collapseSidePanel = () => { - return setSidePanelWidth(PARTIAL_WIDTH) - } - - // Callback to set the latest center coordinates when side panel is collapsed - // to preserve any panning of the map by the user before panel was expanded. - const setNewMapCenter = (newMapCenter: number[]) => { - setMapCenter(newMapCenter) - } - - const shouldRedraw = !showSidePanel || sidePanelWidth === PARTIAL_WIDTH - - const getRedrawCommand = (): RedrawCommand | undefined => { - return shouldRedraw ? { redraw: true } : undefined - } - - const setSidePanelState = (show: boolean) => { - if (show) { - setShowSidePanel(true) - setSidePanelWidth(calculateSidePanelWidth(codesFromQuery)) - } else { - closeSidePanel() - } - } - const closeSidePanel = () => setShowSidePanel(false) - - const [showTableView, toggleTableView] = useState( - codesFromQuery.length > 1 ? SidePanelEnum.Comparison : SidePanelEnum.Tables - ) - const handleToggleView = (_: React.MouseEvent, newTableView: SidePanelEnum) => { - if (newTableView !== null) { - toggleTableView(newTableView) - } - } - - const dispatch: AppDispatch = useDispatch() - useEffect(() => { - const codesFromQuery = getStationCodesFromUrl(location.search) - const toiFromQuery = getTimeOfInterestFromUrl(location.search) - if (codesFromQuery.length > 0) { - dispatch(fetchObservations(codesFromQuery, toiFromQuery)) - dispatch(fetchForecasts(codesFromQuery, toiFromQuery)) - dispatch(fetchForecastSummaries(codesFromQuery, toiFromQuery)) - dispatch(fetchHighResModels(codesFromQuery, toiFromQuery)) - dispatch(fetchHighResModelSummaries(codesFromQuery, toiFromQuery)) - dispatch(fetchRegionalModels(codesFromQuery, toiFromQuery)) - dispatch(fetchRegionalModelSummaries(codesFromQuery, toiFromQuery)) - dispatch(fetchGlobalModelsWithBiasAdj(codesFromQuery, toiFromQuery)) - dispatch(fetchGlobalModelSummaries(codesFromQuery, toiFromQuery)) - } - // Update local state to match with the query url - dispatch(fetchWxStations(getDetailedStations, StationSource.unspecified, toiFromQuery)) - if (codesFromQuery.length > 1) { - toggleTableView(SidePanelEnum.Comparison) - setSidePanelState(true) - } else { - toggleTableView(SidePanelEnum.Tables) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [location]) - - useEffect(() => { - document.title = MORECAST_DOC_TITLE - }, []) - - return ( - - -
- -
-
- {sidePanelWidth < FULL_WIDTH && ( -
- -
- )} - - - - - - -
- {(sidePanelWidth <= PARTIAL_WIDTH || showSidePanel === false) && ( -
- - - -
- )} -
- ) -} - -export default React.memo(MoreCastPage) diff --git a/web/src/features/fireWeather/slices/forecastSummariesSlice.ts b/web/src/features/fireWeather/slices/forecastSummariesSlice.ts deleted file mode 100644 index 5b857123a..000000000 --- a/web/src/features/fireWeather/slices/forecastSummariesSlice.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit' - -import { ForecastSummary, ForecastSummariesForStation, getForecastSummaries } from 'api/forecastAPI' -import { AppThunk } from 'app/store' -import { logError } from 'utils/error' - -interface State { - loading: boolean - error: string | null - forecastSummariesByStation: Record -} - -const initialState: State = { - loading: false, - error: null, - forecastSummariesByStation: {} -} - -const forecastSummariesSlice = createSlice({ - name: 'forecastSummaries', - initialState, - reducers: { - getForecastSummariesStart(state: State) { - state.error = null - state.loading = true - state.forecastSummariesByStation = {} - }, - getForecastSummariesFailed(state: State, action: PayloadAction) { - state.error = action.payload - state.loading = false - }, - getForecastSummariesSuccess(state: State, action: PayloadAction) { - state.error = null - action.payload.forEach(summary => { - if (summary.station) { - const code = summary.station.code - state.forecastSummariesByStation[code] = summary.values - } - }) - state.loading = false - } - } -}) - -export const { getForecastSummariesStart, getForecastSummariesFailed, getForecastSummariesSuccess } = - forecastSummariesSlice.actions - -export default forecastSummariesSlice.reducer - -export const fetchForecastSummaries = - (stationCodes: number[], timeOfInterest: string): AppThunk => - async dispatch => { - try { - dispatch(getForecastSummariesStart()) - const forecastSummaries = await getForecastSummaries(stationCodes, timeOfInterest) - dispatch(getForecastSummariesSuccess(forecastSummaries)) - } catch (err) { - dispatch(getForecastSummariesFailed((err as Error).toString())) - logError(err) - } - } diff --git a/web/src/features/fireWeather/slices/forecastsSlice.ts b/web/src/features/fireWeather/slices/forecastsSlice.ts deleted file mode 100644 index bd11e696e..000000000 --- a/web/src/features/fireWeather/slices/forecastsSlice.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit' - -import { Forecast, getNoonForecasts, NoonForecastValue } from 'api/forecastAPI' -import { AppThunk } from 'app/store' -import { logError } from 'utils/error' - -interface State { - loading: boolean - error: string | null - allNoonForecastsByStation: Record - pastNoonForecastsByStation: Record - noonForecastsByStation: Record -} - -const initialState: State = { - loading: false, - error: null, - allNoonForecastsByStation: {}, - pastNoonForecastsByStation: {}, - noonForecastsByStation: {} -} - -const forecastsSlice = createSlice({ - name: 'forecasts', - initialState, - reducers: { - getForecastsStart(state: State) { - state.loading = true - state.error = null - state.allNoonForecastsByStation = {} - state.pastNoonForecastsByStation = {} - state.noonForecastsByStation = {} - }, - getForecastsFailed(state: State, action: PayloadAction) { - state.loading = false - state.error = action.payload - }, - getForecastsSuccess(state: State, action: PayloadAction) { - action.payload.forEach(forecast => { - const sCode = forecast.station_code - if (sCode) { - const allForecasts: NoonForecastValue[] = [] - - const currDate = new Date() - const pastForecasts: NoonForecastValue[] = [] - - // only add the most recent forecast for the station and datetime - // (query returns forecasts in order for each datetime, from most recently - // issued down to first issued) - let prevDatetime: string - const mostRecentForecasts: NoonForecastValue[] = [] - forecast.values.forEach(value => { - const isDiffDatetime = prevDatetime !== value.datetime - if (isDiffDatetime) { - const isFutureForecast = new Date(value.datetime) >= currDate - if (isFutureForecast) { - mostRecentForecasts.push(value) - } else { - pastForecasts.push(value) - } - - allForecasts.push(value) - prevDatetime = value.datetime - } - }) - state.allNoonForecastsByStation[sCode] = allForecasts - state.pastNoonForecastsByStation[sCode] = pastForecasts - state.noonForecastsByStation[sCode] = mostRecentForecasts - } - }) - state.loading = false - state.error = null - } - } -}) - -export const { getForecastsStart, getForecastsFailed, getForecastsSuccess } = forecastsSlice.actions - -export default forecastsSlice.reducer - -export const fetchForecasts = - (stationCodes: number[], timeOfInterest: string): AppThunk => - async dispatch => { - try { - dispatch(getForecastsStart()) - const forecasts = await getNoonForecasts(stationCodes, timeOfInterest) - dispatch(getForecastsSuccess(forecasts)) - } catch (err) { - dispatch(getForecastsFailed((err as Error).toString())) - logError(err) - } - } diff --git a/web/src/features/fireWeather/slices/highResModelSummariesSlice.ts b/web/src/features/fireWeather/slices/highResModelSummariesSlice.ts deleted file mode 100644 index e90d48a53..000000000 --- a/web/src/features/fireWeather/slices/highResModelSummariesSlice.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit' - -import { ModelSummary, ModelSummariesForStation, getModelSummaries } from 'api/modelAPI' -import { AppThunk } from 'app/store' -import { logError } from 'utils/error' - -interface State { - loading: boolean - error: string | null - highResModelSummariesByStation: Record -} - -const initialState: State = { - loading: false, - error: null, - highResModelSummariesByStation: {} -} - -const highResModelSummariesSlice = createSlice({ - name: 'highResModelSummaries', - initialState, - reducers: { - getHighResModelSummariesStart(state: State) { - state.error = null - state.loading = true - state.highResModelSummariesByStation = {} - }, - getHighResModelSummariesFailed(state: State, action: PayloadAction) { - state.error = action.payload - state.loading = false - }, - getHighResModelSummariesSuccess(state: State, action: PayloadAction) { - state.error = null - action.payload.forEach(summary => { - if (summary.station) { - const code = summary.station.code - state.highResModelSummariesByStation[code] = summary.values - } - }) - state.loading = false - } - } -}) - -export const { getHighResModelSummariesStart, getHighResModelSummariesFailed, getHighResModelSummariesSuccess } = - highResModelSummariesSlice.actions - -export default highResModelSummariesSlice.reducer - -export const fetchHighResModelSummaries = - (stationCodes: number[], timeOfInterest: string): AppThunk => - async dispatch => { - try { - dispatch(getHighResModelSummariesStart()) - const summaries = await getModelSummaries(stationCodes, 'HRDPS', timeOfInterest) - dispatch(getHighResModelSummariesSuccess(summaries)) - } catch (err) { - dispatch(getHighResModelSummariesFailed((err as Error).toString())) - logError(err) - } - } diff --git a/web/src/features/fireWeather/slices/highResModelsSlice.ts b/web/src/features/fireWeather/slices/highResModelsSlice.ts deleted file mode 100644 index 7d376b919..000000000 --- a/web/src/features/fireWeather/slices/highResModelsSlice.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit' - -import { ModelValue, getModelsWithBiasAdj, ModelsForStation } from 'api/modelAPI' -import { parseModelValuesHelper } from 'features/fireWeather/slices/parseModelValuesHelper' -import { AppThunk } from 'app/store' -import { logError } from 'utils/error' - -interface State { - loading: boolean - error: string | null - allHighResModelsByStation: Record - pastHighResModelsByStation: Record - highResModelsByStation: Record -} - -const initialState: State = { - loading: false, - error: null, - allHighResModelsByStation: {}, - pastHighResModelsByStation: {}, - highResModelsByStation: {} -} - -const highResModelsSlice = createSlice({ - name: 'highResModels', - initialState, - reducers: { - getHighResModelsStart(state: State) { - state.error = null - state.loading = true - state.allHighResModelsByStation = {} - state.pastHighResModelsByStation = {} - state.highResModelsByStation = {} - }, - getHighResModelsFailed(state: State, action: PayloadAction) { - state.error = action.payload - state.loading = false - }, - getHighResModelsSuccess(state: State, action: PayloadAction) { - state.error = null - action.payload.forEach(({ station, model_runs }) => { - if (station && model_runs) { - const code = station.code - const parsedValues = parseModelValuesHelper(model_runs, false) - state.pastHighResModelsByStation[code] = parsedValues.pastValues - state.highResModelsByStation[code] = parsedValues.modelValues - state.allHighResModelsByStation[code] = parsedValues.allValues - } - }) - state.loading = false - } - } -}) - -export const { getHighResModelsStart, getHighResModelsFailed, getHighResModelsSuccess } = highResModelsSlice.actions - -export default highResModelsSlice.reducer - -export const fetchHighResModels = - (codes: number[], timeOfInterest: string): AppThunk => - async dispatch => { - try { - dispatch(getHighResModelsStart()) - const modelsForStations = await getModelsWithBiasAdj(codes, 'HRDPS', timeOfInterest) - dispatch(getHighResModelsSuccess(modelsForStations)) - } catch (err) { - dispatch(getHighResModelsFailed((err as Error).toString())) - logError(err) - } - } diff --git a/web/src/features/fireWeather/slices/modelSummariesSlice.ts b/web/src/features/fireWeather/slices/modelSummariesSlice.ts deleted file mode 100644 index 2e19240a0..000000000 --- a/web/src/features/fireWeather/slices/modelSummariesSlice.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit' - -import { ModelSummary, getModelSummaries, ModelSummariesForStation } from 'api/modelAPI' -import { AppThunk } from 'app/store' -import { logError } from 'utils/error' - -interface State { - loading: boolean - error: string | null - modelSummariesByStation: Record -} - -const initialState: State = { - loading: false, - error: null, - modelSummariesByStation: {} -} - -const modelSummariesSlice = createSlice({ - name: 'modelSummaries', - initialState, - reducers: { - getModelSummariesStart(state: State) { - state.error = null - state.loading = true - state.modelSummariesByStation = {} - }, - getModelSummariesFailed(state: State, action: PayloadAction) { - state.error = action.payload - state.loading = false - }, - getModelSummariesSuccess(state: State, action: PayloadAction) { - state.error = null - action.payload.forEach(summary => { - if (summary.station) { - const code = summary.station.code - state.modelSummariesByStation[code] = summary.values - } - }) - state.loading = false - } - } -}) - -export const { getModelSummariesStart, getModelSummariesFailed, getModelSummariesSuccess } = modelSummariesSlice.actions - -export default modelSummariesSlice.reducer - -export const fetchGlobalModelSummaries = - (stationCodes: number[], timeOfInterest: string): AppThunk => - async dispatch => { - try { - dispatch(getModelSummariesStart()) - const modelSummaries = await getModelSummaries(stationCodes, 'GDPS', timeOfInterest) - dispatch(getModelSummariesSuccess(modelSummaries)) - } catch (err) { - dispatch(getModelSummariesFailed((err as Error).toString())) - logError(err) - } - } diff --git a/web/src/features/fireWeather/slices/modelsSlice.ts b/web/src/features/fireWeather/slices/modelsSlice.ts deleted file mode 100644 index 0b8495794..000000000 --- a/web/src/features/fireWeather/slices/modelsSlice.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit' - -import { ModelValue, getModelsWithBiasAdj, ModelsForStation } from 'api/modelAPI' -import { AppThunk } from 'app/store' -import { logError } from 'utils/error' -import { parseModelValuesHelper } from 'features/fireWeather/slices/parseModelValuesHelper' - -interface State { - loading: boolean - error: string | null - allModelsByStation: Record - pastModelsByStation: Record - modelsByStation: Record - noonModelsByStation: Record -} - -const initialState: State = { - loading: false, - error: null, - allModelsByStation: {}, - pastModelsByStation: {}, - modelsByStation: {}, - noonModelsByStation: {} -} - -const modelsSlice = createSlice({ - name: 'models', - initialState, - reducers: { - getModelsStart(state: State) { - state.error = null - state.loading = true - state.allModelsByStation = {} - state.pastModelsByStation = {} - state.modelsByStation = {} - state.noonModelsByStation = {} - }, - getModelsFailed(state: State, action: PayloadAction) { - state.error = action.payload - state.loading = false - }, - getModelsSuccess(state: State, action: PayloadAction) { - state.error = null - action.payload.forEach(({ station, model_runs }) => { - if (station && model_runs) { - const code = station.code - const parsedValues = parseModelValuesHelper(model_runs, true) - state.allModelsByStation[code] = parsedValues.allValues - state.pastModelsByStation[code] = parsedValues.pastValues - state.modelsByStation[code] = parsedValues.modelValues - state.noonModelsByStation[code] = parsedValues.noonValues - } - }) - state.loading = false - } - } -}) - -export const { getModelsStart, getModelsFailed, getModelsSuccess } = modelsSlice.actions - -export default modelsSlice.reducer - -export const fetchGlobalModelsWithBiasAdj = - (codes: number[], timeOfInterest: string): AppThunk => - async dispatch => { - try { - dispatch(getModelsStart()) - const modelsForStations = await getModelsWithBiasAdj(codes, 'GDPS', timeOfInterest) - dispatch(getModelsSuccess(modelsForStations)) - } catch (err) { - dispatch(getModelsFailed((err as Error).toString())) - logError(err) - } - } diff --git a/web/src/features/fireWeather/slices/observationsSlice.ts b/web/src/features/fireWeather/slices/observationsSlice.ts deleted file mode 100644 index 68f86217c..000000000 --- a/web/src/features/fireWeather/slices/observationsSlice.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit' - -import { Observation, ObservedValue, getObservations } from 'api/observationAPI' -import { AppThunk } from 'app/store' -import { logError } from 'utils/error' - -interface State { - loading: boolean - error: string | null - observationsByStation: Record - observations: Observation[] -} - -const initialState: State = { - loading: false, - error: null, - observationsByStation: {}, - observations: [] -} - -const observationsSlice = createSlice({ - name: 'observations', - initialState, - reducers: { - getObservationsStart(state: State) { - state.error = null - state.loading = true - state.observationsByStation = {} - state.observations = [] - }, - getObservationsFailed(state: State, action: PayloadAction) { - state.error = action.payload - state.loading = false - }, - getObservationsSuccess(state: State, action: PayloadAction) { - state.error = null - state.observations = action.payload - action.payload.forEach(observed => { - if (observed.station) { - state.observationsByStation[observed.station.code] = observed.values - } - }) - state.loading = false - } - } -}) - -export const { getObservationsStart, getObservationsFailed, getObservationsSuccess } = observationsSlice.actions - -export default observationsSlice.reducer - -export const fetchObservations = - (stationCodes: number[], timeOfInterest: string): AppThunk => - async dispatch => { - try { - dispatch(getObservationsStart()) - const observations = await getObservations(stationCodes, timeOfInterest) - dispatch(getObservationsSuccess(observations)) - } catch (err) { - dispatch(getObservationsFailed((err as Error).toString())) - logError(err) - } - } diff --git a/web/src/features/fireWeather/slices/parseModelValuesHelper.ts b/web/src/features/fireWeather/slices/parseModelValuesHelper.ts deleted file mode 100644 index efbc2b592..000000000 --- a/web/src/features/fireWeather/slices/parseModelValuesHelper.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { ModelRun, ModelValue } from 'api/modelAPI' -import { isNoonInPST } from 'utils/date' - -export const parseModelValuesHelper = ( - model_runs: ModelRun[], - separate_noon_values: boolean -): Record => { - const pastModelValues: ModelValue[] = [] - const modelValues: ModelValue[] = [] - const noonModelValues: ModelValue[] = [] - const reducer = (values: ModelValue[], modelRun: ModelRun) => { - // flatten data, adding in model run time onto model value. - modelRun.values.forEach((value: ModelValue) => { - value.model_run_datetime = modelRun.model_run.datetime - values.push(value) - }) - return values - } - const allModelValues = model_runs.reduce(reducer, []) - const currDate = new Date() - allModelValues.forEach(v => { - const isFutureModel = new Date(v.datetime) >= currDate - if (isFutureModel) { - modelValues.push(v) - } else { - pastModelValues.push(v) - } - if (separate_noon_values && isNoonInPST(v.datetime)) { - // NOTE: When using noonModelValues - keep in mind that precipitation is for that noon sample ONLY! - noonModelValues.push(v) - } - }) - - return { - pastValues: pastModelValues, - modelValues: modelValues, - noonValues: noonModelValues, - allValues: allModelValues - } -} diff --git a/web/src/features/fireWeather/slices/regionalModelSummariesSlice.ts b/web/src/features/fireWeather/slices/regionalModelSummariesSlice.ts deleted file mode 100644 index e5113e745..000000000 --- a/web/src/features/fireWeather/slices/regionalModelSummariesSlice.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit' - -import { ModelSummary, ModelSummariesForStation, getModelSummaries } from 'api/modelAPI' -import { AppThunk } from 'app/store' -import { logError } from 'utils/error' - -interface State { - loading: boolean - error: string | null - regionalModelSummariesByStation: Record -} - -const initialState: State = { - loading: false, - error: null, - regionalModelSummariesByStation: {} -} - -const regionalModelSummariesSlice = createSlice({ - name: 'regionalModelSummaries', - initialState, - reducers: { - getRegionalModelSummariesStart(state: State) { - state.error = null - state.loading = true - state.regionalModelSummariesByStation = {} - }, - getRegionalModelSummariesFailed(state: State, action: PayloadAction) { - state.error = action.payload - state.loading = false - }, - getRegionalModelSummariesSuccess(state: State, action: PayloadAction) { - state.error = null - action.payload.forEach(summary => { - if (summary.station) { - const code = summary.station.code - state.regionalModelSummariesByStation[code] = summary.values - } - }) - state.loading = false - } - } -}) - -export const { getRegionalModelSummariesStart, getRegionalModelSummariesFailed, getRegionalModelSummariesSuccess } = - regionalModelSummariesSlice.actions - -export default regionalModelSummariesSlice.reducer - -export const fetchRegionalModelSummaries = - (stationCodes: number[], timeOfInterest: string): AppThunk => - async dispatch => { - try { - dispatch(getRegionalModelSummariesStart()) - const summaries = await getModelSummaries(stationCodes, 'RDPS', timeOfInterest) - dispatch(getRegionalModelSummariesSuccess(summaries)) - } catch (err) { - dispatch(getRegionalModelSummariesFailed((err as Error).toString())) - logError(err) - } - } diff --git a/web/src/features/fireWeather/slices/regionalModelsSlice.ts b/web/src/features/fireWeather/slices/regionalModelsSlice.ts deleted file mode 100644 index faba84ea8..000000000 --- a/web/src/features/fireWeather/slices/regionalModelsSlice.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit' -import { parseModelValuesHelper } from 'features/fireWeather/slices/parseModelValuesHelper' -import { ModelValue, getModelsWithBiasAdj, ModelsForStation } from 'api/modelAPI' -import { AppThunk } from 'app/store' -import { logError } from 'utils/error' - -interface State { - loading: boolean - error: string | null - allRegionalModelsByStation: Record - pastRegionalModelsByStation: Record - regionalModelsByStation: Record -} - -const initialState: State = { - loading: false, - error: null, - allRegionalModelsByStation: {}, - pastRegionalModelsByStation: {}, - regionalModelsByStation: {} -} - -const regionalModelsSlice = createSlice({ - name: 'regionalModels', - initialState, - reducers: { - getRegionalModelsStart(state: State) { - state.error = null - state.loading = true - state.allRegionalModelsByStation = {} - state.pastRegionalModelsByStation = {} - state.regionalModelsByStation = {} - }, - getRegionalModelsFailed(state: State, action: PayloadAction) { - state.error = action.payload - state.loading = false - }, - getRegionalModelsSuccess(state: State, action: PayloadAction) { - state.error = null - action.payload.forEach(({ station, model_runs }) => { - if (station && model_runs) { - const code = station.code - const parsedValues = parseModelValuesHelper(model_runs, false) - state.pastRegionalModelsByStation[code] = parsedValues.pastValues - state.regionalModelsByStation[code] = parsedValues.modelValues - state.allRegionalModelsByStation[code] = parsedValues.allValues - } - }) - state.loading = false - } - } -}) - -export const { getRegionalModelsStart, getRegionalModelsFailed, getRegionalModelsSuccess } = regionalModelsSlice.actions - -export default regionalModelsSlice.reducer - -export const fetchRegionalModels = - (codes: number[], timeOfInterest: string): AppThunk => - async dispatch => { - try { - dispatch(getRegionalModelsStart()) - const modelsForStations = await getModelsWithBiasAdj(codes, 'RDPS', timeOfInterest) - dispatch(getRegionalModelsSuccess(modelsForStations)) - } catch (err) { - dispatch(getRegionalModelsFailed((err as Error).toString())) - logError(err) - } - } diff --git a/web/src/features/landingPage/toolInfo.tsx b/web/src/features/landingPage/toolInfo.tsx index db6f3b47a..942ee1c3f 100644 --- a/web/src/features/landingPage/toolInfo.tsx +++ b/web/src/features/landingPage/toolInfo.tsx @@ -19,8 +19,6 @@ import { FIRE_BEHAVIOR_CALC_ROUTE, HFI_CALC_NAME, HFI_CALC_ROUTE, - MORE_CAST_NAME, - MORECAST_ROUTE, PERCENTILE_CALC_NAME, PERCENTILE_CALC_ROUTE, MORE_CAST_2_NAME, @@ -88,19 +86,6 @@ export const hfiCalcInfo: ToolInfo = { isBeta: false } -export const moreCastInfo: ToolInfo = { - name: MORE_CAST_NAME, - route: MORECAST_ROUTE, - description: ( - - A system that uses weather station observations to skill score temperature and relative humidity values forecasted - by three numerical weather models. - - ), - icon: , - isBeta: true -} - export const moreCast2Info: ToolInfo = { name: MORE_CAST_2_NAME, route: MORE_CAST_2_ROUTE, @@ -155,7 +140,6 @@ export const fbpGoInfo: ToolInfo = { export const toolInfos = [ moreCast2Info, fireBehaviourAdvisoryInfo, - moreCastInfo, cHainesInfo, fireBehaviourCalcInfo, hfiCalcInfo, diff --git a/web/src/utils/constants.ts b/web/src/utils/constants.ts index 5fcbdf6e3..e725c8574 100644 --- a/web/src/utils/constants.ts +++ b/web/src/utils/constants.ts @@ -17,7 +17,6 @@ export const PST_UTC_OFFSET = -8 export const PST_ISO_TIMEZONE = 'T00:00-08:00' export const PERCENTILE_CALC_ROUTE = '/percentile-calculator' -export const FIRE_WEATHER_ROUTE = '/fire-weather' export const MORECAST_ROUTE = '/morecast' export const HFI_CALC_ROUTE = '/hfi-calculator' export const C_HAINES_ROUTE = '/c-haines' @@ -40,12 +39,12 @@ export const FBP_GO_NAME = 'FBP Go' export const FIRE_BEHAVIOUR_ADVISORY_NAME = 'Auto Spatial Advisory' export const FIRE_BEHAVIOUR_CALC_NAME = 'FireBat' export const HFI_CALC_NAME = 'HFI Calculator' -export const MORE_CAST_NAME = 'MoreCast' export const MORE_CAST_2_NAME = 'MoreCast 2.0' export const PERCENTILE_CALC_NAME = 'Percentile Calculator' // UI constants export const HEADER_HEIGHT = 56 +export type Order = 'asc' | 'desc' // Document titles export const LANDING_PAGE_DOC_TITLE = 'Decision Support Tools | BCWS PSU' @@ -53,6 +52,5 @@ export const ASA_DOC_TITLE = 'Automated Spatial Advisory | BCWS PSU' export const C_HAINES_DOC_TITLE = 'C-Haines | BCWS PSU' export const FIREBAT_DOC_TITLE = 'FireBat | BCWS PSU' export const HFI_CALC_DOC_TITLE = 'HFI Calculator | BCWS PSU' -export const MORECAST_DOC_TITLE = 'MoreCast | BCWS PSU' export const MORE_CAST_2_DOC_TITLE = 'MoreCast 2.0 | BCWS PSU' export const PERCENTILE_CALC_DOC_TITLE = 'Percentile Calculator | BCWS PSU' diff --git a/web/src/utils/table.test.data.ts b/web/src/utils/table.test.data.ts deleted file mode 100644 index 1712fbaf4..000000000 --- a/web/src/utils/table.test.data.ts +++ /dev/null @@ -1,251 +0,0 @@ -import { WeatherValue } from 'features/fireWeather/components/tables/SortableTableByDatetime' -import { MinMaxValues, RowIdsOfMinMaxValues } from 'utils/table' - -export const dummyWeatherData: WeatherValue[] = [ - { - datetime: '2020-12-09T20:00:00+00:00', - temperature: 8.1, - relative_humidity: 70, - wind_direction: 300, - wind_speed: 17.3, - precipitation: 0.4 - }, - { - datetime: '2020-12-09T19:00:00+00:00', - temperature: 10.5, - relative_humidity: 53, - wind_direction: 260, - wind_speed: 3.7, - precipitation: 0.8 - }, - { - datetime: '2020-12-09T18:00:00+00:00', - temperature: -1.5, - relative_humidity: 28, - wind_direction: 330, - wind_speed: 63.2, - precipitation: 0.0 - }, - { - datetime: '2020-12-09T17:00:00+00:00', - temperature: 2.4, - relative_humidity: 35, - wind_direction: 150, - wind_speed: 4.7, - precipitation: 16.3 - }, - { - datetime: '2020-12-09T16:00:00+00:00', - temperature: -1.5, - relative_humidity: 25, - wind_direction: 280, - wind_speed: 2.5, - precipitation: 0.0 - } -] -export const correctMinMaxValues: MinMaxValues = { - relative_humidity: 25, - precipitation: 16.3, - wind_speed: 63.2, - temperature: { - min: -1.5, - max: 10.5 - } -} -export const correctMinMaxRowIds: RowIdsOfMinMaxValues = { - relative_humidity: [4], - precipitation: [3], - wind: [2], - max_temp: [1], - min_temp: [2, 4] -} - -export const dummyWeatherDataNoPrecip: WeatherValue[] = [ - { - datetime: '2020-12-09T20:00:00+00:00', - temperature: 8.1, - relative_humidity: 70, - wind_direction: 300, - wind_speed: 17.3, - precipitation: 0.0 - }, - { - datetime: '2020-12-09T19:00:00+00:00', - temperature: 10.5, - relative_humidity: 53, - wind_direction: 260, - wind_speed: 3.7, - precipitation: 0.0 - }, - { - datetime: '2020-12-09T18:00:00+00:00', - temperature: -1.5, - relative_humidity: 28, - wind_direction: 330, - wind_speed: 63.2, - precipitation: 0.0 - } -] -export const correctMinMaxValuesNoPrecip: MinMaxValues = { - relative_humidity: 28, - precipitation: null, - wind_speed: 63.2, - temperature: { - min: -1.5, - max: 10.5 - } -} -export const correctMinMaxRowIdsNoPrecip: RowIdsOfMinMaxValues = { - relative_humidity: [2], - precipitation: [], - wind: [2], - max_temp: [1], - min_temp: [2] -} - -export const dummyWeatherDataNoWind: WeatherValue[] = [ - { - datetime: '2020-12-09T18:00:00+00:00', - temperature: -1.5, - relative_humidity: 28, - wind_direction: 330, - wind_speed: 0.0, - precipitation: 0.0 - }, - { - datetime: '2020-12-09T17:00:00+00:00', - temperature: 2.4, - relative_humidity: 35, - wind_direction: 150, - wind_speed: 0.0, - precipitation: 16.3 - }, - { - datetime: '2020-12-09T16:00:00+00:00', - temperature: -1.5, - relative_humidity: 25, - wind_direction: 280, - wind_speed: 0.0, - precipitation: 0.0 - } -] -export const correctMinMaxValuesNoWind: MinMaxValues = { - relative_humidity: 25, - precipitation: 16.3, - wind_speed: null, - temperature: { - min: -1.5, - max: 2.4 - } -} -export const correctMinMaxRowIdsNoWind: RowIdsOfMinMaxValues = { - relative_humidity: [2], - precipitation: [1], - wind: [], - max_temp: [1], - min_temp: [0, 2] -} - -export const dummyWeatherDataMultiplePrecipLabels: WeatherValue[] = [ - { - datetime: '2020-12-09T20:00:00+00:00', - temperature: 8.1, - relative_humidity: 70, - wind_direction: 300, - wind_speed: 17.3, - precipitation: 0.4 - }, - { - datetime: '2020-12-09T19:00:00+00:00', - temperature: 10.5, - relative_humidity: 53, - wind_direction: 260, - wind_speed: 3.7, - delta_precipitation: 0.8 - }, - { - datetime: '2020-12-09T18:00:00+00:00', - temperature: -1.5, - relative_humidity: 28, - wind_direction: 330, - wind_speed: 63.2, - delta_precipitation: 0.0 - }, - { - datetime: '2020-12-09T17:00:00+00:00', - temperature: 2.4, - relative_humidity: 35, - wind_direction: 150, - wind_speed: 4.7, - precipitation: 16.3 - }, - { - datetime: '2020-12-09T16:00:00+00:00', - temperature: -1.5, - relative_humidity: 25, - wind_direction: 280, - wind_speed: 2.5, - total_precipitation: 0.0 - } -] -export const correctMinMaxValuesMultiplePrecipLabels: MinMaxValues = { - relative_humidity: 25, - precipitation: 16.3, - wind_speed: 63.2, - temperature: { - min: -1.5, - max: 10.5 - } -} - -export const dummyWeatherDataNullValues: WeatherValue[] = [ - { - datetime: '2020-12-09T20:00:00+00:00', - temperature: 8.1, - relative_humidity: 70, - wind_direction: 300, - wind_speed: null, - precipitation: 0.4 - }, - { - datetime: '2020-12-09T19:00:00+00:00', - temperature: 10.5, - relative_humidity: 53, - wind_direction: 260, - wind_speed: null, - delta_precipitation: null - }, - { - datetime: '2020-12-09T18:00:00+00:00', - temperature: -1.5, - relative_humidity: 28, - wind_direction: 330, - wind_speed: null, - delta_precipitation: 0.0 - }, - { - datetime: '2020-12-09T17:00:00+00:00', - temperature: null, - relative_humidity: 35, - wind_direction: 150, - wind_speed: null, - precipitation: 16.3 - }, - { - datetime: '2020-12-09T16:00:00+00:00', - temperature: -1.5, - relative_humidity: 25, - wind_direction: 280, - wind_speed: null, - total_precipitation: 0.0 - } -] -export const correctMinMaxValuesNullValues: MinMaxValues = { - relative_humidity: 25, - precipitation: 16.3, - wind_speed: null, - temperature: { - min: -1.5, - max: 10.5 - } -} diff --git a/web/src/utils/table.test.ts b/web/src/utils/table.test.ts deleted file mode 100644 index 1cdad8635..000000000 --- a/web/src/utils/table.test.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { - calculateAccumulatedPrecip, - getDatetimeComparator, - getMinMaxValueCalculator, - getMinMaxValuesRowIds -} from 'utils/table' -import { ModelValue } from 'api/modelAPI' -import { - dummyWeatherData, - dummyWeatherDataNoPrecip, - dummyWeatherDataNoWind, - dummyWeatherDataMultiplePrecipLabels, - dummyWeatherDataNullValues, - correctMinMaxValues, - correctMinMaxValuesNoPrecip, - correctMinMaxValuesNoWind, - correctMinMaxValuesMultiplePrecipLabels, - correctMinMaxValuesNullValues, - correctMinMaxRowIds, - correctMinMaxRowIdsNoPrecip, - correctMinMaxRowIdsNoWind -} from 'utils/table.test.data' - -describe('Table util functions', () => { - describe('calculateAccumulatedPrecip', () => { - it('should add up precipitation correctly', () => { - const noonDate = '2020-12-09T20:00:00+00:00' - const precip = calculateAccumulatedPrecip(noonDate, [ - { - datetime: '2020-12-08T20:00:00+00:00', - delta_precipitation: 1.1 - }, - { datetime: '2020-12-08T19:00:00+00:00', delta_precipitation: 1.1 }, - { - datetime: '2020-12-09T19:00:00+00:00', - delta_precipitation: 1.1 - }, - { - datetime: '2020-12-09T18:00:00+00:00', - delta_precipitation: 1.1 - } - ] as ModelValue[]) - // we expect that only two of the records to summed up. - expect(precip?.precipitation).toEqual(2.2) - expect(precip?.values.length).toEqual(2) - // expect only the relevant records. - expect(precip?.values).toEqual( - expect.arrayContaining([ - { - datetime: '2020-12-09T19:00:00+00:00', - delta_precipitation: 1.1 - }, - { - datetime: '2020-12-09T18:00:00+00:00', - delta_precipitation: 1.1 - } - ] as ModelValue[]) - ) - }) - }) - - describe('getDatetimeComparator', () => { - it('should return the correct compare function', () => { - const ascending = getDatetimeComparator('asc') - const descending = getDatetimeComparator('desc') - const arr = [ - { datetime: '2020-12-09T23:00:00+00:00', meta: 'hmm' }, - { datetime: '2020-12-09T21:00:00+00:00' }, - { datetime: '2020-12-09T20:00:00+00:00' }, - { datetime: '2020-12-09T22:00:00+00:00' } - ] - const deepCopy = JSON.parse(JSON.stringify(arr)) - - expect([...arr].sort(ascending)).toEqual([ - { datetime: '2020-12-09T20:00:00+00:00' }, - { datetime: '2020-12-09T21:00:00+00:00' }, - { datetime: '2020-12-09T22:00:00+00:00' }, - { datetime: '2020-12-09T23:00:00+00:00', meta: 'hmm' } - ]) - - expect([...arr].sort(descending)).toEqual([ - { datetime: '2020-12-09T23:00:00+00:00', meta: 'hmm' }, - { datetime: '2020-12-09T22:00:00+00:00' }, - { datetime: '2020-12-09T21:00:00+00:00' }, - { datetime: '2020-12-09T20:00:00+00:00' } - ]) - - expect(arr).toEqual(deepCopy) - }) - }) - - describe('getMinMaxValueCalculator', () => { - it('should correctly calculate min and max wx values to be highlighted', () => { - const minMaxValues = getMinMaxValueCalculator(dummyWeatherData) - - expect(minMaxValues).toEqual(correctMinMaxValues) - }) - - it('should return null for max precip when all precips are 0.0', () => { - const minMaxValues = getMinMaxValueCalculator(dummyWeatherDataNoPrecip) - expect(minMaxValues).toEqual(correctMinMaxValuesNoPrecip) - }) - - it('should return null for max wind_speed when all wind_speeds are 0.0', () => { - const minMaxValues = getMinMaxValueCalculator(dummyWeatherDataNoWind) - expect(minMaxValues).toEqual(correctMinMaxValuesNoWind) - }) - - it('should correctly calculate min-max values when different precip labels are used', () => { - const minMaxValues = getMinMaxValueCalculator(dummyWeatherDataMultiplePrecipLabels) - expect(minMaxValues).toEqual(correctMinMaxValuesMultiplePrecipLabels) - }) - - it('should calculate min-max wx values when some values are null', () => { - const minMaxValues = getMinMaxValueCalculator(dummyWeatherDataNullValues) - expect(minMaxValues).toEqual(correctMinMaxValuesNullValues) - }) - }) - - describe('getMinMaxValuesRowIds', () => { - it('should correctly determine the rows ids of min-max values to be highlighted', () => { - const minMaxRowIds = getMinMaxValuesRowIds(dummyWeatherData, correctMinMaxValues) - expect(minMaxRowIds).toEqual(correctMinMaxRowIds) - }) - - it('should return empty rowIds list when min-max value is null', () => { - let minMaxRowIds = getMinMaxValuesRowIds(dummyWeatherDataNoPrecip, correctMinMaxValuesNoPrecip) - expect(minMaxRowIds).toEqual(correctMinMaxRowIdsNoPrecip) - - minMaxRowIds = getMinMaxValuesRowIds(dummyWeatherDataNoWind, correctMinMaxValuesNoWind) - expect(minMaxRowIds).toEqual(correctMinMaxRowIdsNoWind) - }) - }) -}) diff --git a/web/src/utils/table.ts b/web/src/utils/table.ts deleted file mode 100644 index 12d0a254d..000000000 --- a/web/src/utils/table.ts +++ /dev/null @@ -1,239 +0,0 @@ -import _ from 'lodash' -import { DateTime } from 'luxon' -import { - PRECIP_VALUES_DECIMAL, - RH_VALUES_DECIMAL, - TEMPERATURE_VALUES_DECIMAL, - WIND_SPEED_VALUES_DECIMAL -} from 'utils/constants' -import { ModelValue } from 'api/modelAPI' -import { ObservedValue } from 'api/observationAPI' -import { WeatherValue, Column } from 'features/fireWeather/components/tables/SortableTableByDatetime' - -export type Order = 'asc' | 'desc' - -export interface MinMaxValues { - relative_humidity: number | null - precipitation: number | null - wind_speed: number | null - temperature: { - min: number | null - max: number | null - } -} - -export interface RowIdsOfMinMaxValues { - relative_humidity: number[] - precipitation: number[] - wind: number[] - max_temp: number[] - min_temp: number[] -} - -// More generic approach https://material-ui.com/components/tables/#EnhancedTable.tsx -export const getDatetimeComparator = - (order: Order) => - (a: T, b: T): number => { - const aDate = new Date(a.datetime) - const bDate = new Date(b.datetime) - const diff = aDate.valueOf() - bDate.valueOf() - - return order === 'asc' ? diff : -diff - } - -const calculateMaxPrecip = (rows: WeatherValue[]): number | null => { - // calculates the maximum precip value from a set of table rows (assuming that - // the precip property is named one of 'precipitation', 'delta_precipitation', - // or 'total_precipitation'). Returns null if none of these properties can be - // found in props.rows, or if no precip values are set in the rows, or if the - // maximum value is 0 - let maxPrecip = null - if (_.maxBy(rows, 'precipitation') !== undefined) { - maxPrecip = _.maxBy(rows, 'precipitation')?.precipitation - } else if (_.maxBy(rows, 'delta_precipitation') !== undefined) { - maxPrecip = _.maxBy(rows, 'delta_precipitation')?.delta_precipitation - } else if (_.maxBy(rows, 'total_precipitation') !== undefined) { - maxPrecip = _.maxBy(rows, 'total_precipitation')?.total_precipitation - } - maxPrecip = maxPrecip ?? null - if (maxPrecip !== null && maxPrecip.toFixed(PRECIP_VALUES_DECIMAL) !== '0.0') { - return maxPrecip - } else { - return null - } -} - -export interface AccumulatedPrecipitation { - precipitation: number | undefined - values: (ModelValue | ObservedValue)[] -} - -export const calculateAccumulatedPrecip = ( - noonDate: string, - collection: ModelValue[] | ObservedValue[] | undefined -): AccumulatedPrecipitation | undefined => { - // We are calculating the accumulated precipitation from 24 hours before noon. - const from = DateTime.fromISO(noonDate).toJSDate() - from.setHours(from.getHours() - 24) - const to = DateTime.fromISO(noonDate).toJSDate() - if (collection) { - const precip = { - precipitation: undefined, - values: [] as (ModelValue | ObservedValue)[] - } as AccumulatedPrecipitation - collection.forEach((value: ModelValue | ObservedValue) => { - const precipDate = DateTime.fromISO(value.datetime).toJSDate() - if (precipDate > from && precipDate <= to) { - let precipitate = undefined - if ('delta_precipitation' in value) { - precipitate = value.delta_precipitation - } else if ('precipitation' in value) { - precipitate = value.precipitation - } - if (typeof precipitate === 'number') { - if (precip.precipitation === undefined) { - precip.precipitation = precipitate - } else { - precip.precipitation += precipitate - } - // Keep track of the model run predictions used to calculate this. - precip.values.push(value) - } - } - }) - return precip - } - return undefined -} - -const calculateMaxWindSpeed = (rows: WeatherValue[]): number | null => { - // calculates the maximum wind speed from a set of table rows. - // Returns null if the maximum value is 0.0 (since we don't want every - // wind cell in the table to be highlighted). - const maxWindSpeed = _.maxBy(rows, 'wind_speed')?.wind_speed ?? null - if (maxWindSpeed !== null && maxWindSpeed.toFixed(WIND_SPEED_VALUES_DECIMAL) !== '0.0') { - return maxWindSpeed - } else { - return null - } -} - -export const getMinMaxValueCalculator = (rows: WeatherValue[]): MinMaxValues => { - return { - relative_humidity: _.minBy(rows, 'relative_humidity')?.relative_humidity ?? null, - wind_speed: calculateMaxWindSpeed(rows), - temperature: { - min: _.minBy(rows, 'temperature')?.temperature ?? null, - max: _.maxBy(rows, 'temperature')?.temperature ?? null - }, - precipitation: calculateMaxPrecip(rows) - } -} - -export const getMinMaxValuesRowIds = ( - rows: WeatherValue[], - minMaxValuesToHighlight: MinMaxValues -): RowIdsOfMinMaxValues => { - const rowIds: RowIdsOfMinMaxValues = { - relative_humidity: [], - precipitation: [], - wind: [], - max_temp: [], - min_temp: [] - } - - rows.forEach((row, idx) => { - if ( - row.relative_humidity?.toFixed(RH_VALUES_DECIMAL) === - minMaxValuesToHighlight.relative_humidity?.toFixed(RH_VALUES_DECIMAL) - ) { - rowIds['relative_humidity'].push(idx) - } - if ( - // max precip value may be null if all precip values in props.rows were 0 - minMaxValuesToHighlight.precipitation !== null && - (row.precipitation?.toFixed(PRECIP_VALUES_DECIMAL) === - minMaxValuesToHighlight.precipitation?.toFixed(PRECIP_VALUES_DECIMAL) || - row.delta_precipitation?.toFixed(PRECIP_VALUES_DECIMAL) === - minMaxValuesToHighlight.precipitation?.toFixed(PRECIP_VALUES_DECIMAL) || - row.total_precipitation?.toFixed(PRECIP_VALUES_DECIMAL) === - minMaxValuesToHighlight.precipitation?.toFixed(PRECIP_VALUES_DECIMAL)) - ) { - rowIds['precipitation'].push(idx) - } - if ( - row.temperature?.toFixed(TEMPERATURE_VALUES_DECIMAL) === - minMaxValuesToHighlight.temperature.max?.toFixed(TEMPERATURE_VALUES_DECIMAL) - ) { - rowIds['max_temp'].push(idx) - } - if ( - row.temperature?.toFixed(TEMPERATURE_VALUES_DECIMAL) === - minMaxValuesToHighlight.temperature.min?.toFixed(TEMPERATURE_VALUES_DECIMAL) - ) { - rowIds['min_temp'].push(idx) - } - if ( - minMaxValuesToHighlight.wind_speed !== null && - row.wind_speed?.toFixed(WIND_SPEED_VALUES_DECIMAL) === - minMaxValuesToHighlight.wind_speed?.toFixed(WIND_SPEED_VALUES_DECIMAL) - ) { - rowIds['wind'].push(idx) - } - }) - - return rowIds -} - -export const getCellClassNameAndTestId = ( - column: Column, - rowIds: RowIdsOfMinMaxValues, - idx: number, - classes: Record -): { className: string | undefined; testId: string | undefined } => { - let className = undefined - let testId = undefined - switch (column.id) { - case 'relative_humidity': { - if (rowIds['relative_humidity'].includes(idx)) { - className = classes.minRH - testId = `min-RH-td` - } - break - } - case 'temperature': { - if (rowIds['min_temp'].includes(idx)) { - className = classes.minTemperature - testId = `min-temperature-td` - } else if (rowIds['max_temp'].includes(idx)) { - className = classes.maxTemperature - testId = `max-temperature-td` - } - break - } - case 'precipitation': - case 'delta_precipitation': - case 'total_precipitation': { - if (rowIds['precipitation'].includes(idx)) { - className = classes.maxPrecipitation - testId = `max-precipitation-td` - } - break - } - case 'wind_speed': { - if (rowIds['wind'].includes(idx)) { - className = classes.maxWindSpeed - testId = `max-wind-speed-td` - } - break - } - case 'wind_direction': { - if (rowIds['wind'].includes(idx)) { - className = classes.directionOfMaxWindSpeed - testId = `direction-max-wind-speed-td` - } - break - } - } - return { className, testId } -} diff --git a/web/yarn.lock b/web/yarn.lock index 095aa29f8..7fba232c2 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -1152,13 +1152,6 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@choojs/findup@^0.2.0": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@choojs/findup/-/findup-0.2.1.tgz#ac13c59ae7be6e1da64de0779a0a7f03d75615a3" - integrity sha512-YstAqNb0MCN8PjdLCDfRsBcGVRN41f3vgLvaI0IrIcBp4AqILRSS0DeWNGkicC+f/zRIPJLc+9RURVSepwvfBw== - dependencies: - commander "^2.15.1" - "@colors/colors@1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" @@ -1862,56 +1855,6 @@ resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== -"@mapbox/geojson-rewind@^0.5.0": - version "0.5.2" - resolved "https://registry.yarnpkg.com/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz#591a5d71a9cd1da1a0bf3420b3bea31b0fc7946a" - integrity sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA== - dependencies: - get-stream "^6.0.1" - minimist "^1.2.6" - -"@mapbox/geojson-types@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@mapbox/geojson-types/-/geojson-types-1.0.2.tgz#9aecf642cb00eab1080a57c4f949a65b4a5846d6" - integrity sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw== - -"@mapbox/jsonlint-lines-primitives@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz#ce56e539f83552b58d10d672ea4d6fc9adc7b234" - integrity sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ== - -"@mapbox/mapbox-gl-supported@^1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-1.5.0.tgz#f60b6a55a5d8e5ee908347d2ce4250b15103dc8e" - integrity sha512-/PT1P6DNf7vjEEiPkVIRJkvibbqWtqnyGaBz3nfRdcxclNSnSdaLU5tfAgcD7I8Yt5i+L19s406YLl1koLnLbg== - -"@mapbox/point-geometry@0.1.0", "@mapbox/point-geometry@^0.1.0", "@mapbox/point-geometry@~0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz#8a83f9335c7860effa2eeeca254332aa0aeed8f2" - integrity sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ== - -"@mapbox/tiny-sdf@^1.1.1": - version "1.2.5" - resolved "https://registry.yarnpkg.com/@mapbox/tiny-sdf/-/tiny-sdf-1.2.5.tgz#424c620a96442b20402552be70a7f62a8407cc59" - integrity sha512-cD8A/zJlm6fdJOk6DqPUV8mcpyJkRz2x2R+/fYcWDYG3oWbG7/L7Yl/WqQ1VZCjnL9OTIMAn6c+BC5Eru4sQEw== - -"@mapbox/unitbezier@^0.0.0": - version "0.0.0" - resolved "https://registry.yarnpkg.com/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz#15651bd553a67b8581fb398810c98ad86a34524e" - integrity sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA== - -"@mapbox/vector-tile@^1.3.1": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz#d3a74c90402d06e89ec66de49ec817ff53409666" - integrity sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw== - dependencies: - "@mapbox/point-geometry" "~0.1.0" - -"@mapbox/whoots-js@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz#497c67a1cef50d1a2459ba60f315e448d2ad87fe" - integrity sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q== - "@mui/base@5.0.0-beta.18", "@mui/base@^5.0.0-beta.17": version "5.0.0-beta.18" resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.18.tgz#f95d393cf80974e77c0823170cc15c854d5af84b" @@ -2060,46 +2003,6 @@ resolved "https://registry.yarnpkg.com/@petamoriken/float16/-/float16-3.8.4.tgz#cd3c02a7fe39f10ae3dd24ed33bd082053aadd66" integrity sha512-kB+NJ5Br56ZhElKsf0pM7/PQfrDdDVMRz8f0JM6eVOGE+L89z9hwcst9QvWBBnazzuqGTGtPsJNZoQ1JdNiGSQ== -"@plotly/d3-sankey-circular@0.33.1": - version "0.33.1" - resolved "https://registry.yarnpkg.com/@plotly/d3-sankey-circular/-/d3-sankey-circular-0.33.1.tgz#15d1e0337e0e4b1135bdf0e2195c88adacace1a7" - integrity sha512-FgBV1HEvCr3DV7RHhDsPXyryknucxtfnLwPtCKKxdolKyTFYoLX/ibEfX39iFYIL7DYbVeRtP43dbFcrHNE+KQ== - dependencies: - d3-array "^1.2.1" - d3-collection "^1.0.4" - d3-shape "^1.2.0" - elementary-circuits-directed-graph "^1.0.4" - -"@plotly/d3-sankey@0.7.2": - version "0.7.2" - resolved "https://registry.yarnpkg.com/@plotly/d3-sankey/-/d3-sankey-0.7.2.tgz#ddd5290d3b02c60037ced018a162644a2ccef33b" - integrity sha512-2jdVos1N3mMp3QW0k2q1ph7Gd6j5PY1YihBrwpkFnKqO+cqtZq3AdEYUeSGXMeLsBDQYiqTVcihYfk8vr5tqhw== - dependencies: - d3-array "1" - d3-collection "1" - d3-shape "^1.2.0" - -"@plotly/d3@3.8.1": - version "3.8.1" - resolved "https://registry.yarnpkg.com/@plotly/d3/-/d3-3.8.1.tgz#674bf19809ffcc359e0ab388a1051f2dac5e6877" - integrity sha512-x49ThEu1FRA00kTso4Jdfyf2byaCPLBGmLjAYQz5OzaPyLUhHesX3/Nfv2OHEhynhdy2UB39DLXq6thYe2L2kg== - -"@plotly/point-cluster@^3.1.9": - version "3.1.9" - resolved "https://registry.yarnpkg.com/@plotly/point-cluster/-/point-cluster-3.1.9.tgz#8ffec77fbf5041bf15401079e4fdf298220291c1" - integrity sha512-MwaI6g9scKf68Orpr1pHZ597pYx9uP8UEFXLPbsCmuw3a84obwz6pnMXGc90VhgDNeNiLEdlmuK7CPo+5PIxXw== - dependencies: - array-bounds "^1.0.1" - binary-search-bounds "^2.0.4" - clamp "^1.0.1" - defined "^1.0.0" - dtype "^2.0.0" - flatten-vertex-data "^1.0.2" - is-obj "^1.0.1" - math-log2 "^1.0.1" - parse-rect "^1.2.0" - pick-by-alias "^1.2.0" - "@pmmmwh/react-refresh-webpack-plugin@^0.5.3": version "0.5.11" resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.11.tgz#7c2268cedaa0644d677e8c4f377bc8fb304f714a" @@ -2436,42 +2339,6 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== -"@turf/area@^6.4.0": - version "6.5.0" - resolved "https://registry.yarnpkg.com/@turf/area/-/area-6.5.0.tgz#1d0d7aee01d8a4a3d4c91663ed35cc615f36ad56" - integrity sha512-xCZdiuojokLbQ+29qR6qoMD89hv+JAgWjLrwSEWL+3JV8IXKeNFl6XkEJz9HGkVpnXvQKJoRz4/liT+8ZZ5Jyg== - dependencies: - "@turf/helpers" "^6.5.0" - "@turf/meta" "^6.5.0" - -"@turf/bbox@^6.4.0": - version "6.5.0" - resolved "https://registry.yarnpkg.com/@turf/bbox/-/bbox-6.5.0.tgz#bec30a744019eae420dac9ea46fb75caa44d8dc5" - integrity sha512-RBbLaao5hXTYyyg577iuMtDB8ehxMlUqHEJiMs8jT1GHkFhr6sYre3lmLsPeYEi/ZKj5TP5tt7fkzNdJ4GIVyw== - dependencies: - "@turf/helpers" "^6.5.0" - "@turf/meta" "^6.5.0" - -"@turf/centroid@^6.0.2": - version "6.5.0" - resolved "https://registry.yarnpkg.com/@turf/centroid/-/centroid-6.5.0.tgz#ecaa365412e5a4d595bb448e7dcdacfb49eb0009" - integrity sha512-MwE1oq5E3isewPprEClbfU5pXljIK/GUOMbn22UM3IFPDJX0KeoyLNwghszkdmFp/qMGL/M13MMWvU+GNLXP/A== - dependencies: - "@turf/helpers" "^6.5.0" - "@turf/meta" "^6.5.0" - -"@turf/helpers@^6.5.0": - version "6.5.0" - resolved "https://registry.yarnpkg.com/@turf/helpers/-/helpers-6.5.0.tgz#f79af094bd6b8ce7ed2bd3e089a8493ee6cae82e" - integrity sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw== - -"@turf/meta@^6.5.0": - version "6.5.0" - resolved "https://registry.yarnpkg.com/@turf/meta/-/meta-6.5.0.tgz#b725c3653c9f432133eaa04d3421f7e51e0418ca" - integrity sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA== - dependencies: - "@turf/helpers" "^6.5.0" - "@types/aria-query@^5.0.1": version "5.0.2" resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.2.tgz#6f1225829d89794fd9f891989c9ce667422d7f64" @@ -3346,11 +3213,6 @@ abab@^2.0.3, abab@^2.0.5: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== -abs-svg-path@^0.1.1, abs-svg-path@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/abs-svg-path/-/abs-svg-path-0.1.1.tgz#df601c8e8d2ba10d4a76d625e236a9a39c2723bf" - integrity sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA== - accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" @@ -3464,11 +3326,6 @@ ajv@^8.0.0, ajv@^8.6.0, ajv@^8.9.0: require-from-string "^2.0.2" uri-js "^4.2.2" -almost-equal@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/almost-equal/-/almost-equal-1.1.0.tgz#f851c631138757994276aa2efbe8dfa3066cccdd" - integrity sha512-0V/PkoculFl5+0Lp47JoxUcO0xSxhIBvm+BxHdD/OgXNmdRpRHCFnKVuUoWyS9EzQP+otSGv0m9Lb4yVkQBn2A== - ansi-colors@^4.1.1: version "4.1.3" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" @@ -3581,11 +3438,6 @@ aria-query@^5.0.0, aria-query@^5.1.3: dependencies: dequal "^2.0.3" -array-bounds@^1.0.0, array-bounds@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/array-bounds/-/array-bounds-1.0.1.tgz#da11356b4e18e075a4f0c86e1f179a67b7d7ea31" - integrity sha512-8wdW3ZGk6UjMPJx/glyEt0sLzzwAE1bhToPsO1W2pbpR2gULyxe3BjSiuJFheP50T/GgODVPz2fuMUmIywt8cQ== - array-buffer-byte-length@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" @@ -3594,11 +3446,6 @@ array-buffer-byte-length@^1.0.0: call-bind "^1.0.2" is-array-buffer "^3.0.1" -array-find-index@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - integrity sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw== - array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -3620,23 +3467,6 @@ array-includes@^3.1.6: get-intrinsic "^1.2.1" is-string "^1.0.7" -array-normalize@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/array-normalize/-/array-normalize-1.1.4.tgz#d75cec57383358af38efdf6a78071aa36ae4174c" - integrity sha512-fCp0wKFLjvSPmCn4F5Tiw4M3lpMZoHlCjfcs7nNzuj3vqQQ1/a8cgB9DXcpDSn18c+coLnaW7rqfcYCvKbyJXg== - dependencies: - array-bounds "^1.0.0" - -array-range@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/array-range/-/array-range-1.0.1.tgz#f56e46591843611c6a56f77ef02eda7c50089bfc" - integrity sha512-shdaI1zT3CVNL2hnx9c0JMc0ZogGaxDs5e85akgHWKYa0yVbIyp06Ind3dVkTj/uuFrzaHBOyqFzo+VV6aXgtA== - -array-rearrange@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/array-rearrange/-/array-rearrange-2.2.2.tgz#fa1a2acf8d02e88dd0c9602aa0e06a79158b2283" - integrity sha512-UfobP5N12Qm4Qu4fwLDIi2v6+wZsSf6snYSxAMeKhrh37YGnNWZPRmVEKc/2wfms53TLQnzfpG8wCx2Y/6NG1w== - array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" @@ -4003,29 +3833,6 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -binary-search-bounds@^2.0.4: - version "2.0.5" - resolved "https://registry.yarnpkg.com/binary-search-bounds/-/binary-search-bounds-2.0.5.tgz#125e5bd399882f71e6660d4bf1186384e989fba7" - integrity sha512-H0ea4Fd3lS1+sTEB2TgcLoK21lLhwEJzlQv3IN47pJS976Gx4zoWe0ak3q+uYh60ppQxg9F16Ri4tS1sfD4+jA== - -bit-twiddle@^1.0.0, bit-twiddle@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bit-twiddle/-/bit-twiddle-1.0.2.tgz#0c6c1fabe2b23d17173d9a61b7b7093eb9e1769e" - integrity sha512-B9UhK0DKFZhoTFcfvAzhqsjStvGJp9vYWf3+6SNTtdSQnvIgfkHbgHrg/e4+TH71N2GDu8tpmCVoyfrL1d7ntA== - -bitmap-sdf@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/bitmap-sdf/-/bitmap-sdf-1.0.4.tgz#e87b8b1d84ee846567cfbb29d60eedd34bca5b6f" - integrity sha512-1G3U4n5JE6RAiALMxu0p1XmeZkTeCwGKykzsLTCqVzfSDaN6S7fKnkIkfejogz+iwqBWc0UYAIKnKHNN7pSfDg== - -bl@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.1.tgz#8c11a7b730655c5d56898cdc871224f40fd901d5" - integrity sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g== - dependencies: - readable-stream "^2.3.5" - safe-buffer "^5.1.1" - blob-util@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/blob-util/-/blob-util-2.0.2.tgz#3b4e3c281111bb7f11128518006cdc60b403a1eb" @@ -4217,13 +4024,6 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001546.tgz#10fdad03436cfe3cc632d3af7a99a0fb497407f0" integrity sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw== -canvas-fit@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/canvas-fit/-/canvas-fit-1.5.0.tgz#ae13be66ade42f5be0e487e345fce30a5e5b5e5f" - integrity sha512-onIcjRpz69/Hx5bB5HGbYKUF2uC6QT6Gp+pfpGm3A7mPfcluSLV5v4Zu+oflDUwLdUw0rLIBhUbi0v8hM4FJQQ== - dependencies: - element-size "^1.1.1" - case-sensitive-paths-webpack-plugin@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4" @@ -4309,11 +4109,6 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== -clamp@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/clamp/-/clamp-1.0.1.tgz#66a0e64011816e37196828fdc8c8c147312c8634" - integrity sha512-kgMuFyE78OC6Dyu3Dy7vcx4uy97EIbVxJB/B0eJ3bUNAkwdNcxYzgKltnyADiYwsR7SEqkkUPsEUT//OVS6XMA== - classnames@^2.2.5: version "2.3.2" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" @@ -4406,20 +4201,6 @@ collect-v8-coverage@^1.0.0: resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== -color-alpha@1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/color-alpha/-/color-alpha-1.0.4.tgz#c141dc926e95fc3db647d0e14e5bc3651c29e040" - integrity sha512-lr8/t5NPozTSqli+duAN+x+no/2WaKTeWvxhHGN+aXT6AJ8vPlzLa7UriyjWak0pSC2jHol9JgjBYnnHsGha9A== - dependencies: - color-parse "^1.3.8" - -color-alpha@^1.0.4: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-alpha/-/color-alpha-1.1.3.tgz#71250189e9f02bba8261a94d5e7d5f5606d1749a" - integrity sha512-krPYBO1RSO5LH4AGb/b6z70O1Ip2o0F0+0cVFN5FN99jfQtZFT08rQyg+9oOBNJYAn3SRwJIFC8jUEOKz7PisA== - dependencies: - color-parse "^1.4.1" - color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -4434,86 +4215,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-id@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/color-id/-/color-id-1.1.0.tgz#5e9159b99a73ac98f74820cb98a15fde3d7e034c" - integrity sha512-2iRtAn6dC/6/G7bBIo0uupVrIne1NsQJvJxZOBCzQOfk7jRq97feaDZ3RdzuHakRXXnHGNwglto3pqtRx1sX0g== - dependencies: - clamp "^1.0.1" - color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== -color-name@^1.0.0, color-name@~1.1.4: +color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-normalize@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/color-normalize/-/color-normalize-1.5.0.tgz#ee610af9acb15daf73e77a945a847b18e40772da" - integrity sha512-rUT/HDXMr6RFffrR53oX3HGWkDOP9goSAQGBkUaAYKjOE2JxozccdGyufageWDlInRAjm/jYPrf/Y38oa+7obw== - dependencies: - clamp "^1.0.1" - color-rgba "^2.1.1" - dtype "^2.0.0" - -color-normalize@^1.5.0: - version "1.5.2" - resolved "https://registry.yarnpkg.com/color-normalize/-/color-normalize-1.5.2.tgz#d6c8beb02966849548f91a6ac0274c6f19924509" - integrity sha512-yYMIoyFJmUoKbCK6sBShljBWfkt8DXVfaZJn9/zvRJkF9eQJDbZhcYC6LdOVy40p4tfVwYYb9cXl8oqpu7pzBw== - dependencies: - color-rgba "^2.2.0" - dtype "^2.0.0" - -color-parse@1.3.8: - version "1.3.8" - resolved "https://registry.yarnpkg.com/color-parse/-/color-parse-1.3.8.tgz#eaf54cd385cb34c0681f18c218aca38478082fa3" - integrity sha512-1Y79qFv0n1xair3lNMTNeoFvmc3nirMVBij24zbs1f13+7fPpQClMg5b4AuKXLt3szj7BRlHMCXHplkce6XlmA== - dependencies: - color-name "^1.0.0" - defined "^1.0.0" - is-plain-obj "^1.1.0" - -color-parse@^1.3.8, color-parse@^1.4.1, color-parse@^1.4.2: - version "1.4.3" - resolved "https://registry.yarnpkg.com/color-parse/-/color-parse-1.4.3.tgz#6dadfb49128c554c60c49d63f3d025f2c5a7ff22" - integrity sha512-BADfVl/FHkQkyo8sRBwMYBqemqsgnu7JZAwUgvBvuwwuNUZAhSvLTbsEErS5bQXzOjDR0dWzJ4vXN2Q+QoPx0A== - dependencies: - color-name "^1.0.0" - -color-rgba@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/color-rgba/-/color-rgba-2.1.1.tgz#4633b83817c7406c90b3d7bf4d1acfa48dde5c83" - integrity sha512-VaX97wsqrMwLSOR6H7rU1Doa2zyVdmShabKrPEIFywLlHoibgD3QW9Dw6fSqM4+H/LfjprDNAUUW31qEQcGzNw== - dependencies: - clamp "^1.0.1" - color-parse "^1.3.8" - color-space "^1.14.6" - -color-rgba@^2.1.1, color-rgba@^2.2.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/color-rgba/-/color-rgba-2.4.0.tgz#ae85819c530262c29fc2da129fc7c8f9efc57015" - integrity sha512-Nti4qbzr/z2LbUWySr7H9dk3Rl7gZt7ihHAxlgT4Ho90EXWkjtkL1avTleu9yeGuqrt/chxTB6GKK8nZZ6V0+Q== - dependencies: - color-parse "^1.4.2" - color-space "^2.0.0" - -color-space@^1.14.6: - version "1.16.0" - resolved "https://registry.yarnpkg.com/color-space/-/color-space-1.16.0.tgz#611781bca41cd8582a1466fd9e28a7d3d89772a2" - integrity sha512-A6WMiFzunQ8KEPFmj02OnnoUnqhmSaHaZ/0LVFcPTdlvm8+3aMJ5x1HRHy3bDHPkovkf4sS0f4wsVvwk71fKkg== - dependencies: - hsluv "^0.0.3" - mumath "^3.3.4" - -color-space@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-space/-/color-space-2.0.1.tgz#da39871175baf4a5785ba519397df04b8d67e0fa" - integrity sha512-nKqUYlo0vZATVOFHY810BSYjmCARrG7e5R3UE3CQlyjJTvv5kSSmPG1kzm/oDyyqjehM+lW1RnEt9It9GNa5JA== - colord@^2.9.1: version "2.9.3" resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" @@ -4531,7 +4242,7 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" -commander@2, commander@^2.15.1, commander@^2.20.0: +commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -4596,16 +4307,6 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -concat-stream@^1.5.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - confusing-browser-globals@^1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" @@ -4705,11 +4406,6 @@ cosmiconfig@^7, cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: path-type "^4.0.0" yaml "^1.10.0" -country-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/country-regex/-/country-regex-1.1.0.tgz#51c333dcdf12927b7e5eeb9c10ac8112a6120896" - integrity sha512-iSPlClZP8vX7MC3/u6s3lrDuoQyhQukh5LyABJ3hvfzbQ3Yyayd4fp04zjLnfi267B/B2FkumcWWgrbban7sSA== - create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" @@ -4741,46 +4437,6 @@ css-declaration-sorter@^6.3.1: resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz#28beac7c20bad7f1775be3a7129d7eae409a3a71" integrity sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g== -css-font-size-keywords@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/css-font-size-keywords/-/css-font-size-keywords-1.0.0.tgz#854875ace9aca6a8d2ee0d345a44aae9bb6db6cb" - integrity sha512-Q+svMDbMlelgCfH/RVDKtTDaf5021O486ZThQPIpahnIjUkMUslC+WuOQSWTgGSrNCH08Y7tYNEmmy0hkfMI8Q== - -css-font-stretch-keywords@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/css-font-stretch-keywords/-/css-font-stretch-keywords-1.0.1.tgz#50cee9b9ba031fb5c952d4723139f1e107b54b10" - integrity sha512-KmugPO2BNqoyp9zmBIUGwt58UQSfyk1X5DbOlkb2pckDXFSAfjsD5wenb88fNrD6fvS+vu90a/tsPpb9vb0SLg== - -css-font-style-keywords@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/css-font-style-keywords/-/css-font-style-keywords-1.0.1.tgz#5c3532813f63b4a1de954d13cea86ab4333409e4" - integrity sha512-0Fn0aTpcDktnR1RzaBYorIxQily85M2KXRpzmxQPgh8pxUN9Fcn00I8u9I3grNr1QXVgCl9T5Imx0ZwKU973Vg== - -css-font-weight-keywords@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/css-font-weight-keywords/-/css-font-weight-keywords-1.0.0.tgz#9bc04671ac85bc724b574ef5d3ac96b0d604fd97" - integrity sha512-5So8/NH+oDD+EzsnF4iaG4ZFHQ3vaViePkL1ZbZ5iC/KrsCY+WHq/lvOgrtmuOQ9pBBZ1ADGpaf+A4lj1Z9eYA== - -css-font@^1.0.0, css-font@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/css-font/-/css-font-1.2.0.tgz#e73cbdc11fd87c8e6c928ad7098a9771c8c2b6e3" - integrity sha512-V4U4Wps4dPDACJ4WpgofJ2RT5Yqwe1lEH6wlOOaIxMi0gTjdIijsc5FmxQlZ7ZZyKQkkutqqvULOp07l9c7ssA== - dependencies: - css-font-size-keywords "^1.0.0" - css-font-stretch-keywords "^1.0.1" - css-font-style-keywords "^1.0.1" - css-font-weight-keywords "^1.0.0" - css-global-keywords "^1.0.1" - css-system-font-keywords "^1.0.0" - pick-by-alias "^1.2.0" - string-split-by "^1.0.0" - unquote "^1.1.0" - -css-global-keywords@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/css-global-keywords/-/css-global-keywords-1.0.1.tgz#72a9aea72796d019b1d2a3252de4e5aaa37e4a69" - integrity sha512-X1xgQhkZ9n94WDwntqst5D/FKkmiU0GlJSFZSV3kLvyJ1WC5VeyoXDOuleUD+SIuH9C7W05is++0Woh0CGfKjQ== - css-has-pseudo@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz#57f6be91ca242d5c9020ee3e51bbb5b89fc7af73" @@ -4845,11 +4501,6 @@ css-select@^4.1.3: domutils "^2.8.0" nth-check "^2.0.1" -css-system-font-keywords@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/css-system-font-keywords/-/css-system-font-keywords-1.0.0.tgz#85c6f086aba4eb32c571a3086affc434b84823ed" - integrity sha512-1umTtVd/fXS25ftfjB71eASCrYhilmEsvDEI6wG/QplnmlfmVM5HkZ/ZX46DT5K3eblFPgLUHt5BRCb0YXkSFA== - css-tree@1.0.0-alpha.37: version "1.0.0-alpha.37" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" @@ -4886,11 +4537,6 @@ css.escape@^1.5.1: resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== -csscolorparser@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/csscolorparser/-/csscolorparser-1.0.3.tgz#b34f391eea4da8f3e98231e2ccd8df9c041f171b" - integrity sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w== - cssdb@^7.1.0: version "7.8.0" resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-7.8.0.tgz#ac41fa025371b74eb2ccfe3d41f5c4dbd444fbe3" @@ -5028,11 +4674,6 @@ cypress@^13.0.0: untildify "^4.0.0" yauzl "^2.10.0" -d3-array@1, d3-array@^1.2.1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f" - integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw== - "d3-array@2 - 3", "d3-array@2.10.0 - 3", d3-array@^3.1.6: version "3.2.4" resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.4.tgz#15fec33b237f97ac5d7c986dc77da273a8ed0bb5" @@ -5040,68 +4681,21 @@ d3-array@1, d3-array@^1.2.1: dependencies: internmap "1 - 2" -d3-collection@1, d3-collection@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.7.tgz#349bd2aa9977db071091c13144d5e4f16b5b310e" - integrity sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A== - "d3-color@1 - 3": version "3.1.0" resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== -d3-dispatch@1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.6.tgz#00d37bcee4dd8cd97729dd893a0ac29caaba5d58" - integrity sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA== - d3-ease@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== -d3-force@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-1.2.1.tgz#fd29a5d1ff181c9e7f0669e4bd72bdb0e914ec0b" - integrity sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg== - dependencies: - d3-collection "1" - d3-dispatch "1" - d3-quadtree "1" - d3-timer "1" - "d3-format@1 - 3": version "3.1.0" resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641" integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA== -d3-format@^1.4.5: - version "1.4.5" - resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.5.tgz#374f2ba1320e3717eb74a9356c67daee17a7edb4" - integrity sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ== - -d3-geo-projection@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/d3-geo-projection/-/d3-geo-projection-2.9.0.tgz#826db62f748e8ecd67cd00aced4c26a236ec030c" - integrity sha512-ZULvK/zBn87of5rWAfFMc9mJOipeSo57O+BBitsKIXmU4rTVAnX1kSsJkE0R+TxY8pGNoM1nbyRRE7GYHhdOEQ== - dependencies: - commander "2" - d3-array "1" - d3-geo "^1.12.0" - resolve "^1.1.10" - -d3-geo@^1.12.0, d3-geo@^1.12.1: - version "1.12.1" - resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-1.12.1.tgz#7fc2ab7414b72e59fbcbd603e80d9adc029b035f" - integrity sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg== - dependencies: - d3-array "1" - -d3-hierarchy@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz#2f6bee24caaea43f8dc37545fa01628559647a83" - integrity sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ== - "d3-interpolate@1.2.0 - 3", d3-interpolate@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" @@ -5109,21 +4703,11 @@ d3-hierarchy@^1.1.9: dependencies: d3-color "1 - 3" -d3-path@1: - version "1.0.9" - resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf" - integrity sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg== - d3-path@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.1.0.tgz#22df939032fb5a71ae8b1800d61ddb7851c42526" integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ== -d3-quadtree@1: - version "1.0.7" - resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-1.0.7.tgz#ca8b84df7bb53763fe3c2f24bd435137f4e53135" - integrity sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA== - d3-scale@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396" @@ -5135,13 +4719,6 @@ d3-scale@^4.0.2: d3-time "2.1.1 - 3" d3-time-format "2 - 4" -d3-shape@^1.2.0: - version "1.3.7" - resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7" - integrity sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw== - dependencies: - d3-path "1" - d3-shape@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.2.0.tgz#a1a839cbd9ba45f28674c69d7f855bcf91dfc6a5" @@ -5156,18 +4733,6 @@ d3-shape@^3.1.0: dependencies: d3-time "1 - 3" -d3-time-format@^2.2.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.3.0.tgz#107bdc028667788a8924ba040faf1fbccd5a7850" - integrity sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ== - dependencies: - d3-time "1" - -d3-time@1, d3-time@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.1.0.tgz#b1e19d307dae9c900b7e5b25ffc5dcc249a8a0f1" - integrity sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA== - "d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.1.0.tgz#9310db56e992e3c0175e1ef385e545e48a9bb5c7" @@ -5175,24 +4740,11 @@ d3-time@1, d3-time@^1.1.0: dependencies: d3-array "2 - 3" -d3-timer@1: - version "1.0.10" - resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.10.tgz#dfe76b8a91748831b13b6d9c793ffbd508dd9de5" - integrity sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw== - d3-timer@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== -d@1, d@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" - integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== - dependencies: - es5-ext "^0.10.50" - type "^1.0.1" - damerau-levenshtein@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" @@ -5231,7 +4783,7 @@ dayjs@^1.10.4: resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0" integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ== -debug@2, debug@2.6.9, debug@^2.6.0: +debug@2.6.9, debug@^2.6.0: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -5252,7 +4804,7 @@ debug@4.2.0: dependencies: ms "2.1.2" -debug@^3.1.0, debug@^3.2.6, debug@^3.2.7: +debug@^3.1.0, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== @@ -5350,11 +4902,6 @@ define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0, de has-property-descriptors "^1.0.0" object-keys "^1.1.1" -defined@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf" - integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q== - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -5380,11 +4927,6 @@ destroy@1.2.0: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== -detect-kerning@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/detect-kerning/-/detect-kerning-2.1.2.tgz#4ecd548e4a5a3fc880fe2a50609312d000fa9fc2" - integrity sha512-I3JIbrnKPAntNLl1I6TpSQQdQ4AutYzv/sKMFKbepawV/hlH0GmYKhUoOEMd4xqaUHT+Bm0f4127lh5qs1m1tw== - detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -5564,40 +5106,12 @@ dotenv@^10.0.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== -draw-svg-path@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/draw-svg-path/-/draw-svg-path-1.0.0.tgz#6f116d962dd314b99ea534d6f58dd66cdbd69379" - integrity sha512-P8j3IHxcgRMcY6sDzr0QvJDLzBnJJqpTG33UZ2Pvp8rw0apCHhJCWqYprqrXjrgHnJ6tuhP1iTJSAodPDHxwkg== - dependencies: - abs-svg-path "~0.1.1" - normalize-svg-path "~0.1.0" - -dtype@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/dtype/-/dtype-2.0.0.tgz#cd052323ce061444ecd2e8f5748f69a29be28434" - integrity sha512-s2YVcLKdFGS0hpFqJaTwscsyt0E8nNFdmo73Ocd81xNPj4URI4rj6D60A+vFMIw7BXWlb4yRkEwfBqcZzPGiZg== - -dup@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/dup/-/dup-1.0.0.tgz#51fc5ac685f8196469df0b905e934b20af5b4029" - integrity sha512-Bz5jxMMC0wgp23Zm15ip1x8IhYRqJvF3nFC0UInJUDkN1z4uNPk9jTnfCUJXbOGiQ1JbXLQsiV41Fb+HXcj5BA== - duplexer@^0.1.2, duplexer@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== -duplexify@^3.4.5: - version "3.7.1" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" - integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - -earcut@^2.1.5, earcut@^2.2.2, earcut@^2.2.3: +earcut@^2.2.3: version "2.2.4" resolved "https://registry.yarnpkg.com/earcut/-/earcut-2.2.4.tgz#6d02fd4d68160c114825d06890a92ecaae60343a" integrity sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ== @@ -5627,18 +5141,6 @@ electron-to-chromium@^1.4.535: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.545.tgz#ab55fcd18796f26e2d124181792ca8b3f013c4b1" integrity sha512-G1HKumUw+y5yxMjewGfKz0XrqG6O+Tb4zrlC/Vs1+9riRXBuFlO0hOEXP3xeI+ltlJkbVUuLkYdmjHYH6Jkiow== -element-size@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/element-size/-/element-size-1.1.1.tgz#64e5f159d97121631845bcbaecaf279c39b5e34e" - integrity sha512-eaN+GMOq/Q+BIWy0ybsgpcYImjGIdNLyjLFJU4XsLHXYQao5jCNb36GyN6C2qwmDDYSfIBmKpPpr4VnBdLCsPQ== - -elementary-circuits-directed-graph@^1.0.4: - version "1.3.1" - resolved "https://registry.yarnpkg.com/elementary-circuits-directed-graph/-/elementary-circuits-directed-graph-1.3.1.tgz#31c5a1c69517de833127247e5460472168e9e1c1" - integrity sha512-ZEiB5qkn2adYmpXGnJKkxT8uJHlW/mxmBpmeqawEHzPxh9HkLD4/1mFYX5l0On+f6rcPIt8/EWlRU2Vo3fX6dQ== - dependencies: - strongly-connected-components "^1.0.1" - emittery@^0.10.2: version "0.10.2" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933" @@ -5669,7 +5171,7 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== -end-of-stream@^1.0.0, end-of-stream@^1.1.0: +end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -5826,47 +5328,11 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50: - version "0.10.62" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5" - integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA== - dependencies: - es6-iterator "^2.0.3" - es6-symbol "^3.1.3" - next-tick "^1.1.0" - es6-error@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== -es6-iterator@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-symbol@^3.1.1, es6-symbol@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" - integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== - dependencies: - d "^1.0.1" - ext "^1.1.2" - -es6-weak-map@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.3.tgz#b6da1f16cc2cc0d9be43e6bdbfc5e7dfcdf31d53" - integrity sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA== - dependencies: - d "1" - es5-ext "^0.10.46" - es6-iterator "^2.0.3" - es6-symbol "^3.1.1" - escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -5892,7 +5358,7 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -escodegen@^1.11.1, escodegen@^1.8.1: +escodegen@^1.8.1: version "1.14.3" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== @@ -6331,13 +5797,6 @@ express@^4.17.3: utils-merge "1.0.1" vary "~1.1.2" -ext@^1.1.2: - version "1.7.0" - resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f" - integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== - dependencies: - type "^2.7.2" - extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" @@ -6364,14 +5823,6 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== -falafel@^2.1.0: - version "2.2.5" - resolved "https://registry.yarnpkg.com/falafel/-/falafel-2.2.5.tgz#3ccb4970a09b094e9e54fead2deee64b4a589d56" - integrity sha512-HuC1qF9iTnHDnML9YZAdCDQwT0yKl/U55K4XSUXqGAA2GLoafFgWRqdAbhWJxXaYD4pyoVxAJ8wH670jMpI9DQ== - dependencies: - acorn "^7.1.1" - isarray "^2.0.1" - fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -6398,13 +5849,6 @@ fast-glob@^3.1.1, fast-glob@^3.2.12, fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-isnumeric@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/fast-isnumeric/-/fast-isnumeric-1.1.4.tgz#e165786ff471c439e9ace2b8c8e66cceb47e2ea4" - integrity sha512-1mM8qOr2LYz8zGaUdmiqRDiuue00Dxjgcb1NQR7TnhLVh6sQyngP9xvLo7Sl7LZpP/sk5eb+bcyWXw530NTBZw== - dependencies: - is-string-blank "^1.0.1" - fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -6565,32 +6009,11 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== -flatten-vertex-data@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/flatten-vertex-data/-/flatten-vertex-data-1.0.2.tgz#889fd60bea506006ca33955ee1105175fb620219" - integrity sha512-BvCBFK2NZqerFTdMDgqfHBwxYWnxeCkwONsw6PvBMcUXqo8U/KDWwmXhqx1x2kLIg7DqIsJfOaJFOmlua3Lxuw== - dependencies: - dtype "^2.0.0" - follow-redirects@^1.0.0, follow-redirects@^1.14.9, follow-redirects@^1.15.0: version "1.15.3" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== -font-atlas@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/font-atlas/-/font-atlas-2.1.0.tgz#aa2d6dcf656a6c871d66abbd3dfbea2f77178348" - integrity sha512-kP3AmvX+HJpW4w3d+PiPR2X6E1yvsBXt2yhuCw+yReO9F1WYhvZwx3c95DGZGwg9xYzDGrgJYa885xmVA+28Cg== - dependencies: - css-font "^1.0.0" - -font-measure@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/font-measure/-/font-measure-1.2.2.tgz#41dbdac5d230dbf4db08865f54da28a475e83026" - integrity sha512-mRLEpdrWzKe9hbfaF3Qpr06TAjquuBVP5cHy4b3hyeNdjc9i0PO6HniGsX5vjL5OWv7+Bd++NiooNpT/s8BvIA== - dependencies: - css-font "^1.2.0" - for-each@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -6672,14 +6095,6 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== -from2@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - integrity sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g== - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - from@~0: version "0.1.7" resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" @@ -6749,11 +6164,6 @@ gensync@^1.0.0-beta.2: resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== -geojson-vt@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/geojson-vt/-/geojson-vt-3.2.1.tgz#f8adb614d2c1d3f6ee7c4265cad4bbf3ad60c8b7" - integrity sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg== - geotiff@^2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/geotiff/-/geotiff-2.0.7.tgz#358e578233af70bfb0b4dee62d599ad78fc5cfca" @@ -6772,11 +6182,6 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-canvas-context@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-canvas-context/-/get-canvas-context-1.0.2.tgz#d6e7b50bc4e4c86357cd39f22647a84b73601e93" - integrity sha512-LnpfLf/TNzr9zVOGiIY6aKCz8EKuXmlYNV7CM2pUjBa/B+c2I15tS7KLySep75+FuerJdmArvJLcsAXWEy2H0A== - get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" @@ -6804,7 +6209,7 @@ get-stream@^5.0.0, get-stream@^5.1.0: dependencies: pump "^3.0.0" -get-stream@^6.0.0, get-stream@^6.0.1: +get-stream@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== @@ -6831,52 +6236,6 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -gl-mat4@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/gl-mat4/-/gl-mat4-1.2.0.tgz#49d8a7636b70aa00819216635f4a3fd3f4669b26" - integrity sha512-sT5C0pwB1/e9G9AvAoLsoaJtbMGjfd/jfxo8jMCKqYYEnjZuFvqV5rehqar0538EmssjdDeiEWnKyBSTw7quoA== - -gl-matrix@^3.2.1: - version "3.4.3" - resolved "https://registry.yarnpkg.com/gl-matrix/-/gl-matrix-3.4.3.tgz#fc1191e8320009fd4d20e9339595c6041ddc22c9" - integrity sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA== - -gl-text@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/gl-text/-/gl-text-1.3.1.tgz#f36594464101b5b053178d6d219c3d08fb9144c8" - integrity sha512-/f5gcEMiZd+UTBJLTl3D+CkCB/0UFGTx3nflH8ZmyWcLkZhsZ1+Xx5YYkw2rgWAzgPeE35xCqBuHSoMKQVsR+w== - dependencies: - bit-twiddle "^1.0.2" - color-normalize "^1.5.0" - css-font "^1.2.0" - detect-kerning "^2.1.2" - es6-weak-map "^2.0.3" - flatten-vertex-data "^1.0.2" - font-atlas "^2.1.0" - font-measure "^1.2.2" - gl-util "^3.1.2" - is-plain-obj "^1.1.0" - object-assign "^4.1.1" - parse-rect "^1.2.0" - parse-unit "^1.0.1" - pick-by-alias "^1.2.0" - regl "^2.0.0" - to-px "^1.0.1" - typedarray-pool "^1.1.0" - -gl-util@^3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/gl-util/-/gl-util-3.1.3.tgz#1e9a724f844b802597c6e30565d4c1e928546861" - integrity sha512-dvRTggw5MSkJnCbh74jZzSoTOGnVYK+Bt+Ckqm39CVcl6+zSsxqWk4lr5NKhkqXHL6qvZAU9h17ZF8mIskY9mA== - dependencies: - is-browser "^2.0.1" - is-firefox "^1.0.3" - is-plain-obj "^1.1.0" - number-is-integer "^1.0.1" - object-assign "^4.1.0" - pick-by-alias "^1.2.0" - weak-map "^1.0.5" - glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -6986,133 +6345,6 @@ globby@^11.0.4, globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -glsl-inject-defines@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/glsl-inject-defines/-/glsl-inject-defines-1.0.3.tgz#dd1aacc2c17fcb2bd3fc32411c6633d0d7b60fd4" - integrity sha512-W49jIhuDtF6w+7wCMcClk27a2hq8znvHtlGnrYkSWEr8tHe9eA2dcnohlcAmxLYBSpSSdzOkRdyPTrx9fw49+A== - dependencies: - glsl-token-inject-block "^1.0.0" - glsl-token-string "^1.0.1" - glsl-tokenizer "^2.0.2" - -glsl-resolve@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/glsl-resolve/-/glsl-resolve-0.0.1.tgz#894bef73910d792c81b5143180035d0a78af76d3" - integrity sha512-xxFNsfnhZTK9NBhzJjSBGX6IOqYpvBHxxmo+4vapiljyGNCY0Bekzn0firQkQrazK59c1hYxMDxYS8MDlhw4gA== - dependencies: - resolve "^0.6.1" - xtend "^2.1.2" - -glsl-token-assignments@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/glsl-token-assignments/-/glsl-token-assignments-2.0.2.tgz#a5d82ab78499c2e8a6b83cb69495e6e665ce019f" - integrity sha512-OwXrxixCyHzzA0U2g4btSNAyB2Dx8XrztY5aVUCjRSh4/D0WoJn8Qdps7Xub3sz6zE73W3szLrmWtQ7QMpeHEQ== - -glsl-token-defines@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/glsl-token-defines/-/glsl-token-defines-1.0.0.tgz#cb892aa959936231728470d4f74032489697fa9d" - integrity sha512-Vb5QMVeLjmOwvvOJuPNg3vnRlffscq2/qvIuTpMzuO/7s5kT+63iL6Dfo2FYLWbzuiycWpbC0/KV0biqFwHxaQ== - dependencies: - glsl-tokenizer "^2.0.0" - -glsl-token-depth@^1.1.0, glsl-token-depth@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/glsl-token-depth/-/glsl-token-depth-1.1.2.tgz#23c5e30ee2bd255884b4a28bc850b8f791e95d84" - integrity sha512-eQnIBLc7vFf8axF9aoi/xW37LSWd2hCQr/3sZui8aBJnksq9C7zMeUYHVJWMhFzXrBU7fgIqni4EhXVW4/krpg== - -glsl-token-descope@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/glsl-token-descope/-/glsl-token-descope-1.0.2.tgz#0fc90ab326186b82f597b2e77dc9e21efcd32076" - integrity sha512-kS2PTWkvi/YOeicVjXGgX5j7+8N7e56srNDEHDTVZ1dcESmbmpmgrnpjPcjxJjMxh56mSXYoFdZqb90gXkGjQw== - dependencies: - glsl-token-assignments "^2.0.0" - glsl-token-depth "^1.1.0" - glsl-token-properties "^1.0.0" - glsl-token-scope "^1.1.0" - -glsl-token-inject-block@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/glsl-token-inject-block/-/glsl-token-inject-block-1.1.0.tgz#e1015f5980c1091824adaa2625f1dfde8bd00034" - integrity sha512-q/m+ukdUBuHCOtLhSr0uFb/qYQr4/oKrPSdIK2C4TD+qLaJvqM9wfXIF/OOBjuSA3pUoYHurVRNao6LTVVUPWA== - -glsl-token-properties@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/glsl-token-properties/-/glsl-token-properties-1.0.1.tgz#483dc3d839f0d4b5c6171d1591f249be53c28a9e" - integrity sha512-dSeW1cOIzbuUoYH0y+nxzwK9S9O3wsjttkq5ij9ZGw0OS41BirKJzzH48VLm8qLg+au6b0sINxGC0IrGwtQUcA== - -glsl-token-scope@^1.1.0, glsl-token-scope@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/glsl-token-scope/-/glsl-token-scope-1.1.2.tgz#a1728e78df24444f9cb93fd18ef0f75503a643b1" - integrity sha512-YKyOMk1B/tz9BwYUdfDoHvMIYTGtVv2vbDSLh94PT4+f87z21FVdou1KNKgF+nECBTo0fJ20dpm0B1vZB1Q03A== - -glsl-token-string@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/glsl-token-string/-/glsl-token-string-1.0.1.tgz#59441d2f857de7c3449c945666021ece358e48ec" - integrity sha512-1mtQ47Uxd47wrovl+T6RshKGkRRCYWhnELmkEcUAPALWGTFe2XZpH3r45XAwL2B6v+l0KNsCnoaZCSnhzKEksg== - -glsl-token-whitespace-trim@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/glsl-token-whitespace-trim/-/glsl-token-whitespace-trim-1.0.0.tgz#46d1dfe98c75bd7d504c05d7d11b1b3e9cc93b10" - integrity sha512-ZJtsPut/aDaUdLUNtmBYhaCmhIjpKNg7IgZSfX5wFReMc2vnj8zok+gB/3Quqs0TsBSX/fGnqUUYZDqyuc2xLQ== - -glsl-tokenizer@^2.0.0, glsl-tokenizer@^2.0.2: - version "2.1.5" - resolved "https://registry.yarnpkg.com/glsl-tokenizer/-/glsl-tokenizer-2.1.5.tgz#1c2e78c16589933c274ba278d0a63b370c5fee1a" - integrity sha512-XSZEJ/i4dmz3Pmbnpsy3cKh7cotvFlBiZnDOwnj/05EwNp2XrhQ4XKJxT7/pDt4kp4YcpRSKz8eTV7S+mwV6MA== - dependencies: - through2 "^0.6.3" - -glslify-bundle@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/glslify-bundle/-/glslify-bundle-5.1.1.tgz#30d2ddf2e6b935bf44d1299321e3b729782c409a" - integrity sha512-plaAOQPv62M1r3OsWf2UbjN0hUYAB7Aph5bfH58VxJZJhloRNbxOL9tl/7H71K7OLJoSJ2ZqWOKk3ttQ6wy24A== - dependencies: - glsl-inject-defines "^1.0.1" - glsl-token-defines "^1.0.0" - glsl-token-depth "^1.1.1" - glsl-token-descope "^1.0.2" - glsl-token-scope "^1.1.1" - glsl-token-string "^1.0.1" - glsl-token-whitespace-trim "^1.0.0" - glsl-tokenizer "^2.0.2" - murmurhash-js "^1.0.0" - shallow-copy "0.0.1" - -glslify-deps@^1.2.5: - version "1.3.2" - resolved "https://registry.yarnpkg.com/glslify-deps/-/glslify-deps-1.3.2.tgz#c09ee945352bfc07ac2d8a1cc9e3de776328c72b" - integrity sha512-7S7IkHWygJRjcawveXQjRXLO2FTjijPDYC7QfZyAQanY+yGLCFHYnPtsGT9bdyHiwPTw/5a1m1M9hamT2aBpag== - dependencies: - "@choojs/findup" "^0.2.0" - events "^3.2.0" - glsl-resolve "0.0.1" - glsl-tokenizer "^2.0.0" - graceful-fs "^4.1.2" - inherits "^2.0.1" - map-limit "0.0.1" - resolve "^1.0.0" - -glslify@^7.0.0, glslify@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/glslify/-/glslify-7.1.1.tgz#454d9172b410cb49864029c86d5613947fefd30b" - integrity sha512-bud98CJ6kGZcP9Yxcsi7Iz647wuDz3oN+IZsjCRi5X1PI7t/xPKeL0mOwXJjo+CRZMqvq0CkSJiywCcY7kVYog== - dependencies: - bl "^2.2.1" - concat-stream "^1.5.2" - duplexify "^3.4.5" - falafel "^2.1.0" - from2 "^2.3.0" - glsl-resolve "0.0.1" - glsl-token-whitespace-trim "^1.0.0" - glslify-bundle "^5.0.0" - glslify-deps "^1.2.5" - minimist "^1.2.5" - resolve "^1.1.5" - stack-trace "0.0.9" - static-eval "^2.0.5" - through2 "^2.0.1" - xtend "^4.0.0" - gopd@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" @@ -7130,11 +6362,6 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -grid-index@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/grid-index/-/grid-index-1.1.0.tgz#97f8221edec1026c8377b86446a7c71e79522ea7" - integrity sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA== - gzip-size@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" @@ -7167,20 +6394,6 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-hover@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-hover/-/has-hover-1.0.1.tgz#3d97437aeb199c62b8ac08acbdc53d3bc52c17f7" - integrity sha512-0G6w7LnlcpyDzpeGUTuT0CEw05+QlMuGVk1IHNAlHrGJITGodjZu3x8BNDUMfKJSZXNB2ZAclqc1bvrd+uUpfg== - dependencies: - is-browser "^2.0.1" - -has-passive-events@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-passive-events/-/has-passive-events-1.0.0.tgz#75fc3dc6dada182c58f24ebbdc018276d1ea3515" - integrity sha512-2vSj6IeIsgvsRMyeQ0JaCX5Q3lX4zMn5HpoVc7MEhQ6pv8Iq9rsXjsp+E5ZwaT7T0xhMT0KmU8gtt1EFVdbJiw== - dependencies: - is-browser "^2.0.1" - has-property-descriptors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" @@ -7245,11 +6458,6 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" -hsluv@^0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/hsluv/-/hsluv-0.0.3.tgz#829107dafb4a9f8b52a1809ed02e091eade6754c" - integrity sha512-08iL2VyCRbkQKBySkSh6m8zMUa3sADAxGVWs3Z1aPcUkTJeK0ETG4Fc27tEmQBGUAXZjIsXOZqBvacuVNSC/fQ== - html-encoding-sniffer@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" @@ -7388,7 +6596,7 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -iconv-lite@0.4.24, iconv-lite@^0.4.4: +iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -7468,7 +6676,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -7563,11 +6771,6 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-browser@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-browser/-/is-browser-2.1.0.tgz#fc084d59a5fced307d6708c59356bad7007371a9" - integrity sha512-F5rTJxDQ2sW81fcfOR1GnCXT6sVJC104fCyfj+mjpwNEwaPYSn5fte5jiHmBg3DHsIoL/l8Kvw5VN5SsTRcRFQ== - is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" @@ -7611,16 +6814,6 @@ is-finalizationregistry@^1.0.2: dependencies: call-bind "^1.0.2" -is-finite@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" - integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== - -is-firefox@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-firefox/-/is-firefox-1.0.3.tgz#2a2a1567783a417f6e158323108f3861b0918562" - integrity sha512-6Q9ITjvWIm0Xdqv+5U12wgOKEM2KoBw4Y926m0OFkvlCxnbG94HKAsVz8w3fWcfAS5YA2fJORXX1dLrkprCCxA== - is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -7645,11 +6838,6 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" -is-iexplorer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-iexplorer/-/is-iexplorer-1.0.0.tgz#1d72bc66d3fe22eaf6170dda8cf10943248cfc76" - integrity sha512-YeLzceuwg3K6O0MLM3UyUUjKAlyULetwryFp1mHy1I5PfArK0AEqlfa+MR4gkJjcbuJXoDJCvXbyqZVf5CR2Sg== - is-installed-globally@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" @@ -7663,11 +6851,6 @@ is-map@^2.0.1, is-map@^2.0.2: resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== -is-mobile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-mobile/-/is-mobile-4.0.0.tgz#bba396eb9656e2739afde3053d7191da310fc758" - integrity sha512-mlcHZA84t1qLSuWkt2v0I2l61PYdyQDt4aG1mLIXF5FDMm4+haBCxCPYSr/uwqQNRk1MiTizn0ypEuRAOLRAew== - is-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" @@ -7700,11 +6883,6 @@ is-path-inside@^3.0.2, is-path-inside@^3.0.3: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== -is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== - is-plain-obj@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" @@ -7757,11 +6935,6 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -is-string-blank@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-string-blank/-/is-string-blank-1.0.1.tgz#866dca066d41d2894ebdfd2d8fe93e586e583a03" - integrity sha512-9H+ZBCVs3L9OYqv8nuUAzpcT9OTgMD1yAWrG7ihlnibdkbtB850heAmYWxHuXc4CHy4lKeK69tN+ny1K7gBIrw== - is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" @@ -7769,11 +6942,6 @@ is-string@^1.0.5, is-string@^1.0.7: dependencies: has-tostringtag "^1.0.0" -is-svg-path@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-svg-path/-/is-svg-path-1.0.2.tgz#77ab590c12b3d20348e5c7a13d0040c87784dda0" - integrity sha512-Lj4vePmqpPR1ZnRctHv8ltSh1OrSxHkhUkd7wi+VQdcdP15/KvQFyk7LhNuM7ZW0EVbJz8kZLVmL9quLrfq4Kg== - is-symbol@^1.0.2, is-symbol@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" @@ -7835,7 +7003,7 @@ isarray@0.0.1: resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== -isarray@^2.0.1, isarray@^2.0.5: +isarray@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== @@ -8680,11 +7848,6 @@ jwt-decode@^3.1.2: resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59" integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A== -kdbush@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/kdbush/-/kdbush-3.0.0.tgz#f8484794d47004cc2d85ed3a79353dbe0abc2bf0" - integrity sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew== - keycloak-js@^22.0.0: version "22.0.4" resolved "https://registry.yarnpkg.com/keycloak-js/-/keycloak-js-22.0.4.tgz#0ab2651288e0464728f44fa5259b0178d56ed68c" @@ -8970,47 +8133,11 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" -map-limit@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/map-limit/-/map-limit-0.0.1.tgz#eb7961031c0f0e8d001bf2d56fab685d58822f38" - integrity sha512-pJpcfLPnIF/Sk3taPW21G/RQsEEirGaFpCW3oXRwH9dnFHPHNGjNyvh++rdmC2fNqEaTw2MhYJraoJWAHx8kEg== - dependencies: - once "~1.3.0" - map-stream@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" integrity sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g== -mapbox-gl@1.10.1: - version "1.10.1" - resolved "https://registry.yarnpkg.com/mapbox-gl/-/mapbox-gl-1.10.1.tgz#7dbd53bdf2f78e45e125c1115e94dea286ef663c" - integrity sha512-0aHt+lFUpYfvh0kMIqXqNXqoYMuhuAsMlw87TbhWrw78Tx2zfuPI0Lx31/YPUgJ+Ire0tzQ4JnuBL7acDNXmMg== - dependencies: - "@mapbox/geojson-rewind" "^0.5.0" - "@mapbox/geojson-types" "^1.0.2" - "@mapbox/jsonlint-lines-primitives" "^2.0.2" - "@mapbox/mapbox-gl-supported" "^1.5.0" - "@mapbox/point-geometry" "^0.1.0" - "@mapbox/tiny-sdf" "^1.1.1" - "@mapbox/unitbezier" "^0.0.0" - "@mapbox/vector-tile" "^1.3.1" - "@mapbox/whoots-js" "^3.1.0" - csscolorparser "~1.0.3" - earcut "^2.2.2" - geojson-vt "^3.2.1" - gl-matrix "^3.2.1" - grid-index "^1.1.0" - minimist "^1.2.5" - murmurhash-js "^1.0.0" - pbf "^3.2.1" - potpack "^1.0.1" - quickselect "^2.0.0" - rw "^1.3.3" - supercluster "^7.0.0" - tinyqueue "^2.0.3" - vt-pbf "^3.1.1" - match-sorter@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.1.tgz#98cc37fda756093424ddf3cbc62bfe9c75b92bda" @@ -9019,11 +8146,6 @@ match-sorter@^6.3.1: "@babel/runtime" "^7.12.5" remove-accents "0.4.2" -math-log2@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/math-log2/-/math-log2-1.0.1.tgz#fb8941be5f5ebe8979e718e6273b178e58694565" - integrity sha512-9W0yGtkaMAkf74XGYVy4Dqw3YUMnTNB2eeiw9aQbUl4A3KmuCEHTt2DgAB07ENzOYAjsYSAYufkAq0Zd+jU7zA== - mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" @@ -9127,7 +8249,7 @@ minimatch@^5.0.1: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.7, minimist@^1.2.8: +minimist@^1.2.0, minimist@^1.2.6, minimist@^1.2.7, minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -9139,32 +8261,6 @@ mkdirp@~0.5.1: dependencies: minimist "^1.2.6" -mouse-change@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/mouse-change/-/mouse-change-1.4.0.tgz#c2b77e5bfa34a43ce1445c8157a4e4dc9895c14f" - integrity sha512-vpN0s+zLL2ykyyUDh+fayu9Xkor5v/zRD9jhSqjRS1cJTGS0+oakVZzNm5n19JvvEj0you+MXlYTpNxUDQUjkQ== - dependencies: - mouse-event "^1.0.0" - -mouse-event-offset@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/mouse-event-offset/-/mouse-event-offset-3.0.2.tgz#dfd86a6e248c6ba8cad53b905d5037a2063e9984" - integrity sha512-s9sqOs5B1Ykox3Xo8b3Ss2IQju4UwlW6LSR+Q5FXWpprJ5fzMLefIIItr3PH8RwzfGy6gxs/4GAmiNuZScE25w== - -mouse-event@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/mouse-event/-/mouse-event-1.0.5.tgz#b3789edb7109997d5a932d1d01daa1543a501732" - integrity sha512-ItUxtL2IkeSKSp9cyaX2JLUuKk2uMoxBg4bbOWVd29+CskYJR9BGsUqtXenNzKbnDshvupjUewDIYVrOB6NmGw== - -mouse-wheel@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mouse-wheel/-/mouse-wheel-1.2.0.tgz#6d2903b1ea8fb48e61f1b53b9036773f042cdb5c" - integrity sha512-+OfYBiUOCTWcTECES49neZwL5AoGkXE+lFjIvzwNCnYRlso+EnfvovcBxGoyQ0yQt806eSPjS675K0EwWknXmw== - dependencies: - right-now "^1.0.0" - signum "^1.0.0" - to-px "^1.0.1" - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -9188,18 +8284,6 @@ multicast-dns@^7.2.5: dns-packet "^5.2.2" thunky "^1.0.2" -mumath@^3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/mumath/-/mumath-3.3.4.tgz#48d4a0f0fd8cad4e7b32096ee89b161a63d30bbf" - integrity sha512-VAFIOG6rsxoc7q/IaY3jdjmrsuX9f15KlRLYTHmixASBZkZEKC1IFqE2BC5CdhXmK6WLM1Re33z//AGmeRI6FA== - dependencies: - almost-equal "^1.1.0" - -murmurhash-js@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/murmurhash-js/-/murmurhash-js-1.0.0.tgz#b06278e21fc6c37fa5313732b0412bcb6ae15f51" - integrity sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw== - mz@^2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" @@ -9214,11 +8298,6 @@ nanoid@^3.3.6: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== -native-promise-only@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/native-promise-only/-/native-promise-only-0.8.1.tgz#20a318c30cb45f71fe7adfbf7b21c99c1472ef11" - integrity sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg== - natural-compare-lite@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" @@ -9229,15 +8308,6 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -needle@^2.5.2: - version "2.9.1" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.9.1.tgz#22d1dffbe3490c2b83e301f7709b6736cd8f2684" - integrity sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ== - dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - negotiator@0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" @@ -9248,11 +8318,6 @@ neo-async@^2.6.2: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -next-tick@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" - integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== - nise@^4.0.4: version "4.1.0" resolved "https://registry.yarnpkg.com/nise/-/nise-4.1.0.tgz#8fb75a26e90b99202fa1e63f448f58efbcdedaf6" @@ -9304,18 +8369,6 @@ normalize-range@^0.1.2: resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== -normalize-svg-path@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/normalize-svg-path/-/normalize-svg-path-1.1.0.tgz#0e614eca23c39f0cffe821d6be6cd17e569a766c" - integrity sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg== - dependencies: - svg-arc-to-cubic-bezier "^3.0.0" - -normalize-svg-path@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/normalize-svg-path/-/normalize-svg-path-0.1.0.tgz#456360e60ece75fbef7b5d7e160480e7ffd16fe5" - integrity sha512-1/kmYej2iedi5+ROxkRESL/pI02pkg0OBnaR4hJkSIX6+ORzepwbuUXfrdZaPjysTsJInj0Rj5NuX027+dMBvA== - normalize-url@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" @@ -9342,13 +8395,6 @@ nth-check@^2.0.1: dependencies: boolbase "^1.0.0" -number-is-integer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-integer/-/number-is-integer-1.0.1.tgz#e59bca172ffed27318e79c7ceb6cb72c095b2152" - integrity sha512-Dq3iuiFBkrbmuQjGFFF3zckXNCQoSD37/SdSbgcBailUx6knDvDwb5CympBgcoWHy36sfS12u74MHYkXyHq6bg== - dependencies: - is-finite "^1.0.1" - nwsapi@^2.2.0: version "2.2.7" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" @@ -9387,7 +8433,7 @@ nyc@15.1.0: test-exclude "^6.0.0" yargs "^15.0.2" -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4.0.1, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== @@ -9522,13 +8568,6 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -once@~1.3.0: - version "1.3.3" - resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" - integrity sha512-6vaNInhu+CHxtONf3zw3vq4SP2DOQhjBvIa3rNcG0+P7eKWlYH6Peu7rHizSloRU2EwMz6GraLieis9Ac9+p1w== - dependencies: - wrappy "1" - onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" @@ -9666,11 +8705,6 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parenthesis@^3.1.5: - version "3.1.8" - resolved "https://registry.yarnpkg.com/parenthesis/-/parenthesis-3.1.8.tgz#3457fccb8f05db27572b841dad9d2630b912f125" - integrity sha512-KF/U8tk54BgQewkJPvB4s/US3VQY68BRDpH638+7O/n58TpnwiwnOtGIOsT2/i+M78s61BBpeC83STB88d8sqw== - parse-headers@^2.0.2: version "2.0.5" resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.5.tgz#069793f9356a54008571eb7f9761153e6c770da9" @@ -9686,23 +8720,6 @@ parse-json@^5.0.0, parse-json@^5.2.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -parse-rect@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/parse-rect/-/parse-rect-1.2.0.tgz#e0a5b0dbaaaee637a0a1eb9779969e19399d8dec" - integrity sha512-4QZ6KYbnE6RTwg9E0HpLchUM9EZt6DnDxajFZZDSV4p/12ZJEvPO702DZpGvRYEPo00yKDys7jASi+/w7aO8LA== - dependencies: - pick-by-alias "^1.2.0" - -parse-svg-path@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/parse-svg-path/-/parse-svg-path-0.1.2.tgz#7a7ec0d1eb06fa5325c7d3e009b859a09b5d49eb" - integrity sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ== - -parse-unit@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parse-unit/-/parse-unit-1.0.1.tgz#7e1bb6d5bef3874c28e392526a2541170291eecf" - integrity sha512-hrqldJHokR3Qj88EIlV/kAyAi/G5R2+R56TBANxNMy0uPlYcttx0jnMW6Yx5KsKPSbC3KddM/7qQm3+0wEXKxg== - parse5@6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" @@ -9770,7 +8787,7 @@ pause-stream@0.0.11: dependencies: through "~2.3" -pbf@3.2.1, pbf@^3.2.1: +pbf@3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/pbf/-/pbf-3.2.1.tgz#b4c1b9e72af966cd82c6531691115cc0409ffe2a" integrity sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ== @@ -9788,11 +8805,6 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== -pick-by-alias@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pick-by-alias/-/pick-by-alias-1.2.0.tgz#5f7cb2b1f21a6e1e884a0c87855aa4a37361107b" - integrity sha512-ESj2+eBxhGrcA1azgHs7lARG5+5iLakc/6nlfbpjcLl00HuuUOIuORhYXN4D1HfvMSKuVtFQjAlnwi1JHEeDIw== - picocolors@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" @@ -9832,61 +8844,6 @@ pkg-up@^3.1.0: dependencies: find-up "^3.0.0" -plotly.js@^2.5.1: - version "2.26.2" - resolved "https://registry.yarnpkg.com/plotly.js/-/plotly.js-2.26.2.tgz#b61f0e7c4b6beb2a86dde3f9b89478ac06731417" - integrity sha512-HJv4n1I1SFTmY1+kzkLzrRyqqWVJ6r0JekvPKP0XtxITr8jugMJNJBFiErlKiPvSz8hcDEMwys5QIdFsK57KYw== - dependencies: - "@plotly/d3" "3.8.1" - "@plotly/d3-sankey" "0.7.2" - "@plotly/d3-sankey-circular" "0.33.1" - "@turf/area" "^6.4.0" - "@turf/bbox" "^6.4.0" - "@turf/centroid" "^6.0.2" - canvas-fit "^1.5.0" - color-alpha "1.0.4" - color-normalize "1.5.0" - color-parse "1.3.8" - color-rgba "2.1.1" - country-regex "^1.1.0" - d3-force "^1.2.1" - d3-format "^1.4.5" - d3-geo "^1.12.1" - d3-geo-projection "^2.9.0" - d3-hierarchy "^1.1.9" - d3-interpolate "^3.0.1" - d3-time "^1.1.0" - d3-time-format "^2.2.3" - fast-isnumeric "^1.1.4" - gl-mat4 "^1.2.0" - gl-text "^1.3.1" - glslify "^7.1.1" - has-hover "^1.0.1" - has-passive-events "^1.0.0" - is-mobile "^4.0.0" - mapbox-gl "1.10.1" - mouse-change "^1.4.0" - mouse-event-offset "^3.0.2" - mouse-wheel "^1.2.0" - native-promise-only "^0.8.1" - parse-svg-path "^0.1.2" - point-in-polygon "^1.1.0" - polybooljs "^1.2.0" - probe-image-size "^7.2.3" - regl "npm:@plotly/regl@^2.1.2" - regl-error2d "^2.0.12" - regl-line2d "^3.1.2" - regl-scatter2d "^3.2.9" - regl-splom "^1.0.14" - strongly-connected-components "^1.0.1" - superscript-text "^1.0.0" - svg-path-sdf "^1.1.3" - tinycolor2 "^1.4.2" - to-px "1.0.1" - topojson-client "^3.1.0" - webgl-context "^2.2.0" - world-calendars "^1.0.3" - pmtiles@2.11.0: version "2.11.0" resolved "https://registry.yarnpkg.com/pmtiles/-/pmtiles-2.11.0.tgz#53aac29408e001a73b15b1c8cad0b17c944ab7bd" @@ -9894,16 +8851,6 @@ pmtiles@2.11.0: dependencies: fflate "^0.8.0" -point-in-polygon@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/point-in-polygon/-/point-in-polygon-1.1.0.tgz#b0af2616c01bdee341cbf2894df643387ca03357" - integrity sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw== - -polybooljs@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/polybooljs/-/polybooljs-1.2.0.tgz#b4390c2e079d4c262d3b2504c6288d95ba7a4758" - integrity sha512-mKjR5nolISvF+q2BtC1fi/llpxBPTQ3wLWN8+ldzdw2Hocpc8C72ZqnamCM4Z6z+68GVVjkeM01WJegQmZ8MEQ== - postcss-attribute-case-insensitive@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz#03d761b24afc04c09e757e92ff53716ae8ea2741" @@ -10461,11 +9408,6 @@ postcss@^8.3.5, postcss@^8.4.21, postcss@^8.4.23, postcss@^8.4.4: picocolors "^1.0.0" source-map-js "^1.0.2" -potpack@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/potpack/-/potpack-1.0.2.tgz#23b99e64eb74f5741ffe7656b5b5c4ddce8dfc14" - integrity sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ== - prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -10529,15 +9471,6 @@ pretty-format@^29.0.0, pretty-format@^29.7.0: ansi-styles "^5.0.0" react-is "^18.0.0" -probe-image-size@^7.2.3: - version "7.2.3" - resolved "https://registry.yarnpkg.com/probe-image-size/-/probe-image-size-7.2.3.tgz#d49c64be540ec8edea538f6f585f65a9b3ab4309" - integrity sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w== - dependencies: - lodash.merge "^4.6.2" - needle "^2.5.2" - stream-parser "~0.3.1" - process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -10778,13 +9711,6 @@ react-lifecycles-compat@^3.0.4: resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== -react-plotly.js@^2.5.1: - version "2.6.0" - resolved "https://registry.yarnpkg.com/react-plotly.js/-/react-plotly.js-2.6.0.tgz#ad6b68ee64f1b5cfa142ee92c59687f9c2c09209" - integrity sha512-g93xcyhAVCSt9kV1svqG1clAEdL6k3U+jjuSzfTV7owaSU9Go6Ph8bl25J+jKfKvIGAEYpe4qj++WHJuc9IaeA== - dependencies: - prop-types "^15.8.1" - react-redux@^8.0.0: version "8.1.3" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.3.tgz#4fdc0462d0acb59af29a13c27ffef6f49ab4df46" @@ -10922,17 +9848,7 @@ read-cache@^1.0.0: dependencies: pify "^2.3.0" -"readable-stream@>=1.0.33-1 <1.1.0-0": - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.2.2, readable-stream@^2.3.5, readable-stream@~2.3.6: +readable-stream@^2.0.1: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -11092,82 +10008,6 @@ regjsparser@^0.9.1: dependencies: jsesc "~0.5.0" -regl-error2d@^2.0.12: - version "2.0.12" - resolved "https://registry.yarnpkg.com/regl-error2d/-/regl-error2d-2.0.12.tgz#3b976e13fe641d5242a154fcacc80aecfa0a9881" - integrity sha512-r7BUprZoPO9AbyqM5qlJesrSRkl+hZnVKWKsVp7YhOl/3RIpi4UDGASGJY0puQ96u5fBYw/OlqV24IGcgJ0McA== - dependencies: - array-bounds "^1.0.1" - color-normalize "^1.5.0" - flatten-vertex-data "^1.0.2" - object-assign "^4.1.1" - pick-by-alias "^1.2.0" - to-float32 "^1.1.0" - update-diff "^1.1.0" - -regl-line2d@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/regl-line2d/-/regl-line2d-3.1.2.tgz#2bedef7f44c1f7fae75c90f9918258723ca84c1c" - integrity sha512-nmT7WWS/WxmXAQMkgaMKWXaVmwJ65KCrjbqHGOUjjqQi6shfT96YbBOvelXwO9hG7/hjvbzjtQ2UO0L3e7YaXQ== - dependencies: - array-bounds "^1.0.1" - array-find-index "^1.0.2" - array-normalize "^1.1.4" - color-normalize "^1.5.0" - earcut "^2.1.5" - es6-weak-map "^2.0.3" - flatten-vertex-data "^1.0.2" - glslify "^7.0.0" - object-assign "^4.1.1" - parse-rect "^1.2.0" - pick-by-alias "^1.2.0" - to-float32 "^1.1.0" - -regl-scatter2d@^3.2.3, regl-scatter2d@^3.2.9: - version "3.2.9" - resolved "https://registry.yarnpkg.com/regl-scatter2d/-/regl-scatter2d-3.2.9.tgz#cd27b014c355e80d96fb2f273b563fd8f1b094f0" - integrity sha512-PNrXs+xaCClKpiB2b3HZ2j3qXQXhC5kcTh/Nfgx9rLO0EpEhab0BSQDqAsbdbpdf+pSHSJvbgitB7ulbGeQ+Fg== - dependencies: - "@plotly/point-cluster" "^3.1.9" - array-range "^1.0.1" - array-rearrange "^2.2.2" - clamp "^1.0.1" - color-id "^1.1.0" - color-normalize "^1.5.0" - color-rgba "^2.1.1" - flatten-vertex-data "^1.0.2" - glslify "^7.0.0" - is-iexplorer "^1.0.0" - object-assign "^4.1.1" - parse-rect "^1.2.0" - pick-by-alias "^1.2.0" - to-float32 "^1.1.0" - update-diff "^1.1.0" - -regl-splom@^1.0.14: - version "1.0.14" - resolved "https://registry.yarnpkg.com/regl-splom/-/regl-splom-1.0.14.tgz#58800b7bbd7576aa323499a1966868a6c9ea1456" - integrity sha512-OiLqjmPRYbd7kDlHC6/zDf6L8lxgDC65BhC8JirhP4ykrK4x22ZyS+BnY8EUinXKDeMgmpRwCvUmk7BK4Nweuw== - dependencies: - array-bounds "^1.0.1" - array-range "^1.0.1" - color-alpha "^1.0.4" - flatten-vertex-data "^1.0.2" - parse-rect "^1.2.0" - pick-by-alias "^1.2.0" - raf "^3.4.1" - regl-scatter2d "^3.2.3" - -regl@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/regl/-/regl-2.1.0.tgz#7dae71e9ff20f29c4f42f510c70cd92ebb6b657c" - integrity sha512-oWUce/aVoEvW5l2V0LK7O5KJMzUSKeiOwFuJehzpSFd43dO5spP9r+sSUfhKtsky4u6MCqWJaRL+abzExynfTg== - -"regl@npm:@plotly/regl@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@plotly/regl/-/regl-2.1.2.tgz#fd31e3e820ed8824d59a67ab5e766bb101b810b6" - integrity sha512-Mdk+vUACbQvjd0m/1JJjOOafmkp/EpmHjISsopEz5Av44CBq7rPC05HHNbYGKVyNUF2zmEoBS/TT0pd0SPFFyw== - relateurl@^0.2.7: version "0.2.7" resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" @@ -11268,12 +10108,7 @@ resolve.exports@^1.1.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.1.tgz#05cfd5b3edf641571fd46fa608b610dda9ead999" integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ== -resolve@^0.6.1: - version "0.6.3" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-0.6.3.tgz#dd957982e7e736debdf53b58a4dd91754575dd46" - integrity sha512-UHBY3viPlJKf85YijDUcikKX6tmF4SokIDp518ZDVT92JNDcG5uKIthaT/owt3Sar0lwtOafsQuwrg22/v2Dwg== - -resolve@^1.0.0, resolve@^1.1.10, resolve@^1.1.5, resolve@^1.1.7, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.2, resolve@^1.22.4: +resolve@^1.1.7, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.2, resolve@^1.22.4: version "1.22.6" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.6.tgz#dd209739eca3aef739c626fea1b4f3c506195362" integrity sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw== @@ -11314,11 +10149,6 @@ rfdc@^1.3.0: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== -right-now@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/right-now/-/right-now-1.0.0.tgz#6e89609deebd7dcdaf8daecc9aea39cf585a0918" - integrity sha512-DA8+YS+sMIVpbsuKgy+Z67L9Lxb1p05mNxRpDPNksPDEFir4vmBlUtuN9jkTGn9YMMdlBuK7XQgFiz6ws+yhSg== - rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -11350,11 +10180,6 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rw@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" - integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ== - rxjs@^7.5.1, rxjs@^7.8.0: version "7.8.1" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" @@ -11377,7 +10202,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -11409,11 +10234,6 @@ sass-loader@^12.3.0: klona "^2.0.4" neo-async "^2.6.2" -sax@^1.2.4: - version "1.3.0" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0" - integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA== - sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -11582,11 +10402,6 @@ shallow-clone@^3.0.0: dependencies: kind-of "^6.0.2" -shallow-copy@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/shallow-copy/-/shallow-copy-0.0.1.tgz#415f42702d73d810330292cc5ee86eae1a11a170" - integrity sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw== - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -11618,11 +10433,6 @@ signal-exit@^3.0.2, signal-exit@^3.0.3: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -signum@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/signum/-/signum-1.0.0.tgz#74a7d2bf2a20b40eba16a92b152124f1d559fa77" - integrity sha512-yodFGwcyt59XRh7w5W3jPcIQb3Bwi21suEfT7MAWnBX3iCdklJpgDgvGT9o04UonglZN5SNMfJFkHIR/jO8GHw== - sinon@^9.0.3: version "9.2.4" resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.2.4.tgz#e55af4d3b174a4443a8762fa8421c2976683752b" @@ -11798,11 +10608,6 @@ stable@^0.1.8: resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== -stack-trace@0.0.9: - version "0.0.9" - resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695" - integrity sha512-vjUc6sfgtgY0dxCdnc40mK6Oftjo9+2K8H/NG81TMhgL392FtiPA9tn9RLyTxXmTLPJPjF3VyzFp6bsWFLisMQ== - stack-utils@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" @@ -11836,13 +10641,6 @@ static-eval@2.0.2: dependencies: escodegen "^1.8.1" -static-eval@^2.0.5: - version "2.1.0" - resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.1.0.tgz#a16dbe54522d7fa5ef1389129d813fd47b148014" - integrity sha512-agtxZ/kWSsCkI5E4QifRwsaPs0P0JmZV6dkLz6ILYfFYQGn+5plctanRN+IC8dJRiFkyXHrwEE3W9Wmx67uDbw== - dependencies: - escodegen "^1.11.1" - statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" @@ -11867,18 +10665,6 @@ stream-combiner@~0.0.4: dependencies: duplexer "~0.1.1" -stream-parser@~0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/stream-parser/-/stream-parser-0.3.1.tgz#1618548694420021a1182ff0af1911c129761773" - integrity sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ== - dependencies: - debug "2" - -stream-shift@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" - integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== - string-length@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" @@ -11900,13 +10686,6 @@ string-natural-compare@^3.0.1: resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== -string-split-by@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/string-split-by/-/string-split-by-1.0.0.tgz#53895fb3397ebc60adab1f1e3a131f5372586812" - integrity sha512-KaJKY+hfpzNyet/emP81PJA9hTVSfxNLS9SFTWxdCnnW1/zOOwiV248+EfoX7IQFcBaOp4G5YE6xTJMF+pLg6A== - dependencies: - parenthesis "^3.1.5" - string-width@^4.1.0, string-width@^4.2.0: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -11965,11 +10744,6 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== - string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -12032,11 +10806,6 @@ strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -strongly-connected-components@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strongly-connected-components/-/strongly-connected-components-1.0.1.tgz#0920e2b4df67c8eaee96c6b6234fe29e873dba99" - integrity sha512-i0TFx4wPcO0FwX+4RkLJi1MxmcTv90jNZgxMu9XRnMXMeFUY1VJlIoXpZunPUvUUqbCT1pg5PEkFqqpcaElNaA== - style-loader@^3.3.1: version "3.3.3" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.3.tgz#bba8daac19930169c0c9c96706749a597ae3acff" @@ -12068,18 +10837,6 @@ sucrase@^3.32.0: pirates "^4.0.1" ts-interface-checker "^0.1.9" -supercluster@^7.0.0: - version "7.1.5" - resolved "https://registry.yarnpkg.com/supercluster/-/supercluster-7.1.5.tgz#65a6ce4a037a972767740614c19051b64b8be5a3" - integrity sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg== - dependencies: - kdbush "^3.0.0" - -superscript-text@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/superscript-text/-/superscript-text-1.0.0.tgz#e7cb2752567360df50beb0610ce8df3d71d8dfd8" - integrity sha512-gwu8l5MtRZ6koO0icVTlmN5pm7Dhh1+Xpe9O4x6ObMAsW+3jPbW14d1DsBq1F4wiI+WOFjXF35pslgec/G8yCQ== - supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -12114,37 +10871,11 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -svg-arc-to-cubic-bezier@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz#390c450035ae1c4a0104d90650304c3bc814abe6" - integrity sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g== - svg-parser@^2.0.2: version "2.0.4" resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== -svg-path-bounds@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/svg-path-bounds/-/svg-path-bounds-1.0.2.tgz#00312f672b08afc432a66ddfbd06db40cec8d0d0" - integrity sha512-H4/uAgLWrppIC0kHsb2/dWUYSmb4GE5UqH06uqWBcg6LBjX2fu0A8+JrO2/FJPZiSsNOKZAhyFFgsLTdYUvSqQ== - dependencies: - abs-svg-path "^0.1.1" - is-svg-path "^1.0.1" - normalize-svg-path "^1.0.0" - parse-svg-path "^0.1.2" - -svg-path-sdf@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/svg-path-sdf/-/svg-path-sdf-1.1.3.tgz#92957a31784c0eaf68945472c8dc6bf9e6d126fc" - integrity sha512-vJJjVq/R5lSr2KLfVXVAStktfcfa1pNFjFOgyJnzZFXlO/fDZ5DmM8FpnSKKzLPfEYTVeXuVBTHF296TpxuJVg== - dependencies: - bitmap-sdf "^1.0.0" - draw-svg-path "^1.0.0" - is-svg-path "^1.0.1" - parse-svg-path "^0.1.2" - svg-path-bounds "^1.0.1" - svgo@^1.2.2: version "1.3.2" resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" @@ -12302,22 +11033,6 @@ throttleit@^1.0.0: resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" integrity sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g== -through2@^0.6.3: - version "0.6.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" - integrity sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg== - dependencies: - readable-stream ">=1.0.33-1 <1.1.0-0" - xtend ">=4.0.0 <4.1.0-0" - -through2@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - through@2, through@^2.3.8, through@~2.3, through@~2.3.1: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -12333,16 +11048,6 @@ tiny-binary-search@^1.0.3: resolved "https://registry.yarnpkg.com/tiny-binary-search/-/tiny-binary-search-1.0.3.tgz#9d52e3d16dd1171eb74486caf704ba08c0c62186" integrity sha512-STSHX/L5nI9WTLv6wrzJbAPbO7OIISX83KFBh2GVbX1Uz/vgZOU/ANn/8iV6t35yMTpoPzzO+3OQid3mifE0CA== -tinycolor2@^1.4.2: - version "1.6.0" - resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e" - integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw== - -tinyqueue@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-2.0.3.tgz#64d8492ebf39e7801d7bd34062e29b45b2035f08" - integrity sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA== - tmp@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" @@ -12360,25 +11065,6 @@ to-fast-properties@^2.0.0: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== -to-float32@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/to-float32/-/to-float32-1.1.0.tgz#39bd3b11eadccd490c08f5f9171da5127b6f3946" - integrity sha512-keDnAusn/vc+R3iEiSDw8TOF7gPiTLdK1ArvWtYbJQiVfmRg6i/CAvbKq3uIS0vWroAC7ZecN3DjQKw3aSklUg== - -to-px@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/to-px/-/to-px-1.0.1.tgz#5bbaed5e5d4f76445bcc903c293a2307dd324646" - integrity sha512-2y3LjBeIZYL19e5gczp14/uRWFDtDUErJPVN3VU9a7SJO+RjGRtYR47aMN2bZgGlxvW4ZcEz2ddUPVHXcMfuXw== - dependencies: - parse-unit "^1.0.1" - -to-px@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/to-px/-/to-px-1.1.0.tgz#b6b269ed5db0cc9aefc15272a4c8bcb2ca1e99ca" - integrity sha512-bfg3GLYrGoEzrGoE05TAL/Uw+H/qrf2ptr9V3W7U0lkjjyYnIfgxmVLUfhQ1hZpIQwin81uxhDjvUkDYsC0xWw== - dependencies: - parse-unit "^1.0.1" - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -12391,13 +11077,6 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== -topojson-client@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/topojson-client/-/topojson-client-3.1.0.tgz#22e8b1ed08a2b922feeb4af6f53b6ef09a467b99" - integrity sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw== - dependencies: - commander "2" - tough-cookie@^4.0.0, tough-cookie@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" @@ -12552,16 +11231,6 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -type@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" - integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== - -type@^2.7.2: - version "2.7.2" - resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0" - integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== - typed-array-buffer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" @@ -12601,14 +11270,6 @@ typed-array-length@^1.0.4: for-each "^0.3.3" is-typed-array "^1.1.9" -typedarray-pool@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/typedarray-pool/-/typedarray-pool-1.2.0.tgz#e7e90720144ba02b9ed660438af6f3aacfe33ac3" - integrity sha512-YTSQbzX43yvtpfRtIDAYygoYtgT+Rpjuxy9iOpczrjpXLgGoyG7aS5USJXV2d3nn8uHTeb9rXDvzS27zUg5KYQ== - dependencies: - bit-twiddle "^1.0.0" - dup "^1.0.0" - typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -12616,11 +11277,6 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== - typescript@^5.0.0: version "5.2.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" @@ -12691,7 +11347,7 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -unquote@^1.1.0, unquote@~1.1.1: +unquote@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" integrity sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg== @@ -12714,11 +11370,6 @@ update-browserslist-db@^1.0.13: escalade "^3.1.1" picocolors "^1.0.0" -update-diff@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/update-diff/-/update-diff-1.1.0.tgz#f510182d81ee819fb82c3a6b22b62bbdeda7808f" - integrity sha512-rCiBPiHxZwT4+sBhEbChzpO5hYHjm91kScWgdHf4Qeafs6Ba7MBl+d9GlGv72bcTZQO0sLmtQS1pHSWoCLtN/A== - uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -12817,15 +11468,6 @@ victory-vendor@^36.6.8: d3-time "^3.0.0" d3-timer "^3.0.1" -vt-pbf@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/vt-pbf/-/vt-pbf-3.1.3.tgz#68fd150756465e2edae1cc5c048e063916dcfaac" - integrity sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA== - dependencies: - "@mapbox/point-geometry" "0.1.0" - "@mapbox/vector-tile" "^1.3.1" - pbf "^3.2.1" - w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" @@ -12873,23 +11515,11 @@ wbuf@^1.1.0, wbuf@^1.7.3: dependencies: minimalistic-assert "^1.0.0" -weak-map@^1.0.5: - version "1.0.8" - resolved "https://registry.yarnpkg.com/weak-map/-/weak-map-1.0.8.tgz#394c18a9e8262e790544ed8b55c6a4ddad1cb1a3" - integrity sha512-lNR9aAefbGPpHO7AEnY0hCFjz1eTkWCXYvkTRrTHs9qv8zJp+SkVYpzfLIFXQQiG3tVvbNFQgVg2bQS8YGgxyw== - web-worker@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/web-worker/-/web-worker-1.2.0.tgz#5d85a04a7fbc1e7db58f66595d7a3ac7c9c180da" integrity sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA== -webgl-context@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/webgl-context/-/webgl-context-2.2.0.tgz#8f37d7257cf6df1cd0a49e6a7b1b721b94cc86a0" - integrity sha512-q/fGIivtqTT7PEoF07axFIlHNk/XCPaYpq64btnepopSWvKNFkoORlQYgqDigBIuGA1ExnFd/GnSUnBNEPQY7Q== - dependencies: - get-canvas-context "^1.0.1" - webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" @@ -13316,13 +11946,6 @@ workbox-window@6.6.1: "@types/trusted-types" "^2.0.2" workbox-core "6.6.1" -world-calendars@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/world-calendars/-/world-calendars-1.0.3.tgz#b25c5032ba24128ffc41d09faf4a5ec1b9c14335" - integrity sha512-sAjLZkBnsbHkHWVhrsCU5Sa/EVuf9QqgvrN8zyJ2L/F9FR9Oc6CvVK0674+PGAtmmmYQMH98tCUSO4QLQv3/TQ== - dependencies: - object-assign "^4.1.0" - wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -13381,16 +12004,6 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -xtend@^2.1.2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.2.0.tgz#eef6b1f198c1c8deafad8b1765a04dad4a01c5a9" - integrity sha512-SLt5uylT+4aoXxXuwtQp5ZnMMzhDb1Xkg4pEqc00WUJCQifPfV9Ub1VrNhp9kXkrjZD2I2Hl8WnjP37jzZLPZw== - y18n@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"