public string GenerateLane(GetViewWorkTableDataResponse response, DBLane lane, DBHost host, DBCommand command)
    {
        StringBuilder      matrix = new StringBuilder();
        List <DBWorkView2> steps;

        steps = response.WorkViews;

        matrix.AppendLine("<table class='buildstatus'>");
        matrix.AppendLine("<tr>");
        matrix.AppendLine("\t<th>Revision</th>");
        matrix.AppendLine("\t<th>Start Time</th>");
        matrix.AppendLine("\t<th>Duration</th>");;
        matrix.AppendLine("\t<th>Html report</th>");
        matrix.AppendLine("\t<th>Summary</th>");
        matrix.AppendLine("\t<th>Files</th>");
        matrix.AppendLine("</tr>");


        for (int i = 0; i < steps.Count; i++)
        {
            DBWorkView2           view  = steps [i];
            List <DBWorkFileView> files = response.WorkFileViews [i];
            DBState state = (DBState)view.state;

            matrix.Append("<tr>");

            // revision
            string result;
            switch (state)
            {
            case DBState.NotDone:
                result = "queued"; break;

            case DBState.Executing:
                result = "running"; break;

            case DBState.Failed:
                result = view.nonfatal ? "issues" : "failure"; break;

            case DBState.Success:
            case DBState.Aborted:
            case DBState.Timeout:
            case DBState.Paused:
            default:
                result = state.ToString().ToLowerInvariant();
                break;
            }

            // result

            matrix.AppendFormat("\t<td class='{0}'><a href='ViewLane.aspx?lane_id={2}&host_id={3}&revision_id={4}'>{1}</a></td>", result, view.revision, lane.id, host.id, view.revision_id);

            if (state > DBState.NotDone && state != DBState.Paused && state != DBState.Ignore)
            {
                matrix.AppendFormat("<td>{0}</td>", view.starttime.ToString("yyyy/MM/dd HH:mm:ss UTC"));
            }
            else
            {
                matrix.AppendLine("<td>-</td>");
            }
            // duration
            matrix.Append("\t<td>");
            if (state >= DBState.Executing && state != DBState.Paused && state != DBState.Ignore)
            {
                matrix.Append("[");
                matrix.Append(MonkeyWrench.Utilities.GetDurationFromWorkView(view).ToString());
                matrix.Append("]");
            }
            else
            {
                matrix.Append("-");
            }
            matrix.AppendLine("</td>");

            // html report
            matrix.AppendLine("<td>");
            DBWorkFileView index_html = null;
            foreach (DBWorkFileView file in files)
            {
                if (file.filename == "index.html")
                {
                    index_html = file;
                    break;
                }
            }
            if (index_html != null)
            {
                matrix.AppendFormat("<a href='ViewHtmlReport.aspx?workfile_id={0}'>View html report</a>", index_html.id);
            }
            else
            {
                matrix.AppendLine("-");
            }
            matrix.AppendLine("</td>");

            // summary
            matrix.AppendLine("<td>");
            matrix.AppendLine(view.summary);
            matrix.AppendLine("</td>");


            matrix.AppendLine("</tr>");
        }

        matrix.AppendLine("</table>");

        return(matrix.ToString());
    }
