This is an automated email from the ASF dual-hosted git repository.
jfthomps pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/vcl.git
The following commit(s) were added to refs/heads/develop by this push:
new afcb8492 VCL-1142 - add top images from past 6 months to dashboard
afcb8492 is described below
commit afcb8492d74c856d148bda4ed10c5f82336611f8
Author: Josh Thompson <[email protected]>
AuthorDate: Mon Feb 19 16:44:54 2024 -0500
VCL-1142 - add top images from past 6 months to dashboard
dashboard.php:
-modified dashboard: added widget for toppast6moimages; added detaildialog
dialog
-modified AJupdateDashboard: added toppast6moimages to returned data;
updated arguments to getTopPastImageData for toppastimages
-added AJdashboardDetail
-modified addWidget: added $clicktitle argument; modified to make title a
link if $clicktitle is passed as true
-modified getTopPastImageData: added $imagecnt, $intervalunit, and
$intervalnum as arguments; modified queries to use arguments for date range and
returned rows
states.php: added AJdashboardDetail
utils.php: added dijit.Dialog to to required dojo modules for dashboard
dashboard.css: added "#detailcontent table td", ".dashwidget h3 a", and
".dashwidget h3 a:hover"
dashboard.js:
-modified updateDashboardCB: added call to updateTopPast6MonthImages
-added updateTopPast6MonthImages
-added cancelDetail
-added showdetail
-added showDetailCB
dropdownmenus/css/theme.css: added "#content div.dashwidget h3 a" and
"#content div.dashwidget h3 a:hover"
---
web/.ht-inc/dashboard.php | 72 +++++++++++++++++++++++++++++-----
web/.ht-inc/states.php | 3 ++
web/.ht-inc/utils.php | 1 +
web/css/dashboard.css | 20 +++++++++-
web/js/dashboard.js | 43 ++++++++++++++++++++
web/themes/dropdownmenus/css/theme.css | 8 +++-
6 files changed, 135 insertions(+), 12 deletions(-)
diff --git a/web/.ht-inc/dashboard.php b/web/.ht-inc/dashboard.php
index 9018c206..82a16731 100644
--- a/web/.ht-inc/dashboard.php
+++ b/web/.ht-inc/dashboard.php
@@ -28,6 +28,7 @@
///
////////////////////////////////////////////////////////////////////////////////
function dashboard() {
+ $affilid = getDashboardAffilID();
print "<h2>VCL Dashboard</h2>\n";
print "(Times and dates on this page are in " . date('T') .
")<br><br>\n";
if(checkUserHasPerm('View Dashboard (global)')) {
@@ -46,6 +47,7 @@ function dashboard() {
print addWidget('topimages', 'Top 5 Images in Use', '(Reservations <
24 hours long)');
print addWidget('toplongimages', 'Top 5 Long Term Images in Use',
'(Reservations > 24 hours long)');
print addWidget('toppastimages', 'Top 5 Images From Past Day',
'(Reservations with a start<br>time within past 24 hours)');
+ print addWidget('toppast6moimages', 'Top 5 Images From Past 6 Months',
'(Reservations with a start<br>time within past 6 months)', 1);
print addWidget('topfailedcomputers', 'Top Recent Computer Failures',
'(Failed in the last 5 days)');
print addWidget('blockallocation', 'Block Allocation Status');
print "</div>\n"; # dashleft
@@ -65,6 +67,24 @@ function dashboard() {
print addWidget('failedimaging', 'Failed Imaging Reservations',
'(Imaging Reservations in the maintenance state)');
$cont = addContinuationsEntry('AJupdateDashboard', array('val' => 0),
90, 1, 0);
print "<input type=\"hidden\" id=\"updatecont\" value=\"$cont\">\n";
+ $cont = addContinuationsEntry('AJdashboardDetail', array('affilid' =>
$affilid));
+ print "<input type=\"hidden\" id=\"detailcont\" value=\"$cont\">\n";
+
+ # detail dialog
+ $h = '';
+ $h .= "<div dojoType=dijit.Dialog\n";
+ $h .= " id=\"detaildialog\"\n";
+ $h .= " duration=250\n";
+ $h .= " autofocus=false\n";
+ $h .= " draggable=true>\n";
+ $h .= "<h3><div id=\"detailtitle\"></div></h3>\n";
+ $h .= "<div id=\"detailcontent\"></div>\n";
+ $h .= "<input type=\"hidden\" id=\"submitcont\">\n";
+ $h .= "<div style=\"text-align: center;\"><br>\n";
+ $h .= dijitButton('canceldetailbtn', 'Close', 'cancelDetail();', 0);
+ $h .= "</div>\n"; # btn div
+ $h .= "</div>\n"; # detaildialog
+ print $h;
}
////////////////////////////////////////////////////////////////////////////////
@@ -80,7 +100,8 @@ function AJupdateDashboard() {
$data['status'] = getStatusData();
$data['topimages'] = getTopImageData();
$data['toplongimages'] = getTopLongImageData();
- $data['toppastimages'] = getTopPastImageData();
+ $data['toppastimages'] = getTopPastImageData(5, 'DAY', 1);
+ $data['toppast6moimages'] = getTopPastImageData(5, 'MONTH', 6);
$data['topfailed'] = getTopFailedData();
$data['topfailedcomputers'] = getTopFailedComputersData();
$data['reschart'] = getActiveResChartData();
@@ -91,6 +112,28 @@ function AJupdateDashboard() {
sendJSON($data);
}
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn AJdashboardDetail()
+///
+/// \param id - id of widget type
+///
+/// \brief gets detailed information for specified type
+///
+////////////////////////////////////////////////////////////////////////////////
+function AJdashboardDetail() {
+ $id = processInputVar('id', ARG_STRING);
+ switch($id) {
+ case 'toppast6moimages':
+ $data = array('divid' => 'detailcontent');
+ $data['title'] = "Top Images From Past 6 Months";
+ $data['result'] = getTopPastImageData(30, 'MONTH', 6);
+ break;
+ default:
+ }
+ sendJSON($data);
+}
+
////////////////////////////////////////////////////////////////////////////////
///
/// \fn addWidget($id, $title, extra)
@@ -99,15 +142,20 @@ function AJupdateDashboard() {
/// \param $title - title to print at top of box
/// \param $extra (optional, default='') - extra text to be placed below title,
/// but above data
+/// \param $clicktitle - (optional, default=0) boolean for title being
clickable
+/// to display more details
///
/// \return div element for a section of data
///
/// \brief creates HTML for a box of data to be displayed
///
////////////////////////////////////////////////////////////////////////////////
-function addWidget($id, $title, $extra='') {
+function addWidget($id, $title, $extra='', $clicktitle=0) {
$txt = "<div class=\"dashwidget\">\n";
- $txt .= "<h3>$title</h3>\n";
+ if($clicktitle)
+ $txt .= "<h3><a
onclick=\"showdetail('$id');\">$title</a></h3>\n";
+ else
+ $txt .= "<h3>$title</h3>\n";
if($extra != '')
$txt .= "<div class=\"extra\">$extra</div>\n";
$txt .= "<div id=\"$id\"></div>\n";
@@ -343,7 +391,11 @@ function getTopLongImageData() {
////////////////////////////////////////////////////////////////////////////////
///
-/// \fn getTopPastImageData()
+/// \fn getTopPastImageData($imagecnt, $intervalunit, $intervalnum)
+///
+/// \param $imagecnt - number of images to return
+/// \param $intervalunit - units of interval for DATE_SUB in query
+/// \param $intervalnum - how many interval units to use in query
///
/// \return array of data with these keys:\n
/// \b prettyname - name of image\n
@@ -352,7 +404,7 @@ function getTopLongImageData() {
/// \brief gets data about top reserved images over past day
///
////////////////////////////////////////////////////////////////////////////////
-function getTopPastImageData() {
+function getTopPastImageData($imagecnt, $intervalunit, $intervalnum) {
$affilid = getDashboardAffilID();
$reloadid = getUserlistID('vclreload@Local');
if($affilid == 0) {
@@ -363,10 +415,10 @@ function getTopPastImageData() {
. "WHERE l.imageid = i.id AND "
. "l.wasavailable = 1 AND "
. "l.userid != $reloadid AND "
- . "l.start > DATE_SUB(NOW(), INTERVAL 1 DAY) "
+ . "l.start > DATE_SUB(NOW(), INTERVAL $intervalnum
$intervalunit) "
. "GROUP BY l.imageid "
. "ORDER BY count DESC "
- . "LIMIT 5";
+ . "LIMIT $imagecnt";
}
else {
$query = "SELECT COUNT(l.imageid) AS count, "
@@ -379,10 +431,10 @@ function getTopPastImageData() {
. "l.imageid = i.id AND "
. "l.wasavailable = 1 AND "
. "l.userid != $reloadid AND "
- . "l.start > DATE_SUB(NOW(), INTERVAL 1 DAY) "
+ . "l.start > DATE_SUB(NOW(), INTERVAL $intervalnum
$intervalunit) "
. "GROUP BY l.imageid "
. "ORDER BY count DESC "
- . "LIMIT 5";
+ . "LIMIT $imagecnt";
}
$data = array();
$qh = doQuery($query, 101);
@@ -918,7 +970,7 @@ function getDashboardAffilID() {
global $user;
if(! checkUserHasPerm('View Dashboard (global)'))
return $user['affiliationid'];
- $affilid = processInputVar('affilid', ARG_NUMERIC);
+ $affilid = getContinuationVar('affilid', processInputVar('affilid',
ARG_NUMERIC, 0));
$affils = getAffiliations();
if($affilid != 0 && ! array_key_exists($affilid, $affils))
return 0;
diff --git a/web/.ht-inc/states.php b/web/.ht-inc/states.php
index 2e7cb06d..9ac803e0 100644
--- a/web/.ht-inc/states.php
+++ b/web/.ht-inc/states.php
@@ -136,6 +136,7 @@ $noHTMLwrappers = array('sendRDPfile',
'AJdeleteSiteMaintenance',
'AJvalidateUserid',
'AJupdateDashboard',
+ 'AJdashboardDetail',
'AJgetStatData',
'AJgetBlockAllocatedMachineData',
'AJpermSelectUserGroup',
@@ -554,9 +555,11 @@ $actions['pages']['AJdeleteSiteMaintenance'] =
"sitemaintenance";
$actions['mode']['dashboard'] = "dashboard";
$actions['mode']['AJupdateDashboard'] = "AJupdateDashboard";
$actions['mode']['AJrestartImageCapture'] = "AJrestartImageCapture";
+$actions['mode']['AJdashboardDetail'] = "AJdashboardDetail";
$actions['pages']['dashboard'] = "dashboard";
$actions['pages']['AJupdateDashboard'] = "dashboard";
$actions['pages']['AJrestartImageCapture'] = "dashboard";
+$actions['pages']['AJdashboardDetail'] = "dashboard";
# site configuration
$actions['mode']['siteconfig'] = "siteconfig";
diff --git a/web/.ht-inc/utils.php b/web/.ht-inc/utils.php
index 667673b6..3032e5a6 100644
--- a/web/.ht-inc/utils.php
+++ b/web/.ht-inc/utils.php
@@ -13957,6 +13957,7 @@ function getDojoHTML($refresh) {
$filename = 'vclDashboard.js';
$dojoRequires = array('dojo.parser',
'dijit.Tooltip',
+ 'dijit.Dialog',
'dijit.form.Button',
'dojox.charting.widget.Chart2D',
'dojox.charting.action2d.Tooltip',
diff --git a/web/css/dashboard.css b/web/css/dashboard.css
index c592364e..5c1ae0b5 100644
--- a/web/css/dashboard.css
+++ b/web/css/dashboard.css
@@ -18,7 +18,8 @@
padding-right: 10px;
}
-#dashboard table td {
+#dashboard table td,
+#detailcontent table td {
padding-left: 5px;
}
@@ -45,3 +46,20 @@
margin-top: 0px;
margin-bottom: 2px;
}
+
+.dashwidget h3 a {
+ background: #0053fb;
+ color: white;
+ margin-top: 0px;
+ margin-bottom: 2px;
+}
+
+.dashwidget h3 a:hover {
+ background: black;
+ color: white;
+ margin-top: 0px;
+ margin-bottom: 2px;
+ text-decoration: none;
+ cursor: pointer;
+}
+
diff --git a/web/js/dashboard.js b/web/js/dashboard.js
index 0591c5ca..582825a0 100644
--- a/web/js/dashboard.js
+++ b/web/js/dashboard.js
@@ -35,6 +35,7 @@ function updateDashboardCB(data, ioArgs) {
updateTopImages(data.items.topimages);
updateTopLongImages(data.items.toplongimages);
updateTopPastImages(data.items.toppastimages);
+ updateTopPast6MonthImages(data.items.toppast6moimages);
updateTopFailed(data.items.topfailed);
updateTopFailedComputers(data.items.topfailedcomputers);
updateResChart(data.items.reschart);
@@ -134,6 +135,31 @@ function updateTopPastImages(data) {
obj.innerHTML = txt;
}
+function updateTopPast6MonthImages(data) {
+ if('items' in data && 'divid' in data.items) {
+ var obj = dojo.byId(data.items.divid);
+ dojo.byId('detailtitle').innerHTML = data.items.title;
+ data = data.items.result;
+ }
+ else {
+ var obj = dojo.byId('toppast6moimages');
+ }
+ console.log("data length: " + data.length);
+ if(data.length == 0) {
+ obj.innerHTML = 'No recent reservations';
+ return;
+ }
+ var txt = '<table>';
+ for(var i = 0; i < data.length; i++) {
+ txt += '<tr><th align="right">'
+ + data[i].prettyname
+ + '</th><td>'
+ + data[i].count
+ + '</td></tr>';
+ }
+ txt += '</table>';
+ obj.innerHTML = txt;
+}
function updateTopFailed(data) {
var obj = dojo.byId('topfailed');
if(data.length == 0) {
@@ -372,3 +398,20 @@ function secToHour(time) {
var min = parseInt((time - (hour * 3600)) / 60);
return dojox.string.sprintf('%d:%02d hour(s)', hour, min);
}
+
+function cancelDetail() {
+ dijit.byId('detaildialog').hide();
+}
+
+function showdetail(id) {
+ var data = {
+ id: id,
+ continuation: dojo.byId('detailcont').value
+ };
+ RPCwrapper(data, showDetailCB, 1);
+}
+
+function showDetailCB(data, ioArgs) {
+ updateTopPast6MonthImages(data);
+ dijit.byId('detaildialog').show();
+}
diff --git a/web/themes/dropdownmenus/css/theme.css
b/web/themes/dropdownmenus/css/theme.css
index be025f7c..3b682864 100644
--- a/web/themes/dropdownmenus/css/theme.css
+++ b/web/themes/dropdownmenus/css/theme.css
@@ -380,9 +380,15 @@ div.dijitMenuPopup table tbody tr.dijitMenuItemFocused td {
#addResourceGroupPane td.privCascade:hover {
background-color: #008000 !important;
}
-#content div.dashwidget h3 {
+#content div.dashwidget h3,
+#content div.dashwidget h3 a {
background-color: #ed1c24;
}
+#content div.dashwidget h3 a:hover {
+ background-color: black;
+ color: white;
+ cursor: pointer;
+}
a:hover, a:active {
text-decoration: underline;
}