Make Mol the primary operating context
This commit is contained in:
@@ -643,7 +643,7 @@ function App(): JSX.Element {
|
||||
</a>
|
||||
<header className="workbench-topbar">
|
||||
<div className="brand-block">
|
||||
<p className="eyebrow">GeoAI Workbench</p>
|
||||
<p className="eyebrow">GeoAI Workbench · Mol / Kempen</p>
|
||||
<h1>GeoIntel Kempen</h1>
|
||||
</div>
|
||||
<div className="context-bar" aria-label="Active workbench context">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import maplibregl from 'maplibre-gl'
|
||||
import 'maplibre-gl/dist/maplibre-gl.css'
|
||||
import { PRIMARY_FOCUS_CENTER } from '../config/primaryFocus'
|
||||
|
||||
interface GeoMapProps {
|
||||
data: GeoJSON.FeatureCollection | null
|
||||
@@ -162,8 +163,8 @@ function GeoMap({
|
||||
const map = new maplibregl.Map({
|
||||
container: containerRef.current,
|
||||
style: defaultMapStyle(),
|
||||
center: [5.3, 51.3],
|
||||
zoom: 9,
|
||||
center: PRIMARY_FOCUS_CENTER,
|
||||
zoom: 11,
|
||||
attributionControl: false,
|
||||
})
|
||||
map.addControl(new maplibregl.NavigationControl(), 'top-right')
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import type { DatasetCreateResponse, ProjectRead } from '../types'
|
||||
|
||||
export const PRIMARY_FOCUS_LABEL = 'Mol'
|
||||
export const PRIMARY_FOCUS_REGION = 'Mol, Kempen'
|
||||
export const PRIMARY_FOCUS_CENTER: [number, number] = [5.1167, 51.1919]
|
||||
export const PRIMARY_FOCUS_AREA_NAME = 'Mol primary AOI'
|
||||
export const PRIMARY_FOCUS_AREA_GEOJSON =
|
||||
'{"type":"MultiPolygon","coordinates":[[[[5.109476746222376,51.18745107550715],[5.123924622861509,51.18745107550715],[5.123924622861509,51.19634848029239],[5.109476746222376,51.19634848029239],[5.109476746222376,51.18745107550715]]]]}'
|
||||
|
||||
const PRIMARY_FOCUS_TOKEN = /(^|[^a-z0-9])mol([^a-z0-9]|$)/i
|
||||
|
||||
function containsPrimaryFocus(values: Array<string | null | undefined>): boolean {
|
||||
return values.some((value) => Boolean(value && PRIMARY_FOCUS_TOKEN.test(value)))
|
||||
}
|
||||
|
||||
export function isPrimaryFocusProject(project: ProjectRead): boolean {
|
||||
return containsPrimaryFocus([project.name, project.description, project.region])
|
||||
}
|
||||
|
||||
export function isPrimaryFocusProjectData(
|
||||
project: ProjectRead,
|
||||
datasets: DatasetCreateResponse[],
|
||||
): boolean {
|
||||
if (isPrimaryFocusProject(project)) {
|
||||
return true
|
||||
}
|
||||
return datasets.some((dataset) =>
|
||||
containsPrimaryFocus([
|
||||
dataset.name,
|
||||
dataset.original_filename,
|
||||
dataset.stored_filename,
|
||||
dataset.storage_path,
|
||||
dataset.source_name,
|
||||
dataset.reference_layer_name,
|
||||
]),
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,11 @@
|
||||
import { FormEvent, useMemo, useState } from 'react'
|
||||
import {
|
||||
PRIMARY_FOCUS_AREA_GEOJSON,
|
||||
PRIMARY_FOCUS_AREA_NAME,
|
||||
PRIMARY_FOCUS_REGION,
|
||||
isPrimaryFocusProject,
|
||||
isPrimaryFocusProjectData,
|
||||
} from '../config/primaryFocus'
|
||||
import { areasApi } from '../services/api/areas'
|
||||
import { datasetsApi } from '../services/api/datasets'
|
||||
import { projectsApi } from '../services/api/projects'
|
||||
@@ -31,12 +38,11 @@ export function useProjectWorkspace() {
|
||||
const [projectForm, setProjectForm] = useState<ProjectCreate>({
|
||||
name: '',
|
||||
description: '',
|
||||
region: 'Kempen',
|
||||
region: PRIMARY_FOCUS_REGION,
|
||||
})
|
||||
const [areaForm, setAreaForm] = useState({
|
||||
name: 'Demo AOI',
|
||||
geometry:
|
||||
'{"type":"MultiPolygon","coordinates":[[[[4.35,51.28],[4.55,51.28],[4.55,51.46],[4.35,51.46],[4.35,51.28]]]]}',
|
||||
name: PRIMARY_FOCUS_AREA_NAME,
|
||||
geometry: PRIMARY_FOCUS_AREA_GEOJSON,
|
||||
crs: 'EPSG:4326',
|
||||
})
|
||||
|
||||
@@ -60,19 +66,32 @@ export function useProjectWorkspace() {
|
||||
if (selectedProjectId && items.some((project) => project.id === selectedProjectId)) {
|
||||
return selectedProjectId
|
||||
}
|
||||
const primaryProjects = items.filter(isPrimaryFocusProject)
|
||||
const demoProjects = items.filter(isDemoProject)
|
||||
const candidates = [...demoProjects, ...items.filter((project) => !isDemoProject(project))].slice(0, 8)
|
||||
const candidates = Array.from(
|
||||
new Map(
|
||||
[...primaryProjects, ...demoProjects, ...items].map((project) => [project.id, project]),
|
||||
).values(),
|
||||
).slice(0, 12)
|
||||
const inspectedCandidates: Array<{
|
||||
project: ProjectRead
|
||||
data: { areas: AreaRead[]; datasets: DatasetCreateResponse[] }
|
||||
}> = []
|
||||
for (const project of candidates) {
|
||||
try {
|
||||
const data = await fetchProjectData(project.id)
|
||||
if (data.areas.length > 0 && data.datasets.length > 0) {
|
||||
inspectedCandidates.push({ project, data })
|
||||
if (data.datasets.length > 0 && isPrimaryFocusProjectData(project, data.datasets)) {
|
||||
return project.id
|
||||
}
|
||||
} catch {
|
||||
// Project list should still render if a candidate's detail endpoints are temporarily unavailable.
|
||||
}
|
||||
}
|
||||
return demoProjects[0]?.id ?? items[0]?.id ?? null
|
||||
const completeContext = inspectedCandidates.find(
|
||||
({ data }) => data.areas.length > 0 && data.datasets.length > 0,
|
||||
)
|
||||
return completeContext?.project.id ?? primaryProjects[0]?.id ?? demoProjects[0]?.id ?? items[0]?.id ?? null
|
||||
}
|
||||
|
||||
const loadProjects = async (preferredProjectId?: string | null) => {
|
||||
@@ -120,7 +139,7 @@ export function useProjectWorkspace() {
|
||||
const createdProject = await projectsApi.create({
|
||||
name: projectForm.name.trim(),
|
||||
description: projectForm.description?.trim() || undefined,
|
||||
region: projectForm.region?.trim() || 'Kempen',
|
||||
region: projectForm.region?.trim() || PRIMARY_FOCUS_REGION,
|
||||
})
|
||||
setProjectForm((previous) => ({ ...previous, name: '', description: '' }))
|
||||
setSelectedProjectId(createdProject.id)
|
||||
|
||||
Reference in New Issue
Block a user