1- const ajax = ( endpoint , callback , data = null ) => {
1+ const ajax = ( endpoint , callback , data = null , send_json = true ) => {
22 let url = window . location . href ;
33 url += url . includes ( '?' ) ? '&' : '?' ;
44 url += ! url . includes ( 'dashboard=' ) ? `dashboard=${ document . body . dataset . dashboard } &` : '' ;
@@ -8,12 +8,17 @@ const ajax = (endpoint, callback, data = null) => {
88
99 if ( data !== null ) {
1010 request . setRequestHeader ( 'Content-type' , 'application/x-www-form-urlencoded' ) ;
11- data = `${ endpoint } =${ JSON . stringify ( data ) } ` ;
11+
12+ if ( send_json ) {
13+ data = `${ endpoint } =${ JSON . stringify ( data ) } ` ;
14+ } else {
15+ data = Object . keys ( data ) . map ( key => encodeURIComponent ( key ) + '=' + encodeURIComponent ( data [ key ] ) ) . join ( '&' ) ;
16+ }
1217 }
1318
1419 request . onload = callback ;
1520 request . send ( data ) ;
16- }
21+ } ;
1722
1823const query_params = ( params ) => {
1924 const url = new URL ( location . href ) ;
@@ -31,7 +36,7 @@ const query_params = (params) => {
3136
3237 url . search = search_params . toString ( ) ;
3338 location . href = url . toString ( ) ;
34- }
39+ } ;
3540
3641const select_and_redirect = ( id , param ) => {
3742 const select = document . getElementById ( id ) ;
@@ -41,7 +46,7 @@ const select_and_redirect = (id, param) => {
4146 query_params ( { [ param ] : e . target . value } ) ;
4247 } ) ;
4348 }
44- }
49+ } ;
4550
4651/**
4752 * Keys
@@ -179,7 +184,7 @@ const update_progress_bar = (progress_element, percentage) => {
179184 progress_element . classList . remove ( 'bg-red-600' , 'bg-orange-600' , 'bg-green-600' ) ;
180185 progress_element . classList . add ( color_class ) ;
181186 progress_element . style . width = percentage + '%' ;
182- }
187+ } ;
183188
184189const update_panel_data = ( panel_element , key , value ) => {
185190 const element = panel_element . querySelector ( `[data-value="${ key } "]` ) ;
@@ -195,7 +200,7 @@ const update_panel_data = (panel_element, key, value) => {
195200 } else {
196201 element . textContent = value ;
197202 }
198- }
203+ } ;
199204
200205const refresh_panels = ( ) => {
201206 ajax ( 'panels' , function ( request ) {
@@ -216,7 +221,7 @@ const refresh_panels = () => {
216221 console . error ( 'Error fetching panel data.' ) ;
217222 }
218223 } ) ;
219- }
224+ } ;
220225
221226document . addEventListener ( 'DOMContentLoaded' , function ( ) {
222227 if ( ajax_panels ) {
@@ -253,7 +258,7 @@ const json_syntax_highlight = (json) => {
253258 }
254259 }
255260 ) ;
256- }
261+ } ;
257262
258263document . querySelectorAll ( '.json-code' ) . forEach ( value => {
259264 value . innerHTML = json_syntax_highlight ( value . textContent ) ;
@@ -333,7 +338,6 @@ if (treeview) {
333338 } ) ;
334339
335340 function toggle_folder ( button , show = null ) {
336- // Find the next sibling that contains the children
337341 const children = button . closest ( 'div' ) . parentElement . querySelector ( '.tree-children' ) ;
338342 if ( ! children ) return false ;
339343
@@ -346,7 +350,6 @@ if (treeview) {
346350 return will_show ;
347351 }
348352
349- // Handle folder toggling
350353 treeview . addEventListener ( 'click' , function ( e ) {
351354 const toggle_btn = e . target . closest ( '.tree-toggle' ) ;
352355 if ( toggle_btn ) {
@@ -463,10 +466,6 @@ class Modal {
463466 this . close_buttons = element . querySelectorAll ( '[data-modal-dismiss]' ) ;
464467 this . backdrop = element . querySelector ( '.modal-backdrop' ) ;
465468
466- this . init ( ) ;
467- }
468-
469- init ( ) {
470469 this . open_buttons . forEach ( btn => {
471470 btn . addEventListener ( 'click' , ( ) => this . open ( ) ) ;
472471 } ) ;
@@ -492,9 +491,100 @@ class Modal {
492491
493492 escapeHandler = ( event ) => {
494493 if ( event . key === 'Escape' ) this . close ( ) ;
495- }
494+ } ;
496495}
497496
498497document . addEventListener ( 'DOMContentLoaded' , ( ) => {
499498 document . querySelectorAll ( '.modal' ) . forEach ( modal => new Modal ( modal ) ) ;
500499} ) ;
500+
501+ /**
502+ * Charts
503+ */
504+ const time_switcher = ( callback ) => {
505+ const default_btn_classes = [ 'hover:text-gray-600' , 'dark:hover:text-gray-300' ] ;
506+ const active_btn_classes = [ 'shadow-sm' , 'bg-white' , 'dark:bg-gray-700' ] ;
507+
508+ const time_buttons = document . querySelectorAll ( '[data-tab]' ) ;
509+ time_buttons . forEach ( button => {
510+ button . addEventListener ( 'click' , ( ) => {
511+ time_buttons . forEach ( btn => {
512+ btn . classList . remove ( ...active_btn_classes ) ;
513+ btn . classList . add ( ...default_btn_classes ) ;
514+ } ) ;
515+ button . classList . remove ( ...default_btn_classes ) ;
516+ button . classList . add ( ...active_btn_classes ) ;
517+
518+ metrics_active_filter = parseInt ( button . dataset . tab , 10 ) ;
519+ callback ( ) ;
520+ } ) ;
521+ } ) ;
522+ } ;
523+
524+ const charts_theme = ( chart_config , callback ) => {
525+ window . addEventListener ( 'resize' , ( ) => {
526+ for ( const chart of Object . values ( chart_config ) ) {
527+ chart . resize ( ) ;
528+ }
529+ } ) ;
530+
531+ const theme_observer = new MutationObserver ( ( mutations_list ) => {
532+ for ( const mutation of mutations_list ) {
533+ if ( mutation . type === 'attributes' && mutation . attributeName === 'class' ) {
534+ const theme = document . documentElement . classList . contains ( 'dark' ) ? 'dark' : null ;
535+
536+ for ( const key of Object . keys ( chart_config ) ) {
537+ chart_config [ key ] . dispose ( ) ;
538+ const chart_element = document . getElementById ( `${ key } _chart` ) ;
539+ chart_config [ key ] = echarts . init ( chart_element , theme , { renderer : 'svg' } ) ;
540+ }
541+
542+ callback ( ) ;
543+ break ;
544+ }
545+ }
546+ } ) ;
547+
548+ theme_observer . observe ( document . documentElement , { attributes : true } ) ;
549+ } ;
550+
551+ const fetch_metrics = ( callback ) => {
552+ ajax ( 'metrics' , function ( request ) {
553+ if ( request . currentTarget . status >= 200 && request . currentTarget . status < 400 ) {
554+ const content_type = request . currentTarget . getResponseHeader ( 'content-type' ) ;
555+ const response_text = request . currentTarget . responseText ;
556+
557+ if ( content_type && content_type . includes ( 'application/json' ) ) {
558+ callback ( JSON . parse ( response_text ) ) ;
559+ document . getElementById ( 'alerts' ) . innerHTML = '' ;
560+ } else {
561+ document . getElementById ( 'alerts' ) . innerHTML = response_text ;
562+ }
563+ } else {
564+ document . getElementById ( 'alerts' ) . innerHTML = `Server responded with status ${ request . status } ` ;
565+ }
566+ } , { points : metrics_active_filter } , false ) ;
567+ } ;
568+
569+ const init_metrics = ( render_charts , chart_config ) => {
570+ let full_data = [ ] ;
571+
572+ const update_page_charts = ( ) => {
573+ fetch_metrics ( ( data ) => {
574+ full_data = data ;
575+ render_charts ( full_data ) ;
576+ } ) ;
577+ } ;
578+
579+ time_switcher ( update_page_charts ) ;
580+
581+ charts_theme ( chart_config , function ( ) {
582+ if ( full_data && full_data . length > 0 ) {
583+ render_charts ( full_data ) ;
584+ }
585+ } ) ;
586+
587+ update_page_charts ( ) ;
588+
589+ setInterval ( update_page_charts , metrics_refresh_interval ) ;
590+ } ;
0 commit comments