";
echo "
".__("Rack stats")."
";
echo "
";
echo "
".__("Space")."
";
Html::progressBar('rack_space', [
'create' => true,
'percent' => $space_prct,
'message' => $space_prct."%",
]);
echo "".__("Weight")."
";
Html::progressBar('rack_weight', [
'create' => true,
'percent' => $weight_prct,
'message' => $weight." / ".$rack->fields['max_weight']
]);
echo "".__("Power")."
";
Html::progressBar('rack_power', [
'create' => true,
'percent' => $power_prct,
'message' => $power." / ".$rack->fields['max_power']
]);
echo "";
echo "
";
}
function showForm($ID, $options = []) {
global $DB, $CFG_GLPI;
$colspan = 4;
echo "";
$this->initForm($ID, $options);
$this->showFormHeader();
$rack = new Rack();
$rack->getFromDB($this->fields['racks_id']);
$rand = mt_rand();
echo "
";
echo " | ";
echo "";
if (isset($options['_onlypdu']) && $options['_onlypdu']) {
$this->fields['itemtype'] = 'PDU';
echo Html::hidden(
'itemtype',
[
'id' => "itemtype_$rand",
'value' => 'PDU'
]
);
echo PDU::getTypeName(1);
} else {
$types = array_combine($CFG_GLPI['rackable_types'], $CFG_GLPI['rackable_types']);
foreach ($types as $type => &$text) {
$text = $type::getTypeName(1);
}
Dropdown::showFromArray(
'itemtype',
$types, [
'display_emptychoice' => true,
'value' => $this->fields["itemtype"],
'rand' => $rand
]
);
}
//get all used items
$used = $used_reserved = [];
$iterator = $DB->request([
'FROM' => $this->getTable()
]);
while ($row = $iterator->next()) {
$used[$row['itemtype']][] = $row['items_id'];
}
// find used pdu (not racked)
foreach (PDU_Rack::getUsed() as $used_pdu) {
$used['PDU'][] = $used_pdu['pdus_id'];
}
// get all reserved items
$iterator = $DB->request([
'FROM' => $this->getTable(),
'WHERE' => [
'is_reserved' => true
]
]);
while ($row = $iterator->next()) {
$used_reserved[$row['itemtype']][] = $row['items_id'];
}
//items part of an enclosure should not be listed
$iterator = $DB->request([
'FROM' => Item_Enclosure::getTable()
]);
while ($row = $iterator->next()) {
$used[$row['itemtype']][] = $row['items_id'];
}
echo Html::hidden(
'used',
[
'id' => "used_$rand",
'value' => json_encode($used)
]
);
//TODO: update possible positions according to selected item number of units
//TODO: update positions on rack selection
//TODO: update hpos from item model info is_half_rack
//TODO: update orientation according to item model depth
echo " | ";
echo " | ";
echo "";
if (isset($this->fields['itemtype']) && !empty($this->fields['itemtype'])) {
$itemtype = $this->fields['itemtype'];
$itemtype = new $itemtype();
$itemtype::dropdown([
'name' => "items_id",
'value' => $this->fields['items_id'],
'rand' => $rand
]);
} else {
Dropdown::showFromArray(
'items_id',
[], [
'display_emptychoice' => true,
'rand' => $rand
]
);
}
echo " | ";
echo "
";
echo "
";
echo " | ";
echo "";
Rack::dropdown(['value' => $this->fields["racks_id"], 'rand' => $rand]);
echo " | ";
echo " | ";
echo "";
Dropdown::showNumber(
'position', [
'value' => $this->fields["position"],
'min' => 1,
'max' => $rack->fields['number_units'],
'step' => 1,
'used' => $rack->getFilled($this->fields['itemtype'], $this->fields['items_id']),
'rand' => $rand
]
);
echo " | ";
echo "
";
echo "
";
echo " | ";
echo "";
Dropdown::showFromArray(
'orientation', [
Rack::FRONT => __('Front'),
Rack::REAR => __('Rear')
], [
'value' => $this->fields["orientation"],
'rand' => $rand
]
);
echo " | ";
echo " | ";
echo "";
Html::showColorField(
'bgcolor', [
'value' => $this->fields['bgcolor'],
'rand' => $rand
]
);
echo " | ";
echo "
";
echo "
";
echo " | ";
echo "";
Dropdown::showFromArray(
'hpos',
[
Rack::POS_NONE => __('None'),
Rack::POS_LEFT => __('Left'),
Rack::POS_RIGHT => __('Right')
], [
'value' => $this->fields['hpos'],
'rand' => $rand
]
);
echo " | ";
echo " | ";
echo "";
echo Html::scriptBlock("
var toggleUsed = function(reserved) {
if (reserved == 1) {
$('#used_$rand').val('".json_encode($used_reserved)."');
} else {
$('#used_$rand').val('".json_encode($used)."');
}
// force change of itemtype dropdown to have a correct (with empty/filled used input)
// filtered items list
$('#dropdown_itemtype$rand').trigger('change');
}
");
Dropdown::showYesNo(
'is_reserved',
$this->fields['is_reserved'],
-1, [
'rand' => $rand,
'on_change' => 'toggleUsed(this.value)'
]
);
$entities = $rack->fields['entities_id'];
if ($rack->fields['is_recursive']) {
$entities = getSonsOf('glpi_entities', $entities);
}
Ajax::updateItemOnSelectEvent(
["dropdown_itemtype$rand", "dropdown_is_reserved$rand", "used_$rand"],
"items_id",
$CFG_GLPI["root_doc"]."/ajax/dropdownAllItems.php", [
'idtable' => '__VALUE0__',
'name' => 'items_id',
'value' => $this->fields['items_id'],
'rand' => $rand,
'is_reserved' => '__VALUE1__',
'used' => '__VALUE2__',
'entity_restrict' => $entities,
]
);
echo " | ";
echo "
";
$this->showFormButtons($options);
}
function post_getEmpty() {
$this->fields['bgcolor'] = '#69CEBA';
}
/**
* Get cell content
*
* @param mixed $cell Rack cell (array or false)
*
* @return string
*/
private static function getCell($cell) {
if ($cell) {
$item = $cell['item'];
$gs_item = $cell['gs_item'];
$name = $gs_item['name'];
$typename = is_object($item)
? $item->getTypeName()
: "";
$serial = is_object($item)
? $item->fields['serial']
: "";
$otherserial = is_object($item)
? $item->fields['otherserial']
: "";
$model = is_object($item)
&& is_object($item->model)
&& isset($item->model->fields['name'])
? $item->model->fields['name']
: '';
$rear = $gs_item['rear'];
$back_class = $rear
? "item_rear"
: "item_front";
$half_class = $gs_item['half_rack']
? "half_rack"
: "";
$reserved = $gs_item['reserved'];
$reserved_cl = $reserved
? "reserved"
: "";
$icon = $reserved
? self::getItemIcon("Reserved")
: self::getItemIcon(get_class($item));
$bg_color = $gs_item['bgcolor'];
if ($item->maybeDeleted() && $item->isDeleted()) {
$bg_color = '#ff0000'; //red for deleted items
}
$fg_color = !empty($bg_color)
? Html::getInvertedColor($gs_item['bgcolor'])
: "";
$fg_color_s = "color: $fg_color;";
$img_class = "";
$img_s = "";
if ($gs_item['picture_f'] && !$rear && !$reserved) {
$img_s = "background: $bg_color url(\"".$gs_item['picture_f']."\") no-repeat top left/100% 100%;";
$img_class = 'with_picture';
}
if ($gs_item['picture_r'] && $rear && !$reserved) {
$img_s = "background: $bg_color url(\"".$gs_item['picture_r']."\") no-repeat top left/100% 100%;";
$img_class = 'with_picture';
}
$tip = "
";
$tip.= "
";
if (!empty($typename)) {
$tip.= "
$typename
";
}
if (!empty($name)) {
$tip.= "
$name
";
}
if (!empty($serial)) {
$tip.= "
$serial
";
}
if (!empty($otherserial)) {
$tip.= "
$otherserial
";
}
if (!empty($model)) {
$tip.= "
$model
";
}
$tip.= "";
return "
";
}
return false;
}
/**
* Return an i html tag with a dedicated icon for the itemtype
* @param string $itemtype A rackable itemtype
* @return string The i html tag
*/
private static function getItemIcon($itemtype = "") {
$icon = "";
switch ($itemtype) {
case "Computer":
$icon = "fas fa-server";
break;
case "Reserved":
$icon = "fas fa-lock";
break;
default:
$icon = $itemtype::getIcon();
break;
}
if (!empty($icon)) {
$icon = "
";
}
return $icon;
}
function prepareInputForAdd($input) {
return $this->prepareInput($input);
}
function prepareInputForUpdate($input) {
return $this->prepareInput($input);
}
/**
* Prepares input (for update and add)
*
* @param array $input Input data
*
* @return array
*/
private function prepareInput($input) {
$error_detected = [];
$itemtype = !$this->isNewItem() ? $this->fields['itemtype'] : null;
$items_id = !$this->isNewItem() ? $this->fields['items_id'] : null;
$racks_id = !$this->isNewItem() ? $this->fields['racks_id'] : null;
$position = !$this->isNewItem() ? $this->fields['position'] : null;
$hpos = !$this->isNewItem() ? $this->fields['hpos'] : null;
$orientation = !$this->isNewItem() ? $this->fields['orientation'] : null;
//check for requirements
if (($this->isNewItem() && (!isset($input['itemtype']) || empty($input['itemtype'])))
|| (isset($input['itemtype']) && empty($input['itemtype']))) {
$error_detected[] = __('An item type is required');
}
if (($this->isNewItem() && (!isset($input['items_id']) || empty($input['items_id'])))
|| (isset($input['items_id']) && empty($input['items_id']))) {
$error_detected[] = __('An item is required');
}
if (($this->isNewItem() && (!isset($input['racks_id']) || empty($input['racks_id'])))
|| (isset($input['racks_id']) && empty($input['racks_id']))) {
$error_detected[] = __('A rack is required');
}
if (($this->isNewItem() && (!isset($input['position']) || empty($input['position'])))
|| (isset($input['position']) && empty($input['position']))) {
$error_detected[] = __('A position is required');
}
if (isset($input['itemtype'])) {
$itemtype = $input['itemtype'];
}
if (isset($input['items_id'])) {
$items_id = $input['items_id'];
}
if (isset($input['racks_id'])) {
$racks_id = $input['racks_id'];
}
if (isset($input['position'])) {
$position = $input['position'];
}
if (isset($input['hpos'])) {
$hpos = $input['hpos'];
}
if (isset($input['orientation'])) {
$orientation = $input['orientation'];
}
if (!count($error_detected)) {
//check if required U are available at position
$rack = new Rack();
$rack->getFromDB($racks_id);
if ($this->isNewItem()) {
$filled = $rack->getFilled();
} else {
// If object is existing, exclude current state from used positions
$filled = $rack->getFilled($this->fields['itemtype'], $this->fields['items_id']);
}
$item = new $itemtype;
$item->getFromDB($items_id);
$model_class = $item->getType() . 'Model';
$modelsfield = strtolower($item->getType()) . 'models_id';
$model = new $model_class;
if ($model->getFromDB($item->fields[$modelsfield])) {
$item->model = $model;
} else {
$item->model = null;
}
$required_units = 1;
$width = 1;
$depth = 1;
if ($item->model != null) {
if ($item->model->fields['required_units'] > 1) {
$required_units = $item->model->fields['required_units'];
}
if ($item->model->fields['is_half_rack'] == 1) {
if ($this->isNewItem() && !isset($input['hpos']) || $input['hpos'] == 0) {
$error_detected[] = __('You must define an horizontal position for this item');
}
$width = 0.5;
}
if ($item->model->fields['depth'] != 1) {
if ($this->isNewItem() && !isset($input['orientation'])) {
$error_detected[] = __('You must define an orientation for this item');
}
$depth = $item->model->fields['depth'];
}
}
if ($position > $rack->fields['number_units'] ||
$position + $required_units > $rack->fields['number_units'] + 1
) {
$error_detected[] = __('Item is out of rack bounds');
} else if (!count($error_detected)) {
$i = 0;
while ($i < $required_units) {
$current_position = $position + $i;
if (isset($filled[$current_position])) {
$content_filled = $filled[$current_position];
if ($hpos == Rack::POS_NONE || $hpos == Rack::POS_LEFT) {
$d = 0;
while ($d/4 < $depth) {
$pos = ($orientation == Rack::REAR) ? 3 - $d : $d;
$val = 1;
if (isset($content_filled[Rack::POS_LEFT][$pos]) && $content_filled[Rack::POS_LEFT][$pos] != 0) {
$error_detected[] = __('Not enough space available to place item');
break 2;
}
++$d;
}
}
if ($hpos == Rack::POS_NONE || $hpos == Rack::POS_RIGHT) {
$d = 0;
while ($d/4 < $depth) {
$pos = ($orientation == Rack::REAR) ? 3 - $d : $d;
$val = 1;
if (isset($content_filled[Rack::POS_RIGHT][$pos]) && $content_filled[Rack::POS_RIGHT][$pos] != 0) {
$error_detected[] = __('Not enough space available to place item');
break 2;
}
++$d;
}
}
}
++$i;
}
}
}
if (count($error_detected)) {
foreach ($error_detected as $error) {
Session::addMessageAfterRedirect(
$error,
true,
ERROR
);
}
return false;
}
return $input;
}
protected function computeFriendlyName() {
$rack = new Rack();
$rack->getFromDB($this->fields['racks_id']);
$name = sprintf(
__('Item for rack "%1$s"'),
$rack->getName()
);
return $name;
}
}