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&auml;ge"
+            : "<strong>" + iVisible + "</strong> von " + ($("tr").length - 1) + " Eintr&auml;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;