Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
nitram509 committed Feb 13, 2025
2 parents dcc0dab + b7fc11e commit aedea2d
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package io.zeebe.monitor.querydsl;

import static org.apache.commons.lang3.StringUtils.isEmpty;

import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.PathBuilder;
import io.zeebe.monitor.entity.QProcessEntity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.util.CollectionUtils;

public class ProcessEntityPredicatesBuilder {

final PathBuilder<QProcessEntity> pathBuilder =
new PathBuilder<>(QProcessEntity.class, QProcessEntity.processEntity.getMetadata());

private final List<Predicate> predicates = new ArrayList<>();

public ProcessEntityPredicatesBuilder withBpmnProcessId(String processId) {
if (!isEmpty(processId)) {
predicates.add(pathBuilder.getString("bpmnProcessId").containsIgnoreCase(processId));
}
return this;
}

public ProcessEntityPredicatesBuilder withKeys(Collection<Long> keys) {
if (!CollectionUtils.isEmpty(keys)) {
predicates.add(pathBuilder.getNumber("key", Long.class).in(keys));
}
return this;
}

public Predicate build() {
BooleanExpression result = Expressions.asBoolean(true).isTrue();
for (Predicate predicate : predicates) {
result = result.and(predicate);
}
return result;
}
}
20 changes: 16 additions & 4 deletions src/main/java/io/zeebe/monitor/repository/ProcessRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,17 @@
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;

