Skip to content

Commit

Permalink
feat(state): ability to calculate any table and to see its log
Browse files Browse the repository at this point in the history
Closes: #67
  • Loading branch information
nergal-perm committed Sep 17, 2024
1 parent 9a600ee commit 5a807a1
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 7 deletions.
4 changes: 4 additions & 0 deletions src/main/java/ru/ewc/checklogic/ServerInstance.java
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ public boolean isAvailable(final String command, final String field) {
return "true".equalsIgnoreCase(this.context.decisionFor(command).get(field));
}

public ComputationContext computation() {
return this.context;
}

public void update(final List<String> values) {
final InMemoryLocator request = InMemoryLocator.empty(this.server.requestLocatorName());
values.forEach(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public String renderInLayout(final String template, final Map<String, String> va
);
}

private String renderTemplateWith(final String template, final Map<String, String> values) {
public String renderTemplateWith(final String template, final Map<String, String> values) {
this.processors.putIfAbsent(
template, ResourceTemplateRender.templateProcessorFor(template)
);
Expand Down
63 changes: 58 additions & 5 deletions src/main/java/ru/ewc/checklogic/server/StatePage.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@
import com.renomad.minum.web.WebFramework;
import java.net.URI;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import ru.ewc.checklogic.ServerConfiguration;
import ru.ewc.checklogic.ServerInstance;
import ru.ewc.checklogic.testing.CheckSuite;
import ru.ewc.decisions.api.ComputationContext;
import ru.ewc.decisions.api.OutputTracker;
import ru.ewc.decisions.input.CombinedCsvFileReader;

/**
Expand Down Expand Up @@ -70,7 +73,7 @@ public StatePage(
@Override
public void register(final WebFramework web) {
web.registerPath(GET, "state", this::statePage);
web.registerPath(POST, "state", this::createState);
web.registerPath(POST, "state", this::postRouter);
web.registerPath(DELETE, "state", this::resetState);
}

Expand All @@ -82,17 +85,60 @@ private Response statePage(final Request request) {
"templates/state.html",
Map.of(
"state", stored.asHtmlList(),
"includes", this.listOfIncludes()
"includes", this.listOfIncludes(),
"tables", this.listOfTables()
)
)
);
}

private Response createState(final Request request) {
private Response postRouter(final Request request) {
assert request.requestLine().getMethod().equals(RequestLine.Method.POST);
final String include = request.body().asString("include");
this.context.createState(include, this.testSuite());
return Response.htmlOk("OK", Map.of("HX-Redirect", "/state"));
final String table = request.body().asString("table");
final ComputationContext computation = this.context.computation();
final Response result;
if (StatePage.isSpecified(include)) {
this.testSuite().findAndPerform(include, computation);
result = Response.htmlOk("OK", Map.of("HX-Redirect", "/state"));
} else if (StatePage.isSpecified(table)) {
final OutputTracker<String> tracker = computation.startTracking();
final Map<String, String> outcomes = computation.decisionFor(table);
result = Response.htmlOk(
this.processors.renderTemplateWith(
"templates/outcomes.html",
Map.of(
"outcomes", StatePage.asTable(outcomes),
"events", StatePage.asCollapsible(tracker.events())
)
)
);
} else {
result = Response.htmlOk("OK", Map.of("HX-Redirect", "/state"));
}
return result;
}

private static boolean isSpecified(final String include) {
return !include.isBlank();
}

private static String asCollapsible(final List<String> events) {
return events.stream()
.map("<li>%s</li>"::formatted)
.collect(Collectors.joining());
}

private static String asTable(final Map<String, String> outcomes) {
return outcomes.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.map(
entry -> "<tr><td>%s</td><td>%s</td></tr>".formatted(
entry.getKey(),
entry.getValue()
)
)
.collect(Collectors.joining());
}

private Response resetState(final Request request) {
Expand All @@ -119,4 +165,11 @@ private String listOfIncludes() {
.map(name -> "<option value=\"%s\">%s</option>".formatted(name, name))
.collect(Collectors.joining());
}

private String listOfTables() {
return this.context.computation().tableNames().stream()
.sorted()
.map(name -> "<option value=\"%s\">%s</option>".formatted(name, name))
.collect(Collectors.joining());
}
}
51 changes: 51 additions & 0 deletions src/main/resources/templates/outcomes.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<!--
~ MIT License
~
~ Copyright (c) 2024 Decision-Driven Development
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in all
~ copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
~ SOFTWARE.
-->
<table class="table table-striped table-hover mb-3">
<thead>
<tr>
<th scope="col">Outcome</th>
<th scope="col">Value</th>
</thead>
<tbody>
{{ outcomes }}
</tbody>
</table>
<div class="accordion">
<div class=" accordion-item">
<h2 class="accordion-header" id="flush-headingOne">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
data-bs-target="#flush-collapseOne" aria-expanded="false"
aria-controls="flush-collapseOne">
Events
</button>
</h2>
<div id="flush-collapseOne" class="accordion-collapse collapse"
aria-labelledby="flush-headingOne"
data-bs-parent="#accordionFlushExample">
<div class="accordion-body">
<ul>{{ events }}</ul>
</div>
</div>
</div>
</div>
13 changes: 12 additions & 1 deletion src/main/resources/templates/state.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ <h1>State entities</h1>
<div class="input-group">
<select class="form-select" id="include" name="include"
placeholder="Select a state to include"
aria-label="Example select with button addon">
aria-label="Dropbox with a list of includable tests or states">
{{ includes }}
</select>
<button class="btn btn-primary" type="submit">Create state</button>
Expand All @@ -46,6 +46,17 @@ <h1>State entities</h1>
</div>
</div>
<div class="col">
<h1>Tables</h1>
<form class="mb-3" hx-post="/state" hx-target="#table-details">
<div class="input-group">
<select class="form-select" id="table" name="table"
aria-label="Dropbox with a list of all the tables that could be evaluated">
{{ tables }}
</select>
<button class="btn btn-primary" type="submit">Evaluate table</button>
</div>
<div id="table-details"></div>
</form>
<h1>Context</h1>
<form class="mb-3" hx-post="/context" hx-target="#commands" hx-swap="innerHTML"
hx-trigger="submit, load">
Expand Down

0 comments on commit 5a807a1

Please sign in to comment.