Add official source edition probes
This commit is contained in:
@@ -1,10 +1,22 @@
|
||||
import type { SourceFreshnessItem, SourceFreshnessReport, SourceFreshnessStatus } from '../../types'
|
||||
import type {
|
||||
SourceCatalogComparisonStatus,
|
||||
SourceCatalogProbeItem,
|
||||
SourceCatalogProbeReport,
|
||||
SourceCatalogProbeStatus,
|
||||
SourceFreshnessItem,
|
||||
SourceFreshnessReport,
|
||||
SourceFreshnessStatus,
|
||||
} from '../../types'
|
||||
|
||||
interface SourceFreshnessPanelProps {
|
||||
report: SourceFreshnessReport | null
|
||||
loading: boolean
|
||||
error: string | null
|
||||
onRefresh: () => void
|
||||
catalogReport: SourceCatalogProbeReport | null
|
||||
catalogLoading: boolean
|
||||
catalogError: string | null
|
||||
onProbeCatalogs: (force: boolean) => void
|
||||
}
|
||||
|
||||
function statusLabel(status: SourceFreshnessStatus): string {
|
||||
@@ -14,6 +26,21 @@ function statusLabel(status: SourceFreshnessStatus): string {
|
||||
return 'lokaal'
|
||||
}
|
||||
|
||||
function catalogStatusLabel(status: SourceCatalogProbeStatus): string {
|
||||
if (status === 'available') return 'bereikbaar'
|
||||
if (status === 'degraded') return 'beperkt'
|
||||
if (status === 'unavailable') return 'niet bereikbaar'
|
||||
return 'uitgeschakeld'
|
||||
}
|
||||
|
||||
function comparisonLabel(status: SourceCatalogComparisonStatus): string {
|
||||
if (status === 'same') return 'zelfde editie'
|
||||
if (status === 'different') return 'verschil controleren'
|
||||
if (status === 'no_local_data') return 'nog niet lokaal ingeladen'
|
||||
if (status === 'not_comparable') return 'andere versienotatie'
|
||||
return 'niet vergelijkbaar'
|
||||
}
|
||||
|
||||
function formatDate(value?: string | null): string {
|
||||
if (!value) return 'geen datum'
|
||||
return new Intl.DateTimeFormat('nl-BE', { dateStyle: 'medium' }).format(new Date(value))
|
||||
@@ -23,6 +50,27 @@ function integrityIssueCount(item: SourceFreshnessItem): number {
|
||||
return Object.values(item.integrity).reduce((total, value) => total + value, 0)
|
||||
}
|
||||
|
||||
function CatalogRow({ item }: { item: SourceCatalogProbeItem }): JSX.Element {
|
||||
return (
|
||||
<div className={`source-catalog-row source-catalog-row-${item.status}`}>
|
||||
<div className="source-freshness-main">
|
||||
<div>
|
||||
<strong>{item.display_name}</strong>
|
||||
<span>{catalogStatusLabel(item.status)} / {comparisonLabel(item.comparison_status)}</span>
|
||||
</div>
|
||||
<span className="source-freshness-status">{item.remote_version ?? 'geen editie'}</span>
|
||||
</div>
|
||||
<p>{item.message}</p>
|
||||
<div className="source-freshness-meta">
|
||||
<span>Lokaal: {item.local_source_version ?? 'niet aanwezig'}</span>
|
||||
<span>Lagen: {item.matched_layers.length}/{item.expected_layers.length} bevestigd</span>
|
||||
{item.remote_modified_at ? <span>Metadata: {formatDate(item.remote_modified_at)}</span> : null}
|
||||
{item.cached ? <span>cache gebruikt</span> : null}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function SourceRow({ item }: { item: SourceFreshnessItem }): JSX.Element {
|
||||
const issueCount = integrityIssueCount(item)
|
||||
return (
|
||||
@@ -30,7 +78,7 @@ function SourceRow({ item }: { item: SourceFreshnessItem }): JSX.Element {
|
||||
<div className="source-freshness-main">
|
||||
<div>
|
||||
<strong>{item.display_name}</strong>
|
||||
<span>{item.dataset_count} datasets · {item.version_count} versies</span>
|
||||
<span>{item.dataset_count} datasets / {item.version_count} versies</span>
|
||||
</div>
|
||||
<span className="source-freshness-status">{statusLabel(item.status)}</span>
|
||||
</div>
|
||||
@@ -45,7 +93,16 @@ function SourceRow({ item }: { item: SourceFreshnessItem }): JSX.Element {
|
||||
)
|
||||
}
|
||||
|
||||
export function SourceFreshnessPanel({ report, loading, error, onRefresh }: SourceFreshnessPanelProps): JSX.Element {
|
||||
export function SourceFreshnessPanel({
|
||||
report,
|
||||
loading,
|
||||
error,
|
||||
onRefresh,
|
||||
catalogReport,
|
||||
catalogLoading,
|
||||
catalogError,
|
||||
onProbeCatalogs,
|
||||
}: SourceFreshnessPanelProps): JSX.Element {
|
||||
const attentionItems = report?.items.filter((item) => item.status === 'due' || item.status === 'review_required') ?? []
|
||||
const summary = report?.summary
|
||||
|
||||
@@ -55,11 +112,21 @@ export function SourceFreshnessPanel({ report, loading, error, onRefresh }: Sour
|
||||
<div>
|
||||
<p className="eyebrow">Bronbeheer</p>
|
||||
<h2>Actualiteit en versiecontrole</h2>
|
||||
<p>Controleert lokale publicaties, versies en bestanden zonder externe bronnen automatisch te wijzigen.</p>
|
||||
<p>Controleert lokale publicaties en kan op aanvraag de officiële GRB- en orthofoto-editie uitlezen.</p>
|
||||
</div>
|
||||
<div className="source-freshness-actions">
|
||||
<button className="secondary-action" type="button" onClick={onRefresh} disabled={loading}>
|
||||
{loading ? 'Controleren...' : 'Lokale status vernieuwen'}
|
||||
</button>
|
||||
<button
|
||||
className="primary-action"
|
||||
type="button"
|
||||
onClick={() => onProbeCatalogs(Boolean(catalogReport))}
|
||||
disabled={catalogLoading}
|
||||
>
|
||||
{catalogLoading ? 'Officiële bronnen lezen...' : catalogReport ? 'Opnieuw bij bron controleren' : 'Officiële edities controleren'}
|
||||
</button>
|
||||
</div>
|
||||
<button className="secondary-action" type="button" onClick={onRefresh} disabled={loading}>
|
||||
{loading ? 'Controleren...' : 'Opnieuw controleren'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{error ? <p className="inline-error">{error}</p> : null}
|
||||
@@ -89,6 +156,31 @@ export function SourceFreshnessPanel({ report, loading, error, onRefresh }: Sour
|
||||
</div>
|
||||
<p className="source-freshness-limitation">{report.limitations.join(' ')}</p>
|
||||
</details>
|
||||
<div className="source-catalog-section" aria-live="polite">
|
||||
<div className="source-catalog-heading">
|
||||
<div>
|
||||
<strong>Officiële catalogusedities</strong>
|
||||
<span>Alleen na jouw expliciete controle; er wordt niets ingeladen of vervangen.</span>
|
||||
</div>
|
||||
{catalogReport ? (
|
||||
<span>{catalogReport.summary.available_count}/{catalogReport.summary.provider_count} bereikbaar</span>
|
||||
) : null}
|
||||
</div>
|
||||
{catalogError ? <p className="inline-error">{catalogError}</p> : null}
|
||||
{!catalogReport && !catalogError ? (
|
||||
<p className="source-catalog-empty">Controleer GRB en orthofoto wanneer je een lokale bronversie met de officiële editie wilt vergelijken.</p>
|
||||
) : null}
|
||||
{catalogReport ? (
|
||||
<>
|
||||
<div className="source-catalog-list">
|
||||
{catalogReport.items.map((item) => <CatalogRow item={item} key={item.source_name} />)}
|
||||
</div>
|
||||
<p className="source-freshness-limitation">
|
||||
Gecontroleerd {formatDate(catalogReport.generated_at)}. Een verschil vraagt menselijke beoordeling en start nooit automatisch een import.
|
||||
</p>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user