Skip to content
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FormControl, FormControlLabel, FormLabel, Radio, RadioGroup } from '@mui/material'
import { RunType } from '@wps/api/fbaAPI'
import { RunType } from '@wps/api/runType'
import { theme } from '@wps/ui/theme'
import { isNull } from 'lodash'
import React from 'react'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { fireEvent, render } from '@testing-library/react'
import { RunType } from '@wps/api/fbaAPI'
import { RunType } from '@wps/api/runType'
import { vi } from 'vitest'
import ActualForecastControl from './ActualForecastControl'

Expand Down
3 changes: 2 additions & 1 deletion web/apps/wps-web/src/features/fba/components/map/FBAMap.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Box } from '@mui/material'
import { type FireShape, RunType } from '@wps/api/fbaAPI'
import type { FireShape } from '@wps/api/fbaAPI'
import { RunType } from '@wps/api/runType'
import type { FireCentre } from '@wps/types/fireCentre'
import { ErrorBoundary } from '@wps/ui/ErrorBoundary'
import { createHillshadeVectorTileLayer, createVectorTileLayer, getStyleJson } from '@wps/utils/vectorLayerUtils'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { render } from '@testing-library/react'
import { RunType } from '@wps/api/fbaAPI'
import { RunType } from '@wps/api/runType'
import { createHillshadeVectorTileLayer, createVectorTileLayer, getStyleJson } from '@wps/utils/vectorLayerUtils'
import store from 'app/store'
import FBAMap from 'features/fba/components/map/FBAMap'
Expand Down
4 changes: 2 additions & 2 deletions web/apps/wps-web/src/features/fba/cqlBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { RunType } from '@wps/api/fbaAPI'
import type { RunType } from '@wps/api/runType'
import type { DateTime } from 'luxon'

