1 /** 2 Copyright: Copyright (c) 2021, Joakim Brännström. All rights reserved. 3 License: MPL-2 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 This Source Code Form is subject to the terms of the Mozilla Public License, 7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain 8 one at http://mozilla.org/MPL/2.0/. 9 */ 10 module dextool.plugin.mutate.backend.report.html.page_worklist; 11 12 import logger = std.experimental.logger; 13 import std.array : empty; 14 import std.conv : to; 15 import std.datetime : Clock; 16 import std.exception : collectException; 17 import std.format : format; 18 import std.traits : EnumMembers; 19 import std.typecons : tuple; 20 21 import arsd.dom : Document, Element, Table, RawSource; 22 import miniorm : spinSql; 23 import my.path : AbsolutePath, Path; 24 import my.optional; 25 26 import dextool.cachetools; 27 import dextool.plugin.mutate.backend.database : Database, MutantInfo2; 28 import dextool.plugin.mutate.backend.report.html.constants : HtmlStyle = Html; 29 import dextool.plugin.mutate.backend.report.html.constants; 30 import dextool.plugin.mutate.backend.report.html.tmpl : tmplBasicPage, 31 dashboardCss, tmplSortableTable; 32 import dextool.plugin.mutate.backend.report.html.utility : pathToHtmlLink, toShortDate, toShortTime; 33 import dextool.plugin.mutate.backend.resource; 34 import dextool.plugin.mutate.backend.type : Mutation; 35 import dextool.plugin.mutate.backend.report.html.utility : generatePopupHelp; 36 37 @safe: 38 39 void makeWorklistPage(ref Database db, Element root, const AbsolutePath mutantPageFname) @trusted { 40 makePage(db, mutantPageFname); 41 } 42 43 private: 44 45 void makePage(ref Database db, const AbsolutePath pageFname) @system { 46 import std.algorithm : map, filter; 47 import std.path : buildPath; 48 import std.range : enumerate; 49 import dextool.plugin.mutate.backend.database : IterateMutantRow2, MutationStatusId; 50 import dextool.plugin.mutate.backend.report.analyzers : calcAvgPerMutant; 51 52 auto doc = tmplBasicPage.dashboardCss; 53 scope (success) 54 () { 55 import std.stdio : File; 56 57 auto fout = File(pageFname, "w"); 58 fout.write(doc.toPrettyString); 59 }(); 60 61 doc.title(format("Worklist %s", Clock.currTime)); 62 doc.mainBody.addChild("h1", "Worklist"); 63 doc.mainBody.setAttribute("onload", "init()"); 64 65 { 66 auto data = dashboard(); 67 auto style = doc.root.childElements("head")[0].addChild("style"); 68 style.addChild(new RawSource(doc, data.bootstrapCss.get)); 69 style.addChild(new RawSource(doc, data.dashboardCss.get)); 70 style.addChild(new RawSource(doc, tmplDefaultCss)); 71 72 auto script = doc.root.childElements("head")[0].addChild("script"); 73 script.addChild(new RawSource(doc, jsIndex)); 74 } 75 76 auto root = doc.mainBody; 77 78 void addPopupHelp(Element e, string header) { 79 switch (header) { 80 case "Tested": 81 generatePopupHelp(e, "Date when the mutant was last tested/executed."); 82 break; 83 case "Finished": 84 generatePopupHelp(e, "Prediction for when the mutant is executed."); 85 break; 86 case "Priority": 87 generatePopupHelp(e, 88 "How important it is to kill the mutant. It is based on modified source code size."); 89 break; 90 default: 91 break; 92 } 93 } 94 95 auto tbl = tmplSortableTable(root, [ 96 "Order", "ID", "Link", "Priority", "Tested", "Status", "Finished" 97 ], &addPopupHelp); 98 99 static string toLinkPath(Path path, MutationStatusId id) { 100 return format!"%s#%s"(buildPath(HtmlStyle.fileDir, pathToHtmlLink(path)), id); 101 } 102 103 const avg = calcAvgPerMutant(db); 104 105 foreach (data; spinSql!(() => db.worklistApi.getAll).map!( 106 a => spinSql!(() => tuple(a.prio, db.mutantApi.getMutantInfo(a.id)))) 107 .filter!(a => a[1].hasValue) 108 .map!(a => tuple(a[0], a[1].orElse(MutantInfo2.init))) 109 .enumerate) { 110 auto mut = data.value[1]; 111 auto r = tbl.appendRow; 112 113 r.addChild("td", data.index.to!string); 114 r.addChild("td", mut.id.get.to!string); 115 r.addChild("td").addChild("a", format("%s:%s", mut.file, 116 mut.sloc.line)).href = toLinkPath(mut.file, mut.id); 117 r.addChild("td", data.value[0].get.to!string); 118 r.addChild("td", mut.status == Mutation.Status.unknown ? "" : mut.updated.toShortDate); 119 r.addChild("td", mut.status.to!string); 120 r.addChild("td", (data.index * avg.get).toShortTime); 121 } 122 }