public interface ProcessRepository
extends PagingAndSortingRepository<ProcessEntity, Long>, CrudRepository<ProcessEntity, Long> {
extends PagingAndSortingRepository<ProcessEntity, Long>,
QuerydslPredicateExecutor<ProcessEntity>,
CrudRepository<ProcessEntity, Long> {

Optional<ProcessEntity> findByKey(long key);

Expand All @@ -43,6 +46,15 @@ List<ElementInstanceStatistics> getElementInstanceStatisticsByKeyAndIntentIn(
@Param("intents") Collection<String> intents,
@Param("excludeElementTypes") Collection<String> excludeElementTypes);

@Transactional(readOnly = true)
List<ProcessEntity> findByBpmnProcessIdStartsWith(String bpmnProcessId);
@Query(
nativeQuery = true,
value =
"""
SELECT p.key_
FROM process p WHERE (bpmn_process_id_,version_) IN
(SELECT bpmn_process_id_, MAX(version_) FROM process p GROUP BY p.bpmn_process_id_)
""")
List<Long> findLatestVersions();

List<ProcessEntity> findByBpmnProcessIdContaining(String bpmnProcessId, Pageable pageable);
}
79 changes: 45 additions & 34 deletions src/main/java/io/zeebe/monitor/rest/ProcessesViewController.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import io.zeebe.monitor.entity.ProcessEntity;
import io.zeebe.monitor.entity.ProcessInstanceEntity;
import io.zeebe.monitor.entity.TimerEntity;
import io.zeebe.monitor.querydsl.ProcessEntityPredicatesBuilder;
import io.zeebe.monitor.repository.MessageSubscriptionRepository;
import io.zeebe.monitor.repository.ProcessInstanceRepository;
import io.zeebe.monitor.repository.ProcessRepository;
Expand All @@ -34,7 +35,9 @@
import java.util.stream.Collectors;
import org.camunda.bpm.model.xml.instance.ModelElementInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
Expand All @@ -48,53 +51,59 @@ public class ProcessesViewController extends AbstractViewController {
static final List<String> EXCLUDE_ELEMENT_TYPES =
List.of(BpmnElementType.MULTI_INSTANCE_BODY.name());

static final Sort DEFAULT_SORT =
Sort.by(Sort.Order.desc("bpmnProcessId"), Sort.Order.desc("timestamp"));

@Autowired private ProcessRepository processRepository;
@Autowired private ProcessInstanceRepository processInstanceRepository;
@Autowired private MessageSubscriptionRepository messageSubscriptionRepository;
@Autowired private TimerRepository timerRepository;

@GetMapping("/")
@Transactional
public String index(final Map<String, Object> model, final Pageable pageable) {
return processList(model, pageable, Optional.empty());
return processList(model, pageable, Optional.empty(), true);
}

@GetMapping("/views/processes")
@Transactional
public String processList(
final Map<String, Object> model,
final Pageable pageable,
@RequestParam(value = "bpmnProcessId", required = false) Optional<String> bpmnProcessId) {

if (bpmnProcessId.isPresent() && bpmnProcessId.get().length() >= 3) {
final List<ProcessDto> processes = new ArrayList<>();
for (final ProcessEntity processEntity :
processRepository.findByBpmnProcessIdStartsWith(bpmnProcessId.get())) {
final ProcessDto dto = toDto(processEntity);
processes.add(dto);
}

model.put("processes", processes);
model.put("bpmnProcessId", bpmnProcessId.get());
model.put("count", processes.size());

addPaginationToModel(model, Pageable.ofSize(Integer.MAX_VALUE), processes.size());
addDefaultAttributesToModel(model);
} else {
final long count = processRepository.count();

final List<ProcessDto> processes = new ArrayList<>();
for (final ProcessEntity processEntity : processRepository.findAll(pageable)) {
final ProcessDto dto = toDto(processEntity);
processes.add(dto);
}

model.put("processes", processes);
model.put("bpmnProcessId", "");
model.put("count", count);

addPaginationToModel(model, pageable, count);
addDefaultAttributesToModel(model);
Pageable pageable,
@RequestParam(value = "bpmnProcessId", required = false) Optional<String> bpmnProcessId,
@RequestParam(value = "showOldProcessVersions", defaultValue = "false")
boolean showOldProcessVersions) {
if (!pageable.getSort().isSorted()) {
pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), DEFAULT_SORT);
}

var predicatesBuilder = new ProcessEntityPredicatesBuilder();
bpmnProcessId.filter(it -> it.length() >= 3).ifPresent(predicatesBuilder::withBpmnProcessId);

if (!showOldProcessVersions) {
var latestProcessKeys = processRepository.findLatestVersions();
predicatesBuilder.withKeys(latestProcessKeys);
}
var processesEntities = processRepository.findAll(predicatesBuilder.build(), pageable);

final List<ProcessDto> processes = new ArrayList<>();

processesEntities.forEach(
process -> {
final ProcessDto dto = toDto(process);
processes.add(dto);
});

var totalProcesses = processesEntities.getTotalElements();

model.put("processes", processes);
model.put("bpmnProcessId", bpmnProcessId.orElse(""));
model.put("showOldProcessVersions", showOldProcessVersions);
model.put("count", totalProcesses);

addPaginationToModel(model, pageable, totalProcesses);
addDefaultAttributesToModel(model);

return "process-list-view";
}

Expand All @@ -113,7 +122,9 @@ public String processDetail(
model.put("process", toDto(process));

final Optional<ProcessEntity> latest =
processRepository.findByBpmnProcessIdStartsWith(process.getBpmnProcessId()).stream()
processRepository
.findByBpmnProcessIdContaining(process.getBpmnProcessId(), pageable)
.stream()
.max(Comparator.comparingInt(ProcessEntity::getVersion));
model.put("latestProcessDefinition", toDto(latest.orElse(process)));
model.put("resource", getProcessResource(process));
Expand Down
16 changes: 12 additions & 4 deletions src/main/resources/templates/process-list-view.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,20 @@
New Deployment
</button>

<form class="form-inline" method="get" action="{{context-path}}views/processes">
<form method="get" action="{{context-path}}views/processes">
<div class="form-inline">
<div class="form-group mb-2 col-sm-3">
<label class="mx-sm-2" for="bpmn-search-input" >Search by</label>
<input class="col-sm-9 form-control" id="bpmn-search-input" placeholder="BPMN process id (min 3 characters)" name="bpmnProcessId" type="text" title="BPMN process id (min 3 characters)" value="{{bpmnProcessId}}" />
</div>

<button class="btn btn-secondary mb-2" type="submit">Search</button>
</div>

<div class="form-group mb-2 col-sm-3">
<label class="mx-sm-2" for="bpmn-search-input" >Search by</label>
<input class="col-sm-9 form-control" id="bpmn-search-input" placeholder="BPMN process id (min 3 characters)" name="bpmnProcessId" type="text" title="BPMN process id (min 3 characters)" value="{{bpmnProcessId}}" />
<label class="form-check-label mx-sm-2" for="showOldProcessVersions" >Show old process versions</label>
<input class="mx-sm-2 btn-secondary" id="showOldProcessVersions" name="showOldProcessVersions" type="checkbox" {{#showOldProcessVersions}}checked{{/showOldProcessVersions}}/>
</div>
<button class="btn btn-secondary mb-2" type="submit">Search</button>
</form>
</div>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package io.zeebe.monitor.repository;

import static org.assertj.core.api.Assertions.assertThat;

import io.zeebe.monitor.entity.ProcessEntity;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

public class ProcessRepositoryTest extends ZeebeRepositoryTest {

@Autowired private ProcessRepository processRepository;

@AfterEach
public void tearDown() {
processRepository.deleteAll();
}

@Test
public void when_process_exists_with_several_versions__then_loaded_only_latest() {
// given
ProcessEntity process1 = createProcess(101L, "A", 1);
ProcessEntity process2 = createProcess(102L, "A", 2);

// when
processRepository.save(process1);
processRepository.save(process2);

// then
List<Long> latestVersions = processRepository.findLatestVersions();
assertThat(latestVersions).containsExactlyInAnyOrder(102L);
}

private ProcessEntity createProcess(long key, String bpmnProcessId, int version) {
ProcessEntity entity = new ProcessEntity();
entity.setKey(key);
entity.setBpmnProcessId(bpmnProcessId);
entity.setVersion(version);
entity.setResource("123");
entity.setTimestamp(456L);
return entity;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.querydsl.core.types.Predicate;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.data.domain.Page;
Expand All @@ -19,6 +20,8 @@ public class ProcessesViewControllerTest extends AbstractViewOrResourceTest {
@BeforeEach
public void setUp() {
when(processRepository.findAll(any(Pageable.class))).thenReturn(Page.empty());
when(processRepository.findAll(any(Predicate.class), any(Pageable.class)))
.thenReturn(Page.empty());
mockCLusterStatusForViews();
}

Expand Down

0 comments on commit aedea2d

Please sign in to comment.