Complete the V1 analysis handoff
This commit is contained in:
@@ -7,6 +7,21 @@
|
|||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## Sprint 232 V1 user-flow completion (2026-07-17)
|
||||||
|
|
||||||
|
- Completed the primary end-user handoff from map analysis to a usable result,
|
||||||
|
local AI question and downloads without exposing technical project or model
|
||||||
|
setup in the normal path.
|
||||||
|
- Added explicit metric names to the all-theme summary so values such as a
|
||||||
|
station water level are no longer shown without their measured meaning.
|
||||||
|
- Kept vector selections downloadable as GeoJSON and added JSON downloads for
|
||||||
|
governed raster analyses and complete historical comparisons.
|
||||||
|
- Added compact post-analysis actions for the local grounded Ollama assistant
|
||||||
|
and the existing Downloads workspace, preserving the active area context.
|
||||||
|
- Replaced the accumulated TODO lists as the product roadmap with one current
|
||||||
|
V1 completion board; historical sprint checklists remain retained as
|
||||||
|
implementation evidence.
|
||||||
|
|
||||||
## Sprint 231 Governed orthophoto release promotion (2026-07-17)
|
## Sprint 231 Governed orthophoto release promotion (2026-07-17)
|
||||||
|
|
||||||
- Added an operator-only `plan -> stage -> review -> apply` coordinator for one
|
- Added an operator-only `plan -> stage -> review -> apply` coordinator for one
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ def test_map_first_explorer_is_the_default_product_flow() -> None:
|
|||||||
assert "useMapThemeSelectionInsights" in workspace
|
assert "useMapThemeSelectionInsights" in workspace
|
||||||
assert "datasetsApi.selectVectorFeatures" in read("frontend/src/hooks/useMapThemeSelectionInsights.ts")
|
assert "datasetsApi.selectVectorFeatures" in read("frontend/src/hooks/useMapThemeSelectionInsights.ts")
|
||||||
assert "activeSelectionResult" in workspace
|
assert "activeSelectionResult" in workspace
|
||||||
assert "downloadActiveThemeSelection" in workspace
|
assert "downloadActiveThemeResult" in workspace
|
||||||
assert "disabled={!activeSelectionResult}" in workspace
|
assert "disabled={!activeSelectionResult}" in workspace
|
||||||
assert "bboxesEqual(mapSelectionBbox, selectedAreaBbox)" in workspace
|
assert "bboxesEqual(mapSelectionBbox, selectedAreaBbox)" in workspace
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
|
def read(path: str) -> str:
|
||||||
|
return (ROOT / path).read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def test_theme_overview_names_the_metric_instead_of_showing_a_bare_value() -> None:
|
||||||
|
workspace = read("frontend/src/components/map/MapWorkspace.tsx")
|
||||||
|
styles = read("frontend/src/styles/app.css")
|
||||||
|
|
||||||
|
assert 'className="geo-theme-result-value"' in workspace
|
||||||
|
assert "item.result.summary.metric_label" in workspace
|
||||||
|
assert ".geo-theme-result-value" in styles
|
||||||
|
|
||||||
|
|
||||||
|
def test_current_and_historical_results_are_downloadable() -> None:
|
||||||
|
workspace = read("frontend/src/components/map/MapWorkspace.tsx")
|
||||||
|
|
||||||
|
assert "activeTheme.id}-analysis.json" in workspace
|
||||||
|
assert "activeTheme.id}-selection.geojson" in workspace
|
||||||
|
assert "application/geo+json" in workspace
|
||||||
|
assert "downloadTemporalComparison" in workspace
|
||||||
|
assert "Download vergelijking" in workspace
|
||||||
|
assert "Kopieer vergelijking" in workspace
|
||||||
|
|
||||||
|
|
||||||
|
def test_completed_analysis_hands_off_to_ai_and_downloads_responsively() -> None:
|
||||||
|
app = read("frontend/src/App.tsx")
|
||||||
|
workspace = read("frontend/src/components/map/MapWorkspace.tsx")
|
||||||
|
styles = read("frontend/src/styles/app.css")
|
||||||
|
|
||||||
|
assert "onOpenAssistant: () => void" in workspace
|
||||||
|
assert "onOpenExports: () => void" in workspace
|
||||||
|
assert "Stel AI-vraag" in workspace
|
||||||
|
assert "Open downloads" in workspace
|
||||||
|
assert "onOpenAssistant={() => setActiveWorkspace('assistant')}" in app
|
||||||
|
assert "onOpenExports={() => setActiveWorkspace('exports')}" in app
|
||||||
|
assert ".geo-result-next-actions" in styles
|
||||||
|
assert ".geo-results-panel > .geo-result-next-actions" in styles
|
||||||
@@ -9839,3 +9839,41 @@ Next:
|
|||||||
workspace so official/local edition, review identity, Dataset ID and hash
|
workspace so official/local edition, review identity, Dataset ID and hash
|
||||||
integrity can be inspected without shell access. Keep all refresh actions
|
integrity can be inspected without shell access. Keep all refresh actions
|
||||||
operator-only and outside the browser.
|
operator-only and outside the browser.
|
||||||
|
|
||||||
|
## Sprint 232 - V1 user-flow completion (2026-07-17)
|
||||||
|
|
||||||
|
Implemented:
|
||||||
|
- Re-audited the live platform from the end-user entry point instead of
|
||||||
|
continuing operator release work. The normal path is now explicitly Map ->
|
||||||
|
area -> measurements/evolution -> AI question or download.
|
||||||
|
- Added the semantic metric label to every row in the 15-theme result summary.
|
||||||
|
This distinguishes, for example, a Waterinfo station level from mapped
|
||||||
|
surface-water area or watercourse length.
|
||||||
|
- Kept vector output as GeoJSON and added complete JSON downloads for governed
|
||||||
|
raster analyses and historical comparisons. Copy actions now copy the full
|
||||||
|
analysis response rather than an empty raster GeoJSON shell.
|
||||||
|
- Added direct post-analysis handoff buttons to `AI-vragen` and `Downloads`.
|
||||||
|
The selected Area or drawn bbox remains in shared App state.
|
||||||
|
- Added one current V1 completion board to `docs/TODO.md`; legacy checklists
|
||||||
|
remain preserved but no longer define product readiness.
|
||||||
|
|
||||||
|
Validation so far:
|
||||||
|
- Live pre-change acceptance selected the persisted Mol municipality Area and
|
||||||
|
completed all 15 PostGIS-backed themes. Representative results included
|
||||||
|
502.14 ha building footprint, 3,626.56 ha forest/green, 36,783 inhabitants,
|
||||||
|
3,223.5 ha agricultural use and 1,015.51 km roads.
|
||||||
|
- Live historical acceptance compared the official modern forest series from
|
||||||
|
2013 to 2025 over Mol: five observations, 3,723.17 ha to 3,626.56 ha,
|
||||||
|
absolute change -96.6 ha and relative change -2.6%.
|
||||||
|
- Ollama status and installed-model discovery were live. A grounded assistant
|
||||||
|
query returned HTTP 200; a separate `qwen3.5:4b` request completed in 13.01
|
||||||
|
seconds. Model answers remain advisory and source evidence remains primary.
|
||||||
|
- Focused end-user, temporal/Ollama and Sprint 232 tests pass: 38 tests.
|
||||||
|
- Frontend typecheck and production build pass.
|
||||||
|
- Complete readiness passes with 881 backend tests, 110 documented routes,
|
||||||
|
one Alembic head `202607160001`, frontend typecheck and production build.
|
||||||
|
|
||||||
|
Next:
|
||||||
|
- Run the complete release gate, deploy to Tower and repeat the same user flow
|
||||||
|
with visual checks of metric labels, raster/evolution downloads and both
|
||||||
|
post-analysis handoffs.
|
||||||
|
|||||||
@@ -1,5 +1,40 @@
|
|||||||
# GeoIntel TODO
|
# GeoIntel TODO
|
||||||
|
|
||||||
|
## Actuele V1-productstatus
|
||||||
|
|
||||||
|
Dit is het enige actuele afwerkingsbord. De lange sprint- en
|
||||||
|
voorbereidingslijsten verderop blijven bewaard als historisch bewijs, maar zijn
|
||||||
|
geen open productroadmap meer.
|
||||||
|
|
||||||
|
- [x] Open automatisch de volledige Kempen-werkruimte met Mol als snel
|
||||||
|
selecteerbaar werkgebied; een technische project- of regioselectie is niet
|
||||||
|
vereist.
|
||||||
|
- [x] Kies een begrijpbaar datathema, teken een rechthoek of gebruik het
|
||||||
|
volledige werkgebied en analyseer alle 15 beschikbare thema's uit PostGIS.
|
||||||
|
- [x] Toon betekenisvolle eenheden en metrieklabels voor oppervlakte, lengte,
|
||||||
|
inwoners, hoogte, scenario's en stationsmetingen; objectaantallen zijn
|
||||||
|
ondersteunend.
|
||||||
|
- [x] Vergelijk beschikbare historische meetmomenten met een volledige
|
||||||
|
tijdreeks, absolute wijziging, procentuele wijziging en bronbeperking.
|
||||||
|
- [x] Download vectorresultaten als GeoJSON, rasteranalyses als JSON en
|
||||||
|
historische vergelijkingen als JSON; kopieren blijft voor alle drie mogelijk.
|
||||||
|
- [x] Ga vanuit een afgeronde analyse rechtstreeks naar de lokale
|
||||||
|
brongebonden Ollama-assistent of naar Downloads.
|
||||||
|
- [x] Gebruik de operationele lokale YOLO/PyTorch-keten alleen met persisted
|
||||||
|
detecties, GRB-QA en expliciete controlewaarschuwingen.
|
||||||
|
- [x] Draai de volledige applicatie in de beheersbare Unraid-container op poort
|
||||||
|
1202 met PostGIS, backend, frontend, Ollama-koppeling en modelconfiguratie.
|
||||||
|
|
||||||
|
Bewuste, niet-blokkerende grenzen:
|
||||||
|
|
||||||
|
- Watervolume blijft niet beschikbaar zolang geen gekoppelde bathymetrie,
|
||||||
|
bodemhoogte en onzekerheidsmodel bestaan. Dit is geospatiale correctheid,
|
||||||
|
geen onafgewerkte UI.
|
||||||
|
- Gebouwdetectie is operationeel maar blijft een controlekandidaat; verdere
|
||||||
|
training gebeurt pas na nieuwe, onafhankelijke reviewdata.
|
||||||
|
- Een echt SAM/YOLO-seg-model en een trainingsstudio blijven post-V1. De
|
||||||
|
persistente segmentatie- en QA-fundering blijft beschikbaar voor later.
|
||||||
|
|
||||||
## Map-first Mol explorer
|
## Map-first Mol explorer
|
||||||
|
|
||||||
- [x] Make the Mol geographic explorer the default workflow.
|
- [x] Make the Mol geographic explorer the default workflow.
|
||||||
|
|||||||
@@ -71,6 +71,14 @@ but is not required for the primary choose-theme, draw-area, read-result flow.
|
|||||||
|
|
||||||
The primary workflow is deliberately short: choose a municipality or the complete region, choose a data theme, drag a rectangle on the MapLibre map and read the resulting PostGIS evidence. Releasing the drag runs the active theme query and every other available theme query for the same EPSG:4326 bbox. The result panel shows selection area, exact intersection totals, active-theme density, source identity and bounded feature properties. Map rendering remains capped at 1,000 features while `total_feature_count` reports the exact database count.
|
The primary workflow is deliberately short: choose a municipality or the complete region, choose a data theme, drag a rectangle on the MapLibre map and read the resulting PostGIS evidence. Releasing the drag runs the active theme query and every other available theme query for the same EPSG:4326 bbox. The result panel shows selection area, exact intersection totals, active-theme density, source identity and bounded feature properties. Map rendering remains capped at 1,000 features while `total_feature_count` reports the exact database count.
|
||||||
|
|
||||||
|
Every cross-theme result now names the measured quantity next to the value, so
|
||||||
|
a station water level, mapped area and line length cannot appear as an
|
||||||
|
unexplained bare number. Current vector selections download as GeoJSON,
|
||||||
|
current raster analyses download as JSON and historical comparisons download
|
||||||
|
as JSON with their complete timeline and provenance. After a successful
|
||||||
|
analysis, compact next actions carry the same spatial context directly into
|
||||||
|
`AI-vragen` or `Downloads`.
|
||||||
|
|
||||||
For a rectangle in `Laatste toestand`, `Herken gebouwen` runs the complete
|
For a rectangle in `Laatste toestand`, `Herken gebouwen` runs the complete
|
||||||
operational image path without opening the technical AI screen: bounded
|
operational image path without opening the technical AI screen: bounded
|
||||||
official orthophoto acquisition, raster persistence, safe tiling, the active
|
official orthophoto acquisition, raster persistence, safe tiling, the active
|
||||||
|
|||||||
@@ -1079,6 +1079,8 @@ function App(): JSX.Element {
|
|||||||
onRunOrthophotoAnalysis={mapOrthophotoAnalysis.run}
|
onRunOrthophotoAnalysis={mapOrthophotoAnalysis.run}
|
||||||
onSelectOrthophotoProduct={mapOrthophotoAnalysis.setSelectedProductKey}
|
onSelectOrthophotoProduct={mapOrthophotoAnalysis.setSelectedProductKey}
|
||||||
onClearQualityEvidence={clearQualityEvidenceGeoJson}
|
onClearQualityEvidence={clearQualityEvidenceGeoJson}
|
||||||
|
onOpenAssistant={() => setActiveWorkspace('assistant')}
|
||||||
|
onOpenExports={() => setActiveWorkspace('exports')}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
|||||||
@@ -625,8 +625,8 @@ function copyText(text: string): void {
|
|||||||
fallbackCopyText(text)
|
fallbackCopyText(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadJsonFile(filename: string, payload: unknown): void {
|
function downloadJsonFile(filename: string, payload: unknown, contentType = 'application/json'): void {
|
||||||
const blob = new Blob([JSON.stringify(payload, null, 2)], { type: 'application/geo+json' })
|
const blob = new Blob([JSON.stringify(payload, null, 2)], { type: contentType })
|
||||||
const url = URL.createObjectURL(blob)
|
const url = URL.createObjectURL(blob)
|
||||||
const link = document.createElement('a')
|
const link = document.createElement('a')
|
||||||
link.href = url
|
link.href = url
|
||||||
@@ -716,6 +716,8 @@ interface MapWorkspaceProps {
|
|||||||
onRunOrthophotoAnalysis: (bbox: VectorSelectionBBox) => Promise<boolean>
|
onRunOrthophotoAnalysis: (bbox: VectorSelectionBBox) => Promise<boolean>
|
||||||
onSelectOrthophotoProduct: (productKey: string) => void
|
onSelectOrthophotoProduct: (productKey: string) => void
|
||||||
onClearQualityEvidence?: () => void
|
onClearQualityEvidence?: () => void
|
||||||
|
onOpenAssistant: () => void
|
||||||
|
onOpenExports: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MapWorkspace({
|
export function MapWorkspace({
|
||||||
@@ -797,6 +799,8 @@ export function MapWorkspace({
|
|||||||
onRunOrthophotoAnalysis,
|
onRunOrthophotoAnalysis,
|
||||||
onSelectOrthophotoProduct,
|
onSelectOrthophotoProduct,
|
||||||
onClearQualityEvidence,
|
onClearQualityEvidence,
|
||||||
|
onOpenAssistant,
|
||||||
|
onOpenExports,
|
||||||
}: MapWorkspaceProps): JSX.Element {
|
}: MapWorkspaceProps): JSX.Element {
|
||||||
const [advancedMode, setAdvancedMode] = useState(false)
|
const [advancedMode, setAdvancedMode] = useState(false)
|
||||||
const [activeThemeId, setActiveThemeId] = useState<DataThemeId>(() => {
|
const [activeThemeId, setActiveThemeId] = useState<DataThemeId>(() => {
|
||||||
@@ -1135,7 +1139,7 @@ export function MapWorkspace({
|
|||||||
if (!selectedFeatureGeoJson) {
|
if (!selectedFeatureGeoJson) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
downloadJsonFile(selectedFeatureFilename, selectedFeatureGeoJson)
|
downloadJsonFile(selectedFeatureFilename, selectedFeatureGeoJson, 'application/geo+json')
|
||||||
}
|
}
|
||||||
|
|
||||||
const copySelectedMapFeatureProperties = () => {
|
const copySelectedMapFeatureProperties = () => {
|
||||||
@@ -1192,22 +1196,46 @@ export function MapWorkspace({
|
|||||||
if (!mapSelectionResult) {
|
if (!mapSelectionResult) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
downloadJsonFile(DEFAULT_AREA_SELECTION_FILENAME, mapSelectionResult.geojson)
|
downloadJsonFile(DEFAULT_AREA_SELECTION_FILENAME, mapSelectionResult.geojson, 'application/geo+json')
|
||||||
}
|
}
|
||||||
|
|
||||||
const copyAreaSelection = () => {
|
const copyAreaSelection = () => {
|
||||||
copyText(JSON.stringify(mapSelectionResult?.geojson ?? { type: 'FeatureCollection', features: [] }, null, 2))
|
copyText(JSON.stringify(mapSelectionResult?.geojson ?? { type: 'FeatureCollection', features: [] }, null, 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
const downloadActiveThemeSelection = () => {
|
const downloadActiveThemeResult = () => {
|
||||||
if (!activeSelectionResult) {
|
if (!activeSelectionResult) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
downloadJsonFile(`${activeTheme.id}-selection.geojson`, activeSelectionResult.geojson)
|
if (activeThemeDataset?.dataset_type === 'raster') {
|
||||||
|
downloadJsonFile(`${activeTheme.id}-analysis.json`, {
|
||||||
|
project_id: selectedProjectId,
|
||||||
|
area_id: selectedMapArea?.id ?? null,
|
||||||
|
area_name: selectedMapArea?.name ?? null,
|
||||||
|
theme: activeTheme,
|
||||||
|
dataset_id: activeThemeDataset.id,
|
||||||
|
dataset_name: activeThemeDataset.name,
|
||||||
|
source_name: activeThemeDataset.source_name,
|
||||||
|
result: activeSelectionResult,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
downloadJsonFile(`${activeTheme.id}-selection.geojson`, activeSelectionResult.geojson, 'application/geo+json')
|
||||||
}
|
}
|
||||||
|
|
||||||
const copyActiveThemeSelection = () => {
|
const copyActiveThemeResult = () => {
|
||||||
copyText(JSON.stringify(activeSelectionResult?.geojson ?? { type: 'FeatureCollection', features: [] }, null, 2))
|
copyText(JSON.stringify(activeSelectionResult ?? {}, null, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
const downloadTemporalComparison = () => {
|
||||||
|
if (!temporalComparison) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
downloadJsonFile(`${activeTheme.id}-evolution-${temporalComparison.earlier.observed_at.slice(0, 10)}-${temporalComparison.later.observed_at.slice(0, 10)}.json`, temporalComparison)
|
||||||
|
}
|
||||||
|
|
||||||
|
const copyTemporalComparison = () => {
|
||||||
|
copyText(JSON.stringify(temporalComparison ?? {}, null, 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveAreaSelectionExport = () => {
|
const saveAreaSelectionExport = () => {
|
||||||
@@ -1888,7 +1916,10 @@ export function MapWorkspace({
|
|||||||
<strong>{theme.label}</strong>
|
<strong>{theme.label}</strong>
|
||||||
<small>{dataset ? getDatasetSourceDisplayName(dataset) : 'Geen bron gekoppeld'}</small>
|
<small>{dataset ? getDatasetSourceDisplayName(dataset) : 'Geen bron gekoppeld'}</small>
|
||||||
</span>
|
</span>
|
||||||
|
<span className="geo-theme-result-value">
|
||||||
<b>{item ? resultMetricLabel(item.result) : dataset ? 'Niet bevraagd' : 'Bron ontbreekt'}</b>
|
<b>{item ? resultMetricLabel(item.result) : dataset ? 'Niet bevraagd' : 'Bron ontbreekt'}</b>
|
||||||
|
{item?.result.summary ? <small>{item.result.summary.metric_label}</small> : null}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
@@ -1930,8 +1961,28 @@ export function MapWorkspace({
|
|||||||
|
|
||||||
{analysisMode === 'current' ? (
|
{analysisMode === 'current' ? (
|
||||||
<div className="geo-result-actions">
|
<div className="geo-result-actions">
|
||||||
<button className="secondary-action" disabled={!activeSelectionResult || activeThemeDataset?.dataset_type === 'raster'} type="button" onClick={downloadActiveThemeSelection}>Download GeoJSON</button>
|
<button className="secondary-action" disabled={!activeSelectionResult} type="button" onClick={downloadActiveThemeResult}>
|
||||||
<button className="secondary-action" disabled={!activeSelectionResult} type="button" onClick={copyActiveThemeSelection}>Kopieer gegevens</button>
|
{activeThemeDataset?.dataset_type === 'raster' ? 'Download analyse' : 'Download GeoJSON'}
|
||||||
|
</button>
|
||||||
|
<button className="secondary-action" disabled={!activeSelectionResult} type="button" onClick={copyActiveThemeResult}>Kopieer gegevens</button>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{analysisMode === 'evolution' && temporalComparison ? (
|
||||||
|
<div className="geo-result-actions">
|
||||||
|
<button className="secondary-action" type="button" onClick={downloadTemporalComparison}>Download vergelijking</button>
|
||||||
|
<button className="secondary-action" type="button" onClick={copyTemporalComparison}>Kopieer vergelijking</button>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{activeSelectionResult || temporalComparison ? (
|
||||||
|
<div className="geo-result-next-actions" aria-label="Volgende stap">
|
||||||
|
<span>
|
||||||
|
<strong>Analyse klaar</strong>
|
||||||
|
<small>Stel een vraag over dit gebied of open je bewaarde resultaten.</small>
|
||||||
|
</span>
|
||||||
|
<button className="primary-action" type="button" onClick={onOpenAssistant}>Stel AI-vraag</button>
|
||||||
|
<button className="secondary-action" type="button" onClick={onOpenExports}>Open downloads</button>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -6459,6 +6459,17 @@ section {
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.geo-theme-result-value {
|
||||||
|
display: grid;
|
||||||
|
justify-items: end;
|
||||||
|
min-width: 8.5rem;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.geo-theme-result-value small {
|
||||||
|
max-width: 13rem;
|
||||||
|
}
|
||||||
|
|
||||||
.geo-data-notice {
|
.geo-data-notice {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border-left: 3px solid #b17a31;
|
border-left: 3px solid #b17a31;
|
||||||
@@ -6542,6 +6553,27 @@ section {
|
|||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.geo-result-next-actions {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) auto auto;
|
||||||
|
gap: 0.45rem;
|
||||||
|
align-items: center;
|
||||||
|
border-top: 1px solid #dfe7e3;
|
||||||
|
padding-top: 0.65rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.geo-result-next-actions > span {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.12rem;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.geo-result-next-actions small {
|
||||||
|
color: #687570;
|
||||||
|
font-size: 0.66rem;
|
||||||
|
line-height: 1.35;
|
||||||
|
}
|
||||||
|
|
||||||
.geo-explorer-footer {
|
.geo-explorer-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
@@ -6581,7 +6613,8 @@ section {
|
|||||||
.geo-results-panel > .geo-panel-heading,
|
.geo-results-panel > .geo-panel-heading,
|
||||||
.geo-results-panel > .error,
|
.geo-results-panel > .error,
|
||||||
.geo-results-panel > .geo-data-notice,
|
.geo-results-panel > .geo-data-notice,
|
||||||
.geo-results-panel > .geo-result-actions {
|
.geo-results-panel > .geo-result-actions,
|
||||||
|
.geo-results-panel > .geo-result-next-actions {
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6661,7 +6694,8 @@ section {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.geo-map-actions,
|
.geo-map-actions,
|
||||||
.geo-result-actions {
|
.geo-result-actions,
|
||||||
|
.geo-result-next-actions {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user