github.com/siglens/siglens@v0.0.0-20240328180423-f7ce9ae441ed/static/js/dashboards-home.js (about)

     1  /*
     2  Copyright 2023.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  
    18  'use strict';
    19  
    20  let dbgridDiv = null;
    21  let dbRowData = [];
    22  
    23  async function getAllDashboards() {
    24  	let serverResponse = []
    25  	await $.ajax({
    26  		method: 'get',
    27  		url: 'api/dashboards/listall',
    28  		headers: {
    29  			'Content-Type': 'application/json; charset=utf-8',
    30  			'Accept': '*/*'
    31  		},
    32  		crossDomain: true,
    33  		dataType: 'json',
    34  	}).then(function (res) {
    35  		serverResponse = res;
    36  	})
    37  	return serverResponse
    38  }
    39  
    40  async function getAllDefaultDashboards() {
    41  	let serverResponse = []
    42  	await $.ajax({
    43  		method: 'get',
    44  		url: 'api/dashboards/defaultlistall',
    45  		headers: {
    46  			'Content-Type': 'application/json; charset=utf-8',
    47  			'Accept': '*/*'
    48  		},
    49  		crossDomain: true,
    50  		dataType: 'json',
    51  	}).then(function (res) {
    52  		serverResponse = res;
    53  	})
    54  	return serverResponse
    55  }
    56  async function getAllFavoriteDashboards() {
    57      let serverResponse = []
    58      await $.ajax({
    59          method: 'get',
    60          url: 'api/dashboards/listfavorites',
    61          headers: {
    62              'Content-Type': 'application/json; charset=utf-8',
    63              'Accept': '*/*'
    64          },
    65          crossDomain: true,
    66          dataType: 'json',
    67      }).then(function (res) {
    68  		serverResponse = res;
    69      })
    70      return serverResponse
    71  }
    72  
    73  function createDashboard() {
    74  	$('.popupOverlay, .popupContent').addClass('active');
    75  	$('#new-dashboard-modal').show();
    76  	$('#delete-db-prompt').hide();
    77    
    78  	function createDashboardWithInput() {
    79  	  var inputdbname = $("#db-name").val();
    80  	  var inputdbdescription = $("#db-description").val();
    81  	  var timeRange = "Last 1 Hour";
    82  	  var refresh = "";
    83    
    84  	  if (!inputdbname) {
    85  		$('.error-tip').addClass('active');
    86  		$('.popupOverlay, .popupContent').addClass('active');
    87  		$('#new-dashboard-modal').show();
    88  	  } else {
    89  		$('#save-dbbtn').off('click');
    90  		$(document).off('keypress');
    91  		
    92  		$.ajax({
    93  		  method: "post",
    94  		  url: "api/dashboards/create",
    95  		  headers: {
    96  			'Content-Type': 'application/json; charset=utf-8',
    97  			'Accept': '*/*'
    98  		  },
    99  		  data: JSON.stringify(inputdbname),
   100  		  dataType: 'json',
   101  		  crossDomain: true,
   102  		}).then(function (res) {
   103  		  $("#db-name").val("");
   104  		  $("#db-description").val("");
   105  		  $('.error-tip').removeClass('active');
   106  		  $('.popupOverlay, .popupContent').removeClass('active');
   107    
   108  		  var updateDashboard = {
   109  			"id": Object.keys(res)[0],
   110  			"name": Object.values(res)[0],
   111  			"details": {
   112  			  "name": Object.values(res)[0],
   113  			  "description": inputdbdescription,
   114  			  "timeRange": timeRange,
   115  			  "refresh": refresh,
   116  			}
   117  		  }
   118    
   119  		  $.ajax({
   120  			method: "post",
   121  			url: "api/dashboards/update",
   122  			headers: {
   123  			  'Content-Type': 'application/json; charset=utf-8',
   124  			  'Accept': '*/*'
   125  			},
   126  			data: JSON.stringify(updateDashboard),
   127  			dataType: 'json',
   128  			crossDomain: true,
   129  		  }).then(function (msg) {
   130  			console.log("done:", msg)
   131  		  })
   132    
   133  		  var queryString = "?id=" + Object.keys(res)[0];
   134  		  window.location.href = "../dashboard.html" + queryString;
   135  		}).catch(function (updateError) {
   136  			if (updateError.status === 409) {
   137  				$('.error-tip').text('Dashboard name already exists!');
   138  				$('.error-tip').addClass('active');
   139  				$('.popupOverlay, .popupContent').addClass('active');
   140  				attachEventHandlers();
   141  			}
   142  		  });
   143  	  }
   144  	}
   145  	// method to attach event handlers to avoid redundant event handlers
   146  	function attachEventHandlers() {
   147  		$('#save-dbbtn').on('click', function () {
   148  			createDashboardWithInput();
   149  		});
   150  
   151  		$(document).on('keypress', function(event){
   152  			if(event.keyCode == '13'){
   153  				event.preventDefault();
   154  				createDashboardWithInput();
   155  			}
   156  		});
   157  
   158  		$('#cancel-dbbtn, .popupOverlay').on('click', function () {
   159  			$("#db-name").val("");
   160  			$("#db-description").val("");		
   161  			$('.popupOverlay, .popupContent').removeClass('active');
   162  			$('.error-tip').removeClass('active');
   163  		});
   164  	}
   165  
   166  	// Attach event handlers initially
   167  	attachEventHandlers();
   168  }
   169  
   170  function createSiglensDashboard(inputdbname) {
   171  	var inputdbdescription = "A pre-created Dashboard to monitor the cluster";
   172  	var timeRange = "Last 1 Hour"
   173  
   174  	$.ajax({
   175  		method: "post",
   176  		url: "api/dashboards/create",
   177  		headers: {
   178  			'Content-Type': 'application/json; charset=utf-8',
   179  			'Accept': '*/*'
   180  		},
   181  		data: JSON.stringify(inputdbname),
   182  		dataType: 'json',
   183  		crossDomain: true,
   184  	}).then(function (res) {
   185  		var updateDashboard = {
   186  			"id": Object.keys(res)[0],
   187  			"name": Object.values(res)[0],
   188  			"details": {
   189  				"name": Object.values(res)[0],
   190  				"description": inputdbdescription,
   191  				"timeRange": timeRange,
   192  			}
   193  		}
   194  		$.ajax({
   195  			method: "post",
   196  			url: "api/dashboards/update",
   197  			headers: {
   198  				'Content-Type': 'application/json; charset=utf-8',
   199  				'Accept': '*/*'
   200  			},
   201  			data: JSON.stringify(updateDashboard),
   202  			dataType: 'json',
   203  			crossDomain: true,
   204  		}).then(function (msg) {
   205  			console.log("done:", msg)
   206  		})
   207  	});
   208  }
   209  
   210  class btnRenderer {
   211      init(params) {
   212  		const starOutlineURL = 'url("../assets/star-outline.svg")';
   213          const starFilledURL = 'url("../assets/star-filled.svg")';
   214  
   215          this.eGui = document.createElement('span');
   216          this.eGui.innerHTML = `<div id="dashboard-grid-btn">
   217               
   218                  <button class='btn' id="viewbutton" title="Open dashboard"></button>
   219                  <button class="btn-simple" id="delbutton" title="Delete dashboard"></button>
   220                  <button class="btn-duplicate" id="duplicateButton" title="Duplicate dashboard"></button>
   221                  <button class="star-icon" id="favbutton" title="Mark as favorite" ></button>
   222                  </div>`;
   223          this.vButton = this.eGui.querySelector('.btn');
   224          this.dButton = this.eGui.querySelector('.btn-simple');
   225          this.duplicateButton = this.eGui.querySelector('.btn-duplicate');
   226          this.starIcon=this.eGui.querySelector('.star-icon');
   227          this.starIcon.style.backgroundImage = favoriteDBsSet.has(params.data.uniqId) ? starFilledURL : starOutlineURL;
   228  
   229  		let defaultDashboardIds = [
   230              "10329b95-47a8-48df-8b1d-0a0a01ec6c42",
   231              "a28f485c-4747-4024-bb6b-d230f101f852",
   232              "bd74f11e-26c8-4827-bf65-c0b464e1f2a4",
   233              "53cb3dde-fd78-4253-808c-18e4077ef0f1"
   234          ];
   235  
   236          if (defaultDashboardIds.includes(params.data.uniqId)) {
   237              this.dButton.disabled = true;
   238              this.dButton.title = "Delete disabled";
   239  			this.dButton.classList.add('default-dashboard-delete'); 
   240          }
   241  
   242          function view() {
   243              $.ajax({
   244                  method: 'get',
   245                  url: 'api/dashboards/' + params.data.uniqId,
   246                  headers: {
   247                      'Content-Type': 'application/json; charset=utf-8',
   248                      Accept: '*/*',
   249                  },
   250                  crossDomain: true,
   251                  dataType: 'json',
   252              }).then(function (res) {
   253                  var queryString = "?id=" + params.data.uniqId;
   254                  window.location.href = "../dashboard.html" + queryString;
   255              });
   256          }
   257  
   258          function deletedb() {
   259              $.ajax({
   260                  method: 'get',
   261                  url: 'api/dashboards/delete/' + params.data.uniqId,
   262                  headers: {
   263                      'Content-Type': 'application/json; charset=utf-8',
   264                      Accept: '*/*',
   265                  },
   266                  crossDomain: true,
   267              }).then(function () {
   268                  let deletedRowID = params.data.rowId;
   269                  dbgridOptions.api.applyTransaction({
   270                      remove: [{ rowId: deletedRowID }],
   271                  });
   272              });
   273          }
   274  
   275          function duplicatedb() {
   276              $.ajax({
   277                  method: 'get',
   278                  url: 'api/dashboards/' + params.data.uniqId,
   279                  headers: {
   280                      'Content-Type': 'application/json; charset=utf-8',
   281                      Accept: '*/*',
   282                  },
   283                  crossDomain: true,
   284                  dataType: 'json',
   285              }).then(function (res) {
   286                  let duplicatedDBName = res.name + "-Copy";
   287                  let duplicatedDescription = res.description;
   288                  let duplicatedPanels = res.panels;
   289                  let duplicateTimeRange = res.timeRange;
   290                  let duplicateRefresh = res.refresh;
   291                  let uniqIDdb;
   292                  $.ajax({
   293                      method: "post",
   294                      url: "api/dashboards/create",
   295                      headers: {
   296                          'Content-Type': 'application/json; charset=utf-8',
   297                          'Accept': '*/*'
   298                      },
   299                      data: JSON.stringify(duplicatedDBName),
   300                      dataType: 'json',
   301                      crossDomain: true,
   302                  }).then((res) => {
   303                      uniqIDdb = Object.keys(res)[0];
   304                      $.ajax(
   305                          {
   306                              method: 'POST',
   307                              url: '/api/dashboards/update',
   308                              data: JSON.stringify({
   309                                  "id": uniqIDdb,
   310                                  "name": duplicatedDBName,
   311                                  "details": {
   312                                      "name": duplicatedDBName,
   313                                      "description": duplicatedDescription,
   314                                      "panels": duplicatedPanels,
   315                                      "timeRange": duplicateTimeRange,
   316                                      "refresh": duplicateRefresh,
   317                                  }
   318                              })
   319                          }
   320                      )
   321                  }).then(function () {
   322                      dbgridOptions.api.applyTransaction({
   323                          add: [{
   324                              dbname: duplicatedDBName,
   325                              uniqId: uniqIDdb,
   326                          }],
   327                      });
   328                  })
   329              })
   330          }
   331  		function toggleFavorite() {
   332  			$.ajax({
   333  				method: 'put',
   334  				url: 'api/dashboards/favorite/' + params.data.uniqId,
   335  				headers: {
   336  					'Content-Type': 'application/json; charset=utf-8',
   337  					Accept: '*/*',
   338  				},
   339  				crossDomain: true,
   340  			}).then((response) => {
   341  				// Update the favorite status based on the response
   342  				params.data.favorite = response.isFavorite;
   343  				if(params.data.favorite) {
   344  					this.starIcon.style.backgroundImage = starFilledURL;
   345  				} else {
   346  					this.starIcon.style.backgroundImage = starOutlineURL;
   347  				}							
   348  			});
   349  		}
   350          function showPrompt() {
   351              $('#delete-db-prompt').css('display', 'flex');
   352              $('.popupOverlay, .popupContent').addClass('active');
   353              $('#new-dashboard-modal').hide();
   354  
   355              $('#cancel-db-prompt, .popupOverlay').click(function () {
   356                  $('.popupOverlay, .popupContent').removeClass('active');
   357                  $('#delete-db-prompt').hide();
   358              });
   359  
   360              $('#delete-dbbtn').click(function () {
   361                  deletedb();
   362                  $('.popupOverlay, .popupContent').removeClass('active');
   363                  $('#delete-db-prompt').hide();
   364              });
   365          }
   366  
   367          this.vButton.addEventListener('click', view);
   368          this.dButton.addEventListener('click', showPrompt);
   369          this.duplicateButton.addEventListener('click', duplicatedb);
   370          this.starIcon.addEventListener('click',toggleFavorite.bind(this));
   371      }
   372  
   373      getGui() {
   374          return this.eGui;
   375      }
   376      refresh(params) {
   377          // Use the URL of the SVG files for star icons
   378          const starOutlineURL = 'url("../assets/star-outline.svg")';
   379          const starFilledURL = 'url("../assets/star-filled.svg")';
   380  
   381          this.starIcon.style.backgroundImage = params.data.favorite ? starFilledURL : starOutlineURL;
   382          return false;
   383      }
   384  }
   385  
   386  let dashboardColumnDefs = [
   387  	{
   388  		field: "rowId",
   389  		hide: true
   390  	},
   391  	{
   392  		headerName: "Dashboard Name",
   393  		field: "dbname",
   394  		sortable: true,
   395  		cellClass: "",
   396  		cellRenderer: (params) => {
   397  			var link = document.createElement('a');
   398  			link.href = '#';
   399  			link.innerText = params.value;
   400  			link.addEventListener('click', (e) => {
   401  				e.preventDefault();
   402  				view()
   403  			});
   404  			return link;
   405  
   406  			function view() {
   407  				$.ajax({
   408  					method: 'get',
   409  					url: 'api/dashboards/' + params.data.uniqId,
   410  					headers: {
   411  						'Content-Type': 'application/json; charset=utf-8',
   412  						Accept: '*/*',
   413  					},
   414  					crossDomain: true,
   415  					dataType: 'json',
   416  				}).then(function (res) {
   417  					var queryString = "?id=" + params.data.uniqId;
   418  					window.location.href = "../dashboard.html" + queryString;
   419  				});
   420  			}
   421  		}
   422  
   423  	},
   424  	{
   425  		cellRenderer: btnRenderer,
   426  		width: 40,
   427  	},
   428  
   429  ];
   430  
   431  // let the grid know which columns and what data to use
   432  const dbgridOptions = {
   433  	columnDefs: dashboardColumnDefs,
   434  	rowData: dbRowData,
   435  	animateRows: true,
   436  	rowHeight: 54,
   437  	defaultColDef: {
   438  		icons: {
   439  			sortAscending: '<i class="fa fa-sort-alpha-up"/>',
   440  			sortDescending: '<i class="fa fa-sort-alpha-down"/>',
   441  		},
   442  	},
   443  	enableCellTextSelection: true,
   444  	suppressScrollOnNewData: true,
   445  	suppressAnimationFrame: true,
   446  	getRowId: (params) => params.data.rowId,
   447  	onGridReady(params) {
   448  		this.gridApi = params.api; // To access the grids API
   449  	},
   450  };
   451  
   452  
   453  function displayDashboards(res, flag) {
   454  	let favorites = [];
   455  	let nonFavorites = [];
   456  	
   457  	for (let [key, value] of Object.entries(res)) {
   458  		if (favoriteDBsSet.has(key)) {
   459  			favorites.push([key, value]);
   460  		} else {
   461  			nonFavorites.push([key, value]);
   462  		}
   463  	}
   464  	favorites.sort((a, b) => b[1].localeCompare(a[1]));
   465  	nonFavorites.sort((a, b) => b[1].localeCompare(a[1]));
   466  	let resArray = [...favorites, ...nonFavorites];
   467  	res = Object.fromEntries(resArray);
   468  	if (flag == -1) {
   469  		// show search results
   470  		let dbFilteredRowData = [];
   471  		if (dbgridDiv === null) {
   472  			dbgridDiv = document.querySelector('#dashboard-grid');
   473  			new agGrid.Grid(dbgridDiv, dbgridOptions);
   474  		}
   475  		dbgridOptions.api.setColumnDefs(dashboardColumnDefs);
   476  		let idx = 0;
   477  		let newRow = new Map()
   478  		$.each(res, function (key, value) {
   479  			newRow.set("rowId", idx)
   480  			newRow.set("uniqId", key)
   481  			newRow.set("dbname", value)
   482  
   483  			dbFilteredRowData = _.concat(dbFilteredRowData, Object.fromEntries(newRow));
   484  			idx = idx + 1;
   485  		})
   486  		dbgridOptions.api.setRowData(dbFilteredRowData);
   487  		dbgridOptions.api.sizeColumnsToFit();
   488  	} else {
   489  		if (dbgridDiv === null) {
   490  			dbgridDiv = document.querySelector('#dashboard-grid');
   491  			new agGrid.Grid(dbgridDiv, dbgridOptions);
   492  		}
   493  		dbgridOptions.api.setColumnDefs(dashboardColumnDefs);
   494  		let idx = 0;
   495  		let newRow = new Map()
   496  		$.each(res, function (key, value) {
   497  			newRow.set("rowId", idx)
   498  			newRow.set("uniqId", key)
   499  			newRow.set("dbname", value)
   500  
   501  			dbRowData = _.concat(dbRowData, Object.fromEntries(newRow));
   502  			idx = idx + 1;
   503  		})
   504  		dbgridOptions.api.setRowData(dbRowData);
   505  		dbgridOptions.api.sizeColumnsToFit();
   506  	}
   507  }
   508  
   509  function searchDB() {
   510  	let searchText = $('.search-db-input').val();
   511  	var tokens = searchText.toLowerCase()
   512  		.split(' ')
   513  		.filter(function (token) {
   514  			return token.trim() !== '';
   515  		});
   516  
   517  	let dbNames = [];
   518  	dbRowData.forEach(rowData => {
   519  		dbNames.push(rowData.dbname)
   520  	})
   521  
   522  	let dbFilteredRowsObject = {};
   523  	if (tokens.length) {
   524  		var searchTermRegex = new RegExp(tokens.join('|'), 'gi');
   525  		var filteredList = dbNames.filter(function (dbName, i) {
   526  			if (dbName.match(searchTermRegex)) {
   527  				let uniqIdDB = dbRowData[i].uniqId;
   528  				dbFilteredRowsObject[`${uniqIdDB}`] = dbRowData[i].dbname;
   529  			}
   530  			return dbName.match(searchTermRegex);
   531  		});
   532  
   533  		if (Object.keys(dbFilteredRowsObject).length === 0) {
   534  			displayDashboards(dbFilteredRowsObject, -1);
   535  			showDBNotFoundMsg();
   536  		} else {
   537  			$('#dashboard-grid-container').show();
   538  			$('#empty-response').hide();
   539  			displayDashboards(dbFilteredRowsObject, -1);
   540  		}
   541  	}
   542  }
   543  
   544  function displayOriginalDashboards() {
   545  	let searchText = $('.search-db-input').val();
   546  
   547  	if (searchText.length === 0) {
   548  		if (dbgridDiv === null) {
   549  			dbgridDiv = document.querySelector('#dashboard-grid');
   550  			new agGrid.Grid(dbgridDiv, dbgridOptions);
   551  		}
   552  		$('#dashboard-grid-container').show();
   553  		$('#empty-response').hide();
   554  		dbgridOptions.api.setColumnDefs(dashboardColumnDefs);
   555  		dbgridOptions.api.setRowData(dbRowData);
   556  		dbgridOptions.api.sizeColumnsToFit();
   557  	}
   558  }
   559  
   560  function showDBNotFoundMsg() {
   561  	$('#dashboard-grid-container').hide();
   562  	$('#empty-response').show();
   563  }
   564  let favoriteDBsSet;
   565  
   566  $(document).ready(async function () {
   567  	if (Cookies.get('theme')) {
   568  		theme = Cookies.get('theme');
   569  		$('body').attr('data-theme', theme);
   570  	}
   571  	$('.theme-btn').on('click', themePickerHandler);
   572  
   573  	let normalDBs = await getAllDashboards();
   574  	let allDefaultDBs = await getAllDefaultDashboards();
   575  	let allDBs = {...normalDBs, ...allDefaultDBs}
   576  	let favoriteDBs = await getAllFavoriteDashboards();
   577  	// Convert the array of favorite dashboards to a Set for faster lookup
   578  	favoriteDBsSet = new Set(Object.keys(favoriteDBs));
   579  	displayDashboards(allDBs)
   580  
   581  	$('#create-db-btn').click(createDashboard);
   582  	$('#run-search').click(searchDB);
   583  	$('.search-db-input').on('keyup', displayOriginalDashboards);
   584  
   585  	let stDate = "now-1h";
   586  	let endDate = "now";
   587  	datePickerHandler(stDate, endDate, stDate);
   588  }
   589  );