├── fe ├── .eslintignore ├── src │ ├── lib │ │ ├── config │ │ │ ├── time.js │ │ │ ├── text.js │ │ │ ├── colors.js │ │ │ └── map.js │ │ ├── components │ │ │ ├── mdsvex │ │ │ │ ├── h5.svelte │ │ │ │ ├── p.svelte │ │ │ │ ├── h1.svelte │ │ │ │ ├── ol.svelte │ │ │ │ ├── ul.svelte │ │ │ │ ├── h3.svelte │ │ │ │ ├── h4.svelte │ │ │ │ ├── td.svelte │ │ │ │ ├── h2.svelte │ │ │ │ ├── th.svelte │ │ │ │ ├── table.svelte │ │ │ │ ├── blockquote.svelte │ │ │ │ ├── code.svelte │ │ │ │ ├── a.svelte │ │ │ │ └── _layout.svelte │ │ │ ├── svizzle │ │ │ │ ├── ui │ │ │ │ │ ├── handlers.js │ │ │ │ │ ├── glyphs │ │ │ │ │ │ └── Legend.svelte │ │ │ │ │ ├── actions │ │ │ │ │ │ └── scrollIntoView.js │ │ │ │ │ ├── geometryObserver.js │ │ │ │ │ └── ScrollIntoView.svelte │ │ │ │ ├── SizeSensor.svelte │ │ │ │ ├── GridRows.svelte │ │ │ │ ├── GridColumns.svelte │ │ │ │ └── legend │ │ │ │ │ └── KeysLegend.svelte │ │ │ ├── explorer │ │ │ │ ├── MetricTitle.svelte │ │ │ │ ├── SelectorInterval.svelte │ │ │ │ ├── SelectorRegionType.svelte │ │ │ │ ├── NoData.svelte │ │ │ │ ├── FlexBar.svelte │ │ │ │ ├── FilterPaneBorder.svelte │ │ │ │ ├── medium │ │ │ │ │ ├── unused │ │ │ │ │ │ ├── ScrollableGrid │ │ │ │ │ │ │ └── ColumnNames.svelte │ │ │ │ │ │ └── LabelsGrid.svelte │ │ │ │ │ └── ViewSelectorMedium.svelte │ │ │ │ ├── Bullet.svelte │ │ │ │ ├── Checkboxed.svelte │ │ │ │ ├── small │ │ │ │ │ ├── InfoSmall.svelte │ │ │ │ │ └── IconBar.svelte │ │ │ │ ├── DismissOrApply.svelte │ │ │ │ ├── SelectionXor.svelte │ │ │ │ └── MetricSelector.svelte │ │ │ └── layout │ │ │ │ ├── Nav.svelte │ │ │ │ └── medium │ │ │ │ └── ExplorerMedium.svelte │ │ ├── utils │ │ │ ├── version.js │ │ │ ├── date.js │ │ │ ├── theme.js │ │ │ ├── color.js │ │ │ ├── unescape-inlineCode.js │ │ │ ├── svizzle │ │ │ │ ├── url.js │ │ │ │ ├── utils.js │ │ │ │ └── style.js │ │ │ ├── download.js │ │ │ └── getters.js │ │ ├── _content │ │ │ ├── metrics │ │ │ │ ├── installations.svx │ │ │ │ ├── installers.svx │ │ │ │ ├── installations_per_installer.svx │ │ │ │ ├── installers_certified.svx │ │ │ │ ├── property_feature_number_habitable_rooms.svx │ │ │ │ ├── installers_dropped_certifications.svx │ │ │ │ ├── property_feature_total_floor_area.svx │ │ │ │ ├── installers_new_certifications.svx │ │ │ │ ├── property_feature_type.svx │ │ │ │ ├── hp_feature_scop.svx │ │ │ │ ├── hp_id_model.svx │ │ │ │ ├── installation_cost.svx │ │ │ │ ├── hp_id_brand.svx │ │ │ │ ├── hp_feature_power_capacity.svx │ │ │ │ ├── hp_feature_power_generation.svx │ │ │ │ ├── hp_feature_flow_temperature.svx │ │ │ │ ├── installation_cost_sum.svx │ │ │ │ ├── hp_feature_power_capacity_sum.svx │ │ │ │ ├── property_tenure.svx │ │ │ │ ├── hp_feature_power_generation_sum.svx │ │ │ │ ├── property_feature_glazed_type.svx │ │ │ │ ├── property_supply_mains_gas_flag.svx │ │ │ │ ├── property_energy_rating_current.svx │ │ │ │ ├── property_supply_photovoltaic.svx │ │ │ │ ├── property_energy_rating_potential.svx │ │ │ │ ├── property_feature_built_form.svx │ │ │ │ ├── hp_feature_design.svx │ │ │ │ ├── property_feature_glazed_area.svx │ │ │ │ ├── property_feature_age_band.svx │ │ │ │ ├── property_energy_efficiency_floor.svx │ │ │ │ ├── property_energy_efficiency_roof.svx │ │ │ │ ├── property_energy_efficiency_walls.svx │ │ │ │ ├── property_energy_efficiency_lighting.svx │ │ │ │ ├── property_energy_efficiency_windows.svx │ │ │ │ ├── property_energy_efficiency_hot_water.svx │ │ │ │ └── property_energy_efficiency_main_heat.svx │ │ │ ├── Index.svx │ │ │ ├── info │ │ │ │ ├── Privacy.svx │ │ │ │ ├── PrivacyBanner.svx │ │ │ │ └── Disclaimer.svx │ │ │ ├── guides │ │ │ │ ├── A11ymenuIntro.svx │ │ │ │ ├── AppSmall.svx │ │ │ │ └── AppMedium.svx │ │ │ ├── methodology │ │ │ │ └── Geography.svx │ │ │ └── Accessibility.svx │ │ ├── statechart │ │ │ ├── actions │ │ │ │ ├── index.js │ │ │ │ └── staticData.js │ │ │ ├── utils.js │ │ │ ├── context.js │ │ │ ├── index.js │ │ │ ├── guards.js │ │ │ └── actors.js │ │ ├── stores │ │ │ ├── data.js │ │ │ ├── tooltip.js │ │ │ ├── geometry.js │ │ │ ├── layout.js │ │ │ ├── regions.js │ │ │ └── navigation.js │ │ ├── env.js │ │ └── data │ │ │ └── regions.js │ ├── routes │ │ ├── guides │ │ │ ├── +page.js │ │ │ ├── a11ymenu │ │ │ │ └── +page.svelte │ │ │ └── app │ │ │ │ └── +page.svelte │ │ ├── info │ │ │ ├── +page.js │ │ │ ├── privacy │ │ │ │ └── +page.svelte │ │ │ └── disclaimer │ │ │ │ └── +page.svelte │ │ ├── feedback │ │ │ ├── +page.js │ │ │ ├── survey │ │ │ │ └── +page.svelte │ │ │ └── survey2 │ │ │ │ └── +page.svelte │ │ ├── methodology │ │ │ ├── +page.js │ │ │ ├── geography │ │ │ │ └── +page.svelte │ │ │ └── dataProcessing │ │ │ │ └── +page.svelte │ │ ├── explorer │ │ │ ├── +page.js │ │ │ ├── count │ │ │ │ ├── +page.js │ │ │ │ └── geo │ │ │ │ │ └── [slug] │ │ │ │ │ └── +page.svelte │ │ │ ├── number │ │ │ │ ├── +page.js │ │ │ │ └── geo │ │ │ │ │ └── [slug] │ │ │ │ │ └── +page.svelte │ │ │ ├── string │ │ │ │ ├── +page.js │ │ │ │ └── geo │ │ │ │ │ └── [slug] │ │ │ │ │ └── +page.svelte │ │ │ ├── category │ │ │ │ ├── +page.js │ │ │ │ └── geo │ │ │ │ │ └── [slug] │ │ │ │ │ └── +page.svelte │ │ │ └── +layout.svelte │ │ ├── +page.svelte │ │ └── +error.svelte │ ├── app.html │ └── bin │ │ └── regions │ │ └── README.md ├── .gitignore ├── static │ ├── favicon.png │ ├── logo-192.png │ ├── logo-512.png │ ├── font │ │ ├── OpenDyslexic │ │ │ ├── Bold.otf │ │ │ ├── Italic.otf │ │ │ ├── Regular.otf │ │ │ └── BoldItalic.otf │ │ ├── AvenirNext │ │ │ └── Variable.ttf │ │ ├── NobotoFlex │ │ │ └── Variable.woff2 │ │ └── Archivo │ │ │ ├── VariableFont_wdth,wght.ttf │ │ │ └── Italic-VariableFont_wdth,wght.ttf │ ├── manifest.json │ ├── logos │ │ ├── Nesta-dark.svg │ │ └── Nesta-light.svg │ └── audits │ │ └── pa11y │ │ ├── Home_themeDark.html │ │ ├── Home_themeLight.html │ │ ├── Guides_themeDark.html │ │ └── Guides_themeLight.html ├── vite.config.js ├── netlify.toml ├── jsconfig.json └── svelte.config.js ├── .npmrc ├── netlify.toml ├── shared ├── index.js └── package.json ├── .dockerignore ├── .gitignore ├── README.md ├── be ├── src │ ├── bin │ │ ├── uploadTiles.sh │ │ ├── generateMbTiles.sh │ │ ├── saveNuts0.js │ │ ├── updateRouteTestData.js │ │ ├── ingest.sh │ │ └── ingestServerSide.sh │ ├── schemas │ │ ├── cardinality.js │ │ ├── certified.js │ │ ├── date_histogram1_certified2.js │ │ ├── stats.js │ │ ├── date_histogram.js │ │ ├── histogram.js │ │ ├── terms1_certified2.js │ │ ├── date_histogram1_cardinality2.js │ │ ├── date_histogram1_histogram2.js │ │ ├── date_histogram1_stats2.js │ │ ├── terms1_histogram2.js │ │ ├── terms.js │ │ ├── terms1_stats2.js │ │ ├── terms1_cardinality2.js │ │ ├── date_histogram1_terms2.js │ │ ├── index.js │ │ └── terms1_terms2.js │ ├── routes │ │ ├── count.js │ │ ├── cardinality.js │ │ ├── stats.js │ │ ├── date_histogram.js │ │ ├── histogram.js │ │ ├── date_histogram1_cardinality2.js │ │ ├── terms1_histogram2.js │ │ ├── date_histogram1_histogram2.js │ │ ├── index.js │ │ ├── terms1_stats2.js │ │ ├── terms.js │ │ ├── date_histogram1_stats2.js │ │ ├── terms1_cardinality2.js │ │ ├── date_histogram1_terms2.js │ │ ├── terms1_terms2.js │ │ └── certified.js │ ├── server.js │ ├── app.js │ ├── conf.js │ ├── filter.js │ ├── util.js │ ├── es.js │ ├── utils │ │ └── certifiedLogic.js │ └── routes.js ├── test │ ├── utils.js │ ├── routes │ │ ├── api │ │ │ ├── count │ │ │ │ └── 01.json │ │ │ ├── certified │ │ │ │ ├── 01.json │ │ │ │ ├── 02.json │ │ │ │ ├── 03.json │ │ │ │ ├── 05.json │ │ │ │ ├── 04.json │ │ │ │ └── 06.json │ │ │ ├── cardinality │ │ │ │ ├── 01.json │ │ │ │ └── 02.json │ │ │ ├── stats │ │ │ │ ├── 01.json │ │ │ │ └── 02.json │ │ │ ├── terms │ │ │ │ ├── 03.json │ │ │ │ ├── 01.json │ │ │ │ ├── 02.json │ │ │ │ ├── 05.json │ │ │ │ └── 04.json │ │ │ ├── terms1_certified2 │ │ │ │ ├── 01.json │ │ │ │ ├── 04.json │ │ │ │ ├── 05.json │ │ │ │ ├── 02.json │ │ │ │ └── 03.json │ │ │ ├── terms1_cardinality2 │ │ │ │ └── 05.json │ │ │ ├── histogram │ │ │ │ └── 01.json │ │ │ ├── terms1_terms2 │ │ │ │ └── 03.json │ │ │ └── terms1_stats2 │ │ │ │ └── 01.json │ │ └── routes.test.js │ └── filter │ │ ├── requests │ │ ├── 01.json │ │ ├── 03.json │ │ ├── 06.json │ │ ├── 02.json │ │ ├── 05.json │ │ ├── 04.json │ │ └── 07.json │ │ └── filter.test.js ├── es │ └── copy_pipeline.conf ├── githooks │ ├── post-receive │ └── README.md ├── tiles │ ├── config.json │ └── README.md └── package.json ├── Dockerfile ├── compose.yaml ├── appTest ├── src │ ├── config.js │ └── pa11y │ │ └── validate.js ├── package.json └── README.md ├── package.json └── LICENSE /fe/.eslintignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | base = "fe" 3 | -------------------------------------------------------------------------------- /fe/src/lib/config/time.js: -------------------------------------------------------------------------------- 1 | export const intervals = ['1M', '1q', '1y']; 2 | -------------------------------------------------------------------------------- /fe/.gitignore: -------------------------------------------------------------------------------- 1 | /.svelte-kit 2 | /.netlify 3 | /test/browserstack/.config.mjs 4 | -------------------------------------------------------------------------------- /fe/src/lib/components/mdsvex/h5.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /fe/src/lib/utils/version.js: -------------------------------------------------------------------------------- 1 | export {version} from '../../../../package.json'; 2 | -------------------------------------------------------------------------------- /shared/index.js: -------------------------------------------------------------------------------- 1 | export * from './counts.js'; 2 | export * from './fields.js'; 3 | -------------------------------------------------------------------------------- /fe/src/lib/config/text.js: -------------------------------------------------------------------------------- 1 | export const noDataMessage = 'No results for the current selection'; 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | **/test 3 | be/tiles 4 | be/es 5 | fe 6 | mapbox -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .git 3 | node_modules 4 | be/**/*.geojson 5 | be/**/*.mbtiles 6 | be/**/*.pmtiles 7 | _ 8 | -------------------------------------------------------------------------------- /fe/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindrones/nestauk-asf_hp_market_tracker/dev/fe/static/favicon.png -------------------------------------------------------------------------------- /fe/static/logo-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindrones/nestauk-asf_hp_market_tracker/dev/fe/static/logo-192.png -------------------------------------------------------------------------------- /fe/static/logo-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindrones/nestauk-asf_hp_market_tracker/dev/fe/static/logo-512.png -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/installations.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The number of heat pump installations. 4 | -------------------------------------------------------------------------------- /fe/src/lib/_content/Index.svx: -------------------------------------------------------------------------------- 1 | 4 | 5 | # {toolName} 6 | 7 | TODO 8 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/installers.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The total number of installers that installed a heat pump. 4 | -------------------------------------------------------------------------------- /fe/src/lib/statechart/actions/index.js: -------------------------------------------------------------------------------- 1 | export * from './navigation.js'; 2 | export * from './staticData.js'; 3 | export * from './view.js'; 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nesta Heat Pump Market Tracker 2 | 3 | The Nesta Heat Pump Market Tracker is a web app to track heat pump installations in the UK. 4 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/installations_per_installer.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The number of installations per active installer. 4 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/installers_certified.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The total number of installers with a valid certification. 4 | -------------------------------------------------------------------------------- /fe/static/font/OpenDyslexic/Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindrones/nestauk-asf_hp_market_tracker/dev/fe/static/font/OpenDyslexic/Bold.otf -------------------------------------------------------------------------------- /fe/src/lib/statechart/utils.js: -------------------------------------------------------------------------------- 1 | import * as _ from 'lamb'; 2 | 3 | export const isViewReady = _.hasPathValue('PageInteractive.ViewData', 'Ready'); 4 | -------------------------------------------------------------------------------- /fe/static/font/AvenirNext/Variable.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindrones/nestauk-asf_hp_market_tracker/dev/fe/static/font/AvenirNext/Variable.ttf -------------------------------------------------------------------------------- /fe/static/font/OpenDyslexic/Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindrones/nestauk-asf_hp_market_tracker/dev/fe/static/font/OpenDyslexic/Italic.otf -------------------------------------------------------------------------------- /fe/static/font/OpenDyslexic/Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindrones/nestauk-asf_hp_market_tracker/dev/fe/static/font/OpenDyslexic/Regular.otf -------------------------------------------------------------------------------- /fe/src/routes/guides/+page.js: -------------------------------------------------------------------------------- 1 | import {redirect} from '@sveltejs/kit'; 2 | 3 | export function load () { 4 | throw redirect(301, '/guides/app'); 5 | } 6 | -------------------------------------------------------------------------------- /fe/src/routes/info/+page.js: -------------------------------------------------------------------------------- 1 | import {redirect} from '@sveltejs/kit'; 2 | 3 | export function load () { 4 | throw redirect(301, '/info/privacy'); 5 | } 6 | -------------------------------------------------------------------------------- /fe/static/font/NobotoFlex/Variable.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindrones/nestauk-asf_hp_market_tracker/dev/fe/static/font/NobotoFlex/Variable.woff2 -------------------------------------------------------------------------------- /fe/static/font/OpenDyslexic/BoldItalic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindrones/nestauk-asf_hp_market_tracker/dev/fe/static/font/OpenDyslexic/BoldItalic.otf -------------------------------------------------------------------------------- /shared/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "App shared modules", 3 | "main": "index.js", 4 | "name": "nesta_hpmt_shared", 5 | "type": "module" 6 | } 7 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_feature_number_habitable_rooms.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The total number of habitable rooms in the property. 4 | -------------------------------------------------------------------------------- /fe/src/lib/components/mdsvex/p.svelte: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | 10 | -------------------------------------------------------------------------------- /fe/src/routes/feedback/+page.js: -------------------------------------------------------------------------------- 1 | import {redirect} from '@sveltejs/kit'; 2 | 3 | export function load () { 4 | throw redirect(301, '/feedback/survey'); 5 | } 6 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/installers_dropped_certifications.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The total number of installers whose certifications have expired. 4 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_feature_total_floor_area.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The total floor area of the property, measured in square meters. 4 | -------------------------------------------------------------------------------- /fe/src/lib/components/mdsvex/h1.svelte: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | 10 | -------------------------------------------------------------------------------- /fe/src/lib/stores/data.js: -------------------------------------------------------------------------------- 1 | import {writable} from 'svelte/store'; 2 | 3 | export const _viewCache = writable({}); 4 | 5 | export const _staticData = writable(); 6 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/installers_new_certifications.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The total number of new or renewed certifications obtained by installers. 4 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_feature_type.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The number of installations by property type (e.g. bungalow, flat, house, etc). 4 | -------------------------------------------------------------------------------- /fe/static/font/Archivo/VariableFont_wdth,wght.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindrones/nestauk-asf_hp_market_tracker/dev/fe/static/font/Archivo/VariableFont_wdth,wght.ttf -------------------------------------------------------------------------------- /be/src/bin/uploadTiles.sh: -------------------------------------------------------------------------------- 1 | name="nuts21_0_country21_itl21_1_itl21_2_itl21_3_lad21_msoa11_lsoa11" 2 | pmtiles upload --bucket=s3://dap-protomaps tiles/$name.pmtiles $name.pmtiles -------------------------------------------------------------------------------- /fe/src/lib/components/mdsvex/ol.svelte: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
4 | 5 | 10 | -------------------------------------------------------------------------------- /fe/src/lib/components/mdsvex/ul.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /fe/src/routes/methodology/+page.js: -------------------------------------------------------------------------------- 1 | import {redirect} from '@sveltejs/kit'; 2 | 3 | export function load () { 4 | throw redirect(301, '/methodology/dataProcessing'); 5 | } 6 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/hp_feature_scop.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | SCOP values. 4 | 5 | #### SCOP 6 | 7 | Manufacturer-provided Seasonal Coefficient of Performance. 8 | -------------------------------------------------------------------------------- /fe/src/lib/_content/info/Privacy.svx: -------------------------------------------------------------------------------- 1 | 4 | 5 | ## Cookies and data privacy policy 6 | 7 | 8 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/hp_id_model.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The number of installations by heat pump model. 4 | 5 | #### Model 6 | 7 | The heat pump product name. 8 | -------------------------------------------------------------------------------- /fe/static/font/Archivo/Italic-VariableFont_wdth,wght.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mindrones/nestauk-asf_hp_market_tracker/dev/fe/static/font/Archivo/Italic-VariableFont_wdth,wght.ttf -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/installation_cost.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | Installation cost (in GBP). 4 | 5 | #### Cost 6 | 7 | The cost of installation of a heat pump (in GBP). 8 | -------------------------------------------------------------------------------- /fe/src/lib/stores/tooltip.js: -------------------------------------------------------------------------------- 1 | import {writable} from 'svelte/store'; 2 | 3 | export const _tooltip = writable(); 4 | 5 | export const clearTooltip = () => { 6 | _tooltip.set(null); 7 | } 8 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/hp_id_brand.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The number of installations by heat pump brand. 4 | 5 | #### Brand 6 | 7 | Brand of the manufacturer of heat pumps. 8 | -------------------------------------------------------------------------------- /fe/src/lib/components/mdsvex/h3.svelte: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | 11 | -------------------------------------------------------------------------------- /fe/src/lib/components/mdsvex/h4.svelte: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | 11 | -------------------------------------------------------------------------------- /fe/src/lib/components/svizzle/ui/handlers.js: -------------------------------------------------------------------------------- 1 | export const makeOnKeyDown = handlerFn => event => { 2 | if (event.key === 'Enter') { 3 | event.preventDefault(); 4 | handlerFn(event); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /fe/src/lib/components/mdsvex/td.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/hp_feature_power_capacity.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | Power capacity values (in kW). 4 | 5 | #### Power capacity 6 | 7 | Total installed capacity of the heat pump (in kW). 8 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM --platform=linux/amd64 node:18-alpine 2 | WORKDIR /app 3 | COPY . . 4 | RUN npm install 5 | WORKDIR be 6 | RUN npm install 7 | ENV HOST=0.0.0.0 PORT=3000 8 | CMD ["npm", "run", "dev"] 9 | EXPOSE 3000 -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/hp_feature_power_generation.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | Energy values (in kWh). 4 | 5 | #### Power generation 6 | 7 | Estimated energy produced by the heat pump in a year (in kWh). 8 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/hp_feature_flow_temperature.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | Flow temperature values (in °C). 4 | 5 | #### Flow temperature 6 | 7 | The flow temperature at which the heat pump is set (in °C). 8 | -------------------------------------------------------------------------------- /fe/src/lib/components/mdsvex/h2.svelte: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | 12 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/installation_cost_sum.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | Heat pumps market value (in GBP). 4 | 5 | #### Market value 6 | 7 | The sum of the installation cost of all selected heat pumps (in GBP). 8 | -------------------------------------------------------------------------------- /fe/src/lib/components/mdsvex/th.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | -------------------------------------------------------------------------------- /fe/src/lib/config/colors.js: -------------------------------------------------------------------------------- 1 | import {interpolateHclLong} from 'd3-interpolate'; 2 | 3 | export const interpolateColor = interpolateHclLong( 4 | 'rgb(189,113,189)', // brighter purple 5 | 'rgb(255,209,124)' // brighter orange 6 | ); 7 | -------------------------------------------------------------------------------- /compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | app: 3 | image: hpmt:latest 4 | command: npm run dev 5 | ports: 6 | - "3000:3000" 7 | environment: 8 | - ELASTICSEARCH_PASSWORD 9 | volumes: 10 | - .be/src:/app/be/src -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/hp_feature_power_capacity_sum.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | Power capacity values (in kW). 4 | 5 | #### Total power capacity 6 | 7 | The sum of the power capacity for all selected heat pumps (in kW). 8 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_tenure.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The number of installations by tenure. 4 | 5 | #### Tenure 6 | 7 | The type of legal rights (tenure) the occupant has over the property (e.g. ownership, rental). 8 | -------------------------------------------------------------------------------- /appTest/src/config.js: -------------------------------------------------------------------------------- 1 | /* testing */ 2 | 3 | export const urlBases = { 4 | development: 'http://localhost:4173', 5 | preview: 'https://skeleton.netlify.app', // FIXME update 6 | production: 'https://hpmt-prod.temp-domain', // TODO netlify 7 | }; 8 | -------------------------------------------------------------------------------- /fe/src/lib/components/mdsvex/table.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 | 11 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/hp_feature_power_generation_sum.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | Energy values (in kWh). 4 | 5 | #### Total power generation 6 | 7 | The sum of the estimated energy produced in a year by all selected heat pumps (in kWh). 8 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_feature_glazed_type.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The number of installations by glazed type. 4 | 5 | #### Glazed type 6 | 7 | The type of glazing used in the property (double-glazing, triple-glazing, etc.). 8 | -------------------------------------------------------------------------------- /fe/src/lib/utils/date.js: -------------------------------------------------------------------------------- 1 | import * as _ from 'lamb'; 2 | 3 | export const formatDateY2 = 4 | date => date.getFullYear().toString().slice(2); 5 | 6 | export const formatDateY4M2 = 7 | date => `${date.getFullYear()}-${_.padLeft(1 + date.getMonth(), 0, 2)}`; 8 | -------------------------------------------------------------------------------- /fe/src/lib/utils/theme.js: -------------------------------------------------------------------------------- 1 | export const makeSegmentToCssVar = 2 | (themeVars, activeSegmentCssVar, inactiveSegmentCssVar) => 3 | (segment, string) => 4 | segment === string 5 | ? themeVars[activeSegmentCssVar] 6 | : themeVars[inactiveSegmentCssVar]; 7 | -------------------------------------------------------------------------------- /be/test/utils.js: -------------------------------------------------------------------------------- 1 | import { buildServer } from '../src/app.js'; 2 | 3 | export const buildTestServer = () => buildServer({ 4 | disableRequestLogging: true, 5 | logger: { 6 | level: 'info', 7 | transport: { 8 | target: 'pino-pretty' 9 | } 10 | } 11 | }); 12 | -------------------------------------------------------------------------------- /be/src/schemas/cardinality.js: -------------------------------------------------------------------------------- 1 | export const schema = { 2 | schema: { 3 | querystring: { 4 | type: 'object', 5 | required: ['field'], 6 | properties: { 7 | field: { type: 'string' }, 8 | missing: { type: 'string' }, 9 | } 10 | } 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_supply_mains_gas_flag.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The number of installations by presence of heating mains gas. 4 | 5 | #### Heating mains gas? 6 | 7 | Whether the property has a mains gas supply: 8 | - Y: Yes 9 | - N: No 10 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_energy_rating_current.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The number of installations by current energy rating. 4 | 5 | #### Current energy rating 6 | 7 | The current energy rating of the property. 8 | 9 | One of: A, B, C, D, E, F, G. 10 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_supply_photovoltaic.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The photovoltaic supply value. 4 | 5 | #### Photovoltaic supply 6 | 7 | The photovoltaic area as a percentage of total roof area: 0% indicates that a Photovoltaic Supply is not present in the property. 8 | -------------------------------------------------------------------------------- /fe/vite.config.js: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | 3 | const config = { 4 | plugins: [sveltekit()], 5 | server: { 6 | fs: { 7 | // Allow serving files from one level up to the project root 8 | allow: ['..'] 9 | } 10 | } 11 | }; 12 | 13 | export default config; 14 | -------------------------------------------------------------------------------- /be/src/schemas/certified.js: -------------------------------------------------------------------------------- 1 | export const schema = { 2 | schema: { 3 | querystring: { 4 | type: 'object', 5 | properties: { 6 | logic: { 7 | default: 'overlaps', 8 | type: 'string', 9 | enum: ['overlaps', 'engulfs', 'dropped', 'new'] 10 | }, 11 | } 12 | } 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /be/src/schemas/date_histogram1_certified2.js: -------------------------------------------------------------------------------- 1 | export const schema = { 2 | schema: { 3 | querystring: { 4 | type: 'object', 5 | properties: { 6 | calendar_interval1: { 7 | default: '1y', 8 | type: 'string', 9 | enum: ['1M', '1q', '1y'] 10 | }, 11 | } 12 | } 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /fe/src/lib/components/svizzle/ui/glyphs/Legend.svelte: -------------------------------------------------------------------------------- 1 | 2 | 7 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /fe/src/routes/explorer/+page.js: -------------------------------------------------------------------------------- 1 | import {redirect} from '@sveltejs/kit'; 2 | import {get} from 'svelte/store'; 3 | 4 | import {_expectedRoute} from '$lib/stores/navigation.js'; 5 | 6 | export function load () { 7 | const expectedRoute = get(_expectedRoute); 8 | throw redirect(301, expectedRoute); 9 | } 10 | -------------------------------------------------------------------------------- /fe/src/routes/explorer/count/+page.js: -------------------------------------------------------------------------------- 1 | import {redirect} from '@sveltejs/kit'; 2 | import {get} from 'svelte/store'; 3 | 4 | import {_expectedRoute} from '$lib/stores/navigation.js'; 5 | 6 | export function load () { 7 | const expectedRoute = get(_expectedRoute); 8 | throw redirect(301, expectedRoute); 9 | } 10 | -------------------------------------------------------------------------------- /fe/src/routes/explorer/number/+page.js: -------------------------------------------------------------------------------- 1 | import {redirect} from '@sveltejs/kit'; 2 | import {get} from 'svelte/store'; 3 | 4 | import {_expectedRoute} from '$lib/stores/navigation.js'; 5 | 6 | export function load () { 7 | const expectedRoute = get(_expectedRoute); 8 | throw redirect(301, expectedRoute); 9 | } 10 | -------------------------------------------------------------------------------- /fe/src/routes/explorer/string/+page.js: -------------------------------------------------------------------------------- 1 | import {redirect} from '@sveltejs/kit'; 2 | import {get} from 'svelte/store'; 3 | 4 | import {_expectedRoute} from '$lib/stores/navigation.js'; 5 | 6 | export function load () { 7 | const expectedRoute = get(_expectedRoute); 8 | throw redirect(301, expectedRoute); 9 | } 10 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_energy_rating_potential.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The number of installations by potential energy rating. 4 | 5 | #### Potential energy rating 6 | 7 | The potential energy rating that the property could achieve with improvements. 8 | 9 | One of: A, B, C, D, E, F, G. 10 | -------------------------------------------------------------------------------- /fe/src/lib/components/mdsvex/blockquote.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 12 | -------------------------------------------------------------------------------- /fe/src/routes/explorer/category/+page.js: -------------------------------------------------------------------------------- 1 | import {redirect} from '@sveltejs/kit'; 2 | import {get} from 'svelte/store'; 3 | 4 | import {_expectedRoute} from '$lib/stores/navigation.js'; 5 | 6 | export function load () { 7 | const expectedRoute = get(_expectedRoute); 8 | throw redirect(301, expectedRoute); 9 | } 10 | -------------------------------------------------------------------------------- /be/src/schemas/stats.js: -------------------------------------------------------------------------------- 1 | 2 | export const schema = { 3 | schema: { 4 | querystring: { 5 | type: 'object', 6 | required: ['field'], 7 | properties: { 8 | field: { type: 'string' }, 9 | use_extended_stats: { 10 | type: 'boolean', 11 | default: false 12 | } 13 | } 14 | } 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /fe/src/lib/components/explorer/MetricTitle.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |

