Expand scoped demo analysis access
This commit is contained in:
+38
-25
@@ -90,9 +90,21 @@ const workspaceNavGroups: WorkspaceNavigationGroup[] = [
|
||||
{ label: 'Beheer', keys: ['overview', 'system'] },
|
||||
]
|
||||
|
||||
const guestWorkspaceKeys = new Set<WorkspaceKey>(['map', 'analysis'])
|
||||
const guestWorkspaceKeys = new Set<WorkspaceKey>([
|
||||
'overview',
|
||||
'data',
|
||||
'map',
|
||||
'assistant',
|
||||
'analysis',
|
||||
'ai',
|
||||
'exports',
|
||||
])
|
||||
const guestWorkspaceGroups: WorkspaceNavigationGroup[] = [
|
||||
{ label: 'Demowerkruimte', keys: ['map', 'analysis'] },
|
||||
{ label: 'Verkennen', keys: ['map', 'data'] },
|
||||
{ label: 'Vragen', keys: ['assistant'] },
|
||||
{ label: 'Analyseren', keys: ['analysis', 'ai'] },
|
||||
{ label: 'Afronden', keys: ['exports'] },
|
||||
{ label: 'Demo', keys: ['overview'] },
|
||||
]
|
||||
|
||||
interface WorkbenchAppProps {
|
||||
@@ -589,7 +601,7 @@ function WorkbenchApp({ username, accessMode, loggingOut, onLogout }: WorkbenchA
|
||||
demoWorkflowMessage,
|
||||
loadDemoWorkflow,
|
||||
} = useDemoWorkflow({
|
||||
restrictedMode: isGuest,
|
||||
restrictedMode: false,
|
||||
loadProjects,
|
||||
loadProjectData,
|
||||
loadDatasetDetails,
|
||||
@@ -618,7 +630,7 @@ function WorkbenchApp({ username, accessMode, loggingOut, onLogout }: WorkbenchA
|
||||
}, [isGuest, loadDemoWorkflow])
|
||||
|
||||
useWorkbenchBootstrap({
|
||||
restrictedMode: isGuest,
|
||||
restrictedMode: false,
|
||||
selectedProjectId,
|
||||
selectedDetectionRunId,
|
||||
detectionClassFilter,
|
||||
@@ -720,7 +732,7 @@ function WorkbenchApp({ username, accessMode, loggingOut, onLogout }: WorkbenchA
|
||||
}
|
||||
const openWorkflowGuidanceStep = (target: WorkspaceKey) => {
|
||||
if (isGuest && !guestWorkspaceKeys.has(target)) {
|
||||
setActiveWorkspace(target === 'exports' ? 'analysis' : 'map')
|
||||
setActiveWorkspace('map')
|
||||
return
|
||||
}
|
||||
if (target === 'map' && availableMapDatasets.length > 0 && !mapFeatureCollection) {
|
||||
@@ -894,9 +906,9 @@ function WorkbenchApp({ username, accessMode, loggingOut, onLogout }: WorkbenchA
|
||||
<ShieldCheck aria-hidden="true" />
|
||||
<div>
|
||||
<strong>Tijdelijke demowerkruimte</strong>
|
||||
<span>U verkent vooraf geladen voorbeelddata. Wijzigingen, nieuwe analyses en operatorfuncties zijn uitgeschakeld.</span>
|
||||
<span>Alle analysemodellen en werkfuncties zijn beschikbaar. Beheer, instellingen en blijvende gegevenswijzigingen blijven afgeschermd.</span>
|
||||
</div>
|
||||
<span className="guest-mode-badge">Alleen-lezen</span>
|
||||
<span className="guest-mode-badge">Analyse-toegang</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -924,7 +936,7 @@ function WorkbenchApp({ username, accessMode, loggingOut, onLogout }: WorkbenchA
|
||||
<WorkspaceSignal workspace={activeWorkspace} />
|
||||
<div className="workspace-heading-actions">
|
||||
<p>{activeWorkspaceItem.description}</p>
|
||||
{!isGuest && activeWorkspace !== 'overview' ? (
|
||||
{activeWorkspace !== 'overview' ? (
|
||||
<button
|
||||
type="button"
|
||||
className={inspectorOpen ? 'inspector-toggle inspector-toggle-active' : 'inspector-toggle'}
|
||||
@@ -960,6 +972,15 @@ function WorkbenchApp({ username, accessMode, loggingOut, onLogout }: WorkbenchA
|
||||
projectId={selectedProjectId ?? undefined}
|
||||
loading={loadingDatasets}
|
||||
/>
|
||||
{isGuest ? (
|
||||
<div className="guest-readonly-card">
|
||||
<ShieldCheck aria-hidden="true" />
|
||||
<div>
|
||||
<strong>Bronnen bekijken zonder beheerrechten</strong>
|
||||
<span>De demo gebruikt dezelfde beschikbare databronnen. Projecten, gebieden en uploads worden alleen door de operator beheerd.</span>
|
||||
</div>
|
||||
</div>
|
||||
) : <>
|
||||
<ProjectPanel
|
||||
projects={projects}
|
||||
selectedProjectId={selectedProjectId}
|
||||
@@ -1002,12 +1023,13 @@ function WorkbenchApp({ username, accessMode, loggingOut, onLogout }: WorkbenchA
|
||||
onOpenDatasetInMap={openDatasetInMap}
|
||||
onOpenDatasetExport={openDatasetExport}
|
||||
/>
|
||||
</>}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="workspace-persistent-map" hidden={activeWorkspace !== 'map'}>
|
||||
<MapWorkspace
|
||||
readOnly={isGuest}
|
||||
readOnly={false}
|
||||
selectedProjectId={selectedProjectId}
|
||||
projects={projects}
|
||||
areas={areas}
|
||||
@@ -1103,8 +1125,8 @@ function WorkbenchApp({ username, accessMode, loggingOut, onLogout }: WorkbenchA
|
||||
onRefreshProjectData={() => (
|
||||
selectedProjectId ? loadProjectData(selectedProjectId) : Promise.resolve(null)
|
||||
)}
|
||||
onOpenAssistant={() => setActiveWorkspace(isGuest ? 'analysis' : 'assistant')}
|
||||
onOpenExports={() => setActiveWorkspace(isGuest ? 'analysis' : 'exports')}
|
||||
onOpenAssistant={() => setActiveWorkspace('assistant')}
|
||||
onOpenExports={() => setActiveWorkspace('exports')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1121,10 +1143,9 @@ function WorkbenchApp({ username, accessMode, loggingOut, onLogout }: WorkbenchA
|
||||
evidenceLoading={qualityEvidenceLoading}
|
||||
evidenceError={qualityEvidenceError}
|
||||
onOpenMapWorkspace={() => setActiveWorkspace('map')}
|
||||
onOpenAnalysisWorkspace={() => setActiveWorkspace(isGuest ? 'map' : 'ai')}
|
||||
onOpenAnalysisWorkspace={() => setActiveWorkspace('ai')}
|
||||
/>
|
||||
{!isGuest ? (
|
||||
<details className="secondary-analysis-disclosure">
|
||||
<details className="secondary-analysis-disclosure">
|
||||
<summary>
|
||||
<span>Historische vectorlagen vergelijken</span>
|
||||
<strong>Geavanceerd</strong>
|
||||
@@ -1144,16 +1165,7 @@ function WorkbenchApp({ username, accessMode, loggingOut, onLogout }: WorkbenchA
|
||||
onIncludeUnchangedChange={setChangeIncludeUnchanged}
|
||||
onRun={runChangeDetection}
|
||||
/>
|
||||
</details>
|
||||
) : (
|
||||
<div className="guest-readonly-card">
|
||||
<ShieldCheck aria-hidden="true" />
|
||||
<div>
|
||||
<strong>Controleerbaar voorbeeldresultaat</strong>
|
||||
<span>Deze kwaliteitsweergave gebruikt de vooraf berekende demo. Nieuwe vergelijkingen zijn alleen beschikbaar voor operators.</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</details>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -1171,6 +1183,7 @@ function WorkbenchApp({ username, accessMode, loggingOut, onLogout }: WorkbenchA
|
||||
{activeWorkspace === 'ai' ? (
|
||||
<div className="workspace-grid workspace-grid-ai">
|
||||
<DetectionLab
|
||||
managementLocked={isGuest}
|
||||
detectionModels={detectionModels}
|
||||
modelAssets={modelAssets}
|
||||
loadingDetectionModels={loadingDetectionModels}
|
||||
@@ -1318,7 +1331,7 @@ function WorkbenchApp({ username, accessMode, loggingOut, onLogout }: WorkbenchA
|
||||
) : null}
|
||||
</main>
|
||||
|
||||
{inspectorOpen && !isGuest ? (
|
||||
{inspectorOpen ? (
|
||||
<aside className="workbench-inspector" id="workbench-inspector" aria-label="Details van de huidige selectie">
|
||||
<WorkbenchInspector
|
||||
selectedProject={selectedProject}
|
||||
|
||||
@@ -78,6 +78,7 @@ interface CalibrationRow {
|
||||
}
|
||||
|
||||
interface DetectionLabProps {
|
||||
managementLocked?: boolean
|
||||
detectionModels: DetectionModelCapability[]
|
||||
modelAssets: ModelAssetRead[]
|
||||
loadingDetectionModels: boolean
|
||||
@@ -138,6 +139,7 @@ interface DetectionLabProps {
|
||||
}
|
||||
|
||||
export function DetectionLab({
|
||||
managementLocked = false,
|
||||
detectionModels,
|
||||
modelAssets,
|
||||
loadingDetectionModels,
|
||||
@@ -332,7 +334,7 @@ export function DetectionLab({
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<DetectionModelManagement
|
||||
{!managementLocked ? <DetectionModelManagement
|
||||
detectionModels={detectionModels}
|
||||
modelAssets={modelAssets}
|
||||
loadingDetectionModels={loadingDetectionModels}
|
||||
@@ -347,7 +349,7 @@ export function DetectionLab({
|
||||
onRefreshYoloPreflight={onRefreshYoloPreflight}
|
||||
onSelectModelAsset={onSelectModelAsset}
|
||||
onApplyOperatorProfile={onApplyOperatorProfile}
|
||||
/>
|
||||
/> : null}
|
||||
|
||||
<div className="lab-block">
|
||||
<div className="ai-lab-run-surface" aria-label="Gebouwdetectie starten">
|
||||
@@ -414,7 +416,7 @@ export function DetectionLab({
|
||||
<p>Voeg hieronder een gegeorefereerde GeoTIFF toe. GeoIntel controleert de projectie en bewaart het bronbestand als dataset.</p>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="guided-raster-input" aria-label="Luchtbeeld toevoegen">
|
||||
{!managementLocked ? <div className="guided-raster-input" aria-label="Luchtbeeld toevoegen">
|
||||
<div>
|
||||
<strong>Eigen luchtbeeld toevoegen</strong>
|
||||
<p>Gebruik een GeoTIFF met geldige CRS en georeferentie. Een bestaand luchtbeeld kan meteen in de keuzelijst worden gebruikt.</p>
|
||||
@@ -444,7 +446,7 @@ export function DetectionLab({
|
||||
>
|
||||
{detectionWorkflowStage === 'uploading' ? 'Luchtbeeld toevoegen...' : 'Luchtbeeld toevoegen'}
|
||||
</button>
|
||||
</div>
|
||||
</div> : null}
|
||||
<div className="lab-form-grid">
|
||||
<label>
|
||||
Luchtbeeld
|
||||
@@ -499,7 +501,7 @@ export function DetectionLab({
|
||||
{detectionWorkflowActionLabel(detectionWorkflowStage)}
|
||||
</button>
|
||||
|
||||
<details className="ai-lab-model-surface technical-manifest-surface" aria-label="Technische tegelinstellingen">
|
||||
{!managementLocked ? <details className="ai-lab-model-surface technical-manifest-surface" aria-label="Technische tegelinstellingen">
|
||||
<summary>
|
||||
<span>Technische tegelinstellingen</span>
|
||||
<strong>{detectionHasTileManifest ? 'manifest beschikbaar' : 'automatisch'}</strong>
|
||||
@@ -528,7 +530,7 @@ export function DetectionLab({
|
||||
Bestaande beeldtegels analyseren
|
||||
</button>
|
||||
</div>
|
||||
</details>
|
||||
</details> : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -556,7 +558,7 @@ export function DetectionLab({
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<details className="ai-lab-model-surface guided-calibration-surface" aria-label="Modelkalibratie voor beheerders">
|
||||
{!managementLocked ? <details className="ai-lab-model-surface guided-calibration-surface" aria-label="Modelkalibratie voor beheerders">
|
||||
<summary>
|
||||
<span>Modelkalibratie voor beheerders</span>
|
||||
<strong>{detectionCalibrationRows.length > 0 ? `${detectionCalibrationRows.length} drempels getest` : 'gesloten'}</strong>
|
||||
@@ -677,7 +679,7 @@ export function DetectionLab({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</details>
|
||||
</details> : null}
|
||||
|
||||
<div className="ai-lab-results-surface" aria-label="Resultaten van de beeldanalyse">
|
||||
<div className="panel-title-row">
|
||||
|
||||
@@ -67,17 +67,15 @@ export function useDemoWorkflow({
|
||||
setSegmentationReferenceDatasetId(result.reference_dataset_id)
|
||||
setDemoWorkflowMessage(result.message)
|
||||
await loadProjects(result.project_id)
|
||||
const operatorOnlyLoads = restrictedMode
|
||||
? Promise.resolve()
|
||||
: Promise.all([
|
||||
loadDetectionRuns(result.project_id),
|
||||
loadSegmentationRuns(result.project_id),
|
||||
loadExports(result.project_id),
|
||||
]).then(() => undefined)
|
||||
const analysisLoads = Promise.all([
|
||||
loadDetectionRuns(result.project_id),
|
||||
loadSegmentationRuns(result.project_id),
|
||||
loadExports(result.project_id),
|
||||
]).then(() => undefined)
|
||||
const [projectData] = await Promise.all([
|
||||
loadProjectData(result.project_id),
|
||||
loadQualityChecks(result.project_id),
|
||||
operatorOnlyLoads,
|
||||
analysisLoads,
|
||||
])
|
||||
const candidateDataset = projectData?.datasets.find((dataset) => dataset.id === result.candidate_dataset_id)
|
||||
const rasterDataset = projectData?.datasets.find((dataset) => dataset.id === result.raster_dataset_id)
|
||||
|
||||
@@ -207,6 +207,7 @@ export function useDetectionWorkflow({
|
||||
setDetectionRunError(null)
|
||||
try {
|
||||
const params = {
|
||||
project_id: selectedProjectId ?? '',
|
||||
class_name: detectionClassFilter || null,
|
||||
min_confidence: detectionMinConfidenceFilter > 0 ? detectionMinConfidenceFilter : null,
|
||||
}
|
||||
@@ -415,7 +416,7 @@ export function useDetectionWorkflow({
|
||||
setDetectionQaResult(null)
|
||||
setRunningDetectionQa(true)
|
||||
try {
|
||||
const result = await detectionApi.compareWithReference(analysisRunId, {
|
||||
const result = await detectionApi.compareWithReference(analysisRunId, selectedProjectId!, {
|
||||
reference_dataset_id: referenceDatasetId,
|
||||
iou_threshold: iouThresholdOverride ?? qaIouThreshold,
|
||||
class_name: useCurrentFilters ? detectionClassFilter || null : null,
|
||||
@@ -486,7 +487,7 @@ export function useDetectionWorkflow({
|
||||
parameters_json: { calibration: true, calibration_thresholds: thresholds },
|
||||
})
|
||||
setSelectedDetectionRunId(result.analysis_run_id)
|
||||
const qa = await detectionApi.compareWithReference(result.analysis_run_id, {
|
||||
const qa = await detectionApi.compareWithReference(result.analysis_run_id, selectedProjectId, {
|
||||
reference_dataset_id: detectionReferenceDatasetId,
|
||||
iou_threshold: qaIouThreshold,
|
||||
class_name: detectionClassFilter || null,
|
||||
|
||||
@@ -59,7 +59,7 @@ export function useExportWorkflow({
|
||||
setExporting(true)
|
||||
setExportError(null)
|
||||
try {
|
||||
const response = await exportsApi.exportGeojson({
|
||||
const response = await exportsApi.exportGeojson(selectedDataset.project_id, {
|
||||
dataset_id: selectedDataset.id,
|
||||
export_kind: 'dataset',
|
||||
name: selectedDataset.name.replace(/\.(geo)?json$/i, ''),
|
||||
@@ -74,14 +74,14 @@ export function useExportWorkflow({
|
||||
}
|
||||
|
||||
const exportSelectedDetectionRunGeoJson = async () => {
|
||||
if (!selectedDetectionRunId) {
|
||||
if (!selectedDetectionRunId || !selectedProjectId) {
|
||||
setExportError('Select a detection run before exporting GeoJSON.')
|
||||
return
|
||||
}
|
||||
setExporting(true)
|
||||
setExportError(null)
|
||||
try {
|
||||
const response = await exportsApi.exportGeojson({
|
||||
const response = await exportsApi.exportGeojson(selectedProjectId, {
|
||||
analysis_run_id: selectedDetectionRunId,
|
||||
export_kind: 'detection_run',
|
||||
})
|
||||
@@ -95,14 +95,14 @@ export function useExportWorkflow({
|
||||
}
|
||||
|
||||
const exportSelectedSegmentationRunGeoJson = async () => {
|
||||
if (!selectedSegmentationRunId) {
|
||||
if (!selectedSegmentationRunId || !selectedProjectId) {
|
||||
setExportError('Select a segmentation run before exporting GeoJSON.')
|
||||
return
|
||||
}
|
||||
setExporting(true)
|
||||
setExportError(null)
|
||||
try {
|
||||
const response = await exportsApi.exportGeojson({
|
||||
const response = await exportsApi.exportGeojson(selectedProjectId, {
|
||||
analysis_run_id: selectedSegmentationRunId,
|
||||
export_kind: 'segmentation_run',
|
||||
})
|
||||
@@ -123,7 +123,7 @@ export function useExportWorkflow({
|
||||
setSelectionExporting(true)
|
||||
setSelectionExportError(null)
|
||||
try {
|
||||
const response = await exportsApi.exportGeojson({
|
||||
const response = await exportsApi.exportGeojson(selectedDataset.project_id, {
|
||||
dataset_id: selectedDataset.id,
|
||||
area_id: areaId,
|
||||
export_kind: 'vector_selection',
|
||||
@@ -199,7 +199,8 @@ export function useExportWorkflow({
|
||||
const previewExportContent = async (exportId: string) => {
|
||||
setExportError(null)
|
||||
try {
|
||||
const response = await exportsApi.getContent(exportId)
|
||||
if (!selectedProjectId) return
|
||||
const response = await exportsApi.getContent(selectedProjectId, exportId)
|
||||
setExportPreview(response.content)
|
||||
} catch (error) {
|
||||
setExportError(formatError(error, 'Failed to load export content'))
|
||||
@@ -207,7 +208,8 @@ export function useExportWorkflow({
|
||||
}
|
||||
|
||||
const downloadExportArtifact = (exportId: string) => {
|
||||
window.open(exportsApi.downloadUrl(exportId), '_blank', 'noopener,noreferrer')
|
||||
if (!selectedProjectId) return
|
||||
window.open(exportsApi.downloadUrl(selectedProjectId, exportId), '_blank', 'noopener,noreferrer')
|
||||
}
|
||||
|
||||
const resetExportsForProject = () => {
|
||||
|
||||
@@ -51,7 +51,7 @@ export function useMapSelectionQa({
|
||||
iou_threshold: 0.5,
|
||||
area_id: candidateDataset.area_id ?? null,
|
||||
}
|
||||
const job: JobRead = await qaApi.runQa(request)
|
||||
const job: JobRead = await qaApi.runQa(selectedProjectId, request)
|
||||
if (job.status === 'failed') {
|
||||
setMapSelectionQaError(job.error_message || 'Map selection QA/QC failed')
|
||||
return null
|
||||
|
||||
@@ -92,7 +92,7 @@ export function useQualityWorkflow({ selectedProjectId, loadProjectData }: Quali
|
||||
iou_threshold: qaIouThreshold,
|
||||
area_id: qaAreaId || null,
|
||||
}
|
||||
const job: JobRead = await qaApi.runQa(request)
|
||||
const job: JobRead = await qaApi.runQa(selectedProjectId, request)
|
||||
if (job.status === 'failed') {
|
||||
setQaError(job.error_message || 'QA comparison failed')
|
||||
return
|
||||
|
||||
@@ -104,6 +104,7 @@ export function useSegmentationWorkflow({
|
||||
setSegmentationRunError(null)
|
||||
try {
|
||||
const params = {
|
||||
project_id: selectedProjectId ?? '',
|
||||
class_name: segmentationClassFilter || null,
|
||||
min_confidence: segmentationMinConfidenceFilter > 0 ? segmentationMinConfidenceFilter : null,
|
||||
}
|
||||
@@ -175,7 +176,7 @@ export function useSegmentationWorkflow({
|
||||
setSegmentationQaResult(null)
|
||||
setRunningSegmentationQa(true)
|
||||
try {
|
||||
const result = await segmentationApi.compareWithReference(selectedSegmentationRunId, {
|
||||
const result = await segmentationApi.compareWithReference(selectedSegmentationRunId, selectedProjectId!, {
|
||||
reference_dataset_id: segmentationReferenceDatasetId,
|
||||
iou_threshold: qaIouThreshold,
|
||||
class_name: segmentationClassFilter || null,
|
||||
|
||||
@@ -65,19 +65,19 @@ describe('useWorkbenchBootstrap', () => {
|
||||
expect(state.loadExports).toHaveBeenCalledWith('project-1')
|
||||
})
|
||||
|
||||
it('keeps the guest bootstrap inside the read-only demo surface', async () => {
|
||||
it('loads the same analysis catalog and project results for a guest', async () => {
|
||||
const state = { ...options('project-1'), restrictedMode: true }
|
||||
renderHook(() => useWorkbenchBootstrap(state))
|
||||
|
||||
await waitFor(() => expect(state.loadProjectData).toHaveBeenCalledWith('project-1'))
|
||||
expect(state.loadCapabilities).toHaveBeenCalledOnce()
|
||||
expect(state.loadQualityChecks).toHaveBeenCalledWith('project-1')
|
||||
expect(state.loadDetectionModels).not.toHaveBeenCalled()
|
||||
expect(state.loadSegmentationModels).not.toHaveBeenCalled()
|
||||
expect(state.loadDetectionRuns).not.toHaveBeenCalled()
|
||||
expect(state.loadSegmentationRuns).not.toHaveBeenCalled()
|
||||
expect(state.loadExports).not.toHaveBeenCalled()
|
||||
expect(state.loadDetectionResults).not.toHaveBeenCalled()
|
||||
expect(state.loadSegmentationResults).not.toHaveBeenCalled()
|
||||
expect(state.loadDetectionModels).toHaveBeenCalledOnce()
|
||||
expect(state.loadSegmentationModels).toHaveBeenCalledOnce()
|
||||
expect(state.loadDetectionRuns).toHaveBeenCalledWith('project-1')
|
||||
expect(state.loadSegmentationRuns).toHaveBeenCalledWith('project-1')
|
||||
expect(state.loadExports).toHaveBeenCalledWith('project-1')
|
||||
expect(state.loadDetectionResults).toHaveBeenCalledOnce()
|
||||
expect(state.loadSegmentationResults).toHaveBeenCalledOnce()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -59,10 +59,8 @@ export function useWorkbenchBootstrap({
|
||||
useEffect(() => {
|
||||
loadProjects().catch(() => null)
|
||||
loadCapabilities().catch(() => null)
|
||||
if (!restrictedMode) {
|
||||
loadDetectionModels().catch(() => null)
|
||||
loadSegmentationModels().catch(() => null)
|
||||
}
|
||||
loadDetectionModels().catch(() => null)
|
||||
loadSegmentationModels().catch(() => null)
|
||||
}, [restrictedMode])
|
||||
|
||||
useEffect(() => {
|
||||
@@ -81,20 +79,16 @@ export function useWorkbenchBootstrap({
|
||||
resetExportsForProject()
|
||||
loadProjectData(selectedProjectId).catch(() => null)
|
||||
loadQualityChecks(selectedProjectId).catch(() => null)
|
||||
if (!restrictedMode) {
|
||||
loadDetectionRuns(selectedProjectId).catch(() => null)
|
||||
loadSegmentationRuns(selectedProjectId).catch(() => null)
|
||||
loadExports(selectedProjectId).catch(() => null)
|
||||
}
|
||||
loadDetectionRuns(selectedProjectId).catch(() => null)
|
||||
loadSegmentationRuns(selectedProjectId).catch(() => null)
|
||||
loadExports(selectedProjectId).catch(() => null)
|
||||
}, [restrictedMode, selectedProjectId])
|
||||
|
||||
useEffect(() => {
|
||||
if (restrictedMode) return
|
||||
loadDetectionResults().catch(() => null)
|
||||
}, [restrictedMode, selectedDetectionRunId, detectionClassFilter, detectionMinConfidenceFilter])
|
||||
|
||||
useEffect(() => {
|
||||
if (restrictedMode) return
|
||||
loadSegmentationResults().catch(() => null)
|
||||
}, [restrictedMode, selectedSegmentationRunId, segmentationClassFilter, segmentationMinConfidenceFilter])
|
||||
}
|
||||
|
||||
@@ -29,21 +29,21 @@ export const detectionApi = {
|
||||
getYoloPreflight: (params: { tile_manifest_path?: string | null; check_model_load?: boolean | null; model_asset_id?: string | null } = {}): Promise<YoloPreflightResponse> =>
|
||||
apiGet<YoloPreflightResponse>(`/api/v1/detection/yolo/preflight${queryString(params)}`),
|
||||
run: (payload: DetectionRunRequest): Promise<DetectionRunResponse> =>
|
||||
apiPost<DetectionRunResponse>('/api/v1/detection/run', payload),
|
||||
apiPost<DetectionRunResponse>(`/api/v1/detection/run?project_id=${encodeURIComponent(payload.project_id)}`, payload),
|
||||
listRuns: (params: { project_id?: string | null; dataset_id?: string | null } = {}): Promise<DetectionRunListResponse> =>
|
||||
apiGet<DetectionRunListResponse>(`/api/v1/detection/runs${queryString(params)}`),
|
||||
getRun: (analysisRunId: string): Promise<DetectionRunRead> =>
|
||||
apiGet<DetectionRunRead>(`/api/v1/detection/runs/${analysisRunId}`),
|
||||
listDetections: (
|
||||
analysisRunId: string,
|
||||
params: { dataset_id?: string | null; class_name?: string | null; min_confidence?: number | null } = {},
|
||||
params: { project_id: string; dataset_id?: string | null; class_name?: string | null; min_confidence?: number | null },
|
||||
): Promise<DetectionListResponse> =>
|
||||
apiGet<DetectionListResponse>(`/api/v1/detection/runs/${analysisRunId}/detections${queryString(params)}`),
|
||||
getRunGeoJson: (
|
||||
analysisRunId: string,
|
||||
params: { class_name?: string | null; min_confidence?: number | null } = {},
|
||||
params: { project_id: string; class_name?: string | null; min_confidence?: number | null },
|
||||
): Promise<GeoJSON.FeatureCollection> =>
|
||||
apiGet<GeoJSON.FeatureCollection>(`/api/v1/detection/runs/${analysisRunId}/geojson${queryString(params)}`),
|
||||
compareWithReference: (analysisRunId: string, payload: DetectionQaRequest): Promise<DetectionQaResult> =>
|
||||
apiPost<DetectionQaResult>(`/api/v1/detection/runs/${analysisRunId}/qa/reference`, payload),
|
||||
compareWithReference: (analysisRunId: string, projectId: string, payload: DetectionQaRequest): Promise<DetectionQaResult> =>
|
||||
apiPost<DetectionQaResult>(`/api/v1/detection/runs/${analysisRunId}/qa/reference?project_id=${encodeURIComponent(projectId)}`, payload),
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import type {
|
||||
|
||||
export const exportsApi = {
|
||||
exportGeojson: (
|
||||
projectId: string,
|
||||
payload:
|
||||
| {
|
||||
dataset_id?: string
|
||||
@@ -24,18 +25,20 @@ export const exportsApi = {
|
||||
| string,
|
||||
): Promise<ExportCreateResponse> => {
|
||||
const body = typeof payload === 'string' ? { dataset_id: payload, export_kind: 'dataset' } : payload
|
||||
return apiPost<ExportCreateResponse>(`/api/v1/exports/geojson`, body)
|
||||
return apiPost<ExportCreateResponse>(`/api/v1/exports/geojson?project_id=${encodeURIComponent(projectId)}`, body)
|
||||
},
|
||||
exportProjectMetadata: (projectId: string, name?: string): Promise<ExportCreateResponse> =>
|
||||
apiPost<ExportCreateResponse>(`/api/v1/exports/metadata`, { project_id: projectId, name }),
|
||||
apiPost<ExportCreateResponse>(`/api/v1/exports/metadata?project_id=${encodeURIComponent(projectId)}`, { project_id: projectId, name }),
|
||||
exportProjectReport: (projectId: string, name?: string): Promise<ExportCreateResponse> =>
|
||||
apiPost<ExportCreateResponse>(`/api/v1/exports/report`, { project_id: projectId, name }),
|
||||
apiPost<ExportCreateResponse>(`/api/v1/exports/report?project_id=${encodeURIComponent(projectId)}`, { project_id: projectId, name }),
|
||||
exportMapResult: (payload: MapResultExportRequest): Promise<ExportCreateResponse> =>
|
||||
apiPost<ExportCreateResponse>(`/api/v1/exports/map-result`, payload),
|
||||
apiPost<ExportCreateResponse>(`/api/v1/exports/map-result?project_id=${encodeURIComponent(payload.project_id)}`, payload),
|
||||
listProjectExports: (projectId: string): Promise<ExportListResponse> =>
|
||||
apiGet<ExportListResponse>(`/api/v1/exports/projects/${projectId}/exports`),
|
||||
getExport: (exportId: string): Promise<ExportRead> => apiGet<ExportRead>(`/api/v1/exports/${exportId}`),
|
||||
getContent: (exportId: string): Promise<ExportContentResponse> =>
|
||||
apiGet<ExportContentResponse>(`/api/v1/exports/${exportId}/content`),
|
||||
downloadUrl: (exportId: string): string => apiUrl(`/api/v1/exports/${exportId}/download`),
|
||||
apiGet<ExportListResponse>(`/api/v1/exports/projects/${projectId}/exports?project_id=${encodeURIComponent(projectId)}`),
|
||||
getExport: (projectId: string, exportId: string): Promise<ExportRead> =>
|
||||
apiGet<ExportRead>(`/api/v1/exports/${exportId}?project_id=${encodeURIComponent(projectId)}`),
|
||||
getContent: (projectId: string, exportId: string): Promise<ExportContentResponse> =>
|
||||
apiGet<ExportContentResponse>(`/api/v1/exports/${exportId}/content?project_id=${encodeURIComponent(projectId)}`),
|
||||
downloadUrl: (projectId: string, exportId: string): string =>
|
||||
apiUrl(`/api/v1/exports/${exportId}/download?project_id=${encodeURIComponent(projectId)}`),
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ import type {
|
||||
} from '../../types'
|
||||
|
||||
export const qaApi = {
|
||||
runQa: (payload: QaComparisonRequest): Promise<JobRead> =>
|
||||
apiPost<JobRead>('/api/v1/qa/detections-vs-reference', payload),
|
||||
runQa: (projectId: string, payload: QaComparisonRequest): Promise<JobRead> =>
|
||||
apiPost<JobRead>(`/api/v1/qa/detections-vs-reference?project_id=${encodeURIComponent(projectId)}`, payload),
|
||||
listQualityChecks: (projectId: string): Promise<QualityCheckListResponse> =>
|
||||
apiGet<QualityCheckListResponse>(`/api/v1/projects/${projectId}/quality-checks`),
|
||||
getQualityEvidenceGeoJson: (projectId: string, qualityCheckId: string): Promise<QualityEvidenceGeoJsonResponse> =>
|
||||
|
||||
@@ -24,21 +24,21 @@ function queryString(params: Record<string, string | number | null | undefined>)
|
||||
export const segmentationApi = {
|
||||
listModels: (): Promise<SegmentationModelsResponse> => apiGet<SegmentationModelsResponse>('/api/v1/segmentation/models'),
|
||||
run: (payload: SegmentationRunRequest): Promise<SegmentationRunResponse> =>
|
||||
apiPost<SegmentationRunResponse>('/api/v1/segmentation/run', payload),
|
||||
apiPost<SegmentationRunResponse>(`/api/v1/segmentation/run?project_id=${encodeURIComponent(payload.project_id)}`, payload),
|
||||
listRuns: (params: { project_id?: string | null; dataset_id?: string | null } = {}): Promise<SegmentationRunListResponse> =>
|
||||
apiGet<SegmentationRunListResponse>(`/api/v1/segmentation/runs${queryString(params)}`),
|
||||
getRun: (analysisRunId: string): Promise<SegmentationRunRead> =>
|
||||
apiGet<SegmentationRunRead>(`/api/v1/segmentation/runs/${analysisRunId}`),
|
||||
listSegmentations: (
|
||||
analysisRunId: string,
|
||||
params: { dataset_id?: string | null; class_name?: string | null; min_confidence?: number | null } = {},
|
||||
params: { project_id: string; dataset_id?: string | null; class_name?: string | null; min_confidence?: number | null },
|
||||
): Promise<SegmentationListResponse> =>
|
||||
apiGet<SegmentationListResponse>(`/api/v1/segmentation/runs/${analysisRunId}/segmentations${queryString(params)}`),
|
||||
getRunGeoJson: (
|
||||
analysisRunId: string,
|
||||
params: { class_name?: string | null; min_confidence?: number | null } = {},
|
||||
params: { project_id: string; class_name?: string | null; min_confidence?: number | null },
|
||||
): Promise<GeoJSON.FeatureCollection> =>
|
||||
apiGet<GeoJSON.FeatureCollection>(`/api/v1/segmentation/runs/${analysisRunId}/geojson${queryString(params)}`),
|
||||
compareWithReference: (analysisRunId: string, payload: SegmentationQaRequest): Promise<SegmentationQaResult> =>
|
||||
apiPost<SegmentationQaResult>(`/api/v1/segmentation/runs/${analysisRunId}/qa/reference`, payload),
|
||||
compareWithReference: (analysisRunId: string, projectId: string, payload: SegmentationQaRequest): Promise<SegmentationQaResult> =>
|
||||
apiPost<SegmentationQaResult>(`/api/v1/segmentation/runs/${analysisRunId}/qa/reference?project_id=${encodeURIComponent(projectId)}`, payload),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user