Polish change detection density
GeoIntel CI / docs-smoke (push) Has been cancelled
GeoIntel CI / contract-smoke (push) Has been cancelled

This commit is contained in:
Codex
2026-06-20 20:37:46 +02:00
parent c941b2619a
commit 335d5d1869
7 changed files with 255 additions and 70 deletions
@@ -37,8 +37,8 @@ export function ChangeDetectionPanel({
onRun,
}: ChangeDetectionPanelProps): JSX.Element {
return (
<section className="panel">
<div className="panel-header">
<section className="panel change-detection-shell">
<div className="panel-header change-detection-heading">
<div>
<p className="eyebrow">Analysis</p>
<h2>Change Detection</h2>
@@ -48,80 +48,99 @@ export function ChangeDetectionPanel({
</button>
</div>
<div className="form-grid">
<label>
Source vector
<select value={sourceDatasetId} onChange={(event) => onSourceDatasetChange(event.target.value)}>
<option value="">Select source</option>
{vectorDatasets.map((dataset) => (
<option key={dataset.id} value={dataset.id}>
{datasetLabel(dataset)}
</option>
))}
</select>
</label>
<label>
Target vector
<select value={targetDatasetId} onChange={(event) => onTargetDatasetChange(event.target.value)}>
<option value="">Select target</option>
{vectorDatasets.map((dataset) => (
<option key={dataset.id} value={dataset.id}>
{datasetLabel(dataset)}
</option>
))}
</select>
</label>
<label>
IoU threshold
<input
max="1"
min="0"
step="0.05"
type="number"
value={iouThreshold}
onChange={(event) => onIouThresholdChange(Number(event.target.value))}
/>
</label>
<label className="checkbox-row">
<input
checked={includeUnchanged}
type="checkbox"
onChange={(event) => onIncludeUnchangedChange(event.target.checked)}
/>
Include unchanged geometry
</label>
<div className="change-detection-input-surface" aria-label="Change detection input controls">
<div className="form-grid">
<label>
Source vector
<select value={sourceDatasetId} onChange={(event) => onSourceDatasetChange(event.target.value)}>
<option value="">Select source</option>
{vectorDatasets.map((dataset) => (
<option key={dataset.id} value={dataset.id}>
{datasetLabel(dataset)}
</option>
))}
</select>
</label>
<label>
Target vector
<select value={targetDatasetId} onChange={(event) => onTargetDatasetChange(event.target.value)}>
<option value="">Select target</option>
{vectorDatasets.map((dataset) => (
<option key={dataset.id} value={dataset.id}>
{datasetLabel(dataset)}
</option>
))}
</select>
</label>
<label>
IoU threshold
<input
max="1"
min="0"
step="0.05"
type="number"
value={iouThreshold}
onChange={(event) => onIouThresholdChange(Number(event.target.value))}
/>
</label>
<label className="checkbox-row">
<input
checked={includeUnchanged}
type="checkbox"
onChange={(event) => onIncludeUnchangedChange(event.target.checked)}
/>
Include unchanged geometry
</label>
</div>
</div>
{error ? <p className="error">{error}</p> : null}
{!error && vectorDatasets.length < 2 ? <p className="muted">Upload at least two vector datasets to compare.</p> : null}
<div className="change-detection-state-stack">
{error ? (
<div className="result-state result-state-error">
<strong>Change detection failed.</strong>
<p>{error}</p>
</div>
) : null}
{!error && vectorDatasets.length < 2 ? (
<div className="result-state result-state-empty">
<strong>Not enough vector datasets</strong>
<p>Upload at least two vector datasets to compare.</p>
</div>
) : null}
</div>
{result ? (
<div className="summary-grid">
<div>
<span className="metric">{result.added_count}</span>
<span>Added</span>
</div>
<div>
<span className="metric">{result.removed_count}</span>
<span>Removed</span>
</div>
<div>
<span className="metric">{result.unchanged_count}</span>
<span>Unchanged</span>
</div>
<div>
<span className="metric">{result.geojson.features.length}</span>
<span>Map features</span>
<div className="change-detection-result-surface" aria-label="Change detection result summary">
<div className="summary-grid">
<div>
<span className="metric">{result.added_count}</span>
<span>Added</span>
</div>
<div>
<span className="metric">{result.removed_count}</span>
<span>Removed</span>
</div>
<div>
<span className="metric">{result.unchanged_count}</span>
<span>Unchanged</span>
</div>
<div>
<span className="metric">{result.geojson.features.length}</span>
<span>Map features</span>
</div>
</div>
</div>
) : null}
{result?.warnings.length ? (
<ul className="compact-list">
{result.warnings.map((warning) => (
<li key={warning}>{warning}</li>
))}
</ul>
<div className="change-detection-warning-surface">
<strong>Warnings</strong>
<ul className="compact-list">
{result.warnings.map((warning) => (
<li key={warning}>{warning}</li>
))}
</ul>
</div>
) : null}
</section>
)
+73 -3
View File
@@ -1465,6 +1465,71 @@ button.entity-card {
margin: 0;
}
.change-detection-shell {
display: grid;
gap: 0.75rem;
}
.change-detection-heading {
margin-bottom: 0;
}
.change-detection-input-surface,
.change-detection-result-surface,
.change-detection-warning-surface {
min-width: 0;
border: 1px solid var(--line);
border-radius: 8px;
padding: 0.72rem;
background: #ffffff;
}
.change-detection-input-surface {
background: linear-gradient(180deg, #ffffff, #f7fbf8);
}
.change-detection-state-stack {
display: grid;
gap: 0.55rem;
}
.change-detection-shell .form-grid {
grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
gap: 0.62rem;
margin: 0;
}
.change-detection-shell .form-grid label {
min-width: 0;
}
.change-detection-shell .form-grid input,
.change-detection-shell .form-grid select {
width: 100%;
min-width: 0;
}
.change-detection-shell .summary-grid {
grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
gap: 0.55rem;
margin: 0;
}
.change-detection-warning-surface {
border-color: rgba(180, 83, 9, 0.24);
background: rgba(180, 83, 9, 0.08);
}
.change-detection-warning-surface strong {
display: block;
color: #92400e;
font-size: 0.88rem;
}
.change-detection-warning-surface .compact-list {
margin-top: 0.45rem;
}
.quality-results-shell .quality-summary-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
@@ -2798,12 +2863,16 @@ button.entity-card {
.quality-summary-surface,
.quality-evidence-surface,
.quality-control-surface,
.quality-history-surface {
.quality-history-surface,
.change-detection-input-surface,
.change-detection-result-surface,
.change-detection-warning-surface {
padding: 0.58rem;
}
.quality-results-shell .quality-summary-grid,
.quality-results-shell .quality-history-controls {
.quality-results-shell .quality-history-controls,
.change-detection-shell .form-grid {
grid-template-columns: repeat(auto-fit, minmax(8.25rem, 1fr));
gap: 0.5rem;
}
@@ -2811,7 +2880,8 @@ button.entity-card {
.quality-results-shell .quality-handoff-grid,
.quality-results-shell .quality-score-row,
.quality-results-shell .quality-metric-grid,
.quality-results-shell .metric-list {
.quality-results-shell .metric-list,
.change-detection-shell .summary-grid {
grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
gap: 0.5rem;
}