{$_currentMetricTitle}

6 | 7 | 15 | -------------------------------------------------------------------------------- /be/src/routes/count.js: -------------------------------------------------------------------------------- 1 | import { index } from '../conf.js'; 2 | import { getXCompatibleCount } from '../es.js'; 3 | 4 | export const getCount = async (request, reply) => { 5 | 6 | const body = { 7 | ...request.filter, 8 | }; 9 | const result = await getXCompatibleCount({ body, index }); 10 | 11 | reply.send(result); 12 | }; 13 | -------------------------------------------------------------------------------- /fe/src/lib/components/explorer/SelectorInterval.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | -------------------------------------------------------------------------------- /fe/src/lib/components/mdsvex/code.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | -------------------------------------------------------------------------------- /be/src/schemas/date_histogram.js: -------------------------------------------------------------------------------- 1 | export const schema = { 2 | schema: { 3 | querystring: { 4 | type: 'object', 5 | required: ['field'], 6 | properties: { 7 | calendar_interval: { 8 | default: '1y', 9 | type: 'string', 10 | enum: ['1M', '1q', '1y'] 11 | }, 12 | field: { type: 'string' }, 13 | } 14 | } 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_feature_built_form.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The number of installations by property built form. 4 | 5 | #### Built form 6 | 7 | The building type of the Property e.g. Detached, Semi-Detached, Terrace etc. 8 | 9 | Together with the Property Type, the Build Form produces a structured description of the property. 10 | -------------------------------------------------------------------------------- /fe/src/routes/info/privacy/+page.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | Privacy - {toolName} 8 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /be/src/bin/generateMbTiles.sh: -------------------------------------------------------------------------------- 1 | cd tiles 2 | for file in `ls geojson`; do 3 | echo $file 4 | name=${file%.geojson} 5 | tippecanoe -o mbtiles/$name.mbtiles -z14 geojson/$file --force 6 | done 7 | 8 | name=nuts21_0_country21_itl21_1_itl21_2_itl21_3_lad21_msoa11_lsoa11 9 | 10 | tile-join -o $name.mbtiles mbtiles/* --force -pk 11 | pmtiles convert $name.mbtiles $name.pmtiles -------------------------------------------------------------------------------- /fe/src/lib/utils/color.js: -------------------------------------------------------------------------------- 1 | import * as _ from 'lamb'; 2 | 3 | import {interpolateColor} from '$lib/config/colors.js'; 4 | 5 | export const getItemsColorScheme = items => { 6 | const range = items.length === 1 7 | ? [0] 8 | : _.range(0, 1, 1 / (items.length - 1)).concat(1); 9 | const colorScheme = _.map(range, interpolateColor); 10 | 11 | return colorScheme; 12 | } 13 | -------------------------------------------------------------------------------- /fe/src/routes/info/disclaimer/+page.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | Disclaimer - {toolName} 9 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/hp_feature_design.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The number of installations by heat pump design. 4 | 5 | #### Design 6 | 7 | What the heat pump has been designed and installed to provide. 8 | 9 | This can be: 10 | - Domestic Hot Water (here abbreviated as `DHW`) 11 | - Space Heat 12 | - Another purpose 13 | - a combination of the above purposes 14 | -------------------------------------------------------------------------------- /be/src/server.js: -------------------------------------------------------------------------------- 1 | import { buildServer } from './app.js'; 2 | 3 | const { HOST='localhost' } = process.env; 4 | 5 | const start = async () => { 6 | const server = await buildServer({ logger: true }); 7 | 8 | try { 9 | await server.listen({ host: HOST, port: 3000 }); 10 | } catch (err) { 11 | server.log.error(err); 12 | throw new Error(err); 13 | } 14 | }; 15 | 16 | start(); 17 | -------------------------------------------------------------------------------- /fe/src/lib/_content/guides/A11ymenuIntro.svx: -------------------------------------------------------------------------------- 1 | ### Toggling the accessibility menu 2 | 3 | Clicking the accessibility icon should: 4 | * open the menu if it was closed, 5 | * close it if it was open. 6 | 7 | When the menu is open, it should appear at the centre of the screen slightly 8 | toward the bottom. 9 | 10 | To know how to use it, please check [this guide](/guides/a11ymenu). 11 | -------------------------------------------------------------------------------- /fe/src/lib/components/svizzle/ui/actions/scrollIntoView.js: -------------------------------------------------------------------------------- 1 | import {tick} from 'svelte'; 2 | 3 | export const scrollIntoViewIfTrue = async (node, doScroll) => { 4 | await tick(); 5 | 6 | if (node && doScroll) { 7 | if (node.scrollIntoViewIfNeeded) { 8 | node.scrollIntoViewIfNeeded(true); // Chrome/Safari/Edge 9 | } else { 10 | node.scrollIntoView(true); // FF 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /fe/src/routes/guides/a11ymenu/+page.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | Accessibility menu guide - {toolName} 9 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /be/src/schemas/histogram.js: -------------------------------------------------------------------------------- 1 | import { maxBins } from '../conf.js'; 2 | 3 | export const schema = { 4 | schema: { 5 | querystring: { 6 | type: 'object', 7 | required: ['field'], 8 | properties: { 9 | bins: { 10 | default: 10, 11 | type: 'integer', 12 | minimum: 1, 13 | maximum: maxBins 14 | }, 15 | field: { type: 'string' }, 16 | } 17 | } 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /be/src/schemas/terms1_certified2.js: -------------------------------------------------------------------------------- 1 | export const schema = { 2 | schema: { 3 | querystring: { 4 | type: 'object', 5 | required: ['field1'], 6 | properties: { 7 | field1: { 8 | type: 'string' 9 | }, 10 | logic2: { 11 | default: 'overlaps', 12 | type: 'string', 13 | enum: ['overlaps', 'engulfs', 'new', 'dropped'] 14 | } 15 | } 16 | } 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /fe/src/lib/components/mdsvex/a.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 18 | -------------------------------------------------------------------------------- /appTest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Nesta HPMT frontend tests", 3 | "devDependencies": { 4 | "lighthouse": "^11.1.0", 5 | "pa11y": "^6.2.3", 6 | "pa11y-reporter-html": "^2.0.0" 7 | }, 8 | "license": "MIT", 9 | "name": "nesta_hpmt_frontend_tests", 10 | "scripts": { 11 | "lighthouse": "node src/lighthouse/validate.js", 12 | "pa11y": "node src/pa11y/validate.js" 13 | }, 14 | "type": "module" 15 | } 16 | -------------------------------------------------------------------------------- /fe/src/routes/methodology/geography/+page.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | Methodology - {toolName} 9 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_feature_glazed_area.svx: -------------------------------------------------------------------------------- 1 | #### What's visualised 2 | 3 | The value of the property glazed area. 4 | 5 | #### Glazed area 6 | 7 | Ranged estimate of the total glazed area of the Habitable Area. 8 | 9 | It's a category with values between 1 and 5, representing: 10 | 11 | - 1: Much Less Than Typical 12 | - 2: Less Than Typical 13 | - 3: Normal 14 | - 4: More Than Typical 15 | - 5: Much More Than Typical 16 | -------------------------------------------------------------------------------- /fe/static/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "background_color": "#ffffff", 3 | "theme_color": "#0189c6", 4 | "name": "app_skeleton", 5 | "short_name": "app_skeleton", 6 | "display": "minimal-ui", 7 | "start_url": "/", 8 | "icons": [ 9 | { 10 | "src": "logo-192.png", 11 | "sizes": "192x192", 12 | "type": "image/png" 13 | }, 14 | { 15 | "src": "logo-512.png", 16 | "sizes": "512x512", 17 | "type": "image/png" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /fe/src/routes/methodology/dataProcessing/+page.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | Data processing methodology - {toolName} 9 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /fe/src/lib/stores/geometry.js: -------------------------------------------------------------------------------- 1 | import {derived} from 'svelte/store'; 2 | 3 | import {_glyph} from '$lib/stores/layout.js'; 4 | 5 | export const _glyphGeometry = derived( 6 | _glyph, 7 | glyph => ({ 8 | glyphHeight: glyph?.height, 9 | glyphWidth: glyph?.width, 10 | }) 11 | ); 12 | 13 | export const _barchartGeometry = derived( 14 | _glyph, 15 | glyph => ({ 16 | glyphHeight: glyph?.height, 17 | glyphWidth: glyph?.width, 18 | padding: 0, 19 | }) 20 | ); 21 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_feature_age_band.svx: -------------------------------------------------------------------------------- 1 | 5 | 6 | #### What's visualised 7 | 8 | The number of installations by property age band. 9 | 10 | #### Age band 11 | 12 | Age band when building part constructed. 13 | 14 | One of: 15 | 16 |
    17 | {#each ageBandOrder as key} 18 |
  • {key}
  • 19 | {/each} 20 |
21 | -------------------------------------------------------------------------------- /fe/src/lib/components/explorer/SelectorRegionType.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 15 | -------------------------------------------------------------------------------- /fe/src/lib/utils/unescape-inlineCode.js: -------------------------------------------------------------------------------- 1 | import {visit} from 'unist-util-visit'; 2 | 3 | const entites = [ 4 | [/{/gu, '{' ], 5 | [/}/gu, '}' ], 6 | ]; 7 | 8 | export function unescape_code () { 9 | return function (tree) { 10 | function unescape (node) { 11 | for (let i = 0; i < entites.length; i += 1) { 12 | node.value = node.value.replace(entites[i][0], entites[i][1]); 13 | } 14 | } 15 | visit(tree, 'inlineCode', unescape); 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /fe/src/lib/components/svizzle/ui/geometryObserver.js: -------------------------------------------------------------------------------- 1 | import {writable} from 'svelte/store'; 2 | 3 | export const setupGeometryObserver = () => { 4 | const _geometry = writable(); 5 | 6 | const geometryObserver = node => { 7 | const observer = new ResizeObserver(() => { 8 | _geometry.set(node.getBoundingClientRect()) 9 | }); 10 | observer.observe(node); 11 | 12 | return () => observer.disconnect(); 13 | } 14 | 15 | return {_geometry, geometryObserver} 16 | } 17 | -------------------------------------------------------------------------------- /fe/src/lib/components/explorer/NoData.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | 18 | 19 | -------------------------------------------------------------------------------- /be/src/schemas/date_histogram1_cardinality2.js: -------------------------------------------------------------------------------- 1 | export const schema = { 2 | schema: { 3 | querystring: { 4 | type: 'object', 5 | required: ['field1', 'field2'], 6 | properties: { 7 | // 1 8 | calendar_interval1: { 9 | default: '1y', 10 | type: 'string', 11 | enum: ['1M', '1q', '1y'] 12 | }, 13 | field1: { type: 'string' }, 14 | // 2 15 | field2: { type: 'string' }, 16 | missing2: { type: 'string' }, 17 | } 18 | } 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /be/src/app.js: -------------------------------------------------------------------------------- 1 | import cors from '@fastify/cors'; 2 | import fastify from 'fastify'; 3 | 4 | import { onRequest, formatPayload } from './hooks.js'; 5 | import { routes } from './routes.js'; 6 | 7 | export const buildServer = async (opts = {}) => { 8 | const server = fastify(opts); 9 | await server.register(cors, { origin: '*' }); 10 | server.addHook('onRequest', onRequest); 11 | server.addHook('preSerialization', formatPayload); 12 | server.register(routes); 13 | return server; 14 | }; 15 | -------------------------------------------------------------------------------- /fe/src/lib/components/svizzle/SizeSensor.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 |
17 | 18 |
19 | -------------------------------------------------------------------------------- /fe/src/lib/stores/layout.js: -------------------------------------------------------------------------------- 1 | import {_screen} from '@svizzle/ui'; 2 | import {derived} from 'svelte/store'; 3 | 4 | /* responsive */ 5 | 6 | export const _screenId = derived( 7 | _screen, 8 | s => s && s.sizes.medium ? 'medium': 'small' 9 | ); 10 | 11 | export const _isSmallScreen = derived( 12 | _screen, 13 | s => s && (s.sizes.small && !s.sizes.medium) 14 | ); 15 | export const _screenClasses = derived(_screen, s => s?.classes); 16 | export const _glyph = derived(_screen, s => s?.glyph); 17 | -------------------------------------------------------------------------------- /fe/src/lib/env.js: -------------------------------------------------------------------------------- 1 | export const isDev = import.meta.env.DEV; 2 | 3 | const backendEnv = import.meta.env?.VITE_BE_ENV || 'dev'; // see `fe/netlify.toml` 4 | const beURLs = { 5 | local: 'http://localhost:3000', 6 | dev: 'https://hpmt.be.dev.dap-tools.uk', 7 | staging: 'https://hpmt.be.staging.dap-tools.uk', 8 | production: 'https://hpmt.be.production.dap-tools.uk' 9 | }; 10 | export const selectedBeURL = beURLs[backendEnv]; 11 | 12 | export const themeOverride = import.meta.env?.VITE_THEME_OVERRIDE; 13 | -------------------------------------------------------------------------------- /fe/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | %sveltekit.head% 11 | 12 | 13 |
%sveltekit.body%
14 | 15 | 16 | -------------------------------------------------------------------------------- /fe/src/lib/components/svizzle/ui/ScrollIntoView.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 |
21 | 22 |
23 | -------------------------------------------------------------------------------- /be/src/bin/saveNuts0.js: -------------------------------------------------------------------------------- 1 | import NUTS_RG_03M_2021_4326_LEVL_0 from '@svizzle/atlas/data/dist/NUTS/topojson/NUTS_RG_03M_2021_4326_LEVL_0.js' 2 | import { saveObj } from '@svizzle/file'; 3 | import { topoToGeo } from '@svizzle/geo'; 4 | 5 | 6 | try { 7 | const geojson = topoToGeo(NUTS_RG_03M_2021_4326_LEVL_0, 'NUTS'); 8 | const save = saveObj('tiles/geojson/nuts21_0.geojson'); 9 | await save(geojson); 10 | console.log("Saved nuts0 successfully") 11 | } catch (e) { 12 | console.error(e); 13 | throw new Error('Saving nuts0 failed'); 14 | } 15 | 16 | -------------------------------------------------------------------------------- /fe/src/lib/utils/svizzle/url.js: -------------------------------------------------------------------------------- 1 | import {isArray, isObject} from '@svizzle/utils'; 2 | import * as _ from 'lamb'; 3 | import {RISON} from 'rison2'; 4 | 5 | export const objectToSearchParams = _.pipe([ 6 | _.pairs, 7 | _.mapWith(_.joinWith('=')), 8 | _.joinWith('&') 9 | ]); 10 | 11 | const escapeAmpersand = string => string.replace(/&/gu, '%26'); 12 | 13 | export const risonifyValues = _.mapValuesWith( 14 | _.when( 15 | _.anyOf([isArray, isObject]), 16 | _.pipe([ 17 | RISON.stringify, 18 | escapeAmpersand 19 | ]) 20 | ) 21 | ); 22 | -------------------------------------------------------------------------------- /be/test/routes/api/count/01.json: -------------------------------------------------------------------------------- 1 | { 2 | "query": { 3 | "method": "GET", 4 | "url": "count" 5 | }, 6 | "response": { 7 | "code": 200, 8 | "data": { 9 | "count": 240509, 10 | "_shards": { 11 | "total": 1, 12 | "successful": 1, 13 | "skipped": 0, 14 | "failed": 0 15 | } 16 | }, 17 | "message": "aggregation successful", 18 | "request": { 19 | "agg": { 20 | "id": "count", 21 | "params": {} 22 | }, 23 | "filter": { 24 | "query": { 25 | "match_all": {} 26 | } 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_energy_efficiency_floor.svx: -------------------------------------------------------------------------------- 1 | 5 | 6 | #### What's visualised 7 | 8 | The number of installations by floor energy efficiency. 9 | 10 | #### Floor energy efficiency 11 | 12 | A qualitative description of the energy efficiency of the floor of the property. 13 | 14 | One of: 15 | 16 |
    17 | {#each energyEfficiencyOrder as key} 18 |
  • {key}
  • 19 | {/each} 20 |
21 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_energy_efficiency_roof.svx: -------------------------------------------------------------------------------- 1 | 5 | 6 | #### What's visualised 7 | 8 | The number of installations by roof heat energy efficiency. 9 | 10 | #### Roof heat energy efficiency 11 | 12 | A qualitative description of the energy efficiency of the roof of the property. 13 | 14 | One of: 15 | 16 |
    17 | {#each energyEfficiencyOrder as key} 18 |
  • {key}
  • 19 | {/each} 20 |
21 | -------------------------------------------------------------------------------- /fe/src/routes/guides/app/+page.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | App guide - {toolName} 12 | 16 | 17 | 18 | {#if $_screen?.sizes.medium} 19 | 20 | {:else} 21 | 22 | {/if} 23 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_energy_efficiency_walls.svx: -------------------------------------------------------------------------------- 1 | 5 | 6 | #### What's visualised 7 | 8 | The number of installations by walls heat energy efficiency. 9 | 10 | #### Walls heat energy efficiency 11 | 12 | A qualitative description of the energy efficiency of the walls of the property. 13 | 14 | One of: 15 | 16 |
    17 | {#each energyEfficiencyOrder as key} 18 |
  • {key}
  • 19 | {/each} 20 |
21 | -------------------------------------------------------------------------------- /be/test/routes/api/certified/01.json: -------------------------------------------------------------------------------- 1 | { 2 | "query": { 3 | "method": "GET", 4 | "url": "certified", 5 | "query": { 6 | "calendar_interval": "1y" 7 | } 8 | }, 9 | "response": { 10 | "code": 200, 11 | "data": { 12 | "count": 2300 13 | }, 14 | "message": "aggregation successful", 15 | "request": { 16 | "agg": { 17 | "id": "certified", 18 | "params": { 19 | "calendar_interval": "1y", 20 | "logic": "overlaps" 21 | } 22 | }, 23 | "filter": { 24 | "query": { 25 | "match_all": {} 26 | } 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /be/test/routes/api/certified/02.json: -------------------------------------------------------------------------------- 1 | { 2 | "query": { 3 | "method": "GET", 4 | "url": "certified", 5 | "query": { 6 | "calendar_interval": "1q" 7 | } 8 | }, 9 | "response": { 10 | "code": 200, 11 | "data": { 12 | "count": 2300 13 | }, 14 | "message": "aggregation successful", 15 | "request": { 16 | "agg": { 17 | "id": "certified", 18 | "params": { 19 | "calendar_interval": "1q", 20 | "logic": "overlaps" 21 | } 22 | }, 23 | "filter": { 24 | "query": { 25 | "match_all": {} 26 | } 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /be/test/routes/api/certified/03.json: -------------------------------------------------------------------------------- 1 | { 2 | "query": { 3 | "method": "GET", 4 | "url": "certified", 5 | "query": { 6 | "calendar_interval": "1M" 7 | } 8 | }, 9 | "response": { 10 | "code": 200, 11 | "data": { 12 | "count": 2300 13 | }, 14 | "message": "aggregation successful", 15 | "request": { 16 | "agg": { 17 | "id": "certified", 18 | "params": { 19 | "calendar_interval": "1M", 20 | "logic": "overlaps" 21 | } 22 | }, 23 | "filter": { 24 | "query": { 25 | "match_all": {} 26 | } 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_energy_efficiency_lighting.svx: -------------------------------------------------------------------------------- 1 | 5 | 6 | #### What's visualised 7 | 8 | The number of installations by lighting energy efficiency. 9 | 10 | #### Lighting energy efficiency 11 | 12 | A qualitative description of the energy efficiency of the lighting used in the property. 13 | 14 | One of: 15 | 16 |
    17 | {#each energyEfficiencyOrder as key} 18 |
  • {key}
  • 19 | {/each} 20 |
21 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_energy_efficiency_windows.svx: -------------------------------------------------------------------------------- 1 | 5 | 6 | #### What's visualised 7 | 8 | The number of installations by windows heat energy efficiency. 9 | 10 | #### Windows heat energy efficiency 11 | 12 | A qualitative description of the energy efficiency of the windows of the property. 13 | 14 | One of: 15 | 16 |
    17 | {#each energyEfficiencyOrder as key} 18 |
  • {key}
  • 19 | {/each} 20 |
21 | -------------------------------------------------------------------------------- /be/test/filter/requests/01.json: -------------------------------------------------------------------------------- 1 | { 2 | "request": { 3 | "property_feature_type": [ 4 | "House" 5 | ] 6 | }, 7 | "query": { 8 | "query": { 9 | "bool": { 10 | "filter": [ 11 | { 12 | "terms": { 13 | "property_feature_type.keyword": [ 14 | "House" 15 | ] 16 | } 17 | } 18 | ] 19 | } 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_energy_efficiency_hot_water.svx: -------------------------------------------------------------------------------- 1 | 5 | 6 | #### What's visualised 7 | 8 | The number of installations by hot water energy efficiency. 9 | 10 | #### Hot water energy efficiency 11 | 12 | A qualitative description of the energy efficiency of the hot water system of the property. 13 | 14 | One of: 15 | 16 |
    17 | {#each energyEfficiencyOrder as key} 18 |
  • {key}
  • 19 | {/each} 20 |
21 | -------------------------------------------------------------------------------- /fe/src/lib/_content/metrics/property_energy_efficiency_main_heat.svx: -------------------------------------------------------------------------------- 1 | 5 | 6 | #### What's visualised 7 | 8 | The number of installations by main heat energy efficiency. 9 | 10 | #### Main heat energy efficiency 11 | 12 | A qualitative description of the energy efficiency of the main heating system of the property. 13 | 14 | One of: 15 | 16 |
    17 | {#each energyEfficiencyOrder as key} 18 |
  • {key}
  • 19 | {/each} 20 |
21 | -------------------------------------------------------------------------------- /fe/src/lib/components/explorer/FlexBar.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
18 | 19 |
20 | 21 | 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "nestauk", 3 | "description": "Nesta Heat Pump Market tracker", 4 | "license": "MIT", 5 | "name": "nesta_hpmt", 6 | "private": true, 7 | "scripts": { 8 | "clearmodules": "rm -rf node_modules be/node_modules fe/node_modules mapbox/node_modules shared/node_modules", 9 | "clearlockfile": "rm -rf package-lock.json", 10 | "clearall": "npm run clearmodules && npm run clearlockfile", 11 | "reinstall": "npm run clearall && npm install" 12 | }, 13 | "version": "0.8.0", 14 | "workspaces": [ 15 | "be", 16 | "fe", 17 | "shared" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /fe/src/lib/utils/svizzle/utils.js: -------------------------------------------------------------------------------- 1 | import { 2 | areAllTruthy, 3 | areEqual, 4 | getLength, 5 | pluckKey, 6 | trim, 7 | } from '@svizzle/utils'; 8 | import * as _ from 'lamb'; 9 | 10 | export const pluckKeySorted = _.pipe([pluckKey, _.sortWith()]); 11 | 12 | export const areAllFalsyWith = accessor => _.every(_.not(accessor)); 13 | 14 | export const doPairItemsContainSameValues = _.allOf([ 15 | _.pipe([_.mapWith(getLength), _.apply(_.areSame)]), 16 | _.pipe([ 17 | _.mapWith(_.sortWith([])), 18 | _.apply(_.zip), 19 | _.mapWith(areEqual), 20 | areAllTruthy 21 | ]) 22 | ]); 23 | -------------------------------------------------------------------------------- /be/es/copy_pipeline.conf: -------------------------------------------------------------------------------- 1 | input { 2 | elasticsearch { 3 | hosts => "${LOGSTASH_INPUT_DOMAIN}:9200" 4 | user => "elastic" 5 | password => "${LOGSTASH_INPUT_PASSWORD}" 6 | index=> "${LOGSTASH_INPUT_INDEX}" 7 | ssl => true 8 | ca_file => "${LOGSTASH_INPUT_CERT}" 9 | } 10 | } 11 | 12 | output { 13 | opensearch { 14 | hosts => ["${LOGSTASH_OUTPUT_DOMAIN}:443"] 15 | auth_type => { 16 | type => 'basic' 17 | user => 'elastic' 18 | password => "${LOGSTASH_OUTPUT_PASSWORD}" 19 | } 20 | index=> "${LOGSTASH_OUTPUT_INDEX}" 21 | cs_compatibility => disabled 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fe/src/lib/_content/info/PrivacyBanner.svx: -------------------------------------------------------------------------------- 1 | Cookies are files saved on your phone, tablet or computer when you visit a 2 | website. 3 | 4 | We only use essential cookies on this website: 5 | 6 | * the tool itself does not collect any personal data. 7 | * the feedback form is using 8 | [Google Forms](https://www.google.com/forms/about/), 9 | which installs cookies in your browser. 10 | 11 | By submitting data with Google Forms you accept the 12 | [Terms of Service](https://policies.google.com/terms) and the 13 | [Data Privacy Policy of Google Inc](https://policies.google.com/privacy). 14 | -------------------------------------------------------------------------------- /fe/src/lib/utils/download.js: -------------------------------------------------------------------------------- 1 | import {saveAs} from 'file-saver'; 2 | import JSZip from 'jszip'; 3 | import * as _ from 'lamb'; 4 | 5 | /* zip */ 6 | 7 | export const getZippedFiles = async files => { 8 | const zipper = new JSZip(); 9 | 10 | _.pairs(files) 11 | .forEach(([name, content]) => zipper.file(name, content)); 12 | 13 | const zipBlob = await zipper.generateAsync({type: 'blob'}); 14 | 15 | return zipBlob; 16 | } 17 | 18 | export const initiateZippedDownload = async (zipName, files) => { 19 | const content = await getZippedFiles(files); 20 | saveAs(content, zipName); 21 | } 22 | -------------------------------------------------------------------------------- /be/src/routes/cardinality.js: -------------------------------------------------------------------------------- 1 | import { index } from '../conf.js'; 2 | import { client } from '../es.js'; 3 | 4 | export const getCardinality = async (request, reply) => { 5 | const { 6 | field, 7 | missing = null, 8 | } = request.query; 9 | 10 | const body = { 11 | ...request.filter, 12 | size: 0, 13 | aggs: { 14 | cardinality: { 15 | cardinality: { 16 | field, 17 | ...missing && { missing } 18 | } 19 | } 20 | } 21 | }; 22 | 23 | const result = await client.search({ 24 | body, 25 | index 26 | }); 27 | 28 | reply.send(result.aggregations); 29 | }; 30 | -------------------------------------------------------------------------------- /be/src/schemas/date_histogram1_histogram2.js: -------------------------------------------------------------------------------- 1 | import { maxBins } from '../conf.js'; 2 | 3 | export const schema = { 4 | schema: { 5 | querystring: { 6 | type: 'object', 7 | required: ['field1', 'field2'], 8 | properties: { 9 | // 1 10 | calendar_interval1: { 11 | default: '1y', 12 | type: 'string', 13 | enum: ['1M', '1q', '1y'] 14 | }, 15 | field1: { type: 'string' }, 16 | // 2 17 | bins2: { 18 | default: 10, 19 | type: 'integer', 20 | minimum: 1, 21 | maximum: maxBins 22 | }, 23 | field2: { type: 'string' }, 24 | } 25 | } 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /be/src/schemas/date_histogram1_stats2.js: -------------------------------------------------------------------------------- 1 | export const schema = { 2 | schema: { 3 | querystring: { 4 | type: 'object', 5 | required: ['field1', 'field2'], 6 | properties: { 7 | // 1 8 | calendar_interval1: { 9 | default: '1y', 10 | type: 'string', 11 | enum: ['1M', '1q', '1y'] 12 | }, 13 | field1: { type: 'string' }, 14 | // 2 15 | field2: { type: 'string' }, 16 | use_extended_stats2: { 17 | default: false, 18 | type: 'boolean' 19 | }, 20 | use_percentiles2: { 21 | default: false, 22 | type: 'boolean' 23 | } 24 | } 25 | } 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /fe/src/lib/components/explorer/FilterPaneBorder.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
11 | 12 |
13 | 14 | 29 | -------------------------------------------------------------------------------- /be/src/routes/stats.js: -------------------------------------------------------------------------------- 1 | import { index } from '../conf.js'; 2 | import { client } from '../es.js'; 3 | 4 | export const getStats = async (request, reply) => { 5 | const { 6 | field, 7 | use_extended_stats = false, 8 | } = request.query; 9 | 10 | const statQuery = use_extended_stats ? 'extended_stats' : 'stats'; 11 | 12 | const body = { 13 | ...request.filter, 14 | size: 0, 15 | aggs: { 16 | stats: { 17 | [statQuery]: { 18 | field, 19 | } 20 | } 21 | } 22 | }; 23 | 24 | const result = await client.search({ 25 | body, 26 | index 27 | }); 28 | 29 | reply.send(result.aggregations); 30 | }; 31 | -------------------------------------------------------------------------------- /fe/netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "cd .. && npm install && cd fe && npm run build" 3 | publish = ".svelte-kit/netlify" 4 | 5 | [build.environment] 6 | ADAPTER = "netlify" 7 | NODE_VERSION = "18.13.0" 8 | VITE_BE_ENV = "dev" 9 | 10 | [functions] 11 | # temporary workaround for https://github.com/sveltejs/kit/issues/6462 12 | node_bundler = "esbuild" 13 | 14 | [context.dev.environment] 15 | VITE_BE_ENV = "dev" 16 | 17 | [context.staging.environment] 18 | VITE_BE_ENV = "staging" 19 | 20 | [context.production.environment] 21 | VITE_BE_ENV = "production" 22 | 23 | # re: `VITE_BE_ENV` please see `fe/src/lib/env.js` 24 | -------------------------------------------------------------------------------- /be/src/routes/date_histogram.js: -------------------------------------------------------------------------------- 1 | import { index } from '../conf.js'; 2 | import { client } from '../es.js'; 3 | 4 | export const getDateHistogram = async (request, reply) => { 5 | const { 6 | calendar_interval = '1y', 7 | field, 8 | } = request.query; 9 | 10 | const body = { 11 | ...request.filter, 12 | size: 0, 13 | aggs: { 14 | date_histogram: { 15 | date_histogram: { 16 | field, 17 | calendar_interval, 18 | format: 'yyyy-MM' 19 | } 20 | } 21 | } 22 | }; 23 | 24 | const result = await client.search({ 25 | body, 26 | index 27 | }); 28 | 29 | reply.send(result.aggregations); 30 | }; 31 | -------------------------------------------------------------------------------- /be/src/schemas/terms1_histogram2.js: -------------------------------------------------------------------------------- 1 | import { maxBuckets, maxBins } from '../conf.js'; 2 | 3 | export const schema = { 4 | schema: { 5 | querystring: { 6 | type: 'object', 7 | required: ['field1', 'field2'], 8 | properties: { 9 | // 1 10 | field1: { type: 'string' }, 11 | size1: { 12 | default: maxBuckets, 13 | type: 'integer', 14 | minimum: 1, 15 | maximum: maxBuckets 16 | }, 17 | // 2 18 | bins2: { 19 | default: 10, 20 | type: 'integer', 21 | minimum: 1, 22 | maximum: maxBins 23 | }, 24 | field2: { type: 'string' }, 25 | } 26 | } 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /be/test/routes/api/cardinality/01.json: -------------------------------------------------------------------------------- 1 | { 2 | "query": { 3 | "method": "GET", 4 | "url": "cardinality", 5 | "query": { 6 | "field": "property_energy_efficiency_windows.keyword" 7 | } 8 | }, 9 | "response": { 10 | "code": 200, 11 | "data": { 12 | "cardinality": { 13 | "value": 5 14 | } 15 | }, 16 | "message": "aggregation successful", 17 | "request": { 18 | "agg": { 19 | "id": "cardinality", 20 | "params": { 21 | "field": "property_energy_efficiency_windows.keyword" 22 | } 23 | }, 24 | "filter": { 25 | "query": { 26 | "match_all": {} 27 | } 28 | } 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /be/test/filter/requests/03.json: -------------------------------------------------------------------------------- 1 | { 2 | "request": { 3 | "hp_feature_flow_temperature": { 4 | "gt": 10, 5 | "lt": 50 6 | } 7 | }, 8 | "query": { 9 | "query": { 10 | "bool": { 11 | "filter": [ 12 | { 13 | "range": { 14 | "hp_feature_flow_temperature": { 15 | "gt": 10, 16 | "lt": 50 17 | } 18 | } 19 | } 20 | ] 21 | } 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /fe/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": false, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": false 12 | } 13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias and https://kit.svelte.dev/docs/configuration#files 14 | // 15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } 18 | -------------------------------------------------------------------------------- /fe/src/lib/components/layout/Nav.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | {#if $_isSmallScreen || isServerSide} 15 | 21 | {:else} 22 | 23 | {/if} 24 | -------------------------------------------------------------------------------- /fe/src/routes/feedback/survey/+page.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | Survey - {toolName} 7 | 11 | 12 | 13 |
14 |