Merge branch 'colouring-cities:master' into ali

This commit is contained in:
Ali 2023-08-24 16:54:21 -04:00 committed by GitHub
commit a33e98c27b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 4970 additions and 2458 deletions

View File

@ -8,9 +8,8 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.7'
- name:
Install dependencies
python-version: "3.11"
- name: Install dependencies
run: |
sudo apt-get install libgeos-dev
python -m pip install --upgrade pip
@ -19,7 +18,7 @@ jobs:
python -m pip install -r etl/requirements.txt
- name: Run Flake8
run: |
ls etl/*py | grep -v 'join_building_data' | xargs flake8 --exclude etl/__init__.py
flake8 etl --ignore=E501
- name: Run tests
run: |
python -m pytest

View File

@ -1,4 +1,4 @@
# Colouring London
# Colouring Cities Core Platform
[![All Contributors](https://img.shields.io/badge/all_contributors-12-orange.svg?style=flat-square)](#contributors)
![Build status](https://github.com/colouring-cities/colouring-core/workflows/Node.js%20CI/badge.svg)

View File

@ -19,7 +19,19 @@
</Style>
<Style name="base_night_outlines">
<Rule>
<LineSymbolizer stroke="#ff0000ff" stroke-width="1" />
<MaxScaleDenominator>20000</MaxScaleDenominator>
<MinScaleDenominator>1200</MinScaleDenominator>
<LineSymbolizer stroke="#0081AF" stroke-width="0.5"/>
</Rule>
<Rule>
<MaxScaleDenominator>12000</MaxScaleDenominator>
<MinScaleDenominator>8000</MinScaleDenominator>
<LineSymbolizer stroke="#0081AF" stroke-width="1.8"/>
</Rule>
<Rule>
<MaxScaleDenominator>8000</MaxScaleDenominator>
<MinScaleDenominator>0</MinScaleDenominator>
<LineSymbolizer stroke="#0081AF" stroke-width="4.0"/>
</Rule>
</Style>
<Style name="base_boroughs">
@ -913,6 +925,83 @@
<LineSymbolizer stroke="#888" stroke-width="3.0"/>
</Rule>
</Style>
<Style name="original_landuse">
<Rule>
<Filter>[typology_original_use_order] = "Agriculture And Fisheries"</Filter>
<PolygonSymbolizer fill="#73ccd1" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Minerals"</Filter>
<PolygonSymbolizer fill="#45cce3" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Unclassified, presumed non-residential"</Filter>
<PolygonSymbolizer fill="#6c6f8e" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Recreation And Leisure"</Filter>
<PolygonSymbolizer fill="#ffbfbf" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Transport"</Filter>
<PolygonSymbolizer fill="#b3de69" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Utilities And Infrastructure"</Filter>
<PolygonSymbolizer fill="#cccccc" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Residential" and not ([typology_original_use_order] = "Garden buildings") and not ([typology_original_use_order] = "Hotels, boarding and guest houses") and not ([typology_original_use_verified])</Filter>
<PolygonSymbolizer fill="#252aa6" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Residential" and not ([typology_original_use_order] = "Garden buildings") and not ([typology_original_use_order] = "Hotels, boarding and guest houses") and ([typology_original_use_verified])</Filter>
<PolygonSymbolizer fill="#7025a6" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Residential" and [typology_original_use_order] = "Hotels, boarding and guest houses"</Filter>
<PolygonSymbolizer fill="#3c4194" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Residential" and [typology_original_use_order] = "Garden buildings" </Filter>
<PolygonSymbolizer fill="#1157fa" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Community Services"</Filter>
<PolygonSymbolizer fill="#fa667d" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Retail"</Filter>
<PolygonSymbolizer fill="#ff8c00" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Industry And Business"</Filter>
<PolygonSymbolizer fill="#f5f58f" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Vacant And Derelict"</Filter>
<PolygonSymbolizer fill="#ffffff" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Defence"</Filter>
<PolygonSymbolizer fill="#898944" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Mixed Use"</Filter>
<PolygonSymbolizer fill="#e5050d" />
</Rule>
<Rule>
<MaxScaleDenominator>8530</MaxScaleDenominator>
<MinScaleDenominator>4264</MinScaleDenominator>
<LineSymbolizer stroke="#888" stroke-width="0.8"/>
</Rule>
<Rule>
<MaxScaleDenominator>4264</MaxScaleDenominator>
<MinScaleDenominator>0</MinScaleDenominator>
<LineSymbolizer stroke="#888" stroke-width="3.0"/>
</Rule>
</Style>
<Style name="disaster_severity">
<Rule>
<Filter>[disaster_severity] = "Building destroyed"</Filter>
@ -973,4 +1062,139 @@
<PolygonSymbolizer fill="#ffe8a9" />
</Rule>
</Style>
<Style name="typology_classification">
<Rule>
<Filter>[typology_classification] = "Low-rise: Not part of a group/cluster (1-3 core floors- excluding extensions)"</Filter>
<PolygonSymbolizer fill="#0311AB" />
</Rule>
<Rule>
<Filter>[typology_classification] = "Low-rise: Part of dense block/row/terrace"</Filter>
<PolygonSymbolizer fill="#3845D4" />
</Rule>
<Rule>
<Filter>[typology_classification] = "Low-rise: Part of group of widely spaced blocks (includes semi-detached houses)"</Filter>
<PolygonSymbolizer fill="#6D79FD" />
</Rule>
<Rule>
<Filter>[typology_classification] = "Mid-rise: Not part of a group/cluster (4-7 core floors)"</Filter>
<PolygonSymbolizer fill="#FF5D00" />
</Rule>
<Rule>
<Filter>[typology_classification] = "Mid-rise: Part of group of densely spaced blocks"</Filter>
<PolygonSymbolizer fill="#FF8000" />
</Rule>
<Rule>
<Filter>[typology_classification] = "Mid-rise: Part of group of widely spaced blocks"</Filter>
<PolygonSymbolizer fill="#FFA200" />
</Rule>
<Rule>
<Filter>[typology_classification] = "High rise: Not part of a group/cluster"</Filter>
<PolygonSymbolizer fill="#AB1303" />
</Rule>
<Rule>
<Filter>[typology_classification] = "High-rise: Part of group of densely spaced blocks (8 + core floors)"</Filter>
<PolygonSymbolizer fill="#D43A29" />
</Rule>
<Rule>
<Filter>[typology_classification] = "High-rise: Part of group of widely spaced blocks"</Filter>
<PolygonSymbolizer fill="#FC604F" />
</Rule>
<Rule>
<MaxScaleDenominator>17061</MaxScaleDenominator>
<MinScaleDenominator>4264</MinScaleDenominator>
<LineSymbolizer stroke="#888" stroke-width="0.8"/>
</Rule>
<Rule>
<MaxScaleDenominator>4264</MaxScaleDenominator>
<MinScaleDenominator>0</MinScaleDenominator>
<LineSymbolizer stroke="#888" stroke-width="2.0"/>
</Rule>
</Style>
<Style name="typology_style_period">
<Rule>
<Filter>[typology_style_period] = "43AD-410 (Roman)"</Filter>
<PolygonSymbolizer fill="#FFF739" />
</Rule>
<Rule>
<Filter>[typology_style_period] = "410-1485 (Medieval)"</Filter>
<PolygonSymbolizer fill="#C5BD00" />
</Rule>
<Rule>
<Filter>[typology_style_period] = "1485-1603 (Tudor)"</Filter>
<PolygonSymbolizer fill="#FF9A39" />
</Rule>
<Rule>
<Filter>[typology_style_period] = "1603-1714 (Stuart)"</Filter>
<PolygonSymbolizer fill="#C56000" />
</Rule>
<Rule>
<Filter>[typology_style_period] = "1714-1837 (Georgian)"</Filter>
<PolygonSymbolizer fill="#EA8072" />
</Rule>
<Rule>
<Filter>[typology_style_period] = "1837-1901 (Victorian)"</Filter>
<PolygonSymbolizer fill="#A71200" />
</Rule>
<Rule>
<Filter>[typology_style_period] = "1901-1914 (Edwardian)"</Filter>
<PolygonSymbolizer fill="#A272D4" />
</Rule>
<Rule>
<Filter>[typology_style_period] = "1914-1945 (WWI-WWII)"</Filter>
<PolygonSymbolizer fill="#3988C5" />
</Rule>
<Rule>
<Filter>[typology_style_period] = "1946-1979 (Post war)"</Filter>
<PolygonSymbolizer fill="#5ADFA2" />
</Rule>
<Rule>
<Filter>[typology_style_period] = "1980-1999 (Late 20th Century)"</Filter>
<PolygonSymbolizer fill="#C2F47A" />
</Rule>
<Rule>
<Filter>[typology_style_period] = "2000-2025 (Early 21st Century)"</Filter>
<PolygonSymbolizer fill="#6FB40A" />
</Rule>
<Rule>
<MaxScaleDenominator>17061</MaxScaleDenominator>
<MinScaleDenominator>4264</MinScaleDenominator>
<LineSymbolizer stroke="#888" stroke-width="0.8"/>
</Rule>
<Rule>
<MaxScaleDenominator>4264</MaxScaleDenominator>
<MinScaleDenominator>0</MinScaleDenominator>
<LineSymbolizer stroke="#888" stroke-width="2.0"/>
</Rule>
</Style>
<Style name="typology_dynamic_classification">
<Rule>
<Filter>[typology_dynamic_classification] = "Repetitive small, domestic plots"</Filter>
<PolygonSymbolizer fill="#96484A" />
</Rule>
<Rule>
<Filter>[typology_dynamic_classification] = "Linear non-domestic, i.e. high streets"</Filter>
<PolygonSymbolizer fill="#4B9889" />
</Rule>
<Rule>
<Filter>[typology_dynamic_classification] = "Large plots with internal roads"</Filter>
<PolygonSymbolizer fill="#4F8DA8" />
</Rule>
<Rule>
<Filter>[typology_dynamic_classification] = "Other"</Filter>
<PolygonSymbolizer fill="#897A5D" />
</Rule>
<Rule>
<MaxScaleDenominator>17061</MaxScaleDenominator>
<MinScaleDenominator>4264</MinScaleDenominator>
<LineSymbolizer stroke="#888" stroke-width="0.8"/>
</Rule>
<Rule>
<MaxScaleDenominator>4264</MaxScaleDenominator>
<MinScaleDenominator>0</MinScaleDenominator>
<LineSymbolizer stroke="#888" stroke-width="2.0"/>
</Rule>
</Style>
</Map>

246
app/package-lock.json generated
View File

@ -128,9 +128,9 @@
}
},
"node_modules/@babel/core/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@ -196,9 +196,9 @@
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@ -264,9 +264,9 @@
}
},
"node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"peer": true,
"bin": {
@ -1664,9 +1664,9 @@
}
},
"node_modules/@babel/plugin-transform-runtime/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"peer": true,
"bin": {
@ -1895,9 +1895,9 @@
}
},
"node_modules/@babel/preset-env/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"peer": true,
"bin": {
@ -4099,9 +4099,9 @@
}
},
"node_modules/babel-plugin-istanbul/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@ -4138,9 +4138,9 @@
}
},
"node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"peer": true,
"bin": {
@ -6160,9 +6160,9 @@
}
},
"node_modules/default-gateway/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"bin": {
"semver": "bin/semver"
@ -6994,9 +6994,9 @@
}
},
"node_modules/eslint-plugin-react/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@ -9776,9 +9776,9 @@
}
},
"node_modules/istanbul-lib-instrument/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@ -10747,9 +10747,9 @@
}
},
"node_modules/make-dir/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
@ -11523,9 +11523,9 @@
}
},
"node_modules/normalize-package-data/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"bin": {
"semver": "bin/semver"
@ -15234,9 +15234,9 @@
}
},
"node_modules/react-dev-utils/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"bin": {
"semver": "bin/semver"
@ -16217,9 +16217,9 @@
}
},
"node_modules/sane/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"bin": {
"semver": "bin/semver"
@ -16363,9 +16363,9 @@
}
},
"node_modules/semver": {
"version": "7.3.8",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"dependencies": {
"lru-cache": "^6.0.0"
},
@ -18206,9 +18206,9 @@
}
},
"node_modules/tiny-async-pool/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"bin": {
"semver": "bin/semver"
@ -18311,23 +18311,24 @@
}
},
"node_modules/tough-cookie": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz",
"integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==",
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
"dev": true,
"dependencies": {
"psl": "^1.1.33",
"punycode": "^2.1.1",
"universalify": "^0.1.2"
"universalify": "^0.2.0",
"url-parse": "^1.5.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/tough-cookie/node_modules/universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
"dev": true,
"engines": {
"node": ">= 4.0.0"
@ -19636,9 +19637,9 @@
}
},
"node_modules/webpack-dev-server/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@ -20144,9 +20145,9 @@
}
},
"node_modules/word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
@ -20356,9 +20357,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true
}
}
@ -20408,9 +20409,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true
}
}
@ -20460,9 +20461,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"peer": true
}
@ -21429,9 +21430,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"peer": true
}
@ -21605,9 +21606,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"peer": true
}
@ -23391,9 +23392,9 @@
}
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true
}
}
@ -23423,9 +23424,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"peer": true
}
@ -24995,9 +24996,9 @@
"dev": true
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true
},
"shebang-command": {
@ -25705,9 +25706,9 @@
}
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true
}
}
@ -27756,9 +27757,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true
}
}
@ -28521,9 +28522,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
}
}
},
@ -29127,9 +29128,9 @@
},
"dependencies": {
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true
}
}
@ -31910,9 +31911,9 @@
}
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true
},
"strip-ansi": {
@ -32690,9 +32691,9 @@
"dev": true
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true
},
"shebang-command": {
@ -32809,9 +32810,9 @@
}
},
"semver": {
"version": "7.3.8",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"requires": {
"lru-cache": "^6.0.0"
}
@ -34294,9 +34295,9 @@
},
"dependencies": {
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true
}
}
@ -34379,20 +34380,21 @@
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
},
"tough-cookie": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz",
"integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==",
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
"dev": true,
"requires": {
"psl": "^1.1.33",
"punycode": "^2.1.1",
"universalify": "^0.1.2"
"universalify": "^0.2.0",
"url-parse": "^1.5.3"
},
"dependencies": {
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
"dev": true
}
}
@ -35535,9 +35537,9 @@
}
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true
},
"sockjs-client": {
@ -35831,9 +35833,9 @@
}
},
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
"dev": true
},
"worker-rpc": {

View File

@ -59,6 +59,10 @@ export const buildingAttributesConfig = valueType<DataFieldConfig>()({ /* eslint
edit: true,
verify: true,
},
location_name_link: {
edit: true,
verify: true,
},
location_number: {
edit: true,
verify: true,
@ -103,6 +107,10 @@ export const buildingAttributesConfig = valueType<DataFieldConfig>()({ /* eslint
edit: true,
verify: true
},
location_alternative_footprint_links: {
edit: true,
verify: true
},
date_year: {
edit: true,
verify: true,
@ -126,6 +134,14 @@ export const buildingAttributesConfig = valueType<DataFieldConfig>()({ /* eslint
edit: true,
verify: true,
},
date_source_type: {
edit: true,
verify: true,
},
date_source_links: {
edit: true,
verify: true,
},
facade_year: {
edit: true,
verify: true,
@ -254,6 +270,14 @@ export const buildingAttributesConfig = valueType<DataFieldConfig>()({ /* eslint
edit: true,
verify: true,
},
construction_core_material_source_type: {
edit: true,
verify: true,
},
construction_core_material_source_links: {
edit: true,
verify: true,
},
construction_secondary_materials: {
edit: false,
},
@ -261,6 +285,116 @@ export const buildingAttributesConfig = valueType<DataFieldConfig>()({ /* eslint
edit: true,
verify: true,
},
construction_roof_covering_source_type: {
edit: true,
verify: true,
},
construction_roof_covering_source_links: {
edit: true,
verify: true,
},
construction_structural_system: {
edit: true,
verify: true,
},
construction_structural_system_source_type: {
edit: true,
verify: true,
},
construction_structural_system_source_links: {
edit: true,
verify: true,
},
construction_foundation: {
edit: true,
verify: true,
},
construction_foundation_source_type: {
edit: true,
verify: true,
},
construction_foundation_source_links: {
edit: true,
verify: true,
},
construction_roof_shape: {
edit: true,
verify: true,
},
construction_roof_shape_source_type: {
edit: true,
verify: true,
},
construction_roof_shape_source_links: {
edit: true,
verify: true,
},
construction_irregularities: {
edit: true,
verify: true,
},
construction_irregularities_source_type: {
edit: true,
verify: true,
},
construction_irregularities_source_links: {
edit: true,
verify: true,
},
construction_decorative_features: {
edit: true,
verify: true,
},
construction_decorative_feature_materials: {
edit: true,
verify: true,
},
construction_decorative_feature_source_type: {
edit: true,
verify: true,
},
construction_decorative_feature_source_links: {
edit: true,
verify: true,
},
construction_external_wall: {
edit: true,
verify: true,
},
construction_external_wall_source_type: {
edit: true,
verify: true,
},
construction_external_wall_source_links: {
edit: true,
verify: true,
},
construction_internal_wall: {
edit: true,
verify: true,
},
construction_internal_wall_source_type: {
edit: true,
verify: true,
},
construction_internal_wall_source_links: {
edit: true,
verify: true,
},
construction_ground_floor: {
edit: true,
verify: true,
},
construction_ground_floor_source_type: {
edit: true,
verify: true,
},
construction_ground_floor_source_links: {
edit: true,
verify: true,
},
planning_portal_link: {
edit: true,
verify: true,
@ -277,10 +411,22 @@ export const buildingAttributesConfig = valueType<DataFieldConfig>()({ /* eslint
edit: true,
verify: true,
},
planning_crowdsourced_site_completion_source_type: {
edit: true,
verify: true,
},
planning_crowdsourced_site_completion_source_links: {
edit: true,
verify: true,
},
planning_crowdsourced_planning_id: {
edit: true,
verify: true,
},
planning_in_conservation_area: {
edit: true,
verify: true,
},
planning_in_conservation_area_id: {
edit: true,
verify: true,
@ -301,6 +447,10 @@ export const buildingAttributesConfig = valueType<DataFieldConfig>()({ /* eslint
edit: true,
verify: true,
},
planning_world_heritage_site: {
edit: true,
verify: true,
},
planning_world_list_id: {
edit: true,
verify: true,
@ -309,14 +459,26 @@ export const buildingAttributesConfig = valueType<DataFieldConfig>()({ /* eslint
edit: true,
verify: true,
},
planning_in_apa: {
edit: true,
verify: true,
},
planning_in_apa_url: {
edit: true,
verify: true,
},
planning_local_list: {
edit: true,
verify: true,
},
planning_local_list_url: {
edit: true,
verify: true,
},
planning_historic_area_assessment: {
edit: true,
verify: true,
},
planning_historic_area_assessment_url: {
edit: true,
verify: true,
@ -325,6 +487,30 @@ export const buildingAttributesConfig = valueType<DataFieldConfig>()({ /* eslint
edit: true,
verify: true,
},
planning_missing_data: {
edit: true,
verify: true,
},
planning_missing_data_links: {
edit: true,
verify: true,
},
planning_heritage_at_risk: {
edit: true,
verify: true,
},
planning_scientific_interest: {
edit: true,
verify: true,
},
planning_scientific_interest_source_type: {
edit: true,
verify: true,
},
planning_scientific_interest_source_links: {
edit: true,
verify: true,
},
sust_breeam_rating: {
edit: true,
verify: true,
@ -355,6 +541,14 @@ export const buildingAttributesConfig = valueType<DataFieldConfig>()({ /* eslint
edit: true,
verify: true,
},
building_attachment_source_type: {
edit: true,
verify: true,
},
building_attachment_source_links: {
edit: true,
verify: true,
},
date_change_building_use: {
edit: true,
},
@ -482,6 +676,10 @@ export const buildingAttributesConfig = valueType<DataFieldConfig>()({ /* eslint
edit: true,
verify: true
},
developer_links: {
edit: true,
verify: true
},
developer_source_type: {
edit: true,
verify: true
@ -494,6 +692,10 @@ export const buildingAttributesConfig = valueType<DataFieldConfig>()({ /* eslint
edit: true,
verify: true
},
landowner_links: {
edit: true,
verify: true
},
landowner_source_type: {
edit: true,
verify: true
@ -506,6 +708,10 @@ export const buildingAttributesConfig = valueType<DataFieldConfig>()({ /* eslint
edit: true,
verify: true
},
designers_links: {
edit: true,
verify: true
},
designers_source_type: {
edit: true,
verify: true
@ -530,6 +736,10 @@ export const buildingAttributesConfig = valueType<DataFieldConfig>()({ /* eslint
edit: true,
verify: true
},
builder_links: {
edit: true,
verify: true
},
builder_source_type: {
edit: true,
verify: true
@ -685,7 +895,95 @@ export const buildingAttributesConfig = valueType<DataFieldConfig>()({ /* eslint
age_retrofit_date_source_links : {
edit: true,
verify: true
}
},
age_historical_raster_map_links : {
edit: true,
verify: true
},
age_historical_vectorised_footprint_links : {
edit: true,
verify: true
},
energy_solar : {
edit: true,
verify: true
},
energy_solar_source_type : {
edit: true,
verify: true
},
energy_solar_source_links : {
edit: true,
verify: true
},
energy_green_roof : {
edit: true,
verify: true
},
energy_green_roof_source_type : {
edit: true,
verify: true
},
energy_green_roof_source_links : {
edit: true,
verify: true
},
typology_classification : {
edit: true,
verify: true
},
typology_classification_source_type : {
edit: true,
verify: true
},
typology_classification_source_links: {
edit: true,
verify: true
},
typology_style_period : {
edit: true,
verify: true
},
typology_style_period_source_type : {
edit: true,
verify: true
},
typology_style_period_source_links: {
edit: true,
verify: true
},
typology_dynamic_classification : {
edit: true,
verify: true
},
typology_dynamic_classification_source_type : {
edit: true,
verify: true
},
typology_dynamic_classification_source_links: {
edit: true,
verify: true
},
typology_original_use : {
edit: true,
derivedEdit: true,
verify: true
},
typology_original_use_verified: {
edit: true,
},
typology_original_use_order : {
edit: true,
verify: true
},
typology_original_use_source_type : {
edit: true,
verify: true
},
typology_original_use_source_links: {
edit: true,
verify: true
},
});

View File

@ -10,6 +10,7 @@ type GetAutofillOptionsFn = (value: string, all?: boolean) => Promise<AutofillOp
const autofillFunctionMap : { [fieldName: string] : GetAutofillOptionsFn } = {
current_landuse_group: getLanduseGroupOptions,
typology_original_use: getLanduseGroupOptions,
};
@ -20,6 +21,7 @@ function getLanduseGroupOptions(value: string, all: boolean = false) {
landuse_id AS id,
description AS value
FROM reference_tables.buildings_landuse_group
ORDER BY description
`
);
}

View File

@ -9,7 +9,7 @@ import { ArgumentError } from '../../errors/general';
import { updateLandUse } from './landUse';
/**
* Process land use classifications - derive land use order from land use groups
* Process current land use classifications - derive land use order from land use groups
*/
async function processCurrentLandUseClassifications(
buildingId: number,
@ -40,6 +40,37 @@ async function processCurrentLandUseClassifications(
}
}
/**
* Process original land use classifications - derive land use order from land use groups
*/
async function processOriginalLandUseClassifications(
buildingId: number,
buildingUpdate: Partial<BuildingAttributes>,
t?: ITask<any>
): Promise<any> {
const currentBuildingData = await getBuildingData(buildingId);
try {
const currentLandUseUpdate = await updateLandUse(
{
landUseGroup: currentBuildingData.typology_original_use,
landUseOrder: currentBuildingData.typology_original_use_order
}, {
landUseGroup: buildingUpdate.typology_original_use
}
);
return Object.assign({}, buildingUpdate, {
typology_original_use: currentLandUseUpdate.landUseGroup,
typology_original_use_order: currentLandUseUpdate.landUseOrder,
});
} catch (error) {
if(error instanceof ArgumentError && error.argumentName === 'landUseUpdate') {
error.argumentName = 'buildingUpdate';
}
throw error;
}
}
/**
* Process Dynamics data - check field relationships and sort demolished buildings by construction date
@ -81,6 +112,9 @@ export async function processBuildingUpdate(buildingId: number, {attributes, use
if(hasAnyOwnProperty(attributes, ['current_landuse_group'])) {
attributes = await processCurrentLandUseClassifications(buildingId, attributes, t);
}
if(hasAnyOwnProperty(attributes, ['typology_original_use'])) {
attributes = await processOriginalLandUseClassifications(buildingId, attributes, t);
}
if(hasAnyOwnProperty(attributes, ['demolished_buildings', 'dynamics_has_demolished_buildings'])) {
attributes = await processDynamicsDemolishedBuildings(buildingId, attributes, t);
}

View File

@ -1,7 +1,9 @@
{
"cityName": "Cities",
"projectBlurb": "Colouring {City Name} is part Colouring Cities.",
"githubURL": "https://github.com/colouring-cities/colouring-core",
"manualURL": "https://github.com/colouring-cities/manual/wiki/M3.-COLOURING-BRITAIN",
"privacyStatement": "{Privacy statement goes here}",
"initialMapPosition": [ 51.5245255, -0.1338422 ],

View File

@ -1,8 +1,12 @@
import { StringNullableChain } from "lodash";
export interface CCConfig
{
cityName: string; // City name (i.e. "Colouring {City Name}")
projectBlurb: string; // Description used on homepage
githubURL: string; // URL of the project's GitHub repository
manualURL: string; // Link to the project's page in the Open Manual (i.e. https://github.com/colouring-cities/manual/wiki/M3.-COLOURING-BRITAIN)
privacyStatement: string; // Privacy statement, including where data is stored
initialMapPosition: [number, number]; // Initial location of the map [latitude, longitude]

View File

@ -76,6 +76,12 @@ export const MultiDataEntry: React.FC<MultiDataEntryProps> = ({
</div>
}
<ul className="data-entry-list">
{
isEditing && isDisabled && values.length === 0 &&
<div className="input-group">
<input className="form-control no-entries" type="text" value="Please add a link below" disabled={true} />
</div>
}
{
values.map((val, i) => (
<li className="input-group" key={i /* i as key prevents input component recreation on edit */}>

View File

@ -12,11 +12,20 @@ interface PatternDataEntryProps extends BaseDataEntryProps {
*/
pattern: string;
maxLength?: number;
valueTransform?: (val: string) => string;
}
export const PatternDataEntry: React.FC<PatternDataEntryProps> = props => {
const handleChange = (value: string) => {
props.onChange?.(props.slug, value);
props.onChange?.(props.slug, transformValue(value));
};
const transformValue = (value: string) => {
const transform = props.valueTransform || (x => x);
const transformedValue = value === '' ?
null :
transform(value);
return transformedValue;
};
return (

View File

@ -99,7 +99,9 @@ const withCopyEdit: (wc: React.ComponentType<CategoryViewProps>) => DataContaine
'likes_total',
'community_type_worth_keeping_total',
'community_local_significance_total',
'community_expected_planning_application_total'
'community_expected_planning_application_total',
'typology_original_use',
'typology_original_use_verified'
]
for (let key in dataFields) {
let fieldName = props.building == undefined ? undefined : props.building[key];
@ -286,6 +288,13 @@ const withCopyEdit: (wc: React.ComponentType<CategoryViewProps>) => DataContaine
this.doSubmit(edits);
}
if (slug == 'typology_original_use'){
const edits = {
'typology_original_use_verified': true
};
this.doSubmit(edits);
}
console.log(slug + " verify button clicked")
}

View File

@ -1,7 +1,7 @@
import React, { Fragment } from 'react';
import '../../map/map-button.css';
import { dataFields } from '../../config/data-fields-config';
import { commonSourceTypes, dataFields } from '../../config/data-fields-config';
import { MultiDataEntry } from '../data-components/multi-data-entry/multi-data-entry';
import { DataEntryGroup } from '../data-components/data-entry-group';
import { DynamicsBuildingPane, DynamicsDataEntry } from './dynamics/dynamics-data-entry';
@ -40,27 +40,49 @@ const AgeView: React.FunctionComponent<CategoryViewProps> = (props) => {
const ageLinkUrl = `/${props.mode}/${Category.Age}/${props.building.building_id}`;
const { historicData, historicDataSwitchOnClick, darkLightTheme } = useDisplayPreferences();
const { historicMap, historicMapSwitchOnClick } = useDisplayPreferences();
const switchToSurvivalMapStyle = (e) => {
e.preventDefault();
props.onMapColourScale('survival_status');
historicMapSwitchOnClick(e);
if (props.mapColourScale == "survival_status") {
props.onMapColourScale('date_year');
if (historicData === 'enabled') {
historicDataSwitchOnClick(e);
}
else {
}
const switchToSurvivalDataStyle = (e) => {
e.preventDefault();
props.onMapColourScale('survival_status');
historicDataSwitchOnClick(e);
if (historicMap === 'enabled') {
historicMapSwitchOnClick(e);
}
}
if (props.building.date_source == "Expert knowledge of building" ||
props.building.date_source == "Expert estimate from image" ||
props.building.date_source == null
){
const switchToAgeMapStyle = (e) => {
e.preventDefault();
if (historicData === 'enabled') {
historicDataSwitchOnClick(e);
}
if (historicMap === 'enabled') {
historicMapSwitchOnClick(e);
}
props.onMapColourScale('date_year');
}
const switchToStylePeriodMapStyle = (e) => {
e.preventDefault();
props.onMapColourScale('typology_style_period')
}
return (
<Fragment>
<DataEntryGroup name="Building age">
<DataEntryGroup name="Building age/construction date">
<YearDataEntry
year={props.building.date_year}
upper={props.building.date_upper}
@ -107,7 +129,7 @@ const AgeView: React.FunctionComponent<CategoryViewProps> = (props) => {
user_verified_as={props.user_verified.facade_year}
verified_count={props.building.verified.facade_year}
/>
<hr/>
<SelectDataEntry
title={dataFields.date_source.title}
slug="date_source"
@ -116,8 +138,8 @@ const AgeView: React.FunctionComponent<CategoryViewProps> = (props) => {
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.date_source.tooltip}
placeholder={dataFields.date_source.example}
options={dataFields.date_source.items}
placeholder={dataFields.date_source.example}
/>
{(props.building.date_source == dataFields.date_source.items[0] ||
props.building.date_source == dataFields.date_source.items[1] ||
@ -137,6 +159,101 @@ const AgeView: React.FunctionComponent<CategoryViewProps> = (props) => {
/>
</>
}
<hr/>
<SelectDataEntry
title={dataFields.date_source_type.title}
slug="date_source_type"
value={props.building.date_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.date_source_type.tooltip}
options={dataFields.date_source_type.items}
placeholder={dataFields.date_source_type.example}
/>
{(props.building.date_source_type == dataFields.date_source_type.items[0] ||
props.building.date_source_type == dataFields.date_source_type.items[1] ||
props.building.date_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.date_source_links.title}
slug="date_source_links"
value={props.building.date_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.date_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
{/*<DataEntry
title="Year of completion (best estimate)"
slug=""
value=""
mode='view'
tooltip='Coming Soon'
/>*/}
</DataEntryGroup>
<DataEntryGroup name="Architectural style">
{(props.mapColourScale == "typology_style_period") ?
<button className={`map-switcher-inline enabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToAgeMapStyle}>
Click here to return to building age.
</button>
:
<button className={`map-switcher-inline disabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToStylePeriodMapStyle}>
Click here to show architectural style.
</button>
}
<SelectDataEntry
title={dataFields.typology_style_period.title}
slug="typology_style_period"
value={props.building.typology_style_period}
tooltip={dataFields.typology_style_period.tooltip}
options={dataFields.typology_style_period.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
/>
<Verification
slug="typology_style_period"
allow_verify={props.user !== undefined && props.building.typology_style_period !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("typology_style_period")}
user_verified_as={props.user_verified.typology_style_period}
verified_count={props.building.verified.typology_style_period}
/>
<SelectDataEntry
title={dataFields.typology_style_period_source_type.title}
slug="typology_style_period_source_type"
value={props.building.typology_style_period_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.typology_style_period_source_type.tooltip}
placeholder={dataFields.typology_style_period_source_type.example}
options={dataFields.typology_style_period_source_type.items}
/>
{(props.building.typology_style_period_source_type == commonSourceTypes[0] ||
props.building.typology_style_period_source_type == commonSourceTypes[1] ||
props.building.typology_style_period_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.typology_style_period_source_links.title}
slug="typology_style_period_source_links"
value={props.building.typology_style_period_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.typology_style_period_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</DataEntryGroup>
<DataEntryGroup name="Cladding, extensions and retrofits">
<NumericDataEntry
@ -290,9 +407,6 @@ const AgeView: React.FunctionComponent<CategoryViewProps> = (props) => {
}
</DataEntryGroup>
<DataEntryGroup name="Lifespan and site history">
<button className={`map-switcher-inline ${props.mapColourScale == "survival_status" ? "enabled-state" : "disabled-state"} btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToSurvivalMapStyle}>
{(props.mapColourScale == "is_domestic")? 'Click here to hide historical maps':'Click here to show historical maps'}
</button>
<DataEntryGroup name="Constructions and demolitions on this site" showCount={false}>
<DynamicsBuildingPane>
<label>Current building (age data <Link to={ageLinkUrl}>editable here</Link>)</label>
@ -379,388 +493,31 @@ const AgeView: React.FunctionComponent<CategoryViewProps> = (props) => {
Please let us know your suggestions on the <a href="https://discuss.colouring.london/t/dynamics-category-discussion/107">discussion forum</a>! (external link - save your edits first)
</InfoBox>
</DataEntryGroup>
<DataEntryGroup name="Survival and loss tracked using historical maps" collapsed={true} >
<DataEntryGroup name="Survival tracking" collapsed={true} >
<div className={`alert alert-dark`} role="alert" style={{ fontSize: 13, backgroundColor: "#f6f8f9" }}>
<i>
Can you help us create a map that shows how many buildings in London have survived since the 1890s?
Choose a colour to indicate whether the building has survived.
</i>
</div>
<button className={`map-switcher-inline ${props.mapColourScale == "survival_status" ? "enabled-state" : "disabled-state"} btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToSurvivalMapStyle}>
{(props.mapColourScale == "is_domestic")? 'Click here to hide historical maps':'Click here to show historical maps'}
{(historicMap === "enabled") ?
<button className={`map-switcher-inline enabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToAgeMapStyle}>
Click here to hide the 1890s OS historical map.
</button>
<SelectDataEntry
title={dataFields.survival_status.title}
slug="survival_status"
value={props.building.survival_status}
tooltip={dataFields.survival_status.tooltip}
options={SurvivalStatusOptions}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
/>
<SelectDataEntry
title={dataFields.survival_source.title}
slug="survival_source"
value={props.building.survival_source}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.survival_source.tooltip}
placeholder={dataFields.survival_source.example}
options={dataFields.survival_source.items}
/>
{(props.building.survival_source == dataFields.survival_source_links[0] ||
props.building.survival_source == dataFields.survival_source_links[1] ||
props.building.survival_source == null) ? <></> :
<><MultiDataEntry
title={dataFields.survival_source_links.title}
slug="survival_source_links"
value={props.building.survival_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.survival_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</DataEntryGroup>
</Fragment>
);
};
return (
<Fragment>
<DataEntryGroup name="Building age">
<YearDataEntry
year={props.building.date_year}
upper={props.building.date_upper}
lower={props.building.date_lower}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
allow_verify={props.user !== undefined && props.building.date_year !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("date_year")}
user_verified_as={props.user_verified.date_year}
verified_count={props.building.verified.date_year}
allow_verify_upper={props.user !== undefined && props.building.date_upper !== null && !props.edited}
onVerify_upper={props.onVerify}
user_verified_upper={props.user_verified.hasOwnProperty("date_upper")}
user_verified_as_upper={props.user_verified.date_upper}
verified_count_upper={props.building.verified.date_upper}
allow_verify_lower={props.user !== undefined && props.building.date_lower !== null && !props.edited}
onVerify_lower={props.onVerify}
user_verified_lower={props.user_verified.hasOwnProperty("date_lower")}
user_verified_as_lower={props.user_verified.date_lower}
verified_count_lower={props.building.verified.date_lower}
/>
<NumericDataEntry
title={dataFields.facade_year.title}
slug="facade_year"
value={props.building.facade_year}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
step={1}
min={1}
max={currentYear}
tooltip={dataFields.facade_year.tooltip}
/>
<Verification
slug="facade_year"
allow_verify={props.user !== undefined && props.building.facade_year !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("facade_year")}
user_verified_as={props.user_verified.facade_year}
verified_count={props.building.verified.facade_year}
/>
<SelectDataEntry
title={dataFields.date_source.title}
slug="date_source"
value={props.building.date_source}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.date_source.tooltip}
options={dataFields.date_source.items}
placeholder={dataFields.date_source.example}
/>
{(props.building.date_source == dataFields.date_source.items[0] ||
props.building.date_source == dataFields.date_source.items[1] ||
props.building.date_source == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.date_link.title}
slug="date_link"
value={props.building.date_link}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.date_link.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</DataEntryGroup>
<DataEntryGroup name="Cladding, extensions and retrofits">
<NumericDataEntry
slug='age_cladding_date'
title={dataFields.age_cladding_date.title}
value={props.building.age_cladding_date}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
step={1}
min={1}
max={currentYear}
tooltip={dataFields.extension_year.tooltip}
/>
<Verification
slug="age_cladding_date"
allow_verify={props.user !== undefined && props.building.age_cladding_date !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("age_cladding_date")}
user_verified_as={props.user_verified.age_cladding_date}
verified_count={props.building.verified.age_cladding_date}
/>
<SelectDataEntry
title={dataFields.age_cladding_date_source_type.title}
slug="age_cladding_date_source_type"
value={props.building.age_cladding_date_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.age_cladding_date_source_type.tooltip}
options={dataFields.age_cladding_date_source_type.items}
placeholder={dataFields.age_cladding_date_source_type.example}
/>
{(props.building.age_cladding_date_source_type == dataFields.age_cladding_date_source_type.items[0] ||
props.building.age_cladding_date_source_type == dataFields.age_cladding_date_source_type.items[1] ||
props.building.age_cladding_date_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.age_cladding_date_source_links.title}
slug="age_cladding_date_source_links"
value={props.building.age_cladding_date_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.age_cladding_date_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
<hr/>
<NumericDataEntry
slug='age_extension_date'
title={dataFields.age_extension_date.title}
value={props.building.age_extension_date}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
step={1}
min={1}
max={currentYear}
tooltip={dataFields.extension_year.tooltip}
/>
<Verification
slug="age_extension_date"
allow_verify={props.user !== undefined && props.building.age_extension_date !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("age_extension_date")}
user_verified_as={props.user_verified.age_extension_date}
verified_count={props.building.verified.age_extension_date}
/>
<SelectDataEntry
title={dataFields.age_extension_date_source_type.title}
slug="age_extension_date_source_type"
value={props.building.age_extension_date_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.age_extension_date_source_type.tooltip}
options={dataFields.age_extension_date_source_type.items}
placeholder={dataFields.age_extension_date_source_type.example}
/>
{(props.building.age_extension_date_source_type == dataFields.age_extension_date_source_type.items[0] ||
props.building.age_extension_date_source_type == dataFields.age_extension_date_source_type.items[1] ||
props.building.age_extension_date_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.age_extension_date_source_links.title}
slug="age_extension_date_source_links"
value={props.building.age_extension_date_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.age_extension_date_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
<hr/>
<NumericDataEntry
slug='age_retrofit_date'
title={dataFields.age_retrofit_date.title}
value={props.building.age_retrofit_date}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
step={1}
min={1}
max={currentYear}
tooltip={dataFields.extension_year.tooltip}
/>
<Verification
slug="age_retrofit_date"
allow_verify={props.user !== undefined && props.building.age_retrofit_date !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("age_retrofit_date")}
user_verified_as={props.user_verified.age_retrofit_date}
verified_count={props.building.verified.age_retrofit_date}
/>
<SelectDataEntry
title={dataFields.age_retrofit_date_source_type.title}
slug="age_retrofit_date_source_type"
value={props.building.age_retrofit_date_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.age_retrofit_date_source_type.tooltip}
options={dataFields.age_retrofit_date_source_type.items}
placeholder={dataFields.age_retrofit_date_source_type.example}
/>
{(props.building.age_retrofit_date_source_type == dataFields.age_retrofit_date_source_type.items[0] ||
props.building.age_retrofit_date_source_type == dataFields.age_retrofit_date_source_type.items[1] ||
props.building.age_retrofit_date_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.age_retrofit_date_source_links.title}
slug="age_retrofit_date_source_links"
value={props.building.age_retrofit_date_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.age_retrofit_date_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</DataEntryGroup>
<DataEntryGroup name="Lifespan and site history">
<button className={`map-switcher-inline ${props.mapColourScale == "survival_status" ? "enabled-state" : "disabled-state"} btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToSurvivalMapStyle}>
{(props.mapColourScale == "is_domestic")? 'Click here to hide historical maps':'Click here to show historical maps'}
:
<button className={`map-switcher-inline disabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToSurvivalMapStyle}>
Click here to show the 1890s OS historical map.
</button>
<DataEntryGroup name="Constructions and demolitions on this site" showCount={false}>
<DynamicsBuildingPane>
<label>Current building (age data <Link to={ageLinkUrl}>editable here</Link>)</label>
<FieldRow>
<div>
<NumericDataEntry
slug=''
title={dataFields.demolished_buildings.items.year_constructed.title}
value={currentBuildingConstructionYear}
disabled={true}
mode='view'
/>
</div>
<div>
<NumericDataEntry
slug=''
title={dataFields.demolished_buildings.items.year_demolished.title}
value={undefined}
placeholder='---'
disabled={true}
mode='view'
/>
</div>
<div style={{flex: '0 1 27%'}}>
<DataEntry
slug=''
title='Lifespan to date'
value={ (thisYear - currentBuildingConstructionYear) + ''}
disabled={true}
mode='view'
/>
</div>
</FieldRow>
</DynamicsBuildingPane>
{
currentBuildingConstructionYear == undefined ?
<InfoBox>To add historical records, fill in the <Link to={ageLinkUrl}>Age</Link> data first.</InfoBox> :
<>
<LogicalDataEntry
slug='dynamics_has_demolished_buildings'
title={dataFields.dynamics_has_demolished_buildings.title}
value={building.dynamics_has_demolished_buildings}
disallowFalse={(building.demolished_buildings?.length ?? 0) > 0}
disallowNull={(building.demolished_buildings?.length ?? 0) > 0}
onChange={props.onSaveChange}
mode={props.mode}
copy={props.copy}
/>
{
building.dynamics_has_demolished_buildings &&
<>
<DynamicsDataEntry
/*
Will clear the edits and new record data upon navigating to another building.
Should get a better way to do this, plus a way to actually keep unsaved edits.
*/
key={building.building_id}
value={building.demolished_buildings}
editableEntries={true}
slug='demolished_buildings'
title={dataFields.demolished_buildings.title}
mode={props.mode}
onChange={props.onChange}
onSaveAdd={props.onSaveAdd}
hasEdits={props.edited}
maxYear={currentBuildingConstructionYear}
minYear={50}
/>
{
props.mode === 'view' &&
<InfoBox>Switch to edit mode to add/edit past building records</InfoBox>
}
</>
}
</>
}
</DataEntryGroup>
<InfoBox type='warning'>
This section is under development in collaboration with the historic environment sector.
Please let us know your suggestions on the <a href="https://discuss.colouring.london/t/dynamics-category-discussion/107">discussion forum</a>! (external link - save your edits first)
</InfoBox>
</DataEntryGroup>
<DataEntryGroup name="Survival and loss tracked using historical maps" collapsed={true} >
<div className={`alert alert-dark`} role="alert" style={{ fontSize: 13, backgroundColor: "#f6f8f9" }}>
<i>
Can you help us create a map that shows how many buildings in London have survived since the 1890s?
Choose a colour to indicate whether the building has survived.
</i>
</div>
<button className={`map-switcher-inline ${props.mapColourScale == "survival_status" ? "enabled-state" : "disabled-state"} btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToSurvivalMapStyle}>
{(props.mapColourScale == "is_domestic")? 'Click here to hide historical maps':'Click here to show historical maps'}
{(historicData === "enabled") ?
<button className={`map-switcher-inline enabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToAgeMapStyle}>
Click here to hide the 1890s OS historical map with modern footprints.
</button>
:
<button className={`map-switcher-inline disabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToSurvivalDataStyle}>
Click here to show the 1890s OS historical map with modern footprints.
</button>
}
<SelectDataEntry
title={dataFields.survival_status.title}
slug="survival_status"
@ -800,6 +557,40 @@ const AgeView: React.FunctionComponent<CategoryViewProps> = (props) => {
</>
}
</DataEntryGroup>
<DataEntryGroup name="Historical map data options" collapsed={true} >
<InfoBox type='warning'>
This section is under development
</InfoBox>
<div className={`alert alert-dark`} role="alert" style={{ fontSize: 13, backgroundColor: "#f6f8f9" }}>
<i>
This section provides links to open digitised historical maps/mapping data that we are using in the Colouring Cities platform.
</i>
</div>
<MultiDataEntry
title={dataFields.age_historical_raster_map_links.title}
slug="age_historical_raster_map_links"
value={props.building.age_historical_raster_map_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.age_historical_raster_map_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
<MultiDataEntry
title={dataFields.age_historical_vectorised_footprint_links.title}
slug="age_historical_vectorised_footprint_links"
value={props.building.age_historical_vectorised_footprint_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.age_historical_vectorised_footprint_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</DataEntryGroup>
</Fragment>
);
};

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { Fragment } from 'react';
import '../../map/map-button.css';
import withCopyEdit from '../data-container';
@ -15,6 +15,7 @@ import SelectDataEntry from '../data-components/select-data-entry';
import Verification from '../data-components/verification';
import { MultiDataEntry } from '../data-components/multi-data-entry/multi-data-entry';
import { useDisplayPreferences } from '../../displayPreferences-context';
import DataEntry from '../data-components/data-entry';
/**
* Community view/edit section
@ -38,8 +39,9 @@ const CommunityView: React.FunctionComponent<CategoryViewProps> = (props) => {
}
const { darkLightTheme } = useDisplayPreferences();
const worthKeepingReasonsNonEmpty = Object.values(props.building.community_type_worth_keeping_reasons ?? {}).some(x => x);
return <>
<DataEntryGroup name="Community views on building types">
return (
<Fragment>
<DataEntryGroup name="Community views on how well buildings work">
<div className={`alert alert-dark`} role="alert" style={{ fontSize: 13, backgroundColor: "#f6f8f9" }}>
<i>
Note: We are currently only collecting data on non-residential buildings.
@ -133,6 +135,11 @@ const CommunityView: React.FunctionComponent<CategoryViewProps> = (props) => {
mode={props.mode}
copy={props.copy}
/>
<div className={`alert alert-dark`} role="alert" style={{ fontSize: 13, backgroundColor: "#f6f8f9" }}>
<i>
For more information on current planning applications, refer to the Planning Controls category.
</i>
</div>
{(props.mapColourScale == "community_expected_planning_application_total") ?
<button className={`map-switcher-inline enabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToTypologyMapStyle}>
{'Click to return to liked typologies mapped.'}
@ -144,7 +151,7 @@ const CommunityView: React.FunctionComponent<CategoryViewProps> = (props) => {
}
</div>
</DataEntryGroup>
<DataEntryGroup name="Building use for community activities">
<DataEntryGroup name="Buildings in community use">
<div className={`alert alert-dark`} role="alert" style={{ fontSize: 13, backgroundColor: "#f6f8f9" }}>
<i>
Here we are collecting information on the location of buildings used for community activities so we can track loss of/additions to community space over time.
@ -223,7 +230,8 @@ const CommunityView: React.FunctionComponent<CategoryViewProps> = (props) => {
</button>
}
</DataEntryGroup>
</>
</Fragment>
);
};
const CommunityContainer = withCopyEdit(CommunityView);

View File

@ -1,6 +1,6 @@
import React, { Fragment } from 'react';
import { dataFields } from '../../config/data-fields-config';
import { commonSourceTypes, dataFields } from '../../config/data-fields-config';
import DataEntry from '../data-components/data-entry';
import SelectDataEntry from '../data-components/select-data-entry';
import withCopyEdit from '../data-container';
@ -9,6 +9,8 @@ import Verification from '../data-components/verification';
import { CategoryViewProps } from './category-view-props';
import InfoBox from '../../components/info-box';
import { DataEntryGroup } from '../data-components/data-entry-group';
import { MultiDataEntry } from '../data-components/multi-data-entry/multi-data-entry';
import { LogicalDataEntry } from '../data-components/logical-data-entry/logical-data-entry';
const ConstructionMaterialsOptions = [
'Wood',
@ -21,23 +23,205 @@ const ConstructionMaterialsOptions = [
'Other Man-Made Material'
];
const RoofCoveringOptions = [
'Slate',
'Clay Tile',
'Wood',
'Asphalt',
'Iron or Steel',
'Other Metal',
'Other Natural Material',
'Other Man-Made Material'
];
/**
* Construction view/edit section
*/
const ConstructionView: React.FunctionComponent<CategoryViewProps> = (props) => {
return (
<Fragment>
<DataEntryGroup name="Structural system">
<SelectDataEntry
title={dataFields.construction_structural_system.title}
slug="construction_structural_system"
value={props.building.construction_structural_system}
tooltip={dataFields.construction_structural_system.tooltip}
options={dataFields.construction_structural_system.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
/>
<Verification
slug="construction_structural_system"
allow_verify={props.user !== undefined && props.building.construction_structural_system !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("construction_structural_system")}
user_verified_as={props.user_verified.construction_structural_system}
verified_count={props.building.verified.construction_structural_system}
/>
<SelectDataEntry
title={dataFields.construction_structural_system_source_type.title}
slug="construction_structural_system_source_type"
value={props.building.construction_structural_system_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_structural_system_source_type.tooltip}
placeholder={dataFields.construction_structural_system_source_type.example}
options={dataFields.construction_structural_system_source_type.items}
/>
{(props.building.construction_structural_system_source_type == commonSourceTypes[0] ||
props.building.construction_structural_system_source_type == commonSourceTypes[1] ||
props.building.construction_structural_system_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.construction_structural_system_source_links.title}
slug="construction_structural_system_source_links"
value={props.building.construction_structural_system_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_structural_system_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
<hr/>
<SelectDataEntry
title={dataFields.construction_foundation.title}
slug="construction_foundation"
value={props.building.construction_foundation}
tooltip={dataFields.construction_foundation.tooltip}
options={dataFields.construction_foundation.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
/>
<Verification
slug="construction_foundation"
allow_verify={props.user !== undefined && props.building.construction_foundation !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("construction_foundation")}
user_verified_as={props.user_verified.construction_foundation}
verified_count={props.building.verified.construction_foundation}
/>
<SelectDataEntry
title={dataFields.construction_foundation_source_type.title}
slug="construction_foundation_source_type"
value={props.building.construction_foundation_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_foundation_source_type.tooltip}
placeholder={dataFields.construction_foundation_source_type.example}
options={dataFields.construction_foundation_source_type.items}
/>
{(props.building.construction_foundation_source_type == commonSourceTypes[0] ||
props.building.construction_foundation_source_type == commonSourceTypes[1] ||
props.building.construction_foundation_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.construction_foundation_source_links.title}
slug="construction_foundation_source_links"
value={props.building.construction_foundation_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_foundation_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
<hr/>
<SelectDataEntry
title={dataFields.construction_roof_shape.title}
slug="construction_roof_shape"
value={props.building.construction_roof_shape}
tooltip={dataFields.construction_roof_shape.tooltip}
options={dataFields.construction_roof_shape.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
/>
<Verification
slug="construction_roof_shape"
allow_verify={props.user !== undefined && props.building.construction_roof_shape !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("construction_roof_shape")}
user_verified_as={props.user_verified.construction_roof_shape}
verified_count={props.building.verified.construction_roof_shape}
/>
<SelectDataEntry
title={dataFields.construction_roof_shape_source_type.title}
slug="construction_roof_shape_source_type"
value={props.building.construction_roof_shape_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_roof_shape_source_type.tooltip}
placeholder={dataFields.construction_roof_shape_source_type.example}
options={dataFields.construction_roof_shape_source_type.items}
/>
{(props.building.construction_roof_shape_source_type == commonSourceTypes[0] ||
props.building.construction_roof_shape_source_type == commonSourceTypes[1] ||
props.building.construction_roof_shape_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.construction_roof_shape_source_links.title}
slug="construction_roof_shape_source_links"
value={props.building.construction_roof_shape_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_roof_shape_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
<hr/>
<SelectDataEntry
title={dataFields.construction_irregularities.title}
slug="construction_irregularities"
value={props.building.construction_irregularities}
tooltip={dataFields.construction_irregularities.tooltip}
options={dataFields.construction_irregularities.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
/>
<Verification
slug="construction_irregularities"
allow_verify={props.user !== undefined && props.building.construction_irregularities !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("construction_irregularities")}
user_verified_as={props.user_verified.construction_irregularities}
verified_count={props.building.verified.construction_irregularities}
/>
<SelectDataEntry
title={dataFields.construction_irregularities_source_type.title}
slug="construction_irregularities_source_type"
value={props.building.construction_irregularities_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_irregularities_source_type.tooltip}
placeholder={dataFields.construction_irregularities_source_type.example}
options={dataFields.construction_irregularities_source_type.items}
/>
{(props.building.construction_irregularities_source_type == commonSourceTypes[0] ||
props.building.construction_irregularities_source_type == commonSourceTypes[1] ||
props.building.construction_irregularities_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.construction_irregularities_source_links.title}
slug="construction_irregularities_source_links"
value={props.building.construction_irregularities_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_irregularities_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</DataEntryGroup>
<DataEntryGroup name="Materials">
<SelectDataEntry
title={dataFields.construction_core_material.title}
@ -58,22 +242,185 @@ const ConstructionView: React.FunctionComponent<CategoryViewProps> = (props) =>
verified_count={props.building.verified.construction_core_material}
/>
<SelectDataEntry
title={dataFields.construction_secondary_materials.title}
disabled={true}
slug="construction_secondary_materials"
value={props.building.construction_secondary_materials}
tooltip={dataFields.construction_secondary_materials.tooltip}
options={ConstructionMaterialsOptions}
title={dataFields.construction_core_material_source_type.title}
slug="construction_core_material_source_type"
value={props.building.construction_core_material_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_core_material_source_type.tooltip}
placeholder={dataFields.construction_core_material_source_type.example}
options={dataFields.construction_core_material_source_type.items}
/>
{(props.building.construction_core_material_source_type == commonSourceTypes[0] ||
props.building.construction_core_material_source_type == commonSourceTypes[1] ||
props.building.construction_core_material_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.construction_core_material_source_links.title}
slug="construction_core_material_source_links"
value={props.building.construction_core_material_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_core_material_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
<hr/>
<SelectDataEntry
title={dataFields.construction_external_wall.title}
slug="construction_external_wall"
value={props.building.construction_external_wall}
tooltip={dataFields.construction_external_wall.tooltip}
options={dataFields.construction_external_wall.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
/>
<Verification
slug="construction_external_wall"
allow_verify={props.user !== undefined && props.building.construction_external_wall !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("construction_external_wall")}
user_verified_as={props.user_verified.construction_external_wall}
verified_count={props.building.verified.construction_external_wall}
/>
<SelectDataEntry
title={dataFields.construction_external_wall_source_type.title}
slug="construction_external_wall_source_type"
value={props.building.construction_external_wall_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_external_wall_source_type.tooltip}
placeholder={dataFields.construction_external_wall_source_type.example}
options={dataFields.construction_external_wall_source_type.items}
/>
{(props.building.construction_external_wall_source_type == commonSourceTypes[0] ||
props.building.construction_external_wall_source_type == commonSourceTypes[1] ||
props.building.construction_external_wall_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.construction_external_wall_source_links.title}
slug="construction_external_wall_source_links"
value={props.building.construction_external_wall_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_external_wall_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
<hr/>
<SelectDataEntry
title={dataFields.construction_internal_wall.title}
slug="construction_internal_wall"
value={props.building.construction_internal_wall}
tooltip={dataFields.construction_internal_wall.tooltip}
options={dataFields.construction_internal_wall.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
/>
<Verification
slug="construction_internal_wall"
allow_verify={props.user !== undefined && props.building.construction_internal_wall !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("construction_internal_wall")}
user_verified_as={props.user_verified.construction_internal_wall}
verified_count={props.building.verified.construction_internal_wall}
/>
<SelectDataEntry
title={dataFields.construction_internal_wall_source_type.title}
slug="construction_internal_wall_source_type"
value={props.building.construction_internal_wall_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_internal_wall_source_type.tooltip}
placeholder={dataFields.construction_internal_wall_source_type.example}
options={dataFields.construction_internal_wall_source_type.items}
/>
{(props.building.construction_internal_wall_source_type == commonSourceTypes[0] ||
props.building.construction_internal_wall_source_type == commonSourceTypes[1] ||
props.building.construction_internal_wall_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.construction_internal_wall_source_links.title}
slug="construction_internal_wall_source_links"
value={props.building.construction_internal_wall_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_internal_wall_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
<hr/>
<SelectDataEntry
title={dataFields.construction_ground_floor.title}
slug="construction_ground_floor"
value={props.building.construction_ground_floor}
tooltip={dataFields.construction_ground_floor.tooltip}
options={dataFields.construction_ground_floor.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
/>
<Verification
slug="construction_ground_floor"
allow_verify={props.user !== undefined && props.building.construction_ground_floor !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("construction_ground_floor")}
user_verified_as={props.user_verified.construction_ground_floor}
verified_count={props.building.verified.construction_ground_floor}
/>
<SelectDataEntry
title={dataFields.construction_ground_floor_source_type.title}
slug="construction_ground_floor_source_type"
value={props.building.construction_ground_floor_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_ground_floor_source_type.tooltip}
placeholder={dataFields.construction_ground_floor_source_type.example}
options={dataFields.construction_ground_floor_source_type.items}
/>
{(props.building.construction_ground_floor_source_type == commonSourceTypes[0] ||
props.building.construction_ground_floor_source_type == commonSourceTypes[1] ||
props.building.construction_ground_floor_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.construction_ground_floor_source_links.title}
slug="construction_ground_floor_source_links"
value={props.building.construction_ground_floor_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_ground_floor_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
<hr/>
<SelectDataEntry
title={dataFields.construction_roof_covering.title}
slug="construction_roof_covering"
value={props.building.construction_roof_covering}
tooltip={dataFields.construction_roof_covering.tooltip}
options={RoofCoveringOptions}
options={dataFields.construction_roof_covering.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
@ -86,14 +433,105 @@ const ConstructionView: React.FunctionComponent<CategoryViewProps> = (props) =>
user_verified_as={props.user_verified.construction_roof_covering}
verified_count={props.building.verified.construction_roof_covering}
/>
</DataEntryGroup>
<DataEntryGroup name="Construction sectors">
<DataEntry
title="Construction system type"
slug=""
value=""
mode='view'
<SelectDataEntry
title={dataFields.construction_roof_covering_source_type.title}
slug="construction_roof_covering_source_type"
value={props.building.construction_roof_covering_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_roof_covering_source_type.tooltip}
placeholder={dataFields.construction_roof_covering_source_type.example}
options={dataFields.construction_roof_covering_source_type.items}
/>
{(props.building.construction_roof_covering_source_type == commonSourceTypes[0] ||
props.building.construction_roof_covering_source_type == commonSourceTypes[1] ||
props.building.construction_roof_covering_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.construction_roof_covering_source_links.title}
slug="construction_roof_covering_source_links"
value={props.building.construction_roof_covering_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_roof_covering_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</DataEntryGroup>
<DataEntryGroup name="Decorative features">
<LogicalDataEntry
slug='construction_decorative_features'
title={dataFields.construction_decorative_features.title}
value={props.building.construction_decorative_features}
onChange={props.onSaveChange}
mode={props.mode}
copy={props.copy}
/>
<Verification
slug="construction_decorative_features"
allow_verify={props.user !== undefined && props.building.construction_decorative_features !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("construction_decorative_features")}
user_verified_as={props.user_verified.construction_decorative_features}
verified_count={props.building.verified.construction_decorative_features}
/>
{
props.building.construction_decorative_features &&
<>
<SelectDataEntry
title={dataFields.construction_decorative_feature_materials.title}
slug="construction_decorative_feature_materials"
value={props.building.construction_decorative_feature_materials}
tooltip={dataFields.construction_decorative_feature_materials.tooltip}
options={dataFields.construction_decorative_feature_materials.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
/>
<Verification
slug="construction_decorative_feature_materials"
allow_verify={props.user !== undefined && props.building.construction_decorative_feature_materials !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("construction_decorative_feature_materials")}
user_verified_as={props.user_verified.construction_decorative_feature_materials}
verified_count={props.building.verified.construction_decorative_feature_materials}
/>
<SelectDataEntry
title={dataFields.construction_decorative_feature_source_type.title}
slug="construction_decorative_feature_source_type"
value={props.building.construction_decorative_feature_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_decorative_feature_source_type.tooltip}
placeholder={dataFields.construction_decorative_feature_source_type.example}
options={dataFields.construction_decorative_feature_source_type.items}
/>
{(props.building.construction_decorative_feature_source_type == commonSourceTypes[0] ||
props.building.construction_decorative_feature_source_type == commonSourceTypes[1] ||
props.building.construction_decorative_feature_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.construction_decorative_feature_source_links.title}
slug="construction_decorative_feature_source_links"
value={props.building.construction_decorative_feature_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.construction_decorative_feature_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</>
}
</DataEntryGroup>
</Fragment>
);

View File

@ -11,6 +11,7 @@ import InfoBox from '../../components/info-box';
import { CategoryViewProps } from './category-view-props';
import { DataEntryGroup } from '../data-components/data-entry-group';
import { MultiDataEntry } from '../data-components/multi-data-entry/multi-data-entry';
import { LogicalDataEntry } from '../data-components/logical-data-entry/logical-data-entry';
const EnergyCategoryOptions = ["A", "B", "C", "D", "E", "F", "G"];
const BreeamRatingOptions = [
@ -25,9 +26,20 @@ const BreeamRatingOptions = [
* Sustainability view/edit section
*/
const SustainabilityView: React.FunctionComponent<CategoryViewProps> = (props) => {
const currentYear = new Date().getFullYear();
return (
<Fragment>
<DataEntryGroup name="Energy rating data">
<DataEntryGroup name="Environmental quality rating">
<DataEntry
title="Official environmental quality rating"
slug=""
value=""
mode='view'
/>
</DataEntryGroup>
<DataEntryGroup name="Energy rating">
<SelectDataEntry
title={dataFields.sust_breeam_rating.title}
slug="sust_breeam_rating"
@ -46,7 +58,6 @@ const SustainabilityView: React.FunctionComponent<CategoryViewProps> = (props) =
user_verified_as={props.user_verified.sust_breeam_rating}
verified_count={props.building.verified.sust_breeam_rating}
/>
<SelectDataEntry
title={dataFields.sust_dec.title}
slug="sust_dec"
@ -65,7 +76,6 @@ const SustainabilityView: React.FunctionComponent<CategoryViewProps> = (props) =
user_verified_as={props.user_verified.sust_dec}
verified_count={props.building.verified.sust_dec}
/>
<SelectDataEntry
title={dataFields.sust_aggregate_estimate_epc.title}
slug="sust_aggregate_estimate_epc"
@ -78,91 +88,160 @@ const SustainabilityView: React.FunctionComponent<CategoryViewProps> = (props) =
onChange={props.onChange}
/>
</DataEntryGroup>
<DataEntryGroup name="Retrofit Data">
<DataEntryGroup name="Retrofit history">
<NumericDataEntry
title={dataFields.sust_retrofit_date.title}
slug="sust_retrofit_date"
value={props.building.sust_retrofit_date}
tooltip={dataFields.sust_retrofit_date.tooltip}
step={1}
min={1086}
max={new Date().getFullYear()}
slug='age_retrofit_date'
title={dataFields.age_retrofit_date.title}
value={props.building.age_retrofit_date}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
step={1}
min={1}
max={currentYear}
tooltip={dataFields.extension_year.tooltip}
/>
<Verification
slug="sust_retrofit_date"
allow_verify={props.user !== undefined && props.building.sust_retrofit_date !== null && !props.edited}
slug="age_retrofit_date"
allow_verify={props.user !== undefined && props.building.age_retrofit_date !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("sust_retrofit_date")}
user_verified_as={props.user_verified.sust_retrofit_date}
verified_count={props.building.verified.sust_retrofit_date}
user_verified={props.user_verified.hasOwnProperty("age_retrofit_date")}
user_verified_as={props.user_verified.age_retrofit_date}
verified_count={props.building.verified.age_retrofit_date}
/>
<SelectDataEntry
title={dataFields.sust_retrofit_source_type.title}
slug="sust_retrofit_source_type"
value={props.building.sust_retrofit_source_type}
title={dataFields.age_retrofit_date_source_type.title}
slug="age_retrofit_date_source_type"
value={props.building.age_retrofit_date_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.sust_retrofit_source_type.tooltip}
options={dataFields.sust_retrofit_source_type.items}
placeholder={dataFields.sust_retrofit_source_type.example}
tooltip={dataFields.age_retrofit_date_source_type.tooltip}
options={dataFields.age_retrofit_date_source_type.items}
placeholder={dataFields.age_retrofit_date_source_type.example}
/>
{(props.building.sust_retrofit_source_type == dataFields.sust_retrofit_source_type.items[0] ||
props.building.sust_retrofit_source_type == dataFields.sust_retrofit_source_type.items[1] ||
props.building.sust_retrofit_source_type == null) ? <></> :
{(props.building.age_retrofit_date_source_type == dataFields.age_retrofit_date_source_type.items[0] ||
props.building.age_retrofit_date_source_type == dataFields.age_retrofit_date_source_type.items[1] ||
props.building.age_retrofit_date_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.sust_retrofit_source_links.title}
slug="sust_retrofit_source_links"
value={props.building.sust_retrofit_source_links}
title={dataFields.age_retrofit_date_source_links.title}
slug="age_retrofit_date_source_links"
value={props.building.age_retrofit_date_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.sust_retrofit_source_links.tooltip}
tooltip={dataFields.age_retrofit_date_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
{/* <hr/>
<DataEntry
title="Date of Significant Retrofits"
slug=""
value=""
mode='view'
</DataEntryGroup>
<DataEntryGroup name="Solar panels">
<LogicalDataEntry
title={dataFields.energy_solar.title}
slug="energy_solar"
value={props.building.energy_solar}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.energy_solar.tooltip}
/>
<Verification
slug="date_link"
allow_verify={props.user !== undefined && props.building.date_link !== null && !props.edited}
slug="energy_solar"
allow_verify={props.user !== undefined && props.building.energy_solar !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("date_link")}
user_verified_as={props.user_verified.date_link}
verified_count={props.building.verified.date_link}
user_verified={props.user_verified.hasOwnProperty("energy_solar")}
user_verified_as={props.user_verified.energy_solar}
verified_count={props.building.verified.energy_solar}
/>
<DataEntry
title="Source"
slug=""
value=""
mode='view'
/> */}
{props.building.energy_solar == null ? <></> :
<>
<SelectDataEntry
title={dataFields.energy_solar_source_type.title}
slug="energy_solar_source_type"
value={props.building.energy_solar_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.energy_solar_source_type.tooltip}
options={dataFields.energy_solar_source_type.items}
placeholder={dataFields.energy_solar_source_type.example}
/>
{(props.building.energy_solar_source_type == dataFields.energy_solar_source_type.items[0] ||
props.building.energy_solar_source_type == dataFields.energy_solar_source_type.items[1] ||
props.building.energy_solar_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.energy_solar_source_links.title}
slug="energy_solar_source_links"
value={props.building.energy_solar_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.energy_solar_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</>
}
</DataEntryGroup>
<DataEntryGroup name="Other sustainability features">
<DataEntry
title="Does the building have Solar Panels?"
slug=""
value=""
mode='view'
<DataEntryGroup name="Green walls/roof">
<LogicalDataEntry
title={dataFields.energy_green_roof.title}
slug="energy_green_roof"
value={props.building.energy_green_roof}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.energy_green_roof.tooltip}
/>
<DataEntry
title="Does the building have Green Walls / Green Roof"
slug=""
value=""
mode='view'
<Verification
slug="energy_green_roof"
allow_verify={props.user !== undefined && props.building.energy_green_roof !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("energy_green_roof")}
user_verified_as={props.user_verified.energy_green_roof}
verified_count={props.building.verified.energy_green_roof}
/>
{props.building.energy_green_roof == null ? <></> :
<>
<SelectDataEntry
title={dataFields.energy_green_roof_source_type.title}
slug="energy_green_roof_source_type"
value={props.building.energy_green_roof_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.energy_green_roof_source_type.tooltip}
options={dataFields.energy_green_roof_source_type.items}
placeholder={dataFields.energy_green_roof_source_type.example}
/>
{(props.building.energy_green_roof_source_type == dataFields.energy_green_roof_source_type.items[0] ||
props.building.energy_green_roof_source_type == dataFields.energy_green_roof_source_type.items[1] ||
props.building.energy_green_roof_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.energy_green_roof_source_links.title}
slug="energy_green_roof_source_links"
value={props.building.energy_green_roof_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.energy_green_roof_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</>
}
</DataEntryGroup>
</Fragment>
);

View File

@ -32,14 +32,14 @@ const UseView: React.FunctionComponent<CategoryViewProps> = (props) => {
const { darkLightTheme } = useDisplayPreferences();
return (
<Fragment>
<DataEntryGroup name="Residential/non-residential land use data (general)">
<DataEntryGroup name="General Land Use">
<div className={`alert alert-dark`} role="alert" style={{ fontSize: 13, backgroundColor: "#f6f8f9" }}>
<i>
The vast majority of properties are residential (93% in the UK), so we have set 'residential' as the default value. Can you help us identify non-residential and mixed use buildings (and verify residential buildings too)?
</i>
</div>
<button className={`map-switcher-inline ${props.mapColourScale == "is_domestic" ? "enabled-state" : "disabled-state"} btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToIsDomesticMapStyle}>
{(props.mapColourScale == "is_domestic")? 'Showing domestic, non-domestic and mixed-use buildings (click to hide)' : 'Click to see domestic, non-domestic and mixed-use buildings on the map.'}
{(props.mapColourScale == "is_domestic")? 'Showing residential, non-residential and mixed-use buildings (click to hide)' : 'Click to see residential, non-residential and mixed-use buildings on the map.'}
</button>
<SelectDataEntry
title={dataFields.is_domestic.title}
@ -87,7 +87,7 @@ const UseView: React.FunctionComponent<CategoryViewProps> = (props) => {
</>
}
</DataEntryGroup>
<DataEntryGroup name="Specific land use data">
<DataEntryGroup name="Specific land use(s)">
<MultiDataEntry
title={dataFields.current_landuse_group.title}
slug="current_landuse_group"
@ -138,6 +138,7 @@ const UseView: React.FunctionComponent<CategoryViewProps> = (props) => {
/>
</>
}
<hr/>
{
props.mode != 'view' &&
<div>

View File

@ -12,12 +12,14 @@ import SelectDataEntry from '../data-components/select-data-entry';
import { MultiDataEntry } from '../data-components/multi-data-entry/multi-data-entry';
const locationNumberPattern = "[1-9]\\d*[a-z]?(-([1-9]\\d*))?"; ///[1-9]\d*[a-z]?(-([1-9]\d*))?/;
const postcodeCharacterPattern = "^[A-Z]{1,2}[0-9]{1,2}[A-Z]?(\\s*[0-9][A-Z]{1,2})?$";
const osmIdentifierPattern = "[0-9]{1,9}";
const LocationView: React.FunctionComponent<CategoryViewProps> = (props) => {
const osm_url = "https://www.openstreetmap.org/way/"+props.building.ref_osm_id;
const osm_url = "www.openstreetmap.org/way/"+props.building.ref_osm_id;
return (
<Fragment>
<DataEntryGroup name="Address data">
<DataEntryGroup name="Addresses">
<DataEntry
title={dataFields.location_name.title}
slug="location_name"
@ -26,8 +28,9 @@ const LocationView: React.FunctionComponent<CategoryViewProps> = (props) => {
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.location_name.tooltip}
placeholder="https://..."
isUrl={true}
placeholder=""
isUrl={false}
disabled={true}
/>
<Verification
slug="location_name"
@ -44,6 +47,23 @@ const LocationView: React.FunctionComponent<CategoryViewProps> = (props) => {
mode='view'
tooltip="Not yet activated.<br><br>For security reasons, we do not allow the use of free text boxes and are currently looking into alternative ways to collect this data."
/>
<DataEntry
title={dataFields.location_name_link.title}
slug="location_name_link"
value={props.building.location_name_link}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.location_name_link.tooltip}
placeholder={dataFields.location_name_link.example}
isUrl={true}
/>
{
(props.building.location_name_link == null) ? <></> :
<div className={`alert alert-dark`} role="alert" style={{ fontSize: 14, backgroundColor: "#f6f8f9" }}>
<i className="source-url">Source: <a href={props.building.location_name_link} target={"_blank"}>{props.building.location_name_link}</a></i>
</div>
}
<hr/>
<PatternDataEntry
title={dataFields.location_number.title}
@ -54,6 +74,7 @@ const LocationView: React.FunctionComponent<CategoryViewProps> = (props) => {
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.location_number.tooltip}
maxLength={5}
/>
<Verification
slug="location_number"
@ -71,6 +92,7 @@ const LocationView: React.FunctionComponent<CategoryViewProps> = (props) => {
copy={props.copy}
onChange={props.onChange}
maxLength={30}
disabled={true}
/>
<Verification
slug="location_street"
@ -88,6 +110,7 @@ const LocationView: React.FunctionComponent<CategoryViewProps> = (props) => {
copy={props.copy}
onChange={props.onChange}
maxLength={30}
disabled={true}
/>
<Verification
slug="location_line_two"
@ -104,6 +127,7 @@ const LocationView: React.FunctionComponent<CategoryViewProps> = (props) => {
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
disabled={true}
/>
<Verification
slug="location_town"
@ -113,15 +137,17 @@ const LocationView: React.FunctionComponent<CategoryViewProps> = (props) => {
user_verified_as={props.user_verified.location_town}
verified_count={props.building.verified.location_town}
/>
<DataEntry
<PatternDataEntry
title={dataFields.location_postcode.title}
slug="location_postcode"
value={props.building.location_postcode}
pattern={postcodeCharacterPattern}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
maxLength={8}
valueTransform={x=>x.toUpperCase()}
tooltip={dataFields.location_postcode.tooltip}
/>
<Verification
slug="location_postcode"
@ -161,7 +187,7 @@ const LocationView: React.FunctionComponent<CategoryViewProps> = (props) => {
</>
}
</DataEntryGroup>
<DataEntryGroup name="Property/footprint IDs and coordinate data">
<DataEntryGroup name="Property/footprint IDs and coordinates">
<DataEntry
title={dataFields.ref_toid.title}
slug="ref_toid"
@ -172,13 +198,27 @@ const LocationView: React.FunctionComponent<CategoryViewProps> = (props) => {
onChange={props.onChange}
disabled={true}
/>
{
(props.building.ref_toid == null) ? <></> :
<div className={`alert alert-dark`} role="alert" style={{ fontSize: 14, backgroundColor: "#f6f8f9" }}>
<i className="source-url">Source: <a href="https://www.ordnancesurvey.co.uk/products/os-open-toid" target={"_blank"}>{"www.ordnancesurvey.co.uk/products/os-open-toid"}</a></i>
</div>
}
<hr/>
<UPRNsDataEntry
title={dataFields.uprns.title}
slug="ref_uprns"
value={props.building.uprns}
tooltip={dataFields.uprns.tooltip}
/>
<DataEntry
{
(props.building.uprns == null) ? <></> :
<div className={`alert alert-dark`} role="alert" style={{ fontSize: 14, backgroundColor: "#f6f8f9" }}>
<i className="source-url">Source: <a href="https://beta.ordnancesurvey.co.uk/products/os-open-uprn" target={"_blank"}>{"beta.ordnancesurvey.co.uk/products/os-open-uprn"}</a></i>
</div>
}
<hr/>
<PatternDataEntry
title={dataFields.ref_osm_id.title}
slug="ref_osm_id"
value={props.building.ref_osm_id}
@ -187,13 +227,8 @@ const LocationView: React.FunctionComponent<CategoryViewProps> = (props) => {
tooltip={dataFields.ref_osm_id.tooltip}
maxLength={20}
onChange={props.onChange}
pattern={osmIdentifierPattern}
/>
{
(props.building.ref_osm_id == null) ? <></> :
<div className={`alert alert-dark`} role="alert" style={{ fontSize: 14, backgroundColor: "#f6f8f9" }}>
<i className="source-url">Source: <a href={osm_url} target={"_blank"}>{osm_url}</a></i>
</div>
}
<Verification
slug="ref_osm_id"
allow_verify={props.user !== undefined && props.building.ref_osm_id !== null && !props.edited}
@ -202,6 +237,12 @@ const LocationView: React.FunctionComponent<CategoryViewProps> = (props) => {
user_verified_as={props.user_verified.ref_osm_id}
verified_count={props.building.verified.ref_osm_id}
/>
{
(props.building.ref_osm_id == null) ? <></> :
<div className={`alert alert-dark`} role="alert" style={{ fontSize: 14, backgroundColor: "#f6f8f9" }}>
<i className="source-url">Source: <a href={"https://"+osm_url} target={"_blank"}>{osm_url}</a></i>
</div>
}
<hr/>
<NumericDataEntry
title={dataFields.location_latitude.title}
@ -274,6 +315,19 @@ const LocationView: React.FunctionComponent<CategoryViewProps> = (props) => {
/>
</>
}
<hr/>
<MultiDataEntry
title={dataFields.location_alternative_footprint_links.title}
slug="location_alternative_footprint_links"
value={props.building.location_alternative_footprint_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.location_alternative_footprint_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</DataEntryGroup>
</Fragment>
);

View File

@ -19,6 +19,8 @@ import { CategoryViewProps } from './category-view-props';
import { Category } from '../../config/categories-config';
import { useDisplayPreferences } from '../../displayPreferences-context';
import { processParam } from '../../../api/parameters';
import { MultiDataEntry } from '../data-components/multi-data-entry/multi-data-entry';
import YearDataEntry from '../data-components/year-data-entry';
const currentTimestamp = new Date().valueOf();
const milisecondsInYear = 1000 * 60 * 60 * 24 * 365;
@ -63,10 +65,12 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
}
const { flood, floodSwitchOnClick, housing, housingSwitchOnClick, creative, creativeSwitchOnClick, vista, vistaSwitchOnClick, parcel, parcelSwitchOnClick, conservation, conservationSwitchOnClick, darkLightTheme } = useDisplayPreferences();
const communityLinkUrl = `/${props.mode}/${Category.Community}/${props.building.building_id}`;
const currentYear = new Date().getFullYear();
return (
<Fragment>
<DataEntryGroup name="Planning application information" collapsed={true} >
<DataEntryGroup name="Current/active applications (official data)">
<DataEntryGroup name="Current planning applications" collapsed={true} >
<DataEntryGroup name="Official data">
<InfoBox>
This section provides data on active applications. We define these as applications with any activity in the last year.
<br />
@ -85,7 +89,119 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
: <></>
}
</DataEntryGroup>
<DataEntryGroup name="Past applications (official data)" collapsed={true} >
<DataEntryGroup name="Year of completion" collapsed={true} >
<LogicalDataEntry
slug='planning_crowdsourced_site_completion_status'
title={dataFields.planning_crowdsourced_site_completion_status.title}
tooltip={dataFields.planning_crowdsourced_site_completion_status.tooltip}
value={props.building.planning_crowdsourced_site_completion_status}
copy={props.copy}
onChange={props.onChange}
mode={props.mode}
/>
<Verification
slug="planning_crowdsourced_site_completion_status"
allow_verify={props.user !== undefined && props.building.planning_crowdsourced_site_completion_status !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("planning_crowdsourced_site_completion_status")}
user_verified_as={props.user_verified.planning_crowdsourced_site_completion_status}
verified_count={props.building.verified.planning_crowdsourced_site_completion_status}
/>
{props.building.planning_crowdsourced_site_completion_status == null ? <></> :
<>
<NumericDataEntry
title={dataFields.planning_crowdsourced_site_completion_year.title}
slug="planning_crowdsourced_site_completion_year"
value={props.building.planning_crowdsourced_site_completion_year}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
step={1}
min={1}
max={currentYear}
tooltip={dataFields.planning_crowdsourced_site_completion_year.tooltip}
/>
<Verification
slug="planning_crowdsourced_site_completion_year"
allow_verify={props.user !== undefined && props.building.planning_crowdsourced_site_completion_year !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("planning_crowdsourced_site_completion_year")}
user_verified_as={props.user_verified.planning_crowdsourced_site_completion_year}
verified_count={props.building.verified.planning_crowdsourced_site_completion_year}
/>
<SelectDataEntry
title={dataFields.planning_crowdsourced_site_completion_source_type.title}
slug="planning_crowdsourced_site_completion_source_type"
value={props.building.planning_crowdsourced_site_completion_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.planning_crowdsourced_site_completion_source_type.tooltip}
options={dataFields.planning_crowdsourced_site_completion_source_type.items}
placeholder={dataFields.planning_crowdsourced_site_completion_source_type.example}
/>
{(props.building.planning_crowdsourced_site_completion_source_type == dataFields.planning_crowdsourced_site_completion_source_type.items[0] ||
props.building.planning_crowdsourced_site_completion_source_type == dataFields.planning_crowdsourced_site_completion_source_type.items[1] ||
props.building.planning_crowdsourced_site_completion_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.planning_crowdsourced_site_completion_source_links.title}
slug="planning_crowdsourced_site_completion_source_links"
value={props.building.planning_crowdsourced_site_completion_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.planning_crowdsourced_site_completion_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</>
}
</DataEntryGroup>
<DataEntryGroup name="Incomplete/missing data" collapsed={true} >
<LogicalDataEntry
slug='planning_missing_data'
title={dataFields.planning_missing_data.title}
tooltip={dataFields.planning_missing_data.tooltip}
value={props.building.planning_missing_data}
copy={props.copy}
onChange={props.onChange}
mode={props.mode}
/>
<Verification
slug="planning_missing_data"
allow_verify={props.user !== undefined && props.building.planning_missing_data !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("planning_missing_data")}
user_verified_as={props.user_verified.planning_missing_data}
verified_count={props.building.verified.planning_missing_data}
/>
{props.building.planning_missing_data == null ? <></> :
<>
<MultiDataEntry
title={dataFields.planning_missing_data_links.title}
slug="planning_missing_data_links"
value={props.building.planning_missing_data_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.planning_missing_data_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
<InfoBox>
If you feel there are incorrect or missing data relating to this building please contact:
planningdata@London.gov.uk
</InfoBox>
</DataEntryGroup>
</DataEntryGroup>
<DataEntryGroup name="Past applications" collapsed={true} >
<InfoBox>
This section provides data on past applications where available from the GLA, including those with no decision in over a year
</InfoBox>
@ -102,7 +218,7 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
: <></>
}
</DataEntryGroup>
<DataEntryGroup name="Possible future applications (crowdsourced data)" collapsed={true} >
<DataEntryGroup name="Possible future applications" collapsed={true} >
<InfoBox type='info'>Click and colour buildings here if you think they may be subject to a future planning application involving demolition. To add your opinion on how well this building works, please also visit the <Link to={communityLinkUrl}>Community</Link> section.</InfoBox>
{
props.mapColourScale != "community_expected_planning_application_total" ?
@ -127,7 +243,6 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
Further improvements to this feature are currently being made.
</InfoBox>
</DataEntryGroup>
</DataEntryGroup>
<DataEntryGroup name="Planning zones" collapsed={true} >
<InfoBox>
To view planning zone data for London click the buttons below. You may need to <u>zoom out</u>.
@ -221,48 +336,26 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
<button className={`map-switcher-inline ${conservation}-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={conservationSwitchOnClick}>
{(conservation === 'enabled')? 'Click to hide Conservation Areas' : 'Click to see Conservation Areas'}
</button>
<NumericDataEntryWithFormattedLink
title={dataFields.planning_list_id.title}
slug="planning_list_id"
value={props.building.planning_list_id}
mode={props.mode}
<hr/>
<LogicalDataEntry
slug='planning_heritage_at_risk'
title={dataFields.planning_heritage_at_risk.title}
tooltip={dataFields.planning_heritage_at_risk.tooltip}
value={props.building.planning_heritage_at_risk}
copy={props.copy}
onChange={props.onChange}
placeholder="add ID here"
linkTargetFunction={(id: String) => { return "https://historicengland.org.uk/listing/the-list/list-entry/" + id + "?section=official-list-entry" } }
linkDescriptionFunction={(id: String) => { return "ID Link" } }
/>
<Verification
slug="planning_list_id"
allow_verify={props.user !== undefined && props.building.planning_list_id !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("planning_list_id")}
user_verified_as={props.user_verified.planning_list_id}
verified_count={props.building.verified.planning_list_id}
/>
<SelectDataEntry
title={dataFields.planning_list_grade.title}
slug="planning_list_grade"
value={props.building.planning_list_grade}
mode={props.mode}
disabled={false}
copy={props.copy}
onChange={props.onChange}
options={[
"I",
"II*",
"II",
"None"
]}
/>
<Verification
slug="planning_list_grade"
allow_verify={props.user !== undefined && props.building.planning_list_grade !== null && !props.edited}
slug="planning_heritage_at_risk"
allow_verify={props.user !== undefined && props.building.planning_heritage_at_risk !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("planning_list_grade")}
user_verified_as={props.user_verified.planning_list_grade}
verified_count={props.building.verified.planning_list_grade}
user_verified={props.user_verified.hasOwnProperty("planning_heritage_at_risk")}
user_verified_as={props.user_verified.planning_heritage_at_risk}
verified_count={props.building.verified.planning_heritage_at_risk}
/>
{(props.building.planning_heritage_at_risk == null || props.building.planning_heritage_at_risk == false) ? <></> :
<>
<DataEntry
title={dataFields.planning_heritage_at_risk_url.title}
slug="planning_heritage_at_risk_url"
@ -281,6 +374,28 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
user_verified_as={props.user_verified.planning_heritage_at_risk_url}
verified_count={props.building.verified.planning_heritage_at_risk_url}
/>
</>
}
<hr/>
<LogicalDataEntry
slug='planning_world_heritage_site'
title={dataFields.planning_world_heritage_site.title}
tooltip={dataFields.planning_world_heritage_site.tooltip}
value={props.building.planning_world_heritage_site}
copy={props.copy}
onChange={props.onChange}
mode={props.mode}
/>
<Verification
slug="planning_world_heritage_site"
allow_verify={props.user !== undefined && props.building.planning_world_heritage_site !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("planning_world_heritage_site")}
user_verified_as={props.user_verified.planning_world_heritage_site}
verified_count={props.building.verified.planning_world_heritage_site}
/>
{(props.building.planning_world_heritage_site == null || props.building.planning_world_heritage_site == false) ? <></> :
<>
<NumericDataEntryWithFormattedLink
title={dataFields.planning_world_list_id.title}
slug="planning_world_list_id"
@ -300,6 +415,28 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
user_verified_as={props.user_verified.planning_world_list_id}
verified_count={props.building.verified.planning_world_list_id}
/>
</>
}
<hr/>
<LogicalDataEntry
slug='planning_local_list'
title={dataFields.planning_local_list.title}
tooltip={dataFields.planning_local_list.tooltip}
value={props.building.planning_local_list}
copy={props.copy}
onChange={props.onChange}
mode={props.mode}
/>
<Verification
slug="planning_local_list"
allow_verify={props.user !== undefined && props.building.planning_local_list !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("planning_local_list")}
user_verified_as={props.user_verified.planning_local_list}
verified_count={props.building.verified.planning_local_list}
/>
{(props.building.planning_local_list == null || props.building.planning_local_list == false) ? <></> :
<>
<DataEntry
title={dataFields.planning_local_list_url.title}
slug="planning_local_list_url"
@ -318,26 +455,28 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
user_verified_as={props.user_verified.planning_local_list_url}
verified_count={props.building.verified.planning_local_list_url}
/>
{/*
<DataEntry
title={dataFields.planning_in_conservation_area_id.title}
slug="planning_in_conservation_area_id"
value={props.building.planning_in_conservation_area_id}
mode={props.mode}
</>
}
<hr/>
<LogicalDataEntry
slug='planning_in_conservation_area'
title={dataFields.planning_in_conservation_area.title}
tooltip={dataFields.planning_in_conservation_area.tooltip}
value={props.building.planning_in_conservation_area}
copy={props.copy}
onChange={props.onChange}
placeholder="Please add Conservation Area identifier"
mode={props.mode}
/>
<Verification
slug="planning_in_conservation_area_id"
allow_verify={props.user !== undefined && props.building.planning_in_conservation_area_id !== null && !props.edited}
slug="planning_in_conservation_area"
allow_verify={props.user !== undefined && props.building.planning_in_conservation_area !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("planning_in_conservation_area_id")}
user_verified_as={props.user_verified.planning_in_conservation_area_id}
verified_count={props.building.verified.planning_in_conservation_area_id}
user_verified={props.user_verified.hasOwnProperty("planning_in_conservation_area")}
user_verified_as={props.user_verified.planning_in_conservation_area}
verified_count={props.building.verified.planning_in_conservation_area}
/>
*/}
{(props.building.planning_in_conservation_area == null || props.building.planning_in_conservation_area == false) ? <></> :
<>
<DataEntry
title={dataFields.planning_in_conservation_area_url.title}
slug="planning_in_conservation_area_url"
@ -358,42 +497,28 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
user_verified_as={props.user_verified.planning_in_conservation_area_url}
verified_count={props.building.verified.planning_in_conservation_area_url}
/>
{/*
<DataEntry
title={dataFields.planning_conservation_area_name.title}
slug="planning_conservation_area_name"
value={props.building.planning_conservation_area_name}
mode={props.mode}
</>
}
<hr/>
<LogicalDataEntry
slug='planning_in_apa'
title={dataFields.planning_in_apa.title}
tooltip={dataFields.planning_in_apa.tooltip}
value={props.building.planning_in_apa}
copy={props.copy}
onChange={props.onChange}
/>
<Verification
slug="planning_conservation_area_name"
allow_verify={props.user !== undefined && props.building.planning_conservation_area_name !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("planning_conservation_area_name")}
user_verified_as={props.user_verified.planning_conservation_area_name}
verified_count={props.building.verified.planning_conservation_area_name}
/>
*/}
<DataEntry
title={dataFields.planning_historic_area_assessment_url.title}
slug="planning_historic_area_assessment_url"
value={props.building.planning_historic_area_assessment_url}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
isUrl={true}
placeholder="Please add relevant link here"
/>
<Verification
slug="planning_historic_area_assessment_url"
allow_verify={props.user !== undefined && props.building.planning_historic_area_assessment_url !== null && !props.edited}
slug="planning_in_apa"
allow_verify={props.user !== undefined && props.building.planning_in_apa !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("planning_historic_area_assessment_url")}
user_verified_as={props.user_verified.planning_historic_area_assessment_url}
verified_count={props.building.verified.planning_historic_area_assessment_url}
user_verified={props.user_verified.hasOwnProperty("planning_in_apa")}
user_verified_as={props.user_verified.planning_in_apa}
verified_count={props.building.verified.planning_in_apa}
/>
{(props.building.planning_in_apa == null || props.building.planning_in_apa == false) ? <></> :
<>
<DataEntry
title={dataFields.planning_in_apa_url.title}
slug="planning_in_apa_url"
@ -412,107 +537,109 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
user_verified_as={props.user_verified.planning_in_apa_url}
verified_count={props.building.verified.planning_in_apa_url}
/>
</DataEntryGroup>
<DataEntryGroup name="Forthcoming data (sections to be activated)" collapsed={true} >
<DataEntryGroup name="Active application info (crowdsourced)" collapsed={true} >
{/* will be titled "Other active application info (crowdsourced data)" once active" */}
<InfoBox type='warning'>
This category is not yet activated - Until this section is activated please report inaccuracies or problems on the <a href=" https://github.com/colouring-cities/colouring-london/discussions/categories/planning-section-comments">Discussion Forum</a>.
</InfoBox>
{/* that is placeholder display, will be replaced by actual code */}
<div className="data-title">
<div className="data-title-text">
<ul>
<li>Year of completion if known</li>
<li>If you know of a planning application that has been recently submitted for this site, and is not listed in the blue box above, please enter its planning application ID below:</li>
<li>If any of the active planning applications are not mapped onto the correct site, please tick here</li>
</ul>
</div>
</div>
{
/*
<NumericDataEntry
title={dataFields.planning_crowdsourced_site_completion_year.title}
slug="planning_crowdsourced_site_completion_year"
value={props.building.planning_crowdsourced_site_completion_year}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
disabled={true}
/>
<Verification
slug="planning_crowdsourced_site_completion_year"
allow_verify={false}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("planning_crowdsourced_site_completion_year")}
user_verified_as={props.user_verified.planning_crowdsourced_site_completion_year}
verified_count={props.building.verified.planning_crowdsourced_site_completion_year}
/>
<DataEntry
title={dataFields.planning_crowdsourced_planning_id.title}
slug="planning_crowdsourced_planning_id"
value={props.building.planning_crowdsourced_planning_id}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
disabled={true}
/>
<Verification
slug="planning_crowdsourced_planning_id"
allow_verify={false && props.user !== undefined && props.building.planning_crowdsourced_planning_id !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("planning_crowdsourced_planning_id")}
user_verified_as={props.user_verified.planning_crowdsourced_planning_id}
verified_count={props.building.verified.planning_crowdsourced_planning_id}
/>
<LogicalDataEntry
slug='community_expected_planning_application_is_inaccurate'
title={"If any of the active planning applications are not mapped onto the correct site, please tick here"}
value={null}
onChange={props.onSaveChange}
mode={props.mode}
copy={props.copy}
disabled={true}
/>
on enabling switch it to UserOpinionEntry, remove value and restore userValue
*/
</>
}
<hr/>
<LogicalDataEntry
slug='planning_scientific_interest'
title={dataFields.planning_scientific_interest.title}
tooltip={dataFields.planning_scientific_interest.tooltip}
value={props.building.planning_scientific_interest}
copy={props.copy}
onChange={props.onChange}
mode={props.mode}
/>
<Verification
slug="planning_scientific_interest"
allow_verify={props.user !== undefined && props.building.planning_scientific_interest !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("planning_scientific_interest")}
user_verified_as={props.user_verified.planning_scientific_interest}
verified_count={props.building.verified.planning_scientific_interest}
/>
{(props.building.planning_scientific_interest == null || props.building.planning_scientific_interest == false) ? <></> :
<>
<SelectDataEntry
title={dataFields.planning_scientific_interest_source_type.title}
slug="planning_scientific_interest_source_type"
value={props.building.planning_scientific_interest_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.planning_scientific_interest_source_type.tooltip}
options={dataFields.planning_scientific_interest_source_type.items}
placeholder={dataFields.planning_scientific_interest_source_type.example}
/>
{(props.building.planning_scientific_interest_source_type == dataFields.planning_scientific_interest_source_type.items[0] ||
props.building.planning_scientific_interest_source_type == dataFields.planning_scientific_interest_source_type.items[1] ||
props.building.planning_scientific_interest_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.planning_scientific_interest_source_links.title}
slug="planning_scientific_interest_source_links"
value={props.building.planning_scientific_interest_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.planning_scientific_interest_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</>
}
<hr/>
<LogicalDataEntry
slug='planning_historic_area_assessment'
title={dataFields.planning_historic_area_assessment.title}
tooltip={dataFields.planning_historic_area_assessment.tooltip}
value={props.building.planning_historic_area_assessment}
copy={props.copy}
onChange={props.onChange}
mode={props.mode}
/>
<Verification
slug="planning_historic_area_assessment"
allow_verify={props.user !== undefined && props.building.planning_historic_area_assessment !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("planning_historic_area_assessment")}
user_verified_as={props.user_verified.planning_historic_area_assessment}
verified_count={props.building.verified.planning_historic_area_assessment}
/>
{(props.building.planning_historic_area_assessment == null || props.building.planning_historic_area_assessment == false) ? <></> :
<>
<DataEntry
title={dataFields.planning_historic_area_assessment_url.title}
slug="planning_historic_area_assessment_url"
value={props.building.planning_historic_area_assessment_url}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
isUrl={true}
placeholder="Please add relevant link here"
/>
<Verification
slug="planning_historic_area_assessment_url"
allow_verify={props.user !== undefined && props.building.planning_historic_area_assessment_url !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("planning_historic_area_assessment_url")}
user_verified_as={props.user_verified.planning_historic_area_assessment_url}
verified_count={props.building.verified.planning_historic_area_assessment_url}
/>
</>
}
</DataEntryGroup>
<DataEntryGroup name="Land ownership type" collapsed={true} >
<InfoBox type='warning'>
This category is not yet activated.
</InfoBox>
<DataEntryGroup name="Land ownership" collapsed={true} >
<InfoBox>
This section is designed to provide information on land parcels and their ownership type. Can you help us to crowdsource this information?
This section is designed to provide information on land parcels and their ownership type. Can you help us collect this information?
</InfoBox>
<button className={`map-switcher-inline ${parcel}-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={parcelSwitchOnClick}>
{(parcel === 'enabled')? 'Click to hide sample of parcel data (in City)' : 'Click to see sample of parcel data (in City) mapped'}
</button>
<div className="data-title">
<div className="data-title-text">
<ul>
<li>What type of owner owns this land parcel?</li>
</ul>
</div>
</div>
{/*
<SelectDataEntry
slug='community_public_ownership'
title={"What type of owner owns this land parcel? "}
title={dataFields.community_public_ownership.title}
value={props.building.community_public_ownership}
options={[
'Government-owned',
'Charity-owned',
'Community-owned/cooperative',
'Owned by other non-profit body',
'Not in public/community ownership',
]}
options={dataFields.community_public_ownership.items}
onChange={props.onChange}
mode={props.mode}
copy={props.copy}
@ -525,9 +652,39 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
user_verified_as={props.user_verified.community_public_ownership}
verified_count={props.building.verified.community_public_ownership}
/>
*/
}
</DataEntryGroup>
<DataEntry
title="Source Type"
slug=""
value=""
mode='view'
tooltip='Coming Soon'
/>
<MultiDataEntry
slug='community_public_ownership_sources'
title={dataFields.community_public_ownership_sources.title}
isUrl={true}
placeholder={'https://...'}
editableEntries={true}
value={props.building.community_public_ownership_sources}
onChange={props.onChange}
mode={props.mode}
copy={props.copy}
/>
<hr/>
<DataEntry
title={dataFields.size_parcel_geometry.title}
slug="size_parcel_geometry"
value={props.building.size_parcel_geometry}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.size_parcel_geometry.tooltip}
placeholder="https://..."
isUrl={true}
/>
<button className={`map-switcher-inline ${parcel}-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={parcelSwitchOnClick}>
{(parcel === 'enabled')? 'Click to hide sample land parcel data' : 'Click to show sample land parcel data'}
</button>
</DataEntryGroup>
</Fragment>
)};

View File

@ -15,7 +15,22 @@ import { MultiDataEntry } from '../data-components/multi-data-entry/multi-data-e
/**
* Size view/edit section
*/
const SizeView: React.FunctionComponent<CategoryViewProps> = (props) => (
const SizeView: React.FunctionComponent<CategoryViewProps> = (props) => {
// Calculate the total number of floors
let total_floors = 0;
if (props.building.size_storeys_attic != null) {
total_floors += props.building.size_storeys_attic;
}
if (props.building.size_storeys_core != null) {
total_floors += props.building.size_storeys_core;
}
if (props.building.size_storeys_basement != null) {
total_floors += props.building.size_storeys_basement;
}
return (
<Fragment>
<DataEntryGroup name="Number of floors/storeys">
<NumericDataEntry
@ -75,6 +90,18 @@ const SizeView: React.FunctionComponent<CategoryViewProps> = (props) => (
user_verified_as={props.user_verified.size_storeys_basement}
verified_count={props.building.verified.size_storeys_basement}
/>
<NumericDataEntry
title="Total number of floors"
slug="size_total_floors"
value={total_floors}
mode={props.mode}
copy={props.copy}
tooltip="Total number of floors, calculated from other values."
onChange={props.onChange}
step={1}
min={0}
disabled={true}
/>
<SelectDataEntry
title={dataFields.size_storeys_source_type.title}
slug="size_storeys_source_type"
@ -103,7 +130,7 @@ const SizeView: React.FunctionComponent<CategoryViewProps> = (props) => (
</>
}
</DataEntryGroup>
<DataEntryGroup name="Building height data">
<DataEntryGroup name="Height">
<NumericDataEntry
title={dataFields.size_height_apex.title}
slug="size_height_apex"
@ -196,7 +223,7 @@ const SizeView: React.FunctionComponent<CategoryViewProps> = (props) => (
</>
}
</DataEntryGroup>
<DataEntryGroup name="Floor area data">
<DataEntryGroup name="Floor area">
<NumericDataEntry
title={dataFields.size_floor_area_ground.title}
slug="size_floor_area_ground"
@ -261,7 +288,7 @@ const SizeView: React.FunctionComponent<CategoryViewProps> = (props) => (
</>
}
</DataEntryGroup>
<DataEntryGroup name="Plot size data">
<DataEntryGroup name="Plot size">
<NumericDataEntry
title={dataFields.size_width_frontage.title}
slug="size_width_frontage"
@ -449,7 +476,8 @@ const SizeView: React.FunctionComponent<CategoryViewProps> = (props) => (
}
</DataEntryGroup>
</Fragment>
);
)
};
const SizeContainer = withCopyEdit(SizeView);
export default SizeContainer;

View File

@ -1,28 +1,25 @@
import React, { Fragment } from 'react';
import InfoBox from '../../components/info-box';
import { commonSourceTypes, dataFields } from '../../config/data-fields-config';
import DataEntry from '../data-components/data-entry';
import NumericDataEntry from '../data-components/numeric-data-entry';
import withCopyEdit from '../data-container';
import { CategoryViewProps } from './category-view-props';
import { DataEntryGroup } from '../data-components/data-entry-group';
import { MultiDataEntry } from '../data-components/multi-data-entry/multi-data-entry';
import SelectDataEntry from '../data-components/select-data-entry';
import Verification from '../data-components/verification';
import { LogicalDataEntry } from '../data-components/logical-data-entry/logical-data-entry';
/**
* Streetscape view/edit section
* Street Context view/edit section
*/
const StreetscapeView: React.FunctionComponent<CategoryViewProps> = (props) => (
const StreetContextView: React.FunctionComponent<CategoryViewProps> = (props) => (
<Fragment>
<DataEntryGroup name="Does the building have a garden?">
<SelectDataEntry
<DataEntryGroup name="Green Space">
<LogicalDataEntry
title={dataFields.context_front_garden.title}
slug="context_front_garden"
value={props.building.context_front_garden}
options={dataFields.context_front_garden.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
@ -36,7 +33,7 @@ const StreetscapeView: React.FunctionComponent<CategoryViewProps> = (props) => (
user_verified_as={props.user_verified.context_front_garden}
verified_count={props.building.verified.context_front_garden}
/>
<SelectDataEntry
<LogicalDataEntry
title={dataFields.context_back_garden.title}
slug="context_back_garden"
value={props.building.context_back_garden}
@ -44,8 +41,6 @@ const StreetscapeView: React.FunctionComponent<CategoryViewProps> = (props) => (
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.context_back_garden.tooltip}
//placeholder={dataFields.context_back_garden.example}
options={dataFields.context_back_garden.items}
/>
<Verification
slug="context_back_garden"
@ -55,7 +50,7 @@ const StreetscapeView: React.FunctionComponent<CategoryViewProps> = (props) => (
user_verified_as={props.user_verified.context_back_garden}
verified_count={props.building.verified.context_back_garden}
/>
<SelectDataEntry
<LogicalDataEntry
title={dataFields.context_flats_garden.title}
slug="context_flats_garden"
value={props.building.context_flats_garden}
@ -63,8 +58,6 @@ const StreetscapeView: React.FunctionComponent<CategoryViewProps> = (props) => (
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.context_flats_garden.tooltip}
//placeholder={dataFields.context_flats_garden.example}
options={dataFields.context_flats_garden.items}
/>
<Verification
slug="context_flats_garden"
@ -74,7 +67,6 @@ const StreetscapeView: React.FunctionComponent<CategoryViewProps> = (props) => (
user_verified_as={props.user_verified.context_flats_garden}
verified_count={props.building.verified.context_flats_garden}
/>
<hr/>
<SelectDataEntry
title={dataFields.context_garden_source_type.title}
slug="context_garden_source_type"
@ -104,8 +96,110 @@ const StreetscapeView: React.FunctionComponent<CategoryViewProps> = (props) => (
/>
</>
}
<hr/>
<NumericDataEntry
title={dataFields.context_green_space_distance.title}
value={props.building.context_green_space_distance}
slug="context_green_space_distance"
tooltip={dataFields.context_green_space_distance.tooltip}
//placeholder={dataFields.context_green_space_distance.example}
mode={props.mode}
onChange={props.onChange}
step={1}
min={0}
/>
<Verification
slug="context_green_space_distance"
allow_verify={props.user !== undefined && props.building.context_green_space_distance !== null}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("context_green_space_distance")}
user_verified_as={props.user_verified.context_green_space_distance}
verified_count={props.building.verified.context_green_space_distance}
/>
<SelectDataEntry
title={dataFields.context_green_space_distance_source_type.title}
slug="context_green_space_distance_source_type"
value={props.building.context_green_space_distance_source_type}
options={dataFields.context_green_space_distance_source_type.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.context_green_space_distance_source_type.tooltip}
/>
{(props.building.context_green_space_distance_source_type == commonSourceTypes[0] ||
props.building.context_green_space_distance_source_type == commonSourceTypes[1] ||
props.building.context_green_space_distance_source_type == null) ? <></> :
<><MultiDataEntry
title={dataFields.context_green_space_distance_source_links.title}
slug="context_green_space_distance_source_links"
value={props.building.context_green_space_distance_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.context_green_space_distance_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
<hr/>
<NumericDataEntry
title={dataFields.context_tree_distance.title}
value={props.building.context_tree_distance}
slug="context_tree_distance"
tooltip={dataFields.context_tree_distance.tooltip}
//placeholder={dataFields.context_tree_distance.example}
mode={props.mode}
onChange={props.onChange}
step={1}
min={0}
/>
<Verification
slug="context_tree_distance"
allow_verify={props.user !== undefined && props.building.context_tree_distance !== null}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("context_tree_distance")}
user_verified_as={props.user_verified.context_tree_distance}
verified_count={props.building.verified.context_tree_distance}
/>
<SelectDataEntry
title={dataFields.context_tree_distance_source_type.title}
slug="context_tree_distance_source_type"
value={props.building.context_tree_distance_source_type}
options={dataFields.context_tree_distance_source_type.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.context_tree_distance_source_type.tooltip}
/>
{(props.building.context_tree_distance_source_type == commonSourceTypes[0] ||
props.building.context_tree_distance_source_type == commonSourceTypes[1] ||
props.building.context_tree_distance_source_type == null) ? <></> :
<><MultiDataEntry
title={dataFields.context_tree_distance_source_links.title}
slug="context_tree_distance_source_links"
value={props.building.context_tree_distance_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.context_tree_distance_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</DataEntryGroup>
<DataEntryGroup name="Street/pavement properties">
<DataEntryGroup name="Street/pavement">
<DataEntry
title="Walkability Index"
slug=""
value=""
mode='view'
tooltip='Under development'
/>
<hr/>
<NumericDataEntry
title={dataFields.context_street_width.title}
value={props.building.context_street_width}
@ -247,103 +341,17 @@ const StreetscapeView: React.FunctionComponent<CategoryViewProps> = (props) => (
</>
}
</DataEntryGroup>
<DataEntryGroup name="Access to green space">
<NumericDataEntry
title={dataFields.context_green_space_distance.title}
value={props.building.context_green_space_distance}
slug="context_green_space_distance"
tooltip={dataFields.context_green_space_distance.tooltip}
//placeholder={dataFields.context_green_space_distance.example}
mode={props.mode}
onChange={props.onChange}
step={1}
min={0}
<DataEntryGroup name="Number of entrances facing street">
<DataEntry
title="Number of entrances facing street"
slug=""
value=""
mode='view'
tooltip='Under development'
/>
<Verification
slug="context_green_space_distance"
allow_verify={props.user !== undefined && props.building.context_green_space_distance !== null}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("context_green_space_distance")}
user_verified_as={props.user_verified.context_green_space_distance}
verified_count={props.building.verified.context_green_space_distance}
/>
<SelectDataEntry
title={dataFields.context_green_space_distance_source_type.title}
slug="context_green_space_distance_source_type"
value={props.building.context_green_space_distance_source_type}
options={dataFields.context_green_space_distance_source_type.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.context_green_space_distance_source_type.tooltip}
/>
{(props.building.context_green_space_distance_source_type == commonSourceTypes[0] ||
props.building.context_green_space_distance_source_type == commonSourceTypes[1] ||
props.building.context_green_space_distance_source_type == null) ? <></> :
<><MultiDataEntry
title={dataFields.context_green_space_distance_source_links.title}
slug="context_green_space_distance_source_links"
value={props.building.context_green_space_distance_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.context_green_space_distance_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
<hr/>
<NumericDataEntry
title={dataFields.context_tree_distance.title}
value={props.building.context_tree_distance}
slug="context_tree_distance"
tooltip={dataFields.context_tree_distance.tooltip}
//placeholder={dataFields.context_tree_distance.example}
mode={props.mode}
onChange={props.onChange}
step={1}
min={0}
/>
<Verification
slug="context_tree_distance"
allow_verify={props.user !== undefined && props.building.context_tree_distance !== null}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("context_tree_distance")}
user_verified_as={props.user_verified.context_tree_distance}
verified_count={props.building.verified.context_tree_distance}
/>
<SelectDataEntry
title={dataFields.context_tree_distance_source_type.title}
slug="context_tree_distance_source_type"
value={props.building.context_tree_distance_source_type}
options={dataFields.context_tree_distance_source_type.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.context_tree_distance_source_type.tooltip}
/>
{(props.building.context_tree_distance_source_type == commonSourceTypes[0] ||
props.building.context_tree_distance_source_type == commonSourceTypes[1] ||
props.building.context_tree_distance_source_type == null) ? <></> :
<><MultiDataEntry
title={dataFields.context_tree_distance_source_links.title}
slug="context_tree_distance_source_links"
value={props.building.context_tree_distance_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.context_tree_distance_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</DataEntryGroup>
</Fragment>
);
const StreetscapeContainer = withCopyEdit(StreetscapeView);
const StreetContextContainer = withCopyEdit(StreetContextView);
export default StreetscapeContainer;
export default StreetContextContainer;

View File

@ -4,9 +4,9 @@ import { commonSourceTypes, dataFields } from '../../config/data-fields-config';
import SelectDataEntry from '../data-components/select-data-entry';
import NumericDataEntry from '../data-components/numeric-data-entry';
import Verification from '../data-components/verification';
import { MultiDataEntry } from '../data-components/multi-data-entry/multi-data-entry';
import { LogicalDataEntry, LogicalDataEntryYesOnly } from '../data-components/logical-data-entry/logical-data-entry';
import { DataEntryGroup } from '../data-components/data-entry-group';
import { MultiDataEntry } from '../data-components/multi-data-entry/multi-data-entry';
import withCopyEdit from '../data-container';
@ -21,57 +21,7 @@ const TeamView: React.FunctionComponent<CategoryViewProps> = (props) => {
const currentBuildingConstructionYear = building.date_year || undefined;
return (
<form>
<DataEntryGroup name="Data relating to original building or extension?">
<NumericDataEntry
slug='date_year'
title={dataFields.date_year.title}
value={currentBuildingConstructionYear}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
step={1}
min={1}
max={currentYear}
tooltip={dataFields.extension_year.tooltip}
/>
<Verification
slug="date_year"
allow_verify={props.user !== undefined && props.building.date_year !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("date_year")}
user_verified_as={props.user_verified.date_year}
verified_count={props.building.verified.date_year}
/>
<SelectDataEntry
title={dataFields.date_source.title}
slug="date_source"
value={props.building.date_source}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.date_source.tooltip}
options={dataFields.date_source.items}
placeholder={dataFields.date_source.example}
/>
{(props.building.date_source == dataFields.date_source.items[0] ||
props.building.date_source == dataFields.date_source.items[1] ||
props.building.date_source == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.date_link.title}
slug="date_link"
value={props.building.date_link}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.date_link.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
<hr/>
<DataEntryGroup name="General info">
<LogicalDataEntry
title={dataFields.has_extension.title}
slug="has_extension"
@ -81,7 +31,7 @@ const TeamView: React.FunctionComponent<CategoryViewProps> = (props) => {
onChange={props.onChange}
tooltip={dataFields.has_extension.tooltip}
/>
{props.building.has_extension ? (
{props.building.has_extension!=null && !props.building.has_extension ? (
<>
<NumericDataEntry
slug='extension_year'
@ -135,7 +85,7 @@ const TeamView: React.FunctionComponent<CategoryViewProps> = (props) => {
</>
) : (null)}
</DataEntryGroup>
<DataEntryGroup name="Land ownership data">
<DataEntryGroup name="Land ownership">
<MultiDataEntry
title={dataFields.landowner.title}
slug="landowner"
@ -146,6 +96,7 @@ const TeamView: React.FunctionComponent<CategoryViewProps> = (props) => {
tooltip={dataFields.landowner.tooltip}
placeholder=""
editableEntries={true}
disabled={true}
/>
<Verification
slug="landowner"
@ -155,6 +106,18 @@ const TeamView: React.FunctionComponent<CategoryViewProps> = (props) => {
user_verified_as={props.user_verified.landowner}
verified_count={props.building.verified.landowner}
/>
<MultiDataEntry
title={dataFields.landowner_links.title}
slug="landowner_links"
value={props.building.landowner_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.landowner_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
<SelectDataEntry
title={dataFields.landowner_source_type.title}
slug="landowner_source_type"
@ -185,7 +148,7 @@ const TeamView: React.FunctionComponent<CategoryViewProps> = (props) => {
</>
}
</DataEntryGroup>
<DataEntryGroup name="Developer data">
<DataEntryGroup name="Developer">
<SelectDataEntry
slug='developer_type'
title={dataFields.developer_type.title}
@ -213,6 +176,7 @@ const TeamView: React.FunctionComponent<CategoryViewProps> = (props) => {
tooltip={dataFields.developer_name.tooltip}
placeholder=""
editableEntries={true}
disabled={true}
/>
<Verification
slug="developer_name"
@ -222,6 +186,18 @@ const TeamView: React.FunctionComponent<CategoryViewProps> = (props) => {
user_verified_as={props.user_verified.developer_name}
verified_count={props.building.verified.developer_name}
/>
<MultiDataEntry
title={dataFields.developer_links.title}
slug="developer_links"
value={props.building.developer_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.developer_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
<SelectDataEntry
title={dataFields.developer_source_type.title}
slug="developer_source_type"
@ -252,7 +228,7 @@ const TeamView: React.FunctionComponent<CategoryViewProps> = (props) => {
</>
}
</DataEntryGroup>
<DataEntryGroup name="Designer data">
<DataEntryGroup name="Designer">
<MultiDataEntry
title={dataFields.designers.title}
slug="designers"
@ -263,6 +239,7 @@ const TeamView: React.FunctionComponent<CategoryViewProps> = (props) => {
tooltip={dataFields.designers.tooltip}
placeholder=""
editableEntries={true}
disabled={true}
/>
<Verification
slug="designers"
@ -272,7 +249,18 @@ const TeamView: React.FunctionComponent<CategoryViewProps> = (props) => {
user_verified_as={props.user_verified.designers}
verified_count={props.building.verified.designers}
/>
<MultiDataEntry
title={dataFields.designers_links.title}
slug="designers_links"
value={props.building.designers_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.designers_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
<SelectDataEntry
slug='lead_designer_type'
title={dataFields.lead_designer_type.title}
@ -319,7 +307,70 @@ const TeamView: React.FunctionComponent<CategoryViewProps> = (props) => {
/>
</>
}
<hr/>
</DataEntryGroup>
<DataEntryGroup name="Builder">
<MultiDataEntry
title={dataFields.builder.title}
slug="builder"
value={props.building.builder}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.builder.tooltip}
placeholder=""
editableEntries={true}
disabled={true}
/>
<Verification
slug="builder"
allow_verify={props.user !== undefined && props.building.builder !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("builder")}
user_verified_as={props.user_verified.builder}
verified_count={props.building.verified.builder}
/>
<MultiDataEntry
title={dataFields.builder_links.title}
slug="builder_links"
value={props.building.builder_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.builder_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
<SelectDataEntry
title={dataFields.builder_source_type.title}
slug="builder_source_type"
value={props.building.builder_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.builder_source_type.tooltip}
options={dataFields.builder_source_type.items}
placeholder={dataFields.builder_source_type.example}
/>
{(props.building.builder_source_type == commonSourceTypes[0] ||
props.building.builder_source_type == commonSourceTypes[1] ||
props.building.builder_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.builder_source_link.title}
slug="builder_source_link"
value={props.building.builder_source_link}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</DataEntryGroup>
<DataEntryGroup name="Awards">
<LogicalDataEntryYesOnly
slug='designer_awards'
title={dataFields.designer_awards.title}
@ -363,54 +414,6 @@ const TeamView: React.FunctionComponent<CategoryViewProps> = (props) => {
) : (null)
}
</DataEntryGroup>
<DataEntryGroup name="Builder data">
<MultiDataEntry
title={dataFields.builder.title}
slug="builder"
value={props.building.builder}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
placeholder=""
editableEntries={true}
/>
<Verification
slug="builder"
allow_verify={props.user !== undefined && props.building.builder !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("builder")}
user_verified_as={props.user_verified.builder}
verified_count={props.building.verified.builder}
/>
<SelectDataEntry
title={dataFields.builder_source_type.title}
slug="builder_source_type"
value={props.building.builder_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.builder_source_type.tooltip}
options={dataFields.builder_source_type.items}
placeholder={dataFields.builder_source_type.example}
/>
{(props.building.builder_source_type == commonSourceTypes[0] ||
props.building.builder_source_type == commonSourceTypes[1] ||
props.building.builder_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.builder_source_link.title}
slug="builder_source_link"
value={props.building.builder_source_link}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</DataEntryGroup>
</form>
);
};

View File

@ -1,6 +1,6 @@
import React, { Fragment } from 'react';
import { dataFields } from '../../config/data-fields-config';
import { commonSourceTypes, dataFields } from '../../config/data-fields-config';
import DataEntry from '../data-components/data-entry';
import NumericDataEntry from '../data-components/numeric-data-entry';
import SelectDataEntry from '../data-components/select-data-entry';
@ -10,27 +10,316 @@ import withCopyEdit from '../data-container';
import { CategoryViewProps } from './category-view-props';
import InfoBox from '../../components/info-box';
import { DataEntryGroup } from '../data-components/data-entry-group';
const AttachmentFormOptions = [
"Detached",
"Semi-Detached",
"End-Terrace",
"Mid-Terrace"
];
import { MultiDataEntry } from '../data-components/multi-data-entry/multi-data-entry';
import { useDisplayPreferences } from '../../displayPreferences-context';
/**
* Type view/edit section
*/
const TypeView: React.FunctionComponent<CategoryViewProps> = (props) => {
const { darkLightTheme } = useDisplayPreferences();
const switchToClassificationMapStyle = (e) => {
e.preventDefault();
props.onMapColourScale('typology_classification')
}
const switchToStylePeriodMapStyle = (e) => {
e.preventDefault();
props.onMapColourScale('typology_style_period')
}
const switchToDynamicClassificationMapStyle = (e) => {
e.preventDefault();
props.onMapColourScale('typology_dynamic_classification')
}
const switchToAttachmentMapStyle = (e) => {
e.preventDefault();
props.onMapColourScale('building_attachment_form')
}
const switchToLandUseMapStyle = (e) => {
e.preventDefault();
props.onMapColourScale('original_landuse')
}
return (
<Fragment>
<DataEntryGroup name="Adjacency and building use data">
<DataEntryGroup name="Basic typology classification">
{(props.mapColourScale == "typology_classification") ?
<button className={`map-switcher-inline enabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToStylePeriodMapStyle}>
{'Click here to change map to show architectural style/historical period.'}
</button>
:
<button className={`map-switcher-inline disabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToClassificationMapStyle}>
{"Click to change map to show typology classification."}
</button>
}
<SelectDataEntry
title={dataFields.typology_classification.title}
slug="typology_classification"
value={props.building.typology_classification}
tooltip={dataFields.typology_classification.tooltip}
options={dataFields.typology_classification.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
/>
<Verification
slug="typology_classification"
allow_verify={props.user !== undefined && props.building.typology_classification !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("typology_classification")}
user_verified_as={props.user_verified.typology_classification}
verified_count={props.building.verified.typology_classification}
/>
<SelectDataEntry
title={dataFields.typology_classification_source_type.title}
slug="typology_classification_source_type"
value={props.building.typology_classification_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.typology_classification_source_type.tooltip}
placeholder={dataFields.typology_classification_source_type.example}
options={dataFields.typology_classification_source_type.items}
/>
{(props.building.typology_classification_source_type == commonSourceTypes[0] ||
props.building.typology_classification_source_type == commonSourceTypes[1] ||
props.building.typology_classification_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.typology_classification_source_links.title}
slug="typology_classification_source_links"
value={props.building.typology_classification_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.typology_classification_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</DataEntryGroup>
<DataEntryGroup name="Architectural style">
{/*(props.mapColourScale == "typology_style_period") ?
<button className={`map-switcher-inline enabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToClassificationMapStyle}>
{'Click to change map to show typology classification.'}
</button>
:
<button className={`map-switcher-inline disabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToStylePeriodMapStyle}>
{"Click here to change map to show architectural style/historical period."}
</button>
*/}
<SelectDataEntry
title={dataFields.typology_style_period.title}
slug="typology_style_period"
value={props.building.typology_style_period}
tooltip={dataFields.typology_style_period.tooltip}
options={dataFields.typology_style_period.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
disabled={true}
/>
{/*
<Verification
slug="typology_style_period"
allow_verify={props.user !== undefined && props.building.typology_style_period !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("typology_style_period")}
user_verified_as={props.user_verified.typology_style_period}
verified_count={props.building.verified.typology_style_period}
/> */}
<div className={`alert alert-dark`} role="alert" style={{ fontSize: 14, backgroundColor: "#f6f8f9" }}>
<i className="source-url">To edit the architectural style box, and to see the data mapped, please go to <a href={"/"+props.mode+"/age/"+props.building.building_id}>Age & History</a>.</i>
</div>
{/* <SelectDataEntry
title={dataFields.typology_style_period_source_type.title}
slug="typology_style_period_source_type"
value={props.building.typology_style_period_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.typology_style_period_source_type.tooltip}
placeholder={dataFields.typology_style_period_source_type.example}
options={dataFields.typology_style_period_source_type.items}
/>
{(props.building.typology_style_period_source_type == commonSourceTypes[0] ||
props.building.typology_style_period_source_type == commonSourceTypes[1] ||
props.building.typology_style_period_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.typology_style_period_source_links.title}
slug="typology_style_period_source_links"
value={props.building.typology_style_period_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.typology_style_period_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
} */}
</DataEntryGroup>
<DataEntryGroup name="Dynamic tissue classification">
{(props.mapColourScale == "typology_dynamic_classification") ?
<button className={`map-switcher-inline enabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToClassificationMapStyle}>
{'Click to change map to show typology classification.'}
</button>
:
<button className={`map-switcher-inline disabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToDynamicClassificationMapStyle}>
{"Click here to change map to show dynamic classification."}
</button>
}
<SelectDataEntry
title={dataFields.typology_dynamic_classification.title}
slug="typology_dynamic_classification"
value={props.building.typology_dynamic_classification}
tooltip={dataFields.typology_dynamic_classification.tooltip}
options={dataFields.typology_dynamic_classification.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
/>
<Verification
slug="typology_dynamic_classification"
allow_verify={props.user !== undefined && props.building.typology_dynamic_classification !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("typology_dynamic_classification")}
user_verified_as={props.user_verified.typology_dynamic_classification}
verified_count={props.building.verified.typology_dynamic_classification}
/>
<SelectDataEntry
title={dataFields.typology_dynamic_classification_source_type.title}
slug="typology_dynamic_classification_source_type"
value={props.building.typology_dynamic_classification_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.typology_dynamic_classification_source_type.tooltip}
placeholder={dataFields.typology_dynamic_classification_source_type.example}
options={dataFields.typology_dynamic_classification_source_type.items}
/>
{(props.building.typology_dynamic_classification_source_type == commonSourceTypes[0] ||
props.building.typology_dynamic_classification_source_type == commonSourceTypes[1] ||
props.building.typology_dynamic_classification_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.typology_dynamic_classification_source_links.title}
slug="typology_dynamic_classification_source_links"
value={props.building.typology_dynamic_classification_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.typology_dynamic_classification_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</DataEntryGroup>
<DataEntryGroup name="Original Use">
{(props.mapColourScale == "original_landuse") ?
<button className={`map-switcher-inline enabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToClassificationMapStyle}>
{'Click to change map to show typology classification.'}
</button>
:
<button className={`map-switcher-inline disabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToLandUseMapStyle}>
{"Click here to change map to original land use."}
</button>
}
<MultiDataEntry
title={dataFields.typology_original_use.title}
slug="typology_original_use"
value={props.building.typology_original_use}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
confirmOnEnter={true}
tooltip={dataFields.typology_original_use.tooltip}
placeholder="Type new land use group here"
copyable={true}
autofill={true}
showAllOptionsOnEmpty={true}
/>
<Verification
slug="typology_original_use"
allow_verify={props.user !== undefined && props.building.typology_original_use !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("typology_original_use")}
user_verified_as={props.user_verified.typology_original_use}
verified_count={props.building.verified.typology_original_use}
/>
<SelectDataEntry
title={dataFields.typology_original_use_source_type.title}
slug="typology_original_use_source_type"
value={props.building.typology_original_use_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.typology_original_use_source_type.tooltip}
placeholder={dataFields.typology_original_use_source_type.example}
options={dataFields.typology_original_use_source_type.items}
/>
{(props.building.typology_original_use_source_type == commonSourceTypes[0] ||
props.building.typology_original_use_source_type == commonSourceTypes[1] ||
props.building.typology_original_use_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.typology_original_use_source_links.title}
slug="typology_original_use_source_links"
value={props.building.typology_original_use_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.typology_original_use_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
<hr/>
{
props.mode != 'view' &&
<div>
<div className={`alert alert-dark`} role="alert" style={{ fontSize: 13, backgroundColor: "#f6f8f9" }}>
<i>
Below is a more general classification for the original land use of this building, automatically derived from the information above.
</i>
</div>
</div>
}
<DataEntry
title={dataFields.typology_original_use_order.title}
tooltip={dataFields.typology_original_use_order.tooltip}
slug="typology_original_use_order"
value={props.building.typology_original_use_order}
mode={props.mode}
disabled={true}
copy={props.copy}
onChange={props.onChange}
/>
</DataEntryGroup>
<DataEntryGroup name="Attachment/Adjacency">
{(props.mapColourScale == "building_attachment_form") ?
<button className={`map-switcher-inline enabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToClassificationMapStyle}>
{'Click to change map to show typology classification.'}
</button>
:
<button className={`map-switcher-inline disabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToAttachmentMapStyle}>
{"Click here to change map to show attachment/adjacency."}
</button>
}
<SelectDataEntry
title={dataFields.building_attachment_form.title}
slug="building_attachment_form"
value={props.building.building_attachment_form}
tooltip={dataFields.building_attachment_form.tooltip}
options={AttachmentFormOptions}
options={dataFields.building_attachment_form.items}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
@ -43,67 +332,38 @@ const TypeView: React.FunctionComponent<CategoryViewProps> = (props) => {
user_verified_as={props.user_verified.building_attachment_form}
verified_count={props.building.verified.building_attachment_form}
/>
<DataEntry
title="Source type"
slug=""
value=""
mode='view'
tooltip="Coming Soon"
/>
<DataEntry
title="Source link"
slug=""
value=""
mode='view'
tooltip="Coming Soon"
/>
<hr/>
<DataEntry
title={dataFields.original_building_use.title}
slug="original_building_use" // doesn't exist in database yet
tooltip={dataFields.original_building_use.tooltip}
value={undefined}
copy={props.copy}
<SelectDataEntry
title={dataFields.building_attachment_source_type.title}
slug="building_attachment_source_type"
value={props.building.building_attachment_source_type}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
disabled={true}
tooltip={dataFields.building_attachment_source_type.tooltip}
placeholder={dataFields.building_attachment_source_type.example}
options={dataFields.building_attachment_source_type.items}
/>
<Verification
slug="building_attachment_form"
allow_verify={props.user !== undefined && props.building.building_attachment_form !== null && !props.edited}
onVerify={props.onVerify}
user_verified={props.user_verified.hasOwnProperty("building_attachment_form")}
user_verified_as={props.user_verified.building_attachment_form}
verified_count={props.building.verified.building_attachment_form}
/>
<DataEntry
title="Source type"
slug=""
value=""
mode='view'
tooltip="Coming Soon"
/>
<DataEntry
title="Source link"
slug=""
value=""
mode='view'
tooltip="Coming Soon"
{(props.building.building_attachment_source_type == commonSourceTypes[0] ||
props.building.building_attachment_source_type == commonSourceTypes[1] ||
props.building.building_attachment_source_type == null) ? <></> :
<>
<MultiDataEntry
title={dataFields.building_attachment_source_links.title}
slug="building_attachment_source_links"
value={props.building.building_attachment_source_links}
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
tooltip={dataFields.building_attachment_source_links.tooltip}
placeholder="https://..."
editableEntries={true}
isUrl={true}
/>
</>
}
</DataEntryGroup>
<DataEntryGroup name="Building typology and classification data">
<DataEntry
title="Local typology/architectural style"
slug=""
value=""
mode='view'
/>
<DataEntry
title="Base type classification"
slug=""
value=""
mode='view'
/>
{/*}
<DataEntryGroup name="Other fields (in development)">
<SelectDataEntry
title={dataFields.size_roof_shape.title}
slug="size_roof_shape"
@ -136,6 +396,7 @@ const TypeView: React.FunctionComponent<CategoryViewProps> = (props) => {
value=""
mode='view'
/>
{/* <NumericDataEntry
title={dataFields.date_change_building_use.title}
slug="date_change_building_use"
@ -147,8 +408,8 @@ const TypeView: React.FunctionComponent<CategoryViewProps> = (props) => {
mode={props.mode}
copy={props.copy}
onChange={props.onChange}
/> */}
</DataEntryGroup>
/>//*}
</DataEntryGroup>*/}
</Fragment>
);
};

View File

@ -184,3 +184,16 @@
padding-top: 0px;
padding-bottom: 5px;
}
dd {
margin-bottom: 15px;
}
.uprn-list {
margin-top: 10px;
margin-bottom: 0px;
}
.uprn-list li {
margin-bottom: 10px;
}

View File

@ -98,7 +98,7 @@ export const categoriesConfig: {[key in Category]: CategoryDefinition} = {
slug: 'typology',
name: 'Typology',
aboutUrl: 'https://pages.colouring.london/buildingtypology',
intro: 'Note: This section is currently under development, we are working to activate it as soon as possible. This section provides open data on the typology of the building.',
intro: 'This section provides open data on the typology of the building.',
},
[Category.LandUse]: {
slug: 'land-use',

View File

@ -48,6 +48,25 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition[]} =
]
},
},
{
mapStyle: 'typology_style_period',
legend: {
title: 'Architectural style',
elements: [
{ color: '#FFF739', text: '43AD-410 (Roman)' },
{ color: '#C5BD00', text: '410-1485 (Medieval)' },
{ color: '#FF9A39', text: '1485-1603 (Tudor)' },
{ color: '#C56000', text: '1603-1714 (Stuart)' },
{ color: '#EA8072', text: '1714-1837 (Georgian)' },
{ color: '#A71200', text: '1837-1901 (Victorian)' },
{ color: '#A272D4', text: '1901-1914 (Edwardian)' },
{ color: '#3988C5', text: '1914-1945 (WWI-WWII)' },
{ color: '#5ADFA2', text: '1946-1979 (Post war)' },
{ color: '#C2F47A', text: '1980-1999 (Late C20)' },
{ color: '#6FB40A', text: '2000-2025 (Early C21)' },
]
}
},
{
mapStyle: 'survival_status',
legend: {
@ -299,10 +318,82 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition[]} =
]
},
}],
[Category.Typology]: [{
[Category.Typology]: [
{
mapStyle: 'typology_classification',
legend: {
title: 'Typology classification',
elements: [
{ color: '#0311AB', text: '1-3 storeys: Detached' },
{ color: '#3845D4', text: '1-3 storeys: Tightly grouped' },
{ color: '#6D79FD', text: '1-3 storeys: Loosely grouped' },
{ color: '#FF5D00', text: '4-7 storeys: Detached' },
{ color: '#FF8000', text: '4-7 storeys: Tightly grouped' },
{ color: '#FFA200', text: '4-7 storeys: Loosely grouped' },
{ color: '#AB1303', text: '8+ storeys: Detached' },
{ color: '#D43A29', text: '8+ storeys: Tightly grouped' },
{ color: '#FC604F', text: '8+ storeys: Loosely grouped' },
]
}
},
/*{
mapStyle: 'typology_style_period',
legend: {
title: 'Architectural style',
elements: [
{ color: '#FFF739', text: '43AD-410 (Roman)' },
{ color: '#C5BD00', text: '410-1485 (Medieval)' },
{ color: '#FF9A39', text: '1485-1603 (Tudor)' },
{ color: '#C56000', text: '1603-1714 (Stuart)' },
{ color: '#EA8072', text: '1714-1837 (Georgian)' },
{ color: '#A71200', text: '1837-1901 (Victorian)' },
{ color: '#A272D4', text: '1901-1914 (Edwardian)' },
{ color: '#3988C5', text: '1914-1945 (WWI-WWII)' },
{ color: '#5ADFA2', text: '1946-1979 (Post war)' },
{ color: '#C2F47A', text: '1980-1999 (Late C20)' },
{ color: '#6FB40A', text: '2000-2025 (Early C21)' },
]
}
},*/
{
mapStyle: 'typology_dynamic_classification',
legend: {
title: 'Dynamic classification',
elements: [
{ color: '#96484A', text: 'Repetitive small, domestic plots' },
{ color: '#4B9889', text: 'Linear non-domestic, i.e. high streets' },
{ color: '#4F8DA8', text: 'Large plots with internal roads' },
{ color: '#897A5D', text: 'Other' },
]
}
},
{
mapStyle: 'original_landuse',
legend: {
title: 'Original Land Use',
elements: [
{ color: '#e5050d', text: 'Mixed Use' },
{ subtitle: 'Single use:'},
{ color: '#252aa6', text: 'Residential (unverified)' },
{ color: '#7025a6', text: 'Residential (verified)' },
{ color: '#ff8c00', text: 'Retail' },
{ color: '#f5f58f', text: 'Industry & Business' },
{ color: '#fa667d', text: 'Community Services' },
{ color: '#ffbfbf', text: 'Recreation & Leisure' },
{ color: '#b3de69', text: 'Transport' },
{ color: '#cccccc', text: 'Utilities & Infrastructure' },
{ color: '#898944', text: 'Defence' },
{ color: '#73ccd1', text: 'Agriculture' },
{ color: '#45cce3', text: 'Minerals' },
{ color: '#ffffff', text: 'Vacant & Derelict' },
{ color: '#6c6f8e', text: 'Unclassified, presumed non-residential' }
]
},
},
{
mapStyle: 'building_attachment_form',
legend: {
title: 'Adjacency/Configuration',
title: 'Attachment/Adjacency',
elements: [
{ color: "#f2a2b9", text: "Detached" },
{ color: "#ab8fb0", text: "Semi-Detached" },
@ -310,7 +401,8 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition[]} =
{ color: "#226291", text: "Mid-Terrace" }
]
},
}],
},
],
[Category.LandUse]: [
{
mapStyle: 'landuse',
@ -338,11 +430,11 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition[]} =
{
mapStyle: 'is_domestic',
legend: {
title: 'Domestic building',
title: 'Residential building',
elements: [
{ color: '#f7ec25', text: 'Domestic' },
{ color: '#f7ec25', text: 'Residential' },
{ color: '#fc9b2a', text: 'Mixed' },
{ color: '#ff2121', text: 'Non-domestic' },
{ color: '#ff2121', text: 'Non-residential' },
]
}
}

View File

@ -7,7 +7,7 @@ import ResilienceContainer from '../building/data-containers/resilience';
import LocationContainer from '../building/data-containers/location';
import PlanningContainer from '../building/data-containers/planning';
import SizeContainer from '../building/data-containers/size';
import StreetscapeContainer from '../building/data-containers/street-context';
import StreetContextContainer from '../building/data-containers/street-context';
import SustainabilityContainer from '../building/data-containers/energy-performance';
import TeamContainer from '../building/data-containers/team';
import TypeContainer from '../building/data-containers/typology';
@ -22,7 +22,7 @@ export const categoryUiConfig: {[key in Category]: DataContainerType} = {
[Category.Age]: AgeContainer,
[Category.Size]: SizeContainer,
[Category.Construction]: ConstructionContainer,
[Category.StreetContext]: StreetscapeContainer,
[Category.StreetContext]: StreetContextContainer,
[Category.Team]: TeamContainer,
[Category.Planning]: PlanningContainer,
[Category.EnergyPerformance]: SustainabilityContainer,

File diff suppressed because it is too large Load Diff

View File

@ -21,10 +21,14 @@ export type BuildingMapTileset =
'sust_dec' |
'building_attachment_form' |
'landuse' |
'original_landuse' |
'dynamics_demolished_count' |
'disaster_severity' |
'team' |
'survival_status';
'survival_status'|
'typology_classification'|
'typology_style_period' |
'typology_dynamic_classification';
export type SpecialMapTileset = 'base_light' | 'base_night' | 'base_night_outlines' | 'highlight' | 'number_labels' | 'base_boroughs';

View File

@ -38,6 +38,10 @@ interface DisplayPreferencesContextState {
historicDataSwitch: (e: React.FormEvent<HTMLFormElement>) => void;
historicDataSwitchOnClick: React.MouseEventHandler<HTMLButtonElement>;
historicMap: LayerEnablementState;
historicMapSwitch: (e: React.FormEvent<HTMLFormElement>) => void;
historicMapSwitchOnClick: React.MouseEventHandler<HTMLButtonElement>;
darkLightTheme: MapTheme;
darkLightThemeSwitch: (e: React.FormEvent<HTMLFormElement>) => void;
darkLightThemeSwitchOnClick: React.MouseEventHandler<HTMLButtonElement>;
@ -87,6 +91,10 @@ export const DisplayPreferencesContext = createContext<DisplayPreferencesContext
historicDataSwitch: stub,
historicDataSwitchOnClick: undefined,
historicMap: undefined,
historicMapSwitch: stub,
historicMapSwitchOnClick: undefined,
darkLightTheme: undefined,
darkLightThemeSwitch: stub,
darkLightThemeSwitchOnClick: undefined,
@ -107,6 +115,7 @@ export const DisplayPreferencesProvider: React.FC<{}> = ({children}) => {
const defaultParcel = 'disabled'
const defaultConservation = 'disabled'
const defaultHistoricData = 'disabled'
const defaultHistoricMap = 'disabled'
const defaultShowLayerSelection = 'disabled'
const [vista, setVista] = useState<LayerEnablementState>(defaultVista);
const [flood, setFlood] = useState<LayerEnablementState>(defaultFlood);
@ -116,6 +125,7 @@ export const DisplayPreferencesProvider: React.FC<{}> = ({children}) => {
const [parcel, setParcel] = useState<LayerEnablementState>(defaultParcel);
const [conservation, setConservation] = useState<LayerEnablementState>(defaultConservation);
const [historicData, setHistoricData] = useState<LayerEnablementState>(defaultHistoricData);
const [historicMap, setHistoricMap] = useState<LayerEnablementState>(defaultHistoricMap);
const [darkLightTheme, setDarkLightTheme] = useState<MapTheme>('night');
const [showLayerSelection, setShowLayerSelection] = useState<LayerEnablementState>(defaultShowLayerSelection);
@ -136,6 +146,7 @@ export const DisplayPreferencesProvider: React.FC<{}> = ({children}) => {
setParcel(defaultParcel);
setConservation(defaultConservation);
setHistoricData(defaultHistoricData);
setHistoricMap(defaultHistoricMap);
setShowLayerSelection(defaultShowLayerSelection); // reset layers + hiding this panel is integrated into one action
//setDarkLightTheme('night'); // reset only layers
},
@ -167,6 +178,9 @@ export const DisplayPreferencesProvider: React.FC<{}> = ({children}) => {
if(historicData != defaultHistoricData) {
return true;
}
if(historicMap != defaultHistoricMap) {
return true;
}
//darkLightTheme not handled here
return false;
}
@ -278,9 +292,12 @@ export const DisplayPreferencesProvider: React.FC<{}> = ({children}) => {
const historicDataSwitch = useCallback(
(e) => {
flipHistoricData(e)
if (historicMap === 'enabled') {
fliphistoricMap(e);
}
flipHistoricData(e);
},
[historicData],
[historicData, historicMap],
)
const historicDataSwitchOnClick = (e) => {
flipHistoricData(e)
@ -291,6 +308,24 @@ export const DisplayPreferencesProvider: React.FC<{}> = ({children}) => {
setHistoricData(newHistoric);
}
const historicMapSwitch = useCallback(
(e) => {
if (historicData === 'enabled') {
flipHistoricData(e);
}
fliphistoricMap(e);
},
[historicMap, historicData],
)
const historicMapSwitchOnClick = (e) => {
fliphistoricMap(e)
}
function fliphistoricMap(e) {
e.preventDefault();
const newHistoric = (historicMap === 'enabled')? 'disabled' : 'enabled';
setHistoricMap(newHistoric);
}
const darkLightThemeSwitch = useCallback(
(e) => {
flipDarkLightTheme(e)
@ -354,6 +389,10 @@ export const DisplayPreferencesProvider: React.FC<{}> = ({children}) => {
historicDataSwitch,
historicDataSwitchOnClick,
historicMap,
historicMapSwitch,
historicMapSwitchOnClick,
darkLightTheme,
darkLightThemeSwitch,
darkLightThemeSwitchOnClick,

View File

@ -57,7 +57,8 @@ function getCurrentMenuLinks(username: string): MenuLink[][] {
},
{
to: "https://github.com/colouring-cities/manual/wiki",
text: "Open Manual - Wiki",
text: "Colouring Cities Open Manual/Wiki",
disabled: false,
external: true
},
{
@ -65,12 +66,6 @@ function getCurrentMenuLinks(username: string): MenuLink[][] {
text: "Open code",
external: true
},
{
to: "https://github.com/colouring-cities/manual/wiki",
text: "Colouring Cities Open Manual/Wiki",
disabled: false,
external: true
},
{
to: "/showcase.html",
text: "Case Study Showcase",
@ -79,30 +74,35 @@ function getCurrentMenuLinks(username: string): MenuLink[][] {
],
[
{
to: "https://pages.colouring.london",
text: "About",
to: "https://github.com/colouring-cities/manual/wiki/A.-What-is-the-CCRP%3F",
text: "About the Colouring Cities Research Programme",
external: true
},
{
to: "https://pages.colouring.london/buildingcategories",
to: config.manualURL,
text: "About the Colouring " + config.cityName + " Project",
external: true
},
{
to: "https://github.com/colouring-cities/manual/wiki/A2.-How-to%3F-Guides",
text: "How to Use",
external: true
},
{
to: "https://github.com/colouring-cities/manual/wiki/I.--DATA",
text: "Data Categories",
external: true
},
{
to: "https://pages.colouring.london/whoisinvolved",
to: "https://github.com/colouring-cities/manual/wiki/M3.2-Colouring-Britain:-Who's-Involved%3F",
text: "Who's Involved?",
external: true
},
{
to: "https://pages.colouring.london/data-ethics",
text: "Data Ethics",
to: "https://github.com/colouring-cities/manual/wiki/C.-Ethical-framework-and-ethics-policies",
text: "Ethical Framework",
external: true
},
{
to: "https://pages.colouring.london/colouring-cities",
text: "Colouring Cities Research Programme",
external: true
},
}
],
[
{
@ -110,32 +110,45 @@ function getCurrentMenuLinks(username: string): MenuLink[][] {
text: "Top Contributors"
},
{
to: "https://discuss.colouring.london",
text: "Discussion Forum",
external: true
},
{
to: "https://discuss.colouring.london/c/blog/9",
text: "Blog",
to: config.githubURL+"/discussions",
text: "Discussion Forum (GitHub)",
external: true
},
// {
// to: "https://discuss.colouring.london/c/blog/9",
// text: "Blog",
// external: true
// },
],
[
{
to: "/privacy-policy.html",
text: "Privacy Policy"
to: "https://github.com/colouring-cities/manual/wiki/C1.-Protocols,-codes-of-conduct-&-data-sharing-agreements#ccrp-contributor-privacy-statement",
text: "Privacy Policy",
external: true
},
{
to: "/contributor-agreement.html",
text: "Contributor Agreement"
to: "https://github.com/colouring-cities/manual/wiki/C1.-Protocols,-codes-of-conduct-&-data-sharing-agreements#ccrp-contributor--data-user-data-accuracy--ethical-use-agreement",
text: "Contributor Agreement",
external: true
},
{
to: "/code-of-conduct.html",
text: "Code of Conduct"
},
{
to: "/data-accuracy.html",
text: "Data Accuracy Agreement"
to: "https://github.com/colouring-cities/manual/wiki/C1.-Protocols,-codes-of-conduct-&-data-sharing-agreements#ccrp-contributor--data-user-data-accuracy--ethical-use-agreement",
text: "Data Accuracy and Use Agreement",
external: true
},
{
to: "https://github.com/colouring-cities/manual/wiki/C1.-Protocols,-codes-of-conduct-&-data-sharing-agreements#ccrp-equality-diversity-and-inclusion-policy",
text: "Equality, Diversity and Inclusion",
external: true
},
{
to: "https://github.com/colouring-cities/manual/wiki/C1.-Protocols,-codes-of-conduct-&-data-sharing-agreements#ccrp-protocols-for-international-academic-partners",
text: "CCRP Academic Partner Protocols",
external: true
},
{
to: "/ordnance-survey-uprn.html",
@ -183,7 +196,7 @@ const InternalNavLink: React.FC<{to: string; onClick: () => void}> = ({ to, onCl
);
const ExternalNavLink: React.FC<{to: string}> = ({ to, children }) => (
<a className="nav-link" href={to}>
<a className="nav-link" href={to} target="_blank">
{children}
</a>
);

View File

@ -5,11 +5,12 @@ import { useDisplayPreferences } from '../displayPreferences-context';
export const HistoricDataSwitcher: React.FC<{}> = (props) => {
const { historicData, historicDataSwitch, darkLightTheme } = useDisplayPreferences();
return (
<form className={`historic-data-switcher map-button ${historicData}-state ${darkLightTheme}`} onSubmit={historicDataSwitch}>
<button className="btn btn-outline btn-outline-dark"
type="submit">
{(historicData === 'enabled')? 'The OS 1890s Historical Map on' : 'The OS 1890s Historical Map off'}
{(historicData === 'enabled')? 'OS 1890s Historical Map + Footprints on' : 'OS 1890s Historical Map + Footprints off'}
</button>
</form>
);

View File

@ -0,0 +1,17 @@
import React from 'react';
import './map-button.css';
import { useDisplayPreferences } from '../displayPreferences-context';
export const HistoricMapSwitcher: React.FC<{}> = (props) => {
const { historicMap, historicMapSwitch, darkLightTheme } = useDisplayPreferences();
return (
<form className={`historic-map-switcher map-button ${historicMap}-state ${darkLightTheme}`} onSubmit={historicMapSwitch}>
<button className="btn btn-outline btn-outline-dark"
type="submit">
{(historicMap === 'enabled')? 'OS 1890s Historical Map on' : 'OS 1890s Historical Map off'}
</button>
</form>
);
}

View File

@ -0,0 +1,21 @@
import * as React from 'react';
import { TileLayer } from 'react-leaflet';
import { LayerEnablementState } from '../../config/map-config';
import { BuildingBaseLayerAllZoom } from './building-base-layer-all-zoom';
import { useDisplayPreferences } from '../../displayPreferences-context';
import { BuildingDataLayer } from './building-data-layer';
export function HistoricMapLayer({revisionId}: {revisionId: string}) {
const { historicMap } = useDisplayPreferences();
if(historicMap == "enabled") {
return <>
<TileLayer
url="https://mapseries-tilesets.s3.amazonaws.com/london_1890s/{z}/{x}/{y}.png"
attribution='&copy; CC BY 4.0 - Reproduced with the permission of the <a href="https://maps.nls.uk/">National Library of Scotland</a>'
/>
</>
} else {
return null;
}
}

View File

@ -57,7 +57,7 @@
padding: 0.5rem 0.25rem;
margin: 0.25rem 0.5rem;
width: auto;
font-size: 18px;
font-size: 17px;
border: 1px solid;
border-radius: 4px;
}

View File

@ -111,11 +111,15 @@
}
.historic-data-switcher {
top: 437px;
}
.historic-map-switcher {
top: 397px;
}
.parcel-switcher {
top: 437px;
top: 477px;
}
.map-switcher-inline {

View File

@ -15,6 +15,7 @@ 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 { HistoricMapLayer } from './layers/historic-map-layer';
import { FloodBoundaryLayer } from './layers/flood-boundary-layer';
import { ConservationAreaBoundaryLayer } from './layers/conservation-boundary-layer';
import { VistaBoundaryLayer } from './layers/vista-boundary-layer';
@ -34,6 +35,7 @@ import { ParcelSwitcher } from './parcel-switcher';
import { FloodSwitcher } from './flood-switcher';
import { ConservationAreaSwitcher } from './conservation-switcher';
import { HistoricDataSwitcher } from './historic-data-switcher';
import { HistoricMapSwitcher } from './historic-map-switcher';
import { VistaSwitcher } from './vista-switcher';
import { CreativeSwitcher } from './creative-switcher';
import { HousingSwitcher } from './housing-switcher';
@ -129,6 +131,7 @@ export const ColouringMap : FC<ColouringMapProps> = ({
>
<CityBoundaryLayer/>
<HistoricDataLayer revisionId={revisionId} />
<HistoricMapLayer revisionId={revisionId} />
<BoroughBoundaryLayer/>
<ParcelBoundaryLayer/>
<FloodBoundaryLayer/>
@ -167,10 +170,12 @@ export const ColouringMap : FC<ColouringMapProps> = ({
<ParcelSwitcher/>
<FloodSwitcher/>
<ConservationAreaSwitcher/>
<HistoricMapSwitcher/>
<HistoricDataSwitcher/>
<VistaSwitcher />
<HousingSwitcher />
<CreativeSwitcher />
</>
: <></>
}

View File

@ -266,6 +266,15 @@ const LAYER_QUERIES = {
buildings
WHERE
current_landuse_order IS NOT NULL`,
original_landuse: `
SELECT
geometry_id,
typology_original_use_order,
typology_original_use[1] as typology_original_use,
typology_original_use_verified
FROM
buildings
WHERE typology_original_use IS NOT NULL`,
disaster_severity: `
SELECT
geometry_id,
@ -281,6 +290,27 @@ const LAYER_QUERIES = {
FROM
buildings
WHERE jsonb_array_length(demolished_buildings) > 0 OR dynamics_has_demolished_buildings = FALSE`,
typology_classification: `
SELECT
geometry_id,
typology_classification
FROM
buildings
WHERE typology_classification IS NOT NULL`,
typology_style_period: `
SELECT
geometry_id,
typology_style_period
FROM
buildings
WHERE typology_style_period IS NOT NULL`,
typology_dynamic_classification: `
SELECT
geometry_id,
typology_dynamic_classification
FROM
buildings
WHERE typology_dynamic_classification IS NOT NULL`,
};
const GEOMETRY_FIELD = 'geometry_geom';

View File

@ -326,6 +326,8 @@ pip install -r requirements.txt
To help test the Colouring Cities application, `get_test_polygons.py` will attempt to save a small (1.5km²) extract from OpenStreetMap to a format suitable for loading to the database.
**NOTE:** You can edit the file by [changing this line](https://github.com/colouring-cities/colouring-core/blob/df651521983665056d442603a329a37d966aede1/etl/get_test_polygons.py#L22) to specify the latitude and longitude used to define the centre of the sample data area, as well as the distance from that point, which are used to generate the sample data. (i.e. you could change it to match the cc-config.json file - as discussed in [configuring-colouring-cities.md](https://github.com/colouring-cities/colouring-core/blob/master/docs/configuring-colouring-cities.md).
Download the test data.
```bash

View File

@ -1 +1,3 @@
from .filter_mastermap import filter_mastermap
__all__ = ["filter_mastermap"]

View File

@ -20,24 +20,24 @@ def main(mastermap_path):
def filter_mastermap(mm_path):
output_path = str(mm_path).replace(".gml.csv", "")
output_path = "{}.filtered.csv".format(output_path)
output_fieldnames = ('WKT', 'fid', 'descriptiveGroup')
output_fieldnames = ("WKT", "fid", "descriptiveGroup")
# Open the input csv with all polygons, buildings and others
with open(mm_path, 'r') as fh:
with open(mm_path, "r") as fh:
r = csv.DictReader(fh)
# Open a new output csv that will contain just buildings
with open(output_path, 'w') as output_fh:
with open(output_path, "w") as output_fh:
w = csv.DictWriter(output_fh, fieldnames=output_fieldnames)
w.writeheader()
for line in r:
try:
if 'Building' in line['descriptiveGroup']:
if "Building" in line["descriptiveGroup"]:
w.writerow(line)
# when descriptiveGroup is missing, ignore this Polygon
except TypeError:
pass
if __name__ == '__main__':
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: filter_mastermap.py ./path/to/mastermap/dir")
exit(-1)

View File

@ -21,43 +21,49 @@ size = 256
# load buildings from about 1.5km² around UCL
point = (51.524498, -0.133874)
dist = 612
gdf = osmnx.footprints_from_point(point=point, dist=dist)
tags = {"building": True}
gdf = osmnx.features_from_point(point, tags, dist=dist)
# preview image
gdf_proj = osmnx.projection.project_gdf(gdf, to_crs={'init': 'epsg:3857'})
gdf_proj = gdf_proj[gdf_proj.geometry.apply(lambda g: g.geom_type != 'MultiPolygon')] # noqa
gdf_proj = osmnx.projection.project_gdf(gdf, to_crs={"init": "epsg:3857"})
gdf_proj = gdf_proj[gdf_proj.geometry.type == "Polygon"]
fig, ax = osmnx.plot_footprints(gdf_proj, bgcolor='#333333',
color='w', figsize=(4, 4),
save=True, show=False, close=True,
filename='test_buildings_preview', dpi=600)
fig, ax = osmnx.plot_footprints(
gdf_proj,
bgcolor="#333333",
color="w",
figsize=(4, 4),
save=True,
show=False,
close=True,
filepath="test_buildings_preview.png",
dpi=600,
)
# save
test_dir = os.path.dirname(__file__)
test_data_geojson = str(os.path.join(test_dir, 'test_buildings.geojson'))
test_data_geojson = str(os.path.join(test_dir, "test_buildings.geojson"))
subprocess.run(["rm", test_data_geojson])
gdf_to_save = gdf_proj.reset_index()[["osmid", "geometry"]]
gdf_to_save = gdf_proj.reset_index(
)[
['index', 'geometry']
]
gdf_to_save.rename(
columns={'index': 'fid'}
).to_file(
test_data_geojson, driver='GeoJSON'
gdf_to_save.rename(columns={"osmid": "fid"}).to_file(
test_data_geojson, driver="GeoJSON"
)
# convert to CSV
test_data_csv = str(os.path.join(test_dir, 'test_buildings.3857.csv'))
test_data_csv = str(os.path.join(test_dir, "test_buildings.3857.csv"))
subprocess.run(["rm", test_data_csv])
subprocess.run(
["ogr2ogr", "-f", "CSV", test_data_csv,
test_data_geojson, "-lco", "GEOMETRY=AS_WKT"]
[
"ogr2ogr",
"-f",
"CSV",
test_data_csv,
test_data_geojson,
"-lco",
"GEOMETRY=AS_WKT",
]
)
# add SRID for ease of loading to PostgreSQL
subprocess.run(
["sed", "-i", "s/^\"POLYGON/\"SRID=3857;POLYGON/",
test_data_csv]
)
subprocess.run(["sed", "-i", 's/^"POLYGON/"SRID=3857;POLYGON/', test_data_csv])

View File

@ -17,7 +17,6 @@ Then with this script:
"""
import json
import csv
import os
import subprocess
@ -28,50 +27,49 @@ from tqdm import tqdm
def main(base_url, api_key, source_file):
"""Read from file, update buildings
"""
with open(source_file, 'r') as source_fh:
"""Read from file, update buildings"""
with open(source_file, "r") as source_fh:
source = csv.DictReader(source_fh)
for feature in tqdm(source, total=line_count(source_file)):
building_id, data = process_ca(feature)
if building_id and building_id != 'building_id':
if building_id and building_id != "building_id":
save_data(building_id, data, api_key, base_url)
def line_count(fname):
"""Count lines - relies on 'wc'
"""
p = subprocess.run(['wc', '-l', fname], stdout=subprocess.PIPE)
"""Count lines - relies on 'wc'"""
p = subprocess.run(["wc", "-l", fname], stdout=subprocess.PIPE)
if p.returncode != 0:
raise IOError(err)
raise IOError(p.returncode)
return int(p.stdout.strip().split()[0])
def process_ca(props):
building_id = props['building_id']
building_id = props["building_id"]
data = {
'planning_in_conservation_area': True,
'planning_conservation_area_name': props['conservation_area_name']
"planning_in_conservation_area": True,
"planning_conservation_area_name": props["conservation_area_name"],
}
return building_id, data
def save_data(building_id, data, api_key, base_url):
"""Save data to a building
"""
r = requests.post(
"""Save data to a building"""
requests.post(
"{}/buildings/{}.json?api_key={}".format(base_url, building_id, api_key),
json=data
json=data,
)
if __name__ == '__main__':
if __name__ == "__main__":
try:
url, api_key, filename = sys.argv[1], sys.argv[2], sys.argv[3]
except IndexError:
print(
"Usage: {} <URL> <api_key> ./path/to/conservation_areas.csv".format(
os.path.basename(__file__)
))
)
)
exit()
main(url, api_key, filename)

View File

@ -44,8 +44,6 @@ TODO extend to allow latitude,longitude or easting,northing columns and lookup b
"""
import csv
import json
import os
import sys
import argparse
import requests
@ -53,9 +51,8 @@ from retrying import retry
def main(base_url, api_key, source_file, json_columns, no_overwrite=False, debug=False):
"""Read from file, update buildings
"""
with open(source_file, 'r') as source:
"""Read from file, update buildings"""
with open(source_file, "r") as source:
reader = csv.DictReader(source)
for line in reader:
building_id = find_building(line, base_url)
@ -64,78 +61,86 @@ def main(base_url, api_key, source_file, json_columns, no_overwrite=False, debug
if building_id is None:
continue
if 'sust_dec' in line and line['sust_dec'] == '':
del line['sust_dec']
if "sust_dec" in line and line["sust_dec"] == "":
del line["sust_dec"]
if no_overwrite:
try:
if check_data_present(building_id, line.keys(), base_url):
print(f'Building {building_id}: Not updating to avoid overwriting existing data')
print(
f"Building {building_id}: Not updating to avoid overwriting existing data"
)
continue
except ApiRequestError as e:
print(f'Error checking existing data for building {building_id}: status {e.code}, data: {e.data}')
print(
f"Error checking existing data for building {building_id}: status {e.code}, data: {e.data}"
)
raise
response_code, response_data = update_building(building_id, line, api_key, base_url)
response_code, response_data = update_building(
building_id, line, api_key, base_url
)
if response_code != 200:
print('ERROR', building_id, response_code, response_data)
print("ERROR", building_id, response_code, response_data)
elif debug:
print('DEBUG', building_id, response_code, response_data)
print("DEBUG", building_id, response_code, response_data)
class ApiRequestError(Exception):
def __init__(self, code, data, message=''):
def __init__(self, code, data, message=""):
self.code = code
self.data = data
super().__init__(message)
def check_data_present(building_id, fields, base_url):
response_code, current_state = get_building(building_id, base_url)
if response_code != 200:
raise ApiRequestError(response_code, current_state)
else:
id_fields = set(['building_id', 'toid', 'uprn'])
id_fields = set(["building_id", "toid", "uprn"])
field_names_without_ids = [k for k in fields if k not in id_fields]
return any([current_state.get(k, None) != None for k in field_names_without_ids])
return any(
[current_state.get(k, None) is not None for k in field_names_without_ids]
)
@retry(wait_exponential_multiplier=1000, wait_exponential_max=10000)
def get_building(building_id, base_url):
"""Get data for a building
"""
"""Get data for a building"""
r = requests.get(f"{base_url}/api/buildings/{building_id}.json")
return r.status_code, r.json()
@retry(wait_exponential_multiplier=1000, wait_exponential_max=10000)
def update_building(building_id, data, api_key, base_url):
"""Save data to a building
"""
"""Save data to a building"""
r = requests.post(
"{}/api/buildings/{}.json".format(base_url, building_id),
params={'api_key': api_key},
json=data
params={"api_key": api_key},
json=data,
)
return r.status_code, r.json()
def find_building(data, base_url):
if 'building_id' in data:
building_id = data['building_id']
if "building_id" in data:
building_id = data["building_id"]
if building_id is not None:
print("match_by_building_id", building_id)
return building_id
if 'toid' in data:
building_id = find_by_reference(base_url, 'toid', data['toid'])
if "toid" in data:
building_id = find_by_reference(base_url, "toid", data["toid"])
if building_id is not None:
print("match_by_toid", data['toid'], building_id)
print("match_by_toid", data["toid"], building_id)
return building_id
if 'uprn' in data:
building_id = find_by_reference(base_url, 'uprn', data['uprn'])
if "uprn" in data:
building_id = find_by_reference(base_url, "uprn", data["uprn"])
if building_id is not None:
print("match_by_uprn", data['uprn'], building_id)
print("match_by_uprn", data["uprn"], building_id)
return building_id
print("no_match", data)
@ -144,21 +149,21 @@ def find_building(data, base_url):
@retry(wait_exponential_multiplier=1000, wait_exponential_max=10000)
def find_by_reference(base_url, ref_key, ref_id):
"""Find building_id by TOID or UPRN
"""
r = requests.get("{}/api/buildings/reference".format(base_url), params={
'key': ref_key,
'id': ref_id
})
"""Find building_id by TOID or UPRN"""
r = requests.get(
"{}/api/buildings/reference".format(base_url),
params={"key": ref_key, "id": ref_id},
)
buildings = r.json()
if buildings and 'error' not in buildings and len(buildings) == 1:
building_id = buildings[0]['building_id']
if buildings and "error" not in buildings and len(buildings) == 1:
building_id = buildings[0]["building_id"]
else:
building_id = None
return building_id
def parse_json_columns(row, json_columns):
for col in json_columns:
row[col] = json.loads(row[col])
@ -167,28 +172,41 @@ def parse_json_columns(row, json_columns):
def list_str(values):
return values.split(',')
return values.split(",")
if __name__ == '__main__':
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('url', help='URL for the app')
parser.add_argument('api_key', help='API key for the user')
parser.add_argument('path', help='Path to data CSV file')
parser.add_argument('json_columns',
nargs='?',
parser.add_argument("url", help="URL for the app")
parser.add_argument("api_key", help="API key for the user")
parser.add_argument("path", help="Path to data CSV file")
parser.add_argument(
"json_columns",
nargs="?",
type=list_str,
default=[],
help='A comma-separated list of columns which should be parsed as JSON')
help="A comma-separated list of columns which should be parsed as JSON",
)
parser.add_argument('--no-overwrite', '-n',
action='store_true',
dest='no_overwrite',
help='Don\'t overwrite building data if any of the fields supplied is already set')
parser.add_argument(
"--no-overwrite",
"-n",
action="store_true",
dest="no_overwrite",
help="Don't overwrite building data if any of the fields supplied is already set",
)
parser.add_argument('--debug', '-d',
action='store_true',
help='Print debug messages')
parser.add_argument(
"--debug", "-d", action="store_true", help="Print debug messages"
)
args = parser.parse_args()
main(args.url, args.api_key, args.path, args.json_columns, args.no_overwrite, args.debug)
main(
args.url,
args.api_key,
args.path,
args.json_columns,
args.no_overwrite,
args.debug,
)

View File

@ -23,18 +23,18 @@ The process:
TODO extend to allow latitude,longitude or easting,northing columns and lookup by location.
"""
import csv
import json
import os
import sys
import requests
session = requests.Session()
session.verify = False
def main(base_url, api_key, source_file):
"""Read from file, update buildings
"""
with open(source_file, 'r') as source:
"""Read from file, update buildings"""
with open(source_file, "r") as source:
reader = csv.DictReader(source)
for line in reader:
building_id = find_building(line, base_url)
@ -42,40 +42,41 @@ def main(base_url, api_key, source_file):
if building_id is None:
continue
response_code, response_data = update_building(building_id, line, api_key, base_url)
response_code, response_data = update_building(
building_id, line, api_key, base_url
)
if response_code != 200:
print('ERROR', building_id, response_code, response_data)
print("ERROR", building_id, response_code, response_data)
def update_building(building_id, data, api_key, base_url):
"""Save data to a building
"""
"""Save data to a building"""
r = requests.post(
"{}/api/buildings/{}.json".format(base_url, building_id),
params={'api_key': api_key},
params={"api_key": api_key},
json=data,
verify=False
verify=False,
)
print(r)
return r.status_code, r.json()
def find_building(data, base_url):
if 'building_id' in data:
building_id = data['building_id']
if "building_id" in data:
building_id = data["building_id"]
if building_id is not None:
print("match_by_building_id", building_id)
return building_id
if 'toid' in data:
building_id = find_by_reference(base_url, 'toid', data['toid'])
if "toid" in data:
building_id = find_by_reference(base_url, "toid", data["toid"])
if building_id is not None:
print("match_by_toid", data['toid'], building_id)
print("match_by_toid", data["toid"], building_id)
return building_id
if 'uprn' in data:
building_id = find_by_reference(base_url, 'uprn', data['uprn'])
if "uprn" in data:
building_id = find_by_reference(base_url, "uprn", data["uprn"])
if building_id is not None:
print("match_by_uprn", data['uprn'], building_id)
print("match_by_uprn", data["uprn"], building_id)
return building_id
print("no_match", data)
@ -83,32 +84,34 @@ def find_building(data, base_url):
def find_by_reference(base_url, ref_key, ref_id):
"""Find building_id by TOID or UPRN
"""
r = requests.get("{}/api/buildings/reference".format(base_url), params={
'key': ref_key,
'id': ref_id,
"""Find building_id by TOID or UPRN"""
r = requests.get(
"{}/api/buildings/reference".format(base_url),
params={
"key": ref_key,
"id": ref_id,
},
verify=False
verify=False,
)
buildings = r.json()
if buildings and 'error' not in buildings and len(buildings) == 1:
building_id = buildings[0]['building_id']
if buildings and "error" not in buildings and len(buildings) == 1:
building_id = buildings[0]["building_id"]
else:
building_id = None
return building_id
if __name__ == '__main__':
if __name__ == "__main__":
try:
url, api_key, filename = sys.argv[1], sys.argv[2], sys.argv[3]
except IndexError:
print(
"Usage: {} <URL> <api_key> ./path/to/data.csv".format(
os.path.basename(__file__)
))
)
)
exit()
main(url, api_key, filename)

View File

@ -8,7 +8,6 @@ datasets for Camden (age data) and Fitzrovia (number of storeys).
- else locate building by representative point
- update building with data
"""
import json
import os
import sys
from functools import partial
@ -21,18 +20,15 @@ from shapely.ops import transform
osgb_to_ll = partial(
pyproj.transform,
pyproj.Proj(init='epsg:27700'),
pyproj.Proj(init='epsg:4326')
pyproj.transform, pyproj.Proj(init="epsg:27700"), pyproj.Proj(init="epsg:4326")
)
def main(base_url, api_key, process, source_file):
"""Read from file, update buildings
"""
with fiona.open(source_file, 'r') as source:
"""Read from file, update buildings"""
with fiona.open(source_file, "r") as source:
for feature in source:
props = feature['properties']
props = feature["properties"]
if process == "camden":
toid, data = process_camden(props)
@ -42,7 +38,7 @@ def main(base_url, api_key, process, source_file):
if data is None:
continue
building_id = find_building(toid, feature['geometry'], base_url)
building_id = find_building(toid, feature["geometry"], base_url)
if not building_id:
print("no_match", toid, "-")
continue
@ -51,31 +47,22 @@ def main(base_url, api_key, process, source_file):
def process_camden(props):
toid = osgb_toid(props['TOID'])
data = {
'date_year': props['Year_C'],
'date_source_detail': props['Date_sou_1']
}
toid = osgb_toid(props["TOID"])
data = {"date_year": props["Year_C"], "date_source_detail": props["Date_sou_1"]}
return toid, data
def process_fitzrovia(props):
toid = osgb_toid(props['TOID'])
storeys = props['Storeys']
toid = osgb_toid(props["TOID"])
storeys = props["Storeys"]
if storeys is None:
return toid, None
if props['Basement'] == 'Yes':
data = {
'size_storeys_core': int(storeys) - 1,
'size_storeys_basement': 1
}
if props["Basement"] == "Yes":
data = {"size_storeys_core": int(storeys) - 1, "size_storeys_basement": 1}
else:
data = {
'size_storeys_core': int(storeys),
'size_storeys_basement': 0
}
data = {"size_storeys_core": int(storeys), "size_storeys_basement": 0}
return toid, data
@ -86,24 +73,21 @@ def osgb_toid(toid):
def save_data(building_id, data, api_key, base_url):
"""Save data to a building
"""
r = requests.post(
"""Save data to a building"""
requests.post(
"{}/buildings/{}.json?api_key={}".format(base_url, building_id, api_key),
json=data
json=data,
)
def find_building(toid, geom, base_url):
"""Find building_id by TOID or location
"""
r = requests.get(base_url + "/buildings/reference", params={
'key': 'toid',
'id': toid
})
"""Find building_id by TOID or location"""
r = requests.get(
base_url + "/buildings/reference", params={"key": "toid", "id": toid}
)
buildings = r.json()
if buildings and len(buildings) == 1:
bid = buildings[0]['building_id']
bid = buildings[0]["building_id"]
print("match_by_toid", toid, bid)
return bid
@ -114,27 +98,32 @@ def find_building(toid, geom, base_url):
point_osgb = poly.representative_point()
point_ll = transform(osgb_to_ll, point_osgb)
r = requests.get(base_url + "/buildings/locate", params={
'lng': point_ll.x,
'lat': point_ll.y
})
r = requests.get(
base_url + "/buildings/locate", params={"lng": point_ll.x, "lat": point_ll.y}
)
buildings = r.json()
if buildings and len(buildings) == 1:
bid = buildings[0]['building_id']
bid = buildings[0]["building_id"]
print("match_by_location", toid, bid)
return bid
return None
if __name__ == '__main__':
if __name__ == "__main__":
try:
url, api_key, process, filename = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]
url, api_key, process, filename = (
sys.argv[1],
sys.argv[2],
sys.argv[3],
sys.argv[4],
)
except IndexError:
print(
"Usage: {} <URL> <api_key> <camden|fitzrovia> ./path/to/camden.shp".format(
os.path.basename(__file__)
))
)
)
exit()
main(url, api_key, process, filename)

View File

@ -8,7 +8,6 @@ datasets for Camden (age data) and Fitzrovia (number of storeys).
- else locate building by representative point
- update building with data
"""
import json
import os
import sys
from functools import partial
@ -21,18 +20,15 @@ from shapely.ops import transform
osgb_to_ll = partial(
pyproj.transform,
pyproj.Proj(init='epsg:27700'),
pyproj.Proj(init='epsg:4326')
pyproj.transform, pyproj.Proj(init="epsg:27700"), pyproj.Proj(init="epsg:4326")
)
def main(base_url, api_key, process, source_file):
"""Read from file, update buildings
"""
with fiona.open(source_file, 'r') as source:
"""Read from file, update buildings"""
with fiona.open(source_file, "r") as source:
for feature in source:
props = feature['properties']
props = feature["properties"]
if process == "camden":
toid, data = process_camden(props)
@ -42,7 +38,7 @@ def main(base_url, api_key, process, source_file):
if data is None:
continue
building_id = find_building(toid, feature['geometry'], base_url)
building_id = find_building(toid, feature["geometry"], base_url)
if not building_id:
print("no_match", toid, "-")
continue
@ -51,31 +47,22 @@ def main(base_url, api_key, process, source_file):
def process_camden(props):
toid = osgb_toid(props['TOID'])
data = {
'date_year': props['Year_C'],
'date_source_detail': props['Date_sou_1']
}
toid = osgb_toid(props["TOID"])
data = {"date_year": props["Year_C"], "date_source_detail": props["Date_sou_1"]}
return toid, data
def process_fitzrovia(props):
toid = osgb_toid(props['TOID'])
storeys = props['Storeys']
toid = osgb_toid(props["TOID"])
storeys = props["Storeys"]
if storeys is None:
return toid, None
if props['Basement'] == 'Yes':
data = {
'size_storeys_core': int(storeys) - 1,
'size_storeys_basement': 1
}
if props["Basement"] == "Yes":
data = {"size_storeys_core": int(storeys) - 1, "size_storeys_basement": 1}
else:
data = {
'size_storeys_core': int(storeys),
'size_storeys_basement': 0
}
data = {"size_storeys_core": int(storeys), "size_storeys_basement": 0}
return toid, data
@ -86,24 +73,21 @@ def osgb_toid(toid):
def save_data(building_id, data, api_key, base_url):
"""Save data to a building
"""
r = requests.post(
"""Save data to a building"""
requests.post(
"{}/buildings/{}.json?api_key={}".format(base_url, building_id, api_key),
json=data
json=data,
)
def find_building(toid, geom, base_url):
"""Find building_id by TOID or location
"""
r = requests.get(base_url + "/buildings/reference", params={
'key': 'toid',
'id': toid
})
"""Find building_id by TOID or location"""
r = requests.get(
base_url + "/buildings/reference", params={"key": "toid", "id": toid}
)
buildings = r.json()
if buildings and len(buildings) == 1:
bid = buildings[0]['building_id']
bid = buildings[0]["building_id"]
print("match_by_toid", toid, bid)
return bid
@ -114,27 +98,32 @@ def find_building(toid, geom, base_url):
point_osgb = poly.representative_point()
point_ll = transform(osgb_to_ll, point_osgb)
r = requests.get(base_url + "/buildings/locate", params={
'lng': point_ll.x,
'lat': point_ll.y
})
r = requests.get(
base_url + "/buildings/locate", params={"lng": point_ll.x, "lat": point_ll.y}
)
buildings = r.json()
if buildings and len(buildings) == 1:
bid = buildings[0]['building_id']
bid = buildings[0]["building_id"]
print("match_by_location", toid, bid)
return bid
return None
if __name__ == '__main__':
if __name__ == "__main__":
try:
url, api_key, process, filename = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]
url, api_key, process, filename = (
sys.argv[1],
sys.argv[2],
sys.argv[3],
sys.argv[4],
)
except IndexError:
print(
"Usage: {} <URL> <api_key> <camden|fitzrovia> ./path/to/camden.shp".format(
os.path.basename(__file__)
))
)
)
exit()
main(url, api_key, process, filename)

View File

@ -1,9 +1,14 @@
def planning_data_entry_to_address(element):
site_name = element["_source"].get("site_name")
site_number = element["_source"].get("site_number")
street_name = element["_source"].get("street_name") # seems often misused - say "31 COPTHALL ROAD EAST" site_name getting Ickenham street_name
street_name = element["_source"].get("street_name")
# seems often misused - say "31 COPTHALL ROAD EAST" site_name
# getting Ickenham street_name
secondary_street_name = element["_source"].get("secondary_street_name")
return generate_address(site_name, site_number, street_name, secondary_street_name)['result']
return generate_address(site_name, site_number, street_name, secondary_street_name)[
"result"
]
def generate_address(site_name, site_number, street_name, secondary_street_name):
"""
@ -11,13 +16,13 @@ def generate_address(site_name, site_number, street_name, secondary_street_name)
sadly it does not always works well and relies on many heursitics as data quality is limited
"""
if site_name != None:
if site_name is not None:
site_name = site_name.strip()
if site_number != None:
if site_number is not None:
site_number = site_number.strip()
if street_name != None:
if street_name is not None:
street_name = street_name.strip()
if secondary_street_name != None:
if secondary_street_name is not None:
secondary_street_name = secondary_street_name.strip()
if site_name == "":
@ -29,68 +34,80 @@ def generate_address(site_name, site_number, street_name, secondary_street_name)
if secondary_street_name == "":
secondary_street_name = None
data = {
'site_name': site_name,
'site_number': site_number,
'street_name': street_name,
'secondary_street_name': secondary_street_name,
"site_name": site_name,
"site_number": site_number,
"street_name": street_name,
"secondary_street_name": secondary_street_name,
}
if site_name == site_number == street_name == secondary_street_name == None:
return {'result': None, 'data': data}
if site_name == site_number == street_name == secondary_street_name is None:
return {"result": None, "data": data}
if secondary_street_name != None:
if street_name == None:
print('"secondary_street_name != None, street_name == None"')
show_data(site_name, site_number, street_name, secondary_street_name, "???????")
if secondary_street_name is not None:
if street_name is None:
print('"secondary_street_name is not None, street_name is None"')
show_data(
site_name, site_number, street_name, secondary_street_name, "???????"
)
else:
street_name += " - with secondary road name: " + secondary_street_name
if site_number != None and street_name != None:
if site_number is not None and street_name is not None:
address = site_number + " " + street_name
if site_name != None:
print('"site_name != None and site_number != None and street_name != None"')
show_data(site_name, site_number, street_name, secondary_street_name, address)
if site_name is not None:
print(
'"site_name is not None and site_number is not None and street_name is not None"'
)
show_data(
site_name, site_number, street_name, secondary_street_name, address
)
return {'result': address, 'data': data}
return {"result": address, "data": data}
if site_name != None:
if street_name != None:
if site_name is not None:
if street_name is not None:
try:
if site_number == None and int(site_name):
return {'result': site_name + " " + street_name, 'data': data}
if site_number is None and int(site_name):
return {"result": site_name + " " + street_name, "data": data}
except ValueError:
pass
if street_name in site_name:
site_name_without_street_name = site_name.replace(street_name, "").strip()
site_name_without_street_name = site_name.replace(
street_name, ""
).strip()
try:
house_number = int(site_name_without_street_name)
_ = int(site_name_without_street_name)
# so it appears to be case like
# site_name: 5 Warwick Road
# street_name: Warwick Road
# no other info provided
# in such case just returning site_name will work fine...
return {'result': site_name, 'data': data}
return {"result": site_name, "data": data}
except ValueError:
pass
print('"site_name != None and street_name != None"')
show_data(site_name, site_number, street_name, secondary_street_name, site_name)
if site_number != None:
print('"site_name != None and site_number != None"')
show_data(site_name, site_number, street_name, secondary_street_name, site_name)
return {'result': site_name, 'data': data}
print('"site_name is not None and street_name is not None"')
show_data(
site_name, site_number, street_name, secondary_street_name, site_name
)
if site_number is not None:
print('"site_name is not None and site_number is not None"')
show_data(
site_name, site_number, street_name, secondary_street_name, site_name
)
return {"result": site_name, "data": data}
else:
if street_name != None:
if site_number != None:
return {'result': site_number + " " + street_name, 'data': data}
if street_name != None and site_number == None:
print('"street_name != None or site_number == None"')
if street_name is not None:
if site_number is not None:
return {"result": site_number + " " + street_name, "data": data}
if street_name is not None and site_number is None:
print('"street_name is not None or site_number is None"')
show_data(site_name, site_number, street_name, secondary_street_name, None)
return {'result': None, 'data': data}
if street_name == None and site_number != None:
print('"street_name == None or site_number != None"')
return {"result": None, "data": data}
if street_name is None and site_number is not None:
print('"street_name is None or site_number is not None"')
show_data(site_name, site_number, street_name, secondary_street_name, None)
return {'result': None, 'data': data}
return {'result': None, 'data': data}
return {"result": None, "data": data}
return {"result": None, "data": data}
def show_data(site_name, site_number, street_name, secondary_street_name, address):

View File

@ -5,6 +5,7 @@ import requests
import psycopg2
import address_data
def main():
connection = get_connection()
cursor = connection.cursor()
@ -16,10 +17,12 @@ def main():
while True:
data = query(search_after).json()
load_data_into_database(cursor, data)
for entry in data['hits']['hits']:
for entry in data["hits"]["hits"]:
downloaded += 1
last_sort = entry['sort']
print("downloaded", downloaded, "last_sort", last_sort, "previous", search_after)
last_sort = entry["sort"]
print(
"downloaded", downloaded, "last_sort", last_sort, "previous", search_after
)
if search_after == last_sort:
break
search_after = last_sort
@ -31,24 +34,30 @@ def load_data_into_database(cursor, data):
print(json.dumps(data, indent=4))
print("timed_out field missing in provided data")
else:
if data['timed_out']:
if data["timed_out"]:
raise Exception("query getting livestream data has failed")
for entry in data['hits']['hits']:
for entry in data["hits"]["hits"]:
try:
description = None
if entry['_source']['description'] != None:
description = entry['_source']['description'].strip()
application_id = entry['_source']['lpa_app_no']
application_id_with_borough_identifier = entry['_source']['id']
decision_date = parse_date_string_into_date_object(entry['_source']['decision_date'])
last_synced_date = parse_date_string_into_date_object(entry['_source']['last_synced'])
uprn = entry['_source']['uprn']
status_before_aliasing = entry['_source']['status']
if entry["_source"]["description"] is not None:
description = entry["_source"]["description"].strip()
application_id = entry["_source"]["lpa_app_no"]
application_id_with_borough_identifier = entry["_source"]["id"]
decision_date = parse_date_string_into_date_object(
entry["_source"]["decision_date"]
)
last_synced_date = parse_date_string_into_date_object(
entry["_source"]["last_synced"]
)
uprn = entry["_source"]["uprn"]
status_before_aliasing = entry["_source"]["status"]
status_info = process_status(status_before_aliasing, decision_date)
status = status_info["status"]
status_explanation_note = status_info["status_explanation_note"]
planning_url = obtain_entry_link(entry['_source']['url_planning_app'], application_id)
if uprn == None:
planning_url = obtain_entry_link(
entry["_source"]["url_planning_app"], application_id
)
if uprn is None:
continue
try:
uprn = int(uprn)
@ -61,7 +70,9 @@ def load_data_into_database(cursor, data):
"last_synced_date": last_synced_date,
"application_id": application_id,
"application_url": planning_url,
"registered_with_local_authority_date": parse_date_string_into_date_object(entry['_source']['valid_date']),
"registered_with_local_authority_date": parse_date_string_into_date_object(
entry["_source"]["valid_date"]
),
"uprn": uprn,
"status": status,
"status_before_aliasing": status_before_aliasing,
@ -70,13 +81,16 @@ def load_data_into_database(cursor, data):
"data_source_link": "https://www.london.gov.uk/programmes-strategies/planning/digital-planning/planning-london-datahub",
"address": address_data.planning_data_entry_to_address(entry),
}
if entry["address"] != None:
if entry["address"] is not None:
maximum_address_length = 300
if len(entry["address"]) > maximum_address_length:
print("address is too long, shortening", entry["address"])
entry["address"] = entry["address"][0:maximum_address_length]
if date_in_future(entry["registered_with_local_authority_date"]):
print("registered_with_local_authority_date is treated as invalid:", entry["registered_with_local_authority_date"])
print(
"registered_with_local_authority_date is treated as invalid:",
entry["registered_with_local_authority_date"],
)
# Brent-87_0946 has "valid_date": "23/04/9187"
entry["registered_with_local_authority_date"] = None
@ -85,13 +99,17 @@ def load_data_into_database(cursor, data):
entry["decision_date"] = None
if date_in_future(entry["last_synced_date"]):
print("last_synced_date is treated as invalid:", entry["last_synced_date"])
print(
"last_synced_date is treated as invalid:", entry["last_synced_date"]
)
entry["last_synced_date"] = None
if "Hackney" in application_id_with_borough_identifier:
if entry["application_url"] != None:
if entry["application_url"] is not None:
if "https://" not in entry["application_url"]:
entry["application_url"] = "https://developmentandhousing.hackney.gov.uk" + entry["application_url"]
entry[
"application_url"
] = f"https://developmentandhousing.hackney.gov.uk{entry['application_url']}"
insert_entry(cursor, entry)
except TypeError as e:
print()
@ -104,40 +122,40 @@ def load_data_into_database(cursor, data):
def date_in_future(date):
if date == None:
if date is None:
return False
return date > datetime.datetime.now()
def query(search_after):
headers = {
'X-API-AllowRequest': os.environ['PLANNNING_DATA_API_ALLOW_REQUEST_CODE'],
"X-API-AllowRequest": os.environ["PLANNNING_DATA_API_ALLOW_REQUEST_CODE"],
# Already added when you pass json= but not when you pass data=
# 'Content-Type': 'application/json',
}
json_data = {
'size': 10000,
'sort': [
"size": 10000,
"sort": [
{
'last_updated': {
'order': 'desc',
'unmapped_type': 'boolean',
"last_updated": {
"order": "desc",
"unmapped_type": "boolean",
},
},
],
'stored_fields': [
'*',
"stored_fields": [
"*",
],
'_source': {
'excludes': [],
"_source": {
"excludes": [],
},
'query': {
'bool': {
'must': [
"query": {
"bool": {
"must": [
{
'range': {
'valid_date': {
'gte': '01/01/1021',
"range": {
"valid_date": {
"gte": "01/01/1021",
},
},
},
@ -147,18 +165,22 @@ def query(search_after):
}
if search_after != []:
json_data['search_after'] = search_after
json_data["search_after"] = search_after
print(json_data)
return requests.post('https://planningdata.london.gov.uk/api-guest/applications/_search', headers=headers, json=json_data)
return requests.post(
"https://planningdata.london.gov.uk/api-guest/applications/_search",
headers=headers,
json=json_data,
)
def get_connection():
return psycopg2.connect(
host=os.environ['PGHOST'],
dbname=os.environ['PGDATABASE'],
user=os.environ['PGUSER'],
password=os.environ['PGPASSWORD']
host=os.environ["PGHOST"],
dbname=os.environ["PGDATABASE"],
user=os.environ["PGUSER"],
password=os.environ["PGPASSWORD"],
)
@ -170,15 +192,18 @@ def insert_entry(cursor, e):
try:
now = datetime.datetime.now()
application_url = None
if e["application_url"] != None:
if e["application_url"] is not None:
application_url = e["application_url"]
cursor.execute('''INSERT INTO
cursor.execute(
"""INSERT INTO
planning_data (planning_application_id, planning_application_link, description, registered_with_local_authority_date, days_since_registration_cached, decision_date, days_since_decision_date_cached, last_synced_date, status, status_before_aliasing, status_explanation_note, data_source, data_source_link, address, uprn)
VALUES
(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
''', (
""",
(
e["application_id"],
application_url, e["description"],
application_url,
e["description"],
date_object_into_date_string(e["registered_with_local_authority_date"]),
days_since(e["registered_with_local_authority_date"], now),
date_object_into_date_string(e["decision_date"]),
@ -191,7 +216,7 @@ def insert_entry(cursor, e):
e["data_source_link"],
e["address"],
e["uprn"],
)
),
)
except psycopg2.errors.Error as error:
show_dictionary(e)
@ -204,30 +229,32 @@ def show_dictionary(data):
def days_since(date, now):
if(date == None):
if date is None:
return None
return (now - date).days
def date_object_into_date_string(date):
if(date == None):
if date is None:
return None
return datetime.datetime.strftime(date, "%Y-%m-%d")
def parse_date_string_into_date_object(incoming):
if incoming == None:
if incoming is None:
return None
date = None
try:
date = datetime.datetime.strptime(incoming, "%d/%m/%Y") # '21/07/2022'
except ValueError:
date = datetime.datetime.strptime(incoming, "%Y-%m-%dT%H:%M:%S.%fZ") # '2022-08-08T20:07:22.238Z'
date = datetime.datetime.strptime(
incoming, "%Y-%m-%dT%H:%M:%S.%fZ"
) # '2022-08-08T20:07:22.238Z'
return date
def obtain_entry_link(provided_link, application_id):
if provided_link != None:
if provided_link is not None:
if "Ealing" in application_id:
if ";" == provided_link[-1]:
return provided_link[:-1]
@ -237,7 +264,7 @@ def obtain_entry_link(provided_link, application_id):
# Planning application ID: Hackney-2021_2491
# https://developmentandhousing.hackney.gov.uk/planning/index.html?fa=getApplication&reference=2021/2491
ref_for_link = application_id.replace("Hackney-", "").replace("_", "/")
return "https://developmentandhousing.hackney.gov.uk/planning/index.html?fa=getApplication&reference=" + ref_for_link
return f"https://developmentandhousing.hackney.gov.uk/planning/index.html?fa=getApplication&reference={ref_for_link}"
if "Lambeth" in application_id:
# sadly, specific links seems impossible
return "https://planning.lambeth.gov.uk/online-applications/refineSearch.do?action=refine"
@ -282,9 +309,16 @@ def obtain_entry_link(provided_link, application_id):
def process_status(status, decision_date):
status_length_limit = 50 # see migrations/034.planning_livestream_data.up.sql
if status in ["Application Under Consideration", "Application Received"]:
if decision_date == None:
if decision_date is None:
status = "Submitted"
if status in ["Refused", "Refusal", "Refusal (P)", "Application Invalid", "Insufficient Fee", "Dismissed"]:
if status in [
"Refused",
"Refusal",
"Refusal (P)",
"Application Invalid",
"Insufficient Fee",
"Dismissed",
]:
status = "Rejected"
if status == "Appeal Received":
status = "Appeal In Progress"
@ -296,16 +330,39 @@ def process_status(status, decision_date):
status = "Withdrawn"
if len(status) > status_length_limit:
print("Status was too long and was skipped:", status)
return {"status": "Processing failed", "status_explanation_note": "status was unusally long and it was imposible to save it"}
if (status in ["Submitted", "Approved", "Rejected", "Appeal In Progress", "Withdrawn", "Unknown"]):
return {
"status": "Processing failed",
"status_explanation_note": "status was unusally long and it was imposible to save it",
}
if status in [
"Submitted",
"Approved",
"Rejected",
"Appeal In Progress",
"Withdrawn",
"Unknown",
]:
return {"status": status, "status_explanation_note": None}
if status in ["No Objection to Proposal (OBS only)", "Objection Raised to Proposal (OBS only)"]:
return {"status": "Approved", "status_explanation_note": "preapproved application, local authority is unable to reject it"}
if status in [
"No Objection to Proposal (OBS only)",
"Objection Raised to Proposal (OBS only)",
]:
return {
"status": "Approved",
"status_explanation_note": "preapproved application, local authority is unable to reject it",
}
print("Unexpected status " + status)
if status not in ["Not Required", "SECS", "Comment Issued", "ALL DECISIONS ISSUED", "Closed", "Declined to Determine"]:
if status not in [
"Not Required",
"SECS",
"Comment Issued",
"ALL DECISIONS ISSUED",
"Closed",
"Declined to Determine",
]:
print("New unexpected status " + status)
return {"status": status, "status_explanation_note": None}
if __name__ == '__main__':
if __name__ == "__main__":
main()

View File

@ -1,3 +1,3 @@
# Python packages for planning data import
psycopg2==2.8.6
psycopg2-binary==2.9.7
requests==2.31.0

View File

@ -1,7 +1,7 @@
# Python packages for etl
fiona==1.7.13
osmnx==0.13
psycopg2==2.7.5
shapely==1.7
fiona
osmnx==1.6.0
psycopg2-binary==2.9.7
retrying==1.3.3
requests==2.31.0
shapely

View File

@ -4,6 +4,7 @@ COPY (SELECT
ref_osm_id,
revision_id,
location_name,
location_name_link,
location_number,
location_street,
location_line_two,
@ -13,6 +14,7 @@ COPY (SELECT
location_address_links,
location_latitude,
location_longitude,
location_alternative_footprint_links
current_landuse_group,
current_landuse_order,
building_attachment_form,

View File

@ -1,2 +1,2 @@
psycopg2==2.8.3
psycopg2-binary==2.9.7
requests==2.31.0

View File

@ -0,0 +1,34 @@
ALTER TABLE buildings DROP COLUMN IF EXISTS location_name_link;
ALTER TABLE buildings DROP COLUMN IF EXISTS location_alternative_footprint_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS age_historical_raster_map_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS age_historical_vectorised_footprint_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS landowner_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS designers_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS builder_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS developer_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS energy_solar;
ALTER TABLE buildings DROP COLUMN IF EXISTS energy_solar_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS energy_solar_source_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS energy_green_roof;
ALTER TABLE buildings DROP COLUMN IF EXISTS energy_green_roof_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS energy_green_roof_source_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS planning_crowdsourced_site_completion_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS planning_crowdsourced_site_completion_source_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS planning_missing_data;
ALTER TABLE buildings DROP COLUMN IF EXISTS planning_missing_data_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS date_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS date_source_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS planning_heritage_at_risk;
ALTER TABLE buildings DROP COLUMN IF EXISTS planning_world_heritage_site;
ALTER TABLE buildings DROP COLUMN IF EXISTS planning_local_list;
ALTER TABLE buildings DROP COLUMN IF EXISTS planning_in_conservation_area;
ALTER TABLE buildings DROP COLUMN IF EXISTS planning_in_apa;
ALTER TABLE buildings DROP COLUMN IF EXISTS planning_historic_area_assessment;
ALTER TABLE buildings DROP COLUMN IF EXISTS planning_scientific_interest;
ALTER TABLE buildings DROP COLUMN IF EXISTS planning_scientific_interest_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS planning_scientific_interest_source_links;

View File

@ -0,0 +1,34 @@
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS location_name_link text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS location_alternative_footprint_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS age_historical_raster_map_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS age_historical_vectorised_footprint_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS landowner_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS designers_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS builder_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS developer_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS energy_solar boolean;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS energy_solar_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS energy_solar_source_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS energy_green_roof boolean;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS energy_green_roof_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS energy_green_roof_source_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS planning_crowdsourced_site_completion_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS planning_crowdsourced_site_completion_source_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS planning_missing_data boolean;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS planning_missing_data_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS date_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS date_source_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS planning_heritage_at_risk boolean;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS planning_world_heritage_site boolean;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS planning_local_list boolean;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS planning_in_conservation_area boolean;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS planning_in_apa boolean;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS planning_historic_area_assessment boolean;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS planning_scientific_interest boolean;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS planning_scientific_interest_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS planning_scientific_interest_source_links text[];

View File

@ -0,0 +1,14 @@
ALTER TABLE buildings DROP COLUMN IF EXISTS context_front_garden;
ALTER TABLE buildings DROP COLUMN IF EXISTS context_back_garden;
ALTER TABLE buildings DROP COLUMN IF EXISTS context_flats_garden;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS context_front_garden boolean;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS context_back_garden boolean;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS context_flats_garden boolean;
ALTER TABLE buildings DROP COLUMN IF EXISTS planning_crowdsourced_site_completion_status;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS planning_crowdsourced_site_completion_status boolean;
ALTER TABLE buildings DROP COLUMN IF EXISTS planning_crowdsourced_site_completion_year;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS planning_crowdsourced_site_completion_year smallint;

View File

@ -0,0 +1,18 @@
ALTER TABLE buildings DROP COLUMN IF EXISTS typology_classification;
ALTER TABLE buildings DROP COLUMN IF EXISTS typology_classification_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS typology_classification_source_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS typology_style_period;
ALTER TABLE buildings DROP COLUMN IF EXISTS typology_style_period_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS typology_style_period_source_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS typology_dynamic_classification;
ALTER TABLE buildings DROP COLUMN IF EXISTS typology_dynamic_classification_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS typology_dynamic_classification_source_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS typology_original_use;
ALTER TABLE buildings DROP COLUMN IF EXISTS typology_original_use_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS typology_original_use_source_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS building_attachment_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS building_attachment_source_links;

View File

@ -0,0 +1,18 @@
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS typology_classification text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS typology_classification_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS typology_classification_source_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS typology_style_period text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS typology_style_period_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS typology_style_period_source_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS typology_dynamic_classification text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS typology_dynamic_classification_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS typology_dynamic_classification_source_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS typology_original_use text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS typology_original_use_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS typology_original_use_source_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS building_attachment_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS building_attachment_source_links text[];

View File

@ -0,0 +1,38 @@
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_structural_system;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_structural_system_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_structural_system_source_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_foundation;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_foundation_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_foundation_source_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_roof_shape;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_roof_shape_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_roof_shape_source_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_irregularities;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_irregularities_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_irregularities_source_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_roof_covering_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_roof_covering_source_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_decorative_features;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_decorative_feature_materials;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_decorative_feature_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_decorative_feature_source_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_internal_wall;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_internal_wall_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_internal_wall_source_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_external_wall;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_external_wall_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_external_wall_source_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_ground_floor;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_ground_floor_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_ground_floor_source_links;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_core_material_source_type;
ALTER TABLE buildings DROP COLUMN IF EXISTS construction_core_material_source_links;

View File

@ -0,0 +1,38 @@
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_structural_system text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_structural_system_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_structural_system_source_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_foundation text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_foundation_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_foundation_source_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_roof_shape text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_roof_shape_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_roof_shape_source_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_irregularities text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_irregularities_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_irregularities_source_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_roof_covering_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_roof_covering_source_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_decorative_features boolean;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_decorative_feature_materials text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_decorative_feature_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_decorative_feature_source_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_internal_wall text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_internal_wall_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_internal_wall_source_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_external_wall text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_external_wall_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_external_wall_source_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_ground_floor text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_ground_floor_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_ground_floor_source_links text[];
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_core_material_source_type text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS construction_core_material_source_links text[];

View File

@ -0,0 +1,2 @@
ALTER TABLE buildings DROP COLUMN IF EXISTS typology_original_use_order;
ALTER TABLE buildings DROP COLUMN IF NOT EXISTS typology_original_use_verified;

View File

@ -0,0 +1,9 @@
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS typology_original_use_order text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS typology_original_use_verified BOOLEAN NOT NULL DEFAULT FALSE;
UPDATE buildings as b
SET typology_original_use_verified = TRUE
FROM building_verification as v
WHERE b.building_id = v.building_id
AND v.attribute = 'current_landuse_group';