From d42c69f9869ef973102cb62f1b28df17947eefd3 Mon Sep 17 00:00:00 2001 From: khatibtamal Date: Mon, 9 Sep 2024 13:25:37 +0600 Subject: [PATCH 1/9] Feature: Add front end for topic events view based on offset range Signed-off-by: khatibtamal --- .../klaw/controller/TopicController.java | 8 +- .../aiven/klaw/error/KlawErrorMessages.java | 4 + .../klaw/model/enums/TopicContentType.java | 15 +++ .../aiven/klaw/service/ClusterApiService.java | 6 +- .../klaw/service/TopicControllerService.java | 29 ++++-- .../main/resources/static/js/browseAcls.js | 49 +++++++++- .../main/resources/templates/browseAcls.html | 23 +++-- .../klaw/controller/TopicControllerTest.java | 34 +++++++ .../service/TopicControllerServiceTest.java | 95 ++++++++++++++++--- 9 files changed, 230 insertions(+), 33 deletions(-) create mode 100644 core/src/main/java/io/aiven/klaw/model/enums/TopicContentType.java diff --git a/core/src/main/java/io/aiven/klaw/controller/TopicController.java b/core/src/main/java/io/aiven/klaw/controller/TopicController.java index 677cd08f41..a79efe150f 100644 --- a/core/src/main/java/io/aiven/klaw/controller/TopicController.java +++ b/core/src/main/java/io/aiven/klaw/controller/TopicController.java @@ -321,7 +321,9 @@ public ResponseEntity> getTopicEvents( @RequestParam(value = "consumerGroupId") String consumerGroupId, @RequestParam(value = "offsetId") String offsetId, @Valid @RequestParam(value = "selectedPartitionId") Integer selectedPartitionId, - @Valid @RequestParam(value = "selectedNumberOfOffsets") Integer selectedNumberOfOffsets) + @Valid @RequestParam(value = "selectedNumberOfOffsets") Integer selectedNumberOfOffsets, + @Valid @RequestParam(value = "selectedOffsetRangeStart") Integer selectedOffsetRangeStart, + @Valid @RequestParam(value = "selectedOffsetRangeEnd") Integer selectedOffsetRangeEnd) throws KlawException { return new ResponseEntity<>( topicControllerService.getTopicEvents( @@ -330,7 +332,9 @@ public ResponseEntity> getTopicEvents( topicName, offsetId, selectedPartitionId, - selectedNumberOfOffsets), + selectedNumberOfOffsets, + selectedOffsetRangeStart, + selectedOffsetRangeEnd), HttpStatus.OK); } diff --git a/core/src/main/java/io/aiven/klaw/error/KlawErrorMessages.java b/core/src/main/java/io/aiven/klaw/error/KlawErrorMessages.java index 859631d429..4d2346855a 100644 --- a/core/src/main/java/io/aiven/klaw/error/KlawErrorMessages.java +++ b/core/src/main/java/io/aiven/klaw/error/KlawErrorMessages.java @@ -342,6 +342,10 @@ public class KlawErrorMessages { public static final String TOPICS_ERR_116 = "Please check if permission " + APPROVE_TOPICS_CREATE + " is assigned to you."; + public static final String TOPICS_ERR_117 = + "PartitionId cannot be empty or less than zero. Offset range start or end cannot be less than " + + "zero and end cannot be larger than start."; + // Topic Validation public static final String TOPICS_VLD_ERR_101 = "Failure. Invalid Topic request type. Possible Value : Create/Promote"; diff --git a/core/src/main/java/io/aiven/klaw/model/enums/TopicContentType.java b/core/src/main/java/io/aiven/klaw/model/enums/TopicContentType.java new file mode 100644 index 0000000000..8cd57345a2 --- /dev/null +++ b/core/src/main/java/io/aiven/klaw/model/enums/TopicContentType.java @@ -0,0 +1,15 @@ +package io.aiven.klaw.model.enums; + +import lombok.Getter; + +@Getter +public enum TopicContentType { + CUSTOM("custom"), + RANGE("range"); + + private final String value; + + TopicContentType(String value) { + this.value = value; + } +} diff --git a/core/src/main/java/io/aiven/klaw/service/ClusterApiService.java b/core/src/main/java/io/aiven/klaw/service/ClusterApiService.java index aff6c73229..b43c717b6e 100644 --- a/core/src/main/java/io/aiven/klaw/service/ClusterApiService.java +++ b/core/src/main/java/io/aiven/klaw/service/ClusterApiService.java @@ -258,6 +258,8 @@ public Map getTopicEvents( String offsetId, Integer selectedPartitionId, Integer selectedNumberOfOffsets, + Integer selectedOffsetRangeStart, + Integer selectedOffsetRangeEnd, String consumerGroupId, int tenantId) throws KlawException { @@ -282,8 +284,8 @@ public Map getTopicEvents( String.valueOf(selectedNumberOfOffsets), clusterIdentification, RANGE_OFFSETS, - String.valueOf(-1), - String.valueOf(-1)); + String.valueOf(selectedOffsetRangeStart), + String.valueOf(selectedOffsetRangeEnd)); ResponseEntity> resultBody = getRestTemplate(null) diff --git a/core/src/main/java/io/aiven/klaw/service/TopicControllerService.java b/core/src/main/java/io/aiven/klaw/service/TopicControllerService.java index 8588643940..eaaa01550f 100644 --- a/core/src/main/java/io/aiven/klaw/service/TopicControllerService.java +++ b/core/src/main/java/io/aiven/klaw/service/TopicControllerService.java @@ -16,6 +16,7 @@ import static io.aiven.klaw.error.KlawErrorMessages.TOPICS_ERR_114; import static io.aiven.klaw.error.KlawErrorMessages.TOPICS_ERR_115; import static io.aiven.klaw.error.KlawErrorMessages.TOPICS_ERR_116; +import static io.aiven.klaw.error.KlawErrorMessages.TOPICS_ERR_117; import static io.aiven.klaw.error.KlawErrorMessages.TOPICS_VLD_ERR_121; import static io.aiven.klaw.error.KlawErrorMessages.TOPICS_VLD_ERR_125; import static io.aiven.klaw.error.KlawErrorMessages.TOPICS_VLD_ERR_126; @@ -89,7 +90,6 @@ public class TopicControllerService { public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - public static final String CUSTOM_OFFSET_SELECTION = "custom"; @Autowired private final ClusterApiService clusterApiService; @Autowired ManageDatabase manageDatabase; @@ -1322,7 +1322,9 @@ public Map getTopicEvents( String topicName, String offsetId, Integer selectedPartitionId, - Integer selectedNumberOfOffsets) { + Integer selectedNumberOfOffsets, + Integer selectedOffsetRangeStart, + Integer selectedOffsetRangeEnd) { Map topicEvents = new TreeMap<>(); int tenantId = commonUtilsService.getTenantId(getUserName()); try { @@ -1330,13 +1332,24 @@ public Map getTopicEvents( manageDatabase .getClusters(KafkaClustersType.KAFKA, tenantId) .get(getEnvDetails(envId).getClusterId()); - if (offsetId != null && offsetId.equals(CUSTOM_OFFSET_SELECTION)) { - if (selectedPartitionId == null - || selectedNumberOfOffsets == null - || selectedPartitionId < 0 - || selectedNumberOfOffsets <= 0) { + if (offsetId != null) { + if (offsetId.equals(TopicContentType.CUSTOM.getValue()) + && (selectedPartitionId == null + || selectedNumberOfOffsets == null + || selectedPartitionId < 0 + || selectedNumberOfOffsets <= 0)) { throw new KlawException(TOPICS_ERR_115); } + if (offsetId.equals(TopicContentType.RANGE.getValue()) + && (selectedPartitionId == null + || selectedPartitionId < 0 + || selectedOffsetRangeStart == null + || selectedOffsetRangeEnd == null + || selectedOffsetRangeStart < 0 + || selectedOffsetRangeEnd < 0 + || selectedOffsetRangeEnd < selectedOffsetRangeStart)) { + throw new KlawException(TOPICS_ERR_117); + } } topicEvents = clusterApiService.getTopicEvents( @@ -1347,6 +1360,8 @@ public Map getTopicEvents( offsetId, selectedPartitionId, selectedNumberOfOffsets, + selectedOffsetRangeStart, + selectedOffsetRangeEnd, consumerGroupId, tenantId); } catch (Exception e) { diff --git a/core/src/main/resources/static/js/browseAcls.js b/core/src/main/resources/static/js/browseAcls.js index 599e9b5c5b..021e1a22ac 100644 --- a/core/src/main/resources/static/js/browseAcls.js +++ b/core/src/main/resources/static/js/browseAcls.js @@ -910,9 +910,54 @@ app.controller("browseAclsCtrl", function($scope, $http, $location, $window) { $scope.showAlertToast(); return; } - }else{ + + $scope.selectedOffsetRangeStart = 0; + $scope.selectedOffsetRangeEnd = 0; + + }else if($scope.topicOffsetsVal === 'range'){ + if($scope.selectedPartitionId === ""){ + $scope.alert = "Please fill in a partition id."; + $scope.showAlertToast(); + return; + } + + if($scope.selectedPartitionId < 0 || isNaN($scope.selectedPartitionId)) + { + $scope.alert = "Please fill in a valid partition id."; + $scope.showAlertToast(); + return; + } + + if(!$scope.selectedOffsetRangeStart || $scope.selectedOffsetRangeStart === "" || + !$scope.selectedOffsetRangeEnd || $scope.selectedOffsetRangeEnd === "" + ){ + $scope.alert = "Please fill how many offsets range start and end."; + $scope.showAlertToast(); + return; + } + + if($scope.selectedOffsetRangeStart <= 0 || isNaN($scope.selectedOffsetRangeStart) || + $scope.selectedOffsetRangeEnd <= 0 || isNaN($scope.selectedOffsetRangeEnd)) + { + $scope.alert = "Please fill in a valid number topic offsets start and end."; + $scope.showAlertToast(); + return; + } + + if($scope.selectedOffsetRangeEnd < $scope.selectedOffsetRangeStart) + { + $scope.alert = "Offset range end cannot be less than offset range start."; + $scope.showAlertToast(); + return; + } + + $scope.selectedNumberOfOffsets = 0; + } + else{ $scope.selectedPartitionId = 0; $scope.selectedNumberOfOffsets = 0; + $scope.selectedOffsetRangeStart = 0; + $scope.selectedOffsetRangeEnd = 0; } $scope.ShowSpinnerStatus = true; @@ -925,6 +970,8 @@ app.controller("browseAclsCtrl", function($scope, $http, $location, $window) { 'offsetId' : $scope.topicOffsetsVal, 'selectedPartitionId' : $scope.selectedPartitionId, 'selectedNumberOfOffsets' : $scope.selectedNumberOfOffsets, + 'selectedOffsetRangeStart' : $scope.selectedOffsetRangeStart, + 'selectedOffsetRangeEnd' : $scope.selectedOffsetRangeEnd, 'envId' : $scope.topicOverview[0].envId, 'consumerGroupId': "notdefined" } diff --git a/core/src/main/resources/templates/browseAcls.html b/core/src/main/resources/templates/browseAcls.html index 0a7bf453c0..823583c7f4 100644 --- a/core/src/main/resources/templates/browseAcls.html +++ b/core/src/main/resources/templates/browseAcls.html @@ -1015,22 +1015,23 @@
Team
{{ aclRequest.teamname }}
- +
- +
-
+
@@ -1038,6 +1039,14 @@
Team
{{ aclRequest.teamname }}
+
+ + +
+
+ + +
diff --git a/core/src/test/java/io/aiven/klaw/controller/TopicControllerTest.java b/core/src/test/java/io/aiven/klaw/controller/TopicControllerTest.java index c148e239c9..bed3a6f137 100644 --- a/core/src/test/java/io/aiven/klaw/controller/TopicControllerTest.java +++ b/core/src/test/java/io/aiven/klaw/controller/TopicControllerTest.java @@ -27,6 +27,7 @@ import io.aiven.klaw.service.TopicControllerService; import io.aiven.klaw.service.TopicSyncControllerService; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; import org.junit.jupiter.api.BeforeEach; @@ -41,6 +42,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.validation.Validator; @@ -315,4 +317,36 @@ public void updateTopic() throws Exception { .andExpect(status().isOk()) .andExpect(jsonPath("$.message", is(ApiResultStatus.SUCCESS.value))); } + + @Test + @Order(13) + public void getTopicEvents() throws Exception { + when(topicControllerService.getTopicEvents( + anyString(), + anyString(), + anyString(), + anyString(), + anyInt(), + anyInt(), + anyInt(), + anyInt())) + .thenReturn(Collections.emptyMap()); + + MvcResult mvcResult = + mvc.perform( + MockMvcRequestBuilders.get("/getTopicEvents") + .param("envId", "1") + .param("topicName", "test") + .param("consumerGroupId", "1") + .param("offsetId", "0") + .param("selectedPartitionId", "0") + .param("selectedNumberOfOffsets", "0") + .param("selectedOffsetRangeStart", "0") + .param("selectedOffsetRangeEnd", "0") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + assertThat(mvcResult.getResponse().getContentAsString()).isEqualTo("{}"); + } } diff --git a/core/src/test/java/io/aiven/klaw/service/TopicControllerServiceTest.java b/core/src/test/java/io/aiven/klaw/service/TopicControllerServiceTest.java index 2fa7c6db11..fcab321d9e 100644 --- a/core/src/test/java/io/aiven/klaw/service/TopicControllerServiceTest.java +++ b/core/src/test/java/io/aiven/klaw/service/TopicControllerServiceTest.java @@ -41,19 +41,17 @@ import io.aiven.klaw.model.response.TopicTeamResponse; import java.sql.SQLDataException; import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; +import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; @@ -1098,12 +1096,15 @@ public void getTopicEvents() throws KlawException { anyString(), anyInt(), anyInt(), + anyInt(), + anyInt(), anyString(), anyInt())) .thenReturn(eventsMap); Map topicEventsMap = - topicControllerService.getTopicEvents(envId, consumerGroupId, topicName, offsetId, 0, 0); + topicControllerService.getTopicEvents( + envId, consumerGroupId, topicName, offsetId, 0, 0, 0, 0); assertThat(topicEventsMap).hasSize(2); } @@ -1554,12 +1555,15 @@ public void getTopicEventsForCustomOffset() throws KlawException { anyString(), anyInt(), anyInt(), + anyInt(), + anyInt(), anyString(), anyInt())) .thenReturn(eventsMap); Map topicEventsMap = - topicControllerService.getTopicEvents(envId, consumerGroupId, topicName, offsetId, 0, 3); + topicControllerService.getTopicEvents( + envId, consumerGroupId, topicName, offsetId, 0, 3, 0, 0); assertThat(topicEventsMap).hasSize(3); } @@ -1589,17 +1593,80 @@ public void getTopicEventsForCustomOffsetFailureForZeroOffsets() throws KlawExce anyString(), anyInt(), anyInt(), + anyInt(), + anyInt(), anyString(), anyInt())) .thenReturn(eventsMap); Map topicEventsMap = - topicControllerService.getTopicEvents(envId, consumerGroupId, topicName, offsetId, 0, 0); + topicControllerService.getTopicEvents( + envId, consumerGroupId, topicName, offsetId, 0, 0, 0, 0); assertThat(topicEventsMap.get("status")).isEqualTo("false"); } - @Test + @ParameterizedTest + @MethodSource("getTopicEventsForCustomRange") @Order(59) + public void getTopicEventsForCustomRange( + Integer partitionId, Integer start, Integer end, boolean success) throws KlawException { + String envId = "1", + consumerGroupId = "consuemrgroup", + topicName = "testtopic", + offsetId = "range"; + stubUserInfo(); + when(commonUtilsService.getTenantId(anyString())).thenReturn(101); + + Map kwClustersMap = new HashMap<>(); + kwClustersMap.put(1, utilMethods.getKwClusters()); + when(manageDatabase.getClusters(any(), anyInt())).thenReturn(kwClustersMap); + when(manageDatabase.getKafkaEnvList(anyInt())).thenReturn(utilMethods.getEnvLists()); + Map eventsMap = new HashMap<>(); + eventsMap.put("1", "hello world1"); + when(clusterApiService.getTopicEvents( + anyString(), + any(), + anyString(), + anyString(), + anyString(), + anyInt(), + anyInt(), + anyInt(), + anyInt(), + anyString(), + anyInt())) + .thenReturn(eventsMap); + + Map topicEventsMap = + topicControllerService.getTopicEvents( + envId, consumerGroupId, topicName, offsetId, partitionId, -1, start, end); + + assertThat(topicEventsMap.size()).isEqualTo(1); + if (success) { + assertThat(topicEventsMap.get("1")).isEqualTo("hello world1"); + } else { + assertThat(topicEventsMap.get("status")).isEqualTo("false"); + } + } + + private static Stream getTopicEventsForCustomRange() { + return Stream.of( + Arguments.of(0, 1, 3, true), // standard + Arguments.of(0, 1, 1, true), // start and end equal + Arguments.of(0, 2, 1, false), // end greater than start + Arguments.of(0, 0, 1, true), // start is 0 + Arguments.of(0, 0, 0, true), // end is o + Arguments.of(0, -1, 1, false), // start is negative + Arguments.of(0, -2, -1, false), // end is negative + Arguments.of(0, null, 3, false), // start is null + Arguments.of(0, 1, null, false), // end is null + Arguments.of(-1, 1, 3, false), // partition ID less than 0 + Arguments.of(null, 1, 3, false) // partition null + ); + } + + @Test + @Order(60) public void getTopicsWithProducerFilterAndEnv() throws KlawNotAuthorizedException { String envSel = "1", pageNo = "1"; @@ -1629,7 +1696,7 @@ public void getTopicsWithProducerFilterAndEnv() throws KlawNotAuthorizedExceptio } @Test - @Order(60) + @Order(61) public void getTopicsWithConsumerFilterNoResults() throws KlawNotAuthorizedException { String envSel = "1", pageNo = "1", topicNameSearch = "top"; @@ -1659,7 +1726,7 @@ public void getTopicsWithConsumerFilterNoResults() throws KlawNotAuthorizedExcep } @Test - @Order(61) + @Order(62) public void getTopicsWithPatternFilterOneResult() throws KlawNotAuthorizedException { String envSel = "1", pageNo = "1", topicNameSearch = "2"; @@ -1694,7 +1761,7 @@ public void getTopicsWithPatternFilterOneResult() throws KlawNotAuthorizedExcept } @Test - @Order(59) + @Order(63) public void approvePromoteTopicRequests() throws KlawException { int topicId = 1001; TopicRequest topicRequest = getTopicRequest(TOPIC_1); From 57445451b146b716b994589fd8c9914406b6d6f5 Mon Sep 17 00:00:00 2001 From: khatibtamal Date: Mon, 9 Sep 2024 13:48:08 +0600 Subject: [PATCH 2/9] minor code quality changes Signed-off-by: khatibtamal --- core/src/main/resources/static/js/browseAcls.js | 3 +-- core/src/main/resources/templates/browseAcls.html | 2 +- .../aiven/klaw/service/TopicControllerServiceTest.java | 9 ++++++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/core/src/main/resources/static/js/browseAcls.js b/core/src/main/resources/static/js/browseAcls.js index 021e1a22ac..b8ae343a35 100644 --- a/core/src/main/resources/static/js/browseAcls.js +++ b/core/src/main/resources/static/js/browseAcls.js @@ -952,8 +952,7 @@ app.controller("browseAclsCtrl", function($scope, $http, $location, $window) { } $scope.selectedNumberOfOffsets = 0; - } - else{ + }else{ $scope.selectedPartitionId = 0; $scope.selectedNumberOfOffsets = 0; $scope.selectedOffsetRangeStart = 0; diff --git a/core/src/main/resources/templates/browseAcls.html b/core/src/main/resources/templates/browseAcls.html index 823583c7f4..1617f7a722 100644 --- a/core/src/main/resources/templates/browseAcls.html +++ b/core/src/main/resources/templates/browseAcls.html @@ -1015,7 +1015,7 @@
Team
{{ aclRequest.teamname }}
- +
diff --git a/core/src/test/java/io/aiven/klaw/service/TopicControllerServiceTest.java b/core/src/test/java/io/aiven/klaw/service/TopicControllerServiceTest.java index fcab321d9e..5aa6e4be96 100644 --- a/core/src/test/java/io/aiven/klaw/service/TopicControllerServiceTest.java +++ b/core/src/test/java/io/aiven/klaw/service/TopicControllerServiceTest.java @@ -41,8 +41,15 @@ import io.aiven.klaw.model.response.TopicTeamResponse; import java.sql.SQLDataException; import java.sql.Timestamp; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Stream; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; From 66206747a5e4976374e6e4e3185d5eeedc24febe Mon Sep 17 00:00:00 2001 From: khatibtamal Date: Mon, 9 Sep 2024 13:52:50 +0600 Subject: [PATCH 3/9] ran mvn spotless apply Signed-off-by: khatibtamal --- .../java/io/aiven/klaw/service/TopicControllerServiceTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/test/java/io/aiven/klaw/service/TopicControllerServiceTest.java b/core/src/test/java/io/aiven/klaw/service/TopicControllerServiceTest.java index 5aa6e4be96..6e202b2dd0 100644 --- a/core/src/test/java/io/aiven/klaw/service/TopicControllerServiceTest.java +++ b/core/src/test/java/io/aiven/klaw/service/TopicControllerServiceTest.java @@ -49,7 +49,6 @@ import java.util.Map; import java.util.Set; import java.util.stream.Stream; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; From 1978904eda23dacc9c497fa42e71756d40abca51 Mon Sep 17 00:00:00 2001 From: khatibtamal Date: Mon, 9 Sep 2024 14:13:19 +0600 Subject: [PATCH 4/9] minor html change Signed-off-by: khatibtamal --- core/src/main/resources/templates/browseAcls.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/resources/templates/browseAcls.html b/core/src/main/resources/templates/browseAcls.html index 1617f7a722..bbba9e0a54 100644 --- a/core/src/main/resources/templates/browseAcls.html +++ b/core/src/main/resources/templates/browseAcls.html @@ -1040,11 +1040,11 @@
Team
{{ aclRequest.teamname }}
- +
- +
From 7327c3c46c821d3a5999bf11813582abf463c1e6 Mon Sep 17 00:00:00 2001 From: khatibtamal Date: Thu, 19 Sep 2024 17:14:24 +0600 Subject: [PATCH 5/9] coral changes with tests Signed-off-by: khatibtamal --- .../filters/useFiltersContext.test.tsx | 33 +++ .../components/filters/useFiltersContext.tsx | 10 +- .../details/messages/TopicMessages.test.tsx | 163 ++++++++--- .../topics/details/messages/TopicMessages.tsx | 104 ++++--- .../components/TopicMessageFilters.test.tsx | 167 +++++++++++- .../components/TopicMessageFilters.tsx | 117 +++++--- .../messages/useMessagesFilters.test.tsx | 257 +++++++++++++++++- .../details/messages/useMessagesFilters.tsx | 202 +++++++++++--- .../pages/topics/details/messages/index.tsx | 2 +- coral/src/domain/topic/topic-types.ts | 12 +- coral/types/api.d.ts | 2 + openapi.yaml | 16 ++ 12 files changed, 921 insertions(+), 164 deletions(-) diff --git a/coral/src/app/features/components/filters/useFiltersContext.test.tsx b/coral/src/app/features/components/filters/useFiltersContext.test.tsx index 605f540b33..61f884453b 100644 --- a/coral/src/app/features/components/filters/useFiltersContext.test.tsx +++ b/coral/src/app/features/components/filters/useFiltersContext.test.tsx @@ -39,6 +39,20 @@ describe("useFiltersValues.tsx", () => { expect(current.aclType).toBe("PRODUCER"); }); + it("gets the correct defaultOffset filter value", () => { + const { + result: { current }, + } = renderHook(() => useFiltersContext(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + expect(current.defaultOffset).toBe("custom"); + }); + it("gets the correct status filter value", () => { const { result: { current }, @@ -302,6 +316,25 @@ describe("useFiltersValues.tsx", () => { expect(window.location.search).toBe("?aclType=PRODUCER&page=1"); }); + it("sets the correct defaultOffset filter value", () => { + const { + result: { current }, + } = renderHook(() => useFiltersContext(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + current.setFilterValue({ + name: "defaultOffset", + value: "custom", + }); + + expect(window.location.search).toBe("?defaultOffset=custom&page=1"); + }); + it("sets the correct status filter value", () => { const { result: { current }, diff --git a/coral/src/app/features/components/filters/useFiltersContext.tsx b/coral/src/app/features/components/filters/useFiltersContext.tsx index 42c483a832..696f75eaf3 100644 --- a/coral/src/app/features/components/filters/useFiltersContext.tsx +++ b/coral/src/app/features/components/filters/useFiltersContext.tsx @@ -4,6 +4,7 @@ import { AclType } from "src/domain/acl/acl-types"; import { ClusterType } from "src/domain/cluster"; import { RequestOperationType, RequestStatus } from "src/domain/requests"; import { TopicType } from "src/domain/topic"; +import { TopicMessagesFetchModeTypes } from "src/domain/topic/topic-types"; type SetFiltersParams = | { name: "environment"; value: string } @@ -15,7 +16,8 @@ type SetFiltersParams = | { name: "search"; value: string } | { name: "teamName"; value: string } | { name: "topicType"; value: TopicType | "ALL" } - | { name: "clusterType"; value: ClusterType }; + | { name: "clusterType"; value: ClusterType } + | { name: "defaultOffset"; value: TopicMessagesFetchModeTypes }; interface UseFiltersDefaultValues { environment: string; @@ -29,6 +31,7 @@ interface UseFiltersDefaultValues { teamName: string; topicType: TopicType | "ALL"; clusterType: ClusterType; + defaultOffset: TopicMessagesFetchModeTypes; } interface UseFiltersReturnedValues @@ -48,6 +51,7 @@ const emptyValues: UseFiltersDefaultValues = { paginated: true, topicType: "ALL", clusterType: "ALL", + defaultOffset: "default", }; const FiltersContext = createContext({ @@ -87,6 +91,9 @@ const FiltersProvider = ({ const clusterType = (searchParams.get("clusterType") as ClusterType) ?? initialValues.clusterType; + const defaultOffset = + (searchParams.get("defaultOffset") as TopicMessagesFetchModeTypes) ?? + initialValues.defaultOffset; const setFilterValue = ({ name, value }: SetFiltersParams) => { const parsedValue = typeof value === "boolean" ? String(value) : value; @@ -114,6 +121,7 @@ const FiltersProvider = ({ search, topicType, clusterType, + defaultOffset, setFilterValue, }; diff --git a/coral/src/app/features/topics/details/messages/TopicMessages.test.tsx b/coral/src/app/features/topics/details/messages/TopicMessages.test.tsx index bd1ab0950b..9fd21db033 100644 --- a/coral/src/app/features/topics/details/messages/TopicMessages.test.tsx +++ b/coral/src/app/features/topics/details/messages/TopicMessages.test.tsx @@ -1,10 +1,11 @@ import { cleanup, screen, waitFor } from "@testing-library/react"; +import { userEvent } from "@testing-library/user-event"; +import { Outlet, Route, Routes } from "react-router-dom"; +import { withFiltersContext } from "src/app/features/components/filters/useFiltersContext"; +import TopicMessages from "src/app/features/topics/details/messages/TopicMessages"; import { getTopicMessages } from "src/domain/topic/topic-api"; import { mockIntersectionObserver } from "src/services/test-utils/mock-intersection-observer"; -import { TopicMessages } from "src/app/features/topics/details/messages/TopicMessages"; import { customRender } from "src/services/test-utils/render-with-wrappers"; -import { Outlet, Route, Routes } from "react-router-dom"; -import { userEvent } from "@testing-library/user-event"; jest.mock("src/domain/topic/topic-api.ts"); @@ -21,6 +22,12 @@ const mockGetTopicMessagesNoContentResponse = { status: "failed", }; +const selectModeOptions = ["Default", "Custom", "Range"]; +const WrappedTopicMessages = withFiltersContext({ + defaultValues: { paginated: false }, + element: , +}); + function DummyParent() { return ; } @@ -33,14 +40,14 @@ describe("TopicMessages", () => { cleanup(); jest.resetAllMocks(); }); - it("allows to switch between Default and Custom modes", async () => { + it("allows to select between Default, Custom and Range modes", async () => { mockGetTopicMessages.mockResolvedValue( mockGetTopicMessagesNoContentResponse ); customRender( }> - } /> + } /> , { @@ -49,33 +56,28 @@ describe("TopicMessages", () => { } ); - const switchInput = screen.getByRole("checkbox"); - - const switchGroupDefault = screen.getByRole("group", { - name: "Fetching mode Select message offset", + const select = screen.getByRole("combobox", { + name: "Select mode Choose mode to fetch messages", }); - expect(switchGroupDefault).toBeVisible(); - expect(switchInput).not.toBeChecked(); - - await userEvent.click(switchInput); + expect(select).toBeEnabled(); - const switchGroupCustom = screen.getByRole("group", { - name: "Fetching mode Specify message offset", + selectModeOptions.forEach((selectMode) => { + const option = screen.getByRole("option", { + name: selectMode, + }); + expect(option).toBeEnabled(); }); - - expect(switchGroupCustom).toBeVisible(); - expect(switchInput).toBeChecked(); }); - it("shows switch as Default mode according to URL search params", async () => { + it("shows selection as Default mode according to URL search params", async () => { mockGetTopicMessages.mockResolvedValue( mockGetTopicMessagesNoContentResponse ); customRender( }> - } /> + } /> , { @@ -85,24 +87,19 @@ describe("TopicMessages", () => { } ); - const switchInput = screen.getByRole("checkbox"); - - const switchGroupDefault = screen.getByRole("group", { - name: "Fetching mode Select message offset", - }); + const select = screen.getByRole("combobox"); - expect(switchGroupDefault).toBeVisible(); - expect(switchInput).not.toBeChecked(); + expect(select).toHaveValue("default"); }); - it("shows switch as Custom mode according to URL search params", async () => { + it("shows selection as Custom mode according to URL search params", async () => { mockGetTopicMessages.mockResolvedValue( mockGetTopicMessagesNoContentResponse ); customRender( }> - } /> + } /> , { @@ -112,14 +109,17 @@ describe("TopicMessages", () => { } ); - const switchInput = screen.getByRole("checkbox"); - - const switchGroupCustom = screen.getByRole("group", { - name: "Fetching mode Specify message offset", - }); - - expect(switchGroupCustom).toBeVisible(); - expect(switchInput).toBeChecked(); + expect(screen.getByRole("combobox")).toHaveValue("custom"); + expect( + screen.getByRole("spinbutton", { + name: "Partition ID * Enter partition ID to retrieve last messages", + }) + ).toBeVisible(); + expect( + screen.getByRole("spinbutton", { + name: "Number of messages * Set the number of recent messages to display from this partition", + }) + ).toBeVisible(); }); it("informs user to specify offset and fetch topic messages", async () => { @@ -129,7 +129,7 @@ describe("TopicMessages", () => { customRender( }> - } /> + } /> , { @@ -141,12 +141,48 @@ describe("TopicMessages", () => { "To view messages in this topic, select the number of messages you'd like to view and select Fetch messages." ); }); + + it("shows selection as Range mode according to URL search params", async () => { + mockGetTopicMessages.mockResolvedValue( + mockGetTopicMessagesNoContentResponse + ); + customRender( + + }> + } /> + + , + { + memoryRouter: true, + queryClient: true, + customRoutePath: "/?defaultOffset=range", + } + ); + + expect(screen.getByRole("combobox")).toHaveValue("range"); + expect( + screen.getByRole("spinbutton", { + name: "Partition ID * Enter partition ID to retrieve last messages", + }) + ).toBeVisible(); + expect( + screen.getByRole("spinbutton", { + name: "Start Offset * Set the start offset", + }) + ).toBeVisible(); + expect( + screen.getByRole("spinbutton", { + name: "End Offset * Set the end offset", + }) + ).toBeVisible(); + }); + it("requests and displays all messages when Update results is pressed", async () => { mockGetTopicMessages.mockResolvedValue(mockGetTopicMessagesResponse); customRender( }> - } /> + } /> , { @@ -167,6 +203,8 @@ describe("TopicMessages", () => { offsetId: "5", selectedNumberOfOffsets: 0, selectedPartitionId: 0, + selectedOffsetRangeStart: 0, + selectedOffsetRangeEnd: 0, }); screen.getByText("HELLO"); screen.getByText("WORLD"); @@ -178,7 +216,7 @@ describe("TopicMessages", () => { customRender( }> - } /> + } /> , { @@ -210,7 +248,7 @@ describe("TopicMessages", () => { customRender( }> - } /> + } /> , { @@ -232,6 +270,8 @@ describe("TopicMessages", () => { offsetId: "25", selectedNumberOfOffsets: 0, selectedPartitionId: 0, + selectedOffsetRangeStart: 0, + selectedOffsetRangeEnd: 0, }); }); }); @@ -239,7 +279,7 @@ describe("TopicMessages", () => { customRender( }> - } /> + } /> , { @@ -262,6 +302,8 @@ describe("TopicMessages", () => { offsetId: "custom", selectedNumberOfOffsets: 20, selectedPartitionId: 1, + selectedOffsetRangeStart: 0, + selectedOffsetRangeEnd: 0, }); }); }); @@ -269,7 +311,7 @@ describe("TopicMessages", () => { customRender( }> - } /> + } /> , { @@ -291,6 +333,41 @@ describe("TopicMessages", () => { offsetId: "50", selectedNumberOfOffsets: 0, selectedPartitionId: 0, + selectedOffsetRangeStart: 0, + selectedOffsetRangeEnd: 0, + }); + }); + }); + it("populates the filter from the url search parameters (partitionId, rangeOffsetStart and rangeOffsetEnd)", async () => { + customRender( + + }> + } /> + + , + { + queryClient: true, + memoryRouter: true, + customRoutePath: + "/?defaultOffset=range&partitionId=1&rangeOffsetStart=5&rangeOffsetEnd=10", + } + ); + + await userEvent.click( + screen.getByRole("button", { + name: "Fetch and display the messages from offset 5 to offset 10 from partiton 1 of topic test", + }) + ); + await waitFor(() => { + expect(getTopicMessages).toHaveBeenNthCalledWith(1, { + topicName: "test", + consumerGroupId: "notdefined", + envId: "2", + offsetId: "range", + selectedNumberOfOffsets: 0, + selectedPartitionId: 1, + selectedOffsetRangeStart: 5, + selectedOffsetRangeEnd: 10, }); }); }); diff --git a/coral/src/app/features/topics/details/messages/TopicMessages.tsx b/coral/src/app/features/topics/details/messages/TopicMessages.tsx index f4e9168e85..4fd91c94fd 100644 --- a/coral/src/app/features/topics/details/messages/TopicMessages.tsx +++ b/coral/src/app/features/topics/details/messages/TopicMessages.tsx @@ -2,14 +2,17 @@ import { Box, Button, EmptyState, + NativeSelect, PageHeader, - Switch, - SwitchGroup, Typography, } from "@aivenio/aquarium"; import refreshIcon from "@aivenio/aquarium/dist/src/icons/refresh"; import { useQuery } from "@tanstack/react-query"; import { useState } from "react"; +import { + useFiltersContext, + withFiltersContext, +} from "src/app/features/components/filters/useFiltersContext"; import { TableLayout } from "src/app/features/components/layouts/TableLayout"; import { useTopicDetails } from "src/app/features/topics/details/TopicDetails"; import { TopicMessageFilters } from "src/app/features/topics/details/messages/components/TopicMessageFilters"; @@ -23,6 +26,7 @@ import { type NoContent, type TopicMessages as TopicMessagesType, TOPIC_MESSAGE_DEFAULT_USER_GROUP_ID, + TopicMessagesFetchModeTypes, } from "src/domain/topic/topic-types"; function isNoContentResult( @@ -32,6 +36,7 @@ function isNoContentResult( } function TopicMessages() { + const { defaultOffset, setFilterValue } = useFiltersContext(); const { topicName, environmentId } = useTopicDetails(); const { @@ -40,12 +45,12 @@ function TopicMessages() { getFetchingMode, defaultOffsetFilters, customOffsetFilters, + rangeOffsetFilters, partitionIdFilters, } = useMessagesFilters(); - const [fetchingMode, setFetchingMode] = useState<"Default" | "Custom">( - getFetchingMode() - ); + const [fetchingMode, setFetchingMode] = + useState(getFetchingMode()); const { data: consumeResult, @@ -66,6 +71,8 @@ function TopicMessages() { offsetId: defaultOffsetFilters.defaultOffset, selectedPartitionId: Number(partitionIdFilters.partitionId), selectedNumberOfOffsets: Number(customOffsetFilters.customOffset), + selectedOffsetRangeStart: Number(rangeOffsetFilters.rangeOffsetStart), + selectedOffsetRangeEnd: Number(rangeOffsetFilters.rangeOffsetEnd), }), keepPreviousData: true, refetchOnWindowFocus: true, @@ -93,14 +100,24 @@ function TopicMessages() { customOffsetFilters.setCustomOffset(customOffset); } - function handleFetchModeChange(): void { - if (fetchingMode === "Default") { - setFetchingMode("Custom"); - defaultOffsetFilters.setDefaultOffset("custom"); - } else { - setFetchingMode("Default"); + function handleRangeOffsetStartChange(rangeOffsetStart: string): void { + rangeOffsetFilters.setRangeOffsetStart(rangeOffsetStart); + } + + function handleRangeOffsetEndChange(rangeOffsetEnd: string): void { + rangeOffsetFilters.setRangeOffsetEnd(rangeOffsetEnd); + } + + function handleFetchModeChange( + selectedFetchMode: TopicMessagesFetchModeTypes + ): void { + if (fetchingMode === selectedFetchMode) { + return; + } + if (selectedFetchMode === "default") { defaultOffsetFilters.setDefaultOffset("5"); } + setFetchingMode(selectedFetchMode); } function getMessagesUpdatedAt(): string { @@ -110,6 +127,16 @@ function TopicMessages() { }).format(messagesUpdatedAt); } + function getButtonLabel(): string { + if (fetchingMode === "custom") { + return `Fetch and display the latest ${customOffsetFilters.customOffset} messages from partiton ${partitionIdFilters.partitionId} of topic ${topicName}`; + } + if (fetchingMode === "range") { + return `Fetch and display the messages from offset ${rangeOffsetFilters.rangeOffsetStart} to offset ${rangeOffsetFilters.rangeOffsetEnd} from partiton ${partitionIdFilters.partitionId} of topic ${topicName}`; + } + return `Fetch and display the latest ${defaultOffsetFilters.defaultOffset} messages from topic ${topicName}`; + } + function getTableContent() { if (!consumeResult) { return ( @@ -147,22 +174,32 @@ function TopicMessages() { filters={[ - { + handleFetchModeChange( + event.target.value as TopicMessagesFetchModeTypes + ); + + return setFilterValue({ + name: "defaultOffset", + value: event.target.value as TopicMessagesFetchModeTypes, + }); + }} > - - {fetchingMode} - - + + + + @@ -185,11 +226,7 @@ function TopicMessages() { onClick={handleUpdateResultClick} disabled={isConsuming} loading={isConsuming} - aria-label={ - fetchingMode === "Default" - ? `Fetch and display the latest ${defaultOffsetFilters.defaultOffset} messages from topic ${topicName}` - : `Fetch and display the latest ${customOffsetFilters.customOffset} messages from partiton ${partitionIdFilters.partitionId} of topic ${topicName}` - } + aria-label={getButtonLabel()} icon={refreshIcon} > Fetch messages @@ -206,4 +243,7 @@ function TopicMessages() { ); } -export { TopicMessages }; +export default withFiltersContext({ + defaultValues: { paginated: false }, + element: , +}); diff --git a/coral/src/app/features/topics/details/messages/components/TopicMessageFilters.test.tsx b/coral/src/app/features/topics/details/messages/components/TopicMessageFilters.test.tsx index 6807b26a5a..d4a3faf5a9 100644 --- a/coral/src/app/features/topics/details/messages/components/TopicMessageFilters.test.tsx +++ b/coral/src/app/features/topics/details/messages/components/TopicMessageFilters.test.tsx @@ -1,9 +1,9 @@ import { cleanup, render, screen, within } from "@testing-library/react"; -import { TopicMessageFilters } from "src/app/features/topics/details/messages/components/TopicMessageFilters"; import { userEvent } from "@testing-library/user-event"; +import { TopicMessageFilters } from "src/app/features/topics/details/messages/components/TopicMessageFilters"; describe("TopicMessageFilters", () => { - describe("mode: Default", () => { + describe("mode: default", () => { afterEach(() => { cleanup(); }); @@ -14,13 +14,22 @@ describe("TopicMessageFilters", () => { defaultOffset: "25", customOffset: null, partitionId: null, + rangeOffsetStart: null, + rangeOffsetEnd: null, }} onDefaultOffsetChange={jest.fn()} onPartitionIdChange={jest.fn()} onCustomOffsetChange={jest.fn()} + onRangeOffsetStartChange={jest.fn()} + onRangeOffsetEndChange={jest.fn()} disabled={false} - mode={"Default"} - filterErrors={{ partitionIdFilters: null, customOffsetFilters: null }} + mode={"default"} + filterErrors={{ + partitionIdFilters: null, + customOffsetFilters: null, + rangeOffsetStartFilters: null, + rangeOffsetEndFilters: null, + }} /> ); expect(screen.getByRole("radio", { name: "5" })).toBeVisible(); @@ -36,13 +45,22 @@ describe("TopicMessageFilters", () => { defaultOffset: "25", customOffset: null, partitionId: null, + rangeOffsetStart: null, + rangeOffsetEnd: null, }} onDefaultOffsetChange={onDefaultOffsetChange} onPartitionIdChange={jest.fn()} onCustomOffsetChange={jest.fn()} + onRangeOffsetStartChange={jest.fn()} + onRangeOffsetEndChange={jest.fn()} disabled={false} - mode={"Default"} - filterErrors={{ partitionIdFilters: null, customOffsetFilters: null }} + mode={"default"} + filterErrors={{ + partitionIdFilters: null, + customOffsetFilters: null, + rangeOffsetStartFilters: null, + rangeOffsetEndFilters: null, + }} /> ); await userEvent.click(screen.getByRole("radio", { name: "50" })); @@ -57,13 +75,22 @@ describe("TopicMessageFilters", () => { defaultOffset: "25", customOffset: null, partitionId: null, + rangeOffsetStart: null, + rangeOffsetEnd: null, }} onDefaultOffsetChange={jest.fn()} onPartitionIdChange={jest.fn()} onCustomOffsetChange={jest.fn()} + onRangeOffsetStartChange={jest.fn()} + onRangeOffsetEndChange={jest.fn()} disabled={true} - mode={"Default"} - filterErrors={{ partitionIdFilters: null, customOffsetFilters: null }} + mode={"default"} + filterErrors={{ + partitionIdFilters: null, + customOffsetFilters: null, + rangeOffsetStartFilters: null, + rangeOffsetEndFilters: null, + }} /> ); within( @@ -75,7 +102,7 @@ describe("TopicMessageFilters", () => { .forEach((option) => expect(option).toBeDisabled()); }); }); - describe("mode: Custom", () => { + describe("mode: custom", () => { afterEach(() => { cleanup(); }); @@ -86,13 +113,22 @@ describe("TopicMessageFilters", () => { defaultOffset: "custom", customOffset: null, partitionId: null, + rangeOffsetStart: null, + rangeOffsetEnd: null, }} onDefaultOffsetChange={jest.fn()} onPartitionIdChange={jest.fn()} onCustomOffsetChange={jest.fn()} + onRangeOffsetStartChange={jest.fn()} + onRangeOffsetEndChange={jest.fn()} disabled={false} - mode={"Custom"} - filterErrors={{ partitionIdFilters: null, customOffsetFilters: null }} + mode={"custom"} + filterErrors={{ + partitionIdFilters: null, + customOffsetFilters: null, + rangeOffsetStartFilters: null, + rangeOffsetEndFilters: null, + }} /> ); expect( @@ -107,7 +143,7 @@ describe("TopicMessageFilters", () => { ).toBeVisible(); }); - it("is possible to enter values in fields", async () => { + it("is possible to enter values in fields for custom select mode", async () => { const onPartitionIdChange = jest.fn(); const onCustomOffsetChange = jest.fn(); render( @@ -116,13 +152,22 @@ describe("TopicMessageFilters", () => { defaultOffset: "custom", customOffset: null, partitionId: null, + rangeOffsetStart: null, + rangeOffsetEnd: null, }} onDefaultOffsetChange={jest.fn()} onPartitionIdChange={onPartitionIdChange} onCustomOffsetChange={onCustomOffsetChange} + onRangeOffsetStartChange={jest.fn()} + onRangeOffsetEndChange={jest.fn()} disabled={false} - mode={"Custom"} - filterErrors={{ partitionIdFilters: null, customOffsetFilters: null }} + mode={"custom"} + filterErrors={{ + partitionIdFilters: null, + customOffsetFilters: null, + rangeOffsetStartFilters: null, + rangeOffsetEndFilters: null, + }} /> ); @@ -139,4 +184,98 @@ describe("TopicMessageFilters", () => { expect(onCustomOffsetChange).toHaveBeenCalledWith("10"); }); }); + + describe("mode: range", () => { + afterEach(() => { + cleanup(); + }); + it("displays required Partion ID and Range offset start and end fields", () => { + render( + + ); + expect( + screen.getByRole("spinbutton", { + name: "Partition ID * Enter partition ID to retrieve last messages", + }) + ).toBeVisible(); + expect( + screen.getByRole("spinbutton", { + name: "Start Offset * Set the start offset", + }) + ).toBeVisible(); + expect( + screen.getByRole("spinbutton", { + name: "End Offset * Set the end offset", + }) + ).toBeVisible(); + }); + + it("is possible to enter values in fields for range select mode", async () => { + const onPartitionIdChange = jest.fn(); + const onRangeOffsetStartChange = jest.fn(); + const onRangeOffsetEndChange = jest.fn(); + render( + + ); + + const partitionIdInput = screen.getByRole("spinbutton", { + name: "Partition ID * Enter partition ID to retrieve last messages", + }); + const startOffsetInput = screen.getByRole("spinbutton", { + name: "Start Offset * Set the start offset", + }); + const endOffsetInput = screen.getByRole("spinbutton", { + name: "End Offset * Set the end offset", + }); + + await userEvent.type(partitionIdInput, "1"); + await userEvent.type(startOffsetInput, "5"); + await userEvent.type(endOffsetInput, "10"); + expect(onPartitionIdChange).toHaveBeenCalledWith("1"); + expect(onRangeOffsetStartChange).toHaveBeenCalledWith("5"); + expect(onRangeOffsetEndChange).toHaveBeenCalledWith("10"); + }); + }); }); diff --git a/coral/src/app/features/topics/details/messages/components/TopicMessageFilters.tsx b/coral/src/app/features/topics/details/messages/components/TopicMessageFilters.tsx index 1f1f04536e..4bbae7d3c7 100644 --- a/coral/src/app/features/topics/details/messages/components/TopicMessageFilters.tsx +++ b/coral/src/app/features/topics/details/messages/components/TopicMessageFilters.tsx @@ -6,22 +6,29 @@ import { RadioButtonGroupProps, } from "@aivenio/aquarium"; import { - defaultOffsets, type DefaultOffset, type FilterErrors, } from "src/app/features/topics/details/messages/useMessagesFilters"; +import { + defaultOffsets, + TopicMessagesFetchModeTypes, +} from "src/domain/topic/topic-types"; type Props = { values: { defaultOffset: DefaultOffset; customOffset: string | null; partitionId: string | null; + rangeOffsetStart: string | null; + rangeOffsetEnd: string | null; }; disabled?: RadioButtonGroupProps["disabled"]; onDefaultOffsetChange: (defaultOffset: DefaultOffset) => void; onPartitionIdChange: (partitionId: string) => void; onCustomOffsetChange: (customOffset: string) => void; - mode: "Default" | "Custom"; + onRangeOffsetStartChange: (rangeOffsetStart: string) => void; + onRangeOffsetEndChange: (rangeOffsetEnd: string) => void; + mode: TopicMessagesFetchModeTypes; filterErrors: FilterErrors; }; @@ -31,30 +38,67 @@ function TopicMessageFilters({ onDefaultOffsetChange, onPartitionIdChange, onCustomOffsetChange, + onRangeOffsetStartChange, + onRangeOffsetEndChange, mode, filterErrors, }: Props) { - return mode === "Default" ? ( - onDefaultOffsetChange(value as DefaultOffset)} - description={"Select number of messages to display from this topic"} - > - {defaultOffsets.map((defaultOffset) => { - if (defaultOffset === "custom") { - return; - } - return ( - - {defaultOffset} - - ); - })} - - ) : ( + if (mode === "default") { + return ( + onDefaultOffsetChange(value as DefaultOffset)} + description={"Select number of messages to display from this topic"} + > + {defaultOffsets.map((defaultOffset) => { + if (defaultOffset === "custom" || defaultOffset === "range") { + return; + } + return ( + + {defaultOffset} + + ); + })} + + ); + } + + if (mode === "custom") { + return ( + + onPartitionIdChange(e.target.value)} + type="number" + helperText={filterErrors.partitionIdFilters || undefined} + valid={filterErrors.partitionIdFilters === null} + required + /> + onCustomOffsetChange(e.target.value)} + type="number" + helperText={filterErrors.customOffsetFilters || undefined} + valid={filterErrors.customOffsetFilters === null} + required + /> + + ); + } + + return ( onCustomOffsetChange(e.target.value)} + value={values.rangeOffsetStart || undefined} + labelText="Start Offset" + placeholder={"0"} + description={"Set the start offset"} + onChange={(e) => onRangeOffsetStartChange(e.target.value)} + type="number" + helperText={filterErrors.rangeOffsetStartFilters || undefined} + valid={filterErrors.rangeOffsetStartFilters === null} + required + /> + onRangeOffsetEndChange(e.target.value)} type="number" - helperText={filterErrors.customOffsetFilters || undefined} - valid={filterErrors.customOffsetFilters === null} + helperText={filterErrors.rangeOffsetEndFilters || undefined} + valid={filterErrors.rangeOffsetEndFilters === null} required /> diff --git a/coral/src/app/features/topics/details/messages/useMessagesFilters.test.tsx b/coral/src/app/features/topics/details/messages/useMessagesFilters.test.tsx index 79f8bbc4ba..f76ba2d923 100644 --- a/coral/src/app/features/topics/details/messages/useMessagesFilters.test.tsx +++ b/coral/src/app/features/topics/details/messages/useMessagesFilters.test.tsx @@ -1,4 +1,4 @@ -import { cleanup, renderHook, act } from "@testing-library/react"; +import { act, cleanup, renderHook } from "@testing-library/react"; import { BrowserRouter, MemoryRouter } from "react-router-dom"; import { useMessagesFilters } from "src/app/features/topics/details/messages/useMessagesFilters"; @@ -196,6 +196,8 @@ describe("useMessagesFilters.tsx", () => { expect(result.current.filterErrors).toStrictEqual({ customOffsetFilters: null, partitionIdFilters: null, + rangeOffsetStartFilters: null, + rangeOffsetEndFilters: null, }); }); it("validateFilters returns false (missing partitionId)", () => { @@ -220,6 +222,8 @@ describe("useMessagesFilters.tsx", () => { expect(result.current.filterErrors).toStrictEqual({ customOffsetFilters: null, partitionIdFilters: "Please enter a partition ID", + rangeOffsetStartFilters: null, + rangeOffsetEndFilters: null, }); }); @@ -246,6 +250,8 @@ describe("useMessagesFilters.tsx", () => { customOffsetFilters: "Please enter the number of recent offsets you want to view", partitionIdFilters: null, + rangeOffsetStartFilters: null, + rangeOffsetEndFilters: null, }); }); it("validateFilters returns false (too high customOffset)", () => { @@ -273,6 +279,8 @@ describe("useMessagesFilters.tsx", () => { customOffsetFilters: "Entered value exceeds the view limit for offsets: 100", partitionIdFilters: null, + rangeOffsetStartFilters: null, + rangeOffsetEndFilters: null, }); }); it("getFetchingMode returns Custom", () => { @@ -289,7 +297,7 @@ describe("useMessagesFilters.tsx", () => { ), }); - expect(current.getFetchingMode()).toBe("Custom"); + expect(current.getFetchingMode()).toBe("custom"); }); it("getFetchingMode returns Default", () => { const { @@ -301,7 +309,250 @@ describe("useMessagesFilters.tsx", () => { ), }); - expect(current.getFetchingMode()).toBe("Default"); + expect(current.getFetchingMode()).toBe("default"); + }); + it("partitionId not deleted when changing from custom to range", () => { + const { + result: { current }, + } = renderHook(() => useMessagesFilters(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + expect(current.getFetchingMode()).toBe("custom"); + expect(current.partitionIdFilters.partitionId).toBe("2"); + + current.defaultOffsetFilters.setDefaultOffset("range"); + expect(current.getFetchingMode()).toBe("range"); + expect(current.partitionIdFilters.partitionId).toBe("2"); + }); + it("partitionId not deleted when changing from range to custom", () => { + const { + result: { current }, + } = renderHook(() => useMessagesFilters(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + expect(current.getFetchingMode()).toBe("range"); + expect(current.partitionIdFilters.partitionId).toBe("2"); + + current.defaultOffsetFilters.setDefaultOffset("custom"); + expect(current.getFetchingMode()).toBe("custom"); + expect(current.partitionIdFilters.partitionId).toBe("2"); + }); + }); + + describe("rangeOffsetFilters", () => { + afterEach(cleanup); + it("returns null as the default offset value", () => { + const { + result: { current }, + } = renderHook(() => useMessagesFilters(), { + wrapper: ({ children }) => {children}, + }); + + expect(current.rangeOffsetFilters.rangeOffsetStart).toBe(null); + expect(current.rangeOffsetFilters.rangeOffsetEnd).toBe(null); + }); + it("gets the start and end offset from search params", () => { + const { + result: { current }, + } = renderHook(() => useMessagesFilters(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + const startOffset = current.rangeOffsetFilters.rangeOffsetStart; + const endOffset = current.rangeOffsetFilters.rangeOffsetEnd; + expect(startOffset).toEqual("20"); + expect(endOffset).toEqual("40"); + }); + it("sets the offset to search params", async () => { + const { + result: { current }, + } = renderHook(() => useMessagesFilters(), { + wrapper: ({ children }) => {children}, + }); + const setRangeOffsetStart = + current.rangeOffsetFilters.setRangeOffsetStart; + const setRangeOffsetEnd = current.rangeOffsetFilters.setRangeOffsetEnd; + setRangeOffsetStart("25"); + setRangeOffsetEnd("50"); + expect(window.location.search).toBe( + "?defaultOffset=range&rangeOffsetStart=25&rangeOffsetEnd=50" + ); + }); + it("deletes the offset from search params", () => { + const { + result: { current }, + } = renderHook(() => useMessagesFilters(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + expect(current.rangeOffsetFilters.rangeOffsetStart).toEqual("25"); + expect(current.rangeOffsetFilters.rangeOffsetEnd).toEqual("50"); + current.rangeOffsetFilters.deleteRangeOffsetStart(); + current.rangeOffsetFilters.deleteRangeOffsetEnd(); + expect(window.location.search).toBe(""); + }); + it("validateFilters returns true", () => { + const { result } = renderHook(() => useMessagesFilters(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + let isValid; + + act(() => { + isValid = result.current.validateFilters(); + }); + + expect(isValid).toBe(true); + expect(result.current.filterErrors).toStrictEqual({ + customOffsetFilters: null, + partitionIdFilters: null, + rangeOffsetStartFilters: null, + rangeOffsetEndFilters: null, + }); + }); + it("validateFilters returns false (missing partitionId)", () => { + const { result } = renderHook(() => useMessagesFilters(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + let isValid; + + act(() => { + isValid = result.current.validateFilters(); + }); + + expect(isValid).toBe(false); + + expect(result.current.filterErrors).toStrictEqual({ + customOffsetFilters: null, + partitionIdFilters: "Please enter a partition ID", + rangeOffsetStartFilters: null, + rangeOffsetEndFilters: null, + }); + }); + it("validateFilters returns false (missing rangeOffsetStart and rangeOffsetEnd)", () => { + const { result } = renderHook(() => useMessagesFilters(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + let isValid; + + act(() => { + isValid = result.current.validateFilters(); + }); + + expect(isValid).toBe(false); + + expect(result.current.filterErrors).toStrictEqual({ + customOffsetFilters: null, + partitionIdFilters: null, + rangeOffsetStartFilters: "Please enter the start offset", + rangeOffsetEndFilters: "Please enter the end offset", + }); + }); + it("validateFilters returns false (negative rangeOffsetStart and rangeOffsetEnd)", () => { + const { result } = renderHook(() => useMessagesFilters(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + let isValid; + + act(() => { + isValid = result.current.validateFilters(); + }); + + expect(isValid).toBe(false); + + expect(result.current.filterErrors).toStrictEqual({ + customOffsetFilters: null, + partitionIdFilters: null, + rangeOffsetStartFilters: "Start offset cannot be negative.", + rangeOffsetEndFilters: "End offset cannot be negative.", + }); + }); + it("validateFilters returns false (rangeOffsetStart bigger than rangeOffsetEnd)", () => { + const { result } = renderHook(() => useMessagesFilters(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + let isValid; + + act(() => { + isValid = result.current.validateFilters(); + }); + + expect(isValid).toBe(false); + + expect(result.current.filterErrors).toStrictEqual({ + customOffsetFilters: null, + partitionIdFilters: null, + rangeOffsetStartFilters: "Start must me less than end.", + rangeOffsetEndFilters: null, + }); }); }); }); diff --git a/coral/src/app/features/topics/details/messages/useMessagesFilters.tsx b/coral/src/app/features/topics/details/messages/useMessagesFilters.tsx index 0d6f41770c..6005404a43 100644 --- a/coral/src/app/features/topics/details/messages/useMessagesFilters.tsx +++ b/coral/src/app/features/topics/details/messages/useMessagesFilters.tsx @@ -1,25 +1,31 @@ import { useEffect, useMemo, useState } from "react"; import { useSearchParams } from "react-router-dom"; +import { + DefaultOffset, + defaultOffsets, + TopicMessagesFetchModeTypes, +} from "src/domain/topic/topic-types"; interface FilterErrors { partitionIdFilters: string | null; customOffsetFilters: string | null; + rangeOffsetStartFilters: string | null; + rangeOffsetEndFilters: string | null; } -const defaultOffsets = ["5", "25", "50", "custom"] as const; -type DefaultOffset = (typeof defaultOffsets)[number]; - const NAMES = { defaultOffset: "defaultOffset", customOffset: "customOffset", + rangeOffsetStart: "rangeOffsetStart", + rangeOffsetEnd: "rangeOffsetEnd", partitionId: "partitionId", }; -const initialDefaultOffset: (typeof defaultOffsets)[0] = "5"; +const initialDefaultOffset = "5" as DefaultOffset; interface OffsetFilters { validateFilters: () => boolean; filterErrors: FilterErrors; - getFetchingMode: () => "Custom" | "Default"; + getFetchingMode: () => TopicMessagesFetchModeTypes; defaultOffsetFilters: { defaultOffset: DefaultOffset; setDefaultOffset: (defaultOffset: DefaultOffset) => void; @@ -30,6 +36,14 @@ interface OffsetFilters { setCustomOffset: (customOffset: string) => void; deleteCustomOffset: () => void; }; + rangeOffsetFilters: { + rangeOffsetStart: string | null; + setRangeOffsetStart: (rangeOffsetStart: string) => void; + deleteRangeOffsetStart: () => void; + rangeOffsetEnd: string | null; + setRangeOffsetEnd: (rangeOffsetEnd: string) => void; + deleteRangeOffsetEnd: () => void; + }; partitionIdFilters: { partitionId: string | null; setPartitionId: (partitionId: string) => void; @@ -47,15 +61,16 @@ function isDefaultOffset( function useMessagesFilters(): OffsetFilters { const [searchParams, setSearchParams] = useSearchParams(); - const defaultOffset = searchParams.get(NAMES.defaultOffset); const [filterErrors, setFilterErrors] = useState({ partitionIdFilters: null, customOffsetFilters: null, + rangeOffsetStartFilters: null, + rangeOffsetEndFilters: null, }); function validateFilters() { - if (getFetchingMode() === "Default") { + if (getFetchingMode() === "default") { return true; } @@ -63,30 +78,61 @@ function useMessagesFilters(): OffsetFilters { getPartitionId() === "" || getPartitionId() === null ? "Please enter a partition ID" : null; - const customOffsetFiltersError = - getCustomOffset() === "" || getCustomOffset() === null - ? "Please enter the number of recent offsets you want to view" - : Number(getCustomOffset()) > 100 - ? "Entered value exceeds the view limit for offsets: 100" - : null; + + let customOffsetFiltersError = null; + let rangeOffsetStartFiltersError = null; + let rangeOffsetEndFiltersError = null; + if (getFetchingMode() === "custom") { + customOffsetFiltersError = + getCustomOffset() === "" || getCustomOffset() === null + ? "Please enter the number of recent offsets you want to view" + : Number(getCustomOffset()) > 100 + ? "Entered value exceeds the view limit for offsets: 100" + : null; + } else { + rangeOffsetStartFiltersError = + getRangeOffsetStart() === "" || getRangeOffsetStart() === null + ? "Please enter the start offset" + : Number(getRangeOffsetStart()) < 0 + ? "Start offset cannot be negative." + : null; + rangeOffsetEndFiltersError = + getRangeOffsetEnd() === "" || getRangeOffsetEnd() === null + ? "Please enter the end offset" + : Number(getRangeOffsetEnd()) < 0 + ? "End offset cannot be negative." + : null; + + if ( + rangeOffsetStartFiltersError === null && + rangeOffsetEndFiltersError === null && + Number(getRangeOffsetStart()) > Number(getRangeOffsetEnd()) + ) { + rangeOffsetStartFiltersError = "Start must me less than end."; + } + } setFilterErrors({ partitionIdFilters: partitionIdFiltersError, customOffsetFilters: customOffsetFiltersError, + rangeOffsetStartFilters: rangeOffsetStartFiltersError, + rangeOffsetEndFilters: rangeOffsetEndFiltersError, }); return ( - partitionIdFiltersError === null && customOffsetFiltersError === null + partitionIdFiltersError === null && + customOffsetFiltersError === null && + rangeOffsetStartFiltersError === null && + rangeOffsetEndFiltersError === null ); } function getDefaultOffset(): DefaultOffset { - return isDefaultOffset(defaultOffset) - ? defaultOffset - : initialDefaultOffset; + return searchParams.get(NAMES.defaultOffset) as DefaultOffset; } function setDefaultOffset(defaultOffset: DefaultOffset): void { + const oldValue = searchParams.get(NAMES.defaultOffset); if (!isDefaultOffset(defaultOffset)) { searchParams.set(NAMES.defaultOffset, initialDefaultOffset); } else { @@ -95,9 +141,21 @@ function useMessagesFilters(): OffsetFilters { setFilterErrors({ partitionIdFilters: null, customOffsetFilters: null, + rangeOffsetStartFilters: null, + rangeOffsetEndFilters: null, }); - deletePartitionId(); + + // If mode is changing from range to custom or vice versa, then no need to delete partition id + if ( + (oldValue !== "custom" && oldValue !== "range") || + (defaultOffset !== "custom" && defaultOffset !== "range") + ) { + deletePartitionId(); + } + deleteCustomOffset(); + deleteRangeOffsetStart(); + deleteRangeOffsetEnd(); setSearchParams(searchParams); } @@ -133,6 +191,8 @@ function useMessagesFilters(): OffsetFilters { : null, })); searchParams.set(NAMES.customOffset, customOffset); + deleteRangeOffsetStart(); + deleteRangeOffsetEnd(); setSearchParams(searchParams); } @@ -141,6 +201,68 @@ function useMessagesFilters(): OffsetFilters { setSearchParams(searchParams); } + function getRangeOffsetStart(): string | null { + return searchParams.get(NAMES.rangeOffsetStart); + } + + function setRangeOffsetStart(rangeOffsetStart: string): void { + if (getDefaultOffset() !== "range") { + setDefaultOffset("range"); + } + if (rangeOffsetStart.length === 0) { + setFilterErrors((prev) => ({ + ...prev, + rangeOffsetFilters: "Please enter the starting offset", + })); + deleteRangeOffsetStart(); + return; + } + setFilterErrors((prev) => ({ + ...prev, + rangeOffsetFilters: + rangeOffsetStart === "" ? "Please enter the starting offset" : null, + })); + searchParams.set(NAMES.rangeOffsetStart, rangeOffsetStart); + deleteCustomOffset(); + setSearchParams(searchParams); + } + + function deleteRangeOffsetStart() { + searchParams.delete(NAMES.rangeOffsetStart); + setSearchParams(searchParams); + } + + function getRangeOffsetEnd(): string | null { + return searchParams.get(NAMES.rangeOffsetEnd); + } + + function setRangeOffsetEnd(rangeOffsetEnd: string): void { + if (getDefaultOffset() !== "range") { + setDefaultOffset("range"); + } + if (rangeOffsetEnd.length === 0) { + setFilterErrors((prev) => ({ + ...prev, + rangeOffsetFilters: "Please enter the ending offset", + })); + deleteRangeOffsetEnd(); + return; + } + setFilterErrors((prev) => ({ + ...prev, + rangeOffsetFilters: + rangeOffsetEnd === "" ? "Please enter the ending offset" : null, + })); + searchParams.set(NAMES.rangeOffsetEnd, rangeOffsetEnd); + deleteCustomOffset(); + setSearchParams(searchParams); + } + + function deleteRangeOffsetEnd() { + searchParams.delete(NAMES.rangeOffsetEnd); + setSearchParams(searchParams); + } + function getPartitionId(): string | null { return searchParams.get(NAMES.partitionId); } @@ -172,22 +294,28 @@ function useMessagesFilters(): OffsetFilters { setSearchParams(searchParams); } - function getFetchingMode() { - if (defaultOffset === "custom") { - return "Custom"; + function getFetchingMode(): TopicMessagesFetchModeTypes { + if (getDefaultOffset() === "custom") { + return "custom"; + } + if (getDefaultOffset() === "range") { + return "range"; } - return "Default"; + return "default"; } useEffect(() => { - if (defaultOffset !== "custom" || defaultOffset === null) { - searchParams.set( - NAMES.defaultOffset, - defaultOffset === null ? initialDefaultOffset : defaultOffset - ); - setSearchParams(searchParams); - } + const toSetDefaultOffset = !isDefaultOffset( + searchParams.get(NAMES.defaultOffset) + ) + ? initialDefaultOffset + : searchParams.get(NAMES.defaultOffset); + searchParams.set( + NAMES.defaultOffset, + toSetDefaultOffset === null ? initialDefaultOffset : toSetDefaultOffset + ); + setSearchParams(searchParams); }, []); return { @@ -204,6 +332,14 @@ function useMessagesFilters(): OffsetFilters { setCustomOffset, deleteCustomOffset, }, + rangeOffsetFilters: { + rangeOffsetStart: getRangeOffsetStart(), + setRangeOffsetStart, + deleteRangeOffsetStart, + rangeOffsetEnd: getRangeOffsetEnd(), + setRangeOffsetEnd, + deleteRangeOffsetEnd, + }, partitionIdFilters: { partitionId: getPartitionId(), setPartitionId, @@ -212,10 +348,4 @@ function useMessagesFilters(): OffsetFilters { }; } -export { - useMessagesFilters, - defaultOffsets, - isDefaultOffset, - type DefaultOffset, - type FilterErrors, -}; +export { useMessagesFilters, type DefaultOffset, type FilterErrors }; diff --git a/coral/src/app/pages/topics/details/messages/index.tsx b/coral/src/app/pages/topics/details/messages/index.tsx index 010e79302d..38a2507b0f 100644 --- a/coral/src/app/pages/topics/details/messages/index.tsx +++ b/coral/src/app/pages/topics/details/messages/index.tsx @@ -1,4 +1,4 @@ -import { TopicMessages } from "src/app/features/topics/details/messages/TopicMessages"; +import TopicMessages from "src/app/features/topics/details/messages/TopicMessages"; function TopicMessagesPage() { return ; diff --git a/coral/src/domain/topic/topic-types.ts b/coral/src/domain/topic/topic-types.ts index d954736571..cefa17b37b 100644 --- a/coral/src/domain/topic/topic-types.ts +++ b/coral/src/domain/topic/topic-types.ts @@ -92,11 +92,19 @@ type TopicClaimPayload = ResolveIntersectionTypes< type TopicDetailsPerEnv = KlawApiModel<"TopicDetailsPerEnv">; +const fetchModeTypes = ["default", "custom", "range"] as const; +type TopicMessagesFetchModeTypes = (typeof fetchModeTypes)[number]; + +const defaultOffsets = ["5", "25", "50", "custom", "range"] as const; +type DefaultOffset = (typeof defaultOffsets)[number]; + const TOPIC_MESSAGE_DEFAULT_USER_GROUP_ID = "notdefined"; export type { AclOverviewInfo, + DefaultOffset, DeleteTopicPayload, + GetTopicsQueryParameter, NoContent, Topic, TopicAdvancedConfigurationOptions, @@ -105,6 +113,7 @@ export type { TopicDetailsPerEnv, TopicDocumentationMarkdown, TopicMessages, + TopicMessagesFetchModeTypes, TopicNames, TopicOverview, TopicRequest, @@ -114,7 +123,6 @@ export type { TopicSchemaOverview, TopicTeam, TopicType, - GetTopicsQueryParameter, }; -export { TOPIC_MESSAGE_DEFAULT_USER_GROUP_ID }; +export { defaultOffsets, TOPIC_MESSAGE_DEFAULT_USER_GROUP_ID }; diff --git a/coral/types/api.d.ts b/coral/types/api.d.ts index df4d4bbef8..b6a7f05721 100644 --- a/coral/types/api.d.ts +++ b/coral/types/api.d.ts @@ -6307,6 +6307,8 @@ export interface operations { offsetId: string; selectedPartitionId: number; selectedNumberOfOffsets: number; + selectedOffsetRangeStart: number; + selectedOffsetRangeEnd: number; }; header?: never; path?: never; diff --git a/openapi.yaml b/openapi.yaml index 48e281a55a..f894d097f7 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -3232,6 +3232,22 @@ "type" : "integer", "format" : "int32" } + }, { + "name" : "selectedOffsetRangeStart", + "in" : "query", + "required" : true, + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "name" : "selectedOffsetRangeEnd", + "in" : "query", + "required" : true, + "schema" : { + "type" : "integer", + "format" : "int32" + } } ], "responses" : { "200" : { From c13080398ab1f9dcc3b78092e2b949fa68efed43 Mon Sep 17 00:00:00 2001 From: khatibtamal Date: Thu, 19 Sep 2024 20:38:37 +0600 Subject: [PATCH 6/9] removed changes that are not needed Signed-off-by: khatibtamal --- .../filters/useFiltersContext.test.tsx | 33 ------------------- .../components/filters/useFiltersContext.tsx | 10 +----- .../details/messages/TopicMessages.test.tsx | 29 +++++++--------- .../topics/details/messages/TopicMessages.tsx | 19 +++-------- .../pages/topics/details/messages/index.tsx | 2 +- 5 files changed, 18 insertions(+), 75 deletions(-) diff --git a/coral/src/app/features/components/filters/useFiltersContext.test.tsx b/coral/src/app/features/components/filters/useFiltersContext.test.tsx index 61f884453b..605f540b33 100644 --- a/coral/src/app/features/components/filters/useFiltersContext.test.tsx +++ b/coral/src/app/features/components/filters/useFiltersContext.test.tsx @@ -39,20 +39,6 @@ describe("useFiltersValues.tsx", () => { expect(current.aclType).toBe("PRODUCER"); }); - it("gets the correct defaultOffset filter value", () => { - const { - result: { current }, - } = renderHook(() => useFiltersContext(), { - wrapper: ({ children }) => ( - - {children} - - ), - }); - - expect(current.defaultOffset).toBe("custom"); - }); - it("gets the correct status filter value", () => { const { result: { current }, @@ -316,25 +302,6 @@ describe("useFiltersValues.tsx", () => { expect(window.location.search).toBe("?aclType=PRODUCER&page=1"); }); - it("sets the correct defaultOffset filter value", () => { - const { - result: { current }, - } = renderHook(() => useFiltersContext(), { - wrapper: ({ children }) => ( - - {children} - - ), - }); - - current.setFilterValue({ - name: "defaultOffset", - value: "custom", - }); - - expect(window.location.search).toBe("?defaultOffset=custom&page=1"); - }); - it("sets the correct status filter value", () => { const { result: { current }, diff --git a/coral/src/app/features/components/filters/useFiltersContext.tsx b/coral/src/app/features/components/filters/useFiltersContext.tsx index 696f75eaf3..42c483a832 100644 --- a/coral/src/app/features/components/filters/useFiltersContext.tsx +++ b/coral/src/app/features/components/filters/useFiltersContext.tsx @@ -4,7 +4,6 @@ import { AclType } from "src/domain/acl/acl-types"; import { ClusterType } from "src/domain/cluster"; import { RequestOperationType, RequestStatus } from "src/domain/requests"; import { TopicType } from "src/domain/topic"; -import { TopicMessagesFetchModeTypes } from "src/domain/topic/topic-types"; type SetFiltersParams = | { name: "environment"; value: string } @@ -16,8 +15,7 @@ type SetFiltersParams = | { name: "search"; value: string } | { name: "teamName"; value: string } | { name: "topicType"; value: TopicType | "ALL" } - | { name: "clusterType"; value: ClusterType } - | { name: "defaultOffset"; value: TopicMessagesFetchModeTypes }; + | { name: "clusterType"; value: ClusterType }; interface UseFiltersDefaultValues { environment: string; @@ -31,7 +29,6 @@ interface UseFiltersDefaultValues { teamName: string; topicType: TopicType | "ALL"; clusterType: ClusterType; - defaultOffset: TopicMessagesFetchModeTypes; } interface UseFiltersReturnedValues @@ -51,7 +48,6 @@ const emptyValues: UseFiltersDefaultValues = { paginated: true, topicType: "ALL", clusterType: "ALL", - defaultOffset: "default", }; const FiltersContext = createContext({ @@ -91,9 +87,6 @@ const FiltersProvider = ({ const clusterType = (searchParams.get("clusterType") as ClusterType) ?? initialValues.clusterType; - const defaultOffset = - (searchParams.get("defaultOffset") as TopicMessagesFetchModeTypes) ?? - initialValues.defaultOffset; const setFilterValue = ({ name, value }: SetFiltersParams) => { const parsedValue = typeof value === "boolean" ? String(value) : value; @@ -121,7 +114,6 @@ const FiltersProvider = ({ search, topicType, clusterType, - defaultOffset, setFilterValue, }; diff --git a/coral/src/app/features/topics/details/messages/TopicMessages.test.tsx b/coral/src/app/features/topics/details/messages/TopicMessages.test.tsx index 9fd21db033..fce8502cff 100644 --- a/coral/src/app/features/topics/details/messages/TopicMessages.test.tsx +++ b/coral/src/app/features/topics/details/messages/TopicMessages.test.tsx @@ -1,8 +1,7 @@ import { cleanup, screen, waitFor } from "@testing-library/react"; import { userEvent } from "@testing-library/user-event"; import { Outlet, Route, Routes } from "react-router-dom"; -import { withFiltersContext } from "src/app/features/components/filters/useFiltersContext"; -import TopicMessages from "src/app/features/topics/details/messages/TopicMessages"; +import { TopicMessages } from "src/app/features/topics/details/messages/TopicMessages"; import { getTopicMessages } from "src/domain/topic/topic-api"; import { mockIntersectionObserver } from "src/services/test-utils/mock-intersection-observer"; import { customRender } from "src/services/test-utils/render-with-wrappers"; @@ -23,10 +22,6 @@ const mockGetTopicMessagesNoContentResponse = { }; const selectModeOptions = ["Default", "Custom", "Range"]; -const WrappedTopicMessages = withFiltersContext({ - defaultValues: { paginated: false }, - element: , -}); function DummyParent() { return ; @@ -47,7 +42,7 @@ describe("TopicMessages", () => { customRender( }> - } /> + } /> , { @@ -77,7 +72,7 @@ describe("TopicMessages", () => { customRender( }> - } /> + } /> , { @@ -99,7 +94,7 @@ describe("TopicMessages", () => { customRender( }> - } /> + } /> , { @@ -129,7 +124,7 @@ describe("TopicMessages", () => { customRender( }> - } /> + } /> , { @@ -149,7 +144,7 @@ describe("TopicMessages", () => { customRender( }> - } /> + } /> , { @@ -182,7 +177,7 @@ describe("TopicMessages", () => { customRender( }> - } /> + } /> , { @@ -216,7 +211,7 @@ describe("TopicMessages", () => { customRender( }> - } /> + } /> , { @@ -248,7 +243,7 @@ describe("TopicMessages", () => { customRender( }> - } /> + } /> , { @@ -279,7 +274,7 @@ describe("TopicMessages", () => { customRender( }> - } /> + } /> , { @@ -311,7 +306,7 @@ describe("TopicMessages", () => { customRender( }> - } /> + } /> , { @@ -342,7 +337,7 @@ describe("TopicMessages", () => { customRender( }> - } /> + } /> , { diff --git a/coral/src/app/features/topics/details/messages/TopicMessages.tsx b/coral/src/app/features/topics/details/messages/TopicMessages.tsx index 4fd91c94fd..2e82a5bf65 100644 --- a/coral/src/app/features/topics/details/messages/TopicMessages.tsx +++ b/coral/src/app/features/topics/details/messages/TopicMessages.tsx @@ -9,10 +9,6 @@ import { import refreshIcon from "@aivenio/aquarium/dist/src/icons/refresh"; import { useQuery } from "@tanstack/react-query"; import { useState } from "react"; -import { - useFiltersContext, - withFiltersContext, -} from "src/app/features/components/filters/useFiltersContext"; import { TableLayout } from "src/app/features/components/layouts/TableLayout"; import { useTopicDetails } from "src/app/features/topics/details/TopicDetails"; import { TopicMessageFilters } from "src/app/features/topics/details/messages/components/TopicMessageFilters"; @@ -36,7 +32,6 @@ function isNoContentResult( } function TopicMessages() { - const { defaultOffset, setFilterValue } = useFiltersContext(); const { topicName, environmentId } = useTopicDetails(); const { @@ -116,6 +111,8 @@ function TopicMessages() { } if (selectedFetchMode === "default") { defaultOffsetFilters.setDefaultOffset("5"); + } else { + defaultOffsetFilters.setDefaultOffset(selectedFetchMode); } setFetchingMode(selectedFetchMode); } @@ -178,16 +175,11 @@ function TopicMessages() { labelText={"Select mode"} description={"Choose mode to fetch messages"} key={"filter-fetch-mode-type"} - defaultValue={defaultOffset} + defaultValue={getFetchingMode()} onChange={(event) => { handleFetchModeChange( event.target.value as TopicMessagesFetchModeTypes ); - - return setFilterValue({ - name: "defaultOffset", - value: event.target.value as TopicMessagesFetchModeTypes, - }); }} >