@@ -155,6 +155,58 @@ <h3 class="card-title"><i class="fas fa-database"></i> Backend Configuration</h3
155155
156156 <!-- Detect tables results area (hidden by default) -->
157157 < div id ="detect-tables-results " class ="d-none " style ="margin-top: 1rem; "> </ div >
158+
159+ <!-- Switch Backend -->
160+ < div style ="margin-top: 1.5rem; border-top: 1px solid var(--color-gray-600); padding-top: 1rem; ">
161+ < h4 style ="margin-bottom: 0.75rem; cursor: pointer; " onclick ="document.getElementById('switch-backend-form').classList.toggle('d-none') ">
162+ < i class ="fas fa-exchange-alt "> </ i > Switch Backend
163+ < small class ="text-muted " style ="font-weight: 400; font-size: 0.75rem; margin-left: 0.5rem; "> click to expand</ small >
164+ </ h4 >
165+
166+ < div id ="switch-backend-form " class ="d-none ">
167+ <!-- Session-only warning -->
168+ < div style ="padding: 0.6rem 0.9rem; margin-bottom: 1rem; background: rgba(245,158,11,0.1); border: 1px solid var(--color-warning); border-radius: var(--radius-sm); color: var(--color-warning); font-size: 0.85rem; ">
169+ < i class ="fas fa-exclamation-triangle "> </ i > < strong > Session-only</ strong > : Switching backend affects only this running server. To persist, set environment variables before restarting.
170+ </ div >
171+
172+ < div class ="form-group mb-md ">
173+ < label for ="switch-backend-type " style ="font-size: 0.875rem; font-weight: 500; margin-bottom: 0.25rem; display: block; "> Backend Type</ label >
174+ < select id ="switch-backend-type " style ="width: 100%; padding: 0.5rem 0.75rem; background: var(--color-gray-700); border: 1px solid var(--color-gray-600); border-radius: var(--radius-sm); color: var(--color-gray-200); font-size: 0.875rem; " onchange ="toggleDynamoFields() ">
175+ < option value ="local " {% if not backend_info or backend_info.backend_type ! = 'dynamodb ' %}selected{% endif %} > Local (filesystem)</ option >
176+ < option value ="dynamodb " {% if backend_info and backend_info.backend_type == 'dynamodb ' %}selected{% endif %} > DynamoDB (AWS)</ option >
177+ </ select >
178+ </ div >
179+
180+ < div id ="dynamo-fields " class ="{% if not backend_info or backend_info.backend_type != 'dynamodb' %}d-none{% endif %} ">
181+ < div class ="grid grid-2 " style ="gap: 0.75rem; margin-bottom: 0.75rem; ">
182+ < div class ="form-group ">
183+ < label for ="switch-table " style ="font-size: 0.8rem; font-weight: 500; display: block; margin-bottom: 0.2rem; "> Table Name</ label >
184+ < input id ="switch-table " type ="text " value ="{{ backend_info.dynamo_table if backend_info and backend_info.backend_type == 'dynamodb' else 'zebra-day-config' }} " placeholder ="zebra-day-config " style ="width: 100%; padding: 0.5rem 0.75rem; background: var(--color-gray-700); border: 1px solid var(--color-gray-600); border-radius: var(--radius-sm); color: var(--color-gray-200); font-size: 0.875rem; ">
185+ </ div >
186+ < div class ="form-group ">
187+ < label for ="switch-region " style ="font-size: 0.8rem; font-weight: 500; display: block; margin-bottom: 0.2rem; "> Region</ label >
188+ < input id ="switch-region " type ="text " value ="{{ backend_info.aws_region if backend_info and backend_info.backend_type == 'dynamodb' else 'us-east-1' }} " placeholder ="us-east-1 " style ="width: 100%; padding: 0.5rem 0.75rem; background: var(--color-gray-700); border: 1px solid var(--color-gray-600); border-radius: var(--radius-sm); color: var(--color-gray-200); font-size: 0.875rem; ">
189+ </ div >
190+ < div class ="form-group ">
191+ < label for ="switch-s3-bucket " style ="font-size: 0.8rem; font-weight: 500; display: block; margin-bottom: 0.2rem; "> S3 Bucket < span style ="color: var(--color-error); "> *</ span > </ label >
192+ < input id ="switch-s3-bucket " type ="text " value ="{{ backend_info.s3_bucket if backend_info and backend_info.backend_type == 'dynamodb' else '' }} " placeholder ="my-zebra-backups " style ="width: 100%; padding: 0.5rem 0.75rem; background: var(--color-gray-700); border: 1px solid var(--color-gray-600); border-radius: var(--radius-sm); color: var(--color-gray-200); font-size: 0.875rem; ">
193+ </ div >
194+ < div class ="form-group ">
195+ < label for ="switch-s3-prefix " style ="font-size: 0.8rem; font-weight: 500; display: block; margin-bottom: 0.2rem; "> S3 Prefix</ label >
196+ < input id ="switch-s3-prefix " type ="text " value ="{{ backend_info.s3_prefix if backend_info and backend_info.backend_type == 'dynamodb' else 'zebra-day/' }} " placeholder ="zebra-day/ " style ="width: 100%; padding: 0.5rem 0.75rem; background: var(--color-gray-700); border: 1px solid var(--color-gray-600); border-radius: var(--radius-sm); color: var(--color-gray-200); font-size: 0.875rem; ">
197+ </ div >
198+ </ div >
199+ < div class ="form-group " style ="margin-bottom: 0.75rem; ">
200+ < label for ="switch-profile " style ="font-size: 0.8rem; font-weight: 500; display: block; margin-bottom: 0.2rem; "> AWS Profile < small class ="text-muted "> (optional)</ small > </ label >
201+ < input id ="switch-profile " type ="text " value ="" placeholder ="Leave empty for default credential chain " style ="width: 100%; padding: 0.5rem 0.75rem; background: var(--color-gray-700); border: 1px solid var(--color-gray-600); border-radius: var(--radius-sm); color: var(--color-gray-200); font-size: 0.875rem; ">
202+ </ div >
203+ </ div >
204+
205+ < button class ="btn btn-primary " onclick ="switchBackend() " id ="btn-switch-backend ">
206+ < i class ="fas fa-plug "> </ i > Connect
207+ </ button >
208+ </ div >
209+ </ div >
158210</ div >
159211
160212<!-- Current Config Summary -->
@@ -284,5 +336,53 @@ <h4 class="mb-md">Configured Labs</h4>
284336 if ( btn ) { btn . disabled = false ; btn . innerHTML = '<i class="fas fa-search"></i> Detect Tables' ; }
285337 }
286338}
339+
340+ function toggleDynamoFields ( ) {
341+ const sel = document . getElementById ( 'switch-backend-type' ) ;
342+ const fields = document . getElementById ( 'dynamo-fields' ) ;
343+ if ( sel && fields ) {
344+ if ( sel . value === 'dynamodb' ) { fields . classList . remove ( 'd-none' ) ; }
345+ else { fields . classList . add ( 'd-none' ) ; }
346+ }
347+ }
348+
349+ async function switchBackend ( ) {
350+ const btn = document . getElementById ( 'btn-switch-backend' ) ;
351+ const backendType = document . getElementById ( 'switch-backend-type' ) . value ;
352+ const payload = { backend_type : backendType } ;
353+ if ( backendType === 'dynamodb' ) {
354+ payload . table_name = document . getElementById ( 'switch-table' ) . value . trim ( ) || 'zebra-day-config' ;
355+ payload . region = document . getElementById ( 'switch-region' ) . value . trim ( ) || 'us-east-1' ;
356+ payload . s3_bucket = document . getElementById ( 'switch-s3-bucket' ) . value . trim ( ) ;
357+ payload . s3_prefix = document . getElementById ( 'switch-s3-prefix' ) . value . trim ( ) || 'zebra-day/' ;
358+ payload . profile = document . getElementById ( 'switch-profile' ) . value . trim ( ) ;
359+ if ( ! payload . s3_bucket ) {
360+ showToast ( 'error' , 'Validation Error' , 'S3 Bucket is required for DynamoDB backend.' ) ;
361+ return ;
362+ }
363+ }
364+ if ( btn ) { btn . disabled = true ; btn . innerHTML = '<i class="fas fa-spinner fa-spin"></i> Connecting...' ; }
365+ showLoading ( 'Switching backend...' ) ;
366+ try {
367+ const resp = await fetch ( '/api/v1/config/switch-backend' , {
368+ method : 'POST' ,
369+ headers : { 'Content-Type' : 'application/json' } ,
370+ body : JSON . stringify ( payload ) ,
371+ } ) ;
372+ const data = await resp . json ( ) ;
373+ hideLoading ( ) ;
374+ if ( resp . ok && data . success ) {
375+ showToast ( 'success' , 'Backend Switched' , data . message || 'Backend switched successfully.' ) ;
376+ setTimeout ( ( ) => window . location . reload ( ) , 1000 ) ;
377+ } else {
378+ showToast ( 'error' , 'Switch Failed' , data . detail || 'Unknown error' ) ;
379+ }
380+ } catch ( e ) {
381+ hideLoading ( ) ;
382+ showToast ( 'error' , 'Switch Failed' , e . message || 'Network error' ) ;
383+ } finally {
384+ if ( btn ) { btn . disabled = false ; btn . innerHTML = '<i class="fas fa-plug"></i> Connect' ; }
385+ }
386+ }
287387</ script >
288388{% endblock %}
0 commit comments