Example #2
0
    void WriteWorkCell(StringBuilder row, DBRevisionWorkView2 work)
    {
        if (work == null)
        {
            row.Append("<td>-</td>");
            return;
        }

        string  revision    = work.revision;
        int     lane_id     = work.lane_id;
        int     host_id     = work.host_id;
        int     revision_id = work.revision_id;
        DBState state       = work.State;
        bool    completed   = work.completed;
        string  state_str   = state.ToString().ToLowerInvariant();
        bool    is_working;
        string  str_date = string.Empty;

        if (work.endtime != null && work.endtime.Value.Year > 2000)
        {
            str_date = "<br/>" + TimeDiffToString(work.endtime.Value, DateTime.UtcNow);
        }

        switch (state)
        {
        case DBState.Executing:
            is_working = true;
            break;

        case DBState.NotDone:
        case DBState.Paused:
        case DBState.DependencyNotFulfilled:
        case DBState.Ignore:
            is_working = false;
            break;

        default:
            is_working = !completed;
            break;
        }

        long dummy;

        if (revision.Length > 16 && !long.TryParse(revision, out dummy))
        {
            revision = revision.Substring(0, 8);
        }

        if (is_working)
        {
            row.AppendFormat(
                @"<td class='{1}'>
							<center>
								<table class='executing'>
									<td>
										<a href='ViewLane.aspx?lane_id={2}&amp;host_id={3}&amp;revision_id={4}' title='{5}'>{0}{6}</a>
									</td>
								</table>
							<center>
						  </td>"                        ,
                revision, state_str, lane_id, host_id, revision_id, "", str_date);
        }
        else
        {
            row.AppendFormat("<td class='{1}'><a href='ViewLane.aspx?lane_id={2}&amp;host_id={3}&amp;revision_id={4}' title='{5}'>{0}{6}</a></td>",
                             revision, state_str, lane_id, host_id, revision_id, "", str_date);
        }
    }
Example #3
0
        private string GetStepHistory()
        {
            using (var db = new DB()) {
                var results = new List <object>();

                DBHost    host    = null;
                DBLane    lane    = null;
                DBCommand command = null;
                GetViewWorkTableDataResponse response = null;

                MonkeyWrench.WebServices.Authentication.Authenticate(Context, db, login, null, true);
                response = Utils.LocalWebService.GetViewWorkTableData(login,
                                                                      Utils.TryParseInt32(Request ["lane_id"]), Request ["lane"],
                                                                      Utils.TryParseInt32(Request ["host_id"]), Request ["host"],
                                                                      Utils.TryParseInt32(Request ["command_id"]), Request ["command"]);

                lane    = response.Lane;
                host    = response.Host;
                command = response.Command;

                if (lane == null || host == null || command == null)
                {
                    return("[]");
                }

                List <DBWorkView2> steps;

                steps = response.WorkViews;
                for (int i = 0; i < steps.Count; i++)
                {
                    DBWorkView2           view  = steps [i];
                    List <DBWorkFileView> files = response.WorkFileViews [i];
                    DBState state = (DBState)view.state;

                    // revision
                    string result;
                    switch (state)
                    {
                    case DBState.NotDone:
                        result = "queued"; break;

                    case DBState.Executing:
                        result = "running"; break;

                    case DBState.Failed:
                        result = view.nonfatal ? "issues" : "failure"; break;

                    case DBState.Success:
                    case DBState.Aborted:
                    case DBState.Timeout:
                    case DBState.Paused:
                    default:
                        result = state.ToString().ToLowerInvariant();
                        break;
                    }

                    DateTime starttime = view.starttime.ToLocalTime();
                    DateTime endtime   = view.endtime.ToLocalTime();
                    int      duration  = (int)(endtime - starttime).TotalSeconds;

                    results.Add(new Dictionary <string, object> {
                        { "id", view.id },
                        { "author", view.author },
                        { "workhost_id", view.workhost_id == null ? -1 : view.workhost_id },
                        { "workhost", view.workhost == null ? "" : view.workhost },
                        { "start", view.starttime.ToUniversalTime() },
                        { "duration", duration },
                        { "duration_string", MonkeyWrench.Utilities.GetDurationFromWorkView(view).ToString() },
                        { "lane", lane.lane },
                        { "revision_id", view.revision_id },
                        { "revision", view.revision },
                        { "status", result },
                        { "summary", view.summary }
                    });
                }

                return(JsonConvert.SerializeObject(results, Formatting.Indented));
            }
        }
Example #4
0
    public string GenerateLane(GetViewLaneDataResponse response)
    {
        StringBuilder      matrix       = new StringBuilder();
        List <DBWorkView2> steps        = response.WorkViews;
        DBRevision         dbr          = response.Revision;
        DBRevisionWork     revisionwork = response.RevisionWork;
        DBLane             lane         = response.Lane;
        DBHost             host         = response.Host;
        DBRevision         revision     = response.Revision;

        StringBuilder header = new StringBuilder();

        header.AppendFormat("Revision: <a href='GetRevisionLog.aspx?id={0}'>{1}</a>", dbr.id, dbr.revision);
        header.AppendFormat(" - Status: {0}", revisionwork.State);
        header.AppendFormat(" - Author: {0}", dbr.author);
        header.AppendFormat(" - Commit date: {0}", dbr.date.ToString("yyyy/MM/dd HH:mm:ss UTC"));

        if (Authentication.IsInRole(response, MonkeyWrench.DataClasses.Logic.Roles.Administrator))
        {
            bool isExecuting = response.RevisionWork.State == DBState.Executing || (response.RevisionWork.State == DBState.Issues && !response.RevisionWork.completed) || response.RevisionWork.State == DBState.Aborted;
            if (isExecuting)
            {
                header.AppendFormat(" - <a href='javascript:confirmViewLaneAction (\"ViewLane.aspx?lane_id={0}&amp;host_id={2}&amp;revision_id={1}&amp;action=clearrevision\", \"clear\");'>reset work</a>", lane.id, dbr.id, host.id);
                header.AppendFormat(" - <a href='javascript:confirmViewLaneAction (\"ViewLane.aspx?lane_id={0}&amp;host_id={2}&amp;revision_id={1}&amp;action=deleterevision\", \"delete\");'>delete work</a>", lane.id, dbr.id, host.id);
                header.AppendFormat(" - <a href='ViewLane.aspx?lane_id={0}&amp;host_id={2}&amp;revision_id={1}&amp;action=abortrevision'>abort work</a>", lane.id, dbr.id, host.id);
            }
            else if (response.RevisionWork.State == DBState.Ignore)
            {
                header.AppendFormat(" - <a href='ViewLane.aspx?lane_id={0}&amp;host_id={2}&amp;revision_id={1}&amp;action=clearrevision'>build this revision</a>", lane.id, dbr.id, host.id);
            }
            else
            {
                if (response.RevisionWork.State == DBState.NotDone)
                {
                    header.AppendFormat(" - <a href='ViewLane.aspx?lane_id={0}&amp;host_id={2}&amp;revision_id={1}&amp;action=ignorerevision'>don't build</a>", lane.id, dbr.id, host.id);
                }
                if (response.RevisionWork.State != DBState.NoWorkYet)
                {
                    header.AppendFormat(" - <a href='ViewLane.aspx?lane_id={0}&amp;host_id={2}&amp;revision_id={1}&amp;action=clearrevision'>reset work</a>", lane.id, dbr.id, host.id);
                    header.AppendFormat(" - <a href='ViewLane.aspx?lane_id={0}&amp;host_id={2}&amp;revision_id={1}&amp;action=deleterevision'>delete work</a>", lane.id, dbr.id, host.id);
                }
            }
        }

        if (response.WorkHost != null)
        {
            header.AppendFormat(" - Assigned to <a href='ViewHostHistory.aspx?host_id={1}'>{0}</a>", response.WorkHost.host, response.WorkHost.id);
        }
        else
        {
            header.AppendFormat(" - Unassigned.");
        }

        if (!revisionwork.completed && revisionwork.State != DBState.NotDone && revisionwork.State != DBState.Paused && revisionwork.State != DBState.Ignore)
        {
            header.Insert(0, "<center><table class='executing'><td>");
            header.Append("</td></table></center>");
        }

        // matrix.AppendFormat ("<div class='buildstatus {0}'>Status: {0}</div>", revisionwork.State.ToString ().ToLowerInvariant ());

        matrix.AppendLine("<table class='buildstatus'>");

        matrix.AppendFormat("<tr class='{0}'>", revisionwork.State.ToString().ToLowerInvariant());
        matrix.Append("<th colspan='9'>");
        matrix.Append(header.ToString());
        matrix.Append("</th>");
        matrix.AppendLine("</tr>");

        matrix.AppendLine("<tr>");
        matrix.AppendLine("\t<th>Step</th>");
        matrix.AppendLine("\t<th>Result</th>");
        matrix.AppendLine("\t<th>Start Time</th>");
        matrix.AppendLine("\t<th>Duration</th>");
        matrix.AppendLine("\t<th>Html report</th>");
        matrix.AppendLine("\t<th>Summary</th>");
        matrix.AppendLine("\t<th>Files</th>");
        matrix.AppendLine("\t<th>Host</th>");
        matrix.AppendLine("\t<th>Misc</th>");
        matrix.AppendLine("</tr>");

        bool failed = false;

        for (int s = 0; s < steps.Count; s++)
        {
            DBWorkView2              step     = steps [s];
            DBState                  state    = (DBState)step.state;
            bool                     nonfatal = step.nonfatal;
            string                   command  = step.command;
            List <DBWorkFileView>    files    = response.WorkFileViews [s];
            IEnumerable <DBFileLink> links    = response.Links.Where <DBFileLink> ((DBFileLink link) => link.work_id == step.id);

            if (state == DBState.Failed && !nonfatal)
            {
                failed = true;
            }

            matrix.AppendLine("<tr>");

            // step
            DBWorkFileView step_log = files.Find((v) => v.filename == command + ".log");
            matrix.Append("\t<td>");
            if (step_log != null)
            {
                matrix.AppendFormat("<a href='GetFile.aspx?id={0}'>{1}</a> ", step_log.id, command);
            }
            else
            {
                matrix.Append(command);
            }
            matrix.Append("</td>");

            // result
            string result;
            switch (state)
            {
            case DBState.NotDone:
                result = failed ? "skipped" : "queued"; break;

            case DBState.Executing:
                result = "running"; break;

            case DBState.Failed:
                result = nonfatal ? "issues" : "failure"; break;

            case DBState.Success:
            case DBState.Aborted:
            case DBState.Timeout:
            case DBState.Paused:
            default:
                result = state.ToString().ToLowerInvariant();
                break;
            }

            // result
            matrix.AppendFormat("\t<td class='{0}'>{0}</td>", result);

            if (state > DBState.NotDone && state != DBState.Paused && state != DBState.Ignore && state != DBState.DependencyNotFulfilled)
            {
                matrix.AppendFormat("<td>{0}</td>", step.starttime.ToString("yyyy/MM/dd HH:mm:ss UTC"));
            }
            else
            {
                matrix.AppendLine("<td>-</td>");
            }
            // duration
            matrix.Append("\t<td>");
            if (state >= DBState.Executing && state != DBState.Paused && state != DBState.Ignore && state != DBState.DependencyNotFulfilled && state != DBState.Aborted)
            {
                matrix.Append("[");
                matrix.Append(MonkeyWrench.Utilities.GetDurationFromWorkView(step).ToString());
                matrix.Append("]");
            }
            else
            {
                matrix.Append("-");
            }
            matrix.AppendLine("</td>");

            // html report
            matrix.AppendLine("<td>");
            DBWorkFileView index_html = null;

            foreach (DBWorkFileView file in files)
            {
                if (file.filename == "index.html")
                {
                    index_html = file;
                    break;
                }
            }

            if (index_html != null)
            {
                matrix.AppendFormat("<a href='ViewHtmlReportEmbedded.aspx?workfile_id={0}&lane_id={1}&host_id={2}&revision_id={3}'>View html report</a>", index_html.id, lane.id, host.id, revision.id);
            }
            else
            {
                matrix.AppendLine("-");
            }
            matrix.AppendLine("</td>");

            // summary
            matrix.AppendLine("<td>");
            matrix.AppendLine(step.summary);
            matrix.AppendLine("</td>");

            // files
            matrix.AppendLine("<td style='text-align: left;'>");
            var sb         = new StringBuilder();
            var file_count = 0;
            foreach (DBWorkFileView file in files.Where((v) => !v.hidden).OrderBy((v) => v.filename))
            {
                if (file.hidden)
                {
                    continue;
                }
                if (file_count > 0)
                {
                    sb.Append(", ");
                }
                file_count++;
                sb.AppendFormat("<a href='GetFile.aspx?id={0}'>{1}</a> ", file.id, file.filename);
            }

            foreach (var link in links.OrderBy((v) => v.link))
            {
                if (file_count > 0)
                {
                    sb.Append(", ");
                }
                file_count++;
                sb.Append(link.link);
            }

            if (file_count > 3)
            {
                matrix.AppendFormat("<span id='files_{0}' style='display: none'>{1}</span>" +
                                    "<a href='#' id='showFiles_{0}' onclick='javascript:document.getElementById (\"files_{0}\").style.display = \"block\"; document.getElementById (\"showFiles_{0}\").style.display = \"none\";'>Show {2} files</a>",
                                    step.id, sb.ToString(), file_count);
            }
            else
            {
                matrix.Append(sb.ToString());
            }
            matrix.AppendLine("</td>");

            // host
            matrix.AppendFormat("<td>{0}</td>", step.workhost);

            // misc
            matrix.AppendFormat("\t<td><a href='ViewWorkTable.aspx?lane_id={1}&amp;host_id={2}&amp;command_id={3}'>History for '{4}'</a></td>", result, lane.id, host.id, step.command_id, command);

            matrix.AppendLine("</tr>");
        }
        matrix.AppendLine("</table>");

        return(matrix.ToString());
    }
    public string GenerateLaneTable(GetViewTableDataResponse response, DBLane lane, DBHost host, bool horizontal, int page, int limit)
    {
        StringBuilder             matrix       = new StringBuilder();
        StringBuilder             tooltip      = new StringBuilder();
        bool                      new_revision = true;
        int                       revision_id  = 0;
        List <DBRevisionWorkView> views        = response.RevisionWorkViews;
        List <List <TableNode> >  table        = new List <List <TableNode> > ();
        List <TableNode>          row          = new List <TableNode> ();
        List <TableNode>          header       = new List <TableNode> ();

        for (int i = 0; i < views.Count; i++)
        {
            while (header.Count <= views [i].sequence)
            {
                header.Add(null);
            }
            if (header [views [i].sequence] != null)
            {
                continue;
            }

            var node = new TableNode(string.Format("<a href='ViewWorkTable.aspx?lane_id={0}&amp;host_id={1}&amp;command_id={2}'>{3}</a>", lane.id, host.id, views [i].command_id, views [i].command));
            node.command_id             = views [i].command_id;
            header [views [i].sequence] = node;
        }
        header.RemoveAll(delegate(TableNode match) { return(match == null); });
        header.Insert(0, new TableNode("Revision", true));
        header.Insert(1, new TableNode("Diff", true));
        header.Insert(2, new TableNode("Author", true));
        //if (Authentication.IsInRole (response, MonkeyWrench.DataClasses.Logic.Roles.Administrator)) {
        //    header.Insert (3, new TableNode ("Select", true));
        //}
        header.Add(new TableNode("Host", true));
        header.Add(new TableNode("Duration", true));
        table.Add(header);

        bool   failed   = false;
        double duration = 0;

        for (int i = 0; i < views.Count; i++)
        {
            DBRevisionWorkView view = views [i];
            DBState            revisionwork_state = (DBState)view.revisionwork_state;
            DBState            state = (DBState)view.state;

            new_revision = revision_id != view.revision_id;
            revision_id  = view.revision_id;

            if (new_revision)
            {
                if (i > 0)
                {
                    table.Add(row);
                    row [row.Count - 1] = new TableNode(TimeSpan.FromSeconds(duration).ToString(), row [0].@class);
                }

                string revision = view.revision;
                long   dummy;
                if (revision.Length > 16 && !long.TryParse(revision, out dummy))
                {
                    revision = revision.Substring(0, 8);
                }

                string clazz = revisionwork_state.ToString().ToLower();
                clazz = clazz + " " + DarkenColor(clazz, table.Count);
                row   = new List <TableNode> ();

                tooltip.Length = 0;
                tooltip.AppendFormat("Author: {0}.", view.author);
                if (view.starttime.Date.Year > 2000)
                {
                    tooltip.AppendFormat(" Build start date: {0}.", view.starttime.ToUniversalTime().ToString("yyyy/MM/dd HH:mm:ss UTC"));
                }

                row.Add(new TableNode(string.Format("<a href='ViewLane.aspx?lane_id={0}&amp;host_id={1}&amp;revision_id={2}' title='{4}'>{3}</a>", lane.id, host.id, view.revision_id, revision, tooltip.ToString()), clazz));
                row.Add(new TableNode(string.Format("<a href='GetRevisionLog.aspx?id={0}'>diff</a>", view.revision_id)));
                row.Add(new TableNode(view.author));

                //if (Authentication.IsInRole (response, MonkeyWrench.DataClasses.Logic.Roles.Administrator))
                //    row.Add (new TableNode (string.Format ("<input type=checkbox id='id_revision_chk_{1}' name='revision_id_{0}' />", view.revision_id, i)));
                while (row.Count < header.Count - 2)
                {
                    row.Add(new TableNode("-"));
                }
                row.Add(new TableNode(view.workhost ?? ""));
                row.Add(new TableNode(""));
                failed   = false;
                duration = 0;
            }

            if (view.endtime > view.starttime)
            {
                duration += (view.endtime - view.starttime).TotalSeconds;
            }

            if (state == DBState.Failed && !view.nonfatal)
            {
                failed = true;
            }
            else if (revisionwork_state == DBState.Failed)
            {
                failed = true;
            }

            // result
            string result;
            bool   completed = true;
            switch (state)
            {
            case DBState.NotDone:
                completed = false;
                result    = failed ? "skipped" : "queued"; break;

            case DBState.Executing:
                completed = false;
                result    = "running"; break;

            case DBState.Failed:
                result = view.nonfatal ? "issues" : "failure"; break;

            case DBState.Success:
                result = "success"; break;

            case DBState.Aborted:
                result = "aborted"; break;

            case DBState.Timeout:
                result = "timeout"; break;

            case DBState.Paused:
                completed = false;
                result    = "paused"; break;

            case DBState.Ignore:
                completed = false;
                result    = "ignore"; break;

            default:
                completed = true;
                result    = "unknown"; break;
            }

            for (int j = 2; j < header.Count; j++)
            {
                if (header [j].command_id == view.command_id)
                {
                    if (completed)
                    {
                        row [j] = new TableNode(string.Format("<a href='{0}'>{1}</a>", Utilities.CreateWebServiceDownloadUrl(Request, view.id, view.command + ".log", true), result));
                    }
                    else
                    {
                        row [j] = new TableNode(result);
                    }
                    row [j].@class = result + " " + DarkenColor(result, table.Count);
                    break;
                }
            }
        }

        table.Add(row);
        row [row.Count - 1] = new TableNode(TimeSpan.FromSeconds(duration).ToString(), row [0].@class);

        matrix.AppendLine("<table class='buildstatus'>");
        if (horizontal)
        {
            for (int i = 0; i < header.Count; i++)
            {
                matrix.Append("<tr>");
                for (int j = 0; j < table.Count; j++)
                {
                    TableNode node = table [j] [i];
                    string    td   = node.is_header ? "th" : "td";
                    matrix.Append('<');
                    matrix.Append(td);
                    if (node.@class != null)
                    {
                        matrix.Append(" class='");
                        matrix.Append(node.@class);
                        matrix.Append("'");
                    }

                    /*
                     * if (node.style != null) {
                     *      matrix.Append (" style='");
                     *      matrix.Append (node.style);
                     *      matrix.Append ("'");
                     * }*/
                    matrix.Append(">");
                    matrix.Append(node.text);
                    matrix.Append("</");
                    matrix.Append(td);
                    matrix.Append(">");
                }
                matrix.AppendLine("</tr>");
            }
        }
        else
        {
            for (int i = 0; i < table.Count; i++)
            {
                matrix.Append("<tr>");
                for (int j = 0; j < row.Count; j++)
                {
                    TableNode node = table [i] [j];
                    string    td   = node.is_header ? "th" : "td";
                    matrix.Append('<');
                    matrix.Append(td);
                    if (node.@class != null)
                    {
                        matrix.Append(" class='");
                        matrix.Append(node.@class);
                        matrix.Append("'");
                    }

                    /*
                     * if (node.style != null) {
                     *      matrix.Append (" style='");
                     *      matrix.Append (node.style);
                     *      matrix.Append ("'");
                     * }*/
                    matrix.Append(">");
                    matrix.Append(node.text);
                    matrix.Append("</");
                    matrix.Append(td);
                    matrix.Append(">");
                }
                matrix.AppendLine("</tr>");
            }
        }
        matrix.AppendLine("</table>");
        return(matrix.ToString());
    }
Example #6
0
    public string GenerateOverview(FrontPageResponse data)
    {
        StringBuilder        matrix         = new StringBuilder();
        LaneTreeNode         tree           = BuildTree(data);
        List <StringBuilder> header_rows    = new List <StringBuilder> ();
        List <int>           hostlane_order = new List <int> ();

        if (tree == null)
        {
            return(string.Empty);
        }

        WriteLanes(header_rows, tree, 0, tree.Depth);

        matrix.AppendLine("<table class='buildstatus'>");
        for (int i = 0; i < header_rows.Count; i++)
        {
            if (header_rows [i].Length == 0)
            {
                continue;
            }

            matrix.Append("<tr>");
            matrix.Append(header_rows [i]);
            matrix.AppendLine("</tr>");
        }

        matrix.AppendLine("<tr>");
        WriteHostLanes(matrix, tree, data.Hosts, hostlane_order);
        matrix.AppendLine("</tr>");

        int           counter = 0;
        int           added   = 0;
        StringBuilder row     = new StringBuilder();

        do
        {
            added      = 0;
            row.Length = 0;

            for (int i = 0; i < hostlane_order.Count; i++)
            {
                int hl_id = hostlane_order [i];

                List <DBRevisionWorkView2> rev  = null;
                DBRevisionWorkView2        work = null;

                for (int k = 0; k < data.RevisionWorkHostLaneRelation.Count; k++)
                {
                    if (data.RevisionWorkHostLaneRelation [k] == hl_id)
                    {
                        rev = data.RevisionWorkViews [k];
                        break;
                    }
                }

                if (rev != null && rev.Count > counter)
                {
                    work = rev [counter];
                    added++;
                }

                if (work != null)
                {
                    string  revision    = work.revision;
                    int     lane_id     = work.lane_id;
                    int     host_id     = work.host_id;
                    int     revision_id = work.revision_id;
                    DBState state       = work.State;
                    bool    completed   = work.completed;
                    string  state_str   = state.ToString().ToLowerInvariant();
                    bool    is_working;
                    string  str_date = string.Empty;

                    if (work.endtime.Year > 2000)
                    {
                        str_date = "<br/>" + TimeDiffToString(work.endtime, DateTime.UtcNow);
                    }

                    switch (state)
                    {
                    case DBState.Executing:
                        is_working = true;
                        break;

                    case DBState.NotDone:
                    case DBState.Paused:
                    case DBState.DependencyNotFulfilled:
                    case DBState.Ignore:
                        is_working = false;
                        break;

                    default:
                        is_working = !completed;
                        break;
                    }

                    long dummy;
                    if (revision.Length > 16 && !long.TryParse(revision, out dummy))
                    {
                        revision = revision.Substring(0, 8);
                    }

                    if (is_working)
                    {
                        row.AppendFormat(
                            @"<td class='{1}'>
								<center>
									<table class='executing'>
										<td>
											<a href='ViewLane.aspx?lane_id={2}&amp;host_id={3}&amp;revision_id={4}' title='{5}'>{0}{6}</a>
										</td>
									</table>
								<center>
							  </td>"                            ,
                            revision, state_str, lane_id, host_id, revision_id, "", str_date);
                    }
                    else
                    {
                        row.AppendFormat("<td class='{1}'><a href='ViewLane.aspx?lane_id={2}&amp;host_id={3}&amp;revision_id={4}' title='{5}'>{0}{6}</a></td>",
                                         revision, state_str, lane_id, host_id, revision_id, "", str_date);
                    }
                }
                else
                {
                    row.Append("<td>-</td>");
                }
            }

            if (added > 0 && row.Length > 0)
            {
                matrix.Append("<tr>");
                matrix.Append(row.ToString());
                matrix.Append("</tr>");
            }

            counter++;
        } while (counter <= limit && added > 0);

        matrix.AppendLine("</table>");

        return(matrix.ToString());
    }