Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add white-label options for title, custom logo, code and styles #269

Merged
merged 2 commits into from
Jul 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,19 @@ server:

It is then available under http://localhost:8082/monitor.

#### change look & feel, a.k.a. white-labeling

You can change the look & feel of Zeebe Simple Monitor to match your own logo
or alter the background color like for example: test=green, prod=red.
These options can be adopted.

```
- white-label.logo.path=img/logo.png
- white-label.custom.title=Zeebe Simple Monitor
- white-label.custom.css.path=css/custom.css
- white-label.custom.js.path=js/custom.js
```

#### Change the Database

For example, using PostgreSQL:
Expand Down
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@

<!-- testing -->

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down
44 changes: 34 additions & 10 deletions src/main/java/io/zeebe/monitor/rest/ViewController.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ public class ViewController {
private static final List<String> JOB_COMPLETED_INTENTS = Arrays.asList("completed", "canceled");

private final String basePath;
private final String logoPath;
private final String customCssPath;
private final String customJsPath;
private final String customTitle;

@Autowired private ProcessRepository processRepository;
@Autowired private ProcessInstanceRepository processInstanceRepository;
Expand All @@ -81,13 +85,21 @@ public class ViewController {
@Autowired private VariableRepository variableRepository;
@Autowired private ErrorRepository errorRepository;

public ViewController(@Value("${server.servlet.context-path}") final String basePath) {
public ViewController(@Value("${server.servlet.context-path}") final String basePath,
@Value("${white-label.logo.path}") final String logoPath,
@Value("${white-label.custom.title}") final String customTitle,
@Value("${white-label.custom.css.path}") final String customCssPath,
@Value("${white-label.custom.js.path}") final String customJsPath){
this.basePath = basePath.endsWith("/") ? basePath : basePath + "/";
this.logoPath = logoPath;
this.customTitle = customTitle;
this.customCssPath = customCssPath;
this.customJsPath = customJsPath;
}

@GetMapping("/")
public String index(final Map<String, Object> model, final Pageable pageable) {
addContextPathToModel(model);
addCommonVariablesToModel(model);
return processList(model, pageable);
}

Expand All @@ -105,7 +117,7 @@ public String processList(final Map<String, Object> model, final Pageable pageab
model.put("processes", processes);
model.put("count", count);

addContextPathToModel(model);
addCommonVariablesToModel(model);
addPaginationToModel(model, pageable, count);

return "process-list-view";
Expand Down Expand Up @@ -168,7 +180,7 @@ public String processDetail(
final var bpmn = Bpmn.readModelFromStream(resourceAsStream);
model.put("instance.bpmnElementInfos", getBpmnElementInfos(bpmn));

addContextPathToModel(model);
addCommonVariablesToModel(model);
addPaginationToModel(model, pageable, count);

return "process-detail-view";
Expand Down Expand Up @@ -244,7 +256,7 @@ public String instanceList(final Map<String, Object> model, final Pageable pagea
model.put("instances", instances);
model.put("count", count);

addContextPathToModel(model);
addCommonVariablesToModel(model);
addPaginationToModel(model, pageable, count);

return "instance-list-view";
Expand All @@ -266,7 +278,7 @@ public String instanceDetail(

model.put("instance", toInstanceDto(instance));

addContextPathToModel(model);
addCommonVariablesToModel(model);

return "instance-detail-view";
}
Expand Down Expand Up @@ -668,7 +680,7 @@ public String incidentList(final Map<String, Object> model, final Pageable pagea
model.put("incidents", incidents);
model.put("count", count);

addContextPathToModel(model);
addCommonVariablesToModel(model);
addPaginationToModel(model, pageable, count);

return "incident-list-view";
Expand Down Expand Up @@ -715,7 +727,7 @@ public String jobList(final Map<String, Object> model, final Pageable pageable)
model.put("jobs", dtos);
model.put("count", count);

addContextPathToModel(model);
addCommonVariablesToModel(model);
addPaginationToModel(model, pageable, count);

return "job-list-view";
Expand Down Expand Up @@ -750,7 +762,7 @@ public String messageList(final Map<String, Object> model, final Pageable pageab
model.put("messages", dtos);
model.put("count", count);

addContextPathToModel(model);
addCommonVariablesToModel(model);
addPaginationToModel(model, pageable, count);

return "message-list-view";
Expand All @@ -770,7 +782,7 @@ public String errorList(final Map<String, Object> model, final Pageable pageable
model.put("errors", dtos);
model.put("count", count);

addContextPathToModel(model);
addCommonVariablesToModel(model);
addPaginationToModel(model, pageable, count);

return "error-list-view";
Expand Down Expand Up @@ -846,10 +858,22 @@ private String getProcessResource(final ProcessEntity process) {
return resource.replaceAll("`", "\"");
}

private void addCommonVariablesToModel(final Map<String, Object> model) {
addContextPathToModel(model);
addWhitelabelingOptionsToModel(model);
}

private void addContextPathToModel(final Map<String, Object> model) {
model.put("context-path", basePath);
}

private void addWhitelabelingOptionsToModel(final Map<String, Object> model) {
model.put("logo-path", logoPath);
model.put("custom-css-path", customCssPath);
model.put("custom-js-path", customJsPath);
model.put("custom-title", customTitle);
}

private void addPaginationToModel(
final Map<String, Object> model, final Pageable pageable, final long count) {

Expand Down
6 changes: 6 additions & 0 deletions src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,9 @@ logging:
io.zeebe: INFO
io.zeebe.monitor: DEBUG
com.hazelcast: WARN

white-label:
logo.path: img/logo.png
custom.title: Zeebe Simple Monitor
custom.css.path: css/custom.css
custom.js.path: js/custom.js
2 changes: 2 additions & 0 deletions src/main/resources/public/css/custom.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/* empty by default */
/* when deployed via Docker or Helm, this file can be replaced with custom CSS */
2 changes: 2 additions & 0 deletions src/main/resources/public/js/custom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/* empty by default */
/* when deployed via Docker or Helm, this file can be replaced with custom JS */
1 change: 1 addition & 0 deletions src/main/resources/templates/layout/footer.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

<script type="text/javascript" src="{{context-path}}js/bpmn-navigated-viewer.production.min.js"></script>
<script src="{{context-path}}js/app.js"></script>
<script src="{{context-path}}{{custom-js-path}}"></script>

</body>
</html>
7 changes: 4 additions & 3 deletions src/main/resources/templates/layout/header.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta http-equiv=X-UA-Compatible content="IE=edge">
<meta name=viewport content="width=device-width,initial-scale=1">

<title> Zeebe Simple Monitor </title>
<title>{{custom-title}}</title>

<!-- bpmn-js viewer -->
<link type="text/css" rel="stylesheet" href="{{context-path}}css/modeler.css"/>
Expand All @@ -14,6 +14,7 @@
<link rel="stylesheet" type="text/css" href="{{context-path}}css/bootstrap.min.css"/>

<link rel="stylesheet" type="text/css" href="{{context-path}}css/app.css"/>
<link rel="stylesheet" type="text/css" href="{{context-path}}{{custom-css-path}}"/>

<link rel=icon href="{{context-path}}img/favicon.ico">

Expand All @@ -23,8 +24,8 @@

<nav class="navbar navbar-expand-md navbar-light bg-white mb-2 top-nav-border">
<a class="navbar-brand" href="{{context-path}}">
<img src="{{context-path}}img/logo.png" width="40" alt="Logo">
<span class="h3">Zeebe Simple Monitor</span>
<img src="{{context-path}}{{logo-path}}" height="36" alt="Logo">
<span id="header-title" class="h3">{{custom-title}}</span>
</a>

<div class="collapse navbar-collapse">
Expand Down
28 changes: 0 additions & 28 deletions src/test/java/io/zeebe/monitor/NoTestsYetTest.java

This file was deleted.

111 changes: 111 additions & 0 deletions src/test/java/io/zeebe/monitor/rest/ViewControllerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package io.zeebe.monitor.rest;

import io.zeebe.monitor.ZeebeSimpleMonitorApp;
import io.zeebe.monitor.repository.*;
import io.zeebe.monitor.zeebe.ZeebeHazelcastService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
@SpringBootTest(classes = ZeebeSimpleMonitorApp.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = {
"white-label.logo.path: img/test-logo.png",
"white-label.custom.title: Test Zeebe Simple Monitor",
"white-label.custom.css.path: css/test-custom.css",
"white-label.custom.js.path: js/test-custom.js",
})
public class ViewControllerTest {

@LocalServerPort
private int port;

@Autowired
private ViewController controller;

@Autowired
private TestRestTemplate restTemplate;

@MockBean
private HazelcastConfigRepository hazelcastConfigRepository;
@MockBean
private ZeebeHazelcastService zeebeHazelcastService;
@MockBean
private ProcessRepository processRepository;
@MockBean
private ProcessInstanceRepository processInstanceRepository;
@MockBean
private ElementInstanceRepository activityInstanceRepository;
@MockBean
private IncidentRepository incidentRepository;
@MockBean
private JobRepository jobRepository;
@MockBean
private MessageRepository messageRepository;
@MockBean
private MessageSubscriptionRepository messageSubscriptionRepository;
@MockBean
private TimerRepository timerRepository;
@MockBean
private VariableRepository variableRepository;
@MockBean
private ErrorRepository errorRepository;

@Before
public void setUp() throws Exception {
when(processRepository.findAll(any(Pageable.class))).thenReturn(Page.empty());
}

@Test
public void index_page_successfully_responded() {
ResponseEntity<String> entity = restTemplate.getForEntity("/", String.class);

assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}

@Test
public void index_page_contains_whitelabeling_title() {
ResponseEntity<String> entity = restTemplate.getForEntity("/", String.class);

assertThat(entity.getBody()).contains("Test Zeebe Simple Monitor");
}

@Test
public void index_page_contains_whitelabeling_logo() {
ResponseEntity<String> entity = restTemplate.getForEntity("/", String.class);

assertThat(entity.getBody()).contains("<img src=\"/img/test-logo.png\"");
}

@Test
public void index_page_contains_whitelabeling_js() {
ResponseEntity<String> entity = restTemplate.getForEntity("/", String.class);

assertThat(entity.getBody()).contains("<script src=\"/js/test-custom.js\"></script>");
}

@Test
public void index_page_contains_whitelabeling_css() {
ResponseEntity<String> entity = restTemplate.getForEntity("/", String.class);

assertThat(entity.getBody()).contains("<link rel=\"stylesheet\" type=\"text/css\" href=\"/css/test-custom.css\"/>");
}

}