class BClientScript extends TClientScript {
- const SCRIPTS_VERSION = 2;
+ const SCRIPTS_VERSION = 3;
public function getScriptUrl()
{
}
var ret = {value: time_seconds, format: f};
return ret;
+ },
+ format_date: function(timestamp) {
+ if (typeof(timestamp) === 'string') {
+ timestamp = parseInt(timestamp, 10);
+ }
+ if (timestamp < 9999999999) {
+ timestamp *= 1000;
+ }
+ var d = new Date(timestamp);
+ var date = [d.getFullYear(), ('0' + (d.getMonth()+1)).slice(-2), ('0' + d.getDate()).slice(-2)].join('-');
+ var time = [d.getHours(), ('0' + d.getMinutes()).slice(-2), ('0' + d.getSeconds()).slice(-2)].join(':');
+ return (date + ' ' + time);
}
}
msgid "Add plugin"
msgstr "Add plugin"
+
+msgid "Job schedules"
+msgstr "Job schedules"
+
+msgid "Priority"
+msgstr "Priority"
+
+msgid "Scheduled"
+msgstr "Scheduled"
+
+msgid "FileSet"
+msgstr "FileSet"
+
+msgid "Filters:"
+msgstr "Filters:"
+
+msgid "Date from:"
+msgstr "Date from:"
+
+msgid "Days:"
+msgstr "Days:"
+
+msgid "Apply filters"
+msgstr "Apply filters"
+
+msgid "You must enter an integer."
+msgstr "You must enter an integer."
+
+msgid "Invalid date format."
+msgstr "Invalid date format."
+
+msgid "Input must be between 1 and 1000."
+msgstr "Input must be between 1 and 1000."
+
+msgid "Schedule status"
+msgstr "Schedule status"
msgid "Plugins"
msgstr "Plugins"
+
+msgid "Job schedules"
+msgstr "Job schedules"
+
+msgid "Priority"
+msgstr "Priority"
+
+msgid "Scheduled"
+msgstr "Scheduled"
+
+msgid "FileSet"
+msgstr "FileSet"
+
+msgid "Filters:"
+msgstr "Filters:"
+
+msgid "Date from:"
+msgstr "Date from:"
+
+msgid "Days:"
+msgstr "Days:"
+
+msgid "Apply filters"
+msgstr "Apply filters"
+
+msgid "You must enter an integer."
+msgstr "You must enter an integer."
+
+msgid "Invalid date format."
+msgstr "Invalid date format."
+
+msgid "Input must be between 1 and 1000."
+msgstr "Input must be between 1 and 1000."
+
+msgid "Schedule status"
+msgstr "Schedule status"
msgid "Plugins"
msgstr "Wtyczki"
+
+msgid "Job schedules"
+msgstr "Harmonogramy zadania"
+
+msgid "Priority"
+msgstr "Priorytet"
+
+msgid "Scheduled"
+msgstr "Zaplanowane"
+
+msgid "FileSet"
+msgstr "FileSet"
+
+msgid "Filters:"
+msgstr "Filtry:"
+
+msgid "Date from:"
+msgstr "Data od:"
+
+msgid "Days:"
+msgstr "Dni:"
+
+msgid "Apply filters"
+msgstr "Zastosuj filtry"
+
+msgid "You must enter an integer."
+msgstr "Musisz wprowadzić liczbę całkowitą."
+
+msgid "Invalid date format."
+msgstr "Niepoprawny format daty."
+
+msgid "Input must be between 1 and 1000."
+msgstr "Pole musi mieć wartość z zakresu 1-1000."
+
+msgid "Schedule status"
+msgstr "Status harmonogramu zadań"
msgid "Plugins"
msgstr "Plugins"
+
+msgid "Job schedules"
+msgstr "Job schedules"
+
+msgid "Priority"
+msgstr "Priority"
+
+msgid "Scheduled"
+msgstr "Scheduled"
+
+msgid "FileSet"
+msgstr "FileSet"
+
+msgid "Filters:"
+msgstr "Filters:"
+
+msgid "Date from:"
+msgstr "Date from:"
+
+msgid "Days:"
+msgstr "Days:"
+
+msgid "Apply filters"
+msgstr "Apply filters"
+
+msgid "You must enter an integer."
+msgstr "You must enter an integer."
+
+msgid "Invalid date format."
+msgstr "Invalid date format."
+
+msgid "Input must be between 1 and 1000."
+msgstr "Input must be between 1 and 1000."
+
+msgid "Schedule status"
+msgstr "Schedule status"
OnClick="loadScheduleConfig"
CommandParameter="show"
/>
+ <com:TActiveLinkButton
+ CssClass="w3-bar-item w3-button tab_btn"
+ Text="<%[ Job schedules ]%>"
+ OnCallback="loadSchedules"
+ CommandParameter="show"
+ Attributes.onclick="W3Tabs.open(this.id, 'job_schedules'); clear_node('#job_config div.directive_field'); clear_node('#fileset_config div.directive_field'); clear_node('#schedule_config div.directive_field');"
+ />
</div>
<div class="w3-container tab_item" id="job_actions">
<com:TActiveLinkButton
ShowCancelButton="false"
/>
</div>
+ <div class="w3-container tab_item" id="job_schedules" style="display: none">
+ <com:Application.Web.Portlets.StatusSchedule
+ ID="Schedules"
+ />
+ </div>
</com:TContent>
}
$this->RunJobModal->setJobName($job_name);
$this->setJobName($job_name);
+ $this->Schedules->setJob($job_name);
+ $this->Schedules->setDays(90);
}
/**
$this->ScheduleConfig->raiseEvent('OnDirectiveListLoad', $this, null);
}
}
+
+ public function loadSchedules($sender, $param) {
+ $this->Schedules->loadSchedules();
+ }
}
?>
</header>
<div class="w3-margin-left w3-margin-bottom">
<button type="button" class="w3-button w3-green<%=empty($_SESSION['dir']) ? ' hide': ''%>" onclick="document.location.href='<%=$this->Service->constructUrl('NewResource', array('component_type' => 'dir', 'component_name' => $_SESSION['dir'], 'resource_type' => 'Schedule'))%>';"><i class="fa fa-plus"></i> <%[ Add schedule ]%></button>
+ <button type="button" class="w3-button w3-green" onclick="document.location.href='<%=$this->Service->constructUrl('ScheduleStatusList')%>';"><i class="fa fa-clock"></i> <%[ Schedule status ]%></button>
</div>
<div class="w3-container">
<table id="schedule_list" class="w3-table w3-striped w3-hoverable w3-white w3-margin-bottom">
--- /dev/null
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum - Bacula web interface
+ *
+ * Copyright (C) 2013-2019 Kern Sibbald
+ *
+ * The main author of Baculum is Marcin Haba.
+ * The original author of Bacula is Kern Sibbald, with contributions
+ * from many others, a complete list can be found in the file AUTHORS.
+ *
+ * You may use this file and others of this release according to the
+ * license defined in the LICENSE file, which includes the Affero General
+ * Public License, v3.0 ("AGPLv3") and some additional permissions and
+ * terms pursuant to its AGPLv3 Section 7.
+ *
+ * This notice must be preserved when any source code is
+ * conveyed and/or propagated.
+ *
+ * Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+
+Prado::using('Application.Web.Class.BaculumWebPage');
+
+class ScheduleStatusList extends BaculumWebPage {
+}
+?>
--- /dev/null
+<%@ MasterClass="Application.Web.Layouts.Main" Theme="Baculum-v2"%>
+<com:TContent ID="Main">
+ <com:Application.Web.Portlets.StatusSchedule
+ ShowClientFilter="true"
+ ShowScheduleFilter="true"
+ />
+</com:TContent>
--- /dev/null
+<?php
+/*
+ * Bacula(R) - The Network Backup Solution
+ * Baculum - Bacula web interface
+ *
+ * Copyright (C) 2013-2019 Kern Sibbald
+ *
+ * The main author of Baculum is Marcin Haba.
+ * The original author of Bacula is Kern Sibbald, with contributions
+ * from many others, a complete list can be found in the file AUTHORS.
+ *
+ * You may use this file and others of this release according to the
+ * license defined in the LICENSE file, which includes the Affero General
+ * Public License, v3.0 ("AGPLv3") and some additional permissions and
+ * terms pursuant to its AGPLv3 Section 7.
+ *
+ * This notice must be preserved when any source code is
+ * conveyed and/or propagated.
+ *
+ * Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+
+Prado::using('System.Web.UI.JuiControls.TJuiDatePicker');
+Prado::using('System.Web.UI.ActiveControls.TActiveLinkButton');
+Prado::using('Application.Web.Portlets.Portlets');
+
+class StatusSchedule extends Portlets {
+
+ const JOB = 'Job';
+ const CLIENT = 'Client';
+ const SCHEDULE = 'Schedule';
+ const DAYS = 'Days';
+ const LIMIT = 'Limit';
+ const TIME = 'Time';
+ const SHOW_CLIENT_FILTER = 'ShowClientFilter';
+ const SHOW_SCHEDULE_FILTER = 'ShowScheduleFilter';
+
+ public $schedules = array();
+
+ public function onLoad($param) {
+ parent::onLoad($param);
+ if ($this->getPage()->IsCallBack || $this->getPage()->IsPostBack) {
+ return;
+ }
+ $this->loadSchedules();
+ $this->DatePicker->setDate(date('Y-m-d'));
+
+ if ($this->getShowClientFilter()) {
+ $clients = $this->getClients();
+ $this->Client->DataSource = array_combine($clients, $clients);
+ $this->Client->dataBind();
+ } else {
+ $this->Client->Visible = false;
+ }
+
+ if ($this->getShowScheduleFilter()) {
+ $schedules = $this->getSchedules();
+ $this->Schedule->DataSource = array_combine($schedules, $schedules);
+ $this->Schedule->dataBind();
+ } else {
+ $this->Schedule->Visible = false;
+ }
+ }
+
+ public function loadSchedules() {
+ $query = array();
+ $job = $this->getJob();
+ if (!empty($job)) {
+ $query[] = 'job=' . rawurlencode($job);
+ }
+ $client = $this->getClient();
+ if (!empty($client)) {
+ $query[] = 'client=' . rawurlencode($client);
+ }
+ $schedule = $this->getSchedule();
+ if (!empty($schedule)) {
+ $query[] = 'schedule=' . rawurlencode($schedule);
+ }
+ $days = $this->getDays();
+ if (!empty($days)) {
+ $query[] = 'days=' . $days;
+ }
+ $limit = $this->getLimit();
+ if (!empty($limit)) {
+ $query[] = 'limit=' . $limit;
+ }
+ $time = $this->getTime();
+ if (!empty($time)) {
+ $query[] = 'time=' . rawurlencode($time);
+ }
+ $params = array('schedules', 'status');
+ if (count($query) > 0) {
+ $params[] = '?' . implode('&', $query);
+ }
+
+ $result = $this->getModule('api')->get($params);
+ if ($result->error === 0) {
+ $schedules = $result->output;
+ if ($this->getPage()->IsCallBack) {
+ $this->getpage()->getcallbackclient()->callclientfunction(
+ 'set_job_schedule_data',
+ json_encode($schedules)
+ );
+ $this->getpage()->getcallbackclient()->callclientfunction(
+ 'init_job_schedule'
+ );
+ } else {
+ $this->schedules = $schedules;
+ }
+ }
+ }
+
+ public function getClients() {
+ $clients = array('');
+ $result = $this->getModule('api')->get(array('clients'));
+ if ($result->error === 0) {
+ for ($i = 0; $i < count($result->output); $i++) {
+ $clients[] = $result->output[$i]->name;
+ }
+ }
+ return $clients;
+ }
+
+ public function getSchedules() {
+ $schedules = array();
+ $result = $this->getModule('api')->get(array('schedules', 'resnames'));
+ if ($result->error === 0) {
+ $schedules = $result->output;
+ array_unshift($schedules, '');
+ }
+ return $schedules;
+ }
+
+ public function applyFilters($sender, $param) {
+ $time = $this->DatePicker->getDate() . ' 00:00:00';
+ $this->setTime($time);
+
+ $days = intval($this->Days->Text);
+ $this->setDays($days);
+
+ if ($this->getShowClientFilter()) {
+ $this->setClient($this->Client->SelectedValue);
+ }
+
+ if ($this->getShowScheduleFilter()) {
+ $this->setSchedule($this->Schedule->SelectedValue);
+ }
+
+ $this->loadSchedules();
+ }
+
+ public function setJob($job) {
+ $this->setViewState(self::JOB, $job);
+ }
+
+ public function getJob() {
+ return $this->getViewState(self::JOB);
+ }
+
+
+ public function setClient($client) {
+ $this->setViewState(self::CLIENT, $client);
+ }
+
+ public function getClient() {
+ return $this->getViewState(self::CLIENT);
+ }
+
+ public function setSchedule($schedule) {
+ $this->setViewState(self::SCHEDULE, $schedule);
+ }
+
+ public function getSchedule() {
+ return $this->getViewState(self::SCHEDULE);
+ }
+
+ public function setDays($days) {
+ $this->setViewState(self::DAYS, $days);
+ }
+
+ public function getDays() {
+ return $this->getViewState(self::DAYS);
+ }
+
+ public function setLimit($limit) {
+ $this->setViewState(self::LIMIT, $limit);
+ }
+
+ public function getLimit() {
+ return $this->getViewState(self::LIMIT);
+ }
+
+ public function setTime($time) {
+ $this->setViewState(self::TIME, $time);
+ }
+
+ public function getTime() {
+ return $this->getViewState(self::TIME);
+ }
+
+ public function setShowClientFilter($show) {
+ $show = TPropertyValue::ensureBoolean($show);
+ $this->setViewState(self::SHOW_CLIENT_FILTER, $show);
+ }
+
+ public function getShowClientFilter() {
+ return $this->getViewState(self::SHOW_CLIENT_FILTER, false);
+ }
+
+ public function setShowScheduleFilter($show) {
+ $show = TPropertyValue::ensureBoolean($show);
+ $this->setViewState(self::SHOW_SCHEDULE_FILTER, $show);
+ }
+
+ public function getShowScheduleFilter() {
+ return $this->getViewState(self::SHOW_SCHEDULE_FILTER, false);
+ }
+}
+?>
--- /dev/null
+<!-- Header -->
+<header class="w3-container">
+ <h5>
+ <b><i class="fa fa-clock"></i> <%[ Schedule status ]%></b>
+ </h5>
+</header>
+<div class="w3-container">
+ <div class="w3-card-4 w3-padding w3-margin-bottom">
+ <strong><%[ Filters: ]%></strong>
+ <%[ Date from: ]%> <com:TJuiDatePicker
+ ID="DatePicker"
+ Options.dateFormat="yy-mm-dd"
+ Options.changeYear="true",
+ Options.changeMonth="true"
+ Options.showAnim="fold"
+ Style.Width="100px"
+ />
+ <com:TRequiredFieldValidator
+ ValidationGroup="ScheduleFilters"
+ ControlToValidate="DatePicker"
+ Text="<%[ Field required. ]%>"
+ Display="Dynamic"
+ />
+ <com:TRegularExpressionValidator
+ ValidationGroup="ScheduleFilters"
+ ControlToValidate="DatePicker"
+ RegularExpression="\d{4}-\d{2}-\d{2}"
+ Text="<%[ Invalid date format. ]%>"
+ Display="Dynamic"
+ />
+ <%[ Days: ]%> <com:TTextBox
+ ID="Days"
+ Style.Width="50px"
+ Text="90"
+ />
+ <com:TRequiredFieldValidator
+ ValidationGroup="ScheduleFilters"
+ ControlToValidate="Days"
+ Text="<%[ Field required. ]%>"
+ Display="Dynamic"
+ />
+ <com:TDataTypeValidator
+ ValidationGroup="ScheduleFilters"
+ ControlToValidate="Days"
+ DataType="Integer"
+ Text="<%[ You must enter an integer. ]%>"
+ Display="Dynamic"
+ />
+ <com:TRangeValidator
+ ValidationGroup="ScheduleFilters"
+ ControlToValidate="Days"
+ DataType="Integer"
+ MinValue="1"
+ MaxValue="1000"
+ Text="<%[ Input must be between 1 and 1000. ]%>"
+ Display="Dynamic"
+ />
+ <com:TLabel
+ ID="ClientLabel"
+ ForControl="Client"
+ Text="<%[ Client: ]%>"
+ /> <com:TDropDownList
+ ID="Client"
+ Style.Width="150px"
+ />
+ <com:TLabel
+ ID="ScheduleLabel"
+ ForControl="Schedule"
+ Text="<%[ Schedule: ]%>"
+ />
+ <com:TDropDownList
+ ID="Schedule"
+ Style.Width="150px"
+ />
+ <com:TActiveLinkButton
+ ID="ApplyFilter"
+ CausesValidation="true"
+ ValidationGroup="ScheduleFilters"
+ CssClass="w3-green w3-button w3-margin-left"
+ OnClick="applyFilters"
+ >
+ <i class="fa fa-check"></i> <%[ Apply filters ]%>
+ </com:TActiveLinkButton>
+ </div>
+ <table id="schedule_list" class="w3-table w3-striped w3-hoverable w3-white w3-margin-bottom" style="width: 100%">
+ <thead>
+ <tr>
+ <th></th>
+ <th><%[ Level ]%></th>
+ <th><%[ Type ]%></th>
+ <th><%[ Priority ]%></th>
+ <th><%[ Scheduled ]%></th>
+ <%=empty($this->getJob()) ? '<th>' . Prado::localize('Job name') . '</th>': ''%>
+ <th><%[ Client ]%></th>
+ <th><%[ FileSet ]%></th>
+ <th><%[ Schedule ]%></th>
+ </tr>
+ </thead>
+ <tbody id="schedule_list_body">
+ </tbody>
+ </table>
+</div>
+<script type="text/javascript">
+var oJobScheduleList = {
+ table: null,
+ data: <%=json_encode($this->schedules)%>,
+ ids: {
+ schedule_list: 'schedule_list',
+ schedule_list_body: 'schedule_list_body'
+ },
+ init: function() {
+ this.set_table();
+ },
+ set_data(data) {
+ data = JSON.parse(data);
+ this.data = data;
+ },
+ get_data(data) {
+ return this.data;
+ },
+ set_table: function() {
+ this.table = $('#' + this.ids.schedule_list).DataTable({
+ data: this.get_data(),
+ deferRender: true,
+ columns: [
+ {
+ className: 'details-control',
+ orderable: false,
+ data: null,
+ defaultContent: '<button type="button" class="w3-button w3-blue"><i class="fa fa-angle-down"></i></button>'
+ },
+ {
+ data: 'level',
+ render: function(data, type, row) {
+ var ret;
+ if (!data) {
+ ret = '-';
+ } else {
+ ret = JobLevel.get_level(data);
+ }
+ return ret;
+ }
+ },
+ {
+ data: 'type',
+ render: function(data, type, row) {
+ return JobType.get_type(data);
+ }
+ },
+ {data: 'priority'},
+ {
+ data: 'schedtime_epoch',
+ render: function(data, type, row) {
+ return Units.format_date(data);
+ }
+ },
+ <%=empty($this->getJob()) ? '{data: "name"},' : ''%>
+ {data: 'client'},
+ {data: 'fileset'},
+ {data: 'schedule'}
+ ],
+ responsive: {
+ details: {
+ type: 'column'
+ }
+ },
+ columnDefs: [{
+ className: 'control',
+ orderable: false,
+ targets: 0
+ },
+ {
+ className: "dt-center",
+ targets: [ 1, 3 ]
+ }],
+ order: [4, 'asc']
+ });
+ }
+};
+
+function set_job_schedule_data(data) {
+ oJobScheduleList.set_data(data);
+}
+function init_job_schedule() {
+ if (oJobScheduleList.table) {
+ oJobScheduleList.table.destroy();
+ }
+ oJobScheduleList.init();
+}
+<%=count($this->schedules) > 0 ? 'init_job_schedule();' : ''%>
+</script>
<url ServiceParameter="FileSetList" pattern="web/fileset/" />
<url ServiceParameter="FileSetView" pattern="web/fileset/{fileset}/" parameters.fileset="[a-zA-Z0-9:.\-_ ]+" />
<url ServiceParameter="ScheduleList" pattern="web/schedule/" />
+ <url ServiceParameter="ScheduleStatusList" pattern="web/schedule/status/" />
<url ServiceParameter="ScheduleView" pattern="web/schedule/{schedule}/" parameters.schedule="[a-zA-Z0-9:.\-_ ]+" />
<url ServiceParameter="Graphs" pattern="web/graphs/" />
<url ServiceParameter="Console" pattern="web/console/" />