/**
Expand All @@ -17,6 +17,6 @@ import type { DateTime } from 'luxon'
*/
// TODO: add in param for run_date: DateTime
export const buildHFICql = (for_date: DateTime, run_type: RunType) => {
const queryParams = encodeURIComponent(`for_date=${for_date.toISODate()} AND run_type='${run_type.toLowerCase()}'`)
const queryParams = encodeURIComponent(`for_date=${for_date.toISODate()} AND run_type='${run_type}'`)
return `filter=${queryParams}`
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Box, FormControl, Grid, styled } from '@mui/material'
import { type FireShape, RunType } from '@wps/api/fbaAPI'
import type { FireShape } from '@wps/api/fbaAPI'
import { RunType } from '@wps/api/runType'
import { getStations, StationSource } from '@wps/api/stationAPI'
import type { FireCentre } from '@wps/types/fireCentre'
import AboutDataPopover from '@wps/ui/AboutDataPopover'
Expand Down Expand Up @@ -52,7 +53,7 @@ const FireBehaviourAdvisoryPage: React.FunctionComponent = () => {
? DateTime.now().setZone(`UTC${PST_UTC_OFFSET}`)
: DateTime.now().setZone(`UTC${PST_UTC_OFFSET}`).plus({ days: 1 })
)
const [runType, setRunType] = useState(RunType.FORECAST)
const [runType, setRunType] = useState<RunType>(RunType.FORECAST)
// Set some reasonable historical min and max dates for ASA (used by the DatePicker).
const [historicalMinDate, setHistoricalMinDate] = useState<DateTime>(
DateTime.fromObject({ year: 2022, month: 4, day: 1 })
Expand All @@ -67,11 +68,10 @@ const FireBehaviourAdvisoryPage: React.FunctionComponent = () => {

const updateDatePickerOptions = useCallback(() => {
const dates: DateTime[] = []
const runTypeLower = runType.toLocaleLowerCase()
if (!isNull(sfmsBounds) && !isEmpty(sfmsBounds)) {
for (const key of Object.keys(sfmsBounds)) {
const minValue = sfmsBounds[key]?.[runTypeLower]?.minimum
const maxValue = sfmsBounds[key]?.[runTypeLower]?.maximum
const minValue = sfmsBounds[key]?.[runType]?.minimum
const maxValue = sfmsBounds[key]?.[runType]?.maximum
if (minValue && maxValue) {
const minDate = DateTime.fromISO(minValue)
const maxDate = DateTime.fromISO(maxValue)
Expand All @@ -84,8 +84,8 @@ const FireBehaviourAdvisoryPage: React.FunctionComponent = () => {
setHistoricalMaxDate(dates[dates.length - 1].plus({ days: 1 }))
}
}
const currentYearMin = sfmsBounds?.[dateOfInterestYear]?.[runTypeLower]?.minimum ?? `${dateOfInterestYear}-04-01`
const currentYearMax = sfmsBounds?.[dateOfInterestYear]?.[runTypeLower]?.maximum ?? `${dateOfInterestYear}-10-31`
const currentYearMin = sfmsBounds?.[dateOfInterestYear]?.[runType]?.minimum ?? `${dateOfInterestYear}-04-01`
const currentYearMax = sfmsBounds?.[dateOfInterestYear]?.[runType]?.maximum ?? `${dateOfInterestYear}-10-31`
setCurrentYearMinDate(DateTime.fromISO(currentYearMin))
setCurrentYearMaxDate(DateTime.fromISO(currentYearMax))
}, [dateOfInterestYear, runType, sfmsBounds])
Expand Down
4 changes: 2 additions & 2 deletions web/apps/wps-web/src/features/fba/pmtilesBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { RunType } from '@wps/api/fbaAPI'
import type { RunType } from '@wps/api/runType'
import { PMTILES_BUCKET } from '@wps/utils/env'
import type { DateTime } from 'luxon'

Expand All @@ -10,7 +10,7 @@ import type { DateTime } from 'luxon'
* @returns a URL to the PMTiles stored in our s3 bucket
*/
export const buildPMTilesURL = (for_date: DateTime, run_type: RunType, run_date: DateTime): string => {
const PMTilesURL = `${PMTILES_BUCKET}hfi/${run_type.toLowerCase()}/${run_date.toISODate()}/hfi${for_date.toISODate({
const PMTilesURL = `${PMTILES_BUCKET}hfi/${run_type}/${run_date.toISODate()}/hfi${for_date.toISODate({
format: 'basic'
})}.pmtiles`

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createSlice, type PayloadAction } from '@reduxjs/toolkit'
import { type FireCentreHFIStats, getFireCentreHFIStats, type RunType } from '@wps/api/fbaAPI'
import { type FireCentreHFIStats, getFireCentreHFIStats } from '@wps/api/fbaAPI'
import type { RunType } from '@wps/api/runType'
import { logError } from '@wps/utils/error'
import type { AppThunk } from 'app/store'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createSlice, type PayloadAction } from '@reduxjs/toolkit'
import { type FireCentreTPIResponse, getFireCentreTPIStats, type RunType } from '@wps/api/fbaAPI'
import { type FireCentreTPIResponse, getFireCentreTPIStats } from '@wps/api/fbaAPI'
import type { RunType } from '@wps/api/runType'
import { logError } from '@wps/utils/error'
import type { AppThunk } from 'app/store'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { createSlice, type PayloadAction } from '@reduxjs/toolkit'
import {
type ElevationInfoByThreshold,
type FireZoneElevationInfoResponse,
getFireZoneElevationInfo,
type RunType
getFireZoneElevationInfo
} from '@wps/api/fbaAPI'
import type { RunType } from '@wps/api/runType'
import { logError } from '@wps/utils/error'
import type { AppThunk } from 'app/store'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { createSelector, createSlice, type PayloadAction } from '@reduxjs/toolkit'
import {
type FireShapeStatusDetail,
getProvincialSummary,
type ProvincialSummaryResponse,
type RunType
} from '@wps/api/fbaAPI'
import { type FireShapeStatusDetail, getProvincialSummary, type ProvincialSummaryResponse } from '@wps/api/fbaAPI'
import type { RunType } from '@wps/api/runType'
import { logError } from '@wps/utils/error'
import type { RootState } from 'app/rootReducer'
import type { AppThunk } from 'app/store'
Expand Down
11 changes: 3 additions & 8 deletions web/apps/wps-web/src/features/fba/slices/runDatesSlice.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import { combineReducers } from '@reduxjs/toolkit'
import {
getAllRunDates,
getMostRecentRunDate,
getSFMSBounds,
RunType,
type SFMSBounds,
type SFMSBoundsResponse
} from '@wps/api/fbaAPI'
import { getAllRunDates, getMostRecentRunDate, getSFMSBounds } from '@wps/api/fbaAPI'
import { RunType } from '@wps/api/runType'
import type { SFMSBounds, SFMSBoundsResponse } from '@wps/api/sfmsBounds'
import { logError } from '@wps/utils/error'
import { DateTime } from 'luxon'
import { beforeEach, describe, expect, it, vi } from 'vitest'
Expand Down
4 changes: 3 additions & 1 deletion web/apps/wps-web/src/features/fba/slices/runDatesSlice.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { createSelector, createSlice, type PayloadAction } from '@reduxjs/toolkit'
import { getAllRunDates, getMostRecentRunDate, getSFMSBounds, type RunType, type SFMSBounds } from '@wps/api/fbaAPI'
import { getAllRunDates, getMostRecentRunDate, getSFMSBounds } from '@wps/api/fbaAPI'
import type { RunType } from '@wps/api/runType'
import type { SFMSBounds } from '@wps/api/sfmsBounds'
import { logError } from '@wps/utils/error'
import type { AppThunk } from 'app/store'
import type { DateTime } from 'luxon'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { fireEvent, render, screen } from '@testing-library/react'
import { RunType } from '@wps/api/runType'
import RunTypeDropdown from './RunTypeDropdown'

describe('RunTypeDropdown', () => {
it('shows actuals and forecasts', () => {
render(<RunTypeDropdown selectedRunType={RunType.ACTUAL} setSelectedRunType={vi.fn()} />)

fireEvent.mouseDown(screen.getByRole('combobox', { name: 'Source' }))

expect(screen.getByRole('option', { name: 'Actual' })).toBeInTheDocument()
expect(screen.getByRole('option', { name: 'Forecast' })).toBeInTheDocument()
})

it('updates the selected run type', () => {
const setSelectedRunType = vi.fn()
render(<RunTypeDropdown selectedRunType={RunType.ACTUAL} setSelectedRunType={setSelectedRunType} />)

fireEvent.mouseDown(screen.getByRole('combobox', { name: 'Source' }))
fireEvent.click(screen.getByRole('option', { name: 'Forecast' }))

expect(setSelectedRunType).toHaveBeenCalledWith(RunType.FORECAST)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { FormControl, InputLabel, MenuItem, Select, type SelectChangeEvent } from '@mui/material'
import { RunType } from '@wps/api/runType'

const RUN_TYPE_LABELS: Record<RunType, string> = {
[RunType.ACTUAL]: 'Actual',
[RunType.FORECAST]: 'Forecast'
}

interface RunTypeDropdownProps {
selectedRunType: RunType
setSelectedRunType: (runType: RunType) => void
}

const RunTypeDropdown = ({ selectedRunType, setSelectedRunType }: RunTypeDropdownProps) => {
const handleChange = (event: SelectChangeEvent<RunType>) => {
setSelectedRunType(event.target.value as RunType)
}

return (
<FormControl sx={{ minWidth: 140 }}>
<InputLabel id="sfms-run-type-label">Source</InputLabel>
<Select
labelId="sfms-run-type-label"
id="sfms-run-type-select"
value={selectedRunType}
label="Source"
onChange={handleChange}
>
{Object.values(RunType).map(runType => (
<MenuItem key={runType} value={runType}>
{RUN_TYPE_LABELS[runType]}
</MenuItem>
))}
</Select>
</FormControl>
)
}

export default RunTypeDropdown
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { RunType } from '@wps/api/runType'
import { describe, expect, it, vi } from 'vitest'
import type { RasterError } from './layerManager'
import RasterErrorNotification, { getAlertSeverity } from './RasterErrorNotification'
Expand All @@ -26,14 +27,28 @@ describe('RasterErrorNotification', () => {
expect(getAlertSeverity('unknown')).toBe('warning')
})

it('should display correct message for not_found error', () => {
it('should identify unavailable actual data without ruling out forecast data', () => {
const error: RasterError = {
type: 'not_found',
message: 'Test message'
}
render(<RasterErrorNotification error={error} onClose={vi.fn()} rasterLabel="FWI" />)
render(<RasterErrorNotification error={error} onClose={vi.fn()} rasterLabel="FWI" runType={RunType.ACTUAL} />)

expect(screen.getByText(/FWI data not available for this date/i)).toBeInTheDocument()
expect(
screen.getByText('Actual FWI data is not available for this date. Forecast data may be available.')
).toBeInTheDocument()
})

it('should identify unavailable forecast data', () => {
const error: RasterError = {
type: 'not_found',
message: 'Test message'
}
render(<RasterErrorNotification error={error} onClose={vi.fn()} rasterLabel="FWI" runType={RunType.FORECAST} />)

expect(
screen.getByText('Forecast FWI data is not available for this date. It may not be generated yet.')
).toBeInTheDocument()
})

it('should display correct message for forbidden error', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Alert, type AlertColor, Snackbar } from '@mui/material'
import { RunType } from '@wps/api/runType'
import React from 'react'
import type { RasterError } from '@/features/sfmsInsights/components/map/layerManager'

interface RasterErrorNotificationProps {
error: RasterError | null
onClose: () => void
rasterLabel?: string
runType?: RunType
}

export const getAlertSeverity = (errorType: RasterError['type']): AlertColor => {
Expand All @@ -19,9 +21,15 @@ export const getAlertSeverity = (errorType: RasterError['type']): AlertColor =>
}
}

const getErrorMessage = (error: RasterError, rasterLabel: string): string => {
const getErrorMessage = (error: RasterError, rasterLabel: string, runType?: RunType): string => {
switch (error.type) {
case 'not_found':
if (runType === RunType.ACTUAL) {
return `Actual ${rasterLabel} data is not available for this date. Forecast data may be available.`
}
if (runType === RunType.FORECAST) {
return `Forecast ${rasterLabel} data is not available for this date. It may not be generated yet.`
}
return `${rasterLabel} data not available for this date. It may not be generated yet.`
case 'forbidden':
return `Access denied to ${rasterLabel} data. Please check your authentication.`
Expand All @@ -32,13 +40,13 @@ const getErrorMessage = (error: RasterError, rasterLabel: string): string => {
}
}

const RasterErrorNotification = ({ error, onClose, rasterLabel = 'Raster' }: RasterErrorNotificationProps) => {
const RasterErrorNotification = ({ error, onClose, rasterLabel = 'Raster', runType }: RasterErrorNotificationProps) => {
if (!error) {
return null
}

const severity = getAlertSeverity(error.type)
const message = getErrorMessage(error, rasterLabel)
const message = getErrorMessage(error, rasterLabel, runType)

return (
<Snackbar
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Box, CircularProgress } from '@mui/material'
import { ErrorBoundary } from '@sentry/react'
import { RunType } from '@wps/api/runType'
import { BC_EXTENT, CENTER_OF_BC } from '@wps/utils/constants'
import { BASEMAP_STYLE_URL, BASEMAP_TILE_URL } from '@wps/utils/env'
import { createVectorTileLayer, getStyleJson } from '@wps/utils/vectorLayerUtils'
Expand Down Expand Up @@ -36,10 +37,17 @@ interface SFMSMapProps {
snowDate: DateTime | null
rasterDate: DateTime | null
rasterType?: RasterType
runType?: RunType
showSnow?: boolean
}

const SFMSMap = ({ snowDate, rasterDate, rasterType = 'fwi', showSnow = true }: SFMSMapProps) => {
const SFMSMap = ({
snowDate,
rasterDate,
rasterType = 'fwi',
runType = RunType.ACTUAL,
showSnow = true
}: SFMSMapProps) => {
const token = useSelector(selectToken)
const [map, setMap] = useState<OlMap | null>(null)
const [rasterTooltipData, setRasterTooltipData] = useState<RasterTooltipData>({
Expand Down Expand Up @@ -114,11 +122,11 @@ const SFMSMap = ({ snowDate, rasterDate, rasterType = 'fwi', showSnow = true }:

// Only load raster layer if we have a date (for fire weather) or if type is fuel (date-independent)
if (rasterDate || rasterType === 'fuel') {
rasterLayerManagerRef.current.updateLayer(getRasterLayer(rasterDate, rasterType, token))
rasterLayerManagerRef.current.updateLayer(getRasterLayer(rasterDate, rasterType, token, runType))
} else {
rasterLayerManagerRef.current.updateLayer(null)
}
}, [rasterDate, rasterType, token])
}, [rasterDate, rasterType, runType, token])

return (
<ErrorBoundary>
Expand Down Expand Up @@ -164,6 +172,7 @@ const SFMSMap = ({ snowDate, rasterDate, rasterType = 'fwi', showSnow = true }:
error={rasterError}
onClose={handleErrorClose}
rasterLabel={RASTER_CONFIG[rasterType].label}
runType={runType}
/>
</Box>
</MapContext.Provider>
Expand Down
Loading
Loading