@@ -106,7 +106,7 @@ const App: React.FC = () => {
106106
107107 async function handleDisconnect ( ) {
108108 await clearStoredApiKey ( ) ;
109- setProfile ( null ) ;
109+ setIsPaid ( false ) ;
110110 setView ( 'disconnected' ) ;
111111 setMessage ( 'Disconnected. Enter your API key to reconnect.' ) ;
112112 }
@@ -187,10 +187,17 @@ const App: React.FC = () => {
187187 fetchSeries ( { seriesId, mode : 'meta' , apiKey : key } )
188188 ] ) ;
189189
190+ // Check if this is a metadata-only dataset
191+ const isMetadataOnly = latestRes . response ?. status === 'metadata_only' ;
192+ const isPending = latestRes . response ?. status === 'ingestion_pending' ;
193+
190194 setPreviewData ( {
191195 latest : latestRes . response ?. scalar ,
192196 meta : metaRes . response ?. meta ,
193- error : latestRes . error || metaRes . error
197+ error : latestRes . error || metaRes . error ,
198+ isMetadataOnly,
199+ isPending,
200+ statusMessage : latestRes . response ?. message
194201 } ) ;
195202 setMessage ( '' ) ;
196203 } catch ( err : any ) {
@@ -199,6 +206,50 @@ const App: React.FC = () => {
199206 }
200207 }
201208
209+ async function requestFullIngestion ( seriesId : string ) {
210+ setMessage ( 'Requesting full dataset ingestion...' ) ;
211+ const { key } = await getStoredApiKey ( ) ;
212+
213+ try {
214+ const response = await fetch ( `https://www.datasetiq.com/api/datasets/${ seriesId } /fetch` , {
215+ method : 'POST' ,
216+ headers : {
217+ 'Content-Type' : 'application/json' ,
218+ ...( key ? { 'Authorization' : `Bearer ${ key } ` } : { } )
219+ }
220+ } ) ;
221+
222+ const data = await response . json ( ) ;
223+
224+ if ( response . status === 401 || data . requiresAuth ) {
225+ setMessage ( '⚠️ Authentication required. Visit datasetiq.com to sign up for full data access.' ) ;
226+ return ;
227+ }
228+
229+ if ( response . status === 429 || data . upgradeToPro ) {
230+ setMessage ( `⚠️ Monthly limit reached (${ data . remaining || 0 } /${ data . limit || 100 } ). Upgrade to Pro for unlimited access.` ) ;
231+ return ;
232+ }
233+
234+ if ( ! response . ok ) {
235+ setMessage ( `⚠️ ${ data . error || 'Failed to queue ingestion' } ` ) ;
236+ return ;
237+ }
238+
239+ setMessage ( '✅ Dataset ingestion started! Data will be available in 1-2 minutes.' ) ;
240+
241+ // Update preview to show pending status
242+ setPreviewData ( prev => ( {
243+ ...prev ,
244+ isPending : true ,
245+ statusMessage : 'Dataset ingestion queued. Full data will be available shortly.'
246+ } ) ) ;
247+
248+ } catch ( err : any ) {
249+ setMessage ( `⚠️ ${ err . message || 'Failed to request ingestion' } ` ) ;
250+ }
251+ }
252+
202253 function checkPremiumAccess ( feature : string ) : boolean {
203254 // Note: Premium plan detection not available from public API
204255 // All users have access to basic features only
@@ -482,16 +533,16 @@ const App: React.FC = () => {
482533 < button
483534 className = { `tab premium-tab ${ activeTab === 'builder' ? 'active' : '' } ` }
484535 onClick = { openBuilder }
485- title = { isPaidPlan ( profile ?. plan ) ? 'Formula Builder' : 'Premium Feature' }
536+ title = { isPaid ? 'Formula Builder' : 'Premium Feature' }
486537 >
487- 🔧 Builder { ! isPaidPlan ( profile ?. plan ) && '🔒' }
538+ 🔧 Builder { ! isPaid && '🔒' }
488539 </ button >
489540 < button
490541 className = { `tab premium-tab ${ activeTab === 'templates' ? 'active' : '' } ` }
491542 onClick = { openTemplates }
492- title = { isPaidPlan ( profile ?. plan ) ? 'Templates' : 'Premium Feature' }
543+ title = { isPaid ? 'Templates' : 'Premium Feature' }
493544 >
494- 📁 Templates { ! isPaidPlan ( profile ?. plan ) && '🔒' }
545+ 📁 Templates { ! isPaid && '🔒' }
495546 </ button >
496547 </ div >
497548
@@ -512,7 +563,7 @@ const App: React.FC = () => {
512563 { results . length === 0 && < div className = "muted" > No results yet.</ div > }
513564 { results . length > 0 && (
514565 < >
515- { isPaidPlan ( profile ?. plan ) && (
566+ { isPaid && (
516567 < div style = { { marginBottom : '12px' , padding : '8px' , background : '#f0f9ff' , borderRadius : '6px' } } >
517568 < label style = { { display : 'flex' , alignItems : 'center' , gap : '6px' , fontSize : '13px' } } >
518569 < input type = "checkbox" onChange = { ( e ) => {
@@ -534,7 +585,7 @@ const App: React.FC = () => {
534585 < ul >
535586 { results . map ( ( r ) => (
536587 < li key = { r . id } className = "result-item" >
537- { isPaidPlan ( profile ?. plan ) && (
588+ { isPaid && (
538589 < input
539590 type = "checkbox"
540591 checked = { selectedForInsert . includes ( r . id ) }
@@ -882,12 +933,38 @@ const App: React.FC = () => {
882933 ) }
883934 { previewData && ! previewData . error && (
884935 < div className = "preview-body" >
936+ { /* Metadata-only notice */ }
937+ { previewData . isMetadataOnly && (
938+ < div style = { { marginBottom : '12px' , padding : '10px' , background : '#fef3c7' , borderRadius : '6px' , border : '1px solid #fbbf24' } } >
939+ < strong style = { { color : '#92400e' , display : 'block' , marginBottom : '4px' } } > 📊 Metadata Only</ strong >
940+ < p style = { { fontSize : '12px' , color : '#78350f' , margin : 0 } } >
941+ This dataset hasn't been fully ingested yet. Click below to fetch the complete time-series data.
942+ </ p >
943+ < button
944+ onClick = { ( ) => requestFullIngestion ( previewSeries ! ) }
945+ style = { { marginTop : '8px' , width : '100%' , padding : '8px' , background : '#f59e0b' , color : '#fff' , border : 'none' , borderRadius : '6px' , fontWeight : '600' , cursor : 'pointer' } }
946+ >
947+ 🚀 Fetch Full Dataset
948+ </ button >
949+ </ div >
950+ ) }
951+
952+ { /* Ingestion pending notice */ }
953+ { previewData . isPending && (
954+ < div style = { { marginBottom : '12px' , padding : '10px' , background : '#dbeafe' , borderRadius : '6px' , border : '1px solid ' #3 b82f6 '} } >
955+ < strong style = { { color : '#1e3a8a' , display : 'block' , marginBottom : '4px' } } > ⏳ Ingestion In Progress</ strong >
956+ < p style = { { fontSize : '12px' , color : '#1e40af' , margin : 0 } } >
957+ { previewData . statusMessage || 'Full dataset is being fetched. This usually takes 1-2 minutes. Please check back shortly.' }
958+ </ p >
959+ </ div >
960+ ) }
961+
885962 < div className = "preview-item" >
886963 < strong > Latest Value:</ strong > { previewData . latest ?? 'N/A' }
887- < button className = "copy-btn" onClick = { ( ) => navigator . clipboard . writeText ( String ( previewData . latest ) ) } title = "Copy" > 📋</ button >
964+ { previewData . latest && < button className = "copy-btn" onClick = { ( ) => navigator . clipboard . writeText ( String ( previewData . latest ) ) } title = "Copy" > 📋</ button > }
888965 </ div >
889966
890- { isPaidPlan ( profile ?. plan ) && previewData . meta && (
967+ { isPaid && previewData . meta && (
891968 < >
892969 < div className = "premium-badge" style = { { marginTop : '12px' , marginBottom : '8px' } } > ✨ Full Metadata (Premium)</ div >
893970 { Object . entries ( previewData . meta ) . map ( ( [ key , value ] ) => (
@@ -899,7 +976,7 @@ const App: React.FC = () => {
899976 </ >
900977 ) }
901978
902- { ! isPaidPlan ( profile ?. plan ) && previewData . meta && (
979+ { ! isPaid && previewData . meta && (
903980 < >
904981 { previewData . meta ?. title && (
905982 < div className = "preview-item" >
0 commit comments