diff --git a/public_html/deployment/classes/project.class.php b/public_html/deployment/classes/project.class.php index fb9353aea36d61e10a4a80e54527bbddb0d7c552..a27cbb1590c1e73d624ea8e67af2cc87290e5031 100644 --- a/public_html/deployment/classes/project.class.php +++ b/public_html/deployment/classes/project.class.php @@ -2188,8 +2188,8 @@ class project extends base { /** * get html code for the colored bar on top of each phase detail items - * @param string $sPhase - * @param string $sPlace + * @param string $sPhase phase of a project + * @param string $sPlace place in the given phase * @return string */ private function _renderBar($sPhase, $sPlace) { @@ -2200,7 +2200,43 @@ class project extends base { } return $this->_getChecksumDiv($aData["revision"]); } - + + private function _renderHostsData($aData){ + $sReturn=''; + if (array_key_exists('_hosts', $aData)){ + // $sReturn.= print_r($aData['_hosts'], 1); + $sReturn.= '<div class="hosts">' + . '<br><strong>'.t('hosts').':</strong><br>' + ; + foreach($aData['_hosts'] as $sHostname=>$aHostinfos){ + $oUpdateDate=date("U", strtotime($aHostinfos['time'])); + $iAgeUpdate=round((date("U")-$oUpdateDate)/ 60); + $sAge=$iAgeUpdate< 60*60*13 ? $iAgeUpdate. " min" : "??"; + + $sReturn.= '<div class="host">' + . $this->_getChecksumDiv($aHostinfos['_data']['revision']) + . '<i class="fa fa-cube"></i><br>' + . $sHostname . "<br>($sAge) " + . '</div>' + ; + } + $sReturn.= '</div><div style="clear: both;"></div>'; + } + return $sReturn; + } + /** + * get html code for list of hosts in a phase + * @param string $sPhase phase of a project + * @return string + */ + private function _renderHosts($sPhase){ + $aDataPhase = $this->getPhaseInfos($sPhase); + if (is_array($aDataPhase) && array_key_exists('deployed', $aDataPhase)){ + return $this->_renderHostsData($aDataPhase['deployed']); + } + return ''; + } + /** * render html for a colored link to any project action * @param string $sFunction name of the action; one of accept|build|cleanup|deploy|new|overview|phase|rollback|setup @@ -2317,14 +2353,15 @@ class project extends base { $sRow1.='<th class="' . $sPhase . '">' . $sPhase . '</th>'; $sRow2.='<td class="' . $sPhase . '">' . t('url') . ': <a href="' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '">' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '</a><br>' - . '<br>' . t('deploytimes') . ':<br>'; + . '<br>' . t('deploytimes') . ':<br>'; if (count($this->_getDeploytimes($sPhase))) { $sRow2.=implode("<br>", $this->_getDeploytimes($sPhase)); } else { $sRow2.=t('deploytimes-immediately'); } - $sRow2.='<br>' . $this->renderLink("phase", $sPhase); - $sRow2.='</td>'; + $sRow2.='<br>' . $this->renderLink("phase", $sPhase) + . $this->_renderHosts($sPhase) + . '</td>'; } return '<table><thead><tr>' . $sRow1 . '</tr></thead><tbody><tr>' . $sRow2 . '</tr></tbody></table>'; } @@ -2360,7 +2397,9 @@ class project extends base { // TODO: getChecksumDiv anhand der Repo-Versionsnummer - dann kann man beim build auch die Farbe mit dem Repo HEAD vergleichen // time + $sDateFormat="d.m.Y H:i"; $oPkgDate=date("U", strtotime($aData["date"])); + /* $iAge=date("U")-$oPkgDate; $sDateFormat="d.m.Y"; if ($iAge< 60*60*24*90){ @@ -2369,6 +2408,8 @@ class project extends base { if ($iAge< 60*60*12){ $sDateFormat='H:i \U\h\r'; } + * + */ $sReturn .= ' ' . $this->_renderBar($sPhase, $sPlace) . ' @@ -2379,7 +2420,7 @@ class project extends base { // $sJsonUrl = $this->_getInfofile($sPhase, $sPlace); $sReturn.='<br> <i class="glyphicon glyphicon-bookmark"></i> ' . t('branch') . ': ' . $aData["branch"] . '<br> - <i class="glyphicon glyphicon-tag"></i> ' . t('revision') . ': ' . $aData["revision"] . '<br> + <i class="glyphicon glyphicon-tag"></i> ' . t('revision') . ': ' . $this->_renderRevision($aData["revision"]) . '<br> <i class="glyphicon glyphicon-comment"></i> ' . t('commitmessage') . ':<br><pre>' . strip_tags($aData["message"], '<br>') . '</pre>' // . '<i class="glyphicon glyphicon-globe"></i> ' . t('url') . ': <a href="' . $sJsonUrl . '">' . $sJsonUrl . '</a><br>' ; @@ -2426,25 +2467,6 @@ class project extends base { default: break; } - if (array_key_exists('_hosts', $aData)){ - // $sReturn.= print_r($aData['_hosts'], 1); - $sReturn.= '<div class="hosts">' - . ($bLong ? '<br><strong>Hosts:</strong><br>':'') - ; - foreach($aData['_hosts'] as $sHostname=>$aHostinfos){ - $oUpdateDate=date("U", strtotime($aHostinfos['time'])); - $iAgeUpdate=round((date("U")-$oUpdateDate)/ 60); - $sAge=$iAgeUpdate< 60*60*13 ? $iAgeUpdate. " min" : "??"; - - $sReturn.= '<div class="host">' - . $this->_getChecksumDiv($aHostinfos['_data']['revision']) - . ($bLong ? '<i class="fa fa-cube"></i><br>' : '') - . $sHostname . "<br>($sAge) " - . '</div>' - ; - } - $sReturn.= '</div>'; - } // $this->_getChecksumDiv($aData["revision"]) } else { if (array_key_exists("error", $aData)) { @@ -2547,6 +2569,19 @@ class project extends base { return $sReturn; } + /** + * get html code for a link to the commit + * (works for guithub and gitlab instances) + * + * @param string $sRevision + * @return string + */ + public function _renderRevision($sRevision){ + $sUrl=str_replace('/tree/master','',$this->_aPrjConfig["build"]["webaccess"]).'/commit/'.$sRevision; + // return '<a href="'.$sUrl.'">'.$sRevision.'</a>'; + return $sUrl; + } + /** * render html code for info link that shows popup with metadata on mouseover * @param array $aInfos metainfos of the package (from json file) @@ -2568,9 +2603,10 @@ class project extends base { if (array_key_exists("ok", $aInfos)) { $sLinktitle = t('infos'); if (array_key_exists("message", $aInfos)) { - $sInfos.='<i class="glyphicon glyphicon-calendar"></i> ' . t('build-from') . ' ' . date("d.m.Y H:i:s", strtotime($aInfos["date"])) . '<br>' + $sInfos.=$this->_getChecksumDiv($aInfos["revision"]) + . '<i class="glyphicon glyphicon-calendar"></i> ' . t('build-from') . ' ' . date("d.m.Y H:i:s", strtotime($aInfos["date"])) . '<br>' . '<i class="glyphicon glyphicon-bookmark"></i> ' . t('branch') . ': ' . $aInfos["branch"] . '<br>' - . '<i class="glyphicon glyphicon-tag"></i> ' . t('revision') . ': ' . $aInfos["revision"] . '<br>' + . '<i class="glyphicon glyphicon-tag"></i> ' . t('revision') . ': ' . $this->_renderRevision($aInfos["revision"]) . '<br>' . '<i class="glyphicon glyphicon-comment"></i> ' . t('commitmessage') . ':<br><span class="pre">' . strip_tags($aInfos["message"], '<br>') . '</span>'; if (array_key_exists("more", $aOptions)) { $sInfos.=$aOptions["more"]; @@ -2584,13 +2620,14 @@ class project extends base { $sLinktitle = '<i class="glyphicon glyphicon-exclamation-sign"></i> ' . t('error'); $sInfos = $aInfos["error"]; } + $sInfos.=$this->_renderHostsData($aInfos); if (array_key_exists("label", $aOptions) && $aOptions["label"]) { $sLinktitle.=$aOptions["label"]; } // render html - $sReturn = '<a href="#" class="info">' + $sReturn = '<a href="#" class="infoAsModal" onclick="showIdAsModalMessage($(this).children())">' . $sLinktitle . '<span'; if (array_key_exists("hpos", $aOptions)) { @@ -2601,6 +2638,7 @@ class project extends base { if ($sTitle) { $sReturn.='<span class="title">' . $sTitle . '</span><br><br>'; } + $sReturn.=$sInfos . '</span></a>'; if ($bIsError) { diff --git a/public_html/deployment/js/functions.js b/public_html/deployment/js/functions.js index 488d4e4ec83647d77e2704581b44485171a9cb0e..2db54381d7802c376dc32902e6c4cdbc6f768cf4 100644 --- a/public_html/deployment/js/functions.js +++ b/public_html/deployment/js/functions.js @@ -26,6 +26,12 @@ function showModalMessage(sMessage){ $('#divmodalmessage').html(sMessage); $('#divmodal').show(); } +function showIdAsModalMessage(o){ + var sHtml='<a href="#" onclick="hideModalMessage()" class="btn btn-danger" style="float:right"> X </a>' + o.html(); + $('#divmodalmessage').html(sHtml); + $('#divmodal').show(); +} + function hideModalMessage(){ $('#divmodal').hide(); } @@ -127,3 +133,126 @@ function filterLogTable(){ return false; } +// ---------------------------------------------------------------------- +// tables +// ---------------------------------------------------------------------- +var localStoreTablefilter="tblvalue" + location.pathname; + + +// http://blog.mastykarz.nl/jquery-regex-filter/ +jQuery.extend( + jQuery.expr[':'], { + regex: function (a, i, m) { + var r = new RegExp(m[3], 'i'); + return r.test(jQuery(a).text()); + } +} +); + +/* + highlight v4 + Highlights arbitrary terms. + + <http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html> + + MIT license. + + Johann Burkard + <http://johannburkard.de> + <mailto:jb@eaio.com> + */ + +jQuery.fn.highlight = function (pat) { + function innerHighlight(node, pat) { + var skip = 0; + if (node.nodeType == 3) { + var pos = node.data.toUpperCase().indexOf(pat); + if (pos >= 0) { + var spannode = document.createElement('span'); + spannode.className = 'highlight'; + var middlebit = node.splitText(pos); + var endbit = middlebit.splitText(pat.length); + var middleclone = middlebit.cloneNode(true); + spannode.appendChild(middleclone); + middlebit.parentNode.replaceChild(spannode, middlebit); + skip = 1; + } + } + else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) { + for (var i = 0; i < node.childNodes.length; ++i) { + i += innerHighlight(node.childNodes[i], pat); + } + } + return skip; + } + return this.length && pat && pat.length ? this.each(function () { + innerHighlight(this, pat.toUpperCase()); + }) : this; +}; + +jQuery.fn.removeHighlight = function () { + return this.find("span.highlight").each(function () { + this.parentNode.firstChild.nodeName; + with (this.parentNode) { + replaceChild(this.firstChild, this); + normalize(); + } + }).end(); +}; + + +/** + * add a filter form to a table + * @returns {undefined} + */ +function addFilterToTable(){ + var sValue=localStorage.getItem(localStoreTablefilter) ? localStorage.getItem(localStoreTablefilter) : ''; + var sForm='<form class="pure-form">\n\ + <fieldset>\n\ + <label for="eFilter">\n\ + <i class="fa fa-filter"></i> Tabelle filtern\n\ + </label>\n\ + <input type="text" id="eFilter" size="40" name="q" placeholder="Suchbegriff..." value="'+sValue+'" onkeypress="filterTable(this);" onkeyup="filterTable(this);" onchange="filterTable(this);">\n\ + <button class="pure-button" onclick="$(\'#eFilter\').val(\'\'); filterTable(); return false;"><i class="fa fa-times"></i> </button>\n\ + <span id="filterinfo"></span>\n\ + </fieldset>\n\ + </form><div style="clear: both;"></div>'; + $(sForm).insertBefore($("table").first()); +} + + +/** + * callback ... filter the table + * use addFilterToTable() before. + * @returns {undefined} + */ +function filterTable() { + var filter = $('#eFilter').val(); + localStorage.setItem(localStoreTablefilter, filter); + $("table").removeHighlight(); + if (filter) { + $("tr:regex('" + filter + "')").show(); + $("tr:not(:regex('" + filter + "'))").hide(); + $("tr").first().show(); + + $("td").highlight(filter); + } else { + $("td").removeHighlight(); + $('tr').show(); + } + + var sInfo = ''; + var iVisible = -1; // 1 abziehen wg. tr der ersten Zeile + $("tr").each(function () { + if ($(this).css('display') != 'none') { + iVisible++; + } + }); + + sInfo = (iVisible == ($("tr").length - 1)) + ? "ges.: <strong>" + ($("tr").length - 1) + "</strong> Einträge" + : "<strong>" + iVisible + "</strong> von " + ($("tr").length - 1) + " Einträgen" + ; + $('#filterinfo').html(sInfo); + +} diff --git a/public_html/deployment/main.css b/public_html/deployment/main.css index 3d99c5219f1f8f0c6f101bdd6af27ad69d10e85a..7baf003a4af9b0bfa32aaaab09222573d5450a14 100644 --- a/public_html/deployment/main.css +++ b/public_html/deployment/main.css @@ -1,5 +1,4 @@ - body{padding-top: 0;} #header,#footer{ background:#eee; background: linear-gradient(#fff,#eee); @@ -56,7 +55,7 @@ div#navbuttom{ display: none; } #divmodalmessage{ - margin: 20% auto; width: 50%; background: #fff; box-shadow: 0 0 3em #000; + margin: 10% auto; width: 50%; background: #fff; box-shadow: 0 0 5em #000; padding: 2em; } @@ -143,6 +142,7 @@ td.highlight{background:rgba(255,220,50,0.5) !important;} a.info { border-bottom: 1px dotted; padding-bottom: 2px;} a.info:hover { text-decoration: none; background: #fff;} +a.infoAsModal>span {display: none;} a.info>span{ background: #fff; box-shadow: 0 0 10px #888; display: none; margin-left: -150px; margin-top: -1em; padding: 0.5em; position: absolute; text-align: left; @@ -150,8 +150,8 @@ a.info>span{ background: #fff; box-shadow: 0 0 10px #888; display: none; } a.info>span.left{margin-left: 0;} a.info:hover span{ display: block; text-decoration: none;} -a.info span span.title{ background: #888; color:#f8f8f8; margin-top: -1em; padding: 0.5em 0.5em; float: left; box-shadow: 0 0 5px #ccc; border: 2px solid #fff;} -a.info span span.pre{ +span.title{ background: #888; color:#f8f8f8; margin-top: -1em; padding: 0.5em 0.5em; float: left; box-shadow: 0 0 5px #ccc; border: 2px solid #fff;} +span.pre{ line-height: 1.2em; padding: 5px; background-color: #F5F5F5;