33
44import React , { useCallback , useEffect , useState } from 'react' ;
55import styled from 'styled-components' ;
6- import { WMSCapabilities , WMSCapabilitiesLoader } from '@loaders.gl/wms' ;
7- import { load } from '@loaders.gl/core' ;
6+ import { WMSCapabilities } from '@loaders.gl/wms' ;
7+
8+ import { validateUrl } from '@kepler.gl/common-utils' ;
9+ import { DatasetType , REMOTE_TILE , RemoteTileFormat , WMSDatasetMetadata } from '@kepler.gl/constants' ;
10+ import { getWMSCapabilities , wmsCapabilitiesToDatasetMetadata } from '@kepler.gl/table' ;
811
9- import { DatasetType , REMOTE_TILE , RemoteTileFormat } from '@kepler.gl/constants' ;
1012import { MetaResponse } from './common' ;
1113import { InputLight } from '../../common' ;
1214
1315const TilesetInputContainer = styled . div `
1416 display: grid;
15- grid-template-rows: repeat(2, 1fr );
17+ grid-template-rows: repeat(3, auto );
1618 row-gap: 18px;
1719 font-size: 12px;
1820` ;
@@ -22,18 +24,34 @@ const TilesetInputDescription = styled.div`
2224 color: ${ props => props . theme . AZURE200 } ;
2325 font-size: 11px;
2426` ;
27+
28+ const ExampleUrlsContainer = styled . div `
29+ text-align: left;
30+ color: ${ props => props . theme . AZURE200 } ;
31+ font-size: 11px;
32+
33+ .example-url {
34+ margin-top: 8px;
35+ display: block;
36+ }
37+ ` ;
38+
2539type WMSTileFormProps = {
2640 setResponse : ( response : MetaResponse ) => void ;
2741} ;
2842
43+ type WMSData = {
44+ metadata : WMSCapabilities | null ;
45+ layers : WMSDatasetMetadata [ 'layers' ] ;
46+ version : string ;
47+ } ;
48+
2949const TilesetWMSForm : React . FC < WMSTileFormProps > = ( { setResponse} ) => {
3050 const [ layerName , setLayerName ] = useState < string > ( '' ) ;
3151 const [ wmsUrl , setWmsUrl ] = useState < string > ( '' ) ;
32- const [ metadata , setMetadata ] = useState < any > ( null ) ;
3352 const [ loading , setLoading ] = useState < boolean > ( false ) ;
3453 const [ error , setError ] = useState < Error | null > ( null ) ;
35- const [ availableLayers , setAvailableLayers ] = useState < { name : string ; title : string } [ ] > ( [ ] ) ;
36- const [ wmsVersion , setWmsVersion ] = useState < string > ( '1.3.0' ) ;
54+ const [ wmsData , setWMSData ] = useState < WMSData | null > ( null ) ;
3755
3856 const onLayerNameChange = useCallback (
3957 ( event : React . ChangeEvent < HTMLInputElement > ) => {
@@ -49,48 +67,34 @@ const TilesetWMSForm: React.FC<WMSTileFormProps> = ({setResponse}) => {
4967 const newWmsUrl = event . target . value ;
5068 setWmsUrl ( newWmsUrl ) ;
5169
70+ if ( ! validateUrl ( newWmsUrl ) ) {
71+ setWMSData ( null ) ;
72+ return ;
73+ }
74+
5275 // Fetch WMS GetCapabilities
5376 try {
5477 setLoading ( true ) ;
5578 setError ( null ) ;
56- const data = ( await load (
57- ` ${ newWmsUrl } ?service=WMS&request=GetCapabilities` ,
58- WMSCapabilitiesLoader
59- ) ) as WMSCapabilities ;
79+
80+ const data = await getWMSCapabilities ( newWmsUrl ) ;
81+
82+ const datasetMetadata = wmsCapabilitiesToDatasetMetadata ( data ) ;
6083
6184 // Extract name or title from GetCapabilities response
6285 const serviceTitle = data ?. title || data ?. name ;
6386 if ( serviceTitle && ! layerName ) {
6487 setLayerName ( serviceTitle ) ;
6588 }
6689
67- // Flatten layers if they are nested
68- const layers = data . layers . flatMap ( layer => {
69- if ( layer . layers && layer . layers . length > 0 ) {
70- return layer . layers ;
71- }
72- return layer ;
90+ setWMSData ( {
91+ metadata : data ,
92+ layers : datasetMetadata . layers ,
93+ version : datasetMetadata . version
7394 } ) ;
74-
75- if ( Array . isArray ( layers ) ) {
76- const layerOptions = layers . map ( ( layer : any ) => ( {
77- name : layer . name ,
78- title : layer . title || layer . name ,
79- boundingBox : layer . geographicBoundingBox
80- } ) ) ;
81- setAvailableLayers ( layerOptions ) ;
82- } else {
83- setAvailableLayers ( [ ] ) ;
84- }
85-
86- // Set WMS version
87- const version = data . version || '1.3.0' ;
88- setWmsVersion ( version ) ;
89-
90- setMetadata ( data ) ;
9195 } catch ( err ) {
9296 setError ( err instanceof Error ? err : new Error ( 'Unknown error' ) ) ;
93- setMetadata ( null ) ;
97+ setWMSData ( null ) ;
9498 } finally {
9599 setLoading ( false ) ;
96100 }
@@ -108,12 +112,12 @@ const TilesetWMSForm: React.FC<WMSTileFormProps> = ({setResponse}) => {
108112 remoteTileFormat : RemoteTileFormat . WMS ,
109113 tilesetDataUrl : wmsUrl ,
110114 tilesetMetadataUrl : `${ wmsUrl } ?service=WMS&request=GetCapabilities` ,
111- layers : availableLayers ,
112- wmsVersion : wmsVersion
115+ layers : wmsData ?. layers || [ ] ,
116+ wmsVersion : wmsData ?. version || '1.3.0'
113117 }
114118 } ;
115119 setResponse ( {
116- metadata,
120+ metadata : wmsData ?. metadata ?? null ,
117121 dataset,
118122 loading,
119123 error
@@ -126,7 +130,7 @@ const TilesetWMSForm: React.FC<WMSTileFormProps> = ({setResponse}) => {
126130 error
127131 } ) ;
128132 }
129- } , [ setResponse , layerName , wmsUrl , metadata , loading , error , availableLayers , wmsVersion ] ) ;
133+ } , [ setResponse , layerName , wmsUrl , wmsData , loading , error ] ) ;
130134
131135 return (
132136 < TilesetInputContainer >
@@ -149,6 +153,18 @@ const TilesetWMSForm: React.FC<WMSTileFormProps> = ({setResponse}) => {
149153 />
150154 < TilesetInputDescription > Provide a valid WMS service URL.</ TilesetInputDescription >
151155 </ div >
156+ < div >
157+ < TilesetInputDescription > For example, try a public WMS URL:</ TilesetInputDescription >
158+ < ExampleUrlsContainer >
159+ < div className = "example-url" > • https://ows.terrestris.de/osm/service</ div >
160+ < div className = "example-url" >
161+ • https://opengeo.ncep.noaa.gov/geoserver/conus/conus_cref_qcd/ows
162+ </ div >
163+ < div className = "example-url" >
164+ • https://gibs.earthdata.nasa.gov/wms/epsg4326/best/wms.cgi
165+ </ div >
166+ </ ExampleUrlsContainer >
167+ </ div >
152168 </ TilesetInputContainer >
153169 ) ;
154170} ;
0 commit comments