Add Belgium and North Sea coverage foundation
This commit is contained in:
@@ -713,3 +713,16 @@ user selects a municipality or draws a bounded rectangle. Forest and
|
||||
agriculture use thematic raster analysis; nature value and soil use the
|
||||
persisted-vector GeoJSON pattern. The browser calls only the GeoIntel API and
|
||||
never contacts WCS, WFS or OGC providers directly.
|
||||
|
||||
## Belgium and Belgian North Sea coverage
|
||||
|
||||
When `Belgium and North Sea Workbench` exists with ready reference data, it is
|
||||
preferred over the legacy Mol/Kempen workspaces at startup. Mol and Kempen
|
||||
remain regression workspaces and can still be selected normally.
|
||||
|
||||
Drawing a rectangle on the Map invokes the GeoIntel coverage resolver after a
|
||||
short debounce. The map displays every intersected land or legal sea zone and
|
||||
the active theme as `Beschikbaar`, `Gedeeltelijk`, `Niet gekoppeld` or `Niet
|
||||
ondersteund`. A coastal or cross-region selection remains visibly split. The
|
||||
browser never calls NGI, SPW, UrbIS, RBINS or MDK directly and never promotes
|
||||
an audited catalog entry to operational data without a matching ready Dataset.
|
||||
|
||||
+21
-5
@@ -19,6 +19,7 @@ import { ProviderPanel } from './components/providers/ProviderPanel'
|
||||
import { SegmentationLab } from './components/segmentation/SegmentationLab'
|
||||
import { useChangeDetectionWorkflow } from './hooks/useChangeDetectionWorkflow'
|
||||
import { useDemoWorkflow } from './hooks/useDemoWorkflow'
|
||||
import { useCoverageResolver } from './hooks/useCoverageResolver'
|
||||
import { useDetectionWorkflow } from './hooks/useDetectionWorkflow'
|
||||
import { useDatasetWorkflow } from './hooks/useDatasetWorkflow'
|
||||
import { useExportWorkflow } from './hooks/useExportWorkflow'
|
||||
@@ -39,6 +40,8 @@ import { getDatasetDisplayName } from './lib/datasetDisplay'
|
||||
import {
|
||||
FLANDERS_WORKSPACE_LABEL,
|
||||
FLANDERS_WORKSPACE_PROJECT_NAME,
|
||||
NATIONAL_WORKSPACE_LABEL,
|
||||
NATIONAL_WORKSPACE_PROJECT_NAME,
|
||||
REGIONAL_WORKSPACE_LABEL,
|
||||
REGIONAL_WORKSPACE_PROJECT_NAME,
|
||||
} from './config/primaryFocus'
|
||||
@@ -475,6 +478,14 @@ function App(): JSX.Element {
|
||||
selectedDataset,
|
||||
isVectorDatasetType,
|
||||
})
|
||||
const {
|
||||
coverage: mapCoverage,
|
||||
loadingCoverage: mapCoverageLoading,
|
||||
coverageError: mapCoverageError,
|
||||
} = useCoverageResolver({
|
||||
projectId: selectedProjectId,
|
||||
bbox: mapSelectionBbox,
|
||||
})
|
||||
const {
|
||||
selectionDatasetSaving,
|
||||
selectionDatasetError,
|
||||
@@ -668,11 +679,13 @@ function App(): JSX.Element {
|
||||
|| Boolean(changeDetectionResult)
|
||||
|| detectionItems.length > 0
|
||||
|| segmentationItems.length > 0
|
||||
const projectContextLabel = selectedProject?.name === REGIONAL_WORKSPACE_PROJECT_NAME
|
||||
? REGIONAL_WORKSPACE_LABEL
|
||||
: selectedProject?.name === FLANDERS_WORKSPACE_PROJECT_NAME
|
||||
? FLANDERS_WORKSPACE_LABEL
|
||||
: selectedProject?.name ?? 'Geen werkruimte'
|
||||
const projectContextLabel = selectedProject?.name === NATIONAL_WORKSPACE_PROJECT_NAME
|
||||
? NATIONAL_WORKSPACE_LABEL
|
||||
: selectedProject?.name === REGIONAL_WORKSPACE_PROJECT_NAME
|
||||
? REGIONAL_WORKSPACE_LABEL
|
||||
: selectedProject?.name === FLANDERS_WORKSPACE_PROJECT_NAME
|
||||
? FLANDERS_WORKSPACE_LABEL
|
||||
: selectedProject?.name ?? 'Geen werkruimte'
|
||||
const areaContextLabel = selectedArea?.name ?? (areas.length > 0 ? 'Kies een gebied' : 'Geen gebied')
|
||||
const bathymetryContextActive = Boolean(
|
||||
activeWorkspace === 'map'
|
||||
@@ -927,6 +940,9 @@ function App(): JSX.Element {
|
||||
mapSelectionResult={mapSelectionResult}
|
||||
mapSelectionLoading={mapSelectionLoading}
|
||||
mapSelectionError={mapSelectionError}
|
||||
coverage={mapCoverage}
|
||||
coverageLoading={mapCoverageLoading}
|
||||
coverageError={mapCoverageError}
|
||||
selectionExporting={selectionExporting}
|
||||
selectionExportError={selectionExportError}
|
||||
latestSelectionExportPath={latestSelectionExport?.path ?? null}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import GeoMap from '../GeoMap'
|
||||
import type { AreaRead, DatasetCreateResponse, DetectionQaResult, MapResultExportRequest, MapViewportState, OrthophotoAcquisitionResult, OrthophotoProductRead, ProjectRead, QaComparisonResult, VectorSelectionBBox, VectorSelectionMetric, VectorSelectionResponse } from '../../types'
|
||||
import type { AreaRead, CoverageResolveResponse, CoverageStatus, DatasetCreateResponse, DetectionQaResult, MapResultExportRequest, MapViewportState, OrthophotoAcquisitionResult, OrthophotoProductRead, ProjectRead, QaComparisonResult, VectorSelectionBBox, VectorSelectionMetric, VectorSelectionResponse } from '../../types'
|
||||
import { useMapThemeSelectionInsights, type MapThemeAcquisition, type MapThemeQuery } from '../../hooks/useMapThemeSelectionInsights'
|
||||
import { useOfficialMapProducts } from '../../hooks/useOfficialMapProducts'
|
||||
import { useTemporalComparison } from '../../hooks/useTemporalComparison'
|
||||
@@ -176,6 +176,49 @@ const DATA_THEMES: DataTheme[] = [
|
||||
},
|
||||
]
|
||||
|
||||
const COVERAGE_THEME_BY_MAP_THEME: Record<DataThemeId, string> = {
|
||||
buildings: 'buildings',
|
||||
space_occupation: 'land_cover_use',
|
||||
open_space: 'land_cover_use',
|
||||
population: 'population',
|
||||
forest: 'land_cover_use',
|
||||
nature_value: 'nature',
|
||||
agriculture: 'land_cover_use',
|
||||
soil: 'soil',
|
||||
water: 'surface_water',
|
||||
bathymetry: 'bathymetry',
|
||||
flood_hazard: 'flood_climate',
|
||||
elevation: 'elevation',
|
||||
accessibility: 'roads',
|
||||
services: 'population',
|
||||
roads: 'roads',
|
||||
parcels: 'parcels',
|
||||
}
|
||||
|
||||
function coverageStatusLabel(status: CoverageStatus): string {
|
||||
const labels: Record<CoverageStatus, string> = {
|
||||
operational: 'Beschikbaar',
|
||||
partial: 'Gedeeltelijk',
|
||||
not_configured: 'Niet gekoppeld',
|
||||
unsupported: 'Niet ondersteund',
|
||||
}
|
||||
return labels[status]
|
||||
}
|
||||
|
||||
function coverageZoneLabel(zone: string): string {
|
||||
const labels: Record<string, string> = {
|
||||
belgium: 'Belgie',
|
||||
flanders: 'Vlaanderen',
|
||||
wallonia: 'Wallonie',
|
||||
brussels: 'Brussel',
|
||||
belgian_north_sea: 'Belgische Noordzee',
|
||||
territorial_sea: 'Territoriale zee',
|
||||
exclusive_economic_zone: 'EEZ',
|
||||
continental_shelf: 'Continentaal plat',
|
||||
}
|
||||
return labels[zone] ?? zone
|
||||
}
|
||||
|
||||
const DATA_THEME_MAP_STYLES: Record<DataThemeId, { fill: string; line: string }> = {
|
||||
buildings: { fill: '#d45f3d', line: '#9f3e24' },
|
||||
space_occupation: { fill: '#be3e33', line: '#8f2c24' },
|
||||
@@ -516,6 +559,9 @@ interface MapWorkspaceProps {
|
||||
mapSelectionResult: VectorSelectionResponse | null
|
||||
mapSelectionLoading: boolean
|
||||
mapSelectionError: string | null
|
||||
coverage: CoverageResolveResponse | null
|
||||
coverageLoading: boolean
|
||||
coverageError: string | null
|
||||
selectionExporting: boolean
|
||||
selectionExportError: string | null
|
||||
latestSelectionExportPath: string | null
|
||||
@@ -602,6 +648,9 @@ export function MapWorkspace({
|
||||
mapSelectionResult,
|
||||
mapSelectionLoading,
|
||||
mapSelectionError,
|
||||
coverage,
|
||||
coverageLoading,
|
||||
coverageError,
|
||||
selectionExporting,
|
||||
selectionExportError,
|
||||
latestSelectionExportPath,
|
||||
@@ -819,6 +868,15 @@ export function MapWorkspace({
|
||||
[availableMapDatasets, regionalScopeSelected, selectedMapAreaId, themeDatasetMap],
|
||||
)
|
||||
const activeTheme = DATA_THEMES.find((theme) => theme.id === activeThemeId) ?? DATA_THEMES[0]
|
||||
const activeCoverageTheme = COVERAGE_THEME_BY_MAP_THEME[activeTheme.id]
|
||||
const activeCoverageItems = coverage?.items.filter((item) => item.theme === activeCoverageTheme) ?? []
|
||||
const coverageCounts = useMemo(
|
||||
() => coverage?.items.reduce<Record<CoverageStatus, number>>(
|
||||
(counts, item) => ({ ...counts, [item.status]: counts[item.status] + 1 }),
|
||||
{ operational: 0, partial: 0, not_configured: 0, unsupported: 0 },
|
||||
) ?? { operational: 0, partial: 0, not_configured: 0, unsupported: 0 },
|
||||
[coverage],
|
||||
)
|
||||
const onDemandProductMap = useMemo(
|
||||
() => {
|
||||
const result = new Map<DataThemeId, OnDemandMapProduct>()
|
||||
@@ -2527,6 +2585,50 @@ export function MapWorkspace({
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{mapSelectionBbox ? (
|
||||
<section className="coverage-resolution-surface" aria-label="Datadekking van de kaartselectie">
|
||||
<div className="panel-title-row">
|
||||
<div>
|
||||
<p className="eyebrow">Dekking van deze selectie</p>
|
||||
<h3>{activeTheme.label}</h3>
|
||||
</div>
|
||||
{coverageLoading ? <span className="count-pill">controleren</span> : null}
|
||||
</div>
|
||||
{coverageError ? <p className="error">{coverageError}</p> : null}
|
||||
{coverage ? (
|
||||
<>
|
||||
<div className="coverage-zone-row">
|
||||
{coverage.intersected_zones.map((zone) => (
|
||||
<span key={zone}>{coverageZoneLabel(zone)}</span>
|
||||
))}
|
||||
{coverage.outside_supported_scope ? <span className="coverage-zone-warning">deels buiten scope</span> : null}
|
||||
</div>
|
||||
<div className="coverage-active-theme-grid">
|
||||
{activeCoverageItems.map((item) => (
|
||||
<div className={`coverage-status-item coverage-status-${item.status}`} key={`${item.zone}:${item.theme}`}>
|
||||
<span>{coverageZoneLabel(item.zone)}</span>
|
||||
<strong>{coverageStatusLabel(item.status)}</strong>
|
||||
<small>{item.source_names.join(', ') || 'Geen broncontract'}</small>
|
||||
</div>
|
||||
))}
|
||||
{activeCoverageItems.length === 0 ? (
|
||||
<p className="muted">Deze selectie raakt geen bewaarde Belgische land- of zeezone.</p>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="coverage-summary-row" aria-label="Samenvatting van alle themas">
|
||||
<span>{coverageCounts.operational} beschikbaar</span>
|
||||
<span>{coverageCounts.partial} gedeeltelijk</span>
|
||||
<span>{coverageCounts.not_configured} niet gekoppeld</span>
|
||||
<span>{coverageCounts.unsupported} niet ondersteund</span>
|
||||
</div>
|
||||
{coverage.warnings.map((warning) => <p className="muted" key={warning}>{warning}</p>)}
|
||||
</>
|
||||
) : !coverageLoading && !coverageError ? (
|
||||
<p className="muted">De dekkingsmatrix wordt bepaald zodra de selectie volledig is.</p>
|
||||
) : null}
|
||||
</section>
|
||||
) : null}
|
||||
|
||||
<div className="map-inspection-surface">
|
||||
<div className="gis-test-run-surface" aria-label="Operationele GIS-controle">
|
||||
<div className="panel-title-row">
|
||||
|
||||
@@ -2,6 +2,8 @@ import type { DatasetCreateResponse, ProjectRead } from '../types'
|
||||
|
||||
export const PRIMARY_FOCUS_LABEL = 'Mol'
|
||||
export const PRIMARY_FOCUS_REGION = 'Mol, Kempen'
|
||||
export const NATIONAL_WORKSPACE_PROJECT_NAME = 'Belgium and North Sea Workbench'
|
||||
export const NATIONAL_WORKSPACE_LABEL = 'Belgie en Belgische Noordzee'
|
||||
export const REGIONAL_WORKSPACE_PROJECT_NAME = 'Kempen Regional Workbench'
|
||||
export const REGIONAL_WORKSPACE_LABEL = 'Kempen (28 gemeenten)'
|
||||
export const FLANDERS_WORKSPACE_PROJECT_NAME = 'Flanders Regional Workbench'
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { externalApi } from '../services/api'
|
||||
import type { CoverageResolveResponse, VectorSelectionBBox } from '../types'
|
||||
|
||||
interface CoverageResolverOptions {
|
||||
projectId: string | null
|
||||
bbox: VectorSelectionBBox | null
|
||||
}
|
||||
|
||||
export function useCoverageResolver({ projectId, bbox }: CoverageResolverOptions) {
|
||||
const [coverage, setCoverage] = useState<CoverageResolveResponse | null>(null)
|
||||
const [loadingCoverage, setLoadingCoverage] = useState(false)
|
||||
const [coverageError, setCoverageError] = useState<string | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (!projectId || !bbox) {
|
||||
setCoverage(null)
|
||||
setCoverageError(null)
|
||||
setLoadingCoverage(false)
|
||||
return
|
||||
}
|
||||
let cancelled = false
|
||||
const timer = window.setTimeout(() => {
|
||||
setLoadingCoverage(true)
|
||||
setCoverageError(null)
|
||||
externalApi.resolveCoverage({
|
||||
projectId,
|
||||
bbox: {
|
||||
minx: bbox.min_x,
|
||||
miny: bbox.min_y,
|
||||
maxx: bbox.max_x,
|
||||
maxy: bbox.max_y,
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
if (!cancelled) {
|
||||
setCoverage(result)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
if (!cancelled) {
|
||||
setCoverage(null)
|
||||
setCoverageError(error instanceof Error ? error.message : 'Dekking kon niet worden bepaald')
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
if (!cancelled) {
|
||||
setLoadingCoverage(false)
|
||||
}
|
||||
})
|
||||
}, 250)
|
||||
return () => {
|
||||
cancelled = true
|
||||
window.clearTimeout(timer)
|
||||
}
|
||||
}, [projectId, bbox?.min_x, bbox?.min_y, bbox?.max_x, bbox?.max_y])
|
||||
|
||||
return {
|
||||
coverage,
|
||||
loadingCoverage,
|
||||
coverageError,
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
PRIMARY_FOCUS_AREA_GEOJSON,
|
||||
PRIMARY_FOCUS_AREA_NAME,
|
||||
PRIMARY_FOCUS_REGION,
|
||||
NATIONAL_WORKSPACE_PROJECT_NAME,
|
||||
REGIONAL_WORKSPACE_PROJECT_NAME,
|
||||
isPrimaryFocusMunicipalityBoundaryDataset,
|
||||
isPrimaryFocusMunicipalityProject,
|
||||
@@ -81,6 +82,17 @@ export function useProjectWorkspace() {
|
||||
if (selectedProjectId && items.some((project) => project.id === selectedProjectId)) {
|
||||
return selectedProjectId
|
||||
}
|
||||
const nationalProject = items.find((project) => project.name === NATIONAL_WORKSPACE_PROJECT_NAME)
|
||||
if (nationalProject) {
|
||||
try {
|
||||
const data = await fetchProjectData(nationalProject.id)
|
||||
if (data.areas.length > 0 && data.datasets.some((dataset) => dataset.status === 'ready')) {
|
||||
return nationalProject.id
|
||||
}
|
||||
} catch {
|
||||
// Continue with regional and municipality fallbacks while national data is unavailable.
|
||||
}
|
||||
}
|
||||
const regionalProject = items.find((project) => project.name === REGIONAL_WORKSPACE_PROJECT_NAME)
|
||||
if (regionalProject) {
|
||||
try {
|
||||
@@ -145,13 +157,15 @@ export function useProjectWorkspace() {
|
||||
setLoadingProjects(true)
|
||||
setErrorMessage(null)
|
||||
try {
|
||||
const [response, canonicalResponse] = await Promise.all([
|
||||
const [response, nationalResponse, canonicalResponse] = await Promise.all([
|
||||
projectsApi.list(),
|
||||
projectsApi.list({ name: NATIONAL_WORKSPACE_PROJECT_NAME, limit: 1 }),
|
||||
projectsApi.list({ name: REGIONAL_WORKSPACE_PROJECT_NAME, limit: 1 }),
|
||||
])
|
||||
const regionalItems = [...canonicalResponse.items, ...response.items]
|
||||
const items = Array.from(
|
||||
new Map(
|
||||
[...canonicalResponse.items, ...response.items].map((project) => [project.id, project]),
|
||||
[...nationalResponse.items, ...regionalItems].map((project) => [project.id, project]),
|
||||
).values(),
|
||||
)
|
||||
setProjects(items)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { apiGet, apiPost } from './client'
|
||||
import type {
|
||||
CoverageCatalogResponse,
|
||||
CoverageResolveResponse,
|
||||
ProviderCapability,
|
||||
ProviderCapabilitiesResponse,
|
||||
ProviderImportResponse,
|
||||
@@ -13,6 +15,18 @@ const normalize = (layers: string[] = []) => layers.filter((value) => value.trim
|
||||
export const externalApi = {
|
||||
listSystemCapabilities: (): Promise<SystemCapabilitiesResponse> =>
|
||||
apiGet<SystemCapabilitiesResponse>('/api/v1/system/capabilities'),
|
||||
getCoverageCatalog: (): Promise<CoverageCatalogResponse> =>
|
||||
apiGet<CoverageCatalogResponse>('/api/v1/external/coverage/catalog'),
|
||||
resolveCoverage: (payload: {
|
||||
projectId: string
|
||||
bbox: { minx: number; miny: number; maxx: number; maxy: number }
|
||||
themes?: string[]
|
||||
}): Promise<CoverageResolveResponse> =>
|
||||
apiPost<CoverageResolveResponse>('/api/v1/external/coverage/resolve', {
|
||||
project_id: payload.projectId,
|
||||
bbox: payload.bbox,
|
||||
themes: payload.themes ?? [],
|
||||
}),
|
||||
listProviders: (): Promise<ProviderCapabilitiesResponse> =>
|
||||
apiGet<ProviderCapabilitiesResponse>('/api/v1/external/providers'),
|
||||
listProviderCapabilities: (): Promise<ProviderCapabilitiesResponse> =>
|
||||
|
||||
@@ -7347,3 +7347,67 @@ section {
|
||||
.workspace-persistent-map[hidden] {
|
||||
display: none;
|
||||
}
|
||||
.coverage-resolution-surface {
|
||||
padding: 18px 20px;
|
||||
border-block: 1px solid var(--line);
|
||||
background: color-mix(in srgb, var(--surface-raised) 94%, var(--accent-soft));
|
||||
}
|
||||
|
||||
.coverage-zone-row,
|
||||
.coverage-summary-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.coverage-zone-row span,
|
||||
.coverage-summary-row span {
|
||||
padding: 4px 8px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 4px;
|
||||
background: var(--surface-raised);
|
||||
color: var(--muted);
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.coverage-zone-row .coverage-zone-warning {
|
||||
border-color: var(--warning);
|
||||
color: var(--warning);
|
||||
}
|
||||
|
||||
.coverage-active-theme-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
|
||||
gap: 8px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.coverage-status-item {
|
||||
display: grid;
|
||||
gap: 3px;
|
||||
min-height: 76px;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--line);
|
||||
border-left: 3px solid var(--muted);
|
||||
border-radius: 6px;
|
||||
background: var(--surface-raised);
|
||||
}
|
||||
|
||||
.coverage-status-item span,
|
||||
.coverage-status-item small {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.coverage-status-operational {
|
||||
border-left-color: var(--accent);
|
||||
}
|
||||
|
||||
.coverage-status-partial {
|
||||
border-left-color: var(--warning);
|
||||
}
|
||||
|
||||
.coverage-status-not_configured,
|
||||
.coverage-status-unsupported {
|
||||
border-left-color: var(--muted);
|
||||
}
|
||||
|
||||
@@ -957,6 +957,57 @@ export interface ProviderCapability {
|
||||
not_configured_reason: string | null
|
||||
}
|
||||
|
||||
export type CoverageStatus = 'operational' | 'partial' | 'not_configured' | 'unsupported'
|
||||
|
||||
export interface CoverageBBox {
|
||||
minx: number
|
||||
miny: number
|
||||
maxx: number
|
||||
maxy: number
|
||||
}
|
||||
|
||||
export interface CoverageSourceContract {
|
||||
source_name: string
|
||||
display_name: string
|
||||
authority_level: 'authoritative' | 'official_context' | 'contextual'
|
||||
coverage_zones: string[]
|
||||
themes: string[]
|
||||
native_layers: string[]
|
||||
supported_geometry_types: string[]
|
||||
acquisition_mode: 'operator_archive' | 'operator_wfs' | 'bounded_api' | 'bounded_raster' | 'catalog_only'
|
||||
integration_status: CoverageStatus
|
||||
source_url: string
|
||||
attribution: string
|
||||
license_note: string
|
||||
limitation_message: string
|
||||
}
|
||||
|
||||
export interface CoverageCatalogResponse {
|
||||
themes: string[]
|
||||
zones: string[]
|
||||
statuses: CoverageStatus[]
|
||||
sources: CoverageSourceContract[]
|
||||
}
|
||||
|
||||
export interface CoverageResolutionItem {
|
||||
zone: string
|
||||
theme: string
|
||||
status: CoverageStatus
|
||||
source_names: string[]
|
||||
materialized_dataset_ids: string[]
|
||||
limitation_message: string
|
||||
}
|
||||
|
||||
export interface CoverageResolveResponse {
|
||||
project_id: string
|
||||
bbox: CoverageBBox
|
||||
requested_themes: string[]
|
||||
intersected_zones: string[]
|
||||
outside_supported_scope: boolean
|
||||
items: CoverageResolutionItem[]
|
||||
warnings: string[]
|
||||
}
|
||||
|
||||
export interface SystemCapabilitiesResponse {
|
||||
status: string
|
||||
service: string
|
||||
|
||||
Reference in New Issue
Block a user