Skip to content

Commit 5a807a1

Browse files
committed
feat(state): ability to calculate any table and to see its log
Closes: #67
1 parent 9a600ee commit 5a807a1

File tree

5 files changed

+126
-7
lines changed

5 files changed

+126
-7
lines changed

src/main/java/ru/ewc/checklogic/ServerInstance.java

+4
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ public boolean isAvailable(final String command, final String field) {
131131
return "true".equalsIgnoreCase(this.context.decisionFor(command).get(field));
132132
}
133133

134+
public ComputationContext computation() {
135+
return this.context;
136+
}
137+
134138
public void update(final List<String> values) {
135139
final InMemoryLocator request = InMemoryLocator.empty(this.server.requestLocatorName());
136140
values.forEach(

src/main/java/ru/ewc/checklogic/server/ResourceTemplateRender.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public String renderInLayout(final String template, final Map<String, String> va
5454
);
5555
}
5656

57-
private String renderTemplateWith(final String template, final Map<String, String> values) {
57+
public String renderTemplateWith(final String template, final Map<String, String> values) {
5858
this.processors.putIfAbsent(
5959
template, ResourceTemplateRender.templateProcessorFor(template)
6060
);

src/main/java/ru/ewc/checklogic/server/StatePage.java

+58-5
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,14 @@
2929
import com.renomad.minum.web.WebFramework;
3030
import java.net.URI;
3131
import java.nio.file.Path;
32+
import java.util.List;
3233
import java.util.Map;
3334
import java.util.stream.Collectors;
3435
import ru.ewc.checklogic.ServerConfiguration;
3536
import ru.ewc.checklogic.ServerInstance;
3637
import ru.ewc.checklogic.testing.CheckSuite;
38+
import ru.ewc.decisions.api.ComputationContext;
39+
import ru.ewc.decisions.api.OutputTracker;
3740
import ru.ewc.decisions.input.CombinedCsvFileReader;
3841

3942
/**
@@ -70,7 +73,7 @@ public StatePage(
7073
@Override
7174
public void register(final WebFramework web) {
7275
web.registerPath(GET, "state", this::statePage);
73-
web.registerPath(POST, "state", this::createState);
76+
web.registerPath(POST, "state", this::postRouter);
7477
web.registerPath(DELETE, "state", this::resetState);
7578
}
7679

@@ -82,17 +85,60 @@ private Response statePage(final Request request) {
8285
"templates/state.html",
8386
Map.of(
8487
"state", stored.asHtmlList(),
85-
"includes", this.listOfIncludes()
88+
"includes", this.listOfIncludes(),
89+
"tables", this.listOfTables()
8690
)
8791
)
8892
);
8993
}
9094

91-
private Response createState(final Request request) {
95+
private Response postRouter(final Request request) {
9296
assert request.requestLine().getMethod().equals(RequestLine.Method.POST);
9397
final String include = request.body().asString("include");
94-
this.context.createState(include, this.testSuite());
95-
return Response.htmlOk("OK", Map.of("HX-Redirect", "/state"));
98+
final String table = request.body().asString("table");
99+
final ComputationContext computation = this.context.computation();
100+
final Response result;
101+
if (StatePage.isSpecified(include)) {
102+
this.testSuite().findAndPerform(include, computation);
103+
result = Response.htmlOk("OK", Map.of("HX-Redirect", "/state"));
104+
} else if (StatePage.isSpecified(table)) {
105+
final OutputTracker<String> tracker = computation.startTracking();
106+
final Map<String, String> outcomes = computation.decisionFor(table);
107+
result = Response.htmlOk(
108+
this.processors.renderTemplateWith(
109+
"templates/outcomes.html",
110+
Map.of(
111+
"outcomes", StatePage.asTable(outcomes),
112+
"events", StatePage.asCollapsible(tracker.events())
113+
)
114+
)
115+
);
116+
} else {
117+
result = Response.htmlOk("OK", Map.of("HX-Redirect", "/state"));
118+
}
119+
return result;
120+
}
121+
122+
private static boolean isSpecified(final String include) {
123+
return !include.isBlank();
124+
}
125+
126+
private static String asCollapsible(final List<String> events) {
127+
return events.stream()
128+
.map("<li>%s</li>"::formatted)
129+
.collect(Collectors.joining());
130+
}
131+
132+
private static String asTable(final Map<String, String> outcomes) {
133+
return outcomes.entrySet().stream()
134+
.sorted(Map.Entry.comparingByKey())
135+
.map(
136+
entry -> "<tr><td>%s</td><td>%s</td></tr>".formatted(
137+
entry.getKey(),
138+
entry.getValue()
139+
)
140+
)
141+
.collect(Collectors.joining());
96142
}
97143

98144
private Response resetState(final Request request) {
@@ -119,4 +165,11 @@ private String listOfIncludes() {
119165
.map(name -> "<option value=\"%s\">%s</option>".formatted(name, name))
120166
.collect(Collectors.joining());
121167
}
168+
169+
private String listOfTables() {
170+
return this.context.computation().tableNames().stream()
171+
.sorted()
172+
.map(name -> "<option value=\"%s\">%s</option>".formatted(name, name))
173+
.collect(Collectors.joining());
174+
}
122175
}
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<!--
2+
~ MIT License
3+
~
4+
~ Copyright (c) 2024 Decision-Driven Development
5+
~
6+
~ Permission is hereby granted, free of charge, to any person obtaining a copy
7+
~ of this software and associated documentation files (the "Software"), to deal
8+
~ in the Software without restriction, including without limitation the rights
9+
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
~ copies of the Software, and to permit persons to whom the Software is
11+
~ furnished to do so, subject to the following conditions:
12+
~
13+
~ The above copyright notice and this permission notice shall be included in all
14+
~ copies or substantial portions of the Software.
15+
~
16+
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
~ SOFTWARE.
23+
-->
24+
<table class="table table-striped table-hover mb-3">
25+
<thead>
26+
<tr>
27+
<th scope="col">Outcome</th>
28+
<th scope="col">Value</th>
29+
</thead>
30+
<tbody>
31+
{{ outcomes }}
32+
</tbody>
33+
</table>
34+
<div class="accordion">
35+
<div class=" accordion-item">
36+
<h2 class="accordion-header" id="flush-headingOne">
37+
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
38+
data-bs-target="#flush-collapseOne" aria-expanded="false"
39+
aria-controls="flush-collapseOne">
40+
Events
41+
</button>
42+
</h2>
43+
<div id="flush-collapseOne" class="accordion-collapse collapse"
44+
aria-labelledby="flush-headingOne"
45+
data-bs-parent="#accordionFlushExample">
46+
<div class="accordion-body">
47+
<ul>{{ events }}</ul>
48+
</div>
49+
</div>
50+
</div>
51+
</div>

src/main/resources/templates/state.html

+12-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ <h1>State entities</h1>
3333
<div class="input-group">
3434
<select class="form-select" id="include" name="include"
3535
placeholder="Select a state to include"
36-
aria-label="Example select with button addon">
36+
aria-label="Dropbox with a list of includable tests or states">
3737
{{ includes }}
3838
</select>
3939
<button class="btn btn-primary" type="submit">Create state</button>
@@ -46,6 +46,17 @@ <h1>State entities</h1>
4646
</div>
4747
</div>
4848
<div class="col">
49+
<h1>Tables</h1>
50+
<form class="mb-3" hx-post="/state" hx-target="#table-details">
51+
<div class="input-group">
52+
<select class="form-select" id="table" name="table"
53+
aria-label="Dropbox with a list of all the tables that could be evaluated">
54+
{{ tables }}
55+
</select>
56+
<button class="btn btn-primary" type="submit">Evaluate table</button>
57+
</div>
58+
<div id="table-details"></div>
59+
</form>
4960
<h1>Context</h1>
5061
<form class="mb-3" hx-post="/context" hx-target="#commands" hx-swap="innerHTML"
5162
hx-trigger="submit, load">

0 commit comments

Comments
 (0)