Skip to content

Commit 9dbf156

Browse files
authored
Merge pull request #151 from amosproj/feature/95-create-subscription-information-popup
Feature/95 create subscription information popup
2 parents d948441 + 088208e commit 9dbf156

File tree

19 files changed

+860
-140
lines changed

19 files changed

+860
-140
lines changed

backend/src/main/java/de/amos/apachepulsarui/controller/TopicController.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,32 @@ public class TopicController {
3434
@GetMapping("/all")
3535
public ResponseEntity<TopicsDto> getAll(@RequestParam(required = false, defaultValue = "") List<String> tenants,
3636
@RequestParam(required = false, defaultValue = "") List<String> namespaces,
37-
@RequestParam(required = false, defaultValue = "") List<String> topics) {
37+
@RequestParam(required = false, defaultValue = "") List<String> topics,
38+
@RequestParam(required = false, defaultValue = "") String producer,
39+
@RequestParam(required = false, defaultValue = "") List<String> subscriptions) {
40+
41+
List<TopicDto> topicsToReturn;
42+
3843
if (!topics.isEmpty()) {
39-
return wrapInEntity(getAllForTopics(topics));
44+
topicsToReturn = getAllForTopics(topics);
4045
} else if (!namespaces.isEmpty()) {
41-
return wrapInEntity(getAllForNamespaces(namespaces));
46+
topicsToReturn = getAllForNamespaces(namespaces);
4247
} else {
43-
return wrapInEntity(getAllForTenants(tenants));
48+
topicsToReturn = getAllForTenants(tenants);
49+
}
50+
51+
if (!producer.isEmpty()) {
52+
topicsToReturn = topicService.getTopicForProducer(topicsToReturn, producer);
53+
}
54+
if (!subscriptions.isEmpty()) {
55+
topicsToReturn = topicService.getAllForSubscriptions(topicsToReturn, subscriptions);
4456
}
57+
return wrapInEntity(topicsToReturn);
4558
}
4659

4760
@GetMapping
4861
public ResponseEntity<TopicDetailDto> getTopicDetails(@RequestParam String name) {
49-
return new ResponseEntity<>(topicService.getTopicDetails(name), HttpStatus.OK);
62+
return new ResponseEntity<>(topicService.getTopicDetails(name), HttpStatus.OK);
5063
}
5164

5265
@GetMapping("/subscription/{subscription}")

backend/src/main/java/de/amos/apachepulsarui/service/TopicService.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
package de.amos.apachepulsarui.service;
88

99
import de.amos.apachepulsarui.dto.ConsumerDto;
10-
import de.amos.apachepulsarui.dto.MessageDto;
1110
import de.amos.apachepulsarui.dto.ProducerDto;
1211
import de.amos.apachepulsarui.dto.SchemaInfoDto;
1312
import de.amos.apachepulsarui.dto.SubscriptionDto;
@@ -187,4 +186,17 @@ private boolean exists(String topic) {
187186
);
188187
}
189188
}
189+
190+
public List<TopicDto> getTopicForProducer(List<TopicDto> topics, String producer) {
191+
return topics.stream()
192+
.filter(topicDto -> topicDto.getProducers().contains(producer))
193+
.toList();
194+
}
195+
196+
public List<TopicDto> getAllForSubscriptions(List<TopicDto> topics, List<String> subscriptions) {
197+
return topics.stream()
198+
.filter(topic -> topic.getSubscriptions().stream().anyMatch(subscriptions::contains))
199+
.toList();
200+
}
201+
190202
}

backend/src/test/java/de/amos/apachepulsarui/controller/TopicControllerTest.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.springframework.test.web.servlet.MockMvc;
2323

2424
import java.util.List;
25+
import java.util.Set;
2526

2627
import static org.hamcrest.Matchers.equalTo;
2728
import static org.mockito.Mockito.when;
@@ -81,6 +82,53 @@ void getAll_withoutParameters_returnsAllTopics() throws Exception {
8182
.andExpect(jsonPath("$.topics[1].tenant", equalTo(topics.get(1).getTenant())));
8283
}
8384

85+
@Test
86+
void getAll_withProducer_returnsSpecifiyTopic() throws Exception {
87+
88+
List<String> tenants = List.of("tenant1", "tenant2");
89+
List<String> namespaces = List.of("tenant1/namespace1", "tenant2/namespace1");
90+
91+
TopicDto topicDto = TopicDto.create("persistent://tenant1/namespace1/topic1", topicStats);
92+
topicDto.setProducers(List.of("Producer"));
93+
List<TopicDto> topics = List.of(topicDto);
94+
95+
when(tenantService.getAllNames()).thenReturn(tenants);
96+
when(namespaceService.getNamespaceNamesForTenants(tenants)).thenReturn(namespaces);
97+
when(topicService.getAllForNamespaces(namespaces)).thenReturn(topics);
98+
when(topicService.getTopicForProducer(topics, "Producer")).thenReturn(topics);
99+
100+
101+
mockMvc.perform(get("/topic/all?producer=Producer")
102+
.contentType(MediaType.APPLICATION_JSON))
103+
.andExpect(status().isOk())
104+
.andExpect(jsonPath("$.topics[0].name", equalTo(topics.get(0).getName())))
105+
.andExpect(jsonPath("$.topics[0].namespace", equalTo(topics.get(0).getNamespace())))
106+
.andExpect(jsonPath("$.topics[0].tenant", equalTo(topics.get(0).getTenant())));
107+
}
108+
109+
@Test
110+
void getAll_withSubscription_returnsSpecifiyTopic() throws Exception {
111+
112+
List<String> tenants = List.of("tenant1", "tenant2");
113+
List<String> namespaces = List.of("tenant1/namespace1", "tenant2/namespace1");
114+
115+
TopicDto topicDto = TopicDto.create("persistent://tenant1/namespace1/topic1", topicStats);
116+
topicDto.setSubscriptions(Set.of("Subscription"));
117+
List<TopicDto> topics = List.of(topicDto);
118+
119+
when(tenantService.getAllNames()).thenReturn(tenants);
120+
when(namespaceService.getNamespaceNamesForTenants(tenants)).thenReturn(namespaces);
121+
when(topicService.getAllForNamespaces(namespaces)).thenReturn(topics);
122+
when(topicService.getAllForSubscriptions(topics, List.of("Subscription"))).thenReturn(topics);
123+
124+
125+
mockMvc.perform(get("/topic/all?subscriptions=Subscription")
126+
.contentType(MediaType.APPLICATION_JSON))
127+
.andExpect(status().isOk())
128+
.andExpect(jsonPath("$.topics[0].name", equalTo(topics.get(0).getName())))
129+
.andExpect(jsonPath("$.topics[0].namespace", equalTo(topics.get(0).getNamespace())))
130+
.andExpect(jsonPath("$.topics[0].tenant", equalTo(topics.get(0).getTenant())));
131+
}
84132
@Test
85133
void getAll_withTenants_returnsAllTopicsForTenants() throws Exception {
86134

backend/src/test/java/de/amos/apachepulsarui/service/TopicServiceTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package de.amos.apachepulsarui.service;
88

99
import de.amos.apachepulsarui.dto.TopicDetailDto;
10+
import de.amos.apachepulsarui.dto.TopicDto;
1011
import org.apache.pulsar.client.admin.Lookup;
1112
import org.apache.pulsar.client.admin.PulsarAdmin;
1213
import org.apache.pulsar.client.admin.PulsarAdminException;
@@ -25,6 +26,7 @@
2526
import org.mockito.junit.jupiter.MockitoExtension;
2627

2728
import java.util.List;
29+
import java.util.Set;
2830

2931
import static org.junit.jupiter.api.Assertions.assertEquals;
3032
import static org.mockito.Mockito.*;
@@ -116,4 +118,27 @@ void getTopicDetails() throws PulsarAdminException {
116118
);
117119
}
118120

121+
122+
@Test
123+
void getTopicByProducer() {
124+
TopicDto topicDto = TopicDto.builder().build();
125+
topicDto.setProducers(List.of("wantedProducer"));
126+
TopicDto topicDto1 = TopicDto.builder().build();
127+
topicDto1.setProducers(List.of("unWantedProducer"));
128+
List<TopicDto> topics = List.of(topicDto, topicDto1);
129+
130+
assertEquals(topicService.getTopicForProducer(topics, "wantedProducer").size() , 1);
131+
}
132+
133+
@Test
134+
void getTopicBySubscription() {
135+
TopicDto topicDto = TopicDto.builder().build();
136+
topicDto.setSubscriptions(Set.of("wantedSubscription"));
137+
TopicDto topicDto1 = TopicDto.builder().build();
138+
topicDto1.setSubscriptions(Set.of("unWantedSubscription"));
139+
List<TopicDto> topics = List.of(topicDto, topicDto1);
140+
141+
assertEquals(topicService.getAllForSubscriptions(topics, List.of("wantedSubscription")).size() , 1);
142+
}
143+
119144
}

frontend/src/__tests__/TopicGroup.test.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ const dataTest: Array<TopicInfo> = [
1010
name: 'amos-topic-1',
1111
namespace: 'amos-namespace-2',
1212
tenant: 'amos-tenant-2',
13+
producers: ['test-producer'],
14+
subscriptions: ['test-subscription'],
1315
},
1416
]
1517

@@ -48,4 +50,10 @@ test('should check if data is being displayed in the TopicGroup', async () => {
4850
expect(screen.getByTestId('main-topicgroup')).toHaveTextContent(
4951
'Tenant: amos-tenant-2'
5052
)
53+
expect(screen.getByTestId('main-topicgroup')).toHaveTextContent(
54+
'Producers: test-producer'
55+
)
56+
expect(screen.getByTestId('main-topicgroup')).toHaveTextContent(
57+
'Subscriptions: test-subscription'
58+
)
5159
})

frontend/src/assets/styles/dashboard.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@
3232
}
3333

3434
.secondary-dashboard {
35+
flex: 0 0 25%;
36+
max-width: 25%;
37+
padding-right: 38px;
38+
display: flex;
39+
flex-direction: column;
40+
3541
.MuiCollapse-wrapper.MuiCollapse-vertical .MuiAccordionDetails-root {
3642
padding: 0px;
3743
padding-bottom: 4px;

frontend/src/assets/styles/form.scss

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
padding: 0px;
3131
}
3232

33-
.custom-checkbox-wrapper {
33+
.custom-checkbox-wrapper, .custom-radio-wrapper {
3434
gap: 16px;
3535
align-items: center;
3636
margin-bottom: 16px;
@@ -42,6 +42,10 @@
4242
width: 16px;
4343
height: 16px;
4444
cursor: pointer;
45+
46+
&.custom-radio {
47+
border-radius: 100%;
48+
}
4549

4650
&.active {
4751
background-color: $primary-blue;
@@ -50,6 +54,9 @@
5054
}
5155

5256
p {
57+
max-width: 225px;
58+
word-break: break-all;
59+
white-space: normal;
5360
font-weight: 400;
5461
font-size: $font-small;
5562
line-height: 19px;

frontend/src/components/Dashboard.tsx

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,12 @@ import { useAppDispatch } from '../store/hooks'
1010
import { useNavigate } from 'react-router-dom'
1111

1212
import {
13-
addFilter,
1413
fetchOptionsThunk,
1514
resetAllFilters,
15+
updateFilterAccordingToNav,
16+
HierarchyInPulsar,
1617
} from '../store/filterSlice'
1718
import { triggerRequest } from './pages/requestTriggerSlice'
18-
// import {
19-
// setCluster,
20-
// setTenant,
21-
// setNamespace,
22-
// setTopic,
23-
// addFilter,
24-
// deleteFilter,
25-
// } from '../store/filterSlice'
2619

2720
const Dashboard: React.FC<DashboardProps> = ({
2821
completeMessages,
@@ -45,6 +38,7 @@ const Dashboard: React.FC<DashboardProps> = ({
4538
if (location.pathname === '/') navigate('/cluster')
4639
// fetch all filter options once beforehand
4740
dispatch(fetchOptionsThunk())
41+
dispatch(updateFilterAccordingToNav(location.pathname as HierarchyInPulsar))
4842
}, [])
4943

5044
/*

frontend/src/components/NavBar.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ function NavBar() {
126126
disabled={page.toLowerCase() == location.pathname.slice(1)}
127127
onClick={() => {
128128
handleClickOnNav(page)
129+
updateFilterAccordingToNav(
130+
page.toLowerCase() as HierarchyInPulsar
131+
)
129132
}}
130133
>
131134
<Typography textAlign="center">{page}</Typography>

0 commit comments

Comments
 (0)