diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/model/ScenarioAction.java b/simulator-starter/src/main/java/org/citrusframework/simulator/model/ScenarioAction.java index 9a1b783fc..69214c43e 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/model/ScenarioAction.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/model/ScenarioAction.java @@ -24,6 +24,8 @@ import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; import jakarta.validation.constraints.NotEmpty; +import org.citrusframework.simulator.service.ScenarioActionQueryService; + import java.io.Serial; import java.io.Serializable; import java.time.Instant; @@ -55,6 +57,10 @@ public class ScenarioAction implements Serializable { @JsonIgnoreProperties(value = { "scenarioParameters", "scenarioActions", "scenarioMessages" }, allowSetters = true) private ScenarioExecution scenarioExecution; + public static ScenarioActionBuilder builder(){ + return new ScenarioActionBuilder(); + } + public Long getActionId() { return actionId; } @@ -100,4 +106,28 @@ public String toString() { ", endDate='" + getEndDate() + "'" + "}"; } + + public static class ScenarioActionBuilder { + + private final ScenarioAction scenarioAction = new ScenarioAction(); + + public ScenarioActionBuilder name(String name) { + scenarioAction.name = name; + return this; + } + + public ScenarioActionBuilder startDate(Instant startDate) { + scenarioAction.startDate = startDate; + return this; + } + + public ScenarioActionBuilder endDate(Instant endDate) { + scenarioAction.endDate = endDate; + return this; + } + + public ScenarioAction build(){ + return scenarioAction; + } + } } diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/model/ScenarioExecution.java b/simulator-starter/src/main/java/org/citrusframework/simulator/model/ScenarioExecution.java index 10d923e8b..51797289a 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/model/ScenarioExecution.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/model/ScenarioExecution.java @@ -67,7 +67,7 @@ public class ScenarioExecution implements Serializable { * Actual status as a numerical representation of {@link Status} */ @Column(nullable = false) - private Integer status; + private Integer status = Status.UNKNOWN.getId(); @Size(max = 1000) @Column(length = 1000) diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/repository/ScenarioActionRepository.java b/simulator-starter/src/main/java/org/citrusframework/simulator/repository/ScenarioActionRepository.java new file mode 100644 index 000000000..990374b18 --- /dev/null +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/repository/ScenarioActionRepository.java @@ -0,0 +1,45 @@ +package org.citrusframework.simulator.repository; + +import org.citrusframework.simulator.model.ScenarioAction; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +/** + * Spring Data JPA repository for the ScenarioAction entity. + */ +@Repository +public interface ScenarioActionRepository extends JpaRepository, JpaSpecificationExecutor { + default Optional findOneWithEagerRelationships(Long id) { + return this.findOneWithToOneRelationships(id); + } + + default List findAllWithEagerRelationships() { + return this.findAllWithToOneRelationships(); + } + + default Page findAllWithEagerRelationships(Pageable pageable) { + return this.findAllWithToOneRelationships(pageable); + } + + @Query( + value = "select scenarioAction from ScenarioAction scenarioAction left join fetch scenarioAction.scenarioExecution", + countQuery = "select count(scenarioAction) from ScenarioAction scenarioAction" + ) + Page findAllWithToOneRelationships(Pageable pageable); + + @Query("select scenarioAction from ScenarioAction scenarioAction left join fetch scenarioAction.scenarioExecution") + List findAllWithToOneRelationships(); + + @Query( + "select scenarioAction from ScenarioAction scenarioAction left join fetch scenarioAction.scenarioExecution where scenarioAction.actionId =:actionId" + ) + Optional findOneWithToOneRelationships(@Param("actionId") Long actionId); +} diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioActionQueryService.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioActionQueryService.java new file mode 100644 index 000000000..85f9ac6ec --- /dev/null +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioActionQueryService.java @@ -0,0 +1,110 @@ +package org.citrusframework.simulator.service; + +import jakarta.persistence.criteria.JoinType; +import org.citrusframework.simulator.model.ScenarioAction; +import org.citrusframework.simulator.model.ScenarioAction_; +import org.citrusframework.simulator.model.ScenarioExecution_; +import org.citrusframework.simulator.repository.ScenarioActionRepository; +import org.citrusframework.simulator.service.criteria.ScenarioActionCriteria; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * Service for executing complex queries for {@link ScenarioAction} entities in the database. + * The main input is a {@link ScenarioActionCriteria} which gets converted to {@link Specification}, + * in a way that all the filters must apply. + * It returns a {@link List} of {@link ScenarioAction} or a {@link Page} of {@link ScenarioAction} which fulfills the criteria. + */ +@Service +@Transactional(readOnly = true) +public class ScenarioActionQueryService extends QueryService { + + private final Logger log = LoggerFactory.getLogger(ScenarioActionQueryService.class); + + private final ScenarioActionRepository scenarioActionRepository; + + public ScenarioActionQueryService(ScenarioActionRepository scenarioActionRepository) { + this.scenarioActionRepository = scenarioActionRepository; + } + + /** + * Return a {@link List} of {@link ScenarioAction} which matches the criteria from the database. + * @param criteria The object which holds all the filters, which the entities should match. + * @return the matching entities. + */ + @Transactional(readOnly = true) + public List findByCriteria(ScenarioActionCriteria criteria) { + log.debug("find by criteria : {}", criteria); + final Specification specification = createSpecification(criteria); + return scenarioActionRepository.findAll(specification); + } + + /** + * Return a {@link Page} of {@link ScenarioAction} which matches the criteria from the database. + * @param criteria The object which holds all the filters, which the entities should match. + * @param page The page, which should be returned. + * @return the matching entities. + */ + @Transactional(readOnly = true) + public Page findByCriteria(ScenarioActionCriteria criteria, Pageable page) { + log.debug("find by criteria : {}, page: {}", criteria, page); + final Specification specification = createSpecification(criteria); + return scenarioActionRepository.findAll(specification, page); + } + + /** + * Return the number of matching entities in the database. + * @param criteria The object which holds all the filters, which the entities should match. + * @return the number of matching entities. + */ + @Transactional(readOnly = true) + public long countByCriteria(ScenarioActionCriteria criteria) { + log.debug("count by criteria : {}", criteria); + final Specification specification = createSpecification(criteria); + return scenarioActionRepository.count(specification); + } + + /** + * Function to convert {@link ScenarioActionCriteria} to a {@link Specification} + * @param criteria The object which holds all the filters, which the entities should match. + * @return the matching {@link Specification} of the entity. + */ + protected Specification createSpecification(ScenarioActionCriteria criteria) { + Specification specification = Specification.where(null); + if (criteria != null) { + // This has to be called first, because the distinct method returns null + if (criteria.getDistinct() != null) { + specification = specification.and(distinct(criteria.getDistinct())); + } + if (criteria.getActionId() != null) { + specification = specification.and(buildRangeSpecification(criteria.getActionId(), ScenarioAction_.actionId)); + } + if (criteria.getName() != null) { + specification = specification.and(buildStringSpecification(criteria.getName(), ScenarioAction_.name)); + } + if (criteria.getStartDate() != null) { + specification = specification.and(buildRangeSpecification(criteria.getStartDate(), ScenarioAction_.startDate)); + } + if (criteria.getEndDate() != null) { + specification = specification.and(buildRangeSpecification(criteria.getEndDate(), ScenarioAction_.endDate)); + } + if (criteria.getScenarioExecutionId() != null) { + specification = + specification.and( + buildSpecification( + criteria.getScenarioExecutionId(), + root -> root.join(ScenarioAction_.scenarioExecution, JoinType.LEFT).get(ScenarioExecution_.executionId) + ) + ); + } + } + return specification; + } +} diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioActionService.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioActionService.java new file mode 100644 index 000000000..31bc7d2e7 --- /dev/null +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/ScenarioActionService.java @@ -0,0 +1,62 @@ +package org.citrusframework.simulator.service; + +import org.citrusframework.simulator.model.ScenarioAction; +import org.citrusframework.simulator.model.ScenarioExecution; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +import java.util.Objects; +import java.util.Optional; + +/** + * Service Interface for managing {@link ScenarioAction}. + */ +public interface ScenarioActionService { + /** + * Save a scenarioAction. + * + * @param scenarioAction the entity to save. + * @return the persisted entity. + */ + ScenarioAction save(ScenarioAction scenarioAction); + + /** + * Updates a scenarioAction. + * + * @param scenarioAction the entity to update. + * @return the persisted entity. + */ + ScenarioAction update(ScenarioAction scenarioAction); + + /** + * Get all the scenarioActions. + * + * @param pageable the pagination information. + * @return the list of entities. + */ + Page findAll(Pageable pageable); + + /** + * Get the "id" scenarioAction. + * + * @param id the id of the entity. + * @return the entity. + */ + Optional findOne(Long id); + + /** + * Function that converts the {@link ScenarioAction} to its "DTO-form": It may only contain the {@code scenarioName} + * of the related {@link ScenarioExecution}, no further attributes. That is especially true for relationships, + * because of a possible {@link org.hibernate.LazyInitializationException}). + * + * @param scenarioAction The entity, which should be returned + * @return the entity with prepared {@link ScenarioExecution} + */ + static ScenarioAction restrictToDtoProperties(ScenarioAction scenarioAction) { + ScenarioExecution scenarioExecution = scenarioAction.getScenarioExecution(); + if (!Objects.isNull(scenarioExecution)) { + scenarioAction.setScenarioExecution(ScenarioExecution.builder().scenarioName(scenarioExecution.getScenarioName()).build()); + } + return scenarioAction; + } +} diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/ScenarioActionCriteria.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/ScenarioActionCriteria.java new file mode 100644 index 000000000..92f58d19d --- /dev/null +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/criteria/ScenarioActionCriteria.java @@ -0,0 +1,176 @@ +package org.citrusframework.simulator.service.criteria; + +import org.citrusframework.simulator.service.filter.InstantFilter; +import org.citrusframework.simulator.service.filter.LongFilter; +import org.citrusframework.simulator.service.filter.StringFilter; +import org.springdoc.core.annotations.ParameterObject; + +import java.io.Serializable; +import java.util.Objects; + +/** + * Criteria class for the {@link org.citrusframework.simulator.model.ScenarioAction} entity. This class is used + * in {@link org.citrusframework.simulator.web.rest.ScenarioActionResource} to receive all the possible filtering + * options from the Http GET request parameters. + *

+ * For example the following could be a valid request: + * {@code /scenario-actions?id.greaterThan=5&attr1.contains=something&attr2.specified=false} + *

+ * As Spring is unable to properly convert the types, unless + * specific {@link org.citrusframework.simulator.service.filter.Filter} class are used, we need to use fix type specific + * filters. + */ +@ParameterObject +@SuppressWarnings("common-java:DuplicatedBlocks") +public class ScenarioActionCriteria implements Serializable, Criteria { + + private static final long serialVersionUID = 1L; + + private LongFilter actionId; + + private StringFilter name; + + private InstantFilter startDate; + + private InstantFilter endDate; + + private LongFilter scenarioExecutionId; + + private Boolean distinct; + + public ScenarioActionCriteria() {} + + public ScenarioActionCriteria(ScenarioActionCriteria other) { + this.actionId = other.actionId == null ? null : other.actionId.copy(); + this.name = other.name == null ? null : other.name.copy(); + this.startDate = other.startDate == null ? null : other.startDate.copy(); + this.endDate = other.endDate == null ? null : other.endDate.copy(); + this.scenarioExecutionId = other.scenarioExecutionId == null ? null : other.scenarioExecutionId.copy(); + this.distinct = other.distinct; + } + + @Override + public ScenarioActionCriteria copy() { + return new ScenarioActionCriteria(this); + } + + public LongFilter getActionId() { + return actionId; + } + + public LongFilter id() { + if (actionId == null) { + actionId = new LongFilter(); + } + return actionId; + } + + public void setActionId(LongFilter actionId) { + this.actionId = actionId; + } + + public StringFilter getName() { + return name; + } + + public StringFilter name() { + if (name == null) { + name = new StringFilter(); + } + return name; + } + + public void setName(StringFilter name) { + this.name = name; + } + + public InstantFilter getStartDate() { + return startDate; + } + + public InstantFilter startDate() { + if (startDate == null) { + startDate = new InstantFilter(); + } + return startDate; + } + + public void setStartDate(InstantFilter startDate) { + this.startDate = startDate; + } + + public InstantFilter getEndDate() { + return endDate; + } + + public InstantFilter endDate() { + if (endDate == null) { + endDate = new InstantFilter(); + } + return endDate; + } + + public void setEndDate(InstantFilter endDate) { + this.endDate = endDate; + } + + public LongFilter getScenarioExecutionId() { + return scenarioExecutionId; + } + + public LongFilter scenarioExecutionId() { + if (scenarioExecutionId == null) { + scenarioExecutionId = new LongFilter(); + } + return scenarioExecutionId; + } + + public void setScenarioExecutionId(LongFilter scenarioExecutionId) { + this.scenarioExecutionId = scenarioExecutionId; + } + + public Boolean getDistinct() { + return distinct; + } + + public void setDistinct(Boolean distinct) { + this.distinct = distinct; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final ScenarioActionCriteria that = (ScenarioActionCriteria) o; + return ( + Objects.equals(actionId, that.actionId) && + Objects.equals(name, that.name) && + Objects.equals(startDate, that.startDate) && + Objects.equals(endDate, that.endDate) && + Objects.equals(scenarioExecutionId, that.scenarioExecutionId) && + Objects.equals(distinct, that.distinct) + ); + } + + @Override + public int hashCode() { + return Objects.hash(actionId, name, startDate, endDate, scenarioExecutionId, distinct); + } + + // prettier-ignore + @Override + public String toString() { + return "ScenarioActionCriteria{" + + (actionId != null ? "id=" + actionId + ", " : "") + + (name != null ? "name=" + name + ", " : "") + + (startDate != null ? "startDate=" + startDate + ", " : "") + + (endDate != null ? "endDate=" + endDate + ", " : "") + + (scenarioExecutionId != null ? "scenarioExecutionId=" + scenarioExecutionId + ", " : "") + + (distinct != null ? "distinct=" + distinct + ", " : "") + + "}"; + } +} diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImpl.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImpl.java index 87d980f48..6b21da452 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImpl.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/MessageHeaderServiceImpl.java @@ -36,7 +36,7 @@ public MessageHeader save(MessageHeader messageHeader) { @Override @Transactional(readOnly = true) public Page findAll(Pageable pageable) { - log.debug("Request to get all MessageHeaders"); + log.debug("Request to get all MessageHeaders with eager relationships"); return messageHeaderRepository.findAllWithEagerRelationships(pageable) .map(MessageHeaderService::restrictToDtoProperties); } diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/MessageServiceImpl.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/MessageServiceImpl.java index 5d8381f37..d701bcf5e 100644 --- a/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/MessageServiceImpl.java +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/MessageServiceImpl.java @@ -36,7 +36,7 @@ public Message save(Message message) { @Override @Transactional(readOnly = true) public Page findAll(Pageable pageable) { - log.debug("Request to get all Messages"); + log.debug("Request to get all Messages with eager relationships"); return messageRepository.findAllWithEagerRelationships(pageable); } diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImpl.java b/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImpl.java new file mode 100644 index 000000000..7a2924869 --- /dev/null +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/service/impl/ScenarioActionServiceImpl.java @@ -0,0 +1,57 @@ +package org.citrusframework.simulator.service.impl; + +import org.citrusframework.simulator.model.ScenarioAction; +import org.citrusframework.simulator.repository.ScenarioActionRepository; +import org.citrusframework.simulator.service.ScenarioActionService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +/** + * Service Implementation for managing {@link ScenarioAction}. + */ +@Service +@Transactional +public class ScenarioActionServiceImpl implements ScenarioActionService { + + private final Logger log = LoggerFactory.getLogger(ScenarioActionServiceImpl.class); + + private final ScenarioActionRepository scenarioActionRepository; + + public ScenarioActionServiceImpl(ScenarioActionRepository scenarioActionRepository) { + this.scenarioActionRepository = scenarioActionRepository; + } + + @Override + public ScenarioAction save(ScenarioAction scenarioAction) { + log.debug("Request to save ScenarioAction : {}", scenarioAction); + return scenarioActionRepository.save(scenarioAction); + } + + @Override + public ScenarioAction update(ScenarioAction scenarioAction) { + log.debug("Request to update ScenarioAction : {}", scenarioAction); + return scenarioActionRepository.save(scenarioAction); + } + + @Override + @Transactional(readOnly = true) + public Page findAll(Pageable pageable) { + log.debug("Request to get all ScenarioActions with eager relationships"); + return scenarioActionRepository.findAll(pageable) + .map(ScenarioActionService::restrictToDtoProperties); + } + + @Override + @Transactional(readOnly = true) + public Optional findOne(Long id) { + log.debug("Request to get ScenarioAction : {}", id); + return scenarioActionRepository.findOneWithEagerRelationships(id) + .map(ScenarioActionService::restrictToDtoProperties); + } +} diff --git a/simulator-starter/src/main/java/org/citrusframework/simulator/web/rest/ScenarioActionResource.java b/simulator-starter/src/main/java/org/citrusframework/simulator/web/rest/ScenarioActionResource.java new file mode 100644 index 000000000..3a9e549bd --- /dev/null +++ b/simulator-starter/src/main/java/org/citrusframework/simulator/web/rest/ScenarioActionResource.java @@ -0,0 +1,85 @@ +package org.citrusframework.simulator.web.rest; + +import org.citrusframework.simulator.model.ScenarioAction; +import org.citrusframework.simulator.service.ScenarioActionQueryService; +import org.citrusframework.simulator.service.ScenarioActionService; +import org.citrusframework.simulator.service.criteria.ScenarioActionCriteria; +import org.citrusframework.simulator.web.util.PaginationUtil; +import org.citrusframework.simulator.web.util.ResponseUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import java.util.List; +import java.util.Optional; + +/** + * REST controller for managing {@link ScenarioAction}. + */ +@RestController +@RequestMapping("/api") +public class ScenarioActionResource { + + private final Logger log = LoggerFactory.getLogger(ScenarioActionResource.class); + + private final ScenarioActionService scenarioActionService; + + private final ScenarioActionQueryService scenarioActionQueryService; + + public ScenarioActionResource(ScenarioActionService scenarioActionService, ScenarioActionQueryService scenarioActionQueryService) { + this.scenarioActionService = scenarioActionService; + this.scenarioActionQueryService = scenarioActionQueryService; + } + + /** + * {@code GET /scenario-actions} : get all the scenarioActions. + * + * @param pageable the pagination information. + * @param criteria the criteria which the requested entities should match. + * @return the {@link ResponseEntity} with status {@code 200 (OK)} and the list of scenarioActions in body. + */ + @GetMapping("/scenario-actions") + public ResponseEntity> getAllScenarioActions( + ScenarioActionCriteria criteria, + @org.springdoc.core.annotations.ParameterObject Pageable pageable + ) { + log.debug("REST request to get ScenarioActions by criteria: {}", criteria); + + Page page = scenarioActionQueryService.findByCriteria(criteria, pageable); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(ServletUriComponentsBuilder.fromCurrentRequest(), page); + return ResponseEntity.ok().headers(headers).body(page.getContent()); + } + + /** + * {@code GET /scenario-actions/count} : count all the scenarioActions. + * + * @param criteria the criteria which the requested entities should match. + * @return the {@link ResponseEntity} with status {@code 200 (OK)} and the count in body. + */ + @GetMapping("/scenario-actions/count") + public ResponseEntity countScenarioActions(ScenarioActionCriteria criteria) { + log.debug("REST request to count ScenarioActions by criteria: {}", criteria); + return ResponseEntity.ok().body(scenarioActionQueryService.countByCriteria(criteria)); + } + + /** + * {@code GET /scenario-actions/:id} : get the "id" scenarioAction. + * + * @param id the id of the scenarioAction to retrieve. + * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the scenarioAction, or with status {@code 404 (Not Found)}. + */ + @GetMapping("/scenario-actions/{id}") + public ResponseEntity getScenarioAction(@PathVariable Long id) { + log.debug("REST request to get ScenarioAction : {}", id); + Optional scenarioAction = scenarioActionService.findOne(id); + return ResponseUtil.wrapOrNotFound(scenarioAction); + } +} diff --git a/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/MessageHeaderResourceIT.java b/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/MessageHeaderResourceIT.java index 88c162a6e..91370cea1 100644 --- a/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/MessageHeaderResourceIT.java +++ b/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/MessageHeaderResourceIT.java @@ -5,16 +5,12 @@ import org.citrusframework.simulator.model.Message; import org.citrusframework.simulator.model.MessageHeader; import org.citrusframework.simulator.repository.MessageHeaderRepository; -import org.citrusframework.simulator.service.MessageHeaderService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.transaction.annotation.Transactional; @@ -23,14 +19,9 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; -import java.util.ArrayList; import static org.citrusframework.simulator.web.rest.TestUtil.sameInstant; import static org.hamcrest.Matchers.hasItem; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @@ -64,12 +55,6 @@ public class MessageHeaderResourceIT { @Autowired private MessageHeaderRepository messageHeaderRepository; - @Mock - private MessageHeaderRepository messageHeaderRepositoryMock; - - @Mock - private MessageHeaderService messageHeaderServiceMock; - @Autowired private EntityManager entityManager; diff --git a/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/ScenarioActionResourceIT.java b/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/ScenarioActionResourceIT.java new file mode 100644 index 000000000..3d4e48977 --- /dev/null +++ b/simulator-starter/src/test/java/org/citrusframework/simulator/web/rest/ScenarioActionResourceIT.java @@ -0,0 +1,354 @@ +package org.citrusframework.simulator.web.rest; + +import jakarta.persistence.EntityManager; +import org.citrusframework.simulator.IntegrationTest; +import org.citrusframework.simulator.model.ScenarioAction; +import org.citrusframework.simulator.model.ScenarioExecution; +import org.citrusframework.simulator.repository.ScenarioActionRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; + +import static org.hamcrest.Matchers.hasItem; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * Integration tests for the {@link ScenarioActionResource} REST controller. + */ +@IntegrationTest +@ExtendWith(MockitoExtension.class) +@AutoConfigureMockMvc +class ScenarioActionResourceIT { + + private static final String DEFAULT_NAME = "AAAAAAAAAA"; + private static final String UPDATED_NAME = "BBBBBBBBBB"; + + private static final Instant DEFAULT_START_DATE = Instant.ofEpochMilli(0L); + private static final Instant UPDATED_START_DATE = Instant.now().truncatedTo(ChronoUnit.MILLIS); + + private static final Instant DEFAULT_END_DATE = Instant.ofEpochMilli(0L); + private static final Instant UPDATED_END_DATE = Instant.now().truncatedTo(ChronoUnit.MILLIS); + + private static final String ENTITY_API_URL = "/api/scenario-actions"; + private static final String ENTITY_API_URL_ID = ENTITY_API_URL + "/{id}"; + + @Autowired + private ScenarioActionRepository scenarioActionRepository; + + @Autowired + private EntityManager entityManager; + + @Autowired + private MockMvc restScenarioActionMockMvc; + + private ScenarioAction scenarioAction; + + /** + * Create an entity for this test. + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which requires the current entity. + */ + public static ScenarioAction createEntity(EntityManager entityManager) { + return ScenarioAction.builder() + .name(DEFAULT_NAME) + .startDate(DEFAULT_START_DATE) + .endDate(DEFAULT_END_DATE) + .build(); + } + + /** + * Create an updated entity for this test. + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which requires the current entity. + */ + public static ScenarioAction createUpdatedEntity(EntityManager entityManager) { + return ScenarioAction.builder() + .name(UPDATED_NAME) + .startDate(UPDATED_START_DATE) + .endDate(UPDATED_END_DATE) + .build(); + } + + @BeforeEach + public void initTest() { + scenarioAction = createEntity(entityManager); + } + + @Test + @Transactional + void getAllScenarioActions() throws Exception { + // Initialize the database + scenarioActionRepository.saveAndFlush(scenarioAction); + + // Get all the scenarioActionList + restScenarioActionMockMvc + .perform(get(ENTITY_API_URL + "?sort=actionId,desc")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$.[*].actionId").value(hasItem(scenarioAction.getActionId().intValue()))) + .andExpect(jsonPath("$.[*].name").value(hasItem(DEFAULT_NAME))) + .andExpect(jsonPath("$.[*].startDate").value(hasItem(DEFAULT_START_DATE.toString()))) + .andExpect(jsonPath("$.[*].endDate").value(hasItem(DEFAULT_END_DATE.toString()))); + } + + @Test + @Transactional + void getScenarioAction() throws Exception { + // Initialize the database + scenarioActionRepository.saveAndFlush(scenarioAction); + + // Get the scenarioAction + restScenarioActionMockMvc + .perform(get(ENTITY_API_URL_ID, scenarioAction.getActionId())) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$.actionId").value(scenarioAction.getActionId().intValue())) + .andExpect(jsonPath("$.name").value(DEFAULT_NAME)) + .andExpect(jsonPath("$.startDate").value(DEFAULT_START_DATE.toString())) + .andExpect(jsonPath("$.endDate").value(DEFAULT_END_DATE.toString())); + } + + @Test + @Transactional + void getScenarioActionsByIdFiltering() throws Exception { + // Initialize the database + scenarioActionRepository.saveAndFlush(scenarioAction); + + Long actionId = scenarioAction.getActionId(); + + defaultScenarioActionShouldBeFound("actionId.equals=" + actionId); + defaultScenarioActionShouldNotBeFound("actionId.notEquals=" + actionId); + + defaultScenarioActionShouldBeFound("actionId.greaterThanOrEqual=" + actionId); + defaultScenarioActionShouldNotBeFound("actionId.greaterThan=" + actionId); + + defaultScenarioActionShouldBeFound("actionId.lessThanOrEqual=" + actionId); + defaultScenarioActionShouldNotBeFound("actionId.lessThan=" + actionId); + } + + @Test + @Transactional + void getAllScenarioActionsByNameIsEqualToSomething() throws Exception { + // Initialize the database + scenarioActionRepository.saveAndFlush(scenarioAction); + + // Get all the scenarioActionList where name equals to DEFAULT_NAME + defaultScenarioActionShouldBeFound("name.equals=" + DEFAULT_NAME); + + // Get all the scenarioActionList where name equals to UPDATED_NAME + defaultScenarioActionShouldNotBeFound("name.equals=" + UPDATED_NAME); + } + + @Test + @Transactional + void getAllScenarioActionsByNameIsInShouldWork() throws Exception { + // Initialize the database + scenarioActionRepository.saveAndFlush(scenarioAction); + + // Get all the scenarioActionList where name in DEFAULT_NAME or UPDATED_NAME + defaultScenarioActionShouldBeFound("name.in=" + DEFAULT_NAME + "," + UPDATED_NAME); + + // Get all the scenarioActionList where name equals to UPDATED_NAME + defaultScenarioActionShouldNotBeFound("name.in=" + UPDATED_NAME); + } + + @Test + @Transactional + void getAllScenarioActionsByNameIsNullOrNotNull() throws Exception { + // Initialize the database + scenarioActionRepository.saveAndFlush(scenarioAction); + + // Get all the scenarioActionList where name is not null + defaultScenarioActionShouldBeFound("name.specified=true"); + + // Get all the scenarioActionList where name is null + defaultScenarioActionShouldNotBeFound("name.specified=false"); + } + + @Test + @Transactional + void getAllScenarioActionsByNameContainsSomething() throws Exception { + // Initialize the database + scenarioActionRepository.saveAndFlush(scenarioAction); + + // Get all the scenarioActionList where name contains DEFAULT_NAME + defaultScenarioActionShouldBeFound("name.contains=" + DEFAULT_NAME); + + // Get all the scenarioActionList where name contains UPDATED_NAME + defaultScenarioActionShouldNotBeFound("name.contains=" + UPDATED_NAME); + } + + @Test + @Transactional + void getAllScenarioActionsByNameNotContainsSomething() throws Exception { + // Initialize the database + scenarioActionRepository.saveAndFlush(scenarioAction); + + // Get all the scenarioActionList where name does not contain DEFAULT_NAME + defaultScenarioActionShouldNotBeFound("name.doesNotContain=" + DEFAULT_NAME); + + // Get all the scenarioActionList where name does not contain UPDATED_NAME + defaultScenarioActionShouldBeFound("name.doesNotContain=" + UPDATED_NAME); + } + + @Test + @Transactional + void getAllScenarioActionsByStartDateIsEqualToSomething() throws Exception { + // Initialize the database + scenarioActionRepository.saveAndFlush(scenarioAction); + + // Get all the scenarioActionList where startDate equals to DEFAULT_START_DATE + defaultScenarioActionShouldBeFound("startDate.equals=" + DEFAULT_START_DATE); + + // Get all the scenarioActionList where startDate equals to UPDATED_START_DATE + defaultScenarioActionShouldNotBeFound("startDate.equals=" + UPDATED_START_DATE); + } + + @Test + @Transactional + void getAllScenarioActionsByStartDateIsInShouldWork() throws Exception { + // Initialize the database + scenarioActionRepository.saveAndFlush(scenarioAction); + + // Get all the scenarioActionList where startDate in DEFAULT_START_DATE or UPDATED_START_DATE + defaultScenarioActionShouldBeFound("startDate.in=" + DEFAULT_START_DATE + "," + UPDATED_START_DATE); + + // Get all the scenarioActionList where startDate equals to UPDATED_START_DATE + defaultScenarioActionShouldNotBeFound("startDate.in=" + UPDATED_START_DATE); + } + + @Test + @Transactional + void getAllScenarioActionsByStartDateIsNullOrNotNull() throws Exception { + // Initialize the database + scenarioActionRepository.saveAndFlush(scenarioAction); + + // Get all the scenarioActionList where startDate is not null + defaultScenarioActionShouldBeFound("startDate.specified=true"); + + // Get all the scenarioActionList where startDate is null + defaultScenarioActionShouldNotBeFound("startDate.specified=false"); + } + + @Test + @Transactional + void getAllScenarioActionsByEndDateIsEqualToSomething() throws Exception { + // Initialize the database + scenarioActionRepository.saveAndFlush(scenarioAction); + + // Get all the scenarioActionList where endDate equals to DEFAULT_END_DATE + defaultScenarioActionShouldBeFound("endDate.equals=" + DEFAULT_END_DATE); + + // Get all the scenarioActionList where endDate equals to UPDATED_END_DATE + defaultScenarioActionShouldNotBeFound("endDate.equals=" + UPDATED_END_DATE); + } + + @Test + @Transactional + void getAllScenarioActionsByEndDateIsInShouldWork() throws Exception { + // Initialize the database + scenarioActionRepository.saveAndFlush(scenarioAction); + + // Get all the scenarioActionList where endDate in DEFAULT_END_DATE or UPDATED_END_DATE + defaultScenarioActionShouldBeFound("endDate.in=" + DEFAULT_END_DATE + "," + UPDATED_END_DATE); + + // Get all the scenarioActionList where endDate equals to UPDATED_END_DATE + defaultScenarioActionShouldNotBeFound("endDate.in=" + UPDATED_END_DATE); + } + + @Test + @Transactional + void getAllScenarioActionsByEndDateIsNullOrNotNull() throws Exception { + // Initialize the database + scenarioActionRepository.saveAndFlush(scenarioAction); + + // Get all the scenarioActionList where endDate is not null + defaultScenarioActionShouldBeFound("endDate.specified=true"); + + // Get all the scenarioActionList where endDate is null + defaultScenarioActionShouldNotBeFound("endDate.specified=false"); + } + + @Test + @Transactional + void getAllScenarioActionsByScenarioExecutionIsEqualToSomething() throws Exception { + ScenarioExecution scenarioExecution; + if (TestUtil.findAll(entityManager, ScenarioExecution.class).isEmpty()) { + scenarioActionRepository.saveAndFlush(scenarioAction); + scenarioExecution = ScenarioExecutionResourceIT.createEntity(entityManager); + } else { + scenarioExecution = TestUtil.findAll(entityManager, ScenarioExecution.class).get(0); + } + entityManager.persist(scenarioExecution); + entityManager.flush(); + scenarioAction.setScenarioExecution(scenarioExecution); + scenarioActionRepository.saveAndFlush(scenarioAction); + Long scenarioExecutionId = scenarioExecution.getExecutionId(); + // Get all the scenarioActionList where scenarioExecution equals to scenarioExecutionId + defaultScenarioActionShouldBeFound("scenarioExecutionId.equals=" + scenarioExecutionId); + + // Get all the scenarioActionList where scenarioExecution equals to (scenarioExecutionId + 1) + defaultScenarioActionShouldNotBeFound("scenarioExecutionId.equals=" + (scenarioExecutionId + 1)); + } + + /** + * Executes the search, and checks that the default entity is returned. + */ + private void defaultScenarioActionShouldBeFound(String filter) throws Exception { + restScenarioActionMockMvc + .perform(get(ENTITY_API_URL + "?sort=actionId,desc&" + filter)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$.[*].actionId").value(hasItem(scenarioAction.getActionId().intValue()))) + .andExpect(jsonPath("$.[*].name").value(hasItem(DEFAULT_NAME))) + .andExpect(jsonPath("$.[*].startDate").value(hasItem(DEFAULT_START_DATE.toString()))) + .andExpect(jsonPath("$.[*].endDate").value(hasItem(DEFAULT_END_DATE.toString()))); + + // Check, that the count call also returns 1 + restScenarioActionMockMvc + .perform(get(ENTITY_API_URL + "/count?sort=actionId,desc&" + filter)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(content().string("1")); + } + + /** + * Executes the search, and checks that the default entity is not returned. + */ + private void defaultScenarioActionShouldNotBeFound(String filter) throws Exception { + restScenarioActionMockMvc + .perform(get(ENTITY_API_URL + "?sort=actionId,desc&" + filter)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(jsonPath("$").isArray()) + .andExpect(jsonPath("$").isEmpty()); + + // Check, that the count call also returns 0 + restScenarioActionMockMvc + .perform(get(ENTITY_API_URL + "/count?sort=actionId,desc&" + filter)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(content().string("0")); + } + + @Test + @Transactional + void getNonExistingScenarioAction() throws Exception { + // Get the scenarioAction + restScenarioActionMockMvc.perform(get(ENTITY_API_URL_ID, Long.MAX_VALUE)).andExpect(status().isNotFound()); + } +} diff --git a/simulator-ui/.jhipster/ScenarioAction.json b/simulator-ui/.jhipster/ScenarioAction.json new file mode 100644 index 000000000..ec7cc5d0d --- /dev/null +++ b/simulator-ui/.jhipster/ScenarioAction.json @@ -0,0 +1,36 @@ +{ + "changelogDate": "20231026180542", + "dto": "no", + "entityTableName": "scenario_action", + "fields": [ + { + "fieldName": "name", + "fieldType": "String", + "fieldValidateRules": ["required"] + }, + { + "fieldName": "startDate", + "fieldType": "Instant", + "fieldValidateRules": ["required"] + }, + { + "fieldName": "endDate", + "fieldType": "Instant" + } + ], + "jpaMetamodelFiltering": true, + "name": "ScenarioAction", + "pagination": "pagination", + "readOnly": true, + "relationships": [ + { + "otherEntityField": "scenarioName", + "otherEntityName": "scenarioExecution", + "relationshipName": "scenarioExecution", + "relationshipSide": "left", + "relationshipType": "many-to-one" + } + ], + "searchEngine": "no", + "service": "serviceImpl" +} diff --git a/simulator-ui/src/main/webapp/app/entities/entity-routing.module.ts b/simulator-ui/src/main/webapp/app/entities/entity-routing.module.ts index 626121297..3370e9b88 100644 --- a/simulator-ui/src/main/webapp/app/entities/entity-routing.module.ts +++ b/simulator-ui/src/main/webapp/app/entities/entity-routing.module.ts @@ -19,6 +19,11 @@ import { RouterModule } from '@angular/router'; data: { pageTitle: 'citrusSimulatorApp.scenarioExecution.home.title' }, loadChildren: () => import('./scenario-execution/scenario-execution.routes'), }, + { + path: 'scenario-action', + data: { pageTitle: 'citrusSimulatorApp.scenarioAction.home.title' }, + loadChildren: () => import('./scenario-action/scenario-action.routes'), + }, { path: 'test-parameter', data: { pageTitle: 'citrusSimulatorApp.testParameter.home.title' }, diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-action/detail/scenario-action-detail.component.html b/simulator-ui/src/main/webapp/app/entities/scenario-action/detail/scenario-action-detail.component.html new file mode 100644 index 000000000..e99b980ce --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-action/detail/scenario-action-detail.component.html @@ -0,0 +1,46 @@ +

+
+
+

+ Scenario Action +

+ +
+ + + + + +
+
ID
+
+ {{ scenarioAction.actionId }} +
+
Name
+
+ {{ scenarioAction.name }} +
+
Start Date
+
+ {{ scenarioAction.startDate | formatMediumDatetime }} +
+
End Date
+
+ {{ scenarioAction.endDate | formatMediumDatetime }} +
+
Scenario Execution
+
+ +
+
+ + +
+
+
diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-action/detail/scenario-action-detail.component.spec.ts b/simulator-ui/src/main/webapp/app/entities/scenario-action/detail/scenario-action-detail.component.spec.ts new file mode 100644 index 000000000..05095d426 --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-action/detail/scenario-action-detail.component.spec.ts @@ -0,0 +1,38 @@ +import { TestBed } from '@angular/core/testing'; +import { provideRouter, withComponentInputBinding } from '@angular/router'; +import { RouterTestingHarness, RouterTestingModule } from '@angular/router/testing'; +import { of } from 'rxjs'; + +import { ScenarioActionDetailComponent } from './scenario-action-detail.component'; + +describe('ScenarioAction Management Detail Component', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ScenarioActionDetailComponent, RouterTestingModule.withRoutes([], { bindToComponentInputs: true })], + providers: [ + provideRouter( + [ + { + path: '**', + component: ScenarioActionDetailComponent, + resolve: { scenarioAction: () => of({ actionId: 123 }) }, + }, + ], + withComponentInputBinding(), + ), + ], + }) + .overrideTemplate(ScenarioActionDetailComponent, '') + .compileComponents(); + }); + + describe('OnInit', () => { + it('Should load scenarioAction on init', async () => { + const harness = await RouterTestingHarness.create(); + const instance = await harness.navigateByUrl('/', ScenarioActionDetailComponent); + + // THEN + expect(instance.scenarioAction).toEqual(expect.objectContaining({ actionId: 123 })); + }); + }); +}); diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-action/detail/scenario-action-detail.component.ts b/simulator-ui/src/main/webapp/app/entities/scenario-action/detail/scenario-action-detail.component.ts new file mode 100644 index 000000000..c78f90a89 --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-action/detail/scenario-action-detail.component.ts @@ -0,0 +1,22 @@ +import { Component, Input } from '@angular/core'; +import { ActivatedRoute, RouterModule } from '@angular/router'; + +import SharedModule from 'app/shared/shared.module'; +import { DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe } from 'app/shared/date'; +import { IScenarioAction } from '../scenario-action.model'; + +@Component({ + standalone: true, + selector: 'jhi-scenario-action-detail', + templateUrl: './scenario-action-detail.component.html', + imports: [SharedModule, RouterModule, DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe], +}) +export class ScenarioActionDetailComponent { + @Input() scenarioAction: IScenarioAction | null = null; + + constructor(protected activatedRoute: ActivatedRoute) {} + + previousState(): void { + window.history.back(); + } +} diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-action/list/scenario-action.component.html b/simulator-ui/src/main/webapp/app/entities/scenario-action/list/scenario-action.component.html new file mode 100644 index 000000000..6a3d2cfb8 --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-action/list/scenario-action.component.html @@ -0,0 +1,110 @@ +
+

+ Scenario Actions + +
+ +
+

+ + + + + + + +
+ No Scenario Actions found +
+ +
+ + + + + + + + + + + + + + + + + + + + + +
+
+ ID + +
+
+
+ Name + +
+
+
+ Start Date + +
+
+
+ End Date + +
+
+
+ Scenario Execution + +
+
+ {{ scenarioAction.actionId }} + {{ scenarioAction.name }}{{ scenarioAction.startDate | formatMediumDatetime }}{{ scenarioAction.endDate | formatMediumDatetime }} + + +
+ +
+
+
+ +
+
+ +
+ +
+ +
+
+
diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-action/list/scenario-action.component.spec.ts b/simulator-ui/src/main/webapp/app/entities/scenario-action/list/scenario-action.component.spec.ts new file mode 100644 index 000000000..27df6967e --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-action/list/scenario-action.component.spec.ts @@ -0,0 +1,125 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { HttpHeaders, HttpResponse } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ActivatedRoute } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; +import { of } from 'rxjs'; + +import { ScenarioActionService } from '../service/scenario-action.service'; + +import { ScenarioActionComponent } from './scenario-action.component'; +import SpyInstance = jest.SpyInstance; + +describe('ScenarioAction Management Component', () => { + let comp: ScenarioActionComponent; + let fixture: ComponentFixture; + let service: ScenarioActionService; + let routerNavigateSpy: SpyInstance>; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + RouterTestingModule.withRoutes([{ path: 'scenario-action', component: ScenarioActionComponent }]), + HttpClientTestingModule, + ScenarioActionComponent, + ], + providers: [ + { + provide: ActivatedRoute, + useValue: { + data: of({ + defaultSort: 'actionId,asc', + }), + queryParamMap: of( + jest.requireActual('@angular/router').convertToParamMap({ + page: '1', + size: '1', + sort: 'actionId,desc', + 'filter[someId.in]': 'dc4279ea-cfb9-11ec-9d64-0242ac120002', + }), + ), + snapshot: { queryParams: {} }, + }, + }, + ], + }) + .overrideTemplate(ScenarioActionComponent, '') + .compileComponents(); + + fixture = TestBed.createComponent(ScenarioActionComponent); + comp = fixture.componentInstance; + service = TestBed.inject(ScenarioActionService); + routerNavigateSpy = jest.spyOn(comp.router, 'navigate'); + + const headers = new HttpHeaders(); + jest.spyOn(service, 'query').mockReturnValue( + of( + new HttpResponse({ + body: [{ actionId: 123 }], + headers, + }), + ), + ); + }); + + it('Should call load all on init', () => { + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.query).toHaveBeenCalled(); + expect(comp.scenarioActions?.[0]).toEqual(expect.objectContaining({ actionId: 123 })); + }); + + describe('trackId', () => { + it('Should forward to scenarioActionService', () => { + const entity = { actionId: 123 }; + jest.spyOn(service, 'getScenarioActionIdentifier'); + const actionId = comp.trackId(0, entity); + expect(service.getScenarioActionIdentifier).toHaveBeenCalledWith(entity); + expect(actionId).toBe(entity.actionId); + }); + }); + + it('should load a page', () => { + // WHEN + comp.navigateToPage(1); + + // THEN + expect(routerNavigateSpy).toHaveBeenCalled(); + }); + + it('should calculate the sort attribute for an id', () => { + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.query).toHaveBeenLastCalledWith(expect.objectContaining({ sort: ['actionId,desc'] })); + }); + + it('should calculate the sort attribute for a non-id attribute', () => { + // GIVEN + comp.predicate = 'name'; + + // WHEN + comp.navigateToWithComponentValues(); + + // THEN + expect(routerNavigateSpy).toHaveBeenLastCalledWith( + expect.anything(), + expect.objectContaining({ + queryParams: expect.objectContaining({ + sort: ['name,asc'], + }), + }), + ); + }); + + it('should calculate the filter attribute', () => { + // WHEN + comp.ngOnInit(); + + // THEN + expect(service.query).toHaveBeenLastCalledWith(expect.objectContaining({ 'someId.in': ['dc4279ea-cfb9-11ec-9d64-0242ac120002'] })); + }); +}); diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-action/list/scenario-action.component.ts b/simulator-ui/src/main/webapp/app/entities/scenario-action/list/scenario-action.component.ts new file mode 100644 index 000000000..56ceb6c1c --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-action/list/scenario-action.component.ts @@ -0,0 +1,152 @@ +import { Component, OnInit } from '@angular/core'; +import { HttpHeaders } from '@angular/common/http'; +import { ActivatedRoute, Data, ParamMap, Router, RouterModule } from '@angular/router'; +import { combineLatest, Observable, switchMap, tap } from 'rxjs'; + +import SharedModule from 'app/shared/shared.module'; +import { SortDirective, SortByDirective } from 'app/shared/sort'; +import { DurationPipe, FormatMediumDatetimePipe, FormatMediumDatePipe } from 'app/shared/date'; +import { ItemCountComponent } from 'app/shared/pagination'; +import { FormsModule } from '@angular/forms'; + +import { ITEMS_PER_PAGE, PAGE_HEADER, TOTAL_COUNT_RESPONSE_HEADER } from 'app/config/pagination.constants'; +import { ASC, DESC, SORT, DEFAULT_SORT_DATA } from 'app/config/navigation.constants'; +import { FilterComponent, FilterOptions, IFilterOptions, IFilterOption } from 'app/shared/filter'; +import { EntityArrayResponseType, ScenarioActionService } from '../service/scenario-action.service'; +import { IScenarioAction } from '../scenario-action.model'; + +@Component({ + standalone: true, + selector: 'jhi-scenario-action', + templateUrl: './scenario-action.component.html', + imports: [ + RouterModule, + FormsModule, + SharedModule, + SortDirective, + SortByDirective, + DurationPipe, + FormatMediumDatetimePipe, + FormatMediumDatePipe, + FilterComponent, + ItemCountComponent, + ], +}) +export class ScenarioActionComponent implements OnInit { + scenarioActions?: IScenarioAction[]; + isLoading = false; + + predicate = 'actionId'; + ascending = true; + filters: IFilterOptions = new FilterOptions(); + + itemsPerPage = ITEMS_PER_PAGE; + totalItems = 0; + page = 1; + + constructor( + protected scenarioActionService: ScenarioActionService, + protected activatedRoute: ActivatedRoute, + public router: Router, + ) {} + + trackId = (_index: number, item: IScenarioAction): number => this.scenarioActionService.getScenarioActionIdentifier(item); + + ngOnInit(): void { + this.load(); + + this.filters.filterChanges.subscribe(filterOptions => this.handleNavigation(1, this.predicate, this.ascending, filterOptions)); + } + + load(): void { + this.loadFromBackendWithRouteInformations().subscribe({ + next: (res: EntityArrayResponseType) => { + this.onResponseSuccess(res); + }, + }); + } + + navigateToWithComponentValues(): void { + this.handleNavigation(this.page, this.predicate, this.ascending, this.filters.filterOptions); + } + + navigateToPage(page = this.page): void { + this.handleNavigation(page, this.predicate, this.ascending, this.filters.filterOptions); + } + + protected loadFromBackendWithRouteInformations(): Observable { + return combineLatest([this.activatedRoute.queryParamMap, this.activatedRoute.data]).pipe( + tap(([params, data]) => this.fillComponentAttributeFromRoute(params, data)), + switchMap(() => this.queryBackend(this.page, this.predicate, this.ascending, this.filters.filterOptions)), + ); + } + + protected fillComponentAttributeFromRoute(params: ParamMap, data: Data): void { + const page = params.get(PAGE_HEADER); + this.page = +(page ?? 1); + const sort = (params.get(SORT) ?? data[DEFAULT_SORT_DATA]).split(','); + this.predicate = sort[0]; + this.ascending = sort[1] === ASC; + this.filters.initializeFromParams(params); + } + + protected onResponseSuccess(response: EntityArrayResponseType): void { + this.fillComponentAttributesFromResponseHeader(response.headers); + const dataFromBody = this.fillComponentAttributesFromResponseBody(response.body); + this.scenarioActions = dataFromBody; + } + + protected fillComponentAttributesFromResponseBody(data: IScenarioAction[] | null): IScenarioAction[] { + return data ?? []; + } + + protected fillComponentAttributesFromResponseHeader(headers: HttpHeaders): void { + this.totalItems = Number(headers.get(TOTAL_COUNT_RESPONSE_HEADER)); + } + + protected queryBackend( + page?: number, + predicate?: string, + ascending?: boolean, + filterOptions?: IFilterOption[], + ): Observable { + this.isLoading = true; + const pageToLoad: number = page ?? 1; + const queryObject: any = { + page: pageToLoad - 1, + size: this.itemsPerPage, + eagerload: true, + sort: this.getSortQueryParam(predicate, ascending), + }; + filterOptions?.forEach(filterOption => { + queryObject[filterOption.name] = filterOption.values; + }); + return this.scenarioActionService.query(queryObject).pipe(tap(() => (this.isLoading = false))); + } + + protected handleNavigation(page = this.page, predicate?: string, ascending?: boolean, filterOptions?: IFilterOption[]): void { + const queryParamsObj: any = { + page, + size: this.itemsPerPage, + sort: this.getSortQueryParam(predicate, ascending), + }; + + filterOptions?.forEach(filterOption => { + queryParamsObj[filterOption.nameAsQueryParam()] = filterOption.values; + }); + + this.router.navigate(['./'], { + relativeTo: this.activatedRoute, + queryParams: queryParamsObj, + }); + } + + protected getSortQueryParam(predicate = this.predicate, ascending = this.ascending): string[] { + const ascendingQueryParam = ascending ? ASC : DESC; + if (predicate === '') { + return []; + } else { + return [predicate + ',' + ascendingQueryParam]; + } + } +} diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-action/route/scenario-action-routing-resolve.service.spec.ts b/simulator-ui/src/main/webapp/app/entities/scenario-action/route/scenario-action-routing-resolve.service.spec.ts new file mode 100644 index 000000000..e7d1560e9 --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-action/route/scenario-action-routing-resolve.service.spec.ts @@ -0,0 +1,99 @@ +import { TestBed } from '@angular/core/testing'; +import { HttpResponse } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ActivatedRouteSnapshot, ActivatedRoute, Router, convertToParamMap } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; +import { of } from 'rxjs'; + +import { IScenarioAction } from '../scenario-action.model'; +import { ScenarioActionService } from '../service/scenario-action.service'; + +import scenarioActionResolve from './scenario-action-routing-resolve.service'; + +describe('ScenarioAction routing resolve service', () => { + let mockRouter: Router; + let mockActivatedRouteSnapshot: ActivatedRouteSnapshot; + let service: ScenarioActionService; + let resultScenarioAction: IScenarioAction | null | undefined; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule, RouterTestingModule.withRoutes([])], + providers: [ + { + provide: ActivatedRoute, + useValue: { + snapshot: { + paramMap: convertToParamMap({}), + }, + }, + }, + ], + }); + mockRouter = TestBed.inject(Router); + jest.spyOn(mockRouter, 'navigate').mockImplementation(() => Promise.resolve(true)); + mockActivatedRouteSnapshot = TestBed.inject(ActivatedRoute).snapshot; + service = TestBed.inject(ScenarioActionService); + resultScenarioAction = undefined; + }); + + describe('resolve', () => { + it('should return IScenarioAction returned by find', () => { + // GIVEN + service.find = jest.fn(actionId => of(new HttpResponse({ body: { actionId } }))); + mockActivatedRouteSnapshot.params = { actionId: 123 }; + + // WHEN + TestBed.runInInjectionContext(() => { + scenarioActionResolve(mockActivatedRouteSnapshot).subscribe({ + next(result) { + resultScenarioAction = result; + }, + }); + }); + + // THEN + expect(service.find).toBeCalledWith(123); + expect(resultScenarioAction).toEqual({ actionId: 123 }); + }); + + it('should return null if actionId is not provided', () => { + // GIVEN + service.find = jest.fn(); + mockActivatedRouteSnapshot.params = {}; + + // WHEN + TestBed.runInInjectionContext(() => { + scenarioActionResolve(mockActivatedRouteSnapshot).subscribe({ + next(result) { + resultScenarioAction = result; + }, + }); + }); + + // THEN + expect(service.find).not.toBeCalled(); + expect(resultScenarioAction).toEqual(null); + }); + + it('should route to 404 page if data not found in server', () => { + // GIVEN + jest.spyOn(service, 'find').mockReturnValue(of(new HttpResponse({ body: null }))); + mockActivatedRouteSnapshot.params = { actionId: 123 }; + + // WHEN + TestBed.runInInjectionContext(() => { + scenarioActionResolve(mockActivatedRouteSnapshot).subscribe({ + next(result) { + resultScenarioAction = result; + }, + }); + }); + + // THEN + expect(service.find).toBeCalledWith(123); + expect(resultScenarioAction).toEqual(undefined); + expect(mockRouter.navigate).toHaveBeenCalledWith(['404']); + }); + }); +}); diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-action/route/scenario-action-routing-resolve.service.ts b/simulator-ui/src/main/webapp/app/entities/scenario-action/route/scenario-action-routing-resolve.service.ts new file mode 100644 index 000000000..aff63f652 --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-action/route/scenario-action-routing-resolve.service.ts @@ -0,0 +1,29 @@ +import { inject } from '@angular/core'; +import { HttpResponse } from '@angular/common/http'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { of, EMPTY, Observable } from 'rxjs'; +import { mergeMap } from 'rxjs/operators'; + +import { IScenarioAction } from '../scenario-action.model'; +import { ScenarioActionService } from '../service/scenario-action.service'; + +export const scenarioActionResolve = (route: ActivatedRouteSnapshot): Observable => { + const actionId = route.params['actionId']; + if (actionId) { + return inject(ScenarioActionService) + .find(actionId) + .pipe( + mergeMap((scenarioAction: HttpResponse) => { + if (scenarioAction.body) { + return of(scenarioAction.body); + } else { + inject(Router).navigate(['404']); + return EMPTY; + } + }), + ); + } + return of(null); +}; + +export default scenarioActionResolve; diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-action/scenario-action.model.ts b/simulator-ui/src/main/webapp/app/entities/scenario-action/scenario-action.model.ts new file mode 100644 index 000000000..66adabdd6 --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-action/scenario-action.model.ts @@ -0,0 +1,12 @@ +import dayjs from 'dayjs/esm'; +import { IScenarioExecution } from 'app/entities/scenario-execution/scenario-execution.model'; + +export interface IScenarioAction { + actionId: number; + name?: string | null; + startDate?: dayjs.Dayjs | null; + endDate?: dayjs.Dayjs | null; + scenarioExecution?: Pick | null; +} + +export type NewScenarioAction = Omit & { actionId: null }; diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-action/scenario-action.routes.ts b/simulator-ui/src/main/webapp/app/entities/scenario-action/scenario-action.routes.ts new file mode 100644 index 000000000..ad1087883 --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-action/scenario-action.routes.ts @@ -0,0 +1,25 @@ +import { Routes } from '@angular/router'; + +import { ASC } from 'app/config/navigation.constants'; +import { ScenarioActionComponent } from './list/scenario-action.component'; +import { ScenarioActionDetailComponent } from './detail/scenario-action-detail.component'; +import ScenarioActionResolve from './route/scenario-action-routing-resolve.service'; + +const scenarioActionRoute: Routes = [ + { + path: '', + component: ScenarioActionComponent, + data: { + defaultSort: 'actionId,' + ASC, + }, + }, + { + path: ':actionId/view', + component: ScenarioActionDetailComponent, + resolve: { + scenarioAction: ScenarioActionResolve, + }, + }, +]; + +export default scenarioActionRoute; diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-action/scenario-action.test-samples.ts b/simulator-ui/src/main/webapp/app/entities/scenario-action/scenario-action.test-samples.ts new file mode 100644 index 000000000..ce0b28ab8 --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-action/scenario-action.test-samples.ts @@ -0,0 +1,33 @@ +import dayjs from 'dayjs/esm'; + +import { IScenarioAction, NewScenarioAction } from './scenario-action.model'; + +export const sampleWithRequiredData: IScenarioAction = { + actionId: 11639, + name: 'genuflect woot absent', + startDate: dayjs('2023-10-26T16:18'), +}; + +export const sampleWithPartialData: IScenarioAction = { + actionId: 7876, + name: 'offensively', + startDate: dayjs('2023-10-26T06:41'), +}; + +export const sampleWithFullData: IScenarioAction = { + actionId: 1734, + name: 'except brr careless', + startDate: dayjs('2023-10-26T10:55'), + endDate: dayjs('2023-10-25T18:11'), +}; + +export const sampleWithNewData: NewScenarioAction = { + name: 'dearly', + startDate: dayjs('2023-10-26T11:00'), + actionId: null, +}; + +Object.freeze(sampleWithNewData); +Object.freeze(sampleWithRequiredData); +Object.freeze(sampleWithPartialData); +Object.freeze(sampleWithFullData); diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-action/service/scenario-action.service.spec.ts b/simulator-ui/src/main/webapp/app/entities/scenario-action/service/scenario-action.service.spec.ts new file mode 100644 index 000000000..fbc6fb466 --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-action/service/scenario-action.service.spec.ts @@ -0,0 +1,160 @@ +import { TestBed } from '@angular/core/testing'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; + +import { IScenarioAction } from '../scenario-action.model'; +import { sampleWithRequiredData, sampleWithPartialData, sampleWithFullData } from '../scenario-action.test-samples'; + +import { ScenarioActionService, RestScenarioAction } from './scenario-action.service'; + +const requireRestSample: RestScenarioAction = { + ...sampleWithRequiredData, + startDate: sampleWithRequiredData.startDate?.toJSON(), + endDate: sampleWithRequiredData.endDate?.toJSON(), +}; + +describe('ScenarioAction Service', () => { + let service: ScenarioActionService; + let httpMock: HttpTestingController; + let expectedResult: IScenarioAction | IScenarioAction[] | boolean | null; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + }); + expectedResult = null; + service = TestBed.inject(ScenarioActionService); + httpMock = TestBed.inject(HttpTestingController); + }); + + describe('Service methods', () => { + it('should find an element', () => { + const returnedFromService = { ...requireRestSample }; + const expected = { ...sampleWithRequiredData }; + + service.find(123).subscribe(resp => (expectedResult = resp.body)); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush(returnedFromService); + expect(expectedResult).toMatchObject(expected); + }); + + it('should return a list of ScenarioAction', () => { + const returnedFromService = { ...requireRestSample }; + + const expected = { ...sampleWithRequiredData }; + + service.query().subscribe(resp => (expectedResult = resp.body)); + + const req = httpMock.expectOne({ method: 'GET' }); + req.flush([returnedFromService]); + httpMock.verify(); + expect(expectedResult).toMatchObject([expected]); + }); + + describe('addScenarioActionToCollectionIfMissing', () => { + it('should add a ScenarioAction to an empty array', () => { + const scenarioAction: IScenarioAction = sampleWithRequiredData; + expectedResult = service.addScenarioActionToCollectionIfMissing([], scenarioAction); + expect(expectedResult).toHaveLength(1); + expect(expectedResult).toContain(scenarioAction); + }); + + it('should not add a ScenarioAction to an array that contains it', () => { + const scenarioAction: IScenarioAction = sampleWithRequiredData; + const scenarioActionCollection: IScenarioAction[] = [ + { + ...scenarioAction, + }, + sampleWithPartialData, + ]; + expectedResult = service.addScenarioActionToCollectionIfMissing(scenarioActionCollection, scenarioAction); + expect(expectedResult).toHaveLength(2); + }); + + it("should add a ScenarioAction to an array that doesn't contain it", () => { + const scenarioAction: IScenarioAction = sampleWithRequiredData; + const scenarioActionCollection: IScenarioAction[] = [sampleWithPartialData]; + expectedResult = service.addScenarioActionToCollectionIfMissing(scenarioActionCollection, scenarioAction); + expect(expectedResult).toHaveLength(2); + expect(expectedResult).toContain(scenarioAction); + }); + + it('should add only unique ScenarioAction to an array', () => { + const scenarioActionArray: IScenarioAction[] = [sampleWithRequiredData, sampleWithPartialData, sampleWithFullData]; + const scenarioActionCollection: IScenarioAction[] = [sampleWithRequiredData]; + expectedResult = service.addScenarioActionToCollectionIfMissing(scenarioActionCollection, ...scenarioActionArray); + expect(expectedResult).toHaveLength(3); + }); + + it('should accept varargs', () => { + const scenarioAction: IScenarioAction = sampleWithRequiredData; + const scenarioAction2: IScenarioAction = sampleWithPartialData; + expectedResult = service.addScenarioActionToCollectionIfMissing([], scenarioAction, scenarioAction2); + expect(expectedResult).toHaveLength(2); + expect(expectedResult).toContain(scenarioAction); + expect(expectedResult).toContain(scenarioAction2); + }); + + it('should accept null and undefined values', () => { + const scenarioAction: IScenarioAction = sampleWithRequiredData; + expectedResult = service.addScenarioActionToCollectionIfMissing([], null, scenarioAction, undefined); + expect(expectedResult).toHaveLength(1); + expect(expectedResult).toContain(scenarioAction); + }); + + it('should return initial array if no ScenarioAction is added', () => { + const scenarioActionCollection: IScenarioAction[] = [sampleWithRequiredData]; + expectedResult = service.addScenarioActionToCollectionIfMissing(scenarioActionCollection, undefined, null); + expect(expectedResult).toEqual(scenarioActionCollection); + }); + }); + + describe('compareScenarioAction', () => { + it('Should return true if both entities are null', () => { + const entity1 = null; + const entity2 = null; + + const compareResult = service.compareScenarioAction(entity1, entity2); + + expect(compareResult).toEqual(true); + }); + + it('Should return false if one entity is null', () => { + const entity1 = { actionId: 123 }; + const entity2 = null; + + const compareResult1 = service.compareScenarioAction(entity1, entity2); + const compareResult2 = service.compareScenarioAction(entity2, entity1); + + expect(compareResult1).toEqual(false); + expect(compareResult2).toEqual(false); + }); + + it('Should return false if primaryKey differs', () => { + const entity1 = { actionId: 123 }; + const entity2 = { actionId: 456 }; + + const compareResult1 = service.compareScenarioAction(entity1, entity2); + const compareResult2 = service.compareScenarioAction(entity2, entity1); + + expect(compareResult1).toEqual(false); + expect(compareResult2).toEqual(false); + }); + + it('Should return false if primaryKey matches', () => { + const entity1 = { actionId: 123 }; + const entity2 = { actionId: 123 }; + + const compareResult1 = service.compareScenarioAction(entity1, entity2); + const compareResult2 = service.compareScenarioAction(entity2, entity1); + + expect(compareResult1).toEqual(true); + expect(compareResult2).toEqual(true); + }); + }); + }); + + afterEach(() => { + httpMock.verify(); + }); +}); diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-action/service/scenario-action.service.ts b/simulator-ui/src/main/webapp/app/entities/scenario-action/service/scenario-action.service.ts new file mode 100644 index 000000000..3e701ca46 --- /dev/null +++ b/simulator-ui/src/main/webapp/app/entities/scenario-action/service/scenario-action.service.ts @@ -0,0 +1,111 @@ +import { Injectable } from '@angular/core'; +import { HttpClient, HttpResponse } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +import { map } from 'rxjs/operators'; + +import dayjs from 'dayjs/esm'; + +import { isPresent } from 'app/core/util/operators'; +import { ApplicationConfigService } from 'app/core/config/application-config.service'; +import { createRequestOption } from 'app/core/request/request-util'; +import { IScenarioAction, NewScenarioAction } from '../scenario-action.model'; + +export type PartialUpdateScenarioAction = Partial & Pick; + +type RestOf = Omit & { + startDate?: string | null; + endDate?: string | null; +}; + +export type RestScenarioAction = RestOf; + +export type NewRestScenarioAction = RestOf; + +export type PartialUpdateRestScenarioAction = RestOf; + +export type EntityResponseType = HttpResponse; +export type EntityArrayResponseType = HttpResponse; + +@Injectable({ providedIn: 'root' }) +export class ScenarioActionService { + protected resourceUrl = this.applicationConfigService.getEndpointFor('api/scenario-actions'); + + constructor( + protected http: HttpClient, + protected applicationConfigService: ApplicationConfigService, + ) {} + + find(actionId: number): Observable { + return this.http + .get(`${this.resourceUrl}/${actionId}`, { observe: 'response' }) + .pipe(map(res => this.convertResponseFromServer(res))); + } + + query(req?: any): Observable { + const options = createRequestOption(req); + return this.http + .get(this.resourceUrl, { params: options, observe: 'response' }) + .pipe(map(res => this.convertResponseArrayFromServer(res))); + } + + getScenarioActionIdentifier(scenarioAction: Pick): number { + return scenarioAction.actionId; + } + + compareScenarioAction(o1: Pick | null, o2: Pick | null): boolean { + return o1 && o2 ? this.getScenarioActionIdentifier(o1) === this.getScenarioActionIdentifier(o2) : o1 === o2; + } + + addScenarioActionToCollectionIfMissing>( + scenarioActionCollection: Type[], + ...scenarioActionsToCheck: (Type | null | undefined)[] + ): Type[] { + const scenarioActions: Type[] = scenarioActionsToCheck.filter(isPresent); + if (scenarioActions.length > 0) { + const scenarioActionCollectionIdentifiers = scenarioActionCollection.map( + scenarioActionItem => this.getScenarioActionIdentifier(scenarioActionItem)!, + ); + const scenarioActionsToAdd = scenarioActions.filter(scenarioActionItem => { + const scenarioActionIdentifier = this.getScenarioActionIdentifier(scenarioActionItem); + if (scenarioActionCollectionIdentifiers.includes(scenarioActionIdentifier)) { + return false; + } + scenarioActionCollectionIdentifiers.push(scenarioActionIdentifier); + return true; + }); + return [...scenarioActionsToAdd, ...scenarioActionCollection]; + } + return scenarioActionCollection; + } + + protected convertDateFromClient( + scenarioAction: T, + ): RestOf { + return { + ...scenarioAction, + startDate: scenarioAction.startDate?.toJSON() ?? null, + endDate: scenarioAction.endDate?.toJSON() ?? null, + }; + } + + protected convertDateFromServer(restScenarioAction: RestScenarioAction): IScenarioAction { + return { + ...restScenarioAction, + startDate: restScenarioAction.startDate ? dayjs(restScenarioAction.startDate) : undefined, + endDate: restScenarioAction.endDate ? dayjs(restScenarioAction.endDate) : undefined, + }; + } + + protected convertResponseFromServer(res: HttpResponse): HttpResponse { + return res.clone({ + body: res.body ? this.convertDateFromServer(res.body) : null, + }); + } + + protected convertResponseArrayFromServer(res: HttpResponse): HttpResponse { + return res.clone({ + body: res.body ? res.body.map(item => this.convertDateFromServer(item)) : null, + }); + } +} diff --git a/simulator-ui/src/main/webapp/app/entities/scenario-execution/list/scenario-execution.component.spec.ts b/simulator-ui/src/main/webapp/app/entities/scenario-execution/list/scenario-execution.component.spec.ts index 944017929..584b0d420 100644 --- a/simulator-ui/src/main/webapp/app/entities/scenario-execution/list/scenario-execution.component.spec.ts +++ b/simulator-ui/src/main/webapp/app/entities/scenario-execution/list/scenario-execution.component.spec.ts @@ -89,7 +89,7 @@ describe('ScenarioExecution Management Component', () => { expect(routerNavigateSpy).toHaveBeenCalled(); }); - it('should calculate the sort attribute for an executionId', () => { + it('should calculate the sort attribute for an id', () => { // WHEN comp.ngOnInit(); diff --git a/simulator-ui/src/main/webapp/app/layouts/navbar/navbar.component.html b/simulator-ui/src/main/webapp/app/layouts/navbar/navbar.component.html index b7e8e8394..4fb4effe6 100644 --- a/simulator-ui/src/main/webapp/app/layouts/navbar/navbar.component.html +++ b/simulator-ui/src/main/webapp/app/layouts/navbar/navbar.component.html @@ -78,6 +78,18 @@ Scenario Execution +
  • + + + Scenario Action + +