*/
const PTYPE_REG_CMD = 0;
const PTYPE_API_CMD = 1;
- const PTYPE_CONFIRM_YES_CMD = 2;
+ const PTYPE_BG_CMD = 2;
+ const PTYPE_CONFIRM_YES_CMD = 3;
+ const PTYPE_CONFIRM_YES_BG_CMD = 4;
const BCONSOLE_COMMAND_PATTERN = "%s%s -c %s %s 2>&1 <<END_OF_DATA\ngui on\n%s\nquit\nEND_OF_DATA";
+ const BCONSOLE_BG_COMMAND_PATTERN = "echo 'gui on\n%s\nquit\n' | nohup %s%s -c %s %s >%s 2>&1 &";
+
const BCONSOLE_CONFIRM_YES_COMMAND_PATTERN = "%s%s -c %s %s 2>&1 <<END_OF_DATA\ngui on\n%s\nyes\nquit\nEND_OF_DATA";
+ const BCONSOLE_CONFIRM_YES_BG_COMMAND_PATTERN = "echo 'gui on\n%s\nyes\nquit\n' | nohup %s%s -c %s %s >%s 2>&1 &";
+
const BCONSOLE_API_COMMAND_PATTERN = "%s%s -c %s %s 2>&1 <<END_OF_DATA\ngui on\n.api 2 nosignal api_opts=o\n%s\nquit\nEND_OF_DATA";
const BCONSOLE_DIRECTORS_PATTERN = "%s%s -c %s -l 2>&1";
+ const OUTPUT_FILE_PREFIX = 'output_';
+
private $allowed_commands = array(
'version',
'status',
$dir = is_null($director) ? '': '-D ' . $director;
$sudo = ($this->getUseSudo() === true) ? self::SUDO . ' ' : '';
$bconsole_command = implode(' ', $command);
- $pattern = null;
- switch ($ptype) {
- case self::PTYPE_API_CMD: $pattern = self::BCONSOLE_API_COMMAND_PATTERN; break;
- case self::PTYPE_CONFIRM_YES_CMD: $pattern = self::BCONSOLE_CONFIRM_YES_COMMAND_PATTERN; break;
- default: $pattern = self::BCONSOLE_COMMAND_PATTERN;
- }
- $cmd = sprintf(
- $pattern,
- $sudo,
- self::getCmdPath(),
- self::getCfgPath(),
- $dir,
- $bconsole_command
- );
- exec($cmd, $output, $exitcode);
+ $pattern = $this->getCmdPattern($ptype);
+ $cmd = $this->getCommand($pattern, $sudo, $dir, $bconsole_command);
+ exec($cmd['cmd'], $output, $exitcode);
if($exitcode != 0) {
$emsg = ' Output=>' . implode("\n", $output) . ', Exitcode=>' . $exitcode;
throw new BConsoleException(
BconsoleError::ERROR_BCONSOLE_CONNECTION_PROBLEM
);
} else {
+ if ($pattern === self::BCONSOLE_BG_COMMAND_PATTERN || $pattern === self::BCONSOLE_CONFIRM_YES_BG_COMMAND_PATTERN) {
+ $output = array(
+ $bconsole_command,
+ json_encode(array('out_id' => $cmd['out_id'])),
+ 'quit' // in prepareResult() this value is deleted
+ );
+ }
$result = $this->prepareResult($output, $exitcode, $bconsole_command);
}
}
$this->Application->getModule('logging')->log(
- $cmd,
+ $cmd['cmd'],
$output,
Logging::CATEGORY_EXECUTE,
__FILE__,
return $result;
}
+ private function getCommand($pattern, $sudo, $director, $bconsole_command) {
+ $command = array('cmd' => null, 'out_id' => null);
+ if ($pattern === self::BCONSOLE_BG_COMMAND_PATTERN || $pattern === self::BCONSOLE_CONFIRM_YES_BG_COMMAND_PATTERN) {
+ $file = $this->prepareOutputFile();
+ $cmd = sprintf(
+ $pattern,
+ $bconsole_command,
+ $sudo,
+ self::getCmdPath(),
+ self::getCfgPath(),
+ $director,
+ $file
+ );
+ $command['cmd'] = $cmd;
+ $command['out_id'] = preg_replace('/^[\s\S]+\/output_/', '', $file);
+ } else {
+ $cmd = sprintf(
+ $pattern,
+ $sudo,
+ self::getCmdPath(),
+ self::getCfgPath(),
+ $director,
+ $bconsole_command
+ );
+ $command['cmd'] = $cmd;
+ $command['out_id'] = '';
+ }
+ return $command;
+ }
+
+ private function getCmdPattern($ptype) {
+ $pattern = null;
+ switch ($ptype) {
+ case self::PTYPE_API_CMD: $pattern = self::BCONSOLE_API_COMMAND_PATTERN; break;
+ case self::PTYPE_BG_CMD: $pattern = self::BCONSOLE_BG_COMMAND_PATTERN; break;
+ case self::PTYPE_CONFIRM_YES_CMD: $pattern = self::BCONSOLE_CONFIRM_YES_COMMAND_PATTERN; break;
+ case self::PTYPE_CONFIRM_YES_BG_CMD: $pattern = self::BCONSOLE_CONFIRM_YES_BG_COMMAND_PATTERN; break;
+ default: $pattern = self::BCONSOLE_COMMAND_PATTERN;
+ }
+ return $pattern;
+ }
+
public function getDirectors() {
$sudo = ($this->getUseSudo() === true) ? self::SUDO . ' ' : '';
$cmd = sprintf(
return in_array($director, $this->getDirectors()->output);
}
+ private function prepareOutputFile() {
+ $dir = Prado::getPathOfNamespace('Application.API.Config');
+ $fname = tempnam($dir, self::OUTPUT_FILE_PREFIX);
+ return $fname;
+ }
+
+ public static function readOutputFile($out_id) {
+ $output = array();
+ $dir = Prado::getPathOfNamespace('Application.API.Config');
+ if (preg_match('/^[a-z0-9]+$/i', $out_id) === 1) {
+ $file = $dir . '/' . self::OUTPUT_FILE_PREFIX . $out_id;
+ if (file_exists($file)) {
+ $output = file($file);
+ }
+ $output_count = count($output);
+ $last = $output_count > 0 ? trim($output[$output_count-1]) : '';
+ if ($last === 'quit') {
+ // output is complete, so remove the file
+ unlink($file);
+ }
+ }
+ return $output;
+ }
+
public function testBconsoleCommand(array $command, $cmd_path, $cfg_path, $use_sudo) {
$this->setEnvironmentParams($cmd_path, $cfg_path, $use_sudo, true);
$director = '';
foreach($volumes as $volume) {
$this->setWhenExpire($volume);
}
- } else {
+ } elseif (is_object($volumes)) {
$this->setWhenExpire($volumes);
}
}
--- /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.API.Class.Bconsole');
+
+class SlotsUpdate extends BaculumAPIServer {
+
+ public function get() {
+ $output = array();
+ $misc = $this->getModule('misc');
+ if ($this->Request->contains('out_id') && $misc->isValidAlphaNumeric($this->Request->itemAt('out_id'))) {
+ $out_id = $this->Request->itemAt('out_id');
+ $output = Bconsole::readOutputFile($out_id);
+ }
+ $this->output = $output;
+ $this->error = VolumeError::ERROR_NO_ERRORS;
+ }
+
+ public function set($id, $params) {
+ $slots = property_exists($params, 'slots') ? $params->slots : 0;
+ $drive = property_exists($params, 'drive') ? intval($params->drive) : 0;
+ $barcodes = ($this->Request->contains('barcodes') && $this->Request->itemAt('barcodes') === 'barcodes');
+ $misc = $this->getModule('misc');
+
+ $storage = null;
+ if (property_exists($params, 'storageid')) {
+ $storageid = intval($params->storageid);
+ $result = $this->getModule('storage')->getStorageById($storageid);
+ if (is_object($result)) {
+ $storage = $result->name;
+ }
+ } elseif (property_exists($params, 'storage') && $misc->isValidName($params->storage)) {
+ $storage = $params->storage;
+ }
+
+ if (!is_null($storage)) {
+ $result = $this->getModule('bconsole')->bconsoleCommand(
+ $this->director,
+ array('.storage')
+ );
+ if ($result->exitcode === 0) {
+ array_shift($result->output);
+ if (!in_array($storage, $result->output)) {
+ $this->output = StorageError::MSG_ERROR_STORAGE_DOES_NOT_EXISTS;
+ $this->error = StorageError::ERROR_STORAGE_DOES_NOT_EXISTS;
+ return;
+ }
+ } else {
+ $this->output = $result->output;
+ $this->error = $result->exitcode;
+ return;
+ }
+ } else {
+ $this->output = StorageError::MSG_ERROR_STORAGE_DOES_NOT_EXISTS;
+ $this->error = StorageError::ERROR_STORAGE_DOES_NOT_EXISTS;
+ return;
+ }
+
+ if (!$misc->isValidRange($slots)) {
+ $this->output = VolumeError::MSG_ERROR_INVALID_SLOT;
+ $this->error = VolumeError::ERROR_INVALID_SLOT;
+ return;
+ }
+
+ $cmd = array(
+ 'update',
+ 'slots',
+ 'storage="' . $storage . '"',
+ 'drive="' . $drive . '"',
+ 'slot="' . $slots . '"'
+ );
+
+ if ($barcodes === false) {
+ array_splice($cmd, 2, 0, array('scan'));
+ }
+
+ $result = $this->getModule('bconsole')->bconsoleCommand(
+ $this->director,
+ $cmd,
+ Bconsole::PTYPE_BG_CMD
+ );
+ array_shift($result->output);
+ if ($result->exitcode === 0) {
+ $this->output = $result->output;
+ $this->error = VolumeError::ERROR_NO_ERRORS;
+ } else {
+ $this->output = $result->output;
+ $this->error = $result->exitcode;
+ }
+ }
+}
+?>
class VolumeLabel extends BaculumAPIServer {
+ public function get() {
+ $output = array();
+ $misc = $this->getModule('misc');
+ if ($this->Request->contains('out_id') && $misc->isValidAlphaNumeric($this->Request->itemAt('out_id'))) {
+ $out_id = $this->Request->itemAt('out_id');
+ $output = Bconsole::readOutputFile($out_id);
+ }
+ $this->output = $output;
+ $this->error = VolumeError::ERROR_NO_ERRORS;
+ }
+
public function create($params) {
$volume = property_exists($params, 'volume') ? $params->volume : 0;
$slot = property_exists($params, 'slot') ? $params->slot : 0;
$drive = property_exists($params, 'drive') ? intval($params->drive) : 0;
- $poolid = property_exists($params, 'poolid') ? intval($params->poolid) : 0;
$misc = $this->getModule('misc');
if (!$misc->isValidName($volume)) {
return;
}
+ $result = $this->getModule('volume')->getVolumeByName($volume);
+ if (is_object($result)) {
+ $this->output = VolumeError::MSG_ERROR_VOLUME_ALREADY_EXISTS;
+ $this->error = VolumeError::ERROR_VOLUME_ALREADY_EXISTS;
+ return;
+ }
+
$cmd = array(
'label',
'volume="' . $volume . '"',
);
$result = $this->getModule('bconsole')->bconsoleCommand(
$this->director,
- $cmd
+ $cmd,
+ Bconsole::PTYPE_BG_CMD
);
+ array_shift($result->output);
if ($result->exitcode === 0) {
$this->output = $result->output;
$this->error = VolumeError::ERROR_NO_ERRORS;
class VolumeLabelBarcodes extends BaculumAPIServer {
+ public function get() {
+ $output = array();
+ $misc = $this->getModule('misc');
+ if ($this->Request->contains('out_id') && $misc->isValidAlphaNumeric($this->Request->itemAt('out_id'))) {
+ $out_id = $this->Request->itemAt('out_id');
+ $output = Bconsole::readOutputFile($out_id);
+ }
+ $this->output = $output;
+ $this->error = VolumeError::ERROR_NO_ERRORS;
+ }
+
public function create($params) {
$slots = property_exists($params, 'slots') ? $params->slots : 0;
$drive = property_exists($params, 'drive') ? intval($params->drive) : 0;
- $poolid = property_exists($params, 'poolid') ? intval($params->poolid) : 0;
$misc = $this->getModule('misc');
$storage = null;
$storage = $params->storage;
}
+ if (!$misc->isValidRange($slots)) {
+ $this->output = VolumeError::MSG_ERROR_INVALID_SLOT;
+ $this->error = VolumeError::ERROR_INVALID_SLOT;
+ return;
+ }
+
$pool = null;
if (property_exists($params, 'poolid')) {
$poolid = intval($params->poolid);
$result = $this->getModule('bconsole')->bconsoleCommand(
$this->director,
$cmd,
- Bconsole::PTYPE_CONFIRM_YES_CMD
+ Bconsole::PTYPE_CONFIRM_YES_BG_CMD
);
+ array_shift($result->output);
if ($result->exitcode === 0) {
$this->output = $result->output;
$this->error = VolumeError::ERROR_NO_ERRORS;
<url ServiceParameter="API.JobsOnVolume" pattern="api/v1/volumes/{id}/jobs/" parameters.id="\d+" />
<url ServiceParameter="API.VolumeLabel" pattern="api/v1/volumes/label/" />
<url ServiceParameter="API.VolumeLabelBarcodes" pattern="api/v1/volumes/label/barcodes/" />
+ <url ServiceParameter="API.SlotsUpdate" pattern="api/v1/volumes/update/" />
+ <url ServiceParameter="API.SlotsUpdate" pattern="api/v1/volumes/update/{barcodes}/" parameters.barcodes="barcodes" />
<!-- pools endpoints -->
<url ServiceParameter="API.Pools" pattern="api/v1/pools/" />
<url ServiceParameter="API.Pool" pattern="api/v1/pools/{id}/" parameters.id="\d+" />
const ERROR_VOLUME_DOES_NOT_EXISTS = 30;
const ERROR_INVALID_VOLUME = 31;
const ERROR_INVALID_SLOT = 32;
+ const ERROR_VOLUME_ALREADY_EXISTS = 33;
const MSG_ERROR_VOLUME_DOES_NOT_EXISTS = 'Volume does not exist.';
const MSG_ERROR_INVALID_VOLUME = 'Invalid volume.';
const MSG_ERROR_INVALID_SLOT = 'Invalid slot.';
+ const MSG_ERROR_VOLUME_ALREADY_EXISTS = 'Volume already exists.';
}
class PoolError extends GenericError {
return (preg_match('/^[\d\-\,]+$/', $range) === 1);
}
+ public function isValidAlphaNumeric($str) {
+ return (preg_match('/^[a-zA-Z0-9]+$/', $str) === 1);
+ }
+
/**
* Writing INI-style configuration file.
msgid "Use barcodes as label:"
msgstr "Use barcodes as label:"
-msgid "Slots for label:"
-msgstr "Slots for label:"
-
-msgid "Slots for update:"
-msgstr "Slots for update:"
-
msgid "Update barcodes slots"
msgstr "Update barcodes slots"
msgid "Schedule status"
msgstr "Schedule status"
+
+msgid "Slots to label (ex. 4 or 1-5 or 2,4,6-10):"
+msgstr "Slots to label (ex. 4 or 1-5 or 2,4,6-10):"
+
+msgid "Labeling status:"
+msgstr "Labeling status:"
+
+msgid "Ready to label"
+msgstr "Ready to label"
+
+msgid "Finished"
+msgstr "Finished"
+
+msgid "Updating status:"
+msgstr "Updating status:"
+
+msgid "Ready to update"
+msgstr "Ready to update"
+
+msgid "Updating..."
+msgstr "Updating..."
+
+msgid "Slots to update (ex. 4 or 1-5 or 2,4,6-10):"
+msgstr "Slots to update (ex. 4 or 1-5 or 2,4,6-10):"
msgid "Slots for label have to contain string value from set [0-9-,]."
msgstr "Slots for label have to contain string value from set [0-9-,]."
-msgid "Slots for label:"
-msgstr "Slots for label:"
-
msgid "Slots for update have to contain string value from set [0-9-,]."
msgstr "Slots for update have to contain string value from set [0-9-,]."
-msgid "Slots for update:"
-msgstr "Slots for update:"
-
msgid "Source parameters"
msgstr "ãƒªã‚¹ãƒˆã‚¢æƒ…å ±"
msgid "Schedule status"
msgstr "Schedule status"
+
+msgid "Slots to label (ex. 4 or 1-5 or 2,4,6-10):"
+msgstr "Slots to label (ex. 4 or 1-5 or 2,4,6-10):"
+
+msgid "Labeling status:"
+msgstr "Labeling status:"
+
+msgid "Ready to label"
+msgstr "Ready to label"
+
+msgid "Finished"
+msgstr "Finished"
+
+msgid "Updating status:"
+msgstr "Updating status:"
+
+msgid "Ready to update"
+msgstr "Ready to update"
+
+msgid "Updating..."
+msgstr "Updating..."
+
+msgid "Slots to update (ex. 4 or 1-5 or 2,4,6-10):"
+msgstr "Slots to update (ex. 4 or 1-5 or 2,4,6-10):"
msgid "Label name:"
msgstr "Nazwa etykiety:"
-msgid "Slots for label:"
-msgstr "Sloty do etykietowania:"
-
msgid "Label"
msgstr "Etykieta"
msgid "Update slots using barcodes"
msgstr "Aktualizuj sloty używając barcode"
-msgid "Slots for update:"
-msgstr "Sloty do aktualizacji"
-
msgid "Update barcodes slots"
msgstr "Aktualizuj sloty z etykietami barcode"
msgid "Schedule status"
msgstr "Status harmonogramu zadań"
+
+msgid "Slots to label (ex. 4 or 1-5 or 2,4,6-10):"
+msgstr "Sloty do etykietowania (np. 4 lub 1-5 lub 2,4,6-10):"
+
+msgid "Labeling status:"
+msgstr "Status etykietowania:"
+
+msgid "Ready to label"
+msgstr "Gotowy do etykietowania"
+
+msgid "Finished"
+msgstr "Zakończony"
+
+msgid "Updating status:"
+msgstr "Status aktualizowania:"
+
+msgid "Ready to update"
+msgstr "Gotowy do aktualizacji"
+
+msgid "Updating..."
+msgstr "Aktualizowanie..."
+
+msgid "Slots to update (ex. 4 or 1-5 or 2,4,6-10):"
+msgstr "Sloty do aktualizacji (np. 4 lub 1-5 lub 2,4,6-10):"
msgid "Use barcodes as label:"
msgstr "Usar código de barras como rótulos:"
-msgid "Slots for label:"
-msgstr "Slots para rotular:"
-
-msgid "Slots for update:"
-msgstr "Slots para atualizar:"
-
msgid "Update barcodes slots"
msgstr "Atualizar código de barras dos slots"
msgid "Schedule status"
msgstr "Schedule status"
+
+msgid "Slots to label (ex. 4 or 1-5 or 2,4,6-10):"
+msgstr "Slots para rotular (ex. 4 or 1-5 or 2,4,6-10):"
+
+msgid "Labeling status:"
+msgstr "Labeling status:"
+
+msgid "Ready to label"
+msgstr "Ready to label"
+
+msgid "Finished"
+msgstr "Finished"
+
+msgid "Updating status:"
+msgstr "Updating status:"
+
+msgid "Ready to update"
+msgstr "Ready to update"
+
+msgid "Updating..."
+msgstr "Updating..."
+
+msgid "Slots to update (ex. 4 or 1-5 or 2,4,6-10):"
+msgstr "Slots to update (ex. 4 or 1-5 or 2,4,6-10):"
'poolid' => $this->PoolLabel->SelectedValue
);
$result = $this->getModule('api')->create(array('volumes', 'label', 'barcodes'), $params);
+ if ($result->error === 0 && count($result->output) === 1) {
+ $out = json_decode($result->output[0]);
+ if (is_object($out) && property_exists($out, 'out_id')) {
+ $result = $this->getLabelBarcodesOutput($out->out_id);
+ $this->getPage()->getCallbackClient()->callClientFunction('label_volume_output_refresh', array($out->out_id));
+ }
+ }
} else {
$params = array(
'slot' => $this->SlotLabel->Text,
'poolid' => $this->PoolLabel->SelectedValue
);
$result = $this->getModule('api')->create(array('volumes', 'label'), $params);
+ if ($result->error === 0 && count($result->output) === 1) {
+ $out = json_decode($result->output[0]);
+ if (is_object($out) && property_exists($out, 'out_id')) {
+ $result = $this->getLabelOutput($out->out_id);
+ $this->getPage()->getCallbackClient()->callClientFunction('label_volume_output_refresh', array($out->out_id));
+ }
+ }
+ }
+ if ($result->error === 0) {
+ $this->getPage()->getCallbackClient()->callClientFunction('set_labeling_status', array('loading'));
+ $this->LabelVolumeLog->Text = implode('', $result->output);
+ } else {
+ $this->LabelVolumeLog->Text = $result->output;
+ }
+ }
+
+ private function getLabelOutput($out_id) {
+ $result = $this->getModule('api')->get(
+ array('volumes', 'label', '?out_id=' . rawurlencode($out_id))
+ );
+ return $result;
+ }
+
+ private function getLabelBarcodesOutput($out_id) {
+ $result = $this->getModule('api')->get(
+ array('volumes', 'label', 'barcodes', '?out_id=' . rawurlencode($out_id))
+ );
+ return $result;
+ }
+
+ public function refreshOutput($sender, $param) {
+ $out_id = $param->getCallbackParameter();
+ $result = null;
+ if ($this->Barcodes->Checked == true) {
+ $result = $this->getLabelBarcodesOutput($out_id);
+ } else {
+ $result = $this->getLabelOutput($out_id);
}
+
if ($result->error === 0) {
- $this->LabelVolumeLog->Text = implode(PHP_EOL, $result->output);
+ if (count($result->output) > 0) {
+ $this->LabelVolumeLog->Text = implode('', $result->output);
+ $this->getPage()->getCallbackClient()->callClientFunction('label_volume_output_refresh', array($out_id));
+ } else {
+ $this->getPage()->getCallbackClient()->callClientFunction('set_labeling_status', array('finish'));
+ }
} else {
$this->LabelVolumeLog->Text = $result->output;
}
<com:TActiveLinkButton
CssClass="w3-button w3-green"
- Attributes.onclick="document.getElementById('label_volume').style.display = 'block';"
OnClick="loadValues"
>
+ <prop:Attributes.onclick>
+ var logbox = document.getElementById('<%=$this->LabelVolumeLog->ClientID%>');
+ logbox.innerHTML = '';
+ var logbox_container = document.getElementById('label_volume_log');
+ logbox_container.style.display = 'none';
+ set_labeling_status('start');
+ document.getElementById('label_volume').style.display = 'block';
+ </prop:Attributes.onclick>
<i class="fa fa-tag"></i> <%[ Label volume(s) ]%>
</com:TActiveLinkButton>
</button>
</div>
</div>
<div id="label_with_barcodes" class="w3-row-padding w3-section" style="display: none">
- <div class="w3-col w3-half"><com:TLabel ForControl="SlotsLabel" Text="<%[ Slots for label: ]%>" /></div>
+ <div class="w3-col w3-half"><com:TLabel ForControl="SlotsLabel" Text="<%[ Slots to label (ex. 4 or 1-5 or 2,4,6-10): ]%>" /></div>
<div class="w3-col w3-half">
<com:TActiveTextBox ID="SlotsLabel" CssClass="w3-input w3-border" Text="0" />
<com:TRequiredFieldValidator
</com:TRequiredFieldValidator>
</div>
</div>
+ <div class="w3-row-padding w3-section">
+ <div class="w3-col w3-half"><%[ Labeling status: ]%></div>
+ <div class="w3-col w3-half">
+ <i id="label_status_start" class="fa fa-step-forward" title="<%[ Ready to label ]%>"></i>
+ <i id="label_status_loading" class="fa fa-sync w3-spin" style="display: none" title="<%[ Loading... ]%>"></i>
+ <i id="label_status_finish" class="fa fa-check" style="display: none" title="<%[ Finished ]%>"></i>
+ </div>
+ </div>
<div id="label_volume_log" class="w3-panel w3-card w3-light-grey" style="display: none; max-height: 200px; overflow-x: auto;">
<div class="w3-code notranslate">
<pre><com:TActiveLabel ID="LabelVolumeLog" /></pre>
ValidationGroup="LabelVolumeGroup"
OnClick="labelVolumes"
CssClass="w3-button w3-green"
- ClientSide.OnLoading="$('#status_label_volume_loading').show();"
- ClientSide.OnSuccess="$('#status_label_volume_loading').hide();$('#label_volume_log').show();"
+ ClientSide.OnLoading="$('#status_label_volume_loading').css('visibility', 'visible');"
>
+ <prop:ClientSide.OnComplete>
+ $('#status_label_volume_loading').css('visibility', 'hidden');
+ $('#label_volume_log').show();
+ var logbox = document.getElementById('label_volume_log');
+ logbox.scrollTo(0, logbox.scrollHeight);
+ </prop:ClientSide.OnComplete>
<i class="fa fa-tag"></i> <%[ Label ]%>
</com:TActiveLinkButton>
- <i id="status_label_volume_loading" class="fa fa-sync w3-spin" style="display: none;"></i>
+ <i id="status_label_volume_loading" class="fa fa-sync w3-spin" style="visibility: hidden;"></i>
</div>
</div>
</div>
</div>
+<com:TCallback ID="LabelVolumeOutputRefresh"
+ OnCallback="refreshOutput"
+>
+ <prop:ClientSide.OnLoading>
+ $('#status_label_volume_loading').css('visibility', 'visible');
+ var logbox = document.getElementById('label_volume_log');
+ if ((logbox.offsetHeight + logbox.scrollTop) === logbox.scrollHeight) {
+ label_volume_logbox_scroll = true;
+ } else {
+ label_volume_logbox_scroll = false;
+ }
+ </prop:ClientSide.OnLoading>
+ <prop:ClientSide.OnComplete>
+ $('#status_label_volume_loading').css('visibility', 'hidden');
+ if (label_volume_logbox_scroll) {
+ var logbox = document.getElementById('label_volume_log');
+ logbox.scrollTo(0, logbox.scrollHeight);
+ }
+ </prop:ClientSide.OnComplete>
+</com:TCallback>
<script type="text/javascript">
+var label_volume_logbox_scroll = false;
function set_barcodes() {
var chkb = document.getElementById('<%=$this->Barcodes->ClientID%>');
var name_el = document.getElementById('label_with_name');
name_el.style.display = 'block';
}
}
+
+function set_labeling_status(status) {
+ var start = document.getElementById('label_status_start');
+ var loading = document.getElementById('label_status_loading');
+ var finish = document.getElementById('label_status_finish');
+ if (status === 'finish') {
+ start.style.display = 'none';
+ loading.style.display = 'none';
+ finish.style.display = '';
+ } else if (status === 'loading') {
+ start.style.display = 'none';
+ loading.style.display = '';
+ finish.style.display = 'none';
+ } else if (status === 'start') {
+ start.style.display = '';
+ loading.style.display = 'none';
+ finish.style.display = 'none';
+ }
+}
+
+function label_volume_output_refresh(out_id) {
+ setTimeout(function() {
+ set_label_volume_output(out_id)
+ }, 3000);
+}
+
+function set_label_volume_output(out_id) {
+ var cb = <%=$this->LabelVolumeOutputRefresh->ActiveControl->Javascript%>;
+ cb.setCallbackParameter(out_id);
+ cb.dispatch();
+}
</script>
}
public function update($sender, $param) {
- $cmd = array('label');
- $cmd = array('update');
- $cmd[] = 'slots="' . $this->SlotsUpdate->Text . '"';
- if($this->Barcodes->Checked == false) {
- $cmd[] = 'scan';
+ $url_params = array();
+ if($this->Barcodes->Checked == true) {
+ $url_params = array('volumes', 'update', 'barcodes');
+ } else {
+ $url_params = array('volumes', 'update');
+ }
+ $params = array(
+ 'slots' => $this->SlotsUpdate->Text,
+ 'drive' => $this->DriveUpdate->Text,
+ 'storageid' => $this->StorageUpdate->SelectedValue
+ );
+
+ $result = $this->getModule('api')->set($url_params, $params);
+
+ if ($result->error === 0 && count($result->output) === 1) {
+ $out = json_decode($result->output[0]);
+ if (is_object($out) && property_exists($out, 'out_id')) {
+ $result = $this->getUpdateSlotsOutput($out->out_id);
+ $this->getPage()->getCallbackClient()->callClientFunction('update_slots_output_refresh', array($out->out_id));
+ }
}
- $cmd[] = 'drive="' . $this->DriveUpdate->Text . '"';
- $cmd[] = 'storage="'. $this->StorageUpdate->SelectedItem->Text . '"';
- $result = $this->getModule('api')->set(array('console'), $cmd);
if ($result->error === 0) {
- $this->UpdateSlotsLog->Text = implode(PHP_EOL, $result->output);
+ $this->getPage()->getCallbackClient()->callClientFunction('set_updating_status', array('loading'));
+ $this->UpdateSlotsLog->Text = implode('', $result->output);
+ } else {
+ $this->UpdateSlotsLog->Text = $result->output;
+ }
+ }
+
+ private function getUpdateSlotsOutput($out_id) {
+ $result = $this->getModule('api')->get(
+ array('volumes', 'update', '?out_id=' . rawurlencode($out_id))
+ );
+ return $result;
+ }
+
+ private function getUpdateSlotsBarcodesOutput($out_id) {
+ $result = $this->getModule('api')->get(
+ array('volumes', 'update', 'barcodes', '?out_id=' . rawurlencode($out_id))
+ );
+ return $result;
+ }
+
+ public function refreshOutput($sender, $param) {
+ $out_id = $param->getCallbackParameter();
+ $result = null;
+ if ($this->Barcodes->Checked == true) {
+ $result = $this->getUpdateSlotsBarcodesOutput($out_id);
+ } else {
+ $result = $this->getUpdateSlotsOutput($out_id);
+ }
+
+ if ($result->error === 0) {
+ if (count($result->output) > 0) {
+ $this->UpdateSlotsLog->Text = implode('', $result->output);
+ $this->getPage()->getCallbackClient()->callClientFunction('update_slots_output_refresh', array($out_id));
+ } else {
+ $this->getPage()->getCallbackClient()->callClientFunction('set_updating_status', array('finish'));
+ }
} else {
$this->UpdateSlotsLog->Text = $result->output;
}
<com:TActiveLinkButton
CssClass="w3-button w3-green"
- Attributes.onclick="document.getElementById('update_slots').style.display = 'block';"
OnClick="loadValues"
>
+ <prop:Attributes.onclick>
+ var logbox = document.getElementById('<%=$this->UpdateSlotsLog->ClientID%>');
+ logbox.innerHTML = '';
+ var logbox_container = document.getElementById('update_slots_log');
+ logbox_container.style.display = 'none';
+ set_updating_status('start');
+ document.getElementById('update_slots').style.display = 'block';
+ </prop:Attributes.onclick>
<i class="fa fa-retweet"></i> <%[ Update slots ]%>
</com:TActiveLinkButton>
</button>
<div class="w3-col w3-half"><com:TActiveDropDownList ID="StorageUpdate" CssClass="w3-select w3-border" /></div>
</div>
<div class="w3-row-padding w3-section">
- <div class="w3-col w3-half"><com:TLabel ForControl="SlotsUpdate" Text="<%[ Slots for update: ]%>" /></div>
+ <div class="w3-col w3-half"><com:TLabel ForControl="SlotsUpdate" Text="<%[ Slots to update (ex. 4 or 1-5 or 2,4,6-10): ]%>" /></div>
<div class="w3-col w3-half">
<com:TActiveTextBox ID="SlotsUpdate" CssClass="w3-input w3-border" Text="0" />
<com:TRequiredFieldValidator
/>
</div>
</div>
+ <div class="w3-row-padding w3-section">
+ <div class="w3-col w3-half"><%[ Updating status: ]%></div>
+ <div class="w3-col w3-half">
+ <i id="update_slots_status_start" class="fa fa-step-forward" title="<%[ Ready to update ]%>"></i>
+ <i id="update_slots_status_loading" class="fa fa-sync w3-spin" style="display: none" title="<%[ Updating... ]%>"></i>
+ <i id="update_slots_status_finish" class="fa fa-check" style="display: none" title="<%[ Finished ]%>"></i>
+ </div>
+ </div>
<div id="update_slots_log" class="w3-panel w3-card w3-light-grey" style="display: none; max-height: 200px; overflow-x: auto;">
<div class="w3-code notranslate">
<pre><com:TActiveLabel ID="UpdateSlotsLog" /></pre>
OnClick="update"
CssClass="w3-button w3-green"
ClientSide.OnLoading="$('#status_update_slots_loading').show();"
- ClientSide.OnSuccess="$('#status_update_slots_loading').hide();$('#update_slots_log').show();"
>
+ <prop:ClientSide.OnComplete>
+ $('#status_update_slots_loading').css('visibility', 'hidden');
+ $('#update_slots_log').show();
+ var logbox = document.getElementById('update_slots_log');
+ logbox.scrollTo(0, logbox.scrollHeight);
+ </prop:ClientSide.OnComplete>
<i class="fa fa-retweet"></i> <%[ Update slots ]%>
</com:TActiveLinkButton>
- <i id="status_update_slots_loading" class="fa fa-sync w3-spin" style="display: none;"></i>
+ <i id="status_update_slots_loading" class="fa fa-sync w3-spin" style="visibility: hidden;"></i>
</div>
</div>
</div>
</div>
+<com:TCallback ID="UpdateSlotsOutputRefresh"
+ OnCallback="refreshOutput"
+>
+ <prop:ClientSide.OnLoading>
+ $('#status_update_slots_loading').css('visibility', 'visible');
+ var logbox = document.getElementById('update_slots_log');
+ if ((logbox.offsetHeight + logbox.scrollTop) === logbox.scrollHeight) {
+ update_slots_logbox_scroll = true;
+ } else {
+ update_slots_logbox_scroll = false;
+ }
+ </prop:ClientSide.OnLoading>
+ <prop:ClientSide.OnComplete>
+ $('#status_update_slots_loading').css('visibility', 'hidden');
+ if (update_slots_logbox_scroll) {
+ var logbox = document.getElementById('update_slots_log');
+ logbox.scrollTo(0, logbox.scrollHeight);
+ }
+ </prop:ClientSide.OnComplete>
+</com:TCallback>
+<script type="text/javascript">
+var update_slots_logbox_scroll = false;
+function set_updating_status(status) {
+ var start = document.getElementById('update_slots_status_start');
+ var loading = document.getElementById('update_slots_status_loading');
+ var finish = document.getElementById('update_slots_status_finish');
+ if (status === 'finish') {
+ start.style.display = 'none';
+ loading.style.display = 'none';
+ finish.style.display = '';
+ } else if (status === 'loading') {
+ start.style.display = 'none';
+ loading.style.display = '';
+ finish.style.display = 'none';
+ } else if (status === 'start') {
+ start.style.display = '';
+ loading.style.display = 'none';
+ finish.style.display = 'none';
+ }
+}
+
+function update_slots_output_refresh(out_id) {
+ setTimeout(function() {
+ set_update_slots_output(out_id)
+ }, 3000);
+}
+
+function set_update_slots_output(out_id) {
+ var cb = <%=$this->UpdateSlotsOutputRefresh->ActiveControl->Javascript%>;
+ cb.setCallbackParameter(out_id);
+ cb.dispatch();
+}
+</script>