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 36 @safe: 37 38 void makeWorklistPage(ref Database db, Element root, const AbsolutePath mutantPageFname) @trusted { 39 root.addChild("a", "Worklist").href = mutantPageFname.baseName; 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, MutationId; 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.setAttribute("onload", "init()"); 63 64 { 65 auto data = dashboard(); 66 auto style = doc.root.childElements("head")[0].addChild("style"); 67 style.addChild(new RawSource(doc, data.bootstrapCss.get)); 68 style.addChild(new RawSource(doc, data.dashboardCss.get)); 69 style.addChild(new RawSource(doc, tmplDefaultCss)); 70 71 auto script = doc.root.childElements("head")[0].addChild("script"); 72 script.addChild(new RawSource(doc, jsIndex)); 73 } 74 75 auto root = doc.mainBody; 76 root.addChild("p", "Tested: date when the mutant was last tested/executed."); 77 root.addChild("p", "Finished: prediction for when the mutan is executed"); 78 79 auto tbl = tmplSortableTable(root, [ 80 "Order", "ID", "Link", "Priority", "Tested", "Status", "Finished" 81 ]); 82 83 static string toLinkPath(Path path, MutationId id) { 84 return format!"%s#%s"(buildPath(HtmlStyle.fileDir, pathToHtmlLink(path)), id); 85 } 86 87 const avg = calcAvgPerMutant(db, [EnumMembers!(Mutation.Kind)]); 88 89 foreach (data; spinSql!(() => db.worklistApi.getAll).map!( 90 a => spinSql!(() => tuple(a.prio, db.mutantApi.getMutantInfo(a.id)))) 91 .filter!(a => a[1].hasValue) 92 .map!(a => tuple(a[0], a[1].orElse(MutantInfo2.init))) 93 .enumerate) { 94 auto mut = data.value[1]; 95 auto r = tbl.appendRow; 96 97 r.addChild("td", data.index.to!string); 98 r.addChild("td", mut.id.get.to!string); 99 r.addChild("td").addChild("a", format("%s:%s", mut.file, 100 mut.sloc.line)).href = toLinkPath(mut.file, mut.id); 101 r.addChild("td", data.value[0].get.to!string); 102 r.addChild("td", mut.status == Mutation.Status.unknown ? "" : mut.updated.toShortDate); 103 r.addChild("td", mut.status.to!string); 104 r.addChild("td", (data.index * avg.get).toShortTime); 105 } 106 }