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?