]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
baculum: Implement graphical status client
authorMarcin Haba <marcin.haba@bacula.pl>
Sun, 28 Jul 2019 17:48:05 +0000 (19:48 +0200)
committerMarcin Haba <marcin.haba@bacula.pl>
Sat, 14 Dec 2019 14:55:27 +0000 (15:55 +0100)
12 files changed:
gui/baculum/protected/Web/JavaScript/misc.js
gui/baculum/protected/Web/Lang/en/messages.mo
gui/baculum/protected/Web/Lang/en/messages.po
gui/baculum/protected/Web/Lang/ja/messages.mo
gui/baculum/protected/Web/Lang/ja/messages.po
gui/baculum/protected/Web/Lang/pl/messages.mo
gui/baculum/protected/Web/Lang/pl/messages.po
gui/baculum/protected/Web/Lang/pt/messages.mo
gui/baculum/protected/Web/Lang/pt/messages.po
gui/baculum/protected/Web/Pages/ClientView.page
gui/baculum/protected/Web/Pages/ClientView.php
gui/baculum/themes/Baculum-v2/css/baculum.css

index 1aed57948284ac9372d602327499b92cf3cb3089..833a85591b3392a7bd7508062c2f36fd7b6d4873 100644 (file)
@@ -792,11 +792,7 @@ var W3SideBar = {
        }
 };
 
-W3Tabs = {
-       css: {
-               tab_btn: 'tab_btn',
-               tab_item: 'tab_item'
-       },
+W3TabsCommon = {
        open: function(btn_id, item_id) {
                var tab_items = document.getElementsByClassName(this.css.tab_item);
                for (var i = 0; i < tab_items.length; i++) {
@@ -808,12 +804,35 @@ W3Tabs = {
                }
                var tab_btns = document.getElementsByClassName(this.css.tab_btn);
                for (var i = 0; i < tab_btns.length; i++) {
-                       tab_btns[i].className = 'w3-bar-item w3-button ' + this.css.tab_btn;
-                       if (tab_btns[i].id === btn_id) {
-                               tab_btns[i].className += ' w3-gray';
+                       if (tab_btns[i].id === btn_id && !tab_btns[i].classList.contains(this.css.tab_item_hover)) {
+                               tab_btns[i].classList.add(this.css.tab_item_hover);
+                       } else if (tab_btns[i].classList.contains(this.css.tab_item_hover)) {
+                               tab_btns[i].classList.remove(this.css.tab_item_hover);
                        }
                }
        }
+};
+
+W3Tabs = {
+       css: {
+               tab_btn: 'tab_btn',
+               tab_item: 'tab_item',
+               tab_item_hover: 'w3-grey'
+       },
+       open: function(btn_id, item_id) {
+               W3TabsCommon.open.call(this, btn_id, item_id);
+       }
+};
+
+W3SubTabs = {
+       css: {
+               tab_btn: 'subtab_btn',
+               tab_item: 'subtab_item',
+               tab_item_hover: 'w3-border-red'
+       },
+       open: function(btn_id, item_id) {
+               W3TabsCommon.open.call(this, btn_id, item_id);
+       }
 }
 
 function get_url_param (name) {
index b1878a30617b7578b8a18c4d53b06afe6e4d202b..7173c91755c615d0afb14762fb21341eeb90e451 100644 (file)
Binary files a/gui/baculum/protected/Web/Lang/en/messages.mo and b/gui/baculum/protected/Web/Lang/en/messages.mo differ
index 0a85e8894706a220f5163a3e8d13612826653955..93497873551c6fac78ef6519b621d9e0ffee99ee 100644 (file)
@@ -2224,3 +2224,69 @@ msgstr "Go to job with jobid %jobid"
 
 msgid "Go to job %job"
 msgstr "Go to job %job"
+
+msgid "Graphical status"
+msgstr "Graphical status"
+
+msgid "Text status"
+msgstr "Text status"
+
+msgid "Uname:"
+msgstr "Uname:"
+
+msgid "Started time:"
+msgstr "Started time:"
+
+msgid "Plugins:"
+msgstr "Plugins:"
+
+msgid "Bandwidth limit:"
+msgstr "Bandwidth limit:"
+
+msgid "No limit"
+msgstr "No limit"
+
+msgid "Debug:"
+msgstr "Debug:"
+
+msgid "No debug"
+msgstr "No debug"
+
+msgid "Job bytes:"
+msgstr "Job bytes:"
+
+msgid "Job files:"
+msgstr "Job files:"
+
+msgid "Average speed:"
+msgstr "Average speed:"
+
+msgid "Processing file:"
+msgstr "Processing file:"
+
+msgid "Read bytes:"
+msgstr "Read bytes:"
+
+msgid "Examined files:"
+msgstr "Examined files:"
+
+msgid "Running jobs"
+msgstr "Running jobs"
+
+msgid "Job errors:"
+msgstr "Job errors:"
+
+msgid "Type:"
+msgstr "Type:"
+
+msgid "Refresh interval (sec.):"
+msgstr "Refresh interval (sec.):"
+
+msgid "To disable refreshing please type 0."
+msgstr "To disable refreshing please type 0."
+
+msgid "No jobs running"
+msgstr "No jobs running"
+
+msgid "Graphical client status is supported for Bacula clients version 9.0 and greater."
+msgstr "Graphical client status is supported for Bacula clients version 9.0 and greater."
index ee5c26e5003fb647a7df122cee45269f8d9beed8..55728b51649f2775f6c59305c1f5b9a416d1fbde 100644 (file)
Binary files a/gui/baculum/protected/Web/Lang/ja/messages.mo and b/gui/baculum/protected/Web/Lang/ja/messages.mo differ
index 0bf2f2120f4c6eaa3ce6ffba6e31d8f7510dd116..7296bb8ea368d32f393396a6a89b01ddb591030e 100644 (file)
@@ -2310,3 +2310,69 @@ msgstr "Go to job with jobid %jobid"
 
 msgid "Go to job %job"
 msgstr "Go to job %job"
+
+msgid "Graphical status"
+msgstr "Graphical status"
+
+msgid "Text status"
+msgstr "Text status"
+
+msgid "Uname:"
+msgstr "Uname:"
+
+msgid "Started time:"
+msgstr "Started time:"
+
+msgid "Plugins:"
+msgstr "Plugins:"
+
+msgid "Bandwidth limit:"
+msgstr "Bandwidth limit:"
+
+msgid "No limit"
+msgstr "No limit"
+
+msgid "Debug:"
+msgstr "Debug:"
+
+msgid "No debug"
+msgstr "No debug"
+
+msgid "Job bytes:"
+msgstr "Job bytes:"
+
+msgid "Job files:"
+msgstr "Job files:"
+
+msgid "Average speed:"
+msgstr "Average speed:"
+
+msgid "Processing file:"
+msgstr "Processing file:"
+
+msgid "Read bytes:"
+msgstr "Read bytes:"
+
+msgid "Examined files:"
+msgstr "Examined files:"
+
+msgid "Running jobs"
+msgstr "Running jobs"
+
+msgid "Job errors:"
+msgstr "Job errors:"
+
+msgid "Type:"
+msgstr "Type:"
+
+msgid "Refresh interval (sec.):"
+msgstr "Refresh interval (sec.):"
+
+msgid "To disable refreshing please type 0."
+msgstr "To disable refreshing please type 0."
+
+msgid "No jobs running"
+msgstr "No jobs running"
+
+msgid "Graphical client status is supported for Bacula clients version 9.0 and greater."
+msgstr "Graphical client status is supported for Bacula clients version 9.0 and greater."
index 8c3c23b8a23b7e23520ff4fd54e71845c6f025aa..31e122c609c1e83e2f3ecf8ee35fa9c0dbfca1d3 100644 (file)
Binary files a/gui/baculum/protected/Web/Lang/pl/messages.mo and b/gui/baculum/protected/Web/Lang/pl/messages.mo differ
index 338a5d930686c27994b107108730ce896470427e..693bd1ceaaecd77438c8b7bc2dad9d0ea3822797 100644 (file)
@@ -2231,3 +2231,69 @@ msgstr "Przejdź do zadania z jobid %jobid"
 
 msgid "Go to job %job"
 msgstr "Przejdź do zadania %job"
+
+msgid "Graphical status"
+msgstr "Status graficzny"
+
+msgid "Text status"
+msgstr "Status tekstowy"
+
+msgid "Uname:"
+msgstr "Uname:"
+
+msgid "Started time:"
+msgstr "Czas uruchomienia:"
+
+msgid "Plugins:"
+msgstr "Wtyczki:"
+
+msgid "Bandwidth limit:"
+msgstr "Limit transferu:"
+
+msgid "No limit"
+msgstr "Bez limitu"
+
+msgid "Debug:"
+msgstr "Debug:"
+
+msgid "No debug"
+msgstr "Bez debugu"
+
+msgid "Job bytes:"
+msgstr "Ilość bajtów zadania:"
+
+msgid "Job files:"
+msgstr "Ilość plików zadania:"
+
+msgid "Average speed:"
+msgstr "Średnia prędkość:"
+
+msgid "Processing file:"
+msgstr "Przetwarzany plik:"
+
+msgid "Read bytes:"
+msgstr "Przeczytanych bajtów:"
+
+msgid "Examined files:"
+msgstr "Przeczytanych plików:"
+
+msgid "Running jobs"
+msgstr "Uruchomione zadania"
+
+msgid "Job errors:"
+msgstr "Błędy zadania:"
+
+msgid "Type:"
+msgstr "Typ:"
+
+msgid "Refresh interval (sec.):"
+msgstr "Interwał odświeżania (sek.):"
+
+msgid "To disable refreshing please type 0."
+msgstr "Aby wyłączyć odświeżanie proszę wypisać 0."
+
+msgid "No jobs running"
+msgstr "Nie ma uruchomionych zadań"
+
+msgid "Graphical client status is supported for Bacula clients version 9.0 and greater."
+msgstr "Graficzny status klienta jest wspierany dla klientów Bacula w wersji 9.0 i większych."
index d9b0e1719db1219885b76f52ecdd9f39d38f35a2..42de8261d51d998393d03524b46d6e8a6304c768 100644 (file)
Binary files a/gui/baculum/protected/Web/Lang/pt/messages.mo and b/gui/baculum/protected/Web/Lang/pt/messages.mo differ
index fb06dc2f2efbb63752a3e267d25466660c7e3af2..6800b726607e7486d8a680d720a5ade34ab34835 100644 (file)
@@ -2239,3 +2239,69 @@ msgstr "Go to job with jobid %jobid"
 
 msgid "Go to job %job"
 msgstr "Go to job %job"
+
+msgid "Graphical status"
+msgstr "Graphical status"
+
+msgid "Text status"
+msgstr "Text status"
+
+msgid "Uname:"
+msgstr "Uname:"
+
+msgid "Started time:"
+msgstr "Started time:"
+
+msgid "Plugins:"
+msgstr "Plugins:"
+
+msgid "Bandwidth limit:"
+msgstr "Bandwidth limit:"
+
+msgid "No limit"
+msgstr "No limit"
+
+msgid "Debug:"
+msgstr "Debug:"
+
+msgid "No debug"
+msgstr "No debug"
+
+msgid "Job bytes:"
+msgstr "Job bytes:"
+
+msgid "Job files:"
+msgstr "Job files:"
+
+msgid "Average speed:"
+msgstr "Average speed:"
+
+msgid "Processing file:"
+msgstr "Processing file:"
+
+msgid "Read bytes:"
+msgstr "Read bytes:"
+
+msgid "Examined files:"
+msgstr "Examined files:"
+
+msgid "Running jobs"
+msgstr "Running jobs"
+
+msgid "Job errors:"
+msgstr "Job errors:"
+
+msgid "Type:"
+msgstr "Type:"
+
+msgid "Refresh interval (sec.):"
+msgstr "Refresh interval (sec.):"
+
+msgid "To disable refreshing please type 0."
+msgstr "To disable refreshing please type 0."
+
+msgid "No jobs running"
+msgstr "No jobs running"
+
+msgid "Graphical client status is supported for Bacula clients version 9.0 and greater."
+msgstr "Graphical client status is supported for Bacula clients version 9.0 and greater."
index 9b981a22b7094c5efe274daa556907c445c4a5bd..24c31e77bd13c0adfb2674f1c686321527d37e59 100644 (file)
                        OnClick="status"
                        CssClass="w3-button w3-green w3-margin-bottom"
                        CausesValidation="false"
-                       ClientSide.OnLoading="$('#status_storage_loading').show();"
-                       ClientSide.OnSuccess="$('#status_storage_loading').hide();"
+                       ClientSide.OnLoading="$('#status_client_loading').show();"
+                       ClientSide.OnSuccess="$('#status_client_loading').hide();$('#show_client_container').hide();$('#status_client_container').show();oGraphicalClientStatus.set_refresh_timeout(document.getElementById('status_client_refresh_interval').value);"
                >
                        <prop:Text><%=Prado::localize('Status client')%> &nbsp;<i class="fa fa-file-medical-alt"></i></prop:Text>
                </com:TActiveLinkButton>
-               <i id="status_storage_loading" class="fa fa-sync w3-spin" style="display: none; vertical-align: super;"></i>
-               <div class="w3-panel w3-card w3-light-grey">
-                       <div class="w3-code notranslate">
-                               <pre><com:TActiveLabel ID="ClientLog" /></pre>
+               <i id="status_client_loading" class="fa fa-sync w3-spin" style="display: none; vertical-align: super; margin-left: 6px;"></i>
+               <div id="show_client_container">
+                       <div id="status_client_text_output" class="w3-code">
+                               <pre><com:TActiveLabel ID="ShowLog" /></pre>
+                       </div>
+               </div>
+               <div id="status_client_container" style="display: none">
+                       <div class="w3-right w3-margin-top w3-margin-right" title="<%[ To disable refreshing please type 0. ]%>">
+                               <span style="line-height: 41px"><%[ Refresh interval (sec.): ]%></span> <input type="text" id="status_client_refresh_interval" class="w3-input w3-border w3-right w3-margin-left" value="0" style="width: 50px"/>
+                       </div>
+                       <div class="w3-panel w3-card w3-light-grey" style="padding-bottom: 16px;">
+                               <div class="w3-row">
+                                       <a href="javascript:void(0)" onclick="W3SubTabs.open('status_client_subtab_graphical', 'status_client_graphical_output');">
+                                               <div id="status_client_subtab_graphical" class="subtab_btn w3-half w3-bottombar w3-hover-light-grey w3-border-red w3-padding"><%[ Graphical status ]%></div>
+                                        </a>
+                                       <a href="javascript:void(0)" onclick="W3SubTabs.open('status_client_subtab_text', 'status_client_text_output');">
+                                               <div id="status_client_subtab_text" class="subtab_btn w3-half w3-bottombar w3-hover-light-grey w3-padding"><%[ Text status ]%></div>
+                                       </a>
+                               </div>
+                               <div id="status_client_graphical_output" class="subtab_item">
+                                       <h4 id="status_client_status_not_supported" style="display: none"><%[ Graphical client status is supported for Bacula clients version 9.0 and greater. ]%></h4>
+                                       <div id="status_client_graphical_container">
+                                               <table class="w3-table w3-stripped w3-border status_table">
+                                                       <tr>
+                                                               <td><%[ Version: ]%></td>
+                                                               <td id="status_client_version"></td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td><%[ Uname: ]%></td>
+                                                               <td id="status_client_uname"></td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td><%[ Started time: ]%></td>
+                                                               <td id="status_client_started_time"></td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td><%[ Running jobs: ]%></td>
+                                                               <td><span id="status_client_jobs_running"></span> / <span id="status_client_maxjobs"></span></td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td><%[ Enabled: ]%></td>
+                                                               <td id="status_client_enabled"></td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td><%[ Plugins: ]%></td>
+                                                               <td id="status_client_plugins"></td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td><%[ Bandwidth limit: ]%></td>
+                                                               <td id="status_client_bwlimit"></td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td><%[ Debug: ]%></td>
+                                                               <td id="status_client_debug"></td>
+                                                       </tr>
+                                               </table>
+                                               <h3><%[ Running jobs ]%></h3>
+                                               <h5 id="status_client_no_jobs_running" style="display: none"><%[ No jobs running ]%></h5>
+                                               <div id="status_client_running_jobs"></div>
+                                       </div>
+<script type="text/javascript">
+var oGraphicalClientStatus = {
+       data: {},
+       refresh_timeout: null,
+       running_jobids: [],
+       ids: {
+               running_jobs: 'status_client_running_jobs',
+               refresh_interval: 'status_client_refresh_interval',
+               no_jobs_running: 'status_client_no_jobs_running',
+               status_not_supported: 'status_client_status_not_supported',
+               graphical_container: 'status_client_graphical_container',
+               header: {
+                       version: 'status_client_version',
+                       uname: 'status_client_uname',
+                       started_epoch: 'status_client_started_time',
+                       jobs_run: 'status_client_jobs_running',
+                       plugins: 'status_client_plugins',
+                       bwlimit: 'status_client_bwlimit',
+                       debug: 'status_client_debug'
+               },
+               show: {
+                       maxjobs: 'status_client_maxjobs',
+                       enabled: 'status_client_enabled'
+               }
+       },
+       formatters: {
+               uname: function(value) {
+                       var img = document.createElement('I');
+                       img.className = 'fab fa-2x';
+                       if (/win\d{2}/i.test(value)) {
+                               img.className += ' fa-windows';
+                       } else if (/ubuntu/i.test(value)) {
+                               img.className += ' fa-ubuntu';
+                       } else if (/fedora/i.test(value)) {
+                               img.className += ' fa-fedora';
+                       } else if (/centos/i.test(value)) {
+                               img.className += ' fa-centos';
+                       } else if (/redhat/i.test(value)) {
+                               img.className += ' fa-redhat';
+                       } else if (/suse/i.test(value)) {
+                               img.className += ' fa-suse';
+                       } else if (/linux/i.test(value)) {
+                               img.className += ' fa-linux';
+                       } else if (/freebsd/i.test(value)) {
+                               img.className += ' fa-freebsd';
+                       } else if (/(darwin|mac\s?os)/i.test(value)) {
+                               img.className += ' fa-apple';
+                       } else {
+                               img.className += ' fa-question';
+                       }
+                       img.style.marginRight = '10px';
+                       var el = document.createElement('SPAN');
+                       var text = document.createTextNode(value);
+                       el.appendChild(img);
+                       el.appendChild(text);
+                       return el;
+               },
+               started_epoch: function(value) {
+                       var t = parseInt(value, 10) * 1000;
+                       return (new Date(t)).toLocaleString();
+               },
+               jobs_run: function(value) {
+                       return (this.data.hasOwnProperty('running') ? this.data.running.length : 0);
+               },
+               enabled: function(value) {
+                       var img = document.createElement('I');
+                       img.className = 'fa';
+                       if (value == 1) {
+                               img.className += ' fa-check w3-text-green';
+                       } else {
+                               img.className += ' fa-times w3-text-red';
+                       }
+                       return img;
+               },
+               plugins: function(value) {
+                       return (value ? value.replace(/-fd\.so/g, '').replace(/,/g, ', ') : '-');
+               },
+               bwlimit: function(value) {
+                       var limit = '<%[ No limit ]%>';
+                       var l = parseInt(value, 10);
+                       if (l > 0) {
+                               var fl = Units.format_speed(l, null, true, true);
+                               limit = fl.value.toFixed(2) + ' ' + fl.format;
+                       }
+                       return limit;
+               },
+               debug: function(value) {
+                       var debug = '<%[ No debug ]%>';
+                       if (value !== '0') {
+                               debug = value;
+                       }
+                       return debug;
+               }
+       },
+       init: function() {
+               this.set_events();
+       },
+       set_data: function(data) {
+               this.data = data;
+       },
+       set_events: function() {
+               var refresh_interval_el = document.getElementById(this.ids.refresh_interval);
+               refresh_interval_el.addEventListener('keyup', function(e) {
+                       var interval = refresh_interval_el.value;
+                       this.set_refresh_timeout(interval);
+               }.bind(this));
+       },
+       set_refresh_timeout: function(timeout) {
+               timeout = parseInt(timeout, 10) * 1000;
+               if (isNaN(timeout)) {
+                       return;
+               }
+               if (this.refresh_timeout !== null) {
+                       clearTimeout(this.refresh_timeout);
+               }
+               if (timeout === 0) {
+                       return;
+               }
+               this.refresh_timeout = setTimeout(function() {
+                       $('#<%=$this->ClientStatusBtn->ClientID%>').click();
+               }.bind(this), timeout);
+       },
+       update: function(data) {
+               this.set_data(data);
+               if (this.is_status_supported() === false) {
+                       return;
+               }
+               var el, val;
+               ['header', 'show'].forEach(function(section) {
+                       if (!this.data.hasOwnProperty(section)) {
+                               return;
+                       }
+                       for (var key in this.ids[section]) {
+                               if (!this.data[section].hasOwnProperty(key)) {
+                                       continue;
+                               }
+                               el = document.getElementById(this.ids[section][key]);
+                               val = this.formatters.hasOwnProperty(key) ? this.formatters[key].call(this, this.data[section][key]) : this.data[section][key];
+                               if (val instanceof HTMLElement) {
+                                       el.innerHTML = val.outerHTML;
+                               } else {
+                                       el.textContent = val;
+                               }
+                       }
+               }.bind(this));
+               this.set_jobs_header();
+               if (this.data.hasOwnProperty('running')) {
+                       var full_refresh = this.is_full_refresh();
+                       if (full_refresh) {
+                               // remembered job list empty so job list changed - full refresh list
+                               this.remove_elements('running_job_header');
+                               this.remove_elements('running_job_table');
+                       }
+                       this.running_jobids = [];
+                       for (var i = 0; i < this.data.running.length; i++) {
+                               this.add_running_job(i, this.data.running[i], full_refresh);
+                               this.running_jobids.push(this.data.running[i].jobid);
+                       }
+               }
+       },
+       add_running_job: function(job_nb, job, full_refresh) {
+               var header = document.createElement('H4');
+               header.className = 'running_job_header';
+               header.textContent = '<%[ Job: ]%> #' + (job_nb+1) + ' ' + job.job;
+
+               var table = document.createElement('TABLE');
+               table.className = 'w3-table w3-stripped w3-border status_table running_job_table';
+               table.setAttribute('rel', job.jobid);
+
+               // JobId
+               var jobid_img = document.createElement('I');
+               jobid_img.className = 'fa fa-external-link-alt fa-xs';
+               var jobid_a = document.createElement('A');
+               jobid_a.href = '/web/job/history/' + job.jobid + '/';
+               jobid_a.appendChild(jobid_img);
+               jobid_a.title = '<%[ Go to job with jobid %jobid ]%>'.replace('%jobid', job.jobid);
+               var jobid = job.jobid + ' ' + jobid_a.outerHTML;
+               this.add_job_row(table, 'JobId', jobid);
+
+               // Type
+               var type = JobType.get_type(job.type);
+               this.add_job_row(table, '<%[ Type: ]%>', type);
+
+               // Level
+               var level = JobLevel.get_level(job.level);
+               this.add_job_row(table, '<%[ Level: ]%>', level);
+
+               // Job bytes
+               var jobbytes = Units.get_formatted_size(job.jobbytes);
+               this.add_job_row(table, '<%[ Job bytes: ]%>', jobbytes);
+
+               // Job files
+               this.add_job_row(table, '<%[ Job files: ]%>', job.jobfiles);
+
+               // Average job speed
+               var ave_speed = Units.format_speed(job.bytes_sec, null, true, true);
+               var ave_job_speed = ave_speed.value.toFixed(2) + ' ' + ave_speed.format;
+               this.add_job_row(table, '<%[ Average speed: ]%>', ave_job_speed);
+
+               // Processing file
+               if (job.hasOwnProperty('processing_file') && job.processing_file) {
+                       var processing_file = document.createElement('SPAN');
+                       processing_file.title = job.processing_file;
+                       if (job.processing_file.length > 60) {
+                               processing_file.textContent = job.processing_file.substr(0, 17) + ' (..) ' + job.processing_file.substr(-37);
+                       } else {
+                               processing_file.textContent = job.processing_file;
+                       }
+                       this.add_job_row(table, '<%[ Processing file: ]%>', processing_file.outerHTML);
+               }
+
+               // Job errors
+               this.add_job_row(table, '<%[ Job errors: ]%>', job.errors);
+
+               // Read bytes
+               var read_bytes = Units.get_formatted_size(job.readbytes);
+               this.add_job_row(table, '<%[ Read bytes: ]%>', read_bytes);
+
+               // Examined files
+               this.add_job_row(table, '<%[ Examined files: ]%>', job.files_examined);
+
+               // Bandwidth limit
+               var bwlimit = '<%[ No limit ]%>';
+               var l = parseInt(job.bwlimit, 10);
+               if (l > 0) {
+                       var fl = Units.format_speed(l, null, true, true);
+                       bwlimit = fl.value.toFixed(2) + ' ' + fl.format;
+               }
+               this.add_job_row(table, '<%[ Bandwidth limit: ]%>', bwlimit);
+
+               var running_jobs_el = document.getElementById(this.ids.running_jobs);
+               if (full_refresh) {
+                       // job list changed - full refresh
+                       running_jobs_el.appendChild(header);
+                       running_jobs_el.appendChild(table);
+               } else {
+                       var t = running_jobs_el.querySelector('table[rel="' + job.jobid + '"]');
+                       running_jobs_el.replaceChild(table, t);
+               }
+       },
+       is_full_refresh: function() {
+               var full_refresh = false;
+               var running_jobids = [];
+               // check if with data came new jobs or disapeared some finished jobs
+               for (var i = 0; i < this.data.running.length; i++) {
+                       running_jobids.push(this.data.running[i].jobid);
+                       if (this.running_jobids.indexOf(this.data.running[i].jobid) === -1) {
+                               full_refresh = true;
+                               break;
+                       }
+               }
+               if (!full_refresh) {
+                       for (var i = 0; i < this.running_jobids.length; i++) {
+                               if (running_jobids.indexOf(this.running_jobids[i]) === -1) {
+                                       full_refresh = true;
+                                       break;
+                               }
+                       }
+               }
+               return full_refresh;
+       },
+       remove_elements: function(css_class) {
+               var elements = document.getElementsByClassName(css_class);
+               for (var i = 0; i < elements.length; i++) {
+                       while (elements[i].firstChild) {
+                               elements[i].removeChild(elements[i].firstChild);
+                       }
+               }
+               var els = [].slice.call(elements);
+               var els_len = els.length;
+               for (var i = 0; i < els_len; i++) {
+                       els[i].parentNode.removeChild(els[i]);
+               }
+       },
+       add_job_row: function(table, key, value) {
+               var tr = document.createElement('TR');
+               var tdl = document.createElement('TD');
+               var tdr = document.createElement('TD');
+               tdl.textContent = key;
+               tdr.innerHTML = value;
+               tr.appendChild(tdl);
+               tr.appendChild(tdr);
+               table.appendChild(tr);
+       },
+       is_status_supported: function() {
+               var supported = false;
+               var not_supported = document.getElementById(this.ids.status_not_supported);
+               var graphical_container = document.getElementById(this.ids.graphical_container);
+               if (this.data && this.data.hasOwnProperty('version') && this.data.version.hasOwnProperty('major') && this.data.version.major >= 9 && this.data.version.minor >= 0 && this.data.version.release >= 0) {
+                       supported = true;
+                       not_supported.style.display = 'none';
+                       graphical_container.style.display = '';
+               } else if (not_supported.style.display == 'none') {
+                       not_supported.style.display = '';
+                       graphical_container.style.display = 'none';
+                       W3SubTabs.open('status_client_subtab_text', 'status_client_text_output');
+               }
+               return supported;
+       },
+       set_jobs_header: function() {
+               var no_jobs_running = document.getElementById(this.ids.no_jobs_running);
+               if (this.data.hasOwnProperty('running') && this.data.running.length > 0) {
+                       no_jobs_running.style.display = 'none';
+               } else {
+                       no_jobs_running.style.display = '';
+               }
+       }
+};
+
+function init_graphical_client_status(data) {
+       oGraphicalClientStatus.update(data);
+}
+oGraphicalClientStatus.init();
+</script>
+                               </div>
+                               <div id="status_client_text_output" class="w3-code subtab_item" style="display: none">
+                                       <pre><com:TActiveLabel ID="ClientLog" /></pre>
+                               </div>
                        </div>
                </div>
        </div>
index f90e7355ee0d53785724f866c5760bedf3b98334..665fbbd099920345f97b0a205783feb590ec7e96 100644 (file)
@@ -55,7 +55,7 @@ class ClientView extends BaculumWebPage {
                        true
                );
                if ($clientshow->error === 0) {
-                       $this->ClientLog->Text = implode(PHP_EOL, $clientshow->output);
+                       $this->ShowLog->Text = implode(PHP_EOL, $clientshow->output);
                }
                $client = $this->getModule('api')->get(
                        array('clients', $clientid)
@@ -109,10 +109,54 @@ class ClientView extends BaculumWebPage {
        }
 
        public function status($sender, $param) {
-               $status = $this->getModule('api')->get(
+               $raw_status = $this->getModule('api')->get(
                        array('clients', $this->getClientId(), 'status')
                )->output;
-               $this->ClientLog->Text = implode(PHP_EOL, $status);
+               $this->ClientLog->Text = implode(PHP_EOL, $raw_status);
+
+               $query_str = '?name=' . rawurlencode($this->getClientName()) . '&type=header';
+               $graph_status = $this->getModule('api')->get(
+                       array('status', 'client', $query_str),
+               );
+               $client_status = array(
+                       'header' => array(),
+                       'running' => array(),
+                       'version' => $this->getClientVersion($raw_status)
+               );
+               if ($graph_status->error === 0) {
+                       $client_status['header'] = $graph_status->output;
+               }
+
+               $query_str = '?name=' . rawurlencode($this->getClientName()) . '&type=running';
+               $graph_status = $this->getModule('api')->get(
+                       array('status', 'client', $query_str),
+               );
+               if ($graph_status->error === 0) {
+                       $client_status['running'] = $graph_status->output;
+               }
+
+               $query_str = '?output=json';
+               $show = $this->getModule('api')->get(
+                       array('clients', $this->getClientId(), 'show', $query_str),
+               );
+               if ($show->error === 0) {
+                       $client_status['show'] = $show->output;
+               }
+
+               $this->getCallbackClient()->callClientFunction('init_graphical_client_status', array($client_status));
+       }
+
+       private function getClientVersion($output) {
+               $version = array('major' => 0, 'minor' => 0, 'release' => 0);
+               for ($i = 0; $i < count($output); $i++) {
+                       if (preg_match('/^[\w\d\s:.\-]+Version:\s+(?P<major>\d+)\.(?P<minor>\d+)\.(?P<release>\d+)\s+\(/', $output[$i], $match) === 1) {
+                               $version['major'] = intval($match['major']);
+                               $version['minor'] = intval($match['minor']);
+                               $version['release'] = intval($match['release']);
+                               break;
+                       }
+               }
+               return $version;
        }
 }
 ?>
index 4b0207cc99603f4f3430fb798f11cded39eb272f..414f1e7c492d3a79404614ba584dc8b8019e1276 100644 (file)
@@ -227,3 +227,15 @@ ul.new_element_menu li {
 ul.new_element_menu li a {
        text-decoration: none;
 }
+
+table.status_table tr {
+       height: 40px;
+}
+
+table.status_table td:nth-of-type(1) {
+       width: 35%;
+}
+
+table.status_table td, table.status_table td svg {
+       vertical-align: middle;
+}