UI elements
CampaignDetailsTab, CampaignExecutionsTab, CampaignHistoryTab
In TimveroOS, tabs (EntityTabController
) are used to display additional information about an entity on its detail page. For campaigns, three tabs are used:
📋 CampaignDetailsTab
Example:
@RequestMapping("/details")
@Controller
@Order(1000)
public class CampaignDetailsTab extends EntityTabController<Long, Campaign> {
@Override
public boolean isVisible(Campaign entity) {
return true; // logic for tab visibility
}
}
🧩 Template: /campaign/tab/details.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<th:block th:object="${entity}">
<div class="card-body card-info-wrapper d-flex">
<div class="card-info d-flex">
<ul class="card-info__body d-flex">
<li class="card-info__item d-flex">
<span class="card-info__property" th:text="#{campaign.name}"
th:title="#{campaign.name}"></span>
<span class="card-info__value" th:text="*{name}"></span>
</li>
<li class="card-info__item d-flex">
<span class="card-info__property" th:text="#{campaign.executionType}"
th:title="#{campaign.executionType}"></span>
<span class="card-info__value" th:text="*{#enums.name(executionType)}"></span>
</li>
<!-- Display additional campaign details -->
</ul>
</div>
</div>
</th:block>
</html>
Purpose: Displays basic information about the campaign:
name
executionType
and more
📈 CampaignExecutionsTab
Example:
@RequestMapping("/executions")
@Controller
@Order(3000)
public class CampaignExecutionsTab extends EntityTabController<Long, Campaign> {
@Autowired
private CampaignFormService formService;
@Override
public boolean isVisible(Campaign entity) {
return true;
}
@Override
protected String getTabTemplate(Long aLong, Model model) throws Exception {
Campaign campaign = loadEntity(aLong);
List<Campaign> versionList = formService.findAllVersions(campaign.getLineageId()).stream()
.sorted(Comparator.comparing(Campaign::getCreatedAt).reversed())
.toList();
model.addAttribute("executions", versionList.stream()
.map(Campaign::getExecutions)
.flatMap(Collection::stream)
.sorted(Comparator.comparing(CampaignExecution::getCreatedAt).reversed())
.collect(Collectors.toList()));
return super.getTabTemplate(aLong, model);
}
}
🧩 Template: /campaign/tab/executions.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<th:block>
<div class="card-body">
<table class="table">
<thead>
<tr role="row">
<th data-sortField="id" th:text="#{symbol.id}"></th>
<th data-sortField="createdAt" th:text="#{campaign.execution.startDate}"></th>
<th th:text="#{campaign.name}"></th>
<th th:text="#{campaign.execution.status}"></th>
</tr>
</thead>
<tbody>
<th:block th:each="execution : ${executions}">
<tr role="row"
th:href="@{${'/campaign-execution/' + execution.id}}"
class="clickable">
<td th:text="${execution.id}"></td>
<td th:text="*{#ldates.format(execution.createdAt)}"></td>
<td th:text="*{#enums.name(execution.status)}"></td>
</tr>
</th:block>
</tbody>
</table>
</div>
</th:block>
</html>
Purpose:
Displays all executions (CampaignExecution
) across all versions of the campaign, sorted from newest to oldest.
🕓 CampaignHistoryTab
Example:
@RequestMapping("/history")
@Controller
@Order(4000)
public class CampaignHistoryTab extends EntityTabController<Long, Campaign> {
@Autowired
private CampaignFormService formService;
@Override
public boolean isVisible(Campaign entity) {
return true;
}
@Override
protected String getTabTemplate(Long aLong, Model model) throws Exception {
Campaign campaign = loadEntity(aLong);
model.addAttribute("history", formService.findAllVersions(campaign.getLineageId()).stream()
.sorted(Comparator.comparing(Campaign::getCreatedAt).reversed())
.collect(Collectors.toList()));
return super.getTabTemplate(aLong, model);
}
}
🧩 Template: /campaign/tab/history.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<div class="template">
<div class="content__container">
<div class="list-group" id="docTemplates" role="tablist">
<div class="list-group-links" style="min-width: 226px;">
<a
class="list-group-item list-group-item-action"
data-toggle="list"
role="tab"
th:attr="action-controls = *{'tab-' + id}"
th:classappend="*{active ? 'active' : ''}"
th:data-id="*{id}"
th:each="item : ${history}"
th:href="*{'#tab-' + id}"
th:id="*{'tab-'+ id + '-list'}"
th:object="${item}">
<span th:text="*{#ldates.format(createdAt, 'MM/dd/yy')}"></span><br/>
<span th:text="*{displayedName}"></span><br/>
<span th:text="#{common.created.by}"></span>
<span th:text="*{createdBy.name}"></span>
</a>
</div>
</div>
<div class="tab-content">
<th:block th:each="item, i : ${history}" th:object="${item}">
<div class="tab-pane fade"
role="tabpanel"
th:attr="aria-labeledby = *{'tab-'+ id + '-list'}"
th:classappend="*{active ? 'show active' : ''}"
th:id="*{'tab-' + id}">
<div class="card-body" style="min-height: calc(100vh - 185px);">
<div class="mb-10 d-flex align-items-center">
<span class="ml-2" th:utext="*{displayedName}"></span>
</div>
<th:block
th:with="height = 'min-height: calc(100vh - 300px);'"
th:insert="~{/form/components-plain :: codeEditor(
'expression.expression',
*{expression.expression},
'code-editor',
'expression.engineName',
${engineNames})}"/>
</div>
</div>
</th:block>
</div>
</div>
</div>
<th:block th:insert="~{/template/details:: templateActions('#docTemplates', 'campaign')}"/>
</html>
Purpose:
Displays the change history of the campaign.
Each version appears as a separate block showing the expression, creation date, and author.
Uses lineageId
to track the version lineage.
Last updated
Was this helpful?