Merge branch 'Patching/improve' into 'master'
improved patching See merge request fronk/thetool!1188
This commit is contained in:
@@ -1,198 +1,451 @@
|
||||
<?php
|
||||
$pagination_baseurl = $this->getUrl($Mod,"Index");
|
||||
$pagination_baseurl_params = ["filter" => $filter];
|
||||
$pagination_entity_name = "Patchungen";
|
||||
|
||||
if(!is_array($filter)) $filter = [];
|
||||
// --- Configuration ---
|
||||
$pagination_baseurl = $this->getUrl($Mod,"Index");
|
||||
$pagination_baseurl_params = ["filter" => $filter]; // Filters passed via GET
|
||||
$pagination_entity_name = "Patchungen";
|
||||
|
||||
// Ensure $filter is always an array
|
||||
if(!is_array($filter)) {
|
||||
$filter = [];
|
||||
}
|
||||
|
||||
// Helper function for safe output (assuming not already handled by framework/template engine)
|
||||
function e($string) {
|
||||
return htmlspecialchars($string ?? '', ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
$additionalHead = [
|
||||
'<link rel="manifest" href="/assets/pwa/patching-manifest.json">'
|
||||
];
|
||||
|
||||
?>
|
||||
<?php include(realpath(dirname(__FILE__)."/../../$mfLayoutPackage")."/header.php"); ?>
|
||||
|
||||
<!-- start page title -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="page-title-box">
|
||||
<div class="page-title-right">
|
||||
<ol class="breadcrumb m-0">
|
||||
<li class="breadcrumb-item"><a href="<?=self::getUrl("Dashboard")?>"><?=MFAPPNAME_SLUG?></a></li>
|
||||
<li class="breadcrumb-item active">Patchungen</li>
|
||||
</ol>
|
||||
</div>
|
||||
<h4 class="page-title">Patchungen</h4>
|
||||
<div class="col-12">
|
||||
<div class="page-title-box">
|
||||
<div class="page-title-right">
|
||||
<ol class="breadcrumb m-0">
|
||||
<li class="breadcrumb-item"><a href="<?=e(self::getUrl("Dashboard"))?>"><?=e(MFAPPNAME_SLUG)?></a></li>
|
||||
<li class="breadcrumb-item active">Patchungen</li>
|
||||
</ol>
|
||||
</div>
|
||||
<h4 class="page-title">Patchungen</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end page title -->
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body mb-3">
|
||||
<h4 class="header-title mb-3">Filter</h4>
|
||||
|
||||
<form method="get" action="<?=self::getUrl("Patching")?>">
|
||||
<div class="row">
|
||||
<div class="col-1">
|
||||
<label class="form-label" for="filter_network_id">Netzgebiet</label>
|
||||
<select name="filter[network_id]" id="filter_network_id" class="form-control">
|
||||
<option></option>
|
||||
<?php foreach($mynetworks as $fnet): ?>
|
||||
<option value="<?=$fnet->id?>" <?=($filter['network_id'] == $fnet->id) ? "selected='selected'" : ""?>><?=$fnet->name?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-2">
|
||||
<label class="form-label" for="filter_pop_id">POP</label>
|
||||
<select name="filter[pop_id]" id="filter_pop_id" class="form-control">
|
||||
<option></option>
|
||||
<?php foreach($mynetworks as $fnet): ?>
|
||||
<?php if(is_array($fnet->pops) && count($fnet->pops)): ?>
|
||||
<optgroup label="<?=$fnet->name?>">
|
||||
<?php foreach($fnet->pops as $pop): ?>
|
||||
<option value="<?=$pop->id?>" <?=($filter['pop_id'] == $pop->id) ? "selected='selected'" : ""?>><?=$pop->name?></option>
|
||||
<?php endforeach; ?>
|
||||
</optgroup>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-2">
|
||||
<label class="form-label" for="filter_patched">Patchstatus</label>
|
||||
<select name="filter[patched]" id="filter_patched" class="form-control">
|
||||
<option value="0" <?=($filter['patched'] < 1) ? "selected='selected'" : ""?>>Nicht gepatched</option>
|
||||
<option value="1" <?=($filter['patched'] == 1) ? "selected='selected'" : ""?>>Gepatched</option>
|
||||
<option value="2" <?=($filter['patched'] == 2) ? "selected='selected'" : ""?>>Vorpatchen</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-2">
|
||||
<label class="form-label" for="filter_hide_delayed_finish">Verzögerte Herstellung</label>
|
||||
<select name="filter[hide_delayed_finish]" id="filter_hide_delayed_finish" class="form-control">
|
||||
<option value="0" <?=(array_key_exists("hide_delayed_finish", $filter) &&$filter['hide_delayed_finish'] != 1) ? "selected='selected'" : ""?>>Anzeigen</option>
|
||||
<option value="1" <?=(!array_key_exists("hide_delayed_finish", $filter) || $filter['hide_delayed_finish'] == 1) ? "selected='selected'" : ""?>>Nicht anzeigen</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-1">
|
||||
<label class="form-label" for="filter_code">Objekt ID</label>
|
||||
<input type="text" class="form-control" name="filter[code]" id="filter_code" value="<?=$filter['code']?>" />
|
||||
</div>
|
||||
|
||||
<div class="col-2">
|
||||
<label class="form-label" for="filter_street">Straße</label>
|
||||
<input type="text" class="form-control" name="filter[street]" id="filter_street" value="<?=$filter['street']?>" />
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
<div class="col">
|
||||
<button type="submit" class="btn btn-primary">Filter anwenden</button>
|
||||
<a class="btn btn-secondary" href="<?=self::getUrl("Patching")?>">Filter zurücksetzen</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body mb-3">
|
||||
<h4 class="header-title">Patchungen</h4>
|
||||
<div class="col-lg-12">
|
||||
|
||||
<?php include(realpath(dirname(__FILE__)."/../")."/tpl/pagination.php"); ?>
|
||||
<?php include(realpath(dirname(__FILE__)."/../")."/tpl/pagination-summary.php"); ?>
|
||||
<div class="card">
|
||||
<div class="card-body mb-3">
|
||||
<h4 class="header-title mb-3">Filter</h4>
|
||||
|
||||
|
||||
<table class="table table-striped table-hover">
|
||||
<tr class="table-bordered text-center">
|
||||
<th colspan="4">Standort</th>
|
||||
<th colspan="2">ODF</th>
|
||||
<th colspan="5">Abschluss/Device</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<tr class="table-bordered">
|
||||
<th>Netzgebiet</th>
|
||||
<th>POP</th>
|
||||
<th>Kunde</th>
|
||||
<th>Standort</th>
|
||||
<th>Patchposition ODF</th>
|
||||
<th>ODF Port</th>
|
||||
<th>Typ</th>
|
||||
<th>Splitter / Gerät</th>
|
||||
<th>Port</th>
|
||||
<th>Gepatched</th>
|
||||
<th>Von</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<?php foreach($terminations as $term): ?>
|
||||
<tr>
|
||||
<td><?=$term->building->network->name?></td>
|
||||
<td>
|
||||
<?php if($term->getPop()): ?>
|
||||
<?=$term->getPop()->name?>
|
||||
<?php else: ?>
|
||||
<?=$term->building->pop->name?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?=($term->order->owner) ? $term->order->owner->customer_number : ""?><br /> <?=($term->order->owner) ? $term->order->owner->getCompanyOrName() : ""?></td>
|
||||
<td>
|
||||
<?=$term->building->street?><br />
|
||||
<?=$term->building->zip?> <?=$term->building->city?>
|
||||
</td>
|
||||
<td class="text-mono text-primary" title="Schrank: <?=($term->workflowitems["ist_schrank"]->value->id) ? $term->workflowitems["ist_schrank"]->value->value_string : $term->workflowitems["schrank"]->value->value_string?> / Einschub: <?=($term->workflowitems["ist_baugruppe"]->value->id) ? $term->workflowitems["ist_baugruppe"]->value->value_string : $term->workflowitems["baugruppe"]->value->value_string?> / Modul: <?=($term->workflowitems["ist_modul"]->value->id) ? $term->workflowitems["ist_modul"]->value->value_string : $term->workflowitems["modul"]->value->value_string?> / Port: <?=($term->workflowitems["ist_ports"]->value->id) ? $term->workflowitems["ist_ports"]->value->value_string : $term->workflowitems["ports"]->value->value_string?>">
|
||||
<?=($term->workflowitems["ist_schrank"]->value->id) ? $term->workflowitems["ist_schrank"]->value->value_string : $term->workflowitems["schrank"]->value->value_string?> /
|
||||
<?=($term->workflowitems["ist_baugruppe"]->value->id) ? $term->workflowitems["ist_baugruppe"]->value->value_string : $term->workflowitems["baugruppe"]->value->value_string?> /
|
||||
<?=($term->workflowitems["ist_modul"]->value->id) ? $term->workflowitems["ist_modul"]->value->value_string : $term->workflowitems["modul"]->value->value_string?> /
|
||||
<?=($term->workflowitems["ist_ports"]->value->id) ? $term->workflowitems["ist_ports"]->value->value_string : $term->workflowitems["ports"]->value->value_string?>
|
||||
</td>
|
||||
<td>
|
||||
<select name="linework_port" form="term-form-<?=$term->id?>" class="form-control">
|
||||
<?php foreach($term->getLineworkportPairs() as $ports): ?>
|
||||
<?php foreach($ports as $p): ?>
|
||||
<option value="<?=$p?>" <?=($term->patching->linework_ports == $p) ? "selected='selected'" : ""?>><?=$p?></option>
|
||||
<?php endforeach; ?>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select name="device_type" form="term-form-<?=$term->id?>" class="form-control">
|
||||
<option></option>
|
||||
<option value="splitter" <?=($term->patching->device_type == "splitter") ? "selected='selected'" : ""?>>Splitter</option>
|
||||
<option value="pon" <?=($term->patching->device_type == "pon") ? "selected='selected'" : ""?>>Shared PON-Port</option>
|
||||
<option value="switch" <?=($term->patching->device_type == "switch") ? "selected='selected'" : ""?>>Switch</option>
|
||||
</select>
|
||||
</td>
|
||||
<td><input type="text" class="form-control" form="term-form-<?=$term->id?>" name="device_name" value="<?=$term->patching->device_name?>" placeholder="Splitte / Gerät" /></td>
|
||||
<td><input type="text" class="form-control" form="term-form-<?=$term->id?>" name="device_port" value="<?=$term->patching->device_port?>" placeholder="Port" /></td>
|
||||
<td><input type="checkbox" class="form-control" form="term-form-<?=$term->id?>" name="patched" value="1" <?=($term->patching->patched == 1) ? "checked='checked'" : ""?> /></td>
|
||||
<td <?=($term->patching->patched == 1 && $term->patching->patched_by) ? "title='Gepatched: ".date("d.m.Y H:i",$term->patching->patched_date)." von ".$term->patching->patcher->name." (".$term->patching->patcher->address->getCompanyOrName(true).")'" : ""?>>
|
||||
|
||||
<?php if($term->patching->patched == 1 && $term->patching->patched_by): ?>
|
||||
<?=($term->patching->patcher) ? $term->patching->patcher->getAbbrName() : ""?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<form method="post" id="term-form-<?=$term->id?>" action="<?=self::getUrl("Patching","save", ["s" => $pagination['start'], "filter" => $filter])?>">
|
||||
<input type="hidden" name="termination_id" value="<?=$term->id?>" />
|
||||
<input type="submit" class="btn btn-primary" value="Speichern" />
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
|
||||
<?php include(realpath(dirname(__FILE__)."/../")."/tpl/pagination-summary.php"); ?>
|
||||
<?php include(realpath(dirname(__FILE__)."/../")."/tpl/pagination.php"); ?>
|
||||
</div>
|
||||
<form method="get" action="<?=e(self::getUrl("Patching"))?>">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-12 col-md-6 col-lg-2 mb-3">
|
||||
<label class="form-label" for="filter_network_id">Netzgebiet</label>
|
||||
<select name="filter[network_id]" id="filter_network_id" class="form-control">
|
||||
<option value=""></option>
|
||||
<?php foreach($mynetworks as $fnet): ?>
|
||||
<option value="<?=e($fnet->id)?>" <?=($filter['network_id'] ?? null == $fnet->id) ? "selected='selected'" : ""?>><?=e($fnet->name)?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-6 col-lg-2 mb-3">
|
||||
<label class="form-label" for="filter_pop_id">POP</label>
|
||||
<select name="filter[pop_id]" id="filter_pop_id" class="form-control">
|
||||
<option value=""></option>
|
||||
<?php foreach($mynetworks as $fnet): ?>
|
||||
<?php if(is_array($fnet->pops) && count($fnet->pops)): ?>
|
||||
<optgroup label="<?=e($fnet->name)?>">
|
||||
<?php foreach($fnet->pops as $pop): ?>
|
||||
<option value="<?=e($pop->id)?>" <?=($filter['pop_id'] ?? null == $pop->id) ? "selected='selected'" : ""?>><?=e($pop->name)?></option>
|
||||
<?php endforeach; ?>
|
||||
</optgroup>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-6 col-lg-2 mb-3">
|
||||
<label class="form-label" for="filter_patched">Patchstatus</label>
|
||||
<select name="filter[patched]" id="filter_patched" class="form-control">
|
||||
<option value="0" <?=((int)($filter['patched'] ?? 0) < 1) ? "selected='selected'" : ""?>>Nicht gepatched</option>
|
||||
<option value="1" <?=((int)($filter['patched'] ?? 0) == 1) ? "selected='selected'" : ""?>>Gepatched</option>
|
||||
<option value="2" <?=((int)($filter['patched'] ?? 0) == 2) ? "selected='selected'" : ""?>>Vorpatchen</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-6 col-lg-2 mb-3">
|
||||
<label class="form-label" for="filter_hide_delayed_finish">Verzögerte Herstellung</label>
|
||||
<select name="filter[hide_delayed_finish]" id="filter_hide_delayed_finish" class="form-control">
|
||||
<option value="0" <?=(isset($filter["hide_delayed_finish"]) && $filter['hide_delayed_finish'] != 1) ? "selected='selected'" : ""?>>Anzeigen</option>
|
||||
<option value="1" <?=(!isset($filter["hide_delayed_finish"]) || $filter['hide_delayed_finish'] == 1) ? "selected='selected'" : ""?>>Nicht anzeigen</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-6 col-lg-1 mb-3">
|
||||
<label class="form-label" for="filter_code">Objekt ID</label>
|
||||
<input type="text" class="form-control" name="filter[code]" id="filter_code" value="<?=e($filter['code'] ?? '')?>" />
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-6 col-lg-3 mb-3">
|
||||
<label class="form-label" for="filter_street">Straße</label>
|
||||
<input type="text" class="form-control" name="filter[street]" id="filter_street" value="<?=e($filter['street'] ?? '')?>" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
<div class="col-12">
|
||||
<button type="submit" class="btn btn-primary">Filter anwenden</button>
|
||||
<a class="btn btn-secondary" href="<?=e(self::getUrl("Patching"))?>">Filter zurücksetzen</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body mb-3">
|
||||
<h4 class="header-title">Patchungen</h4>
|
||||
|
||||
<?php // Include pagination controls - Top ?>
|
||||
<?php include(realpath(dirname(__FILE__)."/../")."/tpl/pagination.php"); ?>
|
||||
<?php include(realpath(dirname(__FILE__)."/../")."/tpl/pagination-summary.php"); ?>
|
||||
|
||||
<div class="table-responsive mt-3"> <?php // Added table-responsive wrapper and margin-top ?>
|
||||
<table class="table table-striped table-hover">
|
||||
<thead class="table-bordered"> <?php // Added thead and border class ?>
|
||||
<tr>
|
||||
<th colspan="4" class="text-center">Standort</th>
|
||||
<th colspan="2" class="text-center">ODF</th>
|
||||
<th colspan="5" class="text-center">Abschluss/Device</th>
|
||||
<th>Aktion</th> <?php // Renamed last header ?>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Netzgebiet</th>
|
||||
<th class="text-nowrap">POP</th> <?php // Added text-nowrap for min-width effect ?>
|
||||
<th class="text-nowrap">Kunde</th> <?php // Added text-nowrap ?>
|
||||
<th>Standort</th> <?php // Allow wrapping ?>
|
||||
<th class="text-nowrap">Patchposition ODF</th> <?php // Added text-nowrap ?>
|
||||
<th style="min-width: 105px">ODF Port</th> <?php // Select handles resize ok ?>
|
||||
<th style="min-width: 195px">Typ</th> <?php // Select handles resize ok ?>
|
||||
<th style="min-width: 190px" class="text-nowrap">Splitter / Gerät</th> <?php // Added text-nowrap ?>
|
||||
<th style="min-width: 90px" class="text-nowrap">Port</th> <?php // Added text-nowrap ?>
|
||||
<th>Gepatched</th>
|
||||
<th class="text-nowrap">Von</th> <?php // Added text-nowrap ?>
|
||||
<th class="text-nowrap">Speichern</th> <?php // Added text-nowrap ?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($terminations as $term): ?>
|
||||
<?php
|
||||
// --- Prepare complex data for cleaner output ---
|
||||
|
||||
// ODF Patch Position
|
||||
$wfItems = $term->workflowitems ?? [];
|
||||
$istSchrankValue = $wfItems["ist_schrank"]->value ?? null;
|
||||
$schrankValue = $wfItems["schrank"]->value ?? null;
|
||||
$istBaugruppeValue = $wfItems["ist_baugruppe"]->value ?? null;
|
||||
$baugruppeValue = $wfItems["baugruppe"]->value ?? null;
|
||||
$istModulValue = $wfItems["ist_modul"]->value ?? null;
|
||||
$modulValue = $wfItems["modul"]->value ?? null;
|
||||
$istPortsValue = $wfItems["ist_ports"]->value ?? null;
|
||||
$portsValue = $wfItems["ports"]->value ?? null;
|
||||
|
||||
$schrank = ($istSchrankValue && $istSchrankValue->id) ? $istSchrankValue->value_string : ($schrankValue ? $schrankValue->value_string : '');
|
||||
$baugruppe = ($istBaugruppeValue && $istBaugruppeValue->id) ? $istBaugruppeValue->value_string : ($baugruppeValue ? $baugruppeValue->value_string : '');
|
||||
$modul = ($istModulValue && $istModulValue->id) ? $istModulValue->value_string : ($modulValue ? $modulValue->value_string : '');
|
||||
$ports = ($istPortsValue && $istPortsValue->id) ? $istPortsValue->value_string : ($portsValue ? $portsValue->value_string : '');
|
||||
|
||||
$odfPositionTitle = "Schrank: " . e($schrank) . " / Einschub: " . e($baugruppe) . " / Modul: " . e($modul) . " / Port: " . e($ports);
|
||||
$odfPositionDisplay = e($schrank) . " / " . e($baugruppe) . " / " . e($modul) . " / " . e($ports);
|
||||
|
||||
// Patched By Info
|
||||
$patching = $term->patching ?? null;
|
||||
$patcher = $patching ? ($patching->patcher ?? null) : null;
|
||||
$patchedByTitle = '';
|
||||
$patchedByDisplay = '';
|
||||
if ($patching && $patching->patched == 1 && $patching->patched_by && $patcher) {
|
||||
$patcherName = $patcher->name ?? 'Unbekannt';
|
||||
$patcherCompany = $patcher->address ? $patcher->address->getCompanyOrName(true) : 'N/A';
|
||||
$patchedDate = date("d.m.Y H:i", $patching->patched_date);
|
||||
$patchedByTitle = "Gepatched: {$patchedDate} von " . e($patcherName) . " (" . e($patcherCompany) . ")";
|
||||
$patchedByDisplay = $patcher->getAbbrName() ?? '';
|
||||
}
|
||||
|
||||
// Customer Info
|
||||
$customer = $term->order->owner ?? null;
|
||||
$customerNumber = $customer ? $customer->customer_number : '';
|
||||
$customerName = $customer ? $customer->getCompanyOrName() : '';
|
||||
|
||||
// Location Info
|
||||
$building = $term->building ?? null;
|
||||
$networkName = $building ? ($building->network->name ?? '') : '';
|
||||
$popName = '';
|
||||
$termPop = $term->getPop(); // Call potentially expensive method once
|
||||
if ($termPop) {
|
||||
$popName = $termPop->name ?? '';
|
||||
} elseif ($building && $building->pop) {
|
||||
$popName = $building->pop->name ?? '';
|
||||
}
|
||||
$street = $building->street ?? '';
|
||||
$zip = $building->zip ?? '';
|
||||
$city = $building->city ?? '';
|
||||
|
||||
// Linework Ports
|
||||
$lineworkPorts = $term->getLineworkportPairs() ?? [];
|
||||
$currentLineworkPort = $patching ? $patching->linework_ports : null;
|
||||
|
||||
// Device Info
|
||||
$deviceType = $patching ? $patching->device_type : '';
|
||||
$deviceName = $patching ? $patching->device_name : '';
|
||||
$devicePort = $patching ? $patching->device_port : '';
|
||||
$isPatched = $patching ? ($patching->patched == 1) : false;
|
||||
?>
|
||||
<tr class="align-middle"> <?php // Added align-middle ?>
|
||||
<td><?=e($networkName)?></td>
|
||||
<td><?=e($popName)?></td>
|
||||
<td><?=e($customerNumber)?><br /><?=e($customerName)?></td>
|
||||
<td>
|
||||
<?=e($street)?><br />
|
||||
<?=e($zip)?> <?=e($city)?>
|
||||
</td>
|
||||
<td class="text-mono text-primary" title="<?=$odfPositionTitle?>">
|
||||
<?=$odfPositionDisplay?>
|
||||
</td>
|
||||
<td>
|
||||
<select name="linework_port" form="term-form-<?=e($term->id)?>" class="form-control"> <?php // Removed -sm ?>
|
||||
<?php foreach($lineworkPorts as $portGroup): ?>
|
||||
<?php foreach($portGroup as $p): ?>
|
||||
<option value="<?=e($p)?>" <?=($currentLineworkPort == $p) ? "selected='selected'" : ""?>><?=e($p)?></option>
|
||||
<?php endforeach; ?>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select name="device_type" form="term-form-<?=e($term->id)?>" class="form-control"> <?php // Removed -sm ?>
|
||||
<option value=""></option>
|
||||
<option value="splitter" <?=($deviceType == "splitter") ? "selected='selected'" : ""?>>Splitter</option>
|
||||
<option value="pon" <?=($deviceType == "pon") ? "selected='selected'" : ""?>>Shared PON-Port</option>
|
||||
<option value="switch" <?=($deviceType == "switch") ? "selected='selected'" : ""?>>Switch</option>
|
||||
</select>
|
||||
</td>
|
||||
<td><input type="text" class="form-control device-name-input" form="term-form-<?=e($term->id)?>" name="device_name" value="<?=e($deviceName)?>" placeholder="Splitter / Gerät" /></td> <?php // Removed -sm ?>
|
||||
<td><input type="text" class="form-control" form="term-form-<?=e($term->id)?>" name="device_port" value="<?=e($devicePort)?>" placeholder="Port" /></td> <?php // Removed -sm ?>
|
||||
<td class="text-center"> <?php // Added text-center ?>
|
||||
<input type="hidden" name="patched" value="0" form="term-form-<?=e($term->id)?>" /> <?php // Ensure 0 is sent if checkbox is unchecked ?>
|
||||
<input type="checkbox" class="form-check-input" style="position:unset !important;height: 2em; width: 2em;" form="term-form-<?=e($term->id)?>" name="patched" value="1" <?=($isPatched) ? "checked='checked'" : ""?> /> <?php // Adjusted checkbox style slightly ?>
|
||||
</td>
|
||||
<td <?=!empty($patchedByTitle) ? 'title="' . $patchedByTitle . '"' : ''?>>
|
||||
<?=e($patchedByDisplay)?>
|
||||
</td>
|
||||
<td>
|
||||
<form method="post" id="term-form-<?=e($term->id)?>" action="<?=e(self::getUrl("Patching","save", ["s" => $pagination['start'] ?? 0, "filter" => $filter]))?>">
|
||||
<input type="hidden" name="termination_id" value="<?=e($term->id)?>" />
|
||||
<button type="submit" class="btn btn-primary">Speichern</button> <?php // Changed value to button text, removed -sm ?>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div> <?php // End table-responsive ?>
|
||||
|
||||
<?php // Include pagination controls - Bottom ?>
|
||||
<?php include(realpath(dirname(__FILE__)."/../")."/tpl/pagination-summary.php"); ?>
|
||||
<?php include(realpath(dirname(__FILE__)."/../")."/tpl/pagination.php"); ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include(realpath(dirname(__FILE__)."/../../$mfLayoutPackage")."/footer.php"); ?>
|
||||
<style>
|
||||
@media (max-width: 768px) {
|
||||
.pagination {
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.select2-selection__rendered {
|
||||
line-height: 38px !important;
|
||||
}
|
||||
.select2-container .select2-selection--single {
|
||||
height: 38px !important;
|
||||
}
|
||||
.select2-selection__arrow {
|
||||
height: 37px !important;
|
||||
}
|
||||
|
||||
@media all and (display-mode: standalone) {
|
||||
#topnav {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
window.DEVICES = <?= json_encode($devices) ?>;
|
||||
window.DEVICES = window.DEVICES.filter(device => {
|
||||
return device.name.toLowerCase().includes('olt') || device.name.toLowerCase().includes('pon')
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('/assets/pwa/patching-sw.js')
|
||||
.then(registration => {
|
||||
console.log('Patching PWA Service Worker registered with scope:', registration.scope);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Patching PWA Service Worker registration failed:', error);
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof $().select2 === 'undefined') {
|
||||
console.error('Select2 library is not loaded.');
|
||||
// Optionally display an error to the user or fall back gracefully
|
||||
return; // Stop execution if Select2 is missing
|
||||
}
|
||||
|
||||
const ipNumRegex = /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})[/-](\d+)$/;
|
||||
|
||||
// Helper: Find device object by IP
|
||||
function findDeviceByIp(ip) {
|
||||
if (!window.DEVICES || !Array.isArray(window.DEVICES)) {
|
||||
console.error('DEVICES array not found or invalid.');
|
||||
return null;
|
||||
}
|
||||
return window.DEVICES.find(device => device.ip === ip);
|
||||
}
|
||||
|
||||
// Helper: Update the original hidden input field's value
|
||||
function updateOriginalInput($originalInput, ip, number) {
|
||||
const cleanNumber = String(number).trim(); // Ensure number is a string and trimmed
|
||||
if (ip && cleanNumber) {
|
||||
$originalInput.val(ip + '/' + cleanNumber).trigger('change'); // Update and trigger change
|
||||
} else {
|
||||
$originalInput.val('').trigger('change'); // Clear if incomplete and trigger change
|
||||
}
|
||||
}
|
||||
|
||||
// --- Initialize for each device name input ---
|
||||
$('.device-name-input').each(function() {
|
||||
const $originalInput = $(this);
|
||||
const $td = $originalInput.closest('td'); // Get the parent cell for structure
|
||||
let initialValue = $originalInput.val().trim();
|
||||
|
||||
// Create wrapper for the Select2 component (Select + Number Input)
|
||||
// Hide it initially
|
||||
const $selectWrapper = $('<div class="device-select-wrapper" style="display: none; align-items: center; gap: 5px;"></div>');
|
||||
const $select = $('<select class="form-control device-select" style="flex-grow: 1; width: auto;"></select>'); // Let flexbox handle width
|
||||
const $numberInput = $('<input type="number" class="form-control device-number" placeholder="Nr." style="width: 70px; flex-grow: 0; flex-shrink: 0;">'); // Fixed width number input
|
||||
|
||||
// Populate Select options
|
||||
$select.append('<option value="">Gerät auswählen...</option>'); // Placeholder
|
||||
if (window.DEVICES && Array.isArray(window.DEVICES)) {
|
||||
window.DEVICES.forEach(device => {
|
||||
// Display name and IP for clarity in dropdown
|
||||
const displayText = `${device.name} (${device.ip})`;
|
||||
$select.append($('<option></option>').val(device.ip).text(displayText));
|
||||
});
|
||||
} else {
|
||||
console.warn("DEVICES array is missing or invalid for row:", $originalInput.attr('form'));
|
||||
// Optionally add a disabled option indicating an error
|
||||
$select.append('<option value="" disabled>Device list error</option>');
|
||||
}
|
||||
|
||||
|
||||
$selectWrapper.append($select).append($numberInput);
|
||||
$td.append($selectWrapper); // Add the hidden wrapper to the cell
|
||||
|
||||
// Function to show Select2 component and hide original input
|
||||
function showSelectComponent(ip, number) {
|
||||
$originalInput.hide();
|
||||
$select.val(ip || '').trigger('change.select2'); // Set value and update Select2 display
|
||||
$numberInput.val(number || '');
|
||||
$selectWrapper.css('display', 'flex'); // Use flex to show side-by-side
|
||||
}
|
||||
|
||||
// Function to show original input and hide Select2 component
|
||||
function showOriginalInput() {
|
||||
$selectWrapper.hide();
|
||||
$originalInput.show();
|
||||
}
|
||||
|
||||
// Initial state determination
|
||||
const match = initialValue.match(ipNumRegex);
|
||||
if (match) {
|
||||
const initialIp = match[1];
|
||||
const initialNumber = match[2];
|
||||
const foundDevice = findDeviceByIp(initialIp);
|
||||
if (foundDevice) {
|
||||
// Valid format and known device -> Show Select2 component
|
||||
showSelectComponent(initialIp, initialNumber);
|
||||
} else {
|
||||
// Valid format but unknown device -> Show original input
|
||||
showOriginalInput();
|
||||
}
|
||||
} else if (!initialValue) {
|
||||
// Empty -> Show Select2 component (empty)
|
||||
showSelectComponent(null, null);
|
||||
} else {
|
||||
// Invalid format -> Show original input
|
||||
showOriginalInput();
|
||||
}
|
||||
|
||||
// Initialize Select2 *after* adding options and inserting into DOM
|
||||
$select.select2({
|
||||
width: 'style', // Adjust width based on container
|
||||
// dropdownParent: $td // Optional: Attach dropdown to cell if needed for positioning
|
||||
});
|
||||
|
||||
// --- Event Listeners ---
|
||||
|
||||
// Update original input when Select2 or number changes
|
||||
$select.on('change', function() {
|
||||
const selectedIp = $(this).val();
|
||||
const currentNumber = $numberInput.val();
|
||||
updateOriginalInput($originalInput, selectedIp, currentNumber);
|
||||
});
|
||||
|
||||
$numberInput.on('input change', function() { // Use 'input change' for better responsiveness
|
||||
const currentIp = $select.val();
|
||||
const selectedNumber = $(this).val();
|
||||
updateOriginalInput($originalInput, currentIp, selectedNumber);
|
||||
});
|
||||
|
||||
// Check original input on change/blur to potentially switch view
|
||||
$originalInput.on('change blur', function() {
|
||||
const currentValue = $(this).val().trim();
|
||||
const currentMatch = currentValue.match(ipNumRegex);
|
||||
if (currentMatch) {
|
||||
const currentIp = currentMatch[1];
|
||||
const currentNumber = currentMatch[2];
|
||||
const device = findDeviceByIp(currentIp);
|
||||
if (device) {
|
||||
// Switched to valid/known format -> Show Select2
|
||||
showSelectComponent(currentIp, currentNumber);
|
||||
}
|
||||
// else: Keep showing original input (valid format, but unknown device)
|
||||
}
|
||||
// else: Keep showing original input (invalid format)
|
||||
});
|
||||
|
||||
}); // End .each loop
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<?php include(realpath(dirname(__FILE__)."/../../$mfLayoutPackage")."/footer.php"); ?>
|
||||
@@ -75,6 +75,11 @@
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if(isset($additionalHead) && is_array($additionalHead) && count($additionalHead)):
|
||||
foreach($additionalHead as $head): ?>
|
||||
<?=$head?>
|
||||
<?php endforeach; endif;?>
|
||||
|
||||
<?php if(MFAPPNAME == "devthetool"): ?>
|
||||
<style type="text/css">
|
||||
body {
|
||||
|
||||
@@ -106,7 +106,15 @@ class PatchingController extends mfBaseController {
|
||||
|
||||
|
||||
$this->layout()->set("terminations", $terminations);
|
||||
|
||||
|
||||
$devices = DeviceModel::getAll();
|
||||
$this->layout()->set("devices", array_map(function($device) {
|
||||
return [
|
||||
"name" => $device->name,
|
||||
"ip" => $device->ip,
|
||||
];
|
||||
}, $devices));
|
||||
|
||||
}
|
||||
|
||||
private function getPreparedFilter($filter) {
|
||||
|
||||
16
public/assets/pwa/patching-manifest.json
Normal file
16
public/assets/pwa/patching-manifest.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "thetool Patching",
|
||||
"short_name": "Patching",
|
||||
"description": "Patching tool for thetool.",
|
||||
"start_url": "/Patching/",
|
||||
"display": "standalone",
|
||||
"background_color": "#ffffff",
|
||||
"theme_color": "#000000",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/assets/images/favicon.ico",
|
||||
"sizes": "66x61",
|
||||
"type": "image/x-icon"
|
||||
}
|
||||
]
|
||||
}
|
||||
9
public/assets/pwa/patching-sw.js
Normal file
9
public/assets/pwa/patching-sw.js
Normal file
@@ -0,0 +1,9 @@
|
||||
self.addEventListener('install', event => {
|
||||
console.log('Patching PWA Service Worker: Installing...');
|
||||
});
|
||||
|
||||
self.addEventListener('activate', event => {
|
||||
console.log('Patching PWA Service Worker: Activating...');
|
||||
});
|
||||
|
||||
console.log('Patching PWA Service Worker: Script loaded.');
|
||||
Reference in New Issue
Block a user