Skip to content
Snippets Groups Projects
Commit 6881e240 authored by Jonas Blatt's avatar Jonas Blatt :ant:
Browse files

Merge branch 'develop' into 'master'

Develop

See merge request fg-bks/br-verification-tool!5
parents 94bf057f 91639b42
No related branches found
No related tags found
No related merge requests found
Showing
with 211 additions and 85 deletions
...@@ -11,6 +11,10 @@ import java.io.File; ...@@ -11,6 +11,10 @@ import java.io.File;
import java.net.URL; import java.net.URL;
import java.util.List; import java.util.List;
/**
* WordnetService provides some functions from wordnet <br>
* First, get the instance with getInstance() (singleton) and than use the provided functions.
*/
public class WordnetService { public class WordnetService {
private static final String PATH_WORDNET = "dict/"; private static final String PATH_WORDNET = "dict/";
...@@ -23,6 +27,13 @@ public class WordnetService { ...@@ -23,6 +27,13 @@ public class WordnetService {
} }
// Singleton pattern // Singleton pattern
/**
* Get the singleton instance of the wordnet service
*
* @param refresh true for a new initialisation of wordnet
* @return the wordnet service instance
*/
public static WordnetService getInstance(boolean refresh) { public static WordnetService getInstance(boolean refresh) {
if (instance == null) { if (instance == null) {
instance = new WordnetService(); instance = new WordnetService();
...@@ -32,7 +43,11 @@ public class WordnetService { ...@@ -32,7 +43,11 @@ public class WordnetService {
return instance; return instance;
} }
// Singleton pattern /**
* Get the singleton instance of the wordnet service
*
* @return the wordnet service instance
*/
public static WordnetService getInstance() { public static WordnetService getInstance() {
return getInstance(false); return getInstance(false);
} }
......
...@@ -39,6 +39,10 @@ public class RuleIdentifier implements Serializable { ...@@ -39,6 +39,10 @@ public class RuleIdentifier implements Serializable {
this.decisionName = decisionName; this.decisionName = decisionName;
} }
public String getTableName() {
return decisionName != null ? decisionName : decisionKey;
}
@XmlElement @XmlElement
public String getRuleId() { public String getRuleId() {
return ruleId; return ruleId;
......
...@@ -6,6 +6,9 @@ import java.util.ArrayList; ...@@ -6,6 +6,9 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import javax.json.Json;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObjectBuilder;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
...@@ -40,6 +43,25 @@ public class VerificationResult implements Serializable { ...@@ -40,6 +43,25 @@ public class VerificationResult implements Serializable {
return message; return message;
} }
public String getRulesAsJson() {
JsonObjectBuilder result = Json.createObjectBuilder();
JsonArrayBuilder jsonRules = Json.createArrayBuilder();
rules
.stream()
.map(
r ->
Json.createObjectBuilder()
.add("ruleId", r.getRuleId())
.add("decisionKey", r.getDecisionKey())
.add("rowNumber", r.getRowNumber())
.build())
.forEach(jsonRules::add);
result.add("rules", jsonRules);
result.add("ruleCount", getRuleCount());
String s = result.build().toString();
return s;
}
public static VerificationResult.Builder getBuilder() { public static VerificationResult.Builder getBuilder() {
return new VerificationResult().new Builder(); return new VerificationResult().new Builder();
} }
......
...@@ -5,20 +5,17 @@ import de.unikoblenz.fgbks.dmn.core.verifier.helper.RuleMap; ...@@ -5,20 +5,17 @@ import de.unikoblenz.fgbks.dmn.core.verifier.helper.RuleMap;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.camunda.bpm.dmn.engine.DmnDecision; import org.camunda.bpm.dmn.engine.DmnDecision;
import org.slf4j.LoggerFactory;
public enum VerifierType { public enum VerifierType {
Identical("Identical Business Rule", IdenticalRules.class), Identical("Checking for identical rules.", IdenticalRules.class),
Subsumption("Business Rules, that are subsumption", SubsumptionRules.class), Subsumption("Checking for rules, which subsume other rules.", SubsumptionRules.class),
Equivalent("Checking for synonyms in columns.", EquivalentRules.class), Equivalent("Checking for synonyms in columns.", EquivalentRules.class),
Overlap("Checking for overlapping rules.", OverlappingRules.class), Overlap("Checking for overlapping rules.", OverlappingRules.class),
Missing("Checking for missing rules", MissingRules.class); Missing("Checking for missing rules.", MissingRules.class),
/* PartialReduction(
, "Checking for partial reduction of rules (combination).", PartialReductionRules.class);
Overlap("", null),
Contradictions("", null),
SpecificPartialReduction("", null),
Missing("", null),
*/
private final Class<? extends AbstractVerifier> verifierClass; private final Class<? extends AbstractVerifier> verifierClass;
private String description; private String description;
...@@ -39,6 +36,8 @@ public enum VerifierType { ...@@ -39,6 +36,8 @@ public enum VerifierType {
return Optional.of( return Optional.of(
verifierClass.newInstance().findValidationErrors(dmnDecisionList, ruleMap)); verifierClass.newInstance().findValidationErrors(dmnDecisionList, ruleMap));
} catch (Exception ex) { } catch (Exception ex) {
LoggerFactory.getLogger(VerifierType.class).warn(ex.getMessage());
ex.printStackTrace();
} }
return Optional.empty(); return Optional.empty();
} }
......
...@@ -28,7 +28,7 @@ public class EquivalentRules extends AbstractVerifier { ...@@ -28,7 +28,7 @@ public class EquivalentRules extends AbstractVerifier {
protected void verifyDecision(DmnDecision d) { protected void verifyDecision(DmnDecision d) {
if (d.isDecisionTable()) { if (d.isDecisionTable()) {
for (Type t : ruleMap.getAllTypesFromDecisionKey(d.getKey())) { for (Type t : ruleMap.getAllTypesFromDecisionKey(d.getKey())) {
// only check strings // only check strings for equvalent rules (input + output)
if (t.getDataType() == DataType.STRING) { if (t.getDataType() == DataType.STRING) {
// ensure expression is not null and not empty // ensure expression is not null and not empty
List<Value> values = List<Value> values =
...@@ -41,6 +41,7 @@ public class EquivalentRules extends AbstractVerifier { ...@@ -41,6 +41,7 @@ public class EquivalentRules extends AbstractVerifier {
&& !v.getOrgExpression().isEmpty() && !v.getOrgExpression().isEmpty()
&& !v.getOrgExpression().equals("\"\"")) && !v.getOrgExpression().equals("\"\""))
.collect(Collectors.toList()); .collect(Collectors.toList());
// Check all combinations for synonyms, if found -> add both rules to the message
for (int i = 0; i < values.size() - 1; i++) { for (int i = 0; i < values.size() - 1; i++) {
for (int u = i + 1; u < values.size(); u++) { for (int u = i + 1; u < values.size(); u++) {
String val1 = values.get(i).getOrgExpression().replace("\"", ""); String val1 = values.get(i).getOrgExpression().replace("\"", "");
...@@ -50,7 +51,12 @@ public class EquivalentRules extends AbstractVerifier { ...@@ -50,7 +51,12 @@ public class EquivalentRules extends AbstractVerifier {
VerificationResult.getBuilder() VerificationResult.getBuilder()
.addRule(values.get(i).getRuleIdentifier()) .addRule(values.get(i).getRuleIdentifier())
.addRule(values.get(u).getRuleIdentifier()) .addRule(values.get(u).getRuleIdentifier())
.withMessage("%s and %s: equal meaning? Are they synonyms?", val1, val2) .withMessage(
"In rule (%d) string \"%s\" and in rule (%d) string \"%s\": equal meaning? Are they synonyms?",
values.get(i).getRuleIdentifier().getRowNumber(),
val1,
values.get(u).getRuleIdentifier().getRowNumber(),
val2)
.build()); .build());
} }
} }
......
...@@ -89,7 +89,7 @@ public class IdenticalRules extends AbstractVerifier { ...@@ -89,7 +89,7 @@ public class IdenticalRules extends AbstractVerifier {
.map(c -> c.getRowNumber().toString()) .map(c -> c.getRowNumber().toString())
.collect(Collectors.joining(", "))); .collect(Collectors.joining(", ")));
sb.append(" in table "); sb.append(" in table ");
sb.append(currentRuleIdentifiers.get(0).getDecisionName()); sb.append(currentRuleIdentifiers.get(0).getTableName());
sb.append(" are identical."); sb.append(" are identical.");
return sb.toString(); return sb.toString();
} }
......
...@@ -4,11 +4,13 @@ import de.unikoblenz.fgbks.dmn.core.models.RuleIdentifier; ...@@ -4,11 +4,13 @@ import de.unikoblenz.fgbks.dmn.core.models.RuleIdentifier;
import de.unikoblenz.fgbks.dmn.core.models.VerificationResult; import de.unikoblenz.fgbks.dmn.core.models.VerificationResult;
import de.unikoblenz.fgbks.dmn.core.models.VerifierType; import de.unikoblenz.fgbks.dmn.core.models.VerifierType;
import de.unikoblenz.fgbks.dmn.core.verifier.helper.Boundary; import de.unikoblenz.fgbks.dmn.core.verifier.helper.Boundary;
import de.unikoblenz.fgbks.dmn.core.verifier.helper.DataType;
import de.unikoblenz.fgbks.dmn.core.verifier.helper.Type; import de.unikoblenz.fgbks.dmn.core.verifier.helper.Type;
import de.unikoblenz.fgbks.dmn.core.verifier.helper.Value; import de.unikoblenz.fgbks.dmn.core.verifier.helper.Value;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Optional;
import org.camunda.bpm.dmn.engine.DmnDecision; import org.camunda.bpm.dmn.engine.DmnDecision;
public class MissingRules extends AbstractVerifier { public class MissingRules extends AbstractVerifier {
...@@ -34,52 +36,50 @@ public class MissingRules extends AbstractVerifier { ...@@ -34,52 +36,50 @@ public class MissingRules extends AbstractVerifier {
int i, int i,
List<RuleIdentifier> currentRuleIdentifiers, List<RuleIdentifier> currentRuleIdentifiers,
List<Boundary> missingIntervals) { List<Boundary> missingIntervals) {
if (inputs.get(i).getDataType() == DataType.NUMBER) {
List<Value> sortedBounds = List<Value> sortedBounds =
new ArrayList<>(ruleMap.getValuesFromInputType(inputs.get(i), currentRuleIdentifiers)); new ArrayList<>(ruleMap.getValuesFromInputType(inputs.get(i), currentRuleIdentifiers));
sortedBounds.sort(Comparator.comparing(Value::getBoundary)); sortedBounds.sort(Comparator.comparing(Value::getBoundary));
Value lastBound = null; Value lastBound = null;
for (Value currentBound : sortedBounds) { for (Value currentBound : sortedBounds) {
if (lastBound == null) { if (lastBound == null) {
if (currentBound.getBoundary().getLowerBound() != Double.MIN_VALUE) { if (currentBound.getBoundary().getLowerBound() != Double.MIN_VALUE) {
missingIntervals.add(currentBound.getBoundary().getNewBoundaryLower().get()); missingIntervals.add(currentBound.getBoundary().getNewBoundaryLower().get());
}
} else {
Optional<Boundary> newBound =
lastBound.getBoundary().getNewBoundaryBetween(currentBound.getBoundary());
newBound.ifPresent(missingIntervals::add);
} }
} else { if (lastBound == null
boolean contiguous = || !lastBound
lastBound.getBoundary().combineWith(currentBound.getBoundary()).isPresent(); .getBoundary()
if (!contiguous) { .isNumberInRange(
Boundary newBound = currentBound.getBoundary().getUpperBound(),
lastBound.getBoundary().getNewBoundaryBetween(currentBound.getBoundary()).get(); currentBound.getBoundary().getUpperBoundType())) {
missingIntervals.add(newBound); lastBound = currentBound;
} }
} }
if (lastBound == null if (lastBound != null) {
|| !lastBound if (lastBound.getBoundary().getUpperBound() != Double.MAX_VALUE) {
.getBoundary() missingIntervals.add(lastBound.getBoundary().getNewBoundaryUpper().get());
.isNumberInRange( }
currentBound.getBoundary().getUpperBound(),
currentBound.getBoundary().getUpperBoundType())) {
lastBound = currentBound;
} }
} for (Boundary b : missingIntervals) {
if (lastBound != null) { addVerification(
if (lastBound.getBoundary().getUpperBound() != Double.MAX_VALUE) { VerificationResult.getBuilder()
missingIntervals.add(lastBound.getBoundary().getNewBoundaryUpper().get()); .addRule(
RuleIdentifier.getBuilder()
.withRowNumber(999)
.withDecision(d)
.withRuleId("a")
.build())
.withMessage("Missing interval: %s", b.toString())
.build());
} }
} }
for (Boundary b : missingIntervals) {
addVerification(
VerificationResult.getBuilder()
.addRule(
RuleIdentifier.getBuilder()
.withRowNumber(999)
.withDecision(d)
.withRuleId("a")
.build())
.withMessage("Missing interval: %s", b.toString())
.build());
}
} }
@Override @Override
......
...@@ -48,7 +48,7 @@ public class OverlappingRules extends AbstractVerifier { ...@@ -48,7 +48,7 @@ public class OverlappingRules extends AbstractVerifier {
if (lastBound != null) { if (lastBound != null) {
boolean isOverlap = boolean isOverlap =
currentBound.getBoundary().isBoundaryOverlapping(lastBound.getBoundary()); currentBound.getBoundary().isBoundaryOverlapping(lastBound.getBoundary());
if (isOverlap || currentBound.getBoundary().isBoundaryEquals(lastBound.getBoundary())) { if (isOverlap || ! currentBound.getBoundary().isBoundaryNotInContact(lastBound.getBoundary())) {
currentBounds.add(lastBound); currentBounds.add(lastBound);
if (isOverlap) { if (isOverlap) {
foundOverlap = true; foundOverlap = true;
......
package de.unikoblenz.fgbks.dmn.core.verifier;
import de.unikoblenz.fgbks.dmn.core.models.VerifierType;
import org.camunda.bpm.dmn.engine.DmnDecision;
public class PartialReductionRules extends AbstractVerifier {
public PartialReductionRules() {
super(VerifierType.PartialReduction);
}
@Override
protected void beforeVerifyDecision() {}
@Override
protected void verifyDecision(DmnDecision d) {}
@Override
protected void afterVerifyDecision() {}
}
...@@ -20,8 +20,7 @@ public class SubsumptionRules extends AbstractVerifier { ...@@ -20,8 +20,7 @@ public class SubsumptionRules extends AbstractVerifier {
} }
@Override @Override
protected void beforeVerifyDecision() { protected void beforeVerifyDecision() {}
}
@Override @Override
protected void verifyDecision(DmnDecision d) { protected void verifyDecision(DmnDecision d) {
...@@ -35,23 +34,38 @@ public class SubsumptionRules extends AbstractVerifier { ...@@ -35,23 +34,38 @@ public class SubsumptionRules extends AbstractVerifier {
List<Type> inputs, List<Type> inputs,
int i, int i,
List<RuleIdentifier> currentRuleIdentifiers, List<RuleIdentifier> currentRuleIdentifiers,
boolean hasSubsumption, Value currentRootSubsumptionElement) { boolean hasSubsumption,
Value currentRootSubsumptionElement) {
if (i == inputs.size()) { if (i == inputs.size()) {
// finish, if subsumption was found previously, than add the rules
if (hasSubsumption) { if (hasSubsumption) {
VerificationResult.Builder vBuilder = VerificationResult.Builder vBuilder =
VerificationResult.getBuilder().withMessage(getMessageText(currentRuleIdentifiers)); VerificationResult.getBuilder()
.withMessage(getMessageText(currentRuleIdentifiers, currentRootSubsumptionElement));
vBuilder.addRules(currentRuleIdentifiers); vBuilder.addRules(currentRuleIdentifiers);
addVerification(vBuilder.build()); addVerification(vBuilder.build());
} }
} else { } else {
// get all input values from the current column, and filter with the prev. iteration
List<Value> selectedBounds = List<Value> selectedBounds =
new ArrayList<>(ruleMap.getValuesFromInputType(inputs.get(i), currentRuleIdentifiers)); new ArrayList<>(ruleMap.getValuesFromInputType(inputs.get(i), currentRuleIdentifiers));
List<Set<Value>> clusters = new ArrayList<>(); List<Set<Value>> clusters = new ArrayList<>(); // clusters of subsumptions
List<Boolean> subsumptions = new ArrayList<>(); List<Boolean> subsumptions =
List<Value> subsumptionValue = new ArrayList<>(); new ArrayList<>(); // is the value in selectedBounds a subsubmption?
List<Value> subsumptionValue =
new ArrayList<>(); // save the subsumption value of the current cluster
// if previously a rule was found, which has a subsumption, than it must be also the element,
// which subsume the other elements.
// First, build clusters, which contain a subsumption set
if (currentRootSubsumptionElement != null) { if (currentRootSubsumptionElement != null) {
Value nValue = ruleMap.getValuesFromInputType(inputs.get(i), Collections.singletonList(currentRootSubsumptionElement.getRuleIdentifier())).get(0); // get the value from the subsumption rule
Value nValue =
ruleMap
.getValuesFromInputType(
inputs.get(i),
Collections.singletonList(currentRootSubsumptionElement.getRuleIdentifier()))
.get(0);
Set<Value> c1 = new HashSet<>(); Set<Value> c1 = new HashSet<>();
c1.add(nValue); c1.add(nValue);
boolean foundSubsumption = false; boolean foundSubsumption = false;
...@@ -68,6 +82,8 @@ public class SubsumptionRules extends AbstractVerifier { ...@@ -68,6 +82,8 @@ public class SubsumptionRules extends AbstractVerifier {
subsumptionValue.add(nValue); subsumptionValue.add(nValue);
} }
} else { } else {
// no subsumption was found yet
// --> build all clusters, where one rule subsume other rules
for (Value cb1 : selectedBounds) { for (Value cb1 : selectedBounds) {
Set<Value> c1 = new HashSet<>(); Set<Value> c1 = new HashSet<>();
c1.add(cb1); c1.add(cb1);
...@@ -86,7 +102,7 @@ public class SubsumptionRules extends AbstractVerifier { ...@@ -86,7 +102,7 @@ public class SubsumptionRules extends AbstractVerifier {
} }
} }
} }
// check for subsets, that includes other subsets // check for subsets, that includes other subsets and remove them
for (int x = 0; x < clusters.size(); x++) { for (int x = 0; x < clusters.size(); x++) {
if (clusters.get(x) != null) { if (clusters.get(x) != null) {
Set<Value> c1 = clusters.get(x); Set<Value> c1 = clusters.get(x);
...@@ -100,7 +116,7 @@ public class SubsumptionRules extends AbstractVerifier { ...@@ -100,7 +116,7 @@ public class SubsumptionRules extends AbstractVerifier {
} }
} }
} }
// recursively search next row for subsumption with all clusters
for (int x = 0; x < clusters.size(); x++) { for (int x = 0; x < clusters.size(); x++) {
if (clusters.get(x) != null) { if (clusters.get(x) != null) {
Set<Value> vals = clusters.get(x); Set<Value> vals = clusters.get(x);
...@@ -108,24 +124,35 @@ public class SubsumptionRules extends AbstractVerifier { ...@@ -108,24 +124,35 @@ public class SubsumptionRules extends AbstractVerifier {
inputs, inputs,
i + 1, i + 1,
vals.stream().map(Value::getRuleIdentifier).collect(Collectors.toList()), vals.stream().map(Value::getRuleIdentifier).collect(Collectors.toList()),
subsumptions.get(x) || hasSubsumption, subsumptionValue.get(x)); subsumptions.get(x) || hasSubsumption,
subsumptionValue.get(x));
} }
} }
} }
} }
@Override @Override
protected void afterVerifyDecision() { protected void afterVerifyDecision() {}
}
private String getMessageText(List<RuleIdentifier> currentRuleIdentifiers) { private String getMessageText(
StringBuilder sb = new StringBuilder("Rules "); List<RuleIdentifier> currentRuleIdentifiers, Value subsumptionRule) {
StringBuilder sb = new StringBuilder();
sb.append("In table ");
sb.append(subsumptionRule.getRuleIdentifier().getTableName());
sb.append(" rule ");
sb.append(subsumptionRule.getRuleIdentifier().getRowNumber());
sb.append(" subsumes the rule");
if (currentRuleIdentifiers.size() > 2) {
sb.append("s");
}
sb.append(" ");
sb.append( sb.append(
currentRuleIdentifiers currentRuleIdentifiers
.stream() .stream()
.filter(r -> !r.equals(subsumptionRule.getRuleIdentifier()))
.map(c -> c.getRowNumber().toString()) .map(c -> c.getRowNumber().toString())
.collect(Collectors.joining(", "))); .collect(Collectors.joining(", ")));
sb.append(" are subsumption."); sb.append(".");
return sb.toString(); return sb.toString();
} }
} }
...@@ -260,14 +260,48 @@ public class RuleMap { ...@@ -260,14 +260,48 @@ public class RuleMap {
} }
// check for subsets, that includes other subsets // check for subsets, that includes other subsets
Iterator<Set<String>> it = returnSet.iterator(); Iterator<Set<String>> it = returnSet.iterator();
Set<Set<String>> removeSets = new HashSet<>();
while (it.hasNext()) { while (it.hasNext()) {
Set<String> s = it.next(); Set<String> s = it.next();
for (Set<String> subset : returnSet) { for (Set<String> subset : returnSet) {
if (subset.size() > s.size() && subset.containsAll(s)) { if (subset.size() > s.size() && subset.containsAll(s)) {
it.remove(); removeSets.add(s);
} }
} }
} }
returnSet.removeAll(removeSets);
return returnSet; return returnSet;
} }
public List<Value> getValuesFromInputExpression(Set<String> dmnDecisionsKeys, String expression) {
Set<Type> types = new HashSet<>();
for (Type type : inputs.keySet()) {
if (type.getExpression().equals(expression)
&& dmnDecisionsKeys.contains(type.getDecisionKey())) {
types.add(type);
}
}
List<Value> valueList = new ArrayList<>();
for (Type type : types) {
valueList.addAll(getValuesFromInputType(type));
}
return valueList;
}
public List<Value> getValuesFromInputExpression(
Set<String> dmnDecisionsKeys, String expression, List<RuleIdentifier> ruleIdentifiersFilter) {
Set<Type> types = new HashSet<>();
for (Type type : inputs.keySet()) {
if (type.getExpression() != null
&& type.getExpression().equals(expression)
&& dmnDecisionsKeys.contains(type.getDecisionKey())) {
types.add(type);
}
}
List<Value> valueList = new ArrayList<>();
for (Type type : types) {
valueList.addAll(getValuesFromInputType(type, ruleIdentifiersFilter));
}
return valueList;
}
} }
...@@ -103,14 +103,10 @@ ...@@ -103,14 +103,10 @@
<h:outputText value="#{results.message}"/> <h:outputText value="#{results.message}"/>
</p:column> </p:column>
<p:column styleClass="subcol-rules" headerText="Rules"> <p:column styleClass="subcol-rules" headerText="Rules">
<p:dataTable var="rule" value="#{results.rules}"> <p:commandButton styleClass="ruleselect-button"
<p:column style="padding: 0px"> style="width: 95%;"
<p:commandButton styleClass="ruleselect-button" onclick="addHighlightCss(#{results.rulesAsJson});"
style="width: 95%;" value="Highlight rules"/>
onclick="addHighlightCss('#{rule.ruleId}', '#{rule.decisionKey}');"
value="#{rule.rowNumber}"/>
</p:column>
</p:dataTable>
</p:column> </p:column>
</p:dataTable> </p:dataTable>
</p:rowExpansion> </p:rowExpansion>
...@@ -119,4 +115,4 @@ ...@@ -119,4 +115,4 @@
</p:ajaxStatus> </p:ajaxStatus>
</h:panelGroup> </h:panelGroup>
</ui:define> </ui:define>
</ui:composition> </ui:composition>
\ No newline at end of file
...@@ -95,7 +95,9 @@ function refreshDmn() { ...@@ -95,7 +95,9 @@ function refreshDmn() {
refreshDmn(); refreshDmn();
function addHighlightCss(id, decisionKey) { function addHighlightCss(ruleC) {
$('#tab-dec-' + decisionKey).click(); $('#tab-dec-' + ruleC.rules[0].decisionKey).click();
$('[data-row-id=' + id + ']').toggleClass('highlight'); ruleC.rules.forEach(function (rule) {
} $('[data-row-id=' + rule.ruleId + ']').toggleClass('highlight');
\ No newline at end of file });
}
...@@ -28,7 +28,8 @@ html, body { ...@@ -28,7 +28,8 @@ html, body {
} }
.highlight { .highlight {
background-color: red; background-color: darkred;
color:white;
} }
.dmn-button { .dmn-button {
...@@ -83,4 +84,4 @@ html, body { ...@@ -83,4 +84,4 @@ html, body {
.editor-tabs .tab:hover { .editor-tabs .tab:hover {
border-bottom: solid 3px #79818d; border-bottom: solid 3px #79818d;
margin-bottom: 0; margin-bottom: 0;
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment