diff --git a/app/src/frontend/building/category-link.css b/app/src/frontend/building/category-link.css index 6ec547f0..b495e77b 100644 --- a/app/src/frontend/building/category-link.css +++ b/app/src/frontend/building/category-link.css @@ -3,7 +3,6 @@ justify-content: center; align-items: center; box-sizing: border-box; - /* padding: 0.1em; */ width: 100%; height: 100%; } @@ -18,5 +17,6 @@ text-align: center; font-size: 1em; margin: 0; + padding: 0.25em; } \ No newline at end of file diff --git a/app/src/frontend/building/container-header.css b/app/src/frontend/building/container-header.css index 04c81d33..0b3fa068 100644 --- a/app/src/frontend/building/container-header.css +++ b/app/src/frontend/building/container-header.css @@ -17,7 +17,7 @@ .section-header .h2 { display: inline-block; - flex-basis: 150px; + flex-basis: 200px; flex-shrink: 0; flex-grow: 1; margin: 0.75rem 0 0.5em 0.1em; @@ -33,7 +33,8 @@ .section-header .section-header-actions { display: inline-block; - flex-basis: 400px; + flex-basis: 220px; + flex-shrink: 0; display: flex; flex-flow: row wrap; align-items: center; diff --git a/app/src/frontend/building/data-components/planning-data-entry.tsx b/app/src/frontend/building/data-components/planning-data-entry.tsx index cb4643e0..d062bf96 100644 --- a/app/src/frontend/building/data-components/planning-data-entry.tsx +++ b/app/src/frontend/building/data-components/planning-data-entry.tsx @@ -99,7 +99,7 @@ const PlanningDataOfficialDataEntry: React.FC -
Current planning application status for this site: Planning application status for this site:
diff --git a/app/src/frontend/building/data-containers/streetscape.tsx b/app/src/frontend/building/data-containers/streetscape.tsx index ff25d7bc..4a0ee069 100644 --- a/app/src/frontend/building/data-containers/streetscape.tsx +++ b/app/src/frontend/building/data-containers/streetscape.tsx @@ -13,7 +13,7 @@ import { CategoryViewProps } from './category-view-props'; */ const StreetscapeView: React.FunctionComponent = (props) => ( - +
  • Gardens
  • Trees
  • diff --git a/app/src/frontend/config/data-fields-config.ts b/app/src/frontend/config/data-fields-config.ts index 31f883ed..dc999d9a 100644 --- a/app/src/frontend/config/data-fields-config.ts +++ b/app/src/frontend/config/data-fields-config.ts @@ -120,7 +120,7 @@ export const buildingUserFields = { export const dataFields = { /* eslint-disable @typescript-eslint/camelcase */ location_name: { category: Category.Location, - title: "Building information (link)", + title: "Building Name (Information link)", tooltip: "Link to a website with information on the building, not needed for most.", example: "https://en.wikipedia.org/wiki/Palace_of_Westminster", }, diff --git a/app/src/frontend/displayPreferences-context.tsx b/app/src/frontend/displayPreferences-context.tsx index bde2d89d..67c0f69a 100644 --- a/app/src/frontend/displayPreferences-context.tsx +++ b/app/src/frontend/displayPreferences-context.tsx @@ -3,6 +3,9 @@ import React, { createContext, useCallback, useContext, useEffect, useState } fr import { LayerEnablementState, MapTheme } from './config/map-config'; interface DisplayPreferencesContextState { + resetLayers: (e: React.FormEvent) => void; + anyLayerModifiedState: () => boolean; + vista: LayerEnablementState; vistaSwitch: (e: React.FormEvent) => void; vistaSwitchOnClick: React.MouseEventHandler; @@ -45,6 +48,9 @@ const stub = (): never => { }; export const DisplayPreferencesContext = createContext({ + resetLayers: stub, + anyLayerModifiedState: stub, + vista: undefined, vistaSwitch: stub, vistaSwitchOnClick: undefined, @@ -85,16 +91,69 @@ export const DisplayPreferencesContext = createContext {}; export const DisplayPreferencesProvider: React.FC<{}> = ({children}) => { - const [vista, setVista] = useState('disabled'); - const [flood, setFlood] = useState('disabled'); - const [creative, setCreative] = useState('disabled'); - const [housing, setHousing] = useState('disabled'); - const [borough, setBorough] = useState('enabled'); - const [parcel, setParcel] = useState('disabled'); - const [conservation, setConservation] = useState('disabled'); - const [historicData, setHistoricData] = useState('disabled'); + const defaultVista = 'disabled' + const defaultFlood = 'disabled' + const defaultCreative = 'disabled' + const defaultHousing = 'disabled' + const defaultBorough = 'enabled' + const defaultParcel = 'disabled' + const defaultConservation = 'disabled' + const defaultHistoricData = 'disabled' + const [vista, setVista] = useState(defaultVista); + const [flood, setFlood] = useState(defaultFlood); + const [creative, setCreative] = useState(defaultCreative); + const [housing, setHousing] = useState(defaultHousing); + const [borough, setBorough] = useState(defaultBorough); + const [parcel, setParcel] = useState(defaultParcel); + const [conservation, setConservation] = useState(defaultConservation); + const [historicData, setHistoricData] = useState(defaultHistoricData); const [darkLightTheme, setDarkLightTheme] = useState('night'); + const resetLayers = useCallback( + (e) => { + e.preventDefault(); + setVista(defaultVista); + setFlood(defaultFlood); + setCreative(defaultCreative); + setHousing(defaultHousing); + setBorough(defaultBorough) + setParcel(defaultParcel); + setConservation(defaultConservation); + setHistoricData(defaultHistoricData); + //setDarkLightTheme('night'); // reset only layers + }, + [] + ) + + function anyLayerModifiedState() { + if(vista != defaultVista) { + return true; + } + if(flood != defaultFlood) { + return true; + } + if(creative != defaultCreative) { + return true; + } + if(housing != defaultHousing) { + return true; + } + if(borough != defaultBorough) { + return true; + } + if(parcel != defaultParcel) { + return true; + } + if(conservation != defaultConservation) { + return true; + } + if(historicData != defaultHistoricData) { + return true; + } + //darkLightTheme not handled here + return false; + } + const vistaSwitch = useCallback( (e) => { e.preventDefault(); @@ -233,6 +292,9 @@ export const DisplayPreferencesProvider: React.FC<{}> = ({children}) => { return ( ; - } else if (borough == "disabled") { - return
    - // do not display anything return boundaryGeojson && + attribution='Borough boundary from London Datastore Ordnance Survey Open Data - Contains public sector information licensed under the Open Government Licence v3.0' + data={boundaryGeojson} + style={{color: '#f00', fill: false, weight: 1}} + />; } else { - return boundaryGeojson && - ; + return <> } } diff --git a/app/src/frontend/map/layers/borough-label-layer.tsx b/app/src/frontend/map/layers/borough-label-layer.tsx new file mode 100644 index 00000000..34787602 --- /dev/null +++ b/app/src/frontend/map/layers/borough-label-layer.tsx @@ -0,0 +1,17 @@ +import { GeoJsonObject } from 'geojson'; +import React, { useEffect, useState } from 'react'; +import { GeoJSON } from 'react-leaflet'; +import { useDisplayPreferences } from '../../displayPreferences-context'; +import { apiGet } from '../../apiHelpers'; +import { BuildingBaseLayerAllZoom } from './building-base-layer-all-zoom'; + +export function BoroughLabelLayer({}) { + const { borough } = useDisplayPreferences(); + + if(borough == "enabled") { + return ; + } else { + return <> + } +} + diff --git a/app/src/frontend/map/map-button.css b/app/src/frontend/map/map-button.css index 8b94524e..0b7773ae 100644 --- a/app/src/frontend/map/map-button.css +++ b/app/src/frontend/map/map-button.css @@ -35,6 +35,14 @@ } } +.reset-switcher { + top: 37px; + margin-right: 60px; +} +.reset-switcher .btn { + min-width: 280px; +} + .theme-switcher { top: 77px; } diff --git a/app/src/frontend/map/map.css b/app/src/frontend/map/map.css index 00a265a3..95466458 100644 --- a/app/src/frontend/map/map.css +++ b/app/src/frontend/map/map.css @@ -28,19 +28,6 @@ .leaflet-grab { cursor: crosshair; } -.map-notice { - position: absolute; - top: 3.5rem; - left: 0.5rem; - z-index: 1000; - padding: 0.5rem 0.75rem; - width: 250px; - background: #fff; - border: 1px solid #fff; - border-radius: 4px; - box-shadow: 0px 0px 1px 1px #222; - display: none; -} @media (min-width: 990px){ /* Only show the "Click a building ..." notice for larger screens */ .map-notice { diff --git a/app/src/frontend/map/map.tsx b/app/src/frontend/map/map.tsx index 80261c67..a23f2d17 100644 --- a/app/src/frontend/map/map.tsx +++ b/app/src/frontend/map/map.tsx @@ -14,6 +14,7 @@ import { Building } from '../models/building'; import { CityBaseMapLayer } from './layers/city-base-map-layer'; import { CityBoundaryLayer } from './layers/city-boundary-layer'; import { BoroughBoundaryLayer } from './layers/borough-boundary-layer'; +import { BoroughLabelLayer } from './layers/borough-label-layer'; import { ParcelBoundaryLayer } from './layers/parcel-boundary-layer'; import { HistoricDataLayer } from './layers/historic-data-layer'; import { FloodBoundaryLayer } from './layers/flood-boundary-layer'; @@ -30,6 +31,7 @@ import { Legend } from './legend'; import SearchBox from './search-box'; import ThemeSwitcher from './theme-switcher'; import DataLayerSwitcher from './data-switcher'; +import { ResetSwitcher } from './reset-switcher'; import { BoroughSwitcher } from './borough-switcher'; import { ParcelSwitcher } from './parcel-switcher'; import { FloodSwitcher } from './flood-switcher'; @@ -158,6 +160,12 @@ export const ColouringMap : FC = ({ /> } + + + @@ -165,13 +173,8 @@ export const ColouringMap : FC = ({ { mode !== 'basic' && <> - { - !hasSelection && -
    - {isEdit ? 'Click a building to edit' : 'Click a building for details'} -
    - } + { diff --git a/app/src/frontend/map/reset-switcher.tsx b/app/src/frontend/map/reset-switcher.tsx new file mode 100644 index 00000000..d8c06845 --- /dev/null +++ b/app/src/frontend/map/reset-switcher.tsx @@ -0,0 +1,20 @@ +import React from 'react'; + +import './map-button.css'; +import { useDisplayPreferences } from '../displayPreferences-context'; + +export const ResetSwitcher: React.FC<{}> = () => { + const { resetLayers, darkLightTheme, anyLayerModifiedState } = useDisplayPreferences(); + if(anyLayerModifiedState()) { + return ( +
    + +
    + ); + } else { + return <> + } +} diff --git a/app/src/frontend/map/search-box.tsx b/app/src/frontend/map/search-box.tsx index 132b57a8..ac06984c 100644 --- a/app/src/frontend/map/search-box.tsx +++ b/app/src/frontend/map/search-box.tsx @@ -103,10 +103,7 @@ class SearchBox extends Component { apiGet(`/api/search?q=${this.state.q}`) .then((data) => { if (data && data.results){ - this.setState({ - results: data.results, - fetching: false - }); + this.props.onLocate(data.results[0].geometry.coordinates[1], data.results[0].geometry.coordinates[0], data.results[0].attributes.zoom) } else { console.error(data); @@ -157,31 +154,7 @@ class SearchBox extends Component { ); } - const resultsList = this.state.results.length? - - : null; + const resultsList = null; return (
    diff --git a/app/src/frontend/route.tsx b/app/src/frontend/route.tsx index 1d595d22..c43beae9 100644 --- a/app/src/frontend/route.tsx +++ b/app/src/frontend/route.tsx @@ -39,7 +39,7 @@ export const AuthRoute: React.FC = ({ component: Component, children if(isAuthenticated) { let state = props.location.state as any; let from = '/my-account.html'; - if (typeof state == 'object' && 'from' in state){ + if (typeof state == 'object' && state !== null && 'from' in state) { from = state.from; } diff --git a/app/src/tiles/rendererDefinition.ts b/app/src/tiles/rendererDefinition.ts index f47ec8f4..d42911ba 100644 --- a/app/src/tiles/rendererDefinition.ts +++ b/app/src/tiles/rendererDefinition.ts @@ -53,7 +53,7 @@ const tileCache = new TileCache( shouldCacheFn, // don't clear on bounding box cache clear tilesets not affected by user-editable data - (tileset: string) => tileset !== 'base_light' && tileset !== 'base_night' && tileset !== 'base_night_outlines' && tileset !== 'base_burough' && tileset !== "planning_applications_status_recent" && tileset !== "planning_applications_status_very_recent" && tileset !== "planning_applications_status_all" + (tileset: string) => tileset !== 'base_light' && tileset !== 'base_night' && tileset !== 'base_night_outlines' && tileset !== 'base_borough' && tileset !== "planning_applications_status_recent" && tileset !== "planning_applications_status_very_recent" && tileset !== "planning_applications_status_all" ); const renderBuildingTile = (t: TileParams, d: any) => renderDataSourceTile(t, d, getDataConfig, getLayerVariables); diff --git a/migrations/011.sustainability.down.sql b/migrations/011.sustainability.down.sql index a1279e3e..68740b84 100644 --- a/migrations/011.sustainability.down.sql +++ b/migrations/011.sustainability.down.sql @@ -1,15 +1,15 @@ --- Remove sustainability fields, update in paralell with adding new fields +-- Remove sustainability fields, update in parallel with adding new fields -- BREEAM rating ALTER TABLE buildings DROP COLUMN IF EXISTS sust_breeam_rating; -- BREEAM date ALTER TABLE buildings DROP COLUMN IF EXISTS sust_breeam_date; --- DEC (display energy certifcate, only applies to non domestic buildings) +-- DEC (display energy certificate, only applies to non domestic buildings) ALTER TABLE buildings DROP COLUMN IF EXISTS sust_dec; -- DEC date ALTER TABLE buildings DROP COLUMN IF EXISTS sust_dec_date; ---DEC certifcate lmk key, this would be lmkkey, no online lookup but can scrape through API. Numeric (25) +--DEC certificate lmk key, this would be lmkkey, no online lookup but can scrape through API. Numeric (25) ALTER TABLE buildings DROP COLUMN IF EXISTS sust_dec_lmkey; -- Aggregate EPC rating (Estimated) for a building, derived from inidividual certificates diff --git a/migrations/011.sustainability.down1-extra.sql b/migrations/011.sustainability.down1-extra.sql index 0dc39b72..385b36aa 100644 --- a/migrations/011.sustainability.down1-extra.sql +++ b/migrations/011.sustainability.down1-extra.sql @@ -1,4 +1,4 @@ --- Remove sustainability fields, update in paralell with adding new fields +-- Remove sustainability fields, update in parallel with adding new fields -- Last significant retrofit date YYYY -- Need to add a constraint to sust_retrofit_date -- Renewal technologies @@ -6,7 +6,7 @@ -- Values: ALTER TABLE buildings DROP COLUMN IF EXISTS sust_renewables_tech; ---Has a building had a major renovation without extenstion (captured in form) +--Has a building had a major renovation without extension (captured in form) --Boolean yes/no - links to the the DATE ALTER TABLE buildings DROP COLUMN IF EXISTS sust_retrofitted; diff --git a/migrations/011.sustainability.up.sql b/migrations/011.sustainability.up.sql index 500fe728..a6e7fac0 100644 --- a/migrations/011.sustainability.up.sql +++ b/migrations/011.sustainability.up.sql @@ -20,7 +20,7 @@ ALTER TABLE buildings ALTER TABLE buildings ADD COLUMN IF NOT EXISTS sust_breeam_date smallint; --- DEC (display energy certifcate, only applies to non domestic buildings) +-- DEC (display energy certificate, only applies to non domestic buildings) -- A - G CREATE TYPE sust_dec AS ENUM ('A', diff --git a/migrations/011.sustainability.up1-extra.sql b/migrations/011.sustainability.up1-extra.sql index 11cc62d5..bcf9864e 100644 --- a/migrations/011.sustainability.up1-extra.sql +++ b/migrations/011.sustainability.up1-extra.sql @@ -1,10 +1,10 @@ --- Remove sustainability fields, update in paralell with adding new fields +-- Remove sustainability fields, update in parallel with adding new fields -- Last significant retrofit date YYYY -- Need to add a constraint to sust_retrofit_date ALTER TABLE buildings ADD CONSTRAINT sust_retrofit_date_end CHECK (sust_retrofit_date <= DATE_PART('year', CURRENT_DATE)); ---Has a building had a major renovation without extenstion (captured in form) +--Has a building had a major renovation without extension (captured in form) --Boolean yes/no - links to the the DATE ALTER TABLE buildings ADD COLUMN IF NOT EXISTS sust_retrofitted boolean DEFAULT 'n'; diff --git a/migrations/016.landuse.down.sql b/migrations/016.landuse.down.sql index 5e1f869b..02f0cfbf 100644 --- a/migrations/016.landuse.down.sql +++ b/migrations/016.landuse.down.sql @@ -1,4 +1,4 @@ ---Landuse is hierachical. Highest level is Order (ie. Residential) then Group (ie Residential-Dwelling) then Class (ie Residential-Dwelling-Detached house) +--Landuse is hierarchical. Highest level is Order (ie. Residential) then Group (ie Residential-Dwelling) then Class (ie Residential-Dwelling-Detached house) --Interface will collected most detailed (class) but visualise highest level (order) --Landuse is a table as #358 --Land use class, group and order will be stored in a new table diff --git a/migrations/016.landuse.up.sql b/migrations/016.landuse.up.sql index f182f9b6..bb9c668a 100644 --- a/migrations/016.landuse.up.sql +++ b/migrations/016.landuse.up.sql @@ -1,5 +1,5 @@ -- Create land use and fields ---Landuse is hierachical. Highest level is Order (Residential) then Group (Residential-Dwelling) then Class (Residential-Dwelling-Detached house) +--Landuse is hierarchical. Highest level is Order (Residential) then Group (Residential-Dwelling) then Class (Residential-Dwelling-Detached house) --Some ETL work required to get this together refer to analysis repo --Prerequesite is to have first run bulk_data_sources migrations --Then create table landuse_order for the app, this is used as foreign key for current and original landuse_order @@ -36,11 +36,11 @@ FROM reference_tables.landuse_classifications a WHERE a.level = 'class' AND a.is_used; ---Landuse is hierachical. Highest level is Order (Residential) then Group (Residential-Dwelling) then Class (Residential-Dwelling-Detached house) +--Landuse is hierarchical. Highest level is Order (Residential) then Group (Residential-Dwelling) then Class (Residential-Dwelling-Detached house) --Interface will collected most detailed (class) but visualise highest level (order) --Landuse is a table as #358 --Prerequisite run bulk_sources migration first - -- Land use is table with 3 levels of hierachy (highest to lowest). order > group > class + -- Land use is table with 3 levels of hierarchy (highest to lowest). order > group > class -- Land use order, singular. Client and db constrained with foreign key diff --git a/migrations/022.community.down.sql b/migrations/022.community.down.sql index 83431649..01030579 100644 --- a/migrations/022.community.down.sql +++ b/migrations/022.community.down.sql @@ -3,7 +3,7 @@ -- -- Ownership type, enumerate type from: -- ALTER TABLE buildings DROP COLUMN IF EXISTS ownership_type; --- -- Ownerhsip perception, would you describe this as a community asset? +-- -- Ownership perception, would you describe this as a community asset? -- -- Boolean yes / no -- ALTER TABLE buildings DROP COLUMN IF EXISTS ownership_perception; diff --git a/migrations/unreleased/0xx.team.down.sql b/migrations/unreleased/0xx.team.down.sql index 6d34b6de..1257501f 100644 --- a/migrations/unreleased/0xx.team.down.sql +++ b/migrations/unreleased/0xx.team.down.sql @@ -1,3 +1,3 @@ --- Remove team fields, update in paralell with adding new fields +-- Remove team fields, update in parallel with adding new fields -- Award or awards (may be multiple) stored as json b object ALTER TABLE buildings DROP COLUMN IF EXISTS team_awards; diff --git a/migrations/unreleased/0xx.team.up.sql b/migrations/unreleased/0xx.team.up.sql index ac9868f3..050770e5 100644 --- a/migrations/unreleased/0xx.team.up.sql +++ b/migrations/unreleased/0xx.team.up.sql @@ -3,6 +3,6 @@ ALTER TABLE buildings ADD COLUMN IF NOT EXISTS team_awards jsonb; ---To validate this input, the following confirms it's an valid object but not that the items in the object are validated agains those we will acccept +--To validate this input, the following confirms it's an valid object but not that the items in the object are validated against those we will accept ALTER TABLE buildings ADD CONSTRAINT data_is_valid CHECK (is_jsonb_valid ('{"type": "object"}', team_awards));