From a6b7065efc77472bcc61e5bde4fc70f87a8f8fd1 Mon Sep 17 00:00:00 2001 From: Conor Brady Date: Wed, 25 Oct 2023 12:12:33 -0700 Subject: [PATCH] Renaming zones to shapes --- api/app/routers/fba.py | 6 +- api/app/schemas/fba.py | 2 +- web/src/api/fbaAPI.ts | 8 +- web/src/app/rootReducer.ts | 6 +- .../features/fba/components/map/FBAMap.tsx | 73 ++++++++++--------- .../features/fba/components/map/Legend.tsx | 6 +- .../fba/components/map/fbaMap.test.tsx | 6 +- .../fba/components/map/featureStylers.ts | 22 +++--- .../fba/components/map/legend.test.tsx | 4 +- .../fba/pages/FireBehaviourAdvisoryPage.tsx | 16 ++-- .../features/fba/slices/fireZoneAreasSlice.ts | 38 +++++----- 11 files changed, 95 insertions(+), 92 deletions(-) diff --git a/api/app/routers/fba.py b/api/app/routers/fba.py index 35514d942..c539569fb 100644 --- a/api/app/routers/fba.py +++ b/api/app/routers/fba.py @@ -44,7 +44,7 @@ async def get_all_fire_centers(_=Depends(authentication_required)): async def get_shapes(run_type: RunType, run_datetime: datetime, for_date: date, _=Depends(authentication_required)): """ Return area of each zone unit shape, and percentage of area of zone unit shape with high hfi. """ async with get_async_read_session_scope() as session: - zones = [] + shapes = [] rows = await get_hfi_area(session, RunTypeEnum(run_type.value), @@ -55,13 +55,13 @@ async def get_shapes(run_type: RunType, run_datetime: datetime, for_date: date, for row in rows: combustible_area = row.combustible_area # type: ignore hfi_area = row.hfi_area # type: ignore - zones.append(FireShapeArea( + shapes.append(FireShapeArea( fire_shape_id=row.source_identifier, # type: ignore threshold=row.threshold, # type: ignore combustible_area=row.combustible_area, # type: ignore elevated_hfi_area=row.hfi_area, # type: ignore elevated_hfi_percentage=hfi_area / combustible_area * 100)) - return FireShapeAreaListResponse(zones=zones) + return FireShapeAreaListResponse(shapes=shapes) @router.get('/hfi-fuels/{run_type}/{for_date}/{run_datetime}/{zone_id}', diff --git a/api/app/schemas/fba.py b/api/app/schemas/fba.py index 56545c824..fee05bd32 100644 --- a/api/app/schemas/fba.py +++ b/api/app/schemas/fba.py @@ -35,7 +35,7 @@ class FireShapeArea(BaseModel): class FireShapeAreaListResponse(BaseModel): """ Response for all planning areas, in a list """ - zones: List[FireShapeArea] + shapes: List[FireShapeArea] class FireShapeHighHfiAreas(BaseModel): diff --git a/web/src/api/fbaAPI.ts b/web/src/api/fbaAPI.ts index 159ca3c7e..3d30ac5b5 100644 --- a/web/src/api/fbaAPI.ts +++ b/web/src/api/fbaAPI.ts @@ -56,8 +56,8 @@ export interface FireZoneElevationInfoResponse { hfi_elevation_info: ElevationInfoByThreshold[] } -export interface ZoneAreaListResponse { - zones: FireShapeArea[] +export interface FireShapeAreaListResponse { + shapes: FireShapeArea[] } export interface HfiThresholdFuelTypeArea { @@ -85,11 +85,11 @@ export async function getFBAFireCenters(): Promise { return data } -export async function getFireZoneAreas( +export async function getFireShapeAreas( run_type: RunType, run_datetime: string, for_date: string -): Promise { +): Promise { const url = `/fba/fire-shape-areas/${run_type.toLowerCase()}/${encodeURI(run_datetime)}/${for_date}` const { data } = await axios.get(url, {}) return data diff --git a/web/src/app/rootReducer.ts b/web/src/app/rootReducer.ts index 0619fd491..cd0b8c18f 100644 --- a/web/src/app/rootReducer.ts +++ b/web/src/app/rootReducer.ts @@ -11,7 +11,7 @@ import hfiStationsReducer from 'features/hfiCalculator/slices/stationsSlice' import hfiReadyReducer, { HFIReadyState } from 'features/hfiCalculator/slices/hfiReadySlice' import fbaCalculatorSlice from 'features/fbaCalculator/slices/fbaCalculatorSlice' import fireCentersSlice from 'commonSlices/fireCentersSlice' -import fireZoneAreasSlice from 'features/fba/slices/fireZoneAreasSlice' +import fireShapeAreasSlice from 'features/fba/slices/fireZoneAreasSlice' import valueAtCoordinateSlice from 'features/fba/slices/valueAtCoordinateSlice' import runDatesSlice from 'features/fba/slices/runDatesSlice' import hfiFuelTypesSlice from 'features/fba/slices/hfiFuelTypesSlice' @@ -34,7 +34,7 @@ const rootReducer = combineReducers({ hfiReady: hfiReadyReducer, fbaCalculatorResults: fbaCalculatorSlice, fireCenters: fireCentersSlice, - fireZoneAreas: fireZoneAreasSlice, + fireShapeAreas: fireShapeAreasSlice, runDates: runDatesSlice, valueAtCoordinate: valueAtCoordinateSlice, hfiFuelTypes: hfiFuelTypesSlice, @@ -63,7 +63,7 @@ export const selectToken = (state: RootState) => state.authentication.token export const selectFireBehaviourCalcResult = (state: RootState) => state.fbaCalculatorResults export const selectHFIStations = (state: RootState) => state.hfiStations export const selectFireCenters = (state: RootState) => state.fireCenters -export const selectFireZoneAreas = (state: RootState) => state.fireZoneAreas +export const selectFireShapeAreas = (state: RootState) => state.fireShapeAreas export const selectRunDates = (state: RootState) => state.runDates export const selectValueAtCoordinate = (state: RootState) => state.valueAtCoordinate export const selectHFIFuelTypes = (state: RootState) => state.hfiFuelTypes diff --git a/web/src/features/fba/components/map/FBAMap.tsx b/web/src/features/fba/components/map/FBAMap.tsx index 8e3e32ff5..95665701d 100644 --- a/web/src/features/fba/components/map/FBAMap.tsx +++ b/web/src/features/fba/components/map/FBAMap.tsx @@ -19,7 +19,7 @@ import { extentsMap } from 'features/fba/fireCentreExtents' import { fireCentreStyler, fireCentreLabelStyler, - fireZoneStyler, + fireShapeStyler, fireShapeLabelStyler, stationStyler, hfiStyler @@ -40,10 +40,10 @@ const zoom = 6 export interface FBAMapProps { testId?: string selectedFireCenter: FireCenter | undefined - selectedFireZone: FireShape | undefined + selectedFireShape: FireShape | undefined forDate: DateTime - setSelectedFireZone: React.Dispatch> - fireZoneAreas: FireShapeArea[] + setSelectedFireShape: React.Dispatch> + fireShapeAreas: FireShapeArea[] runType: RunType advisoryThreshold: number showSummaryPanel: boolean @@ -62,7 +62,7 @@ const removeLayerByName = (map: ol.Map, layerName: string) => { const FBAMap = (props: FBAMapProps) => { const { stations } = useSelector(selectFireWeatherStations) - const [showZoneStatus, setShowZoneStatus] = useState(true) + const [showShapeStatus, setShowShapeStatus] = useState(true) const [showHFI, setShowHFI] = React.useState(false) const [map, setMap] = useState(null) const mapRef = useRef(null) @@ -71,13 +71,13 @@ const FBAMap = (props: FBAMapProps) => { const fireCentreVectorSource = new olpmtiles.PMTilesVectorSource({ url: `${PMTILES_BUCKET}fireCentres.pmtiles` }) - const fireZoneVectorSource = new olpmtiles.PMTilesVectorSource({ + const fireShapeVectorSource = new olpmtiles.PMTilesVectorSource({ url: `${PMTILES_BUCKET}fireZoneUnits.pmtiles` }) const fireCentreLabelVectorSource = new olpmtiles.PMTilesVectorSource({ url: `${PMTILES_BUCKET}fireCentreLabels.pmtiles` }) - const fireZoneLabelVectorSource = new olpmtiles.PMTilesVectorSource({ + const fireShapeLabelVectorSource = new olpmtiles.PMTilesVectorSource({ url: `${PMTILES_BUCKET}fireZoneUnitLabels.pmtiles` }) @@ -88,9 +88,9 @@ const FBAMap = (props: FBAMapProps) => { .getArray() .find(l => l.getProperties()?.name === layerName) - if (layerName === 'fireZoneVector') { - fireZoneVTL.setStyle( - fireZoneStyler(cloneDeep(props.fireZoneAreas), props.advisoryThreshold, props.selectedFireZone, isVisible) + if (layerName === 'fireShapeVector') { + fireShapeVTL.setStyle( + fireShapeStyler(cloneDeep(props.fireShapeAreas), props.advisoryThreshold, props.selectedFireShape, isVisible) ) } else if (layer) { layer.setVisible(isVisible) @@ -105,17 +105,17 @@ const FBAMap = (props: FBAMapProps) => { zIndex: 50 }) ) - const [fireZoneVTL] = useState( + const [fireShapeVTL] = useState( new VectorTileLayer({ - source: fireZoneVectorSource, - style: fireZoneStyler( - cloneDeep(props.fireZoneAreas), + source: fireShapeVectorSource, + style: fireShapeStyler( + cloneDeep(props.fireShapeAreas), props.advisoryThreshold, - props.selectedFireZone, - showZoneStatus + props.selectedFireShape, + showShapeStatus ), zIndex: 49, - properties: { name: 'fireZoneVector' } + properties: { name: 'fireShapeVector' } }) ) // Seperate layer for polygons and for labels, to avoid duplicate labels. @@ -128,11 +128,11 @@ const FBAMap = (props: FBAMapProps) => { }) ) // Seperate layer for polygons and for labels, to avoid duplicate labels. - const [fireZoneLabelVTL] = useState( + const [fireShapeLabelVTL] = useState( new VectorTileLayer({ declutter: true, - source: fireZoneLabelVectorSource, - style: fireShapeLabelStyler(props.selectedFireZone), + source: fireShapeLabelVectorSource, + style: fireShapeLabelStyler(props.selectedFireShape), zIndex: 99, minZoom: 6 }) @@ -141,9 +141,9 @@ const FBAMap = (props: FBAMapProps) => { useEffect(() => { if (map) { map.on('click', event => { - fireZoneVTL.getFeatures(event.pixel).then(features => { + fireShapeVTL.getFeatures(event.pixel).then(features => { if (!features.length) { - props.setSelectedFireZone(undefined) + props.setSelectedFireShape(undefined) return } const feature = features[0] @@ -161,7 +161,7 @@ const FBAMap = (props: FBAMapProps) => { area_sqm: feature.getProperties().Shape_Area } props.setShowSummaryPanel(true) - props.setSelectedFireZone(fireZone) + props.setSelectedFireShape(fireZone) }) }) } @@ -171,7 +171,7 @@ const FBAMap = (props: FBAMapProps) => { if (!map) return if (!props.showSummaryPanel) { - props.setSelectedFireZone(undefined) + props.setSelectedFireShape(undefined) } }, [props.showSummaryPanel]) // eslint-disable-line react-hooks/exhaustive-deps @@ -193,14 +193,19 @@ const FBAMap = (props: FBAMapProps) => { useEffect(() => { if (!map) return - fireZoneVTL.setStyle( - fireZoneStyler(cloneDeep(props.fireZoneAreas), props.advisoryThreshold, props.selectedFireZone, showZoneStatus) + fireShapeVTL.setStyle( + fireShapeStyler( + cloneDeep(props.fireShapeAreas), + props.advisoryThreshold, + props.selectedFireShape, + showShapeStatus + ) ) - fireZoneLabelVTL.setStyle(fireShapeLabelStyler(props.selectedFireZone)) - fireZoneVTL.changed() - fireZoneLabelVTL.changed() + fireShapeLabelVTL.setStyle(fireShapeLabelStyler(props.selectedFireShape)) + fireShapeVTL.changed() + fireShapeLabelVTL.changed() // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.selectedFireZone, props.fireZoneAreas, props.advisoryThreshold]) + }, [props.selectedFireShape, props.fireShapeAreas, props.advisoryThreshold]) useEffect(() => { if (!map) return @@ -246,9 +251,9 @@ const FBAMap = (props: FBAMapProps) => { source: baseMapSource }), fireCentreVTL, - fireZoneVTL, + fireShapeVTL, fireCentreLabelVTL, - fireZoneLabelVTL + fireShapeLabelVTL ], overlays: [], controls: defaultControls().extend([new FullScreen()]) @@ -299,8 +304,8 @@ const FBAMap = (props: FBAMapProps) => { diff --git a/web/src/features/fba/components/map/Legend.tsx b/web/src/features/fba/components/map/Legend.tsx index 486fb551e..08d66c85c 100644 --- a/web/src/features/fba/components/map/Legend.tsx +++ b/web/src/features/fba/components/map/Legend.tsx @@ -76,12 +76,12 @@ const LegendItem: React.FC = ({ label, checked, onChange, subIt interface LegendProps { onToggleLayer: (layerName: string, isVisible: boolean) => void showZoneStatus: boolean - setShowZoneStatus: React.Dispatch> + setShowShapeStatus: React.Dispatch> showHFI: boolean setShowHFI: React.Dispatch> } -const Legend = ({ onToggleLayer, showZoneStatus, setShowZoneStatus, showHFI, setShowHFI }: LegendProps) => { +const Legend = ({ onToggleLayer, showZoneStatus, setShowShapeStatus, showHFI, setShowHFI }: LegendProps) => { const handleLayerChange = ( layerName: string, isVisible: boolean, @@ -108,7 +108,7 @@ const Legend = ({ onToggleLayer, showZoneStatus, setShowZoneStatus, showHFI, set handleLayerChange('fireZoneVector', showZoneStatus, setShowZoneStatus)} + onChange={() => handleLayerChange('fireShapeVector', showZoneStatus, setShowShapeStatus)} subItems={zoneStatusSubItems} /> { forDate={DateTime.fromISO('2016-05-25')} advisoryThreshold={0} selectedFireCenter={undefined} - selectedFireZone={undefined} - fireZoneAreas={[]} + selectedFireShape={undefined} + fireShapeAreas={[]} runType={RunType.FORECAST} - setSelectedFireZone={function (): void { + setSelectedFireShape={function (): void { throw new Error('Function not implemented.') }} showSummaryPanel={true} diff --git a/web/src/features/fba/components/map/featureStylers.ts b/web/src/features/fba/components/map/featureStylers.ts index 1e62fe164..5d0de1e9e 100644 --- a/web/src/features/fba/components/map/featureStylers.ts +++ b/web/src/features/fba/components/map/featureStylers.ts @@ -40,16 +40,16 @@ export const fireCentreStyler = (): Style => { }) } -export const fireZoneStyler = ( - fireZoneAreas: FireShapeArea[], +export const fireShapeStyler = ( + fireShapeAreas: FireShapeArea[], advisoryThreshold: number, - selectedFireZone: FireShape | undefined, + selectedFireShape: FireShape | undefined, showZoneStatus: boolean ) => { const a = (feature: RenderFeature | ol.Feature): Style => { const fire_shape_id = feature.getProperties().OBJECTID - const fireZoneAreaByThreshold = fireZoneAreas.filter(f => f.fire_shape_id === fire_shape_id) - const selected = !!(selectedFireZone?.fire_shape_id && selectedFireZone.fire_shape_id === fire_shape_id) + const fireShapes = fireShapeAreas.filter(f => f.fire_shape_id === fire_shape_id) + const selected = !!(selectedFireShape?.fire_shape_id && selectedFireShape.fire_shape_id === fire_shape_id) let strokeValue = 'black' if (selected) { strokeValue = 'green' @@ -60,22 +60,20 @@ export const fireZoneStyler = ( color: strokeValue, width: selected ? 8 : 1 }), - fill: showZoneStatus - ? getAdvisoryColors(advisoryThreshold, fireZoneAreaByThreshold) - : new Fill({ color: EMPTY_FILL }) + fill: showZoneStatus ? getAdvisoryColors(advisoryThreshold, fireShapes) : new Fill({ color: EMPTY_FILL }) }) } return a } -export const getAdvisoryColors = (advisoryThreshold: number, fireZoneArea?: FireShapeArea[]) => { +export const getAdvisoryColors = (advisoryThreshold: number, fireShapeArea?: FireShapeArea[]) => { let fill = new Fill({ color: EMPTY_FILL }) - if (isUndefined(fireZoneArea) || fireZoneArea.length === 0) { + if (isUndefined(fireShapeArea) || fireShapeArea.length === 0) { return fill } - const advisoryThresholdArea = fireZoneArea.find(area => area.threshold == 1) - const warningThresholdArea = fireZoneArea.find(area => area.threshold == 2) + const advisoryThresholdArea = fireShapeArea.find(area => area.threshold == 1) + const warningThresholdArea = fireShapeArea.find(area => area.threshold == 2) const advisoryPercentage = advisoryThresholdArea?.elevated_hfi_percentage ?? 0 const warningPercentage = warningThresholdArea?.elevated_hfi_percentage ?? 0 diff --git a/web/src/features/fba/components/map/legend.test.tsx b/web/src/features/fba/components/map/legend.test.tsx index 8cefcedca..7cef4228c 100644 --- a/web/src/features/fba/components/map/legend.test.tsx +++ b/web/src/features/fba/components/map/legend.test.tsx @@ -11,7 +11,7 @@ describe('Legend', () => { const { getByTestId } = render( { const { getByTestId } = render( { const [runType, setRunType] = useState(RunType.FORECAST) const [showSummaryPanel, setShowSummaryPanel] = useState(true) const { mostRecentRunDate } = useSelector(selectRunDates) - const { fireZoneAreas } = useSelector(selectFireZoneAreas) + const { fireShapeAreas } = useSelector(selectFireShapeAreas) useEffect(() => { const findCenter = (id: string | null): FireCenter | undefined => { @@ -124,7 +124,7 @@ const FireBehaviourAdvisoryPage: React.FunctionComponent = () => { useEffect(() => { const doiISODate = dateOfInterest.toISODate() if (!isNull(mostRecentRunDate) && !isNull(doiISODate) && !isUndefined(mostRecentRunDate)) { - dispatch(fetchFireZoneAreas(runType, mostRecentRunDate.toString(), doiISODate)) + dispatch(fetchFireShapeAreas(runType, mostRecentRunDate.toString(), doiISODate)) } }, [mostRecentRunDate]) // eslint-disable-line react-hooks/exhaustive-deps @@ -225,7 +225,7 @@ const FireBehaviourAdvisoryPage: React.FunctionComponent = () => { selectedFireZone={selectedFireZone} fuelTypeInfo={hfiThresholdsFuelTypes} hfiElevationInfo={fireZoneElevationInfo} - fireZoneAreas={fireZoneAreas} + fireZoneAreas={fireShapeAreas} showSummaryPanel={showSummaryPanel} setShowSummaryPanel={setShowSummaryPanel} /> @@ -234,11 +234,11 @@ const FireBehaviourAdvisoryPage: React.FunctionComponent = () => { diff --git a/web/src/features/fba/slices/fireZoneAreasSlice.ts b/web/src/features/fba/slices/fireZoneAreasSlice.ts index 44d5f53c7..043d1490e 100644 --- a/web/src/features/fba/slices/fireZoneAreasSlice.ts +++ b/web/src/features/fba/slices/fireZoneAreasSlice.ts @@ -2,63 +2,63 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' import { AppThunk } from 'app/store' import { logError } from 'utils/error' -import { FireShapeArea, ZoneAreaListResponse, getFireZoneAreas } from 'api/fbaAPI' +import { FireShapeArea, FireShapeAreaListResponse, getFireShapeAreas } from 'api/fbaAPI' import { RunType } from 'features/fba/pages/FireBehaviourAdvisoryPage' interface State { loading: boolean error: string | null - fireZoneAreas: FireShapeArea[] + fireShapeAreas: FireShapeArea[] } const initialState: State = { loading: false, error: null, - fireZoneAreas: [] + fireShapeAreas: [] } -const fireZoneAreasSlice = createSlice({ - name: 'fireZoneAreas', +const fireShapeAreasSlice = createSlice({ + name: 'fireShapeAreas', initialState, reducers: { - getFireZoneAreasStart(state: State) { + getFireShapeAreasStart(state: State) { state.error = null state.loading = true - state.fireZoneAreas = [] + state.fireShapeAreas = [] }, - getFireZoneAreasFailed(state: State, action: PayloadAction) { + getFireShapeAreasFailed(state: State, action: PayloadAction) { state.error = action.payload state.loading = false }, - getFireZoneAreasSuccess(state: State, action: PayloadAction) { + getFireShapeAreasSuccess(state: State, action: PayloadAction) { state.error = null - state.fireZoneAreas = action.payload.zones + state.fireShapeAreas = action.payload.shapes state.loading = false } } }) -export const { getFireZoneAreasStart, getFireZoneAreasFailed, getFireZoneAreasSuccess } = fireZoneAreasSlice.actions +export const { getFireShapeAreasStart, getFireShapeAreasFailed, getFireShapeAreasSuccess } = fireShapeAreasSlice.actions -export default fireZoneAreasSlice.reducer +export default fireShapeAreasSlice.reducer -export const fetchFireZoneAreas = +export const fetchFireShapeAreas = (runType: RunType, run_datetime: string, for_date: string): AppThunk => async dispatch => { if (run_datetime != undefined && run_datetime !== ``) { try { - dispatch(getFireZoneAreasStart()) - const fireZoneAreas = await getFireZoneAreas(runType, run_datetime, for_date) - dispatch(getFireZoneAreasSuccess(fireZoneAreas)) + dispatch(getFireShapeAreasStart()) + const fireShapeAreas = await getFireShapeAreas(runType, run_datetime, for_date) + dispatch(getFireShapeAreasSuccess(fireShapeAreas)) } catch (err) { - dispatch(getFireZoneAreasFailed((err as Error).toString())) + dispatch(getFireShapeAreasFailed((err as Error).toString())) logError(err) } } else { try { - dispatch(getFireZoneAreasFailed('run_datetime cannot be undefined!')) + dispatch(getFireShapeAreasFailed('run_datetime cannot be undefined!')) } catch (err) { - dispatch(getFireZoneAreasFailed((err as Error).toString())) + dispatch(getFireShapeAreasFailed((err as Error).toString())) logError(err) } }