Broaden official source portfolio
GeoIntel CI / docs-smoke (push) Canceled after 0s
GeoIntel CI / contract-smoke (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-16 02:04:31 +02:00
parent 8628582caa
commit fdf3881592
10 changed files with 970 additions and 197 deletions
@@ -1,5 +1,12 @@
import type { DatasetCreateResponse } from '../../types'
import { getDatasetSourceDisplayName } from '../../lib/datasetDisplay'
import {
OFFICIAL_SOURCE_PORTFOLIO,
SOURCE_DOMAINS,
operationalSources,
sourcesForDomain,
type SourcePriority,
} from '../../lib/sourcePortfolio'
interface SourceCatalogPanelProps {
datasets: DatasetCreateResponse[]
@@ -18,65 +25,6 @@ const THEME_LABELS: Record<string, string> = {
parcels: 'Percelen',
}
const AVAILABLE_SOURCES = [
{
key: 'historical_orthophoto',
name: 'Historische orthofotos',
owner: 'Digitaal Vlaanderen',
coverage: '1971, 1979-1990, 2000-2025',
value: 'Visuele evolutie via begrensde officiële luchtbeelden',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/orthofotomozaiek-kleinschalig-zomeropnamen',
},
{
key: 'bwk',
name: 'Biologische Waarderingskaart / Natura 2000',
owner: 'INBO',
coverage: 'Toestand 2025',
value: 'Natuurwaarde, biotopen en habitattypen',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/biologische-waarderingskaart-en-natura-2000-habitatkaart-toestand-2025',
},
{
key: 'agriculture',
name: 'Landbouwgebruikspercelen',
owner: 'Agentschap Landbouw en Zeevisserij',
coverage: 'Jaarlijkse bestanden',
value: 'Landbouwoppervlakte, teelten en perceelevolutie',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/open-geodata-landbouwgebruikspercelen',
},
{
key: 'buildings_register',
name: 'Gebouwen- en adressenregister',
owner: 'Digitaal Vlaanderen',
coverage: 'Continu geactualiseerd',
value: 'Gebouwstatus, levensloop en adressen als aanvulling op GRB',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/gebouwen-en-adressenregister',
},
{
key: 'elevation',
name: 'Digitaal Hoogtemodel Vlaanderen II',
owner: 'Digitaal Vlaanderen',
coverage: 'LiDAR-opname 2013-2015, DTM/DSM 1 m en 5 m',
value: 'Hoogte, reliëf en helling; afstroming is afgeleid, geen waterdiepte',
url: 'https://www.vlaanderen.be/digitaal-vlaanderen/onze-diensten-en-platformen/earth-observation-data-science-eodas/het-digitaal-hoogtemodel/digitaal-hoogtemodel-vlaanderen-ii',
},
{
key: 'waterinfo',
name: 'Waterinfo en VMM-metingen',
owner: 'Vlaamse Milieumaatschappij',
coverage: 'Meetpunten en tijdreeksen voor waterstand, debiet en neerslag',
value: 'Hydrologische toestand; geen gebiedsdekkend watervolume zonder bodemprofiel',
url: 'https://waterinfo.vlaanderen.be/',
},
{
key: 'flood_hazard',
name: 'Overstromingsgevaarkaarten waterdiepte',
owner: 'Vlaamse Milieumaatschappij',
coverage: 'Fluviaal/pluviaal, T10/T100/T1000, huidig klimaat en projectie 2050',
value: 'Gemodelleerd overstroomd oppervlak en maximale waterdiepte per vast scenario; geen bathymetrie',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/publieke-inspire-coverage-service-van-ogrk',
},
]
function datasetTheme(dataset: DatasetCreateResponse): string | null {
const configured = String(dataset.source_metadata?.['theme'] ?? dataset.reference_layer_name ?? '').toLowerCase()
if (configured === 'built' || configured === 'building') return 'buildings'
@@ -85,6 +33,12 @@ function datasetTheme(dataset: DatasetCreateResponse): string | null {
return null
}
function priorityLabel(priority: SourcePriority): string {
if (priority === 'next') return 'Eerstvolgend'
if (priority === 'planned') return 'Daarna'
return 'Later'
}
function timelineSummary(
temporalCount: number,
temporalSeriesCount: number,
@@ -132,15 +86,23 @@ export function SourceCatalogPanel({ datasets }: SourceCatalogPanelProps): JSX.E
)[0]
const agricultureYears = agricultureDatasets
.flatMap((dataset) => dataset.observed_at ? [new Date(dataset.observed_at).getUTCFullYear()] : [])
const pendingSources = AVAILABLE_SOURCES.filter((source) => {
if (source.key === 'waterinfo') return waterinfoDatasets.length === 0
if (source.key === 'historical_orthophoto') return historicalOrthophotos.length === 0
const availableSources = operationalSources(ready)
const availableSourceKeys = new Set(availableSources.map((source) => source.key))
const pendingSources = OFFICIAL_SOURCE_PORTFOLIO.filter((source) => {
if (source.key === 'bwk') return bwkDatasets.length === 0
if (source.key === 'agriculture') return agricultureDatasets.length === 0
if (source.key === 'buildings_register') return buildingsRegisterDatasets.length === 0
if (source.key === 'elevation') return dhmvDatasets.length === 0
if (source.key === 'flood_hazard') return floodHazardDatasets.length === 0
return true
return !availableSourceKeys.has(source.key)
})
const domains = SOURCE_DOMAINS.map((domain) => {
const sources = sourcesForDomain(domain.key)
const loaded = sources.filter((source) => availableSourceKeys.has(source.key))
const next = sources.filter((source) => source.priority === 'next' && !availableSourceKeys.has(source.key))
return {
...domain,
sourceCount: sources.length,
loadedCount: loaded.length,
nextCount: next.length,
loadedNames: loaded.map((source) => source.name),
}
})
const themes = Object.keys(THEME_LABELS).map((theme) => {
const matches = ready.filter((dataset) => datasetTheme(dataset) === theme)
@@ -174,33 +136,58 @@ export function SourceCatalogPanel({ datasets }: SourceCatalogPanelProps): JSX.E
<div className="panel-title-row">
<div>
<span className="section-kicker">Broninventaris</span>
<h2>Wat is werkelijk beschikbaar?</h2>
<p className="muted">Ingeladen bronnen staan direct klaar voor de kaart. Andere officiële bronnen worden pas gebruikt na een gecontroleerde import.</p>
<h2>Welke vragen kan GeoIntel beantwoorden?</h2>
<p className="muted">Zes domeinen vormen samen het platform. Alleen werkelijk ingeladen bronnen krijgen de status operationeel; de rest blijft een transparante aansluitplanning.</p>
</div>
<span className="status-badge status-badge-ready">{ready.length} datasets klaar</span>
<span className="status-badge status-badge-ready">{availableSources.length} officiële bronnen operationeel</span>
</div>
<div className="source-catalog-grid">
{themes.map((theme) => (
<article className="source-catalog-card" key={theme.theme}>
<div className="source-domain-grid" aria-label="Platformbrede brondomeinen">
{domains.map((domain) => (
<article className="source-domain-card" key={domain.key}>
<div>
<strong>{theme.label}</strong>
<span>{theme.source ?? 'Nog niet ingeladen'}</span>
<strong>{domain.label}</strong>
<span>{domain.loadedCount} van {domain.sourceCount} bronnen operationeel</span>
</div>
<b>{theme.datasetCount > 0 ? 'Beschikbaar' : 'Ontbreekt'}</b>
<p>{timelineSummary(
theme.temporalCount,
theme.temporalSeriesCount,
theme.otherMethodCount,
theme.firstYear,
theme.lastYear,
)}</p>
<b className={domain.loadedCount > 0 ? 'source-status-operational' : 'source-status-planned'}>
{domain.loadedCount > 0 ? 'Operationeel' : 'Aansluiting nodig'}
</b>
<p>{domain.question}</p>
<small>
{domain.loadedNames.length > 0
? domain.loadedNames.slice(0, 2).join(' · ')
: `${domain.nextCount} geverifieerde bron${domain.nextCount === 1 ? '' : 'nen'} eerstvolgend`}
</small>
</article>
))}
</div>
<details className="source-theme-coverage">
<summary>Dekking per kaartthema en tijdreeks</summary>
<div className="source-catalog-grid">
{themes.map((theme) => (
<article className="source-catalog-card" key={theme.theme}>
<div>
<strong>{theme.label}</strong>
<span>{theme.source ?? 'Nog niet ingeladen'}</span>
</div>
<b>{theme.datasetCount > 0 ? 'Beschikbaar' : 'Ontbreekt'}</b>
<p>{timelineSummary(
theme.temporalCount,
theme.temporalSeriesCount,
theme.otherMethodCount,
theme.firstYear,
theme.lastYear,
)}</p>
</article>
))}
</div>
</details>
{waterinfoDatasets.length > 0 || historicalOrthophotos.length > 0 || bwkDatasets.length > 0 || agricultureDatasets.length > 0 || buildingsRegisterDatasets.length > 0 || dhmvDatasets.length > 0 || floodHazardDatasets.length > 0 ? (
<div className="source-catalog-loaded" aria-label="Aanvullende ingeladen bronnen">
<details className="source-loaded-disclosure">
<summary>Actieve broncollecties en hun beperkingen</summary>
<div className="source-catalog-loaded" aria-label="Aanvullende ingeladen bronnen">
{waterinfoDatasets.length > 0 ? (
<article>
<strong>Waterinfo meetreeksen</strong>
@@ -257,22 +244,39 @@ export function SourceCatalogPanel({ datasets }: SourceCatalogPanelProps): JSX.E
<p>Gemodelleerde maximumdiepte per kansscenario. Geen actuele waterstand, bathymetrie of permanent watervolume.</p>
</article>
) : null}
</div>
</div>
</details>
) : null}
<details className="source-opportunity-list">
<summary>Officiële bronnen die hierna kunnen worden ingeladen</summary>
<div>
{pendingSources.map((source) => (
<article key={source.name}>
<div>
<strong>{source.name}</strong>
<span>{source.owner} · {source.coverage}</span>
</div>
<p>{source.value}</p>
<a href={source.url} target="_blank" rel="noreferrer">Bekijk officiële bron</a>
</article>
))}
<div className="source-opportunity-domains">
{SOURCE_DOMAINS.map((domain) => {
const sources = pendingSources.filter((source) => source.domain === domain.key)
if (sources.length === 0) return null
return (
<section className="source-opportunity-domain" key={domain.key}>
<header>
<strong>{domain.label}</strong>
<span>{sources.length} gecontroleerde kandidaatbron{sources.length === 1 ? '' : 'nen'}</span>
</header>
<div>
{sources.map((source) => (
<article key={source.name}>
<div>
<strong>{source.name}</strong>
<span>{source.owner} · {source.coverage}</span>
</div>
<span className={`source-priority source-priority-${source.priority}`}>{priorityLabel(source.priority)}</span>
<p>{source.value}</p>
<small>Meetbaar als: {source.metricExamples}</small>
<a href={source.url} target="_blank" rel="noreferrer">Bekijk officiële bron</a>
</article>
))}
</div>
</section>
)
})}
</div>
</details>
</section>
+398
View File
@@ -0,0 +1,398 @@
import type { DatasetCreateResponse } from '../types'
export type SourceDomainKey =
| 'space'
| 'nature'
| 'soil'
| 'mobility'
| 'people'
| 'climate'
export type SourcePriority = 'next' | 'planned' | 'later'
export interface SourceDomainDefinition {
key: SourceDomainKey
label: string
question: string
}
export interface OfficialSourceDefinition {
key: string
domain: SourceDomainKey
name: string
owner: string
coverage: string
value: string
metricExamples: string
priority: SourcePriority
url: string
matches: (dataset: DatasetCreateResponse) => boolean
}
const sourceNameIs = (dataset: DatasetCreateResponse, sourceName: string): boolean =>
dataset.source_name === sourceName
const referenceLayerIs = (dataset: DatasetCreateResponse, layerName: string): boolean =>
String(dataset.reference_layer_name ?? dataset.source_metadata?.['theme'] ?? '').toLowerCase() === layerName
export const SOURCE_DOMAINS: SourceDomainDefinition[] = [
{
key: 'space',
label: 'Ruimte en bebouwing',
question: 'Wat staat en gebeurt hier, en hoe verandert het ruimtegebruik?',
},
{
key: 'nature',
label: 'Natuur en landbouw',
question: 'Hoeveel bos, natuurwaarde en landbouwgebruik ligt in de selectie?',
},
{
key: 'soil',
label: 'Bodem en reliëf',
question: 'Welke bodem, hoogte, helling en erosiegevoeligheid komen voor?',
},
{
key: 'mobility',
label: 'Mobiliteit en bereikbaarheid',
question: 'Welke netwerken en knooppunten maken het gebied bereikbaar?',
},
{
key: 'people',
label: 'Bevolking en voorzieningen',
question: 'Hoeveel mensen wonen er en hoe bereikbaar zijn dagelijkse diensten?',
},
{
key: 'climate',
label: 'Klimaat en leefomgeving',
question: 'Welke risicos en omgevingsdruk spelen rond hitte, lucht en water?',
},
]
export const OFFICIAL_SOURCE_PORTFOLIO: OfficialSourceDefinition[] = [
{
key: 'grb_buildings',
domain: 'space',
name: 'GRB-gebouwen',
owner: 'Digitaal Vlaanderen',
coverage: 'Actuele gebouwcontouren',
value: 'Objectniveau voor bebouwing, kaartselectie en AI-validatie.',
metricExamples: 'aantal gebouwen, bebouwde oppervlakte, dichtheid',
priority: 'next',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/grbgis',
matches: (dataset) => sourceNameIs(dataset, 'grb') && referenceLayerIs(dataset, 'buildings'),
},
{
key: 'building_register',
domain: 'space',
name: 'Gebouwen- en Adressenregister',
owner: 'Digitaal Vlaanderen',
coverage: 'Continu geactualiseerd',
value: 'Gebouwstatus en geaggregeerde eenheden als aanvulling op GRB.',
metricExamples: 'gerealiseerde gebouwen, gebouweenheden, statusverdeling',
priority: 'planned',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/gebouwen-en-adressenregister',
matches: (dataset) => sourceNameIs(dataset, 'digitaal_vlaanderen_buildings_addresses_register'),
},
{
key: 'land_use',
domain: 'space',
name: 'Landgebruik Vlaanderen',
owner: 'Departement Omgeving',
coverage: '10 m raster, meerdere officiële toestanden',
value: 'Werkelijk gebruik voor wonen, industrie, landbouw en natuur.',
metricExamples: 'hectare per landgebruiksklasse, aandeel van selectie, evolutie',
priority: 'next',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/landgebruik-vlaanderen-toestand-2022',
matches: (dataset) => sourceNameIs(dataset, 'department_omgeving_land_use') || sourceNameIs(dataset, 'historical_landuse'),
},
{
key: 'orthophoto',
domain: 'space',
name: 'Actuele en historische orthofotos',
owner: 'Digitaal Vlaanderen',
coverage: '1971, 1979-1990 en jaarlijkse reeksen 2000-2025',
value: 'Beeldbewijs voor actuele toestand en visuele evolutie.',
metricExamples: 'beeldjaargang en begrensde AI- of visuele analyse',
priority: 'next',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/orthofotomozaiek-kleinschalig-zomeropnamen',
matches: (dataset) => sourceNameIs(dataset, 'digitaal_vlaanderen_orthophoto'),
},
{
key: 'space_occupation',
domain: 'space',
name: 'Ruimtebeslag Vlaanderen 2025',
owner: 'Departement Omgeving',
coverage: '10 m raster, toestand 2025',
value: 'Gebiedsdruk en ingenomen ruimte naast het fijnere GRB-objectbeeld.',
metricExamples: 'hectare ruimtebeslag, aandeel, vergelijking met open ruimte',
priority: 'next',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/ruimtebeslag-vlaanderen-toestand-2025',
matches: (dataset) => sourceNameIs(dataset, 'department_omgeving_space_occupation'),
},
{
key: 'settlement_typology',
domain: 'space',
name: 'Kernen, linten en verspreide bebouwing',
owner: 'Departement Omgeving',
coverage: 'Toestand 2022',
value: 'Begrijpelijke morfologie voor kern, lint en verspreide bebouwing.',
metricExamples: 'oppervlakte en aandeel per morfologisch type',
priority: 'planned',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/kernen-linten-verspreide-bebouwing-in-vlaanderen-kernen-toestand-2022',
matches: (dataset) => sourceNameIs(dataset, 'department_omgeving_settlement_typology'),
},
{
key: 'business_parks',
domain: 'space',
name: 'Bedrijventerreinen OSLO',
owner: 'VLAIO / Digitaal Vlaanderen',
coverage: 'Productieservice, toestand 2026',
value: 'Economische ruimte, bezetting en bedrijventerreincontext.',
metricExamples: 'hectare bedrijventerrein, bezette/onbezette oppervlakte',
priority: 'planned',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/wfs-bedrijventerreinen',
matches: (dataset) => sourceNameIs(dataset, 'vlaio_business_parks'),
},
{
key: 'bwk',
domain: 'nature',
name: 'BWK / Natura 2000',
owner: 'INBO',
coverage: 'Toestand 2025',
value: 'Biologische waardering, biotopen en habitattypen.',
metricExamples: 'hectare natuurwaarde, habitat en regionaal belangrijk biotoop',
priority: 'next',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/biologische-waarderingskaart-en-natura-2000-habitatkaart-toestand-2025',
matches: (dataset) => sourceNameIs(dataset, 'inbo_bwk_natura2000'),
},
{
key: 'agriculture',
domain: 'nature',
name: 'Landbouwgebruikspercelen',
owner: 'Agentschap Landbouw en Zeevisserij',
coverage: 'Jaarlijkse definitieve bestanden',
value: 'Landbouwoppervlakte en teeltevolutie zonder perceellijnage te verzinnen.',
metricExamples: 'hectare landbouw en hoofdteeltgroep per jaar',
priority: 'next',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/open-geodata-landbouwgebruikspercelen',
matches: (dataset) => sourceNameIs(dataset, 'agentschap_landbouw_zeevisserij_agricultural_parcels'),
},
{
key: 'open_space',
domain: 'nature',
name: 'Open ruimte Vlaanderen',
owner: 'Departement Omgeving',
coverage: '10 m raster, toestand 2022',
value: 'Openruimte-aandeel en versnippering naast ruimtebeslag en landgebruik.',
metricExamples: 'hectare open ruimte, aandeel en fragmentatie',
priority: 'planned',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/open-ruimte-vlaanderen-toestand-2022',
matches: (dataset) => sourceNameIs(dataset, 'department_omgeving_open_space'),
},
{
key: 'dhmv',
domain: 'soil',
name: 'Digitaal Hoogtemodel Vlaanderen II',
owner: 'Digitaal Vlaanderen',
coverage: 'DTM/DSM, opname 2013-2015',
value: 'Hoogte, reliëf en helling als gemeten terreinbasis.',
metricExamples: 'hoogte m TAW, reliëf en helling in graden',
priority: 'next',
url: 'https://www.vlaanderen.be/digitaal-vlaanderen/onze-diensten-en-platformen/earth-observation-data-science-eodas/het-digitaal-hoogtemodel/digitaal-hoogtemodel-vlaanderen-ii',
matches: (dataset) => sourceNameIs(dataset, 'digitaal_vlaanderen_dhmv'),
},
{
key: 'soil_map',
domain: 'soil',
name: 'Digitale bodemkaart',
owner: 'Databank Ondergrond Vlaanderen',
coverage: 'Vlaams Gewest, historische kartering',
value: 'Bodemtype, textuur en drainage voor landbouw en geschiktheid.',
metricExamples: 'hectare per bodemtype, drainage- en textuurverdeling',
priority: 'next',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/digitale-bodemkaart-van-het-vlaams-gewest-bodemtypes',
matches: (dataset) => sourceNameIs(dataset, 'dov_soil_map'),
},
{
key: 'erosion',
domain: 'soil',
name: 'Potentiële bodemerosie per perceel',
owner: 'Departement Omgeving',
coverage: 'Perceelmodel, editie 2023',
value: 'Potentiële erosiedruk gecombineerd met landbouw en reliëf.',
metricExamples: 'hectare per erosieklasse en aandeel risicogebied',
priority: 'planned',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/potentiele-bodemerosiekaart-per-perceel-2023',
matches: (dataset) => sourceNameIs(dataset, 'department_omgeving_erosion'),
},
{
key: 'grb_roads',
domain: 'mobility',
name: 'GRB-wegen en transport',
owner: 'Digitaal Vlaanderen',
coverage: 'Actuele wegcontext',
value: 'Wegennet en transportcontext in de kaartselectie.',
metricExamples: 'kilometer weg, dichtheid en afstand tot netwerk',
priority: 'next',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/grbgis',
matches: (dataset) => sourceNameIs(dataset, 'grb') && referenceLayerIs(dataset, 'roads'),
},
{
key: 'node_value',
domain: 'mobility',
name: 'Knooppuntwaarde per hectare',
owner: 'Departement Omgeving',
coverage: '1 ha raster, toestand 2022',
value: 'Modelmatige bereikbaarheid via collectief vervoer.',
metricExamples: 'gemiddelde score en aandeel per bereikbaarheidsklasse',
priority: 'next',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/knooppuntwaarde-per-ha-toestand-2022',
matches: (dataset) => sourceNameIs(dataset, 'department_omgeving_node_value'),
},
{
key: 'hoppin',
domain: 'mobility',
name: 'Hoppinpunten en mobiliteitsknooppunten',
owner: 'Departement Mobiliteit en Openbare Werken',
coverage: 'Geplande en gerealiseerde punten',
value: 'Multimodale overstappunten en voorzieningen in de buurt.',
metricExamples: 'aantal punten, status en afstand tot selectie',
priority: 'planned',
url: 'https://www.vlaanderen.be/DataCatalogRecord/c262d7d0-d90d-4695-a8c6-6427ef4abb38',
matches: (dataset) => sourceNameIs(dataset, 'mow_hoppin'),
},
{
key: 'cycle_highways',
domain: 'mobility',
name: 'Fietssnelwegen',
owner: 'Vereniging van de Vlaamse Provincies',
coverage: 'Vlaams netwerk, productieservice',
value: 'Gerealiseerde en geplande functionele fietsverbindingen.',
metricExamples: 'kilometer route, realisatiestatus en kwaliteit',
priority: 'planned',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/fietssnelwegen-wfs',
matches: (dataset) => sourceNameIs(dataset, 'vvp_cycle_highways'),
},
{
key: 'statistical_sectors',
domain: 'people',
name: 'Statistische sectoren',
owner: 'Statbel / Digitaal Vlaanderen',
coverage: 'Gebiedsindeling, toestand 2024/2025',
value: 'Betrouwbare ruimtelijke sleutel voor socio-economische indicatoren.',
metricExamples: 'sectorprofielen en gewogen indicatoren per selectie',
priority: 'next',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/statistische-sectoren-van-belgie-toestand-01-01-2024',
matches: (dataset) => sourceNameIs(dataset, 'statbel') && referenceLayerIs(dataset, 'statistical_sectors'),
},
{
key: 'population_density',
domain: 'people',
name: 'Inwonersdichtheid per hectare',
owner: 'Departement Omgeving / Statbel',
coverage: '1 ha raster, toestand 2019',
value: 'Gebiedsdekkende bevolkingsdichtheid zonder adressen te tonen.',
metricExamples: 'geschat aantal inwoners en inwoners per hectare',
priority: 'next',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/inwonersdichtheid-per-ha-vlaanderen-toestand-2019',
matches: (dataset) => sourceNameIs(dataset, 'department_omgeving_population_density'),
},
{
key: 'service_level',
domain: 'people',
name: 'Totaal voorzieningenniveau',
owner: 'Departement Omgeving',
coverage: '1 ha raster, toestand 2022',
value: 'Nabijheid van dagelijkse voorzieningen in één brongetrouwe score.',
metricExamples: 'gemiddelde score en aandeel per voorzieningsklasse',
priority: 'next',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/totaal-voorzieningenniveau-toestand-2022',
matches: (dataset) => sourceNameIs(dataset, 'department_omgeving_service_level'),
},
{
key: 'municipality_indicators',
domain: 'people',
name: 'Gemeente in cijfers',
owner: 'Vlaamse Milieumaatschappij',
coverage: 'Gemeentelijke klimaat- en leefomgevingsindicatoren',
value: 'Contextcijfers voor Mol en vergelijking met andere gemeenten.',
metricExamples: 'hittegolfdagen, temperatuur en luchtkwaliteitsindex',
priority: 'later',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/gemeente-in-cijfers',
matches: (dataset) => sourceNameIs(dataset, 'vmm_municipality_indicators'),
},
{
key: 'flood_hazard',
domain: 'climate',
name: 'VMM-overstromingsgevaar',
owner: 'Vlaamse Milieumaatschappij',
coverage: 'Fluviaal/pluviaal, T10/T100/T1000, huidig en 2050',
value: 'Gemodelleerde lokale maximumdiepte per kansscenario.',
metricExamples: 'hectare positieve diepte, gemiddelde/P90/maximale diepte',
priority: 'next',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/publieke-inspire-coverage-service-van-ogrk',
matches: (dataset) => sourceNameIs(dataset, 'vmm_flood_hazard'),
},
{
key: 'waterinfo',
domain: 'climate',
name: 'Waterinfo meetreeksen',
owner: 'Waterinfo Vlaanderen',
coverage: 'Stationgebonden jaarmetingen',
value: 'Hydrologische waarnemingen als puntreeksen, niet als gebiedsvolume.',
metricExamples: 'waterstand, debiet en neerslag per station en periode',
priority: 'planned',
url: 'https://waterinfo.vlaanderen.be/',
matches: (dataset) => sourceNameIs(dataset, 'waterinfo'),
},
{
key: 'heat_stress',
domain: 'climate',
name: 'Hitte-eilanden in steden',
owner: 'Vlaamse Milieumaatschappij',
coverage: 'Jaarbeelden 2019-2022',
value: 'Ruimtelijke blootstelling aan hittestress voor leefomgevingsanalyse.',
metricExamples: 'hittegolfgraaddagen en aandeel blootgesteld gebied',
priority: 'next',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/hitte-eilanden-in-steden',
matches: (dataset) => sourceNameIs(dataset, 'vmm_heat_stress'),
},
{
key: 'air_quality',
domain: 'climate',
name: 'Luchtkwaliteit',
owner: 'Vlaamse Milieumaatschappij / Departement Omgeving',
coverage: 'Meetreeksen en geselecteerde gebiedskaarten',
value: 'PM2,5 en andere luchtindicatoren met expliciete schaal en jaargang.',
metricExamples: 'concentratie, normoverschrijding en trend per brongebied',
priority: 'planned',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/concentratie-fijn-stof-pm25-in-de-omgevingslucht',
matches: (dataset) => sourceNameIs(dataset, 'vmm_air_quality'),
},
{
key: 'vha',
domain: 'climate',
name: 'Vlaamse Hydrografische Atlas',
owner: 'Vlaamse Milieumaatschappij',
coverage: 'Actuele gecategoriseerde waterlopen',
value: 'Autoritatief waterlopennetwerk voor lengte, categorie en beheerder.',
metricExamples: 'kilometer waterloop per categorie en afstand tot netwerk',
priority: 'later',
url: 'https://www.vlaanderen.be/datavindplaats/catalogus/ogc-api-features-vlaamse-hydrografische-atlas-waterlopen',
matches: (dataset) => sourceNameIs(dataset, 'vmm_vha'),
},
]
export function operationalSources(
datasets: DatasetCreateResponse[],
domain?: SourceDomainKey,
): OfficialSourceDefinition[] {
const ready = datasets.filter((dataset) => dataset.status === 'ready')
return OFFICIAL_SOURCE_PORTFOLIO.filter(
(source) => (!domain || source.domain === domain) && ready.some(source.matches),
)
}
export function sourcesForDomain(domain: SourceDomainKey): OfficialSourceDefinition[] {
return OFFICIAL_SOURCE_PORTFOLIO.filter((source) => source.domain === domain)
}
+156 -5
View File
@@ -6669,13 +6669,91 @@ section {
grid-column: 1 / -1;
}
.source-catalog-grid {
.source-domain-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 0.65rem;
margin-top: 1rem;
}
.source-domain-card {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 0.42rem 0.7rem;
min-width: 0;
border: 1px solid #d9e4df;
border-left: 3px solid #75968a;
border-radius: 6px;
padding: 0.82rem;
background: #fbfcfc;
}
.source-domain-card > div {
display: grid;
min-width: 0;
gap: 0.14rem;
}
.source-domain-card span,
.source-domain-card p,
.source-domain-card small {
margin: 0;
color: #62716c;
font-size: 0.73rem;
line-height: 1.42;
}
.source-domain-card b {
align-self: start;
font-size: 0.68rem;
}
.source-domain-card p,
.source-domain-card small {
grid-column: 1 / -1;
}
.source-domain-card small {
border-top: 1px solid #e6ece9;
padding-top: 0.4rem;
}
.source-status-operational {
color: #286646;
}
.source-status-planned {
color: #8a5a16;
}
.source-theme-coverage,
.source-loaded-disclosure,
.source-catalog-grid {
min-width: 0;
}
.source-theme-coverage,
.source-loaded-disclosure {
margin-top: 0.8rem;
border-top: 1px solid #dfe7e4;
padding-top: 0.7rem;
}
.source-theme-coverage > summary,
.source-loaded-disclosure > summary {
cursor: pointer;
color: #34433e;
font-size: 0.82rem;
font-weight: 750;
}
.source-catalog-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 0.65rem;
margin-top: 0.7rem;
}
.source-catalog-card {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
@@ -6715,7 +6793,7 @@ section {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.6rem;
margin-top: 0.75rem;
margin-top: 0.7rem;
}
.source-catalog-loaded article {
@@ -6747,12 +6825,47 @@ section {
.source-opportunity-list > div {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-template-columns: minmax(0, 1fr);
gap: 0.6rem;
margin-top: 0.7rem;
}
.source-opportunity-domain {
display: grid;
gap: 0.55rem;
border: 0;
border-top: 1px solid #e2e8e6;
border-radius: 0;
padding: 0.7rem 0 0;
background: transparent;
box-shadow: none;
}
.source-opportunity-domain:first-child {
border-top: 0;
padding-top: 0;
}
.source-opportunity-domain > header {
display: flex;
gap: 0.7rem;
align-items: baseline;
justify-content: space-between;
}
.source-opportunity-domain > header span {
color: #66746f;
font-size: 0.7rem;
}
.source-opportunity-domain > div {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.55rem;
}
.source-opportunity-list article {
position: relative;
display: grid;
gap: 0.35rem;
padding: 0.75rem;
@@ -6772,20 +6885,58 @@ section {
font-weight: 700;
}
.source-opportunity-list article > small {
margin: 0;
color: #52635d;
font-size: 0.7rem;
line-height: 1.4;
}
.source-priority {
position: absolute;
top: 0.7rem;
right: 0.7rem;
border-left: 2px solid #718096;
padding-left: 0.38rem;
font-size: 0.65rem !important;
font-weight: 800;
}
.source-opportunity-list article > div {
padding-right: 5.5rem;
}
.source-priority-next {
border-left-color: #287051;
color: #286646 !important;
}
.source-priority-planned {
border-left-color: #a66a18;
color: #8a5a16 !important;
}
@media (max-width: 980px) {
.source-domain-grid,
.source-catalog-grid,
.source-catalog-loaded,
.source-opportunity-list > div {
.source-opportunity-domain > div {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 640px) {
.source-domain-grid,
.source-catalog-grid,
.source-catalog-loaded,
.source-opportunity-list > div {
.source-opportunity-domain > div {
grid-template-columns: 1fr;
}
.source-opportunity-domain > header {
display: grid;
gap: 0.15rem;
}
}
.workspace-grid-assistant {