diff --git a/frontend/src/components/map/MapPage.tsx b/frontend/src/components/map/MapPage.tsx index 2a014b3..ee9fd93 100644 --- a/frontend/src/components/map/MapPage.tsx +++ b/frontend/src/components/map/MapPage.tsx @@ -707,10 +707,7 @@ export default function MapPage({ // link adds are blocked regardless of count, so don't auto-clear there — the user // dismisses it themselves. Prevents a stale flag from resurfacing spuriously. useEffect(() => { - if ( - filtersUnlimited || - (!lockFilterAdds && Object.keys(filters).length < effectiveFilterCap) - ) { + if (filtersUnlimited || (!lockFilterAdds && Object.keys(filters).length < effectiveFilterCap)) { setFilterLimitHit(false); } }, [filtersUnlimited, lockFilterAdds, effectiveFilterCap, filters]); diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index 8a27a76..a13b540 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -682,8 +682,7 @@ const en = { addFilter: 'Add filters', findingPerfectPostcode: 'Finding the Perfect Postcode', addFiltersHint: 'Add filters below to narrow the map to areas that match your criteria', - upgradePrompt: - 'Go lifetime to stack unlimited filters across every postcode in England.', + upgradePrompt: 'Go lifetime to stack unlimited filters across every postcode in England.', oneTimeLifetime: 'One-time payment, lifetime access.', upgradeToFullMap: 'Upgrade to full map', registerPrompt: diff --git a/frontend/src/i18n/locales/hi.ts b/frontend/src/i18n/locales/hi.ts index 571014a..cbee11d 100644 --- a/frontend/src/i18n/locales/hi.ts +++ b/frontend/src/i18n/locales/hi.ts @@ -674,8 +674,7 @@ const hi: Translations = { addFilter: 'फ़िल्टर जोड़ें', findingPerfectPostcode: 'Perfect Postcode खोजा जा रहा है', addFiltersHint: 'अपनी शर्तों से मेल खाने वाले क्षेत्र पाने के लिए नीचे फ़िल्टर जोड़ें', - upgradePrompt: - 'इंग्लैंड के हर पोस्टकोड में असीमित फ़िल्टर लगाने के लिए आजीवन पहुँच लें.', + upgradePrompt: 'इंग्लैंड के हर पोस्टकोड में असीमित फ़िल्टर लगाने के लिए आजीवन पहुँच लें.', oneTimeLifetime: 'एक बार भुगतान, आजीवन पहुँच.', upgradeToFullMap: 'पूरे मानचित्र पर अपग्रेड करें', registerPrompt: diff --git a/frontend/src/i18n/locales/hu.ts b/frontend/src/i18n/locales/hu.ts index 6bca033..ccc5abc 100644 --- a/frontend/src/i18n/locales/hu.ts +++ b/frontend/src/i18n/locales/hu.ts @@ -702,7 +702,8 @@ const hu: Translations = { upgradeToFullMap: 'Teljes térkép megnyitása', registerPrompt: 'Hozz létre egy ingyenes fiókot, hogy akár 5 szűrőt kombinálhass, és menthess, megoszthass és exportálhass kereséseket.', - registerSubPrompt: 'Ingyenes – kártya nélkül. Korlátlan szűrők élethosszig tartó hozzáféréssel.', + registerSubPrompt: + 'Ingyenes – kártya nélkül. Korlátlan szűrők élethosszig tartó hozzáféréssel.', registerCta: 'Ingyenes fiók létrehozása', chooseFilters: 'Kattints a Hozzáadásra a szűréshez. A kis gombok adatokat mutatnak vagy színezik a térképet.', diff --git a/frontend/src/lib/url-state.test.ts b/frontend/src/lib/url-state.test.ts index c59ee96..3645bd1 100644 --- a/frontend/src/lib/url-state.test.ts +++ b/frontend/src/lib/url-state.test.ts @@ -2,6 +2,7 @@ import { beforeEach, describe, expect, it } from 'vitest'; import type { FeatureMeta } from '../types'; import { parseUrlState, stateToParams } from './url-state'; +import { DEFAULT_OVERLAY_IDS } from './overlays'; import { INITIAL_VIEW_STATE } from './consts'; import { createSchoolFilterKey } from './school-filter'; import { createSpecificCrimeFilterKey } from './crime-filter'; @@ -199,10 +200,10 @@ describe('url-state', () => { expect(state.overlays).toEqual(new Set(['noise', 'crime-hotspots'])); }); - it('enables crime + trees overlays by default on a fresh visit', () => { + it('enables the default overlays on a fresh visit', () => { const state = parseUrlState(); - expect(state.overlays).toEqual(new Set(['crime-hotspots', 'trees-outside-woodlands'])); + expect(state.overlays).toEqual(new Set(DEFAULT_OVERLAY_IDS)); }); it('round-trips an explicit "all overlays off" via the __none sentinel', () => { diff --git a/server-rs/src/data/crime_records.rs b/server-rs/src/data/crime_records.rs index 8402ffb..3aa99d3 100644 --- a/server-rs/src/data/crime_records.rs +++ b/server-rs/src/data/crime_records.rs @@ -158,7 +158,10 @@ impl CrimeRecords { ParquetReader::new(file) .get_metadata() .with_context(|| { - format!("Failed to read crime-records parquet metadata at {}", path.display()) + format!( + "Failed to read crime-records parquet metadata at {}", + path.display() + ) })? .clone() }; @@ -193,10 +196,18 @@ impl CrimeRecords { // the column builders' write order. let mut global_row: u32 = 0; - let columns: Vec = ["postcode", "month_index", "crime_type", "location", "outcome", "lat", "lon"] - .iter() - .map(|s| s.to_string()) - .collect(); + let columns: Vec = [ + "postcode", + "month_index", + "crime_type", + "location", + "outcome", + "lat", + "lon", + ] + .iter() + .map(|s| s.to_string()) + .collect(); let mut offset = 0usize; while offset < n { @@ -337,7 +348,10 @@ impl CrimeRecords { if let Some(prev) = cur_pc.take() { by_postcode.insert(prev, (cur_start, global_row - cur_start)); } - debug_assert_eq!(global_row as usize, n, "streamed fewer rows than the parquet declares"); + debug_assert_eq!( + global_row as usize, n, + "streamed fewer rows than the parquet declares" + ); let records = Self { month: month.finish()?, @@ -413,7 +427,7 @@ mod tests { .unwrap(); assert_eq!(robbery.outcome, Some("Court result")); assert_eq!(robbery.location, None); // null location → None - // Two records have a null outcome (an AA1 Burglary and the BB2 Drugs). + // Two records have a null outcome (an AA1 Burglary and the BB2 Drugs). let null_outcomes = all .iter() .map(|&i| recs.view(i)) @@ -518,7 +532,10 @@ mod tests { rss_after, ); - assert!(!recs.by_postcode.is_empty(), "expected at least one postcode"); + assert!( + !recs.by_postcode.is_empty(), + "expected at least one postcode" + ); assert!(total > 0, "expected at least one record"); // The old `.collect()` decoded all rows' string columns at once (tens of // GB). Streaming must keep the peak growth far below that; a generous 20GiB diff --git a/server-rs/src/data/postcode_population.rs b/server-rs/src/data/postcode_population.rs index 928e4cf..1913b3f 100644 --- a/server-rs/src/data/postcode_population.rs +++ b/server-rs/src/data/postcode_population.rs @@ -82,10 +82,7 @@ impl PostcodePopulation { bail!("population parquet at {} produced no rows", path.display()); } - info!( - postcodes = by_postcode.len(), - "Postcode population loaded" - ); + info!(postcodes = by_postcode.len(), "Postcode population loaded"); Ok(Self { by_postcode }) } diff --git a/server-rs/src/data/spill.rs b/server-rs/src/data/spill.rs index 5468d31..a655cda 100644 --- a/server-rs/src/data/spill.rs +++ b/server-rs/src/data/spill.rs @@ -152,7 +152,10 @@ pub struct SpillVecBuilder { } enum Builder { - Owned { values: Vec, len: usize }, + Owned { + values: Vec, + len: usize, + }, Mapped { map: MmapMut, len: usize, @@ -462,7 +465,9 @@ mod tests { #[test] fn builder_streams_identically_owned_and_mapped() { - let values: Vec = (0..50_000u32).map(|n| n.wrapping_mul(2_246_822_519)).collect(); + let values: Vec = (0..50_000u32) + .map(|n| n.wrapping_mul(2_246_822_519)) + .collect(); // Owned path (no spill dir): pushes accumulate into a heap Vec. let mut owned = SpillVecBuilder::::with_len(values.len(), None, "u32_owned").unwrap(); @@ -497,7 +502,8 @@ mod tests { let dir = TempDir::new("builder-spur"); let mut builder = - SpillVecBuilder::::with_len(keys.len(), Some(dir.path()), "spurs").unwrap(); + SpillVecBuilder::::with_len(keys.len(), Some(dir.path()), "spurs") + .unwrap(); for &k in &keys { builder.push(k); } @@ -536,7 +542,8 @@ mod tests { #[should_panic(expected = "overflow")] fn builder_overfill_panics() { let dir = TempDir::new("builder-overfill"); - let mut builder = SpillVecBuilder::::with_len(2, Some(dir.path()), "overfill").unwrap(); + let mut builder = + SpillVecBuilder::::with_len(2, Some(dir.path()), "overfill").unwrap(); builder.push(1); builder.push(2); builder.push(3); // one past the declared length diff --git a/server-rs/src/routes/crime_records.rs b/server-rs/src/routes/crime_records.rs index fd95cf7..3d698f3 100644 --- a/server-rs/src/routes/crime_records.rs +++ b/server-rs/src/routes/crime_records.rs @@ -99,7 +99,11 @@ pub async fn get_crime_records( .postcode_to_idx .get(&normalized) .ok_or_else(|| { - (StatusCode::NOT_FOUND, format!("Postcode not found: {normalized}")).into_response() + ( + StatusCode::NOT_FOUND, + format!("Postcode not found: {normalized}"), + ) + .into_response() })?; Selection::Postcode(normalized) } else { @@ -120,12 +124,9 @@ pub async fn get_crime_records( let mut h3_cache: FxHashMap = FxHashMap::default(); let mut seen: FxHashSet<&str> = FxHashSet::default(); let mut out: Vec = Vec::new(); - state.grid.for_each_in_bounds( - min_lat, - min_lon, - max_lat, - max_lon, - |row_idx| { + state + .grid + .for_each_in_bounds(min_lat, min_lon, max_lat, max_lon, |row_idx| { let row = row_idx as usize; if cell_for_row_cached( row, @@ -140,8 +141,7 @@ pub async fn get_crime_records( out.push(pc.to_string()); } } - }, - ); + }); out } }; @@ -177,6 +177,10 @@ pub async fn get_crime_records( .map_err(|error| (StatusCode::INTERNAL_SERVER_ERROR, error.to_string()).into_response())? .map_err(|error| (StatusCode::INTERNAL_SERVER_ERROR, error).into_response())?; - info!(total = result.total, returned = result.records.len(), "GET /api/crime-records"); + info!( + total = result.total, + returned = result.records.len(), + "GET /api/crime-records" + ); Ok(Json(result)) } diff --git a/server-rs/src/routes/stats.rs b/server-rs/src/routes/stats.rs index bf1d4cf..d1a210a 100644 --- a/server-rs/src/routes/stats.rs +++ b/server-rs/src/routes/stats.rs @@ -11,8 +11,8 @@ use crate::data::{FeatureStats, PostcodePoiMetrics, PropertyData}; use crate::utils::{postcode_outcode, postcode_sector}; use super::hexagon_stats::{ - CrimeAreaAverage, CrimeYearPoint, CrimeYearStats, EnumFeatureStats, - HistogramStats, NumericFeatureStats, PricePoint, + CrimeAreaAverage, CrimeYearPoint, CrimeYearStats, EnumFeatureStats, HistogramStats, + NumericFeatureStats, PricePoint, }; /// Extract price history (year, price) pairs from matching rows, downsampled if needed. @@ -398,7 +398,6 @@ pub fn compute_crime_by_year( out } - /// Latest year present anywhere in the by-year crime dataset. The client /// compares each selection's last charted year against this to caption /// force-level publication gaps (e.g. Greater Manchester ends mid-2019) as @@ -615,18 +614,12 @@ mod tests { assert_eq!(sector.as_deref(), Some("E14 2")); assert_eq!(out.len(), 2); - let burglary = out - .iter() - .find(|c| c.name == "Burglary (/yr, 7y)") - .unwrap(); + let burglary = out.iter().find(|c| c.name == "Burglary (/yr, 7y)").unwrap(); assert_eq!(burglary.national, Some(8.0)); assert_eq!(burglary.outcode, Some(10.0)); assert_eq!(burglary.sector, Some(5.0)); - let robbery = out - .iter() - .find(|c| c.name == "Robbery (/yr, 7y)") - .unwrap(); + let robbery = out.iter().find(|c| c.name == "Robbery (/yr, 7y)").unwrap(); assert_eq!(robbery.national, Some(6.0)); // The outcode value was NaN — dropped to None; the sector value is finite. assert_eq!(robbery.outcode, None); @@ -637,9 +630,7 @@ mod tests { fn area_crime_averages_respect_fields_filter() { let avgs = sample_averages(); // Area averages are keyed by the full crime-feature name. - let fields: HashSet = ["Burglary (/yr, 7y)".to_string()] - .into_iter() - .collect(); + let fields: HashSet = ["Burglary (/yr, 7y)".to_string()].into_iter().collect(); let (_, _, out) = area_crime_averages_for(Some("E14 2DG"), &avgs, true, &fields); assert_eq!(out.len(), 1); assert_eq!(out[0].name, "Burglary (/yr, 7y)");