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 }