Browse Source

Merge branch 'master' into issue2724

Nail Badiullin 2 years ago
parent
commit
ec124b104e
100 changed files with 4078 additions and 3164 deletions
  1. 36 0
      .devcontainer/devcontainer.json
  2. 333 0
      etc/checkstyle/checkstyle-e2e.xml
  3. 2 2
      etc/checkstyle/checkstyle.xml
  4. 2 1
      kafka-ui-api/Dockerfile
  5. 177 35
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/client/RetryingKafkaConnectClient.java
  6. 1 1
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/config/ClustersProperties.java
  7. 1 1
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/config/auth/OAuthProperties.java
  8. 3 10
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/ApplicationConfigController.java
  9. 4 6
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/KafkaConnectController.java
  10. 14 30
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/AbstractEmitter.java
  11. 4 6
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/BackwardRecordEmitter.java
  12. 4 4
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/ConsumingStats.java
  13. 4 8
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/ForwardRecordEmitter.java
  14. 0 16
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/MessageFilterStats.java
  15. 82 0
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/MessagesProcessing.java
  16. 2 3
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/TailingEmitter.java
  17. 1 1
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/exception/GlobalErrorWebExceptionHandler.java
  18. 4 1
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/model/rbac/Permission.java
  19. 76 0
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ApplicationInfoService.java
  20. 49 16
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/KafkaConfigSanitizer.java
  21. 4 4
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/KafkaConnectService.java
  22. 18 39
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/MessagesService.java
  23. 29 10
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ReactiveAdminClient.java
  24. 7 14
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/TopicsService.java
  25. 3 3
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/analyze/TopicAnalysisStats.java
  26. 1 1
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/rbac/AccessControlService.java
  27. 3 4
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/rbac/extractor/CognitoAuthorityExtractor.java
  28. 53 0
      kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/GithubReleaseInfo.java
  29. 2 2
      kafka-ui-api/src/test/java/com/provectus/kafka/ui/AbstractIntegrationTest.java
  30. 4 5
      kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/KafkaConfigSanitizerTest.java
  31. 57 0
      kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/ReactiveAdminClientTest.java
  32. 15 10
      kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/RecordEmitterTest.java
  33. 0 3
      kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/ksql/KsqlServiceV2Test.java
  34. 54 0
      kafka-ui-api/src/test/java/com/provectus/kafka/ui/util/GithubReleaseInfoTest.java
  35. 17 19
      kafka-ui-contract/pom.xml
  36. 24 0
      kafka-ui-contract/src/main/resources/swagger/kafka-ui-api.yaml
  37. 31 0
      kafka-ui-e2e-checks/pom.xml
  38. 1 1
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Connector.java
  39. 20 19
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Schema.java
  40. 6 6
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Topic.java
  41. 126 127
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/BasePage.java
  42. 27 28
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersConfigTab.java
  43. 73 74
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersDetails.java
  44. 88 89
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersList.java
  45. 39 39
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/ConnectorCreateForm.java
  46. 64 64
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/ConnectorDetails.java
  47. 33 33
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/KafkaConnectList.java
  48. 19 19
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/consumers/ConsumersDetails.java
  49. 8 8
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/consumers/ConsumersList.java
  50. 0 139
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/KsqlDbList.java
  51. 0 154
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/KsqlQueryForm.java
  52. 0 17
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/enums/KsqlMenuTabs.java
  53. 0 19
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/enums/KsqlQueryConfig.java
  54. 138 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/KsqlDbList.java
  55. 153 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/KsqlQueryForm.java
  56. 17 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/enums/KsqlMenuTabs.java
  57. 18 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/enums/KsqlQueryConfig.java
  58. 2 2
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/models/Stream.java
  59. 2 2
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/models/Table.java
  60. 46 47
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/NaviSideBar.java
  61. 13 14
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/TopPanel.java
  62. 24 24
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/enums/MenuItem.java
  63. 124 122
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaCreateForm.java
  64. 51 51
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaDetails.java
  65. 30 30
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaRegistryList.java
  66. 45 46
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/ProduceMessagePanel.java
  67. 268 262
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicCreateEditForm.java
  68. 411 398
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicDetails.java
  69. 41 42
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicSettingsTab.java
  70. 232 231
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicsList.java
  71. 15 15
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/CleanupPolicyValue.java
  72. 29 29
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/CustomParameterType.java
  73. 17 17
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/MaxSizeOnDisk.java
  74. 17 17
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/TimeToRetain.java
  75. 232 222
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/services/ApiService.java
  76. 19 19
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/BaseSource.java
  77. 8 8
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/configs/Profiles.java
  78. 77 72
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/drivers/WebDriver.java
  79. 25 21
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/AllureListener.java
  80. 24 24
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/LoggerListener.java
  81. 105 92
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/QaseCreateListener.java
  82. 74 71
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/QaseResultListener.java
  83. 14 15
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/FileUtils.java
  84. 7 8
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/TimeUtils.java
  85. 83 78
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/WebUtils.java
  86. 33 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/QaseSetup.java
  87. 3 4
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/annotations/Automation.java
  88. 2 2
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/annotations/Status.java
  89. 2 2
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/annotations/Suite.java
  90. 18 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/enums/State.java
  91. 18 0
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/enums/Status.java
  92. 0 34
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/QaseSetup.java
  93. 0 18
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/enums/State.java
  94. 0 18
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/enums/Status.java
  95. 2 2
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Browser.java
  96. 5 5
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Suite.java
  97. 6 6
      kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Url.java
  98. 1 1
      kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_create_connector.json
  99. 1 1
      kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_create_connector_via_api.json
  100. 1 1
      kafka-ui-e2e-checks/src/main/resources/testData/connectors/delete_connector_config.json

+ 36 - 0
.devcontainer/devcontainer.json

@@ -0,0 +1,36 @@
+{
+	"name": "Java",
+
+	"image": "mcr.microsoft.com/devcontainers/java:0-17",
+
+	"features": {
+		"ghcr.io/devcontainers/features/java:1": {
+			"version": "none",
+			"installMaven": "true",
+			"installGradle": "false"
+		},
+		"ghcr.io/devcontainers/features/docker-in-docker:2": {}
+	},
+
+	// Use 'forwardPorts' to make a list of ports inside the container available locally.
+	// "forwardPorts": [],
+
+	// Use 'postCreateCommand' to run commands after the container is created.
+	// "postCreateCommand": "java -version",
+
+	"customizations": {
+		"vscode": {
+			"extensions" : [
+				"vscjava.vscode-java-pack",
+				"vscjava.vscode-maven",
+				"vscjava.vscode-java-debug",
+				"EditorConfig.EditorConfig",
+				"ms-azuretools.vscode-docker",
+				"antfu.vite",
+				"ms-kubernetes-tools.vscode-kubernetes-tools",
+                "github.vscode-pull-request-github"
+			]
+		}
+	}
+
+}

+ 333 - 0
etc/checkstyle/checkstyle-e2e.xml

@@ -0,0 +1,333 @@
+<?xml version="1.0"?>
+<!DOCTYPE module PUBLIC
+        "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
+        "https://checkstyle.org/dtds/configuration_1_3.dtd">
+
+<!--
+    Checkstyle configuration that checks the Google coding conventions from Google Java Style
+    that can be found at https://google.github.io/styleguide/javaguide.html
+
+    Checkstyle is very configurable. Be sure to read the documentation at
+    http://checkstyle.org (or in your downloaded distribution).
+
+    To completely disable a check, just comment it out or delete it from the file.
+    To suppress certain violations please review suppression filters.
+
+    Authors: Max Vetrenko, Ruslan Diachenko, Roman Ivanov.
+ -->
+
+<module name = "Checker">
+    <property name="charset" value="UTF-8"/>
+
+    <property name="severity" value="warning"/>
+
+    <property name="fileExtensions" value="java, properties, xml"/>
+    <!-- Excludes all 'module-info.java' files              -->
+    <!-- See https://checkstyle.org/config_filefilters.html -->
+    <module name="BeforeExecutionExclusionFileFilter">
+        <property name="fileNamePattern" value="module\-info\.java$"/>
+    </module>
+    <!-- https://checkstyle.org/config_filters.html#SuppressionFilter -->
+    <module name="SuppressionFilter">
+        <property name="file" value="${org.checkstyle.google.suppressionfilter.config}"
+                  default="checkstyle-suppressions.xml" />
+        <property name="optional" value="true"/>
+    </module>
+
+    <!-- Checks for whitespace                               -->
+    <!-- See http://checkstyle.org/config_whitespace.html -->
+    <module name="FileTabCharacter">
+        <property name="eachLine" value="true"/>
+    </module>
+
+    <module name="LineLength">
+        <property name="fileExtensions" value="java"/>
+        <property name="max" value="120"/>
+        <property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
+    </module>
+
+    <module name="TreeWalker">
+        <module name="OuterTypeFilename"/>
+        <module name="IllegalTokenText">
+            <property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
+            <property name="format"
+                      value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
+            <property name="message"
+                      value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
+        </module>
+        <module name="AvoidEscapedUnicodeCharacters">
+            <property name="allowEscapesForControlCharacters" value="true"/>
+            <property name="allowByTailComment" value="true"/>
+            <property name="allowNonPrintableEscapes" value="true"/>
+        </module>
+        <module name="AvoidStarImport"/>
+        <module name="OneTopLevelClass"/>
+        <module name="NoLineWrap">
+            <property name="tokens" value="PACKAGE_DEF, IMPORT, STATIC_IMPORT"/>
+        </module>
+        <module name="EmptyBlock">
+            <property name="option" value="TEXT"/>
+            <property name="tokens"
+                      value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
+        </module>
+        <module name="NeedBraces">
+            <property name="tokens"
+                      value="LITERAL_DO, LITERAL_ELSE, LITERAL_FOR, LITERAL_IF, LITERAL_WHILE"/>
+        </module>
+        <module name="LeftCurly">
+            <property name="tokens"
+                      value="ANNOTATION_DEF, CLASS_DEF, CTOR_DEF, ENUM_CONSTANT_DEF, ENUM_DEF,
+                    INTERFACE_DEF, LAMBDA, LITERAL_CASE, LITERAL_CATCH, LITERAL_DEFAULT,
+                    LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF,
+                    LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, METHOD_DEF,
+                    OBJBLOCK, STATIC_INIT"/>
+        </module>
+        <module name="RightCurly">
+            <property name="id" value="RightCurlySame"/>
+            <property name="tokens"
+                      value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE,
+                    LITERAL_DO"/>
+        </module>
+        <module name="RightCurly">
+            <property name="id" value="RightCurlyAlone"/>
+            <property name="option" value="alone"/>
+            <property name="tokens"
+                      value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT,
+                    INSTANCE_INIT, ANNOTATION_DEF, ENUM_DEF"/>
+        </module>
+        <module name="SuppressionXpathSingleFilter">
+            <!-- suppresion is required till https://github.com/checkstyle/checkstyle/issues/7541 -->
+            <property name="id" value="RightCurlyAlone"/>
+            <property name="query" value="//RCURLY[parent::SLIST[count(./*)=1]
+                                                 or preceding-sibling::*[last()][self::LCURLY]]"/>
+        </module>
+        <module name="WhitespaceAfter">
+            <property name="tokens"
+                      value="COMMA, SEMI, TYPECAST, LITERAL_IF, LITERAL_ELSE,
+                    LITERAL_WHILE, LITERAL_DO, LITERAL_FOR, DO_WHILE"/>
+        </module>
+        <module name="WhitespaceAround">
+            <property name="allowEmptyConstructors" value="true"/>
+            <property name="allowEmptyLambdas" value="true"/>
+            <property name="allowEmptyMethods" value="true"/>
+            <property name="allowEmptyTypes" value="true"/>
+            <property name="allowEmptyLoops" value="true"/>
+            <property name="tokens"
+                      value="ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR,
+                    BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, DO_WHILE, EQUAL, GE, GT, LAMBDA, LAND,
+                    LCURLY, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY,
+                    LITERAL_FOR, LITERAL_IF, LITERAL_RETURN, LITERAL_SWITCH, LITERAL_SYNCHRONIZED,
+                     LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN,
+                     NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION, RCURLY, SL, SLIST, SL_ASSIGN, SR,
+                     SR_ASSIGN, STAR, STAR_ASSIGN, LITERAL_ASSERT, TYPE_EXTENSION_AND"/>
+            <message key="ws.notFollowed"
+                     value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
+            <message key="ws.notPreceded"
+                     value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
+        </module>
+        <module name="OneStatementPerLine"/>
+<!--        <module name="MultipleVariableDeclarations"/>-->
+        <module name="ArrayTypeStyle"/>
+        <module name="MissingSwitchDefault"/>
+        <module name="FallThrough"/>
+        <module name="UpperEll"/>
+        <module name="ModifierOrder"/>
+        <module name="EmptyLineSeparator">
+            <property name="tokens"
+                      value="PACKAGE_DEF, IMPORT, STATIC_IMPORT, CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
+                    STATIC_INIT, INSTANCE_INIT, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
+            <property name="allowNoEmptyLineBetweenFields" value="true"/>
+        </module>
+        <module name="SeparatorWrap">
+            <property name="id" value="SeparatorWrapDot"/>
+            <property name="tokens" value="DOT"/>
+            <property name="option" value="nl"/>
+        </module>
+        <module name="SeparatorWrap">
+            <property name="id" value="SeparatorWrapComma"/>
+            <property name="tokens" value="COMMA"/>
+            <property name="option" value="EOL"/>
+        </module>
+        <module name="SeparatorWrap">
+            <!-- ELLIPSIS is EOL until https://github.com/google/styleguide/issues/258 -->
+            <property name="id" value="SeparatorWrapEllipsis"/>
+            <property name="tokens" value="ELLIPSIS"/>
+            <property name="option" value="EOL"/>
+        </module>
+        <module name="SeparatorWrap">
+            <!-- ARRAY_DECLARATOR is EOL until https://github.com/google/styleguide/issues/259 -->
+            <property name="id" value="SeparatorWrapArrayDeclarator"/>
+            <property name="tokens" value="ARRAY_DECLARATOR"/>
+            <property name="option" value="EOL"/>
+        </module>
+        <module name="SeparatorWrap">
+            <property name="id" value="SeparatorWrapMethodRef"/>
+            <property name="tokens" value="METHOD_REF"/>
+            <property name="option" value="nl"/>
+        </module>
+        <module name="PackageName">
+            <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
+            <message key="name.invalidPattern"
+                     value="Package name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+        <module name="TypeName">
+            <property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, ANNOTATION_DEF"/>
+            <message key="name.invalidPattern"
+                     value="Type name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+        <module name="MemberName">
+            <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
+            <message key="name.invalidPattern"
+                     value="Member name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+        <module name="ParameterName">
+            <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
+            <message key="name.invalidPattern"
+                     value="Parameter name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+        <module name="LambdaParameterName">
+            <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
+            <message key="name.invalidPattern"
+                     value="Lambda parameter name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+        <module name="CatchParameterName">
+            <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
+            <message key="name.invalidPattern"
+                     value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+        <module name="LocalVariableName">
+            <property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
+            <message key="name.invalidPattern"
+                     value="Local variable name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+        <module name="ClassTypeParameterName">
+            <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
+            <message key="name.invalidPattern"
+                     value="Class type name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+        <module name="MethodTypeParameterName">
+            <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
+            <message key="name.invalidPattern"
+                     value="Method type name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+        <module name="InterfaceTypeParameterName">
+            <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
+            <message key="name.invalidPattern"
+                     value="Interface type name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+        <module name="NoFinalizer"/>
+        <module name="GenericWhitespace">
+            <message key="ws.followed"
+                     value="GenericWhitespace ''{0}'' is followed by whitespace."/>
+            <message key="ws.preceded"
+                     value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
+            <message key="ws.illegalFollow"
+                     value="GenericWhitespace ''{0}'' should followed by whitespace."/>
+            <message key="ws.notPreceded"
+                     value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
+        </module>
+        <module name="Indentation">
+            <property name="basicOffset" value="2"/>
+            <property name="braceAdjustment" value="0"/>
+            <property name="caseIndent" value="2"/>
+            <property name="throwsIndent" value="4"/>
+            <property name="lineWrappingIndentation" value="4"/>
+            <property name="arrayInitIndent" value="2"/>
+        </module>
+        <module name="AbbreviationAsWordInName">
+            <property name="ignoreFinal" value="false"/>
+            <property name="allowedAbbreviationLength" value="1"/>
+            <property name="tokens"
+                      value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, ANNOTATION_DEF, ANNOTATION_FIELD_DEF,
+                    PARAMETER_DEF, VARIABLE_DEF, METHOD_DEF"/>
+        </module>
+        <module name="OverloadMethodsDeclarationOrder"/>
+<!--        <module name="VariableDeclarationUsageDistance"/>-->
+        <module name="CustomImportOrder">
+            <property name="sortImportsInGroupAlphabetically" value="true"/>
+            <property name="separateLineBetweenGroups" value="true"/>
+            <property name="customImportOrderRules" value="STATIC###THIRD_PARTY_PACKAGE"/>
+            <property name="tokens" value="IMPORT, STATIC_IMPORT, PACKAGE_DEF"/>
+        </module>
+        <module name="MethodParamPad">
+            <property name="tokens"
+                      value="CTOR_DEF, LITERAL_NEW, METHOD_CALL, METHOD_DEF,
+                    SUPER_CTOR_CALL, ENUM_CONSTANT_DEF"/>
+        </module>
+        <module name="NoWhitespaceBefore">
+            <property name="tokens"
+                      value="COMMA, SEMI, POST_INC, POST_DEC, DOT, ELLIPSIS,
+                    LABELED_STAT, METHOD_REF"/>
+            <property name="allowLineBreaks" value="true"/>
+        </module>
+        <module name="ParenPad">
+            <property name="tokens"
+                      value="ANNOTATION, ANNOTATION_FIELD_DEF, CTOR_CALL, CTOR_DEF, DOT, ENUM_CONSTANT_DEF,
+                    EXPR, LITERAL_CATCH, LITERAL_DO, LITERAL_FOR, LITERAL_IF, LITERAL_NEW,
+                    LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_WHILE, METHOD_CALL,
+                    METHOD_DEF, QUESTION, RESOURCE_SPECIFICATION, SUPER_CTOR_CALL, LAMBDA"/>
+        </module>
+        <module name="OperatorWrap">
+            <property name="option" value="NL"/>
+            <property name="tokens"
+                      value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR,
+                    LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR, METHOD_REF "/>
+        </module>
+        <module name="AnnotationLocation">
+            <property name="id" value="AnnotationLocationMostCases"/>
+            <property name="tokens"
+                      value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/>
+        </module>
+        <module name="AnnotationLocation">
+            <property name="id" value="AnnotationLocationVariables"/>
+            <property name="tokens" value="VARIABLE_DEF"/>
+            <property name="allowSamelineMultipleAnnotations" value="true"/>
+        </module>
+        <module name="NonEmptyAtclauseDescription"/>
+        <module name="InvalidJavadocPosition"/>
+        <module name="JavadocTagContinuationIndentation"/>
+        <module name="SummaryJavadoc">
+            <property name="forbiddenSummaryFragments"
+                      value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
+        </module>
+        <module name="JavadocParagraph"/>
+        <module name="AtclauseOrder">
+            <property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
+            <property name="target"
+                      value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
+        </module>
+        <module name="JavadocMethod">
+            <property name="accessModifiers" value="public"/>
+            <property name="allowMissingParamTags" value="true"/>
+            <property name="allowMissingReturnTag" value="true"/>
+            <property name="allowedAnnotations" value="Override, Test"/>
+            <property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF"/>
+        </module>
+<!--        <module name="MissingJavadocMethod">-->
+<!--            <property name="scope" value="public"/>-->
+<!--            <property name="minLineCount" value="2"/>-->
+<!--            <property name="allowedAnnotations" value="Override, Test"/>-->
+<!--            <property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF"/>-->
+<!--        </module>-->
+        <module name="MethodName">
+            <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/>
+            <message key="name.invalidPattern"
+                     value="Method name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+        <module name="SingleLineJavadoc">
+            <property name="ignoreInlineTags" value="false"/>
+        </module>
+        <module name="EmptyCatchBlock">
+            <property name="exceptionVariableName" value="ignored"/>
+        </module>
+        <module name="CommentsIndentation">
+            <property name="tokens" value="SINGLE_LINE_COMMENT, BLOCK_COMMENT_BEGIN"/>
+        </module>
+        <!-- https://checkstyle.org/config_filters.html#SuppressionXpathFilter -->
+        <module name="SuppressionXpathFilter">
+            <property name="file" value="${org.checkstyle.google.suppressionxpathfilter.config}"
+                      default="checkstyle-xpath-suppressions.xml" />
+            <property name="optional" value="true"/>
+        </module>
+    </module>
+</module>

+ 2 - 2
etc/checkstyle/checkstyle.xml

@@ -318,7 +318,7 @@
             <property name="ignoreInlineTags" value="false"/>
         </module>
         <module name="EmptyCatchBlock">
-            <property name="exceptionVariableName" value="expected"/>
+            <property name="exceptionVariableName" value="ignored"/>
         </module>
         <module name="CommentsIndentation">
             <property name="tokens" value="SINGLE_LINE_COMMENT, BLOCK_COMMENT_BEGIN"/>
@@ -330,4 +330,4 @@
             <property name="optional" value="true"/>
         </module>
     </module>
-</module>
+</module>

+ 2 - 1
kafka-ui-api/Dockerfile

@@ -1,4 +1,5 @@
-FROM azul/zulu-openjdk-alpine:17-jre
+#FROM azul/zulu-openjdk-alpine:17-jre-headless
+FROM azul/zulu-openjdk-alpine@sha256:a36679ac0d28cb835e2a8c00e1e0d95509c6c51c5081c7782b85edb1f37a771a
 
 RUN apk add --no-cache gcompat # need to make snappy codec work
 RUN addgroup -S kafkaui && adduser -S kafkaui -G kafkaui

+ 177 - 35
kafka-ui-api/src/main/java/com/provectus/kafka/ui/client/RetryingKafkaConnectClient.java

@@ -6,7 +6,13 @@ import com.provectus.kafka.ui.config.ClustersProperties;
 import com.provectus.kafka.ui.connect.ApiClient;
 import com.provectus.kafka.ui.connect.api.KafkaConnectClientApi;
 import com.provectus.kafka.ui.connect.model.Connector;
+import com.provectus.kafka.ui.connect.model.ConnectorPlugin;
+import com.provectus.kafka.ui.connect.model.ConnectorPluginConfigValidationResponse;
+import com.provectus.kafka.ui.connect.model.ConnectorStatus;
+import com.provectus.kafka.ui.connect.model.ConnectorTask;
+import com.provectus.kafka.ui.connect.model.ConnectorTopics;
 import com.provectus.kafka.ui.connect.model.NewConnector;
+import com.provectus.kafka.ui.connect.model.TaskStatus;
 import com.provectus.kafka.ui.exception.KafkaConnectConflictReponseException;
 import com.provectus.kafka.ui.exception.ValidationException;
 import com.provectus.kafka.ui.util.WebClientConfigurator;
@@ -15,11 +21,7 @@ import java.util.List;
 import java.util.Map;
 import javax.annotation.Nullable;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.core.ParameterizedTypeReference;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.MediaType;
-import org.springframework.util.MultiValueMap;
+import org.springframework.http.ResponseEntity;
 import org.springframework.util.unit.DataSize;
 import org.springframework.web.client.RestClientException;
 import org.springframework.web.reactive.function.client.WebClient;
@@ -79,6 +81,176 @@ public class RetryingKafkaConnectClient extends KafkaConnectClientApi {
     );
   }
 
+  @Override
+  public Mono<ResponseEntity<Connector>> createConnectorWithHttpInfo(NewConnector newConnector)
+      throws WebClientResponseException {
+    return withRetryOnConflict(super.createConnectorWithHttpInfo(newConnector));
+  }
+
+  @Override
+  public Mono<Void> deleteConnector(String connectorName) throws WebClientResponseException {
+    return withRetryOnConflict(super.deleteConnector(connectorName));
+  }
+
+  @Override
+  public Mono<ResponseEntity<Void>> deleteConnectorWithHttpInfo(String connectorName)
+      throws WebClientResponseException {
+    return withRetryOnConflict(super.deleteConnectorWithHttpInfo(connectorName));
+  }
+
+
+  @Override
+  public Mono<Connector> getConnector(String connectorName) throws WebClientResponseException {
+    return withRetryOnConflict(super.getConnector(connectorName));
+  }
+
+  @Override
+  public Mono<ResponseEntity<Connector>> getConnectorWithHttpInfo(String connectorName)
+      throws WebClientResponseException {
+    return withRetryOnConflict(super.getConnectorWithHttpInfo(connectorName));
+  }
+
+  @Override
+  public Mono<Map<String, Object>> getConnectorConfig(String connectorName) throws WebClientResponseException {
+    return withRetryOnConflict(super.getConnectorConfig(connectorName));
+  }
+
+  @Override
+  public Mono<ResponseEntity<Map<String, Object>>> getConnectorConfigWithHttpInfo(String connectorName)
+      throws WebClientResponseException {
+    return withRetryOnConflict(super.getConnectorConfigWithHttpInfo(connectorName));
+  }
+
+  @Override
+  public Flux<ConnectorPlugin> getConnectorPlugins() throws WebClientResponseException {
+    return withRetryOnConflict(super.getConnectorPlugins());
+  }
+
+  @Override
+  public Mono<ResponseEntity<List<ConnectorPlugin>>> getConnectorPluginsWithHttpInfo()
+      throws WebClientResponseException {
+    return withRetryOnConflict(super.getConnectorPluginsWithHttpInfo());
+  }
+
+  @Override
+  public Mono<ConnectorStatus> getConnectorStatus(String connectorName) throws WebClientResponseException {
+    return withRetryOnConflict(super.getConnectorStatus(connectorName));
+  }
+
+  @Override
+  public Mono<ResponseEntity<ConnectorStatus>> getConnectorStatusWithHttpInfo(String connectorName)
+      throws WebClientResponseException {
+    return withRetryOnConflict(super.getConnectorStatusWithHttpInfo(connectorName));
+  }
+
+  @Override
+  public Mono<TaskStatus> getConnectorTaskStatus(String connectorName, Integer taskId)
+      throws WebClientResponseException {
+    return withRetryOnConflict(super.getConnectorTaskStatus(connectorName, taskId));
+  }
+
+  @Override
+  public Mono<ResponseEntity<TaskStatus>> getConnectorTaskStatusWithHttpInfo(String connectorName, Integer taskId)
+      throws WebClientResponseException {
+    return withRetryOnConflict(super.getConnectorTaskStatusWithHttpInfo(connectorName, taskId));
+  }
+
+  @Override
+  public Flux<ConnectorTask> getConnectorTasks(String connectorName) throws WebClientResponseException {
+    return withRetryOnConflict(super.getConnectorTasks(connectorName));
+  }
+
+  @Override
+  public Mono<ResponseEntity<List<ConnectorTask>>> getConnectorTasksWithHttpInfo(String connectorName)
+      throws WebClientResponseException {
+    return withRetryOnConflict(super.getConnectorTasksWithHttpInfo(connectorName));
+  }
+
+  @Override
+  public Mono<Map<String, ConnectorTopics>> getConnectorTopics(String connectorName) throws WebClientResponseException {
+    return withRetryOnConflict(super.getConnectorTopics(connectorName));
+  }
+
+  @Override
+  public Mono<ResponseEntity<Map<String, ConnectorTopics>>> getConnectorTopicsWithHttpInfo(String connectorName)
+      throws WebClientResponseException {
+    return withRetryOnConflict(super.getConnectorTopicsWithHttpInfo(connectorName));
+  }
+
+  @Override
+  public Flux<String> getConnectors(String search) throws WebClientResponseException {
+    return withRetryOnConflict(super.getConnectors(search));
+  }
+
+  @Override
+  public Mono<ResponseEntity<List<String>>> getConnectorsWithHttpInfo(String search) throws WebClientResponseException {
+    return withRetryOnConflict(super.getConnectorsWithHttpInfo(search));
+  }
+
+  @Override
+  public Mono<Void> pauseConnector(String connectorName) throws WebClientResponseException {
+    return withRetryOnConflict(super.pauseConnector(connectorName));
+  }
+
+  @Override
+  public Mono<ResponseEntity<Void>> pauseConnectorWithHttpInfo(String connectorName) throws WebClientResponseException {
+    return withRetryOnConflict(super.pauseConnectorWithHttpInfo(connectorName));
+  }
+
+  @Override
+  public Mono<Void> restartConnector(String connectorName, Boolean includeTasks, Boolean onlyFailed)
+      throws WebClientResponseException {
+    return withRetryOnConflict(super.restartConnector(connectorName, includeTasks, onlyFailed));
+  }
+
+  @Override
+  public Mono<ResponseEntity<Void>> restartConnectorWithHttpInfo(String connectorName, Boolean includeTasks,
+                                                                 Boolean onlyFailed) throws WebClientResponseException {
+    return withRetryOnConflict(super.restartConnectorWithHttpInfo(connectorName, includeTasks, onlyFailed));
+  }
+
+  @Override
+  public Mono<Void> restartConnectorTask(String connectorName, Integer taskId) throws WebClientResponseException {
+    return withRetryOnConflict(super.restartConnectorTask(connectorName, taskId));
+  }
+
+  @Override
+  public Mono<ResponseEntity<Void>> restartConnectorTaskWithHttpInfo(String connectorName, Integer taskId)
+      throws WebClientResponseException {
+    return withRetryOnConflict(super.restartConnectorTaskWithHttpInfo(connectorName, taskId));
+  }
+
+  @Override
+  public Mono<Void> resumeConnector(String connectorName) throws WebClientResponseException {
+    return super.resumeConnector(connectorName);
+  }
+
+  @Override
+  public Mono<ResponseEntity<Void>> resumeConnectorWithHttpInfo(String connectorName)
+      throws WebClientResponseException {
+    return withRetryOnConflict(super.resumeConnectorWithHttpInfo(connectorName));
+  }
+
+  @Override
+  public Mono<ResponseEntity<Connector>> setConnectorConfigWithHttpInfo(String connectorName,
+                                                                        Map<String, Object> requestBody)
+      throws WebClientResponseException {
+    return withRetryOnConflict(super.setConnectorConfigWithHttpInfo(connectorName, requestBody));
+  }
+
+  @Override
+  public Mono<ConnectorPluginConfigValidationResponse> validateConnectorPluginConfig(String pluginName,
+                                                                                     Map<String, Object> requestBody)
+      throws WebClientResponseException {
+    return withRetryOnConflict(super.validateConnectorPluginConfig(pluginName, requestBody));
+  }
+
+  @Override
+  public Mono<ResponseEntity<ConnectorPluginConfigValidationResponse>> validateConnectorPluginConfigWithHttpInfo(
+      String pluginName, Map<String, Object> requestBody) throws WebClientResponseException {
+    return withRetryOnConflict(super.validateConnectorPluginConfigWithHttpInfo(pluginName, requestBody));
+  }
+
   private static class RetryingApiClient extends ApiClient {
 
     public RetryingApiClient(ConnectCluster config,
@@ -108,35 +280,5 @@ public class RetryingKafkaConnectClient extends KafkaConnectClientApi {
           .configureBufferSize(maxBuffSize)
           .build();
     }
-
-    @Override
-    public <T> Mono<T> invokeAPI(String path, HttpMethod method, Map<String, Object> pathParams,
-                                 MultiValueMap<String, String> queryParams, Object body,
-                                 HttpHeaders headerParams,
-                                 MultiValueMap<String, String> cookieParams,
-                                 MultiValueMap<String, Object> formParams, List<MediaType> accept,
-                                 MediaType contentType, String[] authNames,
-                                 ParameterizedTypeReference<T> returnType)
-        throws RestClientException {
-      return withRetryOnConflict(
-          super.invokeAPI(path, method, pathParams, queryParams, body, headerParams, cookieParams,
-              formParams, accept, contentType, authNames, returnType)
-      );
-    }
-
-    @Override
-    public <T> Flux<T> invokeFluxAPI(String path, HttpMethod method, Map<String, Object> pathParams,
-                                     MultiValueMap<String, String> queryParams, Object body,
-                                     HttpHeaders headerParams,
-                                     MultiValueMap<String, String> cookieParams,
-                                     MultiValueMap<String, Object> formParams,
-                                     List<MediaType> accept, MediaType contentType,
-                                     String[] authNames, ParameterizedTypeReference<T> returnType)
-        throws RestClientException {
-      return withRetryOnConflict(
-          super.invokeFluxAPI(path, method, pathParams, queryParams, body, headerParams,
-              cookieParams, formParams, accept, contentType, authNames, returnType)
-      );
-    }
   }
 }

+ 1 - 1
kafka-ui-api/src/main/java/com/provectus/kafka/ui/config/ClustersProperties.java

@@ -1,6 +1,7 @@
 package com.provectus.kafka.ui.config;
 
 import com.provectus.kafka.ui.model.MetricsConfig;
+import jakarta.annotation.PostConstruct;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -8,7 +9,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import javax.annotation.Nullable;
-import javax.annotation.PostConstruct;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;

+ 1 - 1
kafka-ui-api/src/main/java/com/provectus/kafka/ui/config/auth/OAuthProperties.java

@@ -1,9 +1,9 @@
 package com.provectus.kafka.ui.config.auth;
 
+import jakarta.annotation.PostConstruct;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
-import javax.annotation.PostConstruct;
 import lombok.Data;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.util.Assert;

+ 3 - 10
kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/ApplicationConfigController.java

@@ -13,12 +13,12 @@ import com.provectus.kafka.ui.model.ClusterConfigValidationDTO;
 import com.provectus.kafka.ui.model.RestartRequestDTO;
 import com.provectus.kafka.ui.model.UploadedFileInfoDTO;
 import com.provectus.kafka.ui.model.rbac.AccessContext;
+import com.provectus.kafka.ui.service.ApplicationInfoService;
 import com.provectus.kafka.ui.service.KafkaClusterFactory;
 import com.provectus.kafka.ui.service.rbac.AccessControlService;
 import com.provectus.kafka.ui.util.ApplicationRestarter;
 import com.provectus.kafka.ui.util.DynamicConfigOperations;
 import com.provectus.kafka.ui.util.DynamicConfigOperations.PropertiesStructure;
-import java.util.List;
 import java.util.Map;
 import javax.annotation.Nullable;
 import lombok.RequiredArgsConstructor;
@@ -53,18 +53,11 @@ public class ApplicationConfigController implements ApplicationConfigApi {
   private final DynamicConfigOperations dynamicConfigOperations;
   private final ApplicationRestarter restarter;
   private final KafkaClusterFactory kafkaClusterFactory;
-
+  private final ApplicationInfoService applicationInfoService;
 
   @Override
   public Mono<ResponseEntity<ApplicationInfoDTO>> getApplicationInfo(ServerWebExchange exchange) {
-    return Mono.just(
-        new ApplicationInfoDTO()
-            .enabledFeatures(
-                dynamicConfigOperations.dynamicConfigEnabled()
-                    ? List.of(ApplicationInfoDTO.EnabledFeaturesEnum.DYNAMIC_CONFIG)
-                    : List.of()
-            )
-    ).map(ResponseEntity::ok);
+    return Mono.just(applicationInfoService.getApplicationInfo()).map(ResponseEntity::ok);
   }
 
   @Override

+ 4 - 6
kafka-ui-api/src/main/java/com/provectus/kafka/ui/controller/KafkaConnectController.java

@@ -149,10 +149,9 @@ public class KafkaConnectController extends AbstractController implements KafkaC
   }
 
   @Override
-  public Mono<ResponseEntity<ConnectorDTO>> setConnectorConfig(String clusterName,
-                                                               String connectName,
+  public Mono<ResponseEntity<ConnectorDTO>> setConnectorConfig(String clusterName, String connectName,
                                                                String connectorName,
-                                                               @Valid Mono<Object> requestBody,
+                                                               Mono<Map<String, Object>> requestBody,
                                                                ServerWebExchange exchange) {
 
     Mono<Void> validateAccess = accessControlService.validateAccess(AccessContext.builder()
@@ -164,8 +163,7 @@ public class KafkaConnectController extends AbstractController implements KafkaC
     return validateAccess.then(
         kafkaConnectService
             .setConnectorConfig(getCluster(clusterName), connectName, connectorName, requestBody)
-            .map(ResponseEntity::ok)
-    );
+            .map(ResponseEntity::ok));
   }
 
   @Override
@@ -242,7 +240,7 @@ public class KafkaConnectController extends AbstractController implements KafkaC
 
   @Override
   public Mono<ResponseEntity<ConnectorPluginConfigValidationResponseDTO>> validateConnectorPluginConfig(
-      String clusterName, String connectName, String pluginName, @Valid Mono<Object> requestBody,
+      String clusterName, String connectName, String pluginName, @Valid Mono<Map<String, Object>> requestBody,
       ServerWebExchange exchange) {
     return kafkaConnectService
         .validateConnectorPluginConfig(

+ 14 - 30
kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/AbstractEmitter.java

@@ -1,9 +1,6 @@
 package com.provectus.kafka.ui.emitter;
 
-import com.provectus.kafka.ui.model.TopicMessageDTO;
 import com.provectus.kafka.ui.model.TopicMessageEventDTO;
-import com.provectus.kafka.ui.model.TopicMessagePhaseDTO;
-import com.provectus.kafka.ui.serdes.ConsumerRecordDeserializer;
 import java.time.Duration;
 import java.time.Instant;
 import org.apache.kafka.clients.consumer.Consumer;
@@ -14,13 +11,12 @@ import reactor.core.publisher.FluxSink;
 
 public abstract class AbstractEmitter {
 
-  private final ConsumerRecordDeserializer recordDeserializer;
-  private final ConsumingStats consumingStats = new ConsumingStats();
+  private final MessagesProcessing messagesProcessing;
   private final PollingThrottler throttler;
   protected final PollingSettings pollingSettings;
 
-  protected AbstractEmitter(ConsumerRecordDeserializer recordDeserializer, PollingSettings pollingSettings) {
-    this.recordDeserializer = recordDeserializer;
+  protected AbstractEmitter(MessagesProcessing messagesProcessing, PollingSettings pollingSettings) {
+    this.messagesProcessing = messagesProcessing;
     this.pollingSettings = pollingSettings;
     this.throttler = pollingSettings.getPollingThrottler();
   }
@@ -40,39 +36,27 @@ public abstract class AbstractEmitter {
     return records;
   }
 
+  protected boolean sendLimitReached() {
+    return messagesProcessing.limitReached();
+  }
+
   protected void sendMessage(FluxSink<TopicMessageEventDTO> sink,
-                                                       ConsumerRecord<Bytes, Bytes> msg) {
-    final TopicMessageDTO topicMessage = recordDeserializer.deserialize(msg);
-    sink.next(
-        new TopicMessageEventDTO()
-            .type(TopicMessageEventDTO.TypeEnum.MESSAGE)
-            .message(topicMessage)
-    );
+                             ConsumerRecord<Bytes, Bytes> msg) {
+    messagesProcessing.sendMsg(sink, msg);
   }
 
   protected void sendPhase(FluxSink<TopicMessageEventDTO> sink, String name) {
-    sink.next(
-        new TopicMessageEventDTO()
-            .type(TopicMessageEventDTO.TypeEnum.PHASE)
-            .phase(new TopicMessagePhaseDTO().name(name))
-    );
+    messagesProcessing.sendPhase(sink, name);
   }
 
   protected int sendConsuming(FluxSink<TopicMessageEventDTO> sink,
-                               ConsumerRecords<Bytes, Bytes> records,
-                               long elapsed) {
-    return consumingStats.sendConsumingEvt(sink, records, elapsed, getFilterApplyErrors(sink));
+                              ConsumerRecords<Bytes, Bytes> records,
+                              long elapsed) {
+    return messagesProcessing.sentConsumingInfo(sink, records, elapsed);
   }
 
   protected void sendFinishStatsAndCompleteSink(FluxSink<TopicMessageEventDTO> sink) {
-    consumingStats.sendFinishEvent(sink, getFilterApplyErrors(sink));
+    messagesProcessing.sendFinishEvent(sink);
     sink.complete();
   }
-
-  protected Number getFilterApplyErrors(FluxSink<?> sink) {
-    return sink.contextView()
-        .<MessageFilterStats>getOrEmpty(MessageFilterStats.class)
-        .<Number>map(MessageFilterStats::getFilterApplyErrors)
-        .orElse(0);
-  }
 }

+ 4 - 6
kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/BackwardRecordEmitter.java

@@ -2,7 +2,6 @@ package com.provectus.kafka.ui.emitter;
 
 import com.provectus.kafka.ui.model.ConsumerPosition;
 import com.provectus.kafka.ui.model.TopicMessageEventDTO;
-import com.provectus.kafka.ui.serdes.ConsumerRecordDeserializer;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -31,9 +30,9 @@ public class BackwardRecordEmitter
       Supplier<KafkaConsumer<Bytes, Bytes>> consumerSupplier,
       ConsumerPosition consumerPosition,
       int messagesPerPage,
-      ConsumerRecordDeserializer recordDeserializer,
+      MessagesProcessing messagesProcessing,
       PollingSettings pollingSettings) {
-    super(recordDeserializer, pollingSettings);
+    super(messagesProcessing, pollingSettings);
     this.consumerPosition = consumerPosition;
     this.messagesPerPage = messagesPerPage;
     this.consumerSupplier = consumerSupplier;
@@ -52,7 +51,7 @@ public class BackwardRecordEmitter
       int msgsToPollPerPartition = (int) Math.ceil((double) messagesPerPage / readUntilOffsets.size());
       log.debug("'Until' offsets for polling: {}", readUntilOffsets);
 
-      while (!sink.isCancelled() && !readUntilOffsets.isEmpty()) {
+      while (!sink.isCancelled() && !readUntilOffsets.isEmpty() && !sendLimitReached()) {
         new TreeMap<>(readUntilOffsets).forEach((tp, readToOffset) -> {
           if (sink.isCancelled()) {
             return; //fast return in case of sink cancellation
@@ -61,8 +60,6 @@ public class BackwardRecordEmitter
           long readFromOffset = Math.max(beginOffset, readToOffset - msgsToPollPerPartition);
 
           partitionPollIteration(tp, readFromOffset, readToOffset, consumer, sink)
-              .stream()
-              .filter(r -> !sink.isCancelled())
               .forEach(r -> sendMessage(sink, r));
 
           if (beginOffset == readFromOffset) {
@@ -106,6 +103,7 @@ public class BackwardRecordEmitter
 
     EmptyPollsCounter emptyPolls  = pollingSettings.createEmptyPollsCounter();
     while (!sink.isCancelled()
+        && !sendLimitReached()
         && recordsToSend.size() < desiredMsgsToPoll
         && !emptyPolls.noDataEmptyPollsReached()) {
       var polledRecords = poll(sink, consumer, pollingSettings.getPartitionPollTimeout());

+ 4 - 4
kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/ConsumingStats.java

@@ -19,7 +19,7 @@ class ConsumingStats {
   int sendConsumingEvt(FluxSink<TopicMessageEventDTO> sink,
                         ConsumerRecords<Bytes, Bytes> polledRecords,
                         long elapsed,
-                        Number filterApplyErrors) {
+                        int filterApplyErrors) {
     int polledBytes = ConsumerRecordsUtil.calculatePolledSize(polledRecords);
     bytes += polledBytes;
     this.records += polledRecords.count();
@@ -32,7 +32,7 @@ class ConsumingStats {
     return polledBytes;
   }
 
-  void sendFinishEvent(FluxSink<TopicMessageEventDTO> sink, Number filterApplyErrors) {
+  void sendFinishEvent(FluxSink<TopicMessageEventDTO> sink, int filterApplyErrors) {
     sink.next(
         new TopicMessageEventDTO()
             .type(TopicMessageEventDTO.TypeEnum.DONE)
@@ -41,12 +41,12 @@ class ConsumingStats {
   }
 
   private TopicMessageConsumingDTO createConsumingStats(FluxSink<TopicMessageEventDTO> sink,
-                                                        Number filterApplyErrors) {
+                                                        int filterApplyErrors) {
     return new TopicMessageConsumingDTO()
         .bytesConsumed(this.bytes)
         .elapsedMs(this.elapsed)
         .isCancelled(sink.isCancelled())
-        .filterApplyErrors(filterApplyErrors.intValue())
+        .filterApplyErrors(filterApplyErrors)
         .messagesConsumed(this.records);
   }
 }

+ 4 - 8
kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/ForwardRecordEmitter.java

@@ -2,7 +2,6 @@ package com.provectus.kafka.ui.emitter;
 
 import com.provectus.kafka.ui.model.ConsumerPosition;
 import com.provectus.kafka.ui.model.TopicMessageEventDTO;
-import com.provectus.kafka.ui.serdes.ConsumerRecordDeserializer;
 import java.util.function.Supplier;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.kafka.clients.consumer.ConsumerRecord;
@@ -23,9 +22,9 @@ public class ForwardRecordEmitter
   public ForwardRecordEmitter(
       Supplier<KafkaConsumer<Bytes, Bytes>> consumerSupplier,
       ConsumerPosition position,
-      ConsumerRecordDeserializer recordDeserializer,
+      MessagesProcessing messagesProcessing,
       PollingSettings pollingSettings) {
-    super(recordDeserializer, pollingSettings);
+    super(messagesProcessing, pollingSettings);
     this.position = position;
     this.consumerSupplier = consumerSupplier;
   }
@@ -40,6 +39,7 @@ public class ForwardRecordEmitter
 
       EmptyPollsCounter emptyPolls = pollingSettings.createEmptyPollsCounter();
       while (!sink.isCancelled()
+          && !sendLimitReached()
           && !seekOperations.assignedPartitionsFullyPolled()
           && !emptyPolls.noDataEmptyPollsReached()) {
 
@@ -50,11 +50,7 @@ public class ForwardRecordEmitter
         log.debug("{} records polled", records.count());
 
         for (ConsumerRecord<Bytes, Bytes> msg : records) {
-          if (!sink.isCancelled()) {
-            sendMessage(sink, msg);
-          } else {
-            break;
-          }
+          sendMessage(sink, msg);
         }
       }
       sendFinishStatsAndCompleteSink(sink);

+ 0 - 16
kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/MessageFilterStats.java

@@ -1,16 +0,0 @@
-package com.provectus.kafka.ui.emitter;
-
-import java.util.concurrent.atomic.AtomicLong;
-import lombok.AccessLevel;
-import lombok.Getter;
-
-public class MessageFilterStats {
-
-  @Getter(AccessLevel.PACKAGE)
-  private final AtomicLong filterApplyErrors = new AtomicLong();
-
-  public final void incrementApplyErrors() {
-    filterApplyErrors.incrementAndGet();
-  }
-
-}

+ 82 - 0
kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/MessagesProcessing.java

@@ -0,0 +1,82 @@
+package com.provectus.kafka.ui.emitter;
+
+import com.provectus.kafka.ui.model.TopicMessageDTO;
+import com.provectus.kafka.ui.model.TopicMessageEventDTO;
+import com.provectus.kafka.ui.model.TopicMessagePhaseDTO;
+import com.provectus.kafka.ui.serdes.ConsumerRecordDeserializer;
+import java.util.function.Predicate;
+import javax.annotation.Nullable;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.apache.kafka.clients.consumer.ConsumerRecords;
+import org.apache.kafka.common.utils.Bytes;
+import reactor.core.publisher.FluxSink;
+
+@Slf4j
+public class MessagesProcessing {
+
+  private final ConsumingStats consumingStats = new ConsumingStats();
+  private long sentMessages = 0;
+  private int filterApplyErrors = 0;
+
+  private final ConsumerRecordDeserializer deserializer;
+  private final Predicate<TopicMessageDTO> filter;
+  private final @Nullable Integer limit;
+
+  public MessagesProcessing(ConsumerRecordDeserializer deserializer,
+                            Predicate<TopicMessageDTO> filter,
+                            @Nullable Integer limit) {
+    this.deserializer = deserializer;
+    this.filter = filter;
+    this.limit = limit;
+  }
+
+  boolean limitReached() {
+    return limit != null && sentMessages >= limit;
+  }
+
+  void sendMsg(FluxSink<TopicMessageEventDTO> sink, ConsumerRecord<Bytes, Bytes> rec) {
+    if (!sink.isCancelled() && !limitReached()) {
+      TopicMessageDTO topicMessage = deserializer.deserialize(rec);
+      try {
+        if (filter.test(topicMessage)) {
+          sink.next(
+              new TopicMessageEventDTO()
+                  .type(TopicMessageEventDTO.TypeEnum.MESSAGE)
+                  .message(topicMessage)
+          );
+          sentMessages++;
+        }
+      } catch (Exception e) {
+        filterApplyErrors++;
+        log.trace("Error applying filter for message {}", topicMessage);
+      }
+    }
+  }
+
+  int sentConsumingInfo(FluxSink<TopicMessageEventDTO> sink,
+                        ConsumerRecords<Bytes, Bytes> polledRecords,
+                        long elapsed) {
+    if (!sink.isCancelled()) {
+      return consumingStats.sendConsumingEvt(sink, polledRecords, elapsed, filterApplyErrors);
+    }
+    return 0;
+  }
+
+  void sendFinishEvent(FluxSink<TopicMessageEventDTO> sink) {
+    if (!sink.isCancelled()) {
+      consumingStats.sendFinishEvent(sink, filterApplyErrors);
+    }
+  }
+
+  void sendPhase(FluxSink<TopicMessageEventDTO> sink, String name) {
+    if (!sink.isCancelled()) {
+      sink.next(
+          new TopicMessageEventDTO()
+              .type(TopicMessageEventDTO.TypeEnum.PHASE)
+              .phase(new TopicMessagePhaseDTO().name(name))
+      );
+    }
+  }
+
+}

+ 2 - 3
kafka-ui-api/src/main/java/com/provectus/kafka/ui/emitter/TailingEmitter.java

@@ -2,7 +2,6 @@ package com.provectus.kafka.ui.emitter;
 
 import com.provectus.kafka.ui.model.ConsumerPosition;
 import com.provectus.kafka.ui.model.TopicMessageEventDTO;
-import com.provectus.kafka.ui.serdes.ConsumerRecordDeserializer;
 import java.util.HashMap;
 import java.util.function.Supplier;
 import lombok.extern.slf4j.Slf4j;
@@ -20,9 +19,9 @@ public class TailingEmitter extends AbstractEmitter
 
   public TailingEmitter(Supplier<KafkaConsumer<Bytes, Bytes>> consumerSupplier,
                         ConsumerPosition consumerPosition,
-                        ConsumerRecordDeserializer recordDeserializer,
+                        MessagesProcessing messagesProcessing,
                         PollingSettings pollingSettings) {
-    super(recordDeserializer, pollingSettings);
+    super(messagesProcessing, pollingSettings);
     this.consumerSupplier = consumerSupplier;
     this.consumerPosition = consumerPosition;
   }

+ 1 - 1
kafka-ui-api/src/main/java/com/provectus/kafka/ui/exception/GlobalErrorWebExceptionHandler.java

@@ -134,7 +134,7 @@ public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHan
         .timestamp(currentTimestamp())
         .stackTrace(Throwables.getStackTraceAsString(exception));
     return ServerResponse
-        .status(exception.getStatus())
+        .status(exception.getStatusCode())
         .contentType(MediaType.APPLICATION_JSON)
         .bodyValue(response);
   }

+ 4 - 1
kafka-ui-api/src/main/java/com/provectus/kafka/ui/model/rbac/Permission.java

@@ -1,5 +1,6 @@
 package com.provectus.kafka.ui.model.rbac;
 
+import static com.provectus.kafka.ui.model.rbac.Resource.APPLICATIONCONFIG;
 import static com.provectus.kafka.ui.model.rbac.Resource.CLUSTERCONFIG;
 import static com.provectus.kafka.ui.model.rbac.Resource.KSQL;
 
@@ -25,6 +26,8 @@ import org.springframework.util.Assert;
 @EqualsAndHashCode
 public class Permission {
 
+  private static final List<Resource> RBAC_ACTION_EXEMPT_LIST = List.of(KSQL, CLUSTERCONFIG, APPLICATIONCONFIG);
+
   Resource resource;
   List<String> actions;
 
@@ -50,7 +53,7 @@ public class Permission {
 
   public void validate() {
     Assert.notNull(resource, "resource cannot be null");
-    if (!List.of(KSQL, CLUSTERCONFIG).contains(this.resource)) {
+    if (!RBAC_ACTION_EXEMPT_LIST.contains(this.resource)) {
       Assert.notNull(value, "permission value can't be empty for resource " + resource);
     }
   }

+ 76 - 0
kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ApplicationInfoService.java

@@ -0,0 +1,76 @@
+package com.provectus.kafka.ui.service;
+
+import static com.provectus.kafka.ui.model.ApplicationInfoDTO.EnabledFeaturesEnum;
+
+import com.provectus.kafka.ui.model.ApplicationInfoBuildDTO;
+import com.provectus.kafka.ui.model.ApplicationInfoDTO;
+import com.provectus.kafka.ui.model.ApplicationInfoLatestReleaseDTO;
+import com.provectus.kafka.ui.util.DynamicConfigOperations;
+import com.provectus.kafka.ui.util.GithubReleaseInfo;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.Properties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.info.BuildProperties;
+import org.springframework.boot.info.GitProperties;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ApplicationInfoService {
+
+  private final GithubReleaseInfo githubReleaseInfo = new GithubReleaseInfo();
+
+  private final DynamicConfigOperations dynamicConfigOperations;
+  private final BuildProperties buildProperties;
+  private final GitProperties gitProperties;
+
+  public ApplicationInfoService(DynamicConfigOperations dynamicConfigOperations,
+                                @Autowired(required = false) BuildProperties buildProperties,
+                                @Autowired(required = false) GitProperties gitProperties) {
+    this.dynamicConfigOperations = dynamicConfigOperations;
+    this.buildProperties = Optional.ofNullable(buildProperties).orElse(new BuildProperties(new Properties()));
+    this.gitProperties = Optional.ofNullable(gitProperties).orElse(new GitProperties(new Properties()));
+  }
+
+  public ApplicationInfoDTO getApplicationInfo() {
+    var releaseInfo = githubReleaseInfo.get();
+    return new ApplicationInfoDTO()
+        .build(getBuildInfo(releaseInfo))
+        .enabledFeatures(getEnabledFeatures())
+        .latestRelease(convert(releaseInfo));
+  }
+
+  private ApplicationInfoLatestReleaseDTO convert(GithubReleaseInfo.GithubReleaseDto releaseInfo) {
+    return new ApplicationInfoLatestReleaseDTO()
+        .htmlUrl(releaseInfo.html_url())
+        .publishedAt(releaseInfo.published_at())
+        .versionTag(releaseInfo.tag_name());
+  }
+
+  private ApplicationInfoBuildDTO getBuildInfo(GithubReleaseInfo.GithubReleaseDto release) {
+    return new ApplicationInfoBuildDTO()
+        .isLatestRelease(release.tag_name() != null && release.tag_name().equals(buildProperties.getVersion()))
+        .commitId(gitProperties.getShortCommitId())
+        .version(buildProperties.getVersion())
+        .buildTime(buildProperties.getTime() != null
+            ? DateTimeFormatter.ISO_INSTANT.format(buildProperties.getTime()) : null);
+  }
+
+  private List<EnabledFeaturesEnum> getEnabledFeatures() {
+    var enabledFeatures = new ArrayList<EnabledFeaturesEnum>();
+    if (dynamicConfigOperations.dynamicConfigEnabled()) {
+      enabledFeatures.add(EnabledFeaturesEnum.DYNAMIC_CONFIG);
+    }
+    return enabledFeatures;
+  }
+
+  // updating on startup and every hour
+  @Scheduled(fixedRateString = "${github-release-info-update-rate:3600000}")
+  public void updateGithubReleaseInfo() {
+    githubReleaseInfo.refresh().block();
+  }
+
+}

+ 49 - 16
kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/KafkaConfigSanitizer.java

@@ -1,38 +1,58 @@
 package com.provectus.kafka.ui.service;
 
+import static java.util.regex.Pattern.CASE_INSENSITIVE;
+
+import com.google.common.collect.ImmutableList;
 import java.util.Arrays;
-import java.util.HashSet;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import org.apache.kafka.common.config.ConfigDef;
 import org.apache.kafka.common.config.SaslConfigs;
 import org.apache.kafka.common.config.SslConfigs;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.actuate.endpoint.Sanitizer;
 import org.springframework.stereotype.Component;
 
 @Component
-class KafkaConfigSanitizer extends Sanitizer {
-  private static final List<String> DEFAULT_PATTERNS_TO_SANITIZE = Arrays.asList(
-      "basic.auth.user.info",  /* For Schema Registry credentials */
-      "password", "secret", "token", "key", ".*credentials.*",   /* General credential patterns */
-      "aws.access.*", "aws.secret.*", "aws.session.*"   /* AWS-related credential patterns */
-  );
+class KafkaConfigSanitizer  {
+
+  private static final String SANITIZED_VALUE = "******";
+
+  private static final String[] REGEX_PARTS = {"*", "$", "^", "+"};
+
+  private static final List<String> DEFAULT_PATTERNS_TO_SANITIZE = ImmutableList.<String>builder()
+      .addAll(kafkaConfigKeysToSanitize())
+      .add(
+          "basic.auth.user.info",  /* For Schema Registry credentials */
+          "password", "secret", "token", "key", ".*credentials.*",   /* General credential patterns */
+          "aws.access.*", "aws.secret.*", "aws.session.*"   /* AWS-related credential patterns */
+      )
+      .build();
+
+  private final List<Pattern> sanitizeKeysPatterns;
 
   KafkaConfigSanitizer(
       @Value("${kafka.config.sanitizer.enabled:true}") boolean enabled,
       @Value("${kafka.config.sanitizer.patterns:}") List<String> patternsToSanitize
   ) {
-    if (!enabled) {
-      setKeysToSanitize();
-    } else {
-      var keysToSanitize = new HashSet<>(
-          patternsToSanitize.isEmpty() ? DEFAULT_PATTERNS_TO_SANITIZE : patternsToSanitize);
-      keysToSanitize.addAll(kafkaConfigKeysToSanitize());
-      setKeysToSanitize(keysToSanitize.toArray(new String[] {}));
-    }
+    this.sanitizeKeysPatterns = enabled
+        ? compile(patternsToSanitize.isEmpty() ? DEFAULT_PATTERNS_TO_SANITIZE : patternsToSanitize)
+        : List.of();
+  }
+
+  private static List<Pattern> compile(Collection<String> patternStrings) {
+    return patternStrings.stream()
+        .map(p -> isRegex(p)
+            ? Pattern.compile(p, CASE_INSENSITIVE)
+            : Pattern.compile(".*" + p + "$", CASE_INSENSITIVE))
+        .toList();
+  }
+
+  private static boolean isRegex(String str) {
+    return Arrays.stream(REGEX_PARTS).anyMatch(str::contains);
   }
 
   private static Set<String> kafkaConfigKeysToSanitize() {
@@ -45,4 +65,17 @@ class KafkaConfigSanitizer extends Sanitizer {
         .collect(Collectors.toSet());
   }
 
+  public Object sanitize(String key, Object value) {
+    if (value == null) {
+      return null;
+    }
+    for (Pattern pattern : sanitizeKeysPatterns) {
+      if (pattern.matcher(key).matches()) {
+        return SANITIZED_VALUE;
+      }
+    }
+    return value;
+  }
+
+
 }

+ 4 - 4
kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/KafkaConnectService.java

@@ -225,11 +225,11 @@ public class KafkaConnectService {
   }
 
   public Mono<ConnectorDTO> setConnectorConfig(KafkaCluster cluster, String connectName,
-                                               String connectorName, Mono<Object> requestBody) {
+                                               String connectorName, Mono<Map<String, Object>> requestBody) {
     return api(cluster, connectName)
         .mono(c ->
             requestBody
-                .flatMap(body -> c.setConnectorConfig(connectorName, (Map<String, Object>) body))
+                .flatMap(body -> c.setConnectorConfig(connectorName, body))
                 .map(kafkaConnectMapper::fromClient));
   }
 
@@ -298,12 +298,12 @@ public class KafkaConnectService {
   }
 
   public Mono<ConnectorPluginConfigValidationResponseDTO> validateConnectorPluginConfig(
-      KafkaCluster cluster, String connectName, String pluginName, Mono<Object> requestBody) {
+      KafkaCluster cluster, String connectName, String pluginName, Mono<Map<String, Object>> requestBody) {
     return api(cluster, connectName)
         .mono(client ->
             requestBody
                 .flatMap(body ->
-                    client.validateConnectorPluginConfig(pluginName, (Map<String, Object>) body))
+                    client.validateConnectorPluginConfig(pluginName, body))
                 .map(kafkaConnectMapper::fromClient)
         );
   }

+ 18 - 39
kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/MessagesService.java

@@ -3,9 +3,8 @@ package com.provectus.kafka.ui.service;
 import com.google.common.util.concurrent.RateLimiter;
 import com.provectus.kafka.ui.emitter.BackwardRecordEmitter;
 import com.provectus.kafka.ui.emitter.ForwardRecordEmitter;
-import com.provectus.kafka.ui.emitter.MessageFilterStats;
 import com.provectus.kafka.ui.emitter.MessageFilters;
-import com.provectus.kafka.ui.emitter.ResultSizeLimiter;
+import com.provectus.kafka.ui.emitter.MessagesProcessing;
 import com.provectus.kafka.ui.emitter.TailingEmitter;
 import com.provectus.kafka.ui.exception.TopicNotFoundException;
 import com.provectus.kafka.ui.exception.ValidationException;
@@ -14,9 +13,9 @@ import com.provectus.kafka.ui.model.CreateTopicMessageDTO;
 import com.provectus.kafka.ui.model.KafkaCluster;
 import com.provectus.kafka.ui.model.MessageFilterTypeDTO;
 import com.provectus.kafka.ui.model.SeekDirectionDTO;
+import com.provectus.kafka.ui.model.TopicMessageDTO;
 import com.provectus.kafka.ui.model.TopicMessageEventDTO;
 import com.provectus.kafka.ui.serde.api.Serde;
-import com.provectus.kafka.ui.serdes.ConsumerRecordDeserializer;
 import com.provectus.kafka.ui.serdes.ProducerRecordCreator;
 import com.provectus.kafka.ui.util.SslPropertiesUtil;
 import java.util.List;
@@ -162,13 +161,18 @@ public class MessagesService {
                                                       @Nullable String valueSerde) {
 
     java.util.function.Consumer<? super FluxSink<TopicMessageEventDTO>> emitter;
-    ConsumerRecordDeserializer recordDeserializer =
-        deserializationService.deserializerFor(cluster, topic, keySerde, valueSerde);
+
+    var processing = new MessagesProcessing(
+        deserializationService.deserializerFor(cluster, topic, keySerde, valueSerde),
+        getMsgFilter(query, filterQueryType),
+        seekDirection == SeekDirectionDTO.TAILING ? null : limit
+    );
+
     if (seekDirection.equals(SeekDirectionDTO.FORWARD)) {
       emitter = new ForwardRecordEmitter(
           () -> consumerGroupService.createConsumer(cluster),
           consumerPosition,
-          recordDeserializer,
+          processing,
           cluster.getPollingSettings()
       );
     } else if (seekDirection.equals(SeekDirectionDTO.BACKWARD)) {
@@ -176,33 +180,22 @@ public class MessagesService {
           () -> consumerGroupService.createConsumer(cluster),
           consumerPosition,
           limit,
-          recordDeserializer,
+          processing,
           cluster.getPollingSettings()
       );
     } else {
       emitter = new TailingEmitter(
           () -> consumerGroupService.createConsumer(cluster),
           consumerPosition,
-          recordDeserializer,
+          processing,
           cluster.getPollingSettings()
       );
     }
-    MessageFilterStats filterStats = new MessageFilterStats();
     return Flux.create(emitter)
-        .contextWrite(ctx -> ctx.put(MessageFilterStats.class, filterStats))
-        .filter(getMsgFilter(query, filterQueryType, filterStats))
         .map(getDataMasker(cluster, topic))
-        .takeWhile(createTakeWhilePredicate(seekDirection, limit))
         .map(throttleUiPublish(seekDirection));
   }
 
-  private Predicate<TopicMessageEventDTO> createTakeWhilePredicate(
-      SeekDirectionDTO seekDirection, int limit) {
-    return seekDirection == SeekDirectionDTO.TAILING
-        ? evt -> true // no limit for tailing
-        : new ResultSizeLimiter(limit);
-  }
-
   private UnaryOperator<TopicMessageEventDTO> getDataMasker(KafkaCluster cluster, String topicName) {
     var keyMasker = cluster.getMasking().getMaskingFunction(topicName, Serde.Target.KEY);
     var valMasker = cluster.getMasking().getMaskingFunction(topicName, Serde.Target.VALUE);
@@ -211,32 +204,18 @@ public class MessagesService {
         return evt;
       }
       return evt.message(
-        evt.getMessage()
-            .key(keyMasker.apply(evt.getMessage().getKey()))
-            .content(valMasker.apply(evt.getMessage().getContent())));
+          evt.getMessage()
+              .key(keyMasker.apply(evt.getMessage().getKey()))
+              .content(valMasker.apply(evt.getMessage().getContent())));
     };
   }
 
-  private Predicate<TopicMessageEventDTO> getMsgFilter(String query,
-                                                       MessageFilterTypeDTO filterQueryType,
-                                                       MessageFilterStats filterStats) {
+  private Predicate<TopicMessageDTO> getMsgFilter(String query,
+                                                  MessageFilterTypeDTO filterQueryType) {
     if (StringUtils.isEmpty(query)) {
       return evt -> true;
     }
-    var messageFilter = MessageFilters.createMsgFilter(query, filterQueryType);
-    return evt -> {
-      // we only apply filter for message events
-      if (evt.getType() == TopicMessageEventDTO.TypeEnum.MESSAGE) {
-        try {
-          return messageFilter.test(evt.getMessage());
-        } catch (Exception e) {
-          filterStats.incrementApplyErrors();
-          log.trace("Error applying filter '{}' for message {}", query, evt.getMessage());
-          return false;
-        }
-      }
-      return true;
-    };
+    return MessageFilters.createMsgFilter(query, filterQueryType);
   }
 
   private <T> UnaryOperator<T> throttleUiPublish(SeekDirectionDTO seekDirection) {

+ 29 - 10
kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/ReactiveAdminClient.java

@@ -4,6 +4,7 @@ import static java.util.stream.Collectors.toList;
 import static java.util.stream.Collectors.toMap;
 import static org.apache.kafka.clients.admin.ListOffsetsResult.ListOffsetsResultInfo;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableTable;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Table;
@@ -498,6 +499,14 @@ public class ReactiveAdminClient implements Closeable {
         .flatMap(parts -> listOffsetsUnsafe(parts, offsetSpec));
   }
 
+  /**
+   * List offset for the specified topics, skipping no-leader partitions.
+   */
+  public Mono<Map<TopicPartition, Long>> listOffsets(Collection<TopicDescription> topicDescriptions,
+                                                     OffsetSpec offsetSpec) {
+    return listOffsetsUnsafe(filterPartitionsWithLeaderCheck(topicDescriptions, p -> true, false), offsetSpec);
+  }
+
   private Mono<Collection<TopicPartition>> filterPartitionsWithLeaderCheck(Collection<TopicPartition> partitions,
                                                                            boolean failOnUnknownLeader) {
     var targetTopics = partitions.stream().map(TopicPartition::topic).collect(Collectors.toSet());
@@ -507,34 +516,44 @@ public class ReactiveAdminClient implements Closeable {
                 descriptions.values(), partitions::contains, failOnUnknownLeader));
   }
 
-  private Set<TopicPartition> filterPartitionsWithLeaderCheck(Collection<TopicDescription> topicDescriptions,
+  @VisibleForTesting
+  static Set<TopicPartition> filterPartitionsWithLeaderCheck(Collection<TopicDescription> topicDescriptions,
                                                               Predicate<TopicPartition> partitionPredicate,
                                                               boolean failOnUnknownLeader) {
     var goodPartitions = new HashSet<TopicPartition>();
     for (TopicDescription description : topicDescriptions) {
+      var goodTopicPartitions = new ArrayList<TopicPartition>();
       for (TopicPartitionInfo partitionInfo : description.partitions()) {
         TopicPartition topicPartition = new TopicPartition(description.name(), partitionInfo.partition());
-        if (!partitionPredicate.test(topicPartition)) {
-          continue;
+        if (partitionInfo.leader() == null) {
+          if (failOnUnknownLeader) {
+            throw new ValidationException(String.format("Topic partition %s has no leader", topicPartition));
+          } else {
+            // if ANY of topic partitions has no leader - we have to skip all topic partitions
+            goodTopicPartitions.clear();
+            break;
+          }
         }
-        if (partitionInfo.leader() != null) {
-          goodPartitions.add(topicPartition);
-        } else if (failOnUnknownLeader) {
-          throw new ValidationException(String.format("Topic partition %s has no leader", topicPartition));
+        if (partitionPredicate.test(topicPartition)) {
+          goodTopicPartitions.add(topicPartition);
         }
       }
+      goodPartitions.addAll(goodTopicPartitions);
     }
     return goodPartitions;
   }
 
-  // 1. NOTE(!): should only apply for partitions with existing leader,
+  // 1. NOTE(!): should only apply for partitions from topics where all partitions have leaders,
   //    otherwise AdminClient will try to fetch topic metadata, fail and retry infinitely (until timeout)
   // 2. NOTE(!): Skips partitions that were not initialized yet
   //    (UnknownTopicOrPartitionException thrown, ex. after topic creation)
   // 3. TODO: check if it is a bug that AdminClient never throws LeaderNotAvailableException and just retrying instead
   @KafkaClientInternalsDependant
-  public Mono<Map<TopicPartition, Long>> listOffsetsUnsafe(Collection<TopicPartition> partitions,
-                                                           OffsetSpec offsetSpec) {
+  @VisibleForTesting
+  Mono<Map<TopicPartition, Long>> listOffsetsUnsafe(Collection<TopicPartition> partitions, OffsetSpec offsetSpec) {
+    if (partitions.isEmpty()) {
+      return Mono.just(Map.of());
+    }
 
     Function<Collection<TopicPartition>, Mono<Map<TopicPartition, Long>>> call =
         parts -> {

+ 7 - 14
kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/TopicsService.java

@@ -3,6 +3,7 @@ package com.provectus.kafka.ui.service;
 import static java.util.stream.Collectors.toList;
 import static java.util.stream.Collectors.toMap;
 
+import com.google.common.collect.Sets;
 import com.provectus.kafka.ui.config.ClustersProperties;
 import com.provectus.kafka.ui.exception.TopicMetadataException;
 import com.provectus.kafka.ui.exception.TopicNotFoundException;
@@ -136,22 +137,14 @@ public class TopicsService {
   }
 
   private Mono<InternalPartitionsOffsets> getPartitionOffsets(Map<String, TopicDescription>
-                                                                  descriptions,
+                                                                  descriptionsMap,
                                                               ReactiveAdminClient ac) {
-    var topicPartitions = descriptions.values().stream()
-        .flatMap(desc ->
-            desc.partitions().stream()
-                // list offsets should only be applied to partitions with existing leader
-                // (see ReactiveAdminClient.listOffsetsUnsafe(..) docs)
-                .filter(tp -> tp.leader() != null)
-                .map(p -> new TopicPartition(desc.name(), p.partition())))
-        .collect(toList());
-
-    return ac.listOffsetsUnsafe(topicPartitions, OffsetSpec.earliest())
-        .zipWith(ac.listOffsetsUnsafe(topicPartitions, OffsetSpec.latest()),
+    var descriptions = descriptionsMap.values();
+    return ac.listOffsets(descriptions, OffsetSpec.earliest())
+        .zipWith(ac.listOffsets(descriptions, OffsetSpec.latest()),
             (earliest, latest) ->
-                topicPartitions.stream()
-                    .filter(tp -> earliest.containsKey(tp) && latest.containsKey(tp))
+                Sets.intersection(earliest.keySet(), latest.keySet())
+                    .stream()
                     .map(tp ->
                         Map.entry(tp,
                             new InternalPartitionsOffsets.Offsets(

+ 3 - 3
kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/analyze/TopicAnalysisStats.java

@@ -2,7 +2,7 @@ package com.provectus.kafka.ui.service.analyze;
 
 import com.provectus.kafka.ui.model.TopicAnalysisSizeStatsDTO;
 import com.provectus.kafka.ui.model.TopicAnalysisStatsDTO;
-import com.provectus.kafka.ui.model.TopicAnalysisStatsHourlyMsgCountsDTO;
+import com.provectus.kafka.ui.model.TopicAnalysisStatsHourlyMsgCountsInnerDTO;
 import java.time.Duration;
 import java.time.Instant;
 import java.util.Comparator;
@@ -78,10 +78,10 @@ class TopicAnalysisStats {
       }
     }
 
-    List<TopicAnalysisStatsHourlyMsgCountsDTO> toDto() {
+    List<TopicAnalysisStatsHourlyMsgCountsInnerDTO> toDto() {
       return hourlyStats.entrySet().stream()
           .sorted(Comparator.comparingLong(Map.Entry::getKey))
-          .map(e -> new TopicAnalysisStatsHourlyMsgCountsDTO()
+          .map(e -> new TopicAnalysisStatsHourlyMsgCountsInnerDTO()
               .hourStart(e.getKey())
               .count(e.getValue()))
           .collect(Collectors.toList());

+ 1 - 1
kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/rbac/AccessControlService.java

@@ -21,6 +21,7 @@ import com.provectus.kafka.ui.service.rbac.extractor.GithubAuthorityExtractor;
 import com.provectus.kafka.ui.service.rbac.extractor.GoogleAuthorityExtractor;
 import com.provectus.kafka.ui.service.rbac.extractor.LdapAuthorityExtractor;
 import com.provectus.kafka.ui.service.rbac.extractor.ProviderAuthorityExtractor;
+import jakarta.annotation.PostConstruct;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
@@ -28,7 +29,6 @@ import java.util.function.Predicate;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import javax.annotation.Nullable;
-import javax.annotation.PostConstruct;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections.CollectionUtils;

+ 3 - 4
kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/rbac/extractor/CognitoAuthorityExtractor.java

@@ -1,9 +1,9 @@
 package com.provectus.kafka.ui.service.rbac.extractor;
 
-import com.nimbusds.jose.shaded.json.JSONArray;
 import com.provectus.kafka.ui.model.rbac.Role;
 import com.provectus.kafka.ui.model.rbac.provider.Provider;
 import com.provectus.kafka.ui.service.rbac.AccessControlService;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -44,7 +44,7 @@ public class CognitoAuthorityExtractor implements ProviderAuthorityExtractor {
         .map(Role::getName)
         .collect(Collectors.toSet());
 
-    JSONArray groups = principal.getAttribute(COGNITO_GROUPS_ATTRIBUTE_NAME);
+    List<String> groups = principal.getAttribute(COGNITO_GROUPS_ATTRIBUTE_NAME);
     if (groups == null) {
       log.debug("Cognito groups param is not present");
       return Mono.just(groupsByUsername);
@@ -56,9 +56,8 @@ public class CognitoAuthorityExtractor implements ProviderAuthorityExtractor {
             .stream()
             .filter(s -> s.getProvider().equals(Provider.OAUTH_COGNITO))
             .filter(s -> s.getType().equals("group"))
-            .anyMatch(subject -> Stream.of(groups.toArray())
+            .anyMatch(subject -> Stream.of(groups)
                 .map(Object::toString)
-                .distinct()
                 .anyMatch(cognitoGroup -> cognitoGroup.equals(subject.getValue()))
             ))
         .map(Role::getName)

+ 53 - 0
kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/GithubReleaseInfo.java

@@ -0,0 +1,53 @@
+package com.provectus.kafka.ui.util;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.time.Duration;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.reactive.function.client.WebClient;
+import reactor.core.publisher.Mono;
+
+@Slf4j
+public class GithubReleaseInfo {
+
+  private static final String GITHUB_LATEST_RELEASE_RETRIEVAL_URL =
+      "https://api.github.com/repos/provectus/kafka-ui/releases/latest";
+
+  private static final Duration GITHUB_API_MAX_WAIT_TIME = Duration.ofSeconds(2);
+
+  public record GithubReleaseDto(String html_url, String tag_name, String published_at) {
+
+    static GithubReleaseDto empty() {
+      return new GithubReleaseDto(null, null, null);
+    }
+  }
+
+  private volatile GithubReleaseDto release = GithubReleaseDto.empty();
+
+  private final Mono<Void> refreshMono;
+
+  public GithubReleaseInfo() {
+    this(GITHUB_LATEST_RELEASE_RETRIEVAL_URL);
+  }
+
+  @VisibleForTesting
+  GithubReleaseInfo(String url) {
+    this.refreshMono = WebClient.create()
+        .get()
+        .uri(url)
+        .exchangeToMono(resp -> resp.bodyToMono(GithubReleaseDto.class))
+        .timeout(GITHUB_API_MAX_WAIT_TIME)
+        .doOnError(th -> log.trace("Error getting latest github release info", th))
+        .onErrorResume(th -> true, th -> Mono.just(GithubReleaseDto.empty()))
+        .doOnNext(release -> this.release = release)
+        .then();
+  }
+
+  public GithubReleaseDto get() {
+    return release;
+  }
+
+  public Mono<Void> refresh() {
+    return refreshMono;
+  }
+
+}

+ 2 - 2
kafka-ui-api/src/test/java/com/provectus/kafka/ui/AbstractIntegrationTest.java

@@ -16,7 +16,7 @@ import org.springframework.context.ApplicationContextInitializer;
 import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.test.context.ActiveProfiles;
 import org.springframework.test.context.ContextConfiguration;
-import org.springframework.util.SocketUtils;
+import org.springframework.test.util.TestSocketUtils;
 import org.testcontainers.containers.KafkaContainer;
 import org.testcontainers.containers.Network;
 import org.testcontainers.utility.DockerImageName;
@@ -61,7 +61,7 @@ public abstract class AbstractIntegrationTest {
       System.setProperty("kafka.clusters.0.bootstrapServers", kafka.getBootstrapServers());
       // List unavailable hosts to verify failover
       System.setProperty("kafka.clusters.0.schemaRegistry", String.format("http://localhost:%1$s,http://localhost:%1$s,%2$s",
-              SocketUtils.findAvailableTcpPort(), schemaRegistry.getUrl()));
+              TestSocketUtils.findAvailableTcpPort(), schemaRegistry.getUrl()));
       System.setProperty("kafka.clusters.0.kafkaConnect.0.name", "kafka-connect");
       System.setProperty("kafka.clusters.0.kafkaConnect.0.userName", "kafka-connect");
       System.setProperty("kafka.clusters.0.kafkaConnect.0.password", "kafka-connect");

+ 4 - 5
kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/KafkaConfigSanitizerTest.java

@@ -5,13 +5,12 @@ import static org.assertj.core.api.Assertions.assertThat;
 import java.util.Arrays;
 import java.util.Collections;
 import org.junit.jupiter.api.Test;
-import org.springframework.boot.actuate.endpoint.Sanitizer;
 
 class KafkaConfigSanitizerTest {
 
   @Test
   void doNothingIfEnabledPropertySetToFalse() {
-    final Sanitizer sanitizer = new KafkaConfigSanitizer(false, Collections.emptyList());
+    final var sanitizer = new KafkaConfigSanitizer(false, Collections.emptyList());
     assertThat(sanitizer.sanitize("password", "secret")).isEqualTo("secret");
     assertThat(sanitizer.sanitize("sasl.jaas.config", "secret")).isEqualTo("secret");
     assertThat(sanitizer.sanitize("database.password", "secret")).isEqualTo("secret");
@@ -19,7 +18,7 @@ class KafkaConfigSanitizerTest {
 
   @Test
   void obfuscateCredentials() {
-    final Sanitizer sanitizer = new KafkaConfigSanitizer(true, Collections.emptyList());
+    final var sanitizer = new KafkaConfigSanitizer(true, Collections.emptyList());
     assertThat(sanitizer.sanitize("sasl.jaas.config", "secret")).isEqualTo("******");
     assertThat(sanitizer.sanitize("consumer.sasl.jaas.config", "secret")).isEqualTo("******");
     assertThat(sanitizer.sanitize("producer.sasl.jaas.config", "secret")).isEqualTo("******");
@@ -37,7 +36,7 @@ class KafkaConfigSanitizerTest {
 
   @Test
   void notObfuscateNormalConfigs() {
-    final Sanitizer sanitizer = new KafkaConfigSanitizer(true, Collections.emptyList());
+    final var sanitizer = new KafkaConfigSanitizer(true, Collections.emptyList());
     assertThat(sanitizer.sanitize("security.protocol", "SASL_SSL")).isEqualTo("SASL_SSL");
     final String[] bootstrapServer = new String[] {"test1:9092", "test2:9092"};
     assertThat(sanitizer.sanitize("bootstrap.servers", bootstrapServer)).isEqualTo(bootstrapServer);
@@ -45,7 +44,7 @@ class KafkaConfigSanitizerTest {
 
   @Test
   void obfuscateCredentialsWithDefinedPatterns() {
-    final Sanitizer sanitizer = new KafkaConfigSanitizer(true, Arrays.asList("kafka.ui", ".*test.*"));
+    final var sanitizer = new KafkaConfigSanitizer(true, Arrays.asList("kafka.ui", ".*test.*"));
     assertThat(sanitizer.sanitize("consumer.kafka.ui", "secret")).isEqualTo("******");
     assertThat(sanitizer.sanitize("this.is.test.credentials", "secret")).isEqualTo("******");
     assertThat(sanitizer.sanitize("this.is.not.credential", "not.credential"))

+ 57 - 0
kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/ReactiveAdminClientTest.java

@@ -4,8 +4,11 @@ import static com.provectus.kafka.ui.service.ReactiveAdminClient.toMonoWithExcep
 import static java.util.Objects.requireNonNull;
 import static org.apache.kafka.clients.admin.ListOffsetsResult.ListOffsetsResultInfo;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.assertj.core.api.ThrowableAssert.ThrowingCallable;
 
 import com.provectus.kafka.ui.AbstractIntegrationTest;
+import com.provectus.kafka.ui.exception.ValidationException;
 import com.provectus.kafka.ui.producer.KafkaTestProducer;
 import java.time.Duration;
 import java.util.ArrayList;
@@ -22,16 +25,20 @@ import org.apache.kafka.clients.admin.Config;
 import org.apache.kafka.clients.admin.ConfigEntry;
 import org.apache.kafka.clients.admin.NewTopic;
 import org.apache.kafka.clients.admin.OffsetSpec;
+import org.apache.kafka.clients.admin.TopicDescription;
 import org.apache.kafka.clients.consumer.ConsumerConfig;
 import org.apache.kafka.clients.consumer.KafkaConsumer;
 import org.apache.kafka.clients.consumer.OffsetAndMetadata;
 import org.apache.kafka.clients.producer.ProducerRecord;
 import org.apache.kafka.common.KafkaFuture;
+import org.apache.kafka.common.Node;
 import org.apache.kafka.common.TopicPartition;
+import org.apache.kafka.common.TopicPartitionInfo;
 import org.apache.kafka.common.config.ConfigResource;
 import org.apache.kafka.common.errors.UnknownTopicOrPartitionException;
 import org.apache.kafka.common.internals.KafkaFutureImpl;
 import org.apache.kafka.common.serialization.StringDeserializer;
+import org.assertj.core.api.ThrowableAssert;
 import org.junit.function.ThrowingRunnable;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
@@ -133,6 +140,56 @@ class ReactiveAdminClientTest extends AbstractIntegrationTest {
         .verifyComplete();
   }
 
+  @Test
+  void filterPartitionsWithLeaderCheckSkipsPartitionsFromTopicWhereSomePartitionsHaveNoLeader() {
+    var filteredPartitions = ReactiveAdminClient.filterPartitionsWithLeaderCheck(
+        List.of(
+            // contains partitions with no leader
+            new TopicDescription("noLeaderTopic", false,
+                List.of(
+                    new TopicPartitionInfo(0, new Node(1, "n1", 9092), List.of(), List.of()),
+                    new TopicPartitionInfo(1, null, List.of(), List.of()))),
+            // should be skipped by predicate
+            new TopicDescription("skippingByPredicate", false,
+                List.of(
+                    new TopicPartitionInfo(0, new Node(1, "n1", 9092), List.of(), List.of()))),
+            // good topic
+            new TopicDescription("good", false,
+                List.of(
+                    new TopicPartitionInfo(0, new Node(1, "n1", 9092), List.of(), List.of()),
+                    new TopicPartitionInfo(1, new Node(2, "n2", 9092), List.of(), List.of()))
+            )),
+        p -> !p.topic().equals("skippingByPredicate"),
+        false
+    );
+
+    assertThat(filteredPartitions)
+        .containsExactlyInAnyOrder(
+            new TopicPartition("good", 0),
+            new TopicPartition("good", 1)
+        );
+  }
+
+  @Test
+  void filterPartitionsWithLeaderCheckThrowExceptionIfThereIsSomePartitionsWithoutLeaderAndFlagSet() {
+    ThrowingCallable call = () -> ReactiveAdminClient.filterPartitionsWithLeaderCheck(
+        List.of(
+            // contains partitions with no leader
+            new TopicDescription("t1", false,
+                List.of(
+                    new TopicPartitionInfo(0, new Node(1, "n1", 9092), List.of(), List.of()),
+                    new TopicPartitionInfo(1, null, List.of(), List.of()))),
+            new TopicDescription("t2", false,
+                List.of(
+                    new TopicPartitionInfo(0, new Node(1, "n1", 9092), List.of(), List.of()))
+            )),
+        p -> true,
+        // setting failOnNoLeader flag
+        true
+    );
+    assertThatThrownBy(call).isInstanceOf(ValidationException.class);
+  }
+
   @Test
   void testListOffsetsUnsafe() {
     String topic = UUID.randomUUID().toString();

+ 15 - 10
kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/RecordEmitterTest.java

@@ -9,6 +9,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 import com.provectus.kafka.ui.AbstractIntegrationTest;
 import com.provectus.kafka.ui.emitter.BackwardRecordEmitter;
 import com.provectus.kafka.ui.emitter.ForwardRecordEmitter;
+import com.provectus.kafka.ui.emitter.MessagesProcessing;
 import com.provectus.kafka.ui.emitter.PollingSettings;
 import com.provectus.kafka.ui.model.ConsumerPosition;
 import com.provectus.kafka.ui.model.TopicMessageEventDTO;
@@ -106,12 +107,16 @@ class RecordEmitterTest extends AbstractIntegrationTest {
     );
   }
 
+  private MessagesProcessing createMessagesProcessing() {
+    return new MessagesProcessing(RECORD_DESERIALIZER, msg -> true, null);
+  }
+
   @Test
   void pollNothingOnEmptyTopic() {
     var forwardEmitter = new ForwardRecordEmitter(
         this::createConsumer,
         new ConsumerPosition(BEGINNING, EMPTY_TOPIC, null),
-        RECORD_DESERIALIZER,
+        createMessagesProcessing(),
         PollingSettings.createDefault()
     );
 
@@ -119,7 +124,7 @@ class RecordEmitterTest extends AbstractIntegrationTest {
         this::createConsumer,
         new ConsumerPosition(BEGINNING, EMPTY_TOPIC, null),
         100,
-        RECORD_DESERIALIZER,
+        createMessagesProcessing(),
         PollingSettings.createDefault()
     );
 
@@ -141,7 +146,7 @@ class RecordEmitterTest extends AbstractIntegrationTest {
     var forwardEmitter = new ForwardRecordEmitter(
         this::createConsumer,
         new ConsumerPosition(BEGINNING, TOPIC, null),
-        RECORD_DESERIALIZER,
+        createMessagesProcessing(),
         PollingSettings.createDefault()
     );
 
@@ -149,7 +154,7 @@ class RecordEmitterTest extends AbstractIntegrationTest {
         this::createConsumer,
         new ConsumerPosition(LATEST, TOPIC, null),
         PARTITIONS * MSGS_PER_PARTITION,
-        RECORD_DESERIALIZER,
+        createMessagesProcessing(),
         PollingSettings.createDefault()
     );
 
@@ -170,7 +175,7 @@ class RecordEmitterTest extends AbstractIntegrationTest {
     var forwardEmitter = new ForwardRecordEmitter(
         this::createConsumer,
         new ConsumerPosition(OFFSET, TOPIC, targetOffsets),
-        RECORD_DESERIALIZER,
+        createMessagesProcessing(),
         PollingSettings.createDefault()
     );
 
@@ -178,7 +183,7 @@ class RecordEmitterTest extends AbstractIntegrationTest {
         this::createConsumer,
         new ConsumerPosition(OFFSET, TOPIC, targetOffsets),
         PARTITIONS * MSGS_PER_PARTITION,
-        RECORD_DESERIALIZER,
+        createMessagesProcessing(),
         PollingSettings.createDefault()
     );
 
@@ -215,7 +220,7 @@ class RecordEmitterTest extends AbstractIntegrationTest {
     var forwardEmitter = new ForwardRecordEmitter(
         this::createConsumer,
         new ConsumerPosition(TIMESTAMP, TOPIC, targetTimestamps),
-        RECORD_DESERIALIZER,
+        createMessagesProcessing(),
         PollingSettings.createDefault()
     );
 
@@ -223,7 +228,7 @@ class RecordEmitterTest extends AbstractIntegrationTest {
         this::createConsumer,
         new ConsumerPosition(TIMESTAMP, TOPIC, targetTimestamps),
         PARTITIONS * MSGS_PER_PARTITION,
-        RECORD_DESERIALIZER,
+        createMessagesProcessing(),
         PollingSettings.createDefault()
     );
 
@@ -254,7 +259,7 @@ class RecordEmitterTest extends AbstractIntegrationTest {
         this::createConsumer,
         new ConsumerPosition(OFFSET, TOPIC, targetOffsets),
         numMessages,
-        RECORD_DESERIALIZER,
+        createMessagesProcessing(),
         PollingSettings.createDefault()
     );
 
@@ -280,7 +285,7 @@ class RecordEmitterTest extends AbstractIntegrationTest {
         this::createConsumer,
         new ConsumerPosition(OFFSET, TOPIC, offsets),
         100,
-        RECORD_DESERIALIZER,
+        createMessagesProcessing(),
         PollingSettings.createDefault()
     );
 

+ 0 - 3
kafka-ui-api/src/test/java/com/provectus/kafka/ui/service/ksql/KsqlServiceV2Test.java

@@ -15,7 +15,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.springframework.util.unit.DataSize;
 import org.testcontainers.utility.DockerImageName;
 
 class KsqlServiceV2Test extends AbstractIntegrationTest {
@@ -27,8 +26,6 @@ class KsqlServiceV2Test extends AbstractIntegrationTest {
   private static final Set<String> STREAMS_TO_DELETE = new CopyOnWriteArraySet<>();
   private static final Set<String> TABLES_TO_DELETE = new CopyOnWriteArraySet<>();
 
-  private static final DataSize maxBuffSize = DataSize.ofMegabytes(20);
-
   @BeforeAll
   static void init() {
     KSQL_DB.start();

+ 54 - 0
kafka-ui-api/src/test/java/com/provectus/kafka/ui/util/GithubReleaseInfoTest.java

@@ -0,0 +1,54 @@
+package com.provectus.kafka.ui.util;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.IOException;
+import java.time.Duration;
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import reactor.test.StepVerifier;
+
+class GithubReleaseInfoTest {
+
+  private final MockWebServer mockWebServer = new MockWebServer();
+
+  @BeforeEach
+  void startMockServer() throws IOException {
+    mockWebServer.start();
+  }
+
+  @AfterEach
+  void stopMockServer() throws IOException {
+    mockWebServer.close();
+  }
+
+  @Test
+  void test() {
+    mockWebServer.enqueue(new MockResponse()
+        .addHeader("content-type: application/json")
+        .setBody("""
+            {
+              "published_at": "2023-03-09T16:11:31Z",
+              "tag_name": "v0.6.0",
+              "html_url": "https://github.com/provectus/kafka-ui/releases/tag/v0.6.0",
+              "some_unused_prop": "ololo"
+            }
+            """));
+    var url = mockWebServer.url("repos/provectus/kafka-ui/releases/latest").toString();
+
+    var infoHolder = new GithubReleaseInfo(url);
+    infoHolder.refresh().block();
+
+    var i = infoHolder.get();
+    assertThat(i.html_url())
+        .isEqualTo("https://github.com/provectus/kafka-ui/releases/tag/v0.6.0");
+    assertThat(i.published_at())
+        .isEqualTo("2023-03-09T16:11:31Z");
+    assertThat(i.tag_name())
+        .isEqualTo("v0.6.0");
+  }
+
+}

+ 17 - 19
kafka-ui-contract/pom.xml

@@ -27,20 +27,24 @@
                     <artifactId>spring-boot-starter-validation</artifactId>
                 </dependency>
                 <dependency>
-                    <groupId>io.swagger</groupId>
-                    <artifactId>swagger-annotations</artifactId>
-                    <version>${swagger-annotations.version}</version>
+                    <groupId>io.swagger.core.v3</groupId>
+                    <artifactId>swagger-integration-jakarta</artifactId>
+                    <version>2.2.8</version>
                 </dependency>
                 <dependency>
                     <groupId>org.openapitools</groupId>
                     <artifactId>jackson-databind-nullable</artifactId>
-                    <version>${jackson-databind-nullable.version}</version>
+                    <version>0.2.4</version>
                 </dependency>
                 <dependency>
-                    <groupId>com.google.code.findbugs</groupId>
-                    <artifactId>jsr305</artifactId>
-                    <version>3.0.2</version>
-                    <scope>provided</scope>
+                    <groupId>jakarta.annotation</groupId>
+                    <artifactId>jakarta.annotation-api</artifactId>
+                    <version>2.1.1</version>
+                </dependency>
+                <dependency>
+                    <groupId>javax.annotation</groupId>
+                    <artifactId>javax.annotation-api</artifactId>
+                    <version>1.3.2</version>
                 </dependency>
             </dependencies>
 
@@ -71,6 +75,7 @@
                                         <library>webclient</library>
                                         <useBeanValidation>true</useBeanValidation>
                                         <dateLibrary>java8</dateLibrary>
+                                        <useJakartaEe>true</useJakartaEe>
                                     </configOptions>
                                 </configuration>
                             </execution>
@@ -80,8 +85,7 @@
                                     <goal>generate</goal>
                                 </goals>
                                 <configuration>
-                                    <inputSpec>${project.basedir}/src/main/resources/swagger/kafka-ui-api.yaml
-                                    </inputSpec>
+                                    <inputSpec>${project.basedir}/src/main/resources/swagger/kafka-ui-api.yaml</inputSpec>
                                     <output>${project.build.directory}/generated-sources/api</output>
                                     <generatorName>spring</generatorName>
                                     <modelNameSuffix>DTO</modelNameSuffix>
@@ -89,14 +93,12 @@
                                         <modelPackage>com.provectus.kafka.ui.model</modelPackage>
                                         <apiPackage>com.provectus.kafka.ui.api</apiPackage>
                                         <sourceFolder>kafka-ui-contract</sourceFolder>
-
                                         <reactive>true</reactive>
-
                                         <interfaceOnly>true</interfaceOnly>
                                         <skipDefaultInterface>true</skipDefaultInterface>
                                         <useBeanValidation>true</useBeanValidation>
                                         <useTags>true</useTags>
-
+                                        <useSpringBoot3>true</useSpringBoot3>
                                         <dateLibrary>java8</dateLibrary>
                                     </configOptions>
                                     <typeMappings>
@@ -116,15 +118,13 @@
                                     <generatorName>java</generatorName>
                                     <generateApiTests>false</generateApiTests>
                                     <generateModelTests>false</generateModelTests>
-
                                     <configOptions>
                                         <modelPackage>com.provectus.kafka.ui.connect.model</modelPackage>
                                         <apiPackage>com.provectus.kafka.ui.connect.api</apiPackage>
                                         <sourceFolder>kafka-connect-client</sourceFolder>
-
                                         <asyncNative>true</asyncNative>
                                         <library>webclient</library>
-
+                                        <useJakartaEe>true</useJakartaEe>
                                         <useBeanValidation>true</useBeanValidation>
                                         <dateLibrary>java8</dateLibrary>
                                     </configOptions>
@@ -142,15 +142,13 @@
                                     <generatorName>java</generatorName>
                                     <generateApiTests>false</generateApiTests>
                                     <generateModelTests>false</generateModelTests>
-
                                     <configOptions>
                                         <modelPackage>com.provectus.kafka.ui.sr.model</modelPackage>
                                         <apiPackage>com.provectus.kafka.ui.sr.api</apiPackage>
                                         <sourceFolder>kafka-sr-client</sourceFolder>
-
                                         <asyncNative>true</asyncNative>
                                         <library>webclient</library>
-
+                                        <useJakartaEe>true</useJakartaEe>
                                         <useBeanValidation>true</useBeanValidation>
                                         <dateLibrary>java8</dateLibrary>
                                     </configOptions>

+ 24 - 0
kafka-ui-contract/src/main/resources/swagger/kafka-ui-api.yaml

@@ -1917,6 +1917,26 @@ components:
             type: string
             enum:
               - DYNAMIC_CONFIG
+        build:
+          type: object
+          properties:
+            commitId:
+              type: string
+            version:
+              type: string
+            buildTime:
+              type: string
+            isLatestRelease:
+              type: boolean
+        latestRelease:
+          type: object
+          properties:
+            versionTag:
+              type: string
+            publishedAt:
+              type: string
+            htmlUrl:
+              type: string
 
     Cluster:
       type: object
@@ -2387,6 +2407,10 @@ components:
         - UNKNOWN
 
     ConsumerGroup:
+      discriminator:
+        propertyName: inherit
+        mapping:
+          details: "#/components/schemas/ConsumerGroupDetails"
       type: object
       properties:
         groupId:

+ 31 - 0
kafka-ui-e2e-checks/pom.xml

@@ -264,6 +264,37 @@
                         <artifactId>allure-maven</artifactId>
                         <version>2.10.0</version>
                     </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-checkstyle-plugin</artifactId>
+                        <version>3.1.2</version>
+                        <dependencies>
+                            <dependency>
+                                <groupId>com.puppycrawl.tools</groupId>
+                                <artifactId>checkstyle</artifactId>
+                                <version>10.3.1</version>
+                            </dependency>
+                        </dependencies>
+                        <executions>
+                            <execution>
+                                <id>checkstyle</id>
+                                <phase>validate</phase>
+                                <goals>
+                                    <goal>check</goal>
+                                </goals>
+                                <configuration>
+                                    <violationSeverity>warning</violationSeverity>
+                                    <failOnViolation>true</failOnViolation>
+                                    <failsOnError>true</failsOnError>
+                                    <includeTestSourceDirectory>true</includeTestSourceDirectory>
+                                    <configLocation>file:${basedir}/../etc/checkstyle/checkstyle-e2e.xml</configLocation>
+                                    <headerLocation>file:${basedir}/../etc/checkstyle/apache-header.txt</headerLocation>
+                                </configuration>
+                            </execution>
+                        </executions>
+
+                    </plugin>
+
                 </plugins>
             </build>
         </profile>

+ 1 - 1
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Connector.java

@@ -7,5 +7,5 @@ import lombok.experimental.Accessors;
 @Accessors(chain = true)
 public class Connector {
 
-    private String name, config;
+  private String name, config;
 }

+ 20 - 19
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Schema.java

@@ -1,33 +1,34 @@
 package com.provectus.kafka.ui.models;
 
+import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
+
 import com.provectus.kafka.ui.api.model.SchemaType;
 import lombok.Data;
 import lombok.experimental.Accessors;
 
-import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
-
 @Data
 @Accessors(chain = true)
 public class Schema {
 
-    private String name, valuePath;
-    private SchemaType type;
+  private String name, valuePath;
+  private SchemaType type;
 
-    public static Schema createSchemaAvro() {
-        return new Schema().setName("schema_avro-" + randomAlphabetic(5))
-                .setType(SchemaType.AVRO)
-                .setValuePath(System.getProperty("user.dir") + "/src/main/resources/testData/schemas/schema_avro_value.json");
-    }
+  public static Schema createSchemaAvro() {
+    return new Schema().setName("schema_avro-" + randomAlphabetic(5))
+        .setType(SchemaType.AVRO)
+        .setValuePath(System.getProperty("user.dir") + "/src/main/resources/testData/schemas/schema_avro_value.json");
+  }
 
-    public static Schema createSchemaJson() {
-        return new Schema().setName("schema_json-" + randomAlphabetic(5))
-                .setType(SchemaType.JSON)
-                .setValuePath(System.getProperty("user.dir") + "/src/main/resources/testData/schemas/schema_json_Value.json");
-    }
+  public static Schema createSchemaJson() {
+    return new Schema().setName("schema_json-" + randomAlphabetic(5))
+        .setType(SchemaType.JSON)
+        .setValuePath(System.getProperty("user.dir") + "/src/main/resources/testData/schemas/schema_json_Value.json");
+  }
 
-    public static Schema createSchemaProtobuf() {
-        return new Schema().setName("schema_protobuf-" + randomAlphabetic(5))
-                .setType(SchemaType.PROTOBUF)
-                .setValuePath(System.getProperty("user.dir") + "/src/main/resources/testData/schemas/schema_protobuf_value.txt");
-    }
+  public static Schema createSchemaProtobuf() {
+    return new Schema().setName("schema_protobuf-" + randomAlphabetic(5))
+        .setType(SchemaType.PROTOBUF)
+        .setValuePath(
+            System.getProperty("user.dir") + "/src/main/resources/testData/schemas/schema_protobuf_value.txt");
+  }
 }

+ 6 - 6
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Topic.java

@@ -11,10 +11,10 @@ import lombok.experimental.Accessors;
 @Accessors(chain = true)
 public class Topic {
 
-    private String name, timeToRetainData, maxMessageBytes, messageKey, messageContent, customParameterValue;
-    private int numberOfPartitions;
-    private CustomParameterType customParameterType;
-    private CleanupPolicyValue cleanupPolicyValue;
-    private MaxSizeOnDisk maxSizeOnDisk;
-    private TimeToRetain timeToRetain;
+  private String name, timeToRetainData, maxMessageBytes, messageKey, messageValue, customParameterValue;
+  private int numberOfPartitions;
+  private CustomParameterType customParameterType;
+  private CleanupPolicyValue cleanupPolicyValue;
+  private MaxSizeOnDisk maxSizeOnDisk;
+  private TimeToRetain timeToRetain;
 }

+ 126 - 127
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/BasePage.java

@@ -1,143 +1,142 @@
 package com.provectus.kafka.ui.pages;
 
+import static com.codeborne.selenide.Selenide.$$x;
+import static com.codeborne.selenide.Selenide.$x;
+
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.ElementsCollection;
 import com.codeborne.selenide.SelenideElement;
 import com.codeborne.selenide.WebDriverRunner;
 import com.provectus.kafka.ui.pages.panels.enums.MenuItem;
 import com.provectus.kafka.ui.utilities.WebUtils;
+import java.time.Duration;
 import lombok.extern.slf4j.Slf4j;
 import org.openqa.selenium.Keys;
 import org.openqa.selenium.interactions.Actions;
 
-import java.time.Duration;
-
-import static com.codeborne.selenide.Selenide.$$x;
-import static com.codeborne.selenide.Selenide.$x;
-
 @Slf4j
 public abstract class BasePage extends WebUtils {
 
-    protected SelenideElement loadingSpinner = $x("//div[@role='progressbar']");
-    protected SelenideElement submitBtn = $x("//button[@type='submit']");
-    protected SelenideElement tableGrid = $x("//table");
-    protected SelenideElement searchFld = $x("//input[@type='text'][contains(@id, ':r')]");
-    protected SelenideElement dotMenuBtn = $x("//button[@aria-label='Dropdown Toggle']");
-    protected SelenideElement alertHeader = $x("//div[@role='alert']//div[@role='heading']");
-    protected SelenideElement alertMessage = $x("//div[@role='alert']//div[@role='contentinfo']");
-    protected SelenideElement confirmationMdl = $x("//div[text()= 'Confirm the action']/..");
-    protected SelenideElement confirmBtn = $x("//button[contains(text(),'Confirm')]");
-    protected SelenideElement cancelBtn = $x("//button[contains(text(),'Cancel')]");
-    protected SelenideElement backBtn = $x("//button[contains(text(),'Back')]");
-    protected SelenideElement nextBtn = $x("//button[contains(text(),'Next')]");
-    protected ElementsCollection ddlOptions = $$x("//li[@value]");
-    protected ElementsCollection gridItems = $$x("//tr[@class]");
-    protected String summaryCellLocator = "//div[contains(text(),'%s')]";
-    protected String tableElementNameLocator = "//tbody//a[contains(text(),'%s')]";
-    protected String columnHeaderLocator = "//table//tr/th//div[text()='%s']";
-    protected String pageTitleFromHeader = "//h1[text()='%s']";
-    protected String pagePathFromHeader = "//a[text()='%s']/../h1";
-
-    protected void waitUntilSpinnerDisappear(int... timeoutInSeconds) {
-        log.debug("\nwaitUntilSpinnerDisappear");
-        if (isVisible(loadingSpinner, timeoutInSeconds)) {
-            loadingSpinner.shouldBe(Condition.disappear, Duration.ofSeconds(60));
-        }
-    }
-
-    protected void searchItem(String tag) {
-        log.debug("\nsearchItem: {}", tag);
-        sendKeysAfterClear(searchFld, tag);
-        searchFld.pressEnter().shouldHave(Condition.value(tag));
-        waitUntilSpinnerDisappear(1);
-    }
-
-    protected SelenideElement getPageTitleFromHeader(MenuItem menuItem) {
-        return $x(String.format(pageTitleFromHeader, menuItem.getPageTitle()));
-    }
-
-    protected SelenideElement getPagePathFromHeader(MenuItem menuItem) {
-        return $x(String.format(pagePathFromHeader, menuItem.getPageTitle()));
-    }
-
-    protected void clickSubmitBtn() {
-        clickByJavaScript(submitBtn);
-    }
-
-    protected void setJsonInputValue(SelenideElement jsonInput, String jsonConfig) {
-        sendKeysByActions(jsonInput, jsonConfig.replace("  ", ""));
-        new Actions(WebDriverRunner.getWebDriver())
-                .keyDown(Keys.SHIFT)
-                .sendKeys(Keys.PAGE_DOWN)
-                .keyUp(Keys.SHIFT)
-                .sendKeys(Keys.DELETE)
-                .perform();
-    }
-
-    protected SelenideElement getTableElement(String elementName) {
-        log.debug("\ngetTableElement: {}", elementName);
-        return $x(String.format(tableElementNameLocator, elementName));
-    }
-
-    protected ElementsCollection getDdlOptions() {
-        return ddlOptions;
-    }
-
-    protected String getAlertHeader() {
-        log.debug("\ngetAlertHeader");
-        String result = alertHeader.shouldBe(Condition.visible).getText();
-        log.debug("-> {}", result);
-        return result;
-    }
-
-    protected String getAlertMessage() {
-        log.debug("\ngetAlertMessage");
-        String result = alertMessage.shouldBe(Condition.visible).getText();
-        log.debug("-> {}", result);
-        return result;
-    }
-
-    protected boolean isAlertVisible(AlertHeader header) {
-        log.debug("\nisAlertVisible: {}", header.toString());
-        boolean result = getAlertHeader().equals(header.toString());
-        log.debug("-> {}", result);
-        return result;
-    }
-
-    protected boolean isAlertVisible(AlertHeader header, String message) {
-        log.debug("\nisAlertVisible: {} {}", header, message);
-        boolean result = isAlertVisible(header) && getAlertMessage().equals(message);
-        log.debug("-> {}", result);
-        return result;
-    }
-
-    protected void clickConfirmButton() {
-        confirmBtn.shouldBe(Condition.enabled).click();
-        confirmBtn.shouldBe(Condition.disappear);
-    }
-
-    protected void clickCancelButton() {
-        cancelBtn.shouldBe(Condition.enabled).click();
-        cancelBtn.shouldBe(Condition.disappear);
-    }
-
-    protected boolean isConfirmationModalVisible() {
-        return isVisible(confirmationMdl);
-    }
-
-    public enum AlertHeader {
-        SUCCESS("Success"),
-        VALIDATION_ERROR("Validation Error"),
-        BAD_REQUEST("400 Bad Request");
-
-        private final String value;
-
-        AlertHeader(String value) {
-            this.value = value;
-        }
-
-        public String toString() {
-            return value;
-        }
-    }
+  protected SelenideElement loadingSpinner = $x("//div[@role='progressbar']");
+  protected SelenideElement submitBtn = $x("//button[@type='submit']");
+  protected SelenideElement tableGrid = $x("//table");
+  protected SelenideElement searchFld = $x("//input[@type='text'][contains(@id, ':r')]");
+  protected SelenideElement dotMenuBtn = $x("//button[@aria-label='Dropdown Toggle']");
+  protected SelenideElement alertHeader = $x("//div[@role='alert']//div[@role='heading']");
+  protected SelenideElement alertMessage = $x("//div[@role='alert']//div[@role='contentinfo']");
+  protected SelenideElement confirmationMdl = $x("//div[text()= 'Confirm the action']/..");
+  protected SelenideElement confirmBtn = $x("//button[contains(text(),'Confirm')]");
+  protected SelenideElement cancelBtn = $x("//button[contains(text(),'Cancel')]");
+  protected SelenideElement backBtn = $x("//button[contains(text(),'Back')]");
+  protected SelenideElement nextBtn = $x("//button[contains(text(),'Next')]");
+  protected ElementsCollection ddlOptions = $$x("//li[@value]");
+  protected ElementsCollection gridItems = $$x("//tr[@class]");
+  protected String summaryCellLocator = "//div[contains(text(),'%s')]";
+  protected String tableElementNameLocator = "//tbody//a[contains(text(),'%s')]";
+  protected String columnHeaderLocator = "//table//tr/th//div[text()='%s']";
+  protected String pageTitleFromHeader = "//h1[text()='%s']";
+  protected String pagePathFromHeader = "//a[text()='%s']/../h1";
+
+  protected void waitUntilSpinnerDisappear(int... timeoutInSeconds) {
+    log.debug("\nwaitUntilSpinnerDisappear");
+    if (isVisible(loadingSpinner, timeoutInSeconds)) {
+      loadingSpinner.shouldBe(Condition.disappear, Duration.ofSeconds(60));
+    }
+  }
+
+  protected void searchItem(String tag) {
+    log.debug("\nsearchItem: {}", tag);
+    sendKeysAfterClear(searchFld, tag);
+    searchFld.pressEnter().shouldHave(Condition.value(tag));
+    waitUntilSpinnerDisappear(1);
+  }
+
+  protected SelenideElement getPageTitleFromHeader(MenuItem menuItem) {
+    return $x(String.format(pageTitleFromHeader, menuItem.getPageTitle()));
+  }
+
+  protected SelenideElement getPagePathFromHeader(MenuItem menuItem) {
+    return $x(String.format(pagePathFromHeader, menuItem.getPageTitle()));
+  }
+
+  protected void clickSubmitBtn() {
+    clickByJavaScript(submitBtn);
+  }
+
+  protected void setJsonInputValue(SelenideElement jsonInput, String jsonConfig) {
+    sendKeysByActions(jsonInput, jsonConfig.replace("  ", ""));
+    new Actions(WebDriverRunner.getWebDriver())
+        .keyDown(Keys.SHIFT)
+        .sendKeys(Keys.PAGE_DOWN)
+        .keyUp(Keys.SHIFT)
+        .sendKeys(Keys.DELETE)
+        .perform();
+  }
+
+  protected SelenideElement getTableElement(String elementName) {
+    log.debug("\ngetTableElement: {}", elementName);
+    return $x(String.format(tableElementNameLocator, elementName));
+  }
+
+  protected ElementsCollection getDdlOptions() {
+    return ddlOptions;
+  }
+
+  protected String getAlertHeader() {
+    log.debug("\ngetAlertHeader");
+    String result = alertHeader.shouldBe(Condition.visible).getText();
+    log.debug("-> {}", result);
+    return result;
+  }
+
+  protected String getAlertMessage() {
+    log.debug("\ngetAlertMessage");
+    String result = alertMessage.shouldBe(Condition.visible).getText();
+    log.debug("-> {}", result);
+    return result;
+  }
+
+  protected boolean isAlertVisible(AlertHeader header) {
+    log.debug("\nisAlertVisible: {}", header.toString());
+    boolean result = getAlertHeader().equals(header.toString());
+    log.debug("-> {}", result);
+    return result;
+  }
+
+  protected boolean isAlertVisible(AlertHeader header, String message) {
+    log.debug("\nisAlertVisible: {} {}", header, message);
+    boolean result = isAlertVisible(header) && getAlertMessage().equals(message);
+    log.debug("-> {}", result);
+    return result;
+  }
+
+  protected void clickConfirmButton() {
+    confirmBtn.shouldBe(Condition.enabled).click();
+    confirmBtn.shouldBe(Condition.disappear);
+  }
+
+  protected void clickCancelButton() {
+    cancelBtn.shouldBe(Condition.enabled).click();
+    cancelBtn.shouldBe(Condition.disappear);
+  }
+
+  protected boolean isConfirmationModalVisible() {
+    return isVisible(confirmationMdl);
+  }
+
+  public enum AlertHeader {
+    SUCCESS("Success"),
+    VALIDATION_ERROR("Validation Error"),
+    BAD_REQUEST("400 Bad Request");
+
+    private final String value;
+
+    AlertHeader(String value) {
+      this.value = value;
+    }
+
+    public String toString() {
+      return value;
+    }
+  }
 }

+ 27 - 28
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersConfigTab.java

@@ -1,41 +1,40 @@
 package com.provectus.kafka.ui.pages.brokers;
 
+import static com.codeborne.selenide.Selenide.$$x;
+import static com.codeborne.selenide.Selenide.$x;
+
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.SelenideElement;
 import com.provectus.kafka.ui.pages.BasePage;
 import io.qameta.allure.Step;
-
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import static com.codeborne.selenide.Selenide.$$x;
-import static com.codeborne.selenide.Selenide.$x;
-
 public class BrokersConfigTab extends BasePage {
 
-    protected List<SelenideElement> editBtn = $$x("//button[@aria-label='editAction']");
-    protected SelenideElement searchByKeyField = $x("//input[@placeholder='Search by Key']");
-
-    @Step
-    public BrokersConfigTab waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        searchByKeyField.shouldBe(Condition.visible);
-        return this;
-    }
-
-    @Step
-    public boolean isSearchByKeyVisible() {
-        return isVisible(searchByKeyField);
-    }
-
-    public List<SelenideElement> getColumnHeaders() {
-        return Stream.of("Key", "Value", "Source")
-                .map(name -> $x(String.format(columnHeaderLocator, name)))
-                .collect(Collectors.toList());
-    }
-
-    public List<SelenideElement> getEditButtons() {
-        return editBtn;
-    }
+  protected List<SelenideElement> editBtn = $$x("//button[@aria-label='editAction']");
+  protected SelenideElement searchByKeyField = $x("//input[@placeholder='Search by Key']");
+
+  @Step
+  public BrokersConfigTab waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    searchByKeyField.shouldBe(Condition.visible);
+    return this;
+  }
+
+  @Step
+  public boolean isSearchByKeyVisible() {
+    return isVisible(searchByKeyField);
+  }
+
+  public List<SelenideElement> getColumnHeaders() {
+    return Stream.of("Key", "Value", "Source")
+        .map(name -> $x(String.format(columnHeaderLocator, name)))
+        .collect(Collectors.toList());
+  }
+
+  public List<SelenideElement> getEditButtons() {
+    return editBtn;
+  }
 }

+ 73 - 74
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersDetails.java

@@ -1,92 +1,91 @@
 package com.provectus.kafka.ui.pages.brokers;
 
+import static com.codeborne.selenide.Selenide.$;
+import static com.codeborne.selenide.Selenide.$x;
+
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.SelenideElement;
 import com.provectus.kafka.ui.pages.BasePage;
 import io.qameta.allure.Step;
-import org.openqa.selenium.By;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
-
-import static com.codeborne.selenide.Selenide.$;
-import static com.codeborne.selenide.Selenide.$x;
+import org.openqa.selenium.By;
 
 public class BrokersDetails extends BasePage {
 
-    protected SelenideElement logDirectoriesTab = $x("//a[text()='Log directories']");
-    protected SelenideElement metricsTab = $x("//a[text()='Metrics']");
-    protected String brokersTabLocator = "//a[text()='%s']";
-
-    @Step
-    public BrokersDetails waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        Arrays.asList(logDirectoriesTab, metricsTab).forEach(element -> element.shouldBe(Condition.visible));
-        return this;
-    }
-
-    @Step
-    public BrokersDetails openDetailsTab(DetailsTab menu) {
-        $(By.linkText(menu.toString())).shouldBe(Condition.enabled).click();
-        waitUntilSpinnerDisappear();
-        return this;
-    }
-
-    private List<SelenideElement> getVisibleColumnHeaders() {
-        return Stream.of("Name", "Topics", "Error", "Partitions")
-                .map(name -> $x(String.format(columnHeaderLocator, name)))
-                .collect(Collectors.toList());
+  protected SelenideElement logDirectoriesTab = $x("//a[text()='Log directories']");
+  protected SelenideElement metricsTab = $x("//a[text()='Metrics']");
+  protected String brokersTabLocator = "//a[text()='%s']";
+
+  @Step
+  public BrokersDetails waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    Arrays.asList(logDirectoriesTab, metricsTab).forEach(element -> element.shouldBe(Condition.visible));
+    return this;
+  }
+
+  @Step
+  public BrokersDetails openDetailsTab(DetailsTab menu) {
+    $(By.linkText(menu.toString())).shouldBe(Condition.enabled).click();
+    waitUntilSpinnerDisappear();
+    return this;
+  }
+
+  private List<SelenideElement> getVisibleColumnHeaders() {
+    return Stream.of("Name", "Topics", "Error", "Partitions")
+        .map(name -> $x(String.format(columnHeaderLocator, name)))
+        .collect(Collectors.toList());
+  }
+
+  private List<SelenideElement> getEnabledColumnHeaders() {
+    return Stream.of("Name", "Error")
+        .map(name -> $x(String.format(columnHeaderLocator, name)))
+        .collect(Collectors.toList());
+  }
+
+  private List<SelenideElement> getVisibleSummaryCells() {
+    return Stream.of("Segment Size", "Segment Count", "Port", "Host")
+        .map(name -> $x(String.format(summaryCellLocator, name)))
+        .collect(Collectors.toList());
+  }
+
+  private List<SelenideElement> getDetailsTabs() {
+    return Stream.of(DetailsTab.values())
+        .map(name -> $x(String.format(brokersTabLocator, name)))
+        .collect(Collectors.toList());
+  }
+
+  @Step
+  public List<SelenideElement> getAllEnabledElements() {
+    List<SelenideElement> enabledElements = new ArrayList<>(getEnabledColumnHeaders());
+    enabledElements.addAll(getDetailsTabs());
+    return enabledElements;
+  }
+
+  @Step
+  public List<SelenideElement> getAllVisibleElements() {
+    List<SelenideElement> visibleElements = new ArrayList<>(getVisibleSummaryCells());
+    visibleElements.addAll(getVisibleColumnHeaders());
+    visibleElements.addAll(getDetailsTabs());
+    return visibleElements;
+  }
+
+  public enum DetailsTab {
+    LOG_DIRECTORIES("Log directories"),
+    CONFIGS("Configs"),
+    METRICS("Metrics");
+
+    private final String value;
+
+    DetailsTab(String value) {
+      this.value = value;
     }
 
-    private List<SelenideElement> getEnabledColumnHeaders() {
-        return Stream.of("Name", "Error")
-                .map(name -> $x(String.format(columnHeaderLocator, name)))
-                .collect(Collectors.toList());
-    }
-
-    private List<SelenideElement> getVisibleSummaryCells() {
-        return Stream.of("Segment Size", "Segment Count", "Port", "Host")
-                .map(name -> $x(String.format(summaryCellLocator, name)))
-                .collect(Collectors.toList());
-    }
-
-    private List<SelenideElement> getDetailsTabs() {
-        return Stream.of(DetailsTab.values())
-                .map(name -> $x(String.format(brokersTabLocator, name)))
-                .collect(Collectors.toList());
-    }
-
-    @Step
-    public List<SelenideElement> getAllEnabledElements() {
-        List<SelenideElement> enabledElements = new ArrayList<>(getEnabledColumnHeaders());
-        enabledElements.addAll(getDetailsTabs());
-        return enabledElements;
-    }
-
-    @Step
-    public List<SelenideElement> getAllVisibleElements() {
-        List<SelenideElement> visibleElements = new ArrayList<>(getVisibleSummaryCells());
-        visibleElements.addAll(getVisibleColumnHeaders());
-        visibleElements.addAll(getDetailsTabs());
-        return visibleElements;
-    }
-
-    public enum DetailsTab {
-        LOG_DIRECTORIES("Log directories"),
-        CONFIGS("Configs"),
-        METRICS("Metrics");
-
-        private final String value;
-
-        DetailsTab(String value) {
-            this.value = value;
-        }
-
-        public String toString() {
-            return value;
-        }
+    public String toString() {
+      return value;
     }
+  }
 }

+ 88 - 89
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/brokers/BrokersList.java

@@ -1,123 +1,122 @@
 package com.provectus.kafka.ui.pages.brokers;
 
+import static com.codeborne.selenide.Selenide.$x;
+import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.BROKERS;
+
 import com.codeborne.selenide.CollectionCondition;
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.SelenideElement;
 import com.provectus.kafka.ui.pages.BasePage;
 import io.qameta.allure.Step;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import static com.codeborne.selenide.Selenide.$x;
-import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.BROKERS;
-
 public class BrokersList extends BasePage {
 
-    @Step
-    public BrokersList waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        getPageTitleFromHeader(BROKERS).shouldBe(Condition.visible);
-        return this;
-    }
-
-    @Step
-    public BrokersList openBroker(int brokerId) {
-        getBrokerItem(brokerId).openItem();
-        return this;
-    }
-
-    private List<SelenideElement> getUptimeSummaryCells() {
-        return Stream.of("Broker Count", "Active Controller", "Version")
-                .map(name -> $x(String.format(summaryCellLocator, name)))
-                .collect(Collectors.toList());
+  @Step
+  public BrokersList waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    getPageTitleFromHeader(BROKERS).shouldBe(Condition.visible);
+    return this;
+  }
+
+  @Step
+  public BrokersList openBroker(int brokerId) {
+    getBrokerItem(brokerId).openItem();
+    return this;
+  }
+
+  private List<SelenideElement> getUptimeSummaryCells() {
+    return Stream.of("Broker Count", "Active Controller", "Version")
+        .map(name -> $x(String.format(summaryCellLocator, name)))
+        .collect(Collectors.toList());
+  }
+
+  private List<SelenideElement> getPartitionsSummaryCells() {
+    return Stream.of("Online", "URP", "In Sync Replicas", "Out Of Sync Replicas")
+        .map(name -> $x(String.format(summaryCellLocator, name)))
+        .collect(Collectors.toList());
+  }
+
+  @Step
+  public List<SelenideElement> getAllVisibleElements() {
+    List<SelenideElement> visibleElements = new ArrayList<>(getUptimeSummaryCells());
+    visibleElements.addAll(getPartitionsSummaryCells());
+    return visibleElements;
+  }
+
+  private List<SelenideElement> getEnabledColumnHeaders() {
+    return Stream.of("Broker ID", "Segment Size", "Segment Count", "Port", "Host")
+        .map(name -> $x(String.format(columnHeaderLocator, name)))
+        .collect(Collectors.toList());
+  }
+
+  @Step
+  public List<SelenideElement> getAllEnabledElements() {
+    return getEnabledColumnHeaders();
+  }
+
+  private List<BrokersList.BrokerGridItem> initGridItems() {
+    List<BrokersList.BrokerGridItem> gridItemList = new ArrayList<>();
+    gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0))
+        .forEach(item -> gridItemList.add(new BrokersList.BrokerGridItem(item)));
+    return gridItemList;
+  }
+
+  @Step
+  public BrokerGridItem getBrokerItem(int id) {
+    return initGridItems().stream()
+        .filter(e -> e.getId() == id)
+        .findFirst().orElseThrow();
+  }
+
+  @Step
+  public List<BrokerGridItem> getAllBrokers() {
+    return initGridItems();
+  }
+
+  public static class BrokerGridItem extends BasePage {
+
+    private final SelenideElement element;
+
+    public BrokerGridItem(SelenideElement element) {
+      this.element = element;
     }
 
-    private List<SelenideElement> getPartitionsSummaryCells() {
-        return Stream.of("Online", "URP", "In Sync Replicas", "Out Of Sync Replicas")
-                .map(name -> $x(String.format(summaryCellLocator, name)))
-                .collect(Collectors.toList());
+    private SelenideElement getIdElm() {
+      return element.$x("./td[1]/div/a");
     }
 
     @Step
-    public List<SelenideElement> getAllVisibleElements() {
-        List<SelenideElement> visibleElements = new ArrayList<>(getUptimeSummaryCells());
-        visibleElements.addAll(getPartitionsSummaryCells());
-        return visibleElements;
-    }
-
-    private List<SelenideElement> getEnabledColumnHeaders() {
-        return Stream.of("Broker ID", "Segment Size", "Segment Count", "Port", "Host")
-                .map(name -> $x(String.format(columnHeaderLocator, name)))
-                .collect(Collectors.toList());
+    public int getId() {
+      return Integer.parseInt(getIdElm().getText().trim());
     }
 
     @Step
-    public List<SelenideElement> getAllEnabledElements() {
-        return getEnabledColumnHeaders();
+    public void openItem() {
+      getIdElm().click();
     }
 
-    private List<BrokersList.BrokerGridItem> initGridItems() {
-        List<BrokersList.BrokerGridItem> gridItemList = new ArrayList<>();
-        gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0))
-                .forEach(item -> gridItemList.add(new BrokersList.BrokerGridItem(item)));
-        return gridItemList;
+    @Step
+    public int getSegmentSize() {
+      return Integer.parseInt(element.$x("./td[2]").getText().trim());
     }
 
     @Step
-    public BrokerGridItem getBrokerItem(int id) {
-        return initGridItems().stream()
-                .filter(e -> e.getId() == id)
-                .findFirst().orElseThrow();
+    public int getSegmentCount() {
+      return Integer.parseInt(element.$x("./td[3]").getText().trim());
     }
 
     @Step
-    public List<BrokerGridItem> getAllBrokers() {
-        return initGridItems();
+    public int getPort() {
+      return Integer.parseInt(element.$x("./td[4]").getText().trim());
     }
 
-    public static class BrokerGridItem extends BasePage {
-
-        private final SelenideElement element;
-
-        public BrokerGridItem(SelenideElement element) {
-            this.element = element;
-        }
-
-        private SelenideElement getIdElm() {
-            return element.$x("./td[1]/div/a");
-        }
-
-        @Step
-        public int getId() {
-            return Integer.parseInt(getIdElm().getText().trim());
-        }
-
-        @Step
-        public void openItem() {
-            getIdElm().click();
-        }
-
-        @Step
-        public int getSegmentSize() {
-            return Integer.parseInt(element.$x("./td[2]").getText().trim());
-        }
-
-        @Step
-        public int getSegmentCount() {
-            return Integer.parseInt(element.$x("./td[3]").getText().trim());
-        }
-
-        @Step
-        public int getPort() {
-            return Integer.parseInt(element.$x("./td[4]").getText().trim());
-        }
-
-        @Step
-        public String getHost() {
-            return element.$x("./td[5]").getText().trim();
-        }
+    @Step
+    public String getHost() {
+      return element.$x("./td[5]").getText().trim();
     }
+  }
 }

+ 39 - 39
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/ConnectorCreateForm.java

@@ -1,49 +1,49 @@
 package com.provectus.kafka.ui.pages.connectors;
 
+import static com.codeborne.selenide.Selenide.$x;
+
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.SelenideElement;
 import com.provectus.kafka.ui.pages.BasePage;
 import io.qameta.allure.Step;
 
-import static com.codeborne.selenide.Selenide.$x;
-
 public class ConnectorCreateForm extends BasePage {
 
-    protected SelenideElement nameField = $x("//input[@name='name']");
-    protected SelenideElement contentTextArea = $x("//textarea[@class='ace_text-input']");
-    protected SelenideElement configField = $x("//div[@id='config']");
-
-    @Step
-    public ConnectorCreateForm waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        nameField.shouldBe(Condition.visible);
-        return this;
-    }
-
-    @Step
-    public ConnectorCreateForm setName(String connectName) {
-        nameField.shouldBe(Condition.enabled).setValue(connectName);
-        return this;
-    }
-
-    @Step
-    public ConnectorCreateForm setConfig(String configJson) {
-        configField.shouldBe(Condition.enabled).click();
-        setJsonInputValue(contentTextArea, configJson);
-        return this;
-    }
-
-    @Step
-    public ConnectorCreateForm setConnectorDetails(String connectName, String configJson) {
-        setName(connectName);
-        setConfig(configJson);
-        return this;
-    }
-
-    @Step
-    public ConnectorCreateForm clickSubmitButton() {
-        clickSubmitBtn();
-        waitUntilSpinnerDisappear();
-        return this;
-    }
+  protected SelenideElement nameField = $x("//input[@name='name']");
+  protected SelenideElement contentTextArea = $x("//textarea[@class='ace_text-input']");
+  protected SelenideElement configField = $x("//div[@id='config']");
+
+  @Step
+  public ConnectorCreateForm waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    nameField.shouldBe(Condition.visible);
+    return this;
+  }
+
+  @Step
+  public ConnectorCreateForm setName(String connectName) {
+    nameField.shouldBe(Condition.enabled).setValue(connectName);
+    return this;
+  }
+
+  @Step
+  public ConnectorCreateForm setConfig(String configJson) {
+    configField.shouldBe(Condition.enabled).click();
+    setJsonInputValue(contentTextArea, configJson);
+    return this;
+  }
+
+  @Step
+  public ConnectorCreateForm setConnectorDetails(String connectName, String configJson) {
+    setName(connectName);
+    setConfig(configJson);
+    return this;
+  }
+
+  @Step
+  public ConnectorCreateForm clickSubmitButton() {
+    clickSubmitBtn();
+    waitUntilSpinnerDisappear();
+    return this;
+  }
 }

+ 64 - 64
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/ConnectorDetails.java

@@ -1,84 +1,84 @@
 package com.provectus.kafka.ui.pages.connectors;
 
+import static com.codeborne.selenide.Selenide.$x;
+
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.SelenideElement;
 import com.provectus.kafka.ui.pages.BasePage;
 import io.qameta.allure.Step;
 
-import static com.codeborne.selenide.Selenide.$x;
-
 public class ConnectorDetails extends BasePage {
 
-    protected SelenideElement deleteBtn = $x("//li/div[contains(text(),'Delete')]");
-    protected SelenideElement confirmBtnMdl = $x("//div[@role='dialog']//button[contains(text(),'Confirm')]");
-    protected SelenideElement contentTextArea = $x("//textarea[@class='ace_text-input']");
-    protected SelenideElement taskTab = $x("//a[contains(text(),'Tasks')]");
-    protected SelenideElement configTab = $x("//a[contains(text(),'Config')]");
-    protected SelenideElement configField = $x("//div[@id='config']");
-    protected String connectorHeaderLocator = "//h1[contains(text(),'%s')]";
+  protected SelenideElement deleteBtn = $x("//li/div[contains(text(),'Delete')]");
+  protected SelenideElement confirmBtnMdl = $x("//div[@role='dialog']//button[contains(text(),'Confirm')]");
+  protected SelenideElement contentTextArea = $x("//textarea[@class='ace_text-input']");
+  protected SelenideElement taskTab = $x("//a[contains(text(),'Tasks')]");
+  protected SelenideElement configTab = $x("//a[contains(text(),'Config')]");
+  protected SelenideElement configField = $x("//div[@id='config']");
+  protected String connectorHeaderLocator = "//h1[contains(text(),'%s')]";
 
-    @Step
-    public ConnectorDetails waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        dotMenuBtn.shouldBe(Condition.visible);
-        return this;
-    }
+  @Step
+  public ConnectorDetails waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    dotMenuBtn.shouldBe(Condition.visible);
+    return this;
+  }
 
-    @Step
-    public ConnectorDetails openConfigTab() {
-        clickByJavaScript(configTab);
-        return this;
-    }
+  @Step
+  public ConnectorDetails openConfigTab() {
+    clickByJavaScript(configTab);
+    return this;
+  }
 
-    @Step
-    public ConnectorDetails setConfig(String configJson) {
-        configField.shouldBe(Condition.enabled).click();
-        clearByKeyboard(contentTextArea);
-        contentTextArea.setValue(configJson);
-        configField.shouldBe(Condition.enabled).click();
-        return this;
-    }
+  @Step
+  public ConnectorDetails setConfig(String configJson) {
+    configField.shouldBe(Condition.enabled).click();
+    clearByKeyboard(contentTextArea);
+    contentTextArea.setValue(configJson);
+    configField.shouldBe(Condition.enabled).click();
+    return this;
+  }
 
-    @Step
-    public ConnectorDetails clickSubmitButton() {
-        clickSubmitBtn();
-        return this;
-    }
+  @Step
+  public ConnectorDetails clickSubmitButton() {
+    clickSubmitBtn();
+    return this;
+  }
 
-    @Step
-    public ConnectorDetails openDotMenu() {
-        clickByJavaScript(dotMenuBtn);
-        return this;
-    }
+  @Step
+  public ConnectorDetails openDotMenu() {
+    clickByJavaScript(dotMenuBtn);
+    return this;
+  }
 
-    @Step
-    public ConnectorDetails clickDeleteBtn() {
-        clickByJavaScript(deleteBtn);
-        return this;
-    }
+  @Step
+  public ConnectorDetails clickDeleteBtn() {
+    clickByJavaScript(deleteBtn);
+    return this;
+  }
 
-    @Step
-    public ConnectorDetails clickConfirmBtn() {
-        confirmBtnMdl.shouldBe(Condition.enabled).click();
-        confirmBtnMdl.shouldBe(Condition.disappear);
-        return this;
-    }
+  @Step
+  public ConnectorDetails clickConfirmBtn() {
+    confirmBtnMdl.shouldBe(Condition.enabled).click();
+    confirmBtnMdl.shouldBe(Condition.disappear);
+    return this;
+  }
 
-    @Step
-    public ConnectorDetails deleteConnector() {
-        openDotMenu();
-        clickDeleteBtn();
-        clickConfirmBtn();
-        return this;
-    }
+  @Step
+  public ConnectorDetails deleteConnector() {
+    openDotMenu();
+    clickDeleteBtn();
+    clickConfirmBtn();
+    return this;
+  }
 
-    @Step
-    public boolean isConnectorHeaderVisible(String connectorName) {
-        return isVisible($x(String.format(connectorHeaderLocator, connectorName)));
-    }
+  @Step
+  public boolean isConnectorHeaderVisible(String connectorName) {
+    return isVisible($x(String.format(connectorHeaderLocator, connectorName)));
+  }
 
-    @Step
-    public boolean isAlertWithMessageVisible(AlertHeader header, String message) {
-        return isAlertVisible(header, message);
-    }
+  @Step
+  public boolean isAlertWithMessageVisible(AlertHeader header, String message) {
+    return isAlertVisible(header, message);
+  }
 }

+ 33 - 33
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/KafkaConnectList.java

@@ -1,44 +1,44 @@
 package com.provectus.kafka.ui.pages.connectors;
 
+import static com.codeborne.selenide.Selenide.$x;
+import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.KAFKA_CONNECT;
+
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.SelenideElement;
 import com.provectus.kafka.ui.pages.BasePage;
 import io.qameta.allure.Step;
 
-import static com.codeborne.selenide.Selenide.$x;
-import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.KAFKA_CONNECT;
-
 
 public class KafkaConnectList extends BasePage {
 
-    protected SelenideElement createConnectorBtn = $x("//button[contains(text(),'Create Connector')]");
-
-    public KafkaConnectList() {
-        tableElementNameLocator = "//tbody//td[contains(text(),'%s')]";
-    }
-
-    @Step
-    public KafkaConnectList waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        getPageTitleFromHeader(KAFKA_CONNECT).shouldBe(Condition.visible);
-        return this;
-    }
-
-    @Step
-    public KafkaConnectList clickCreateConnectorBtn() {
-        clickByJavaScript(createConnectorBtn);
-        return this;
-    }
-
-    @Step
-    public KafkaConnectList openConnector(String connectorName) {
-        getTableElement(connectorName).shouldBe(Condition.enabled).click();
-        return this;
-    }
-
-    @Step
-    public boolean isConnectorVisible(String connectorName) {
-        tableGrid.shouldBe(Condition.visible);
-        return isVisible(getTableElement(connectorName));
-    }
+  protected SelenideElement createConnectorBtn = $x("//button[contains(text(),'Create Connector')]");
+
+  public KafkaConnectList() {
+    tableElementNameLocator = "//tbody//td[contains(text(),'%s')]";
+  }
+
+  @Step
+  public KafkaConnectList waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    getPageTitleFromHeader(KAFKA_CONNECT).shouldBe(Condition.visible);
+    return this;
+  }
+
+  @Step
+  public KafkaConnectList clickCreateConnectorBtn() {
+    clickByJavaScript(createConnectorBtn);
+    return this;
+  }
+
+  @Step
+  public KafkaConnectList openConnector(String connectorName) {
+    getTableElement(connectorName).shouldBe(Condition.enabled).click();
+    return this;
+  }
+
+  @Step
+  public boolean isConnectorVisible(String connectorName) {
+    tableGrid.shouldBe(Condition.visible);
+    return isVisible(getTableElement(connectorName));
+  }
 }

+ 19 - 19
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/consumers/ConsumersDetails.java

@@ -1,31 +1,31 @@
 package com.provectus.kafka.ui.pages.consumers;
 
+import static com.codeborne.selenide.Selenide.$x;
+
 import com.codeborne.selenide.Condition;
 import com.provectus.kafka.ui.pages.BasePage;
 import io.qameta.allure.Step;
 
-import static com.codeborne.selenide.Selenide.$x;
-
 public class ConsumersDetails extends BasePage {
 
-    protected String consumerIdHeaderLocator = "//h1[contains(text(),'%s')]";
-    protected String topicElementLocator = "//tbody//td//a[text()='%s']";
+  protected String consumerIdHeaderLocator = "//h1[contains(text(),'%s')]";
+  protected String topicElementLocator = "//tbody//td//a[text()='%s']";
 
-    @Step
-    public ConsumersDetails waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        tableGrid.shouldBe(Condition.visible);
-        return this;
-    }
+  @Step
+  public ConsumersDetails waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    tableGrid.shouldBe(Condition.visible);
+    return this;
+  }
 
-    @Step
-    public boolean isRedirectedConsumerTitleVisible(String consumerGroupId) {
-        return isVisible($x(String.format(consumerIdHeaderLocator, consumerGroupId)));
-    }
+  @Step
+  public boolean isRedirectedConsumerTitleVisible(String consumerGroupId) {
+    return isVisible($x(String.format(consumerIdHeaderLocator, consumerGroupId)));
+  }
 
-    @Step
-    public boolean isTopicInConsumersDetailsVisible(String topicName) {
-        tableGrid.shouldBe(Condition.visible);
-        return isVisible($x(String.format(topicElementLocator, topicName)));
-    }
+  @Step
+  public boolean isTopicInConsumersDetailsVisible(String topicName) {
+    tableGrid.shouldBe(Condition.visible);
+    return isVisible($x(String.format(topicElementLocator, topicName)));
+  }
 }

+ 8 - 8
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/consumers/ConsumersList.java

@@ -1,17 +1,17 @@
 package com.provectus.kafka.ui.pages.consumers;
 
+import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.CONSUMERS;
+
 import com.codeborne.selenide.Condition;
 import com.provectus.kafka.ui.pages.BasePage;
 import io.qameta.allure.Step;
 
-import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.CONSUMERS;
-
 public class ConsumersList extends BasePage {
 
-    @Step
-    public ConsumersList waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        getPageTitleFromHeader(CONSUMERS).shouldBe(Condition.visible);
-        return this;
-    }
+  @Step
+  public ConsumersList waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    getPageTitleFromHeader(CONSUMERS).shouldBe(Condition.visible);
+    return this;
+  }
 }

+ 0 - 139
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/KsqlDbList.java

@@ -1,139 +0,0 @@
-package com.provectus.kafka.ui.pages.ksqlDb;
-
-import com.codeborne.selenide.CollectionCondition;
-import com.codeborne.selenide.Condition;
-import com.codeborne.selenide.SelenideElement;
-import com.provectus.kafka.ui.pages.BasePage;
-import com.provectus.kafka.ui.pages.ksqlDb.enums.KsqlMenuTabs;
-import io.qameta.allure.Step;
-import org.openqa.selenium.By;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.codeborne.selenide.Selenide.$;
-import static com.codeborne.selenide.Selenide.$x;
-import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.KSQL_DB;
-
-public class KsqlDbList extends BasePage {
-
-    protected SelenideElement executeKsqlBtn = $x("//button[text()='Execute KSQL Request']");
-    protected SelenideElement tablesTab = $x("//nav[@role='navigation']/a[text()='Tables']");
-    protected SelenideElement streamsTab = $x("//nav[@role='navigation']/a[text()='Streams']");
-
-    @Step
-    public KsqlDbList waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        getPageTitleFromHeader(KSQL_DB).shouldBe(Condition.visible);
-        return this;
-    }
-
-    @Step
-    public KsqlDbList clickExecuteKsqlRequestBtn() {
-        clickByJavaScript(executeKsqlBtn);
-        return this;
-    }
-
-    @Step
-    public KsqlDbList openDetailsTab(KsqlMenuTabs menu) {
-        $(By.linkText(menu.toString())).shouldBe(Condition.visible).click();
-        waitUntilSpinnerDisappear();
-        return this;
-    }
-
-    private List<KsqlDbList.KsqlTablesGridItem> initTablesItems() {
-        List<KsqlDbList.KsqlTablesGridItem> gridItemList = new ArrayList<>();
-        gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0))
-                .forEach(item -> gridItemList.add(new KsqlDbList.KsqlTablesGridItem(item)));
-        return gridItemList;
-    }
-
-    @Step
-    public KsqlDbList.KsqlTablesGridItem getTableByName(String tableName) {
-        return initTablesItems().stream()
-                .filter(e -> e.getTableName().equals(tableName))
-                .findFirst().orElseThrow();
-    }
-
-    private List<KsqlDbList.KsqlStreamsGridItem> initStreamsItems() {
-        List<KsqlDbList.KsqlStreamsGridItem> gridItemList = new ArrayList<>();
-        gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0))
-                .forEach(item -> gridItemList.add(new KsqlDbList.KsqlStreamsGridItem(item)));
-        return gridItemList;
-    }
-
-    @Step
-    public KsqlDbList.KsqlStreamsGridItem getStreamByName(String streamName) {
-        return initStreamsItems().stream()
-                .filter(e -> e.getStreamName().equals(streamName))
-                .findFirst().orElseThrow();
-    }
-
-    public static class KsqlTablesGridItem extends BasePage {
-
-        private final SelenideElement element;
-
-        public KsqlTablesGridItem(SelenideElement element) {
-            this.element = element;
-        }
-
-        @Step
-        public String getTableName() {
-            return element.$x("./td[1]").getText().trim();
-        }
-
-        @Step
-        public String getTopicName() {
-            return element.$x("./td[2]").getText().trim();
-        }
-
-        @Step
-        public String getKeyFormat() {
-            return element.$x("./td[3]").getText().trim();
-        }
-
-        @Step
-        public String getValueFormat() {
-            return element.$x("./td[4]").getText().trim();
-        }
-
-        @Step
-        public String getIsWindowed() {
-            return element.$x("./td[5]").getText().trim();
-        }
-    }
-
-    public static class KsqlStreamsGridItem extends BasePage {
-
-        private final SelenideElement element;
-
-        public KsqlStreamsGridItem(SelenideElement element) {
-            this.element = element;
-        }
-
-        @Step
-        public String getStreamName() {
-            return element.$x("./td[1]").getText().trim();
-        }
-
-        @Step
-        public String getTopicName() {
-            return element.$x("./td[2]").getText().trim();
-        }
-
-        @Step
-        public String getKeyFormat() {
-            return element.$x("./td[3]").getText().trim();
-        }
-
-        @Step
-        public String getValueFormat() {
-            return element.$x("./td[4]").getText().trim();
-        }
-
-        @Step
-        public String getIsWindowed() {
-            return element.$x("./td[5]").getText().trim();
-        }
-    }
-}

+ 0 - 154
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/KsqlQueryForm.java

@@ -1,154 +0,0 @@
-package com.provectus.kafka.ui.pages.ksqlDb;
-
-import com.codeborne.selenide.CollectionCondition;
-import com.codeborne.selenide.Condition;
-import com.codeborne.selenide.ElementsCollection;
-import com.codeborne.selenide.SelenideElement;
-import com.provectus.kafka.ui.pages.BasePage;
-import io.qameta.allure.Step;
-
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.codeborne.selenide.Condition.visible;
-import static com.codeborne.selenide.Selenide.$$x;
-import static com.codeborne.selenide.Selenide.$x;
-
-public class KsqlQueryForm extends BasePage {
-    protected SelenideElement clearBtn = $x("//div/button[text()='Clear']");
-    protected SelenideElement executeBtn = $x("//div/button[text()='Execute']");
-    protected SelenideElement stopQueryBtn = $x("//div/button[text()='Stop query']");
-    protected SelenideElement clearResultsBtn = $x("//div/button[text()='Clear results']");
-    protected SelenideElement addStreamPropertyBtn = $x("//button[text()='Add Stream Property']");
-    protected SelenideElement queryAreaValue = $x("//div[@class='ace_content']");
-    protected SelenideElement queryArea = $x("//div[@id='ksql']/textarea[@class='ace_text-input']");
-    protected ElementsCollection ksqlGridItems = $$x("//tbody//tr");
-    protected ElementsCollection keyField = $$x("//input[@aria-label='key']");
-    protected ElementsCollection valueField = $$x("//input[@aria-label='value']");
-
-    @Step
-    public KsqlQueryForm waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        executeBtn.shouldBe(Condition.visible);
-        return this;
-    }
-
-    @Step
-    public KsqlQueryForm clickClearBtn() {
-        clickByJavaScript(clearBtn);
-        return this;
-    }
-
-    @Step
-    public KsqlQueryForm clickExecuteBtn() {
-        clickByActions(executeBtn);
-        if (queryAreaValue.getText().contains("EMIT CHANGES;")) {
-            loadingSpinner.shouldBe(Condition.visible);
-        } else {
-            waitUntilSpinnerDisappear();
-        }
-        return this;
-    }
-
-    @Step
-    public KsqlQueryForm clickStopQueryBtn() {
-        clickByActions(stopQueryBtn);
-        waitUntilSpinnerDisappear();
-        return this;
-    }
-
-    @Step
-    public KsqlQueryForm clickClearResultsBtn() {
-        clickByActions(clearResultsBtn);
-        waitUntilSpinnerDisappear();
-        return this;
-    }
-
-    @Step
-    public KsqlQueryForm clickAddStreamProperty() {
-        clickByJavaScript(addStreamPropertyBtn);
-        return this;
-    }
-
-    @Step
-    public KsqlQueryForm setQuery(String query) {
-        queryAreaValue.shouldBe(Condition.visible).click();
-        queryArea.setValue(query);
-        return this;
-    }
-
-    @Step
-    public KsqlQueryForm.KsqlResponseGridItem getTableByName(String name) {
-        return initItems().stream()
-                .filter(e -> e.getName().equalsIgnoreCase(name))
-                .findFirst().orElseThrow();
-    }
-
-    @Step
-    public boolean areResultsVisible() {
-        boolean visible = false;
-        try {
-            visible = initItems().size() > 0;
-        } catch (Throwable ignored) {
-        }
-        return visible;
-    }
-
-    private List<KsqlQueryForm.KsqlResponseGridItem> initItems() {
-        List<KsqlQueryForm.KsqlResponseGridItem> gridItemList = new ArrayList<>();
-        ksqlGridItems.shouldHave(CollectionCondition.sizeGreaterThan(0))
-                .forEach(item -> gridItemList.add(new KsqlQueryForm.KsqlResponseGridItem(item)));
-        return gridItemList;
-    }
-
-    public static class KsqlResponseGridItem extends BasePage {
-
-        private final SelenideElement element;
-
-        private KsqlResponseGridItem(SelenideElement element) {
-            this.element = element;
-        }
-
-        @Step
-        public String getType() {
-            return element.$x("./td[1]").getText().trim();
-        }
-
-        @Step
-        public String getName() {
-            return element.$x("./td[2]").scrollTo().getText().trim();
-        }
-
-        @Step
-        public boolean isVisible() {
-            boolean isVisible = false;
-            try {
-                element.$x("./td[2]").shouldBe(visible, Duration.ofMillis(500));
-                isVisible = true;
-            } catch (Throwable ignored) {
-            }
-            return isVisible;
-        }
-
-        @Step
-        public String getTopic() {
-            return element.$x("./td[3]").getText().trim();
-        }
-
-        @Step
-        public String getKeyFormat() {
-            return element.$x("./td[4]").getText().trim();
-        }
-
-        @Step
-        public String getValueFormat() {
-            return element.$x("./td[5]").getText().trim();
-        }
-
-        @Step
-        public String getIsWindowed() {
-            return element.$x("./td[6]").getText().trim();
-        }
-    }
-}

+ 0 - 17
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/enums/KsqlMenuTabs.java

@@ -1,17 +0,0 @@
-package com.provectus.kafka.ui.pages.ksqlDb.enums;
-
-public enum KsqlMenuTabs {
-
-    TABLES("Table"),
-    STREAMS("Streams");
-
-    private final String value;
-
-    KsqlMenuTabs(String value) {
-        this.value = value;
-    }
-
-    public String toString() {
-        return value;
-    }
-}

+ 0 - 19
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/enums/KsqlQueryConfig.java

@@ -1,19 +0,0 @@
-package com.provectus.kafka.ui.pages.ksqlDb.enums;
-
-public enum KsqlQueryConfig {
-
-    SHOW_TABLES("show tables;"),
-    SHOW_STREAMS("show streams;"),
-    SELECT_ALL_FROM("SELECT * FROM %s\n" +
-            "EMIT CHANGES;");
-
-    private final String query;
-
-    KsqlQueryConfig(String query) {
-        this.query = query;
-    }
-
-    public String getQuery() {
-        return query;
-    }
-}

+ 138 - 0
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/KsqlDbList.java

@@ -0,0 +1,138 @@
+package com.provectus.kafka.ui.pages.ksqldb;
+
+import static com.codeborne.selenide.Selenide.$;
+import static com.codeborne.selenide.Selenide.$x;
+import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.KSQL_DB;
+
+import com.codeborne.selenide.CollectionCondition;
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.SelenideElement;
+import com.provectus.kafka.ui.pages.BasePage;
+import com.provectus.kafka.ui.pages.ksqldb.enums.KsqlMenuTabs;
+import io.qameta.allure.Step;
+import java.util.ArrayList;
+import java.util.List;
+import org.openqa.selenium.By;
+
+public class KsqlDbList extends BasePage {
+
+  protected SelenideElement executeKsqlBtn = $x("//button[text()='Execute KSQL Request']");
+  protected SelenideElement tablesTab = $x("//nav[@role='navigation']/a[text()='Tables']");
+  protected SelenideElement streamsTab = $x("//nav[@role='navigation']/a[text()='Streams']");
+
+  @Step
+  public KsqlDbList waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    getPageTitleFromHeader(KSQL_DB).shouldBe(Condition.visible);
+    return this;
+  }
+
+  @Step
+  public KsqlDbList clickExecuteKsqlRequestBtn() {
+    clickByJavaScript(executeKsqlBtn);
+    return this;
+  }
+
+  @Step
+  public KsqlDbList openDetailsTab(KsqlMenuTabs menu) {
+    $(By.linkText(menu.toString())).shouldBe(Condition.visible).click();
+    waitUntilSpinnerDisappear();
+    return this;
+  }
+
+  private List<KsqlDbList.KsqlTablesGridItem> initTablesItems() {
+    List<KsqlDbList.KsqlTablesGridItem> gridItemList = new ArrayList<>();
+    gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0))
+        .forEach(item -> gridItemList.add(new KsqlDbList.KsqlTablesGridItem(item)));
+    return gridItemList;
+  }
+
+  @Step
+  public KsqlDbList.KsqlTablesGridItem getTableByName(String tableName) {
+    return initTablesItems().stream()
+        .filter(e -> e.getTableName().equals(tableName))
+        .findFirst().orElseThrow();
+  }
+
+  private List<KsqlDbList.KsqlStreamsGridItem> initStreamsItems() {
+    List<KsqlDbList.KsqlStreamsGridItem> gridItemList = new ArrayList<>();
+    gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0))
+        .forEach(item -> gridItemList.add(new KsqlDbList.KsqlStreamsGridItem(item)));
+    return gridItemList;
+  }
+
+  @Step
+  public KsqlDbList.KsqlStreamsGridItem getStreamByName(String streamName) {
+    return initStreamsItems().stream()
+        .filter(e -> e.getStreamName().equals(streamName))
+        .findFirst().orElseThrow();
+  }
+
+  public static class KsqlTablesGridItem extends BasePage {
+
+    private final SelenideElement element;
+
+    public KsqlTablesGridItem(SelenideElement element) {
+      this.element = element;
+    }
+
+    @Step
+    public String getTableName() {
+      return element.$x("./td[1]").getText().trim();
+    }
+
+    @Step
+    public String getTopicName() {
+      return element.$x("./td[2]").getText().trim();
+    }
+
+    @Step
+    public String getKeyFormat() {
+      return element.$x("./td[3]").getText().trim();
+    }
+
+    @Step
+    public String getValueFormat() {
+      return element.$x("./td[4]").getText().trim();
+    }
+
+    @Step
+    public String getIsWindowed() {
+      return element.$x("./td[5]").getText().trim();
+    }
+  }
+
+  public static class KsqlStreamsGridItem extends BasePage {
+
+    private final SelenideElement element;
+
+    public KsqlStreamsGridItem(SelenideElement element) {
+      this.element = element;
+    }
+
+    @Step
+    public String getStreamName() {
+      return element.$x("./td[1]").getText().trim();
+    }
+
+    @Step
+    public String getTopicName() {
+      return element.$x("./td[2]").getText().trim();
+    }
+
+    @Step
+    public String getKeyFormat() {
+      return element.$x("./td[3]").getText().trim();
+    }
+
+    @Step
+    public String getValueFormat() {
+      return element.$x("./td[4]").getText().trim();
+    }
+
+    @Step
+    public String getIsWindowed() {
+      return element.$x("./td[5]").getText().trim();
+    }
+  }
+}

+ 153 - 0
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/KsqlQueryForm.java

@@ -0,0 +1,153 @@
+package com.provectus.kafka.ui.pages.ksqldb;
+
+import static com.codeborne.selenide.Condition.visible;
+import static com.codeborne.selenide.Selenide.$$x;
+import static com.codeborne.selenide.Selenide.$x;
+
+import com.codeborne.selenide.CollectionCondition;
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.ElementsCollection;
+import com.codeborne.selenide.SelenideElement;
+import com.provectus.kafka.ui.pages.BasePage;
+import io.qameta.allure.Step;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+
+public class KsqlQueryForm extends BasePage {
+  protected SelenideElement clearBtn = $x("//div/button[text()='Clear']");
+  protected SelenideElement executeBtn = $x("//div/button[text()='Execute']");
+  protected SelenideElement stopQueryBtn = $x("//div/button[text()='Stop query']");
+  protected SelenideElement clearResultsBtn = $x("//div/button[text()='Clear results']");
+  protected SelenideElement addStreamPropertyBtn = $x("//button[text()='Add Stream Property']");
+  protected SelenideElement queryAreaValue = $x("//div[@class='ace_content']");
+  protected SelenideElement queryArea = $x("//div[@id='ksql']/textarea[@class='ace_text-input']");
+  protected ElementsCollection ksqlGridItems = $$x("//tbody//tr");
+  protected ElementsCollection keyField = $$x("//input[@aria-label='key']");
+  protected ElementsCollection valueField = $$x("//input[@aria-label='value']");
+
+  @Step
+  public KsqlQueryForm waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    executeBtn.shouldBe(Condition.visible);
+    return this;
+  }
+
+  @Step
+  public KsqlQueryForm clickClearBtn() {
+    clickByJavaScript(clearBtn);
+    return this;
+  }
+
+  @Step
+  public KsqlQueryForm clickExecuteBtn() {
+    clickByActions(executeBtn);
+    if (queryAreaValue.getText().contains("EMIT CHANGES;")) {
+      loadingSpinner.shouldBe(Condition.visible);
+    } else {
+      waitUntilSpinnerDisappear();
+    }
+    return this;
+  }
+
+  @Step
+  public KsqlQueryForm clickStopQueryBtn() {
+    clickByActions(stopQueryBtn);
+    waitUntilSpinnerDisappear();
+    return this;
+  }
+
+  @Step
+  public KsqlQueryForm clickClearResultsBtn() {
+    clickByActions(clearResultsBtn);
+    waitUntilSpinnerDisappear();
+    return this;
+  }
+
+  @Step
+  public KsqlQueryForm clickAddStreamProperty() {
+    clickByJavaScript(addStreamPropertyBtn);
+    return this;
+  }
+
+  @Step
+  public KsqlQueryForm setQuery(String query) {
+    queryAreaValue.shouldBe(Condition.visible).click();
+    queryArea.setValue(query);
+    return this;
+  }
+
+  @Step
+  public KsqlQueryForm.KsqlResponseGridItem getTableByName(String name) {
+    return initItems().stream()
+        .filter(e -> e.getName().equalsIgnoreCase(name))
+        .findFirst().orElseThrow();
+  }
+
+  @Step
+  public boolean areResultsVisible() {
+    boolean visible = false;
+    try {
+      visible = initItems().size() > 0;
+    } catch (Throwable ignored) {
+    }
+    return visible;
+  }
+
+  private List<KsqlQueryForm.KsqlResponseGridItem> initItems() {
+    List<KsqlQueryForm.KsqlResponseGridItem> gridItemList = new ArrayList<>();
+    ksqlGridItems.shouldHave(CollectionCondition.sizeGreaterThan(0))
+        .forEach(item -> gridItemList.add(new KsqlQueryForm.KsqlResponseGridItem(item)));
+    return gridItemList;
+  }
+
+  public static class KsqlResponseGridItem extends BasePage {
+
+    private final SelenideElement element;
+
+    private KsqlResponseGridItem(SelenideElement element) {
+      this.element = element;
+    }
+
+    @Step
+    public String getType() {
+      return element.$x("./td[1]").getText().trim();
+    }
+
+    @Step
+    public String getName() {
+      return element.$x("./td[2]").scrollTo().getText().trim();
+    }
+
+    @Step
+    public boolean isVisible() {
+      boolean isVisible = false;
+      try {
+        element.$x("./td[2]").shouldBe(visible, Duration.ofMillis(500));
+        isVisible = true;
+      } catch (Throwable ignored) {
+      }
+      return isVisible;
+    }
+
+    @Step
+    public String getTopic() {
+      return element.$x("./td[3]").getText().trim();
+    }
+
+    @Step
+    public String getKeyFormat() {
+      return element.$x("./td[4]").getText().trim();
+    }
+
+    @Step
+    public String getValueFormat() {
+      return element.$x("./td[5]").getText().trim();
+    }
+
+    @Step
+    public String getIsWindowed() {
+      return element.$x("./td[6]").getText().trim();
+    }
+  }
+}

+ 17 - 0
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/enums/KsqlMenuTabs.java

@@ -0,0 +1,17 @@
+package com.provectus.kafka.ui.pages.ksqldb.enums;
+
+public enum KsqlMenuTabs {
+
+  TABLES("Table"),
+  STREAMS("Streams");
+
+  private final String value;
+
+  KsqlMenuTabs(String value) {
+    this.value = value;
+  }
+
+  public String toString() {
+    return value;
+  }
+}

+ 18 - 0
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/enums/KsqlQueryConfig.java

@@ -0,0 +1,18 @@
+package com.provectus.kafka.ui.pages.ksqldb.enums;
+
+public enum KsqlQueryConfig {
+
+  SHOW_TABLES("show tables;"),
+  SHOW_STREAMS("show streams;"),
+  SELECT_ALL_FROM("SELECT * FROM %s\n" + "EMIT CHANGES;");
+
+  private final String query;
+
+  KsqlQueryConfig(String query) {
+    this.query = query;
+  }
+
+  public String getQuery() {
+    return query;
+  }
+}

+ 2 - 2
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/models/Stream.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/models/Stream.java

@@ -1,4 +1,4 @@
-package com.provectus.kafka.ui.pages.ksqlDb.models;
+package com.provectus.kafka.ui.pages.ksqldb.models;
 
 import lombok.Data;
 import lombok.experimental.Accessors;
@@ -7,5 +7,5 @@ import lombok.experimental.Accessors;
 @Accessors(chain = true)
 public class Stream {
 
-    private String name, topicName, valueFormat, partitions;
+  private String name, topicName, valueFormat, partitions;
 }

+ 2 - 2
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqlDb/models/Table.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/ksqldb/models/Table.java

@@ -1,4 +1,4 @@
-package com.provectus.kafka.ui.pages.ksqlDb.models;
+package com.provectus.kafka.ui.pages.ksqldb.models;
 
 import lombok.Data;
 import lombok.experimental.Accessors;
@@ -7,5 +7,5 @@ import lombok.experimental.Accessors;
 @Accessors(chain = true)
 public class Table {
 
-    private String name, streamName;
+  private String name, streamName;
 }

+ 46 - 47
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/NaviSideBar.java

@@ -1,64 +1,63 @@
 package com.provectus.kafka.ui.pages.panels;
 
+import static com.codeborne.selenide.Selenide.$x;
+import static com.provectus.kafka.ui.settings.BaseSource.CLUSTER_NAME;
+
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.SelenideElement;
 import com.provectus.kafka.ui.pages.BasePage;
 import com.provectus.kafka.ui.pages.panels.enums.MenuItem;
 import io.qameta.allure.Step;
-
 import java.time.Duration;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import static com.codeborne.selenide.Selenide.$x;
-import static com.provectus.kafka.ui.settings.BaseSource.CLUSTER_NAME;
-
 public class NaviSideBar extends BasePage {
 
-    protected SelenideElement dashboardMenuItem = $x("//a[@title='Dashboard']");
-    protected String sideMenuOptionElementLocator = ".//ul/li[contains(.,'%s')]";
-    protected String clusterElementLocator = "//aside/ul/li[contains(.,'%s')]";
-
-    private SelenideElement expandCluster(String clusterName) {
-        SelenideElement clusterElement = $x(String.format(clusterElementLocator, clusterName)).shouldBe(Condition.visible);
-        if (clusterElement.parent().$$x(".//ul").size() == 0) {
-            clickByActions(clusterElement);
-        }
-        return clusterElement;
-    }
-
-    @Step
-    public NaviSideBar waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        dashboardMenuItem.shouldBe(Condition.visible, Duration.ofSeconds(30));
-        return this;
-    }
-
-    @Step
-    public String getPagePath(MenuItem menuItem) {
-        return getPagePathFromHeader(menuItem)
-                .shouldBe(Condition.visible)
-                .getText().trim();
-    }
-
-    @Step
-    public NaviSideBar openSideMenu(String clusterName, MenuItem menuItem) {
-        clickByActions(expandCluster(clusterName).parent()
-                .$x(String.format(sideMenuOptionElementLocator, menuItem.getNaviTitle())));
-        return this;
-    }
-
-    @Step
-    public NaviSideBar openSideMenu(MenuItem menuItem) {
-        openSideMenu(CLUSTER_NAME, menuItem);
-        return this;
-    }
+  protected SelenideElement dashboardMenuItem = $x("//a[@title='Dashboard']");
+  protected String sideMenuOptionElementLocator = ".//ul/li[contains(.,'%s')]";
+  protected String clusterElementLocator = "//aside/ul/li[contains(.,'%s')]";
 
-    public List<SelenideElement> getAllMenuButtons() {
-        expandCluster(CLUSTER_NAME);
-        return Stream.of(MenuItem.values())
-                .map(menuItem -> $x(String.format(sideMenuOptionElementLocator, menuItem.getNaviTitle())))
-                .collect(Collectors.toList());
+  private SelenideElement expandCluster(String clusterName) {
+    SelenideElement clusterElement = $x(String.format(clusterElementLocator, clusterName)).shouldBe(Condition.visible);
+    if (clusterElement.parent().$$x(".//ul").size() == 0) {
+      clickByActions(clusterElement);
     }
+    return clusterElement;
+  }
+
+  @Step
+  public NaviSideBar waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    dashboardMenuItem.shouldBe(Condition.visible, Duration.ofSeconds(30));
+    return this;
+  }
+
+  @Step
+  public String getPagePath(MenuItem menuItem) {
+    return getPagePathFromHeader(menuItem)
+        .shouldBe(Condition.visible)
+        .getText().trim();
+  }
+
+  @Step
+  public NaviSideBar openSideMenu(String clusterName, MenuItem menuItem) {
+    clickByActions(expandCluster(clusterName).parent()
+        .$x(String.format(sideMenuOptionElementLocator, menuItem.getNaviTitle())));
+    return this;
+  }
+
+  @Step
+  public NaviSideBar openSideMenu(MenuItem menuItem) {
+    openSideMenu(CLUSTER_NAME, menuItem);
+    return this;
+  }
+
+  public List<SelenideElement> getAllMenuButtons() {
+    expandCluster(CLUSTER_NAME);
+    return Stream.of(MenuItem.values())
+        .map(menuItem -> $x(String.format(sideMenuOptionElementLocator, menuItem.getNaviTitle())))
+        .collect(Collectors.toList());
+  }
 }

+ 13 - 14
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/TopPanel.java

@@ -1,26 +1,25 @@
 package com.provectus.kafka.ui.pages.panels;
 
+import static com.codeborne.selenide.Selenide.$x;
+
 import com.codeborne.selenide.SelenideElement;
 import com.provectus.kafka.ui.pages.BasePage;
-
 import java.util.Arrays;
 import java.util.List;
 
-import static com.codeborne.selenide.Selenide.$x;
-
 public class TopPanel extends BasePage {
 
-    protected SelenideElement kafkaLogo = $x("//a[contains(text(),'UI for Apache Kafka')]");
-    protected SelenideElement kafkaVersion = $x("//a[@title='Current commit']");
-    protected SelenideElement logOutBtn = $x("//button[contains(text(),'Log out')]");
-    protected SelenideElement gitBtn = $x("//a[@href='https://github.com/provectus/kafka-ui']");
-    protected SelenideElement discordBtn = $x("//a[contains(@href,'https://discord.com/invite')]");
+  protected SelenideElement kafkaLogo = $x("//a[contains(text(),'UI for Apache Kafka')]");
+  protected SelenideElement kafkaVersion = $x("//a[@title='Current commit']");
+  protected SelenideElement logOutBtn = $x("//button[contains(text(),'Log out')]");
+  protected SelenideElement gitBtn = $x("//a[@href='https://github.com/provectus/kafka-ui']");
+  protected SelenideElement discordBtn = $x("//a[contains(@href,'https://discord.com/invite')]");
 
-    public List<SelenideElement> getAllVisibleElements() {
-        return Arrays.asList(kafkaLogo, kafkaVersion, gitBtn, discordBtn);
-    }
+  public List<SelenideElement> getAllVisibleElements() {
+    return Arrays.asList(kafkaLogo, kafkaVersion, gitBtn, discordBtn);
+  }
 
-    public List<SelenideElement> getAllEnabledElements() {
-        return Arrays.asList(gitBtn, discordBtn, kafkaLogo);
-    }
+  public List<SelenideElement> getAllEnabledElements() {
+    return Arrays.asList(gitBtn, discordBtn, kafkaLogo);
+  }
 }

+ 24 - 24
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/panels/enums/MenuItem.java

@@ -1,28 +1,28 @@
 package com.provectus.kafka.ui.pages.panels.enums;
 
 public enum MenuItem {
-    
-    DASHBOARD("Dashboard", "Dashboard"),
-    BROKERS("Brokers", "Brokers"),
-    TOPICS("Topics", "Topics"),
-    CONSUMERS("Consumers", "Consumers"),
-    SCHEMA_REGISTRY("Schema Registry", "Schema Registry"),
-    KAFKA_CONNECT("Kafka Connect", "Connectors"),
-    KSQL_DB("KSQL DB", "KSQL DB");
-    
-    private final String naviTitle;
-    private final String pageTitle;
-    
-    MenuItem(String naviTitle, String pageTitle) {
-        this.naviTitle = naviTitle;
-        this.pageTitle = pageTitle;
-    }
-    
-    public String getNaviTitle() {
-        return naviTitle;
-    }
-    
-    public String getPageTitle() {
-        return pageTitle;
-    }
+
+  DASHBOARD("Dashboard", "Dashboard"),
+  BROKERS("Brokers", "Brokers"),
+  TOPICS("Topics", "Topics"),
+  CONSUMERS("Consumers", "Consumers"),
+  SCHEMA_REGISTRY("Schema Registry", "Schema Registry"),
+  KAFKA_CONNECT("Kafka Connect", "Connectors"),
+  KSQL_DB("KSQL DB", "KSQL DB");
+
+  private final String naviTitle;
+  private final String pageTitle;
+
+  MenuItem(String naviTitle, String pageTitle) {
+    this.naviTitle = naviTitle;
+    this.pageTitle = pageTitle;
+  }
+
+  public String getNaviTitle() {
+    return naviTitle;
+  }
+
+  public String getPageTitle() {
+    return pageTitle;
+  }
 }

+ 124 - 122
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaCreateForm.java

@@ -1,5 +1,10 @@
 package com.provectus.kafka.ui.pages.schemas;
 
+import static com.codeborne.selenide.Selenide.$;
+import static com.codeborne.selenide.Selenide.$$x;
+import static com.codeborne.selenide.Selenide.$x;
+import static org.openqa.selenium.By.id;
+
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.SelenideElement;
 import com.codeborne.selenide.WebDriverRunner;
@@ -7,133 +12,130 @@ import com.provectus.kafka.ui.api.model.CompatibilityLevel;
 import com.provectus.kafka.ui.api.model.SchemaType;
 import com.provectus.kafka.ui.pages.BasePage;
 import io.qameta.allure.Step;
-import org.openqa.selenium.Keys;
-import org.openqa.selenium.interactions.Actions;
-
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
-
-import static com.codeborne.selenide.Selenide.*;
-import static org.openqa.selenium.By.id;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.interactions.Actions;
 
 public class SchemaCreateForm extends BasePage {
 
-    protected SelenideElement schemaNameField = $x("//input[@name='subject']");
-    protected SelenideElement pageTitle = $x("//h1['Edit']");
-    protected SelenideElement schemaTextArea = $x("//textarea[@name='schema']");
-    protected SelenideElement newSchemaInput = $("#newSchema [wrap]");
-    protected SelenideElement schemaTypeDdl = $x("//ul[@name='schemaType']");
-    protected SelenideElement compatibilityLevelList = $x("//ul[@name='compatibilityLevel']");
-    protected SelenideElement newSchemaTextArea = $x("//div[@id='newSchema']");
-    protected SelenideElement latestSchemaTextArea = $x("//div[@id='latestSchema']");
-    protected SelenideElement leftVersionDdl = $(id("left-select"));
-    protected SelenideElement rightVersionDdl = $(id("right-select"));
-    protected List<SelenideElement> visibleMarkers = $$x("//div[@class='ace_scroller']//div[contains(@class,'codeMarker')]");
-    protected List<SelenideElement> elementsCompareVersionDdl = $$x("//ul[@role='listbox']/ul/li");
-    protected String ddlElementLocator = "//li[@value='%s']";
-
-    @Step
-    public SchemaCreateForm waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        pageTitle.shouldBe(Condition.visible);
-        return this;
-    }
-
-    @Step
-    public SchemaCreateForm setSubjectName(String name) {
-        schemaNameField.setValue(name);
-        return this;
-    }
-
-    @Step
-    public SchemaCreateForm setSchemaField(String text) {
-        schemaTextArea.setValue(text);
-        return this;
-    }
-
-    @Step
-    public SchemaCreateForm selectSchemaTypeFromDropdown(SchemaType schemaType) {
-        schemaTypeDdl.shouldBe(Condition.enabled).click();
-        $x(String.format(ddlElementLocator, schemaType.getValue())).shouldBe(Condition.visible).click();
-        return this;
-    }
-
-    @Step
-    public SchemaCreateForm clickSubmitButton() {
-        clickSubmitBtn();
-        return this;
-    }
-
-    @Step
-    public SchemaCreateForm selectCompatibilityLevelFromDropdown(CompatibilityLevel.CompatibilityEnum level) {
-        compatibilityLevelList.shouldBe(Condition.enabled).click();
-        $x(String.format(ddlElementLocator, level.getValue())).shouldBe(Condition.visible).click();
-        return this;
-    }
-
-    @Step
-    public SchemaCreateForm openLeftVersionDdl() {
-        leftVersionDdl.shouldBe(Condition.enabled).click();
-        return this;
-    }
-
-    @Step
-    public SchemaCreateForm openRightVersionDdl() {
-        rightVersionDdl.shouldBe(Condition.enabled).click();
-        return this;
-    }
-
-    @Step
-    public int getVersionsNumberFromList() {
-        return elementsCompareVersionDdl.size();
-    }
-
-    @Step
-    public SchemaCreateForm selectVersionFromDropDown(int versionNumberDd) {
-        $x(String.format(ddlElementLocator, versionNumberDd)).shouldBe(Condition.visible).click();
-        return this;
-    }
-
-    @Step
-    public int getMarkedLinesNumber() {
-        return visibleMarkers.size();
-    }
-
-    @Step
-    public SchemaCreateForm setNewSchemaValue(String configJson) {
-        newSchemaTextArea.shouldBe(Condition.visible).click();
-        newSchemaInput.shouldBe(Condition.enabled);
-        new Actions(WebDriverRunner.getWebDriver())
-                .sendKeys(Keys.PAGE_UP)
-                .keyDown(Keys.SHIFT)
-                .sendKeys(Keys.PAGE_DOWN)
-                .keyUp(Keys.SHIFT)
-                .sendKeys(Keys.DELETE)
-                .perform();
-        setJsonInputValue(newSchemaInput, configJson);
-        return this;
-    }
-
-    @Step
-    public List<SelenideElement> getAllDetailsPageElements() {
-        return Stream.of(compatibilityLevelList, newSchemaTextArea, latestSchemaTextArea, submitBtn, schemaTypeDdl)
-                .collect(Collectors.toList());
-    }
-
-    @Step
-    public boolean isSubmitBtnEnabled() {
-        return isEnabled(submitBtn);
-    }
-
-    @Step
-    public boolean isSchemaDropDownEnabled() {
-        boolean enabled = true;
-        try {
-            String attribute = schemaTypeDdl.getAttribute("disabled");
-            enabled = false;
-        } catch (Throwable ignored) {
-        }
-        return enabled;
+  protected SelenideElement schemaNameField = $x("//input[@name='subject']");
+  protected SelenideElement pageTitle = $x("//h1['Edit']");
+  protected SelenideElement schemaTextArea = $x("//textarea[@name='schema']");
+  protected SelenideElement newSchemaInput = $("#newSchema [wrap]");
+  protected SelenideElement schemaTypeDdl = $x("//ul[@name='schemaType']");
+  protected SelenideElement compatibilityLevelList = $x("//ul[@name='compatibilityLevel']");
+  protected SelenideElement newSchemaTextArea = $x("//div[@id='newSchema']");
+  protected SelenideElement latestSchemaTextArea = $x("//div[@id='latestSchema']");
+  protected SelenideElement leftVersionDdl = $(id("left-select"));
+  protected SelenideElement rightVersionDdl = $(id("right-select"));
+  protected List<SelenideElement> visibleMarkers =
+      $$x("//div[@class='ace_scroller']//div[contains(@class,'codeMarker')]");
+  protected List<SelenideElement> elementsCompareVersionDdl = $$x("//ul[@role='listbox']/ul/li");
+  protected String ddlElementLocator = "//li[@value='%s']";
+
+  @Step
+  public SchemaCreateForm waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    pageTitle.shouldBe(Condition.visible);
+    return this;
+  }
+
+  @Step
+  public SchemaCreateForm setSubjectName(String name) {
+    schemaNameField.setValue(name);
+    return this;
+  }
+
+  @Step
+  public SchemaCreateForm setSchemaField(String text) {
+    schemaTextArea.setValue(text);
+    return this;
+  }
+
+  @Step
+  public SchemaCreateForm selectSchemaTypeFromDropdown(SchemaType schemaType) {
+    schemaTypeDdl.shouldBe(Condition.enabled).click();
+    $x(String.format(ddlElementLocator, schemaType.getValue())).shouldBe(Condition.visible).click();
+    return this;
+  }
+
+  @Step
+  public SchemaCreateForm clickSubmitButton() {
+    clickSubmitBtn();
+    return this;
+  }
+
+  @Step
+  public SchemaCreateForm selectCompatibilityLevelFromDropdown(CompatibilityLevel.CompatibilityEnum level) {
+    compatibilityLevelList.shouldBe(Condition.enabled).click();
+    $x(String.format(ddlElementLocator, level.getValue())).shouldBe(Condition.visible).click();
+    return this;
+  }
+
+  @Step
+  public SchemaCreateForm openLeftVersionDdl() {
+    leftVersionDdl.shouldBe(Condition.enabled).click();
+    return this;
+  }
+
+  @Step
+  public SchemaCreateForm openRightVersionDdl() {
+    rightVersionDdl.shouldBe(Condition.enabled).click();
+    return this;
+  }
+
+  @Step
+  public int getVersionsNumberFromList() {
+    return elementsCompareVersionDdl.size();
+  }
+
+  @Step
+  public SchemaCreateForm selectVersionFromDropDown(int versionNumberDd) {
+    $x(String.format(ddlElementLocator, versionNumberDd)).shouldBe(Condition.visible).click();
+    return this;
+  }
+
+  @Step
+  public int getMarkedLinesNumber() {
+    return visibleMarkers.size();
+  }
+
+  @Step
+  public SchemaCreateForm setNewSchemaValue(String configJson) {
+    newSchemaTextArea.shouldBe(Condition.visible).click();
+    newSchemaInput.shouldBe(Condition.enabled);
+    new Actions(WebDriverRunner.getWebDriver())
+        .sendKeys(Keys.PAGE_UP)
+        .keyDown(Keys.SHIFT)
+        .sendKeys(Keys.PAGE_DOWN)
+        .keyUp(Keys.SHIFT)
+        .sendKeys(Keys.DELETE)
+        .perform();
+    setJsonInputValue(newSchemaInput, configJson);
+    return this;
+  }
+
+  @Step
+  public List<SelenideElement> getAllDetailsPageElements() {
+    return Stream.of(compatibilityLevelList, newSchemaTextArea, latestSchemaTextArea, submitBtn, schemaTypeDdl)
+        .collect(Collectors.toList());
+  }
+
+  @Step
+  public boolean isSubmitBtnEnabled() {
+    return isEnabled(submitBtn);
+  }
+
+  @Step
+  public boolean isSchemaDropDownEnabled() {
+    boolean enabled = true;
+    try {
+      String attribute = schemaTypeDdl.getAttribute("disabled");
+      enabled = false;
+    } catch (Throwable ignored) {
     }
+    return enabled;
+  }
 }

+ 51 - 51
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaDetails.java

@@ -1,69 +1,69 @@
 package com.provectus.kafka.ui.pages.schemas;
 
+import static com.codeborne.selenide.Selenide.$x;
+
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.SelenideElement;
 import com.provectus.kafka.ui.pages.BasePage;
 import io.qameta.allure.Step;
 
-import static com.codeborne.selenide.Selenide.$x;
-
 public class SchemaDetails extends BasePage {
 
-    protected SelenideElement actualVersionTextArea = $x("//div[@id='schema']");
-    protected SelenideElement compatibilityField = $x("//h4[contains(text(),'Compatibility')]/../p");
-    protected SelenideElement editSchemaBtn = $x("//button[contains(text(),'Edit Schema')]");
-    protected SelenideElement removeBtn = $x("//*[contains(text(),'Remove')]");
-    protected SelenideElement confirmBtn = $x("//div[@role='dialog']//button[contains(text(),'Confirm')]");
-    protected SelenideElement schemaTypeField = $x("//h4[contains(text(),'Type')]/../p");
-    protected SelenideElement latestVersionField = $x("//h4[contains(text(),'Latest version')]/../p");
-    protected SelenideElement compareVersionBtn = $x("//button[text()='Compare Versions']");
-    protected String schemaHeaderLocator = "//h1[contains(text(),'%s')]";
+  protected SelenideElement actualVersionTextArea = $x("//div[@id='schema']");
+  protected SelenideElement compatibilityField = $x("//h4[contains(text(),'Compatibility')]/../p");
+  protected SelenideElement editSchemaBtn = $x("//button[contains(text(),'Edit Schema')]");
+  protected SelenideElement removeBtn = $x("//*[contains(text(),'Remove')]");
+  protected SelenideElement confirmBtn = $x("//div[@role='dialog']//button[contains(text(),'Confirm')]");
+  protected SelenideElement schemaTypeField = $x("//h4[contains(text(),'Type')]/../p");
+  protected SelenideElement latestVersionField = $x("//h4[contains(text(),'Latest version')]/../p");
+  protected SelenideElement compareVersionBtn = $x("//button[text()='Compare Versions']");
+  protected String schemaHeaderLocator = "//h1[contains(text(),'%s')]";
 
-    @Step
-    public SchemaDetails waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        actualVersionTextArea.shouldBe(Condition.visible);
-        return this;
-    }
+  @Step
+  public SchemaDetails waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    actualVersionTextArea.shouldBe(Condition.visible);
+    return this;
+  }
 
-    @Step
-    public String getCompatibility() {
-        return compatibilityField.getText();
-    }
+  @Step
+  public String getCompatibility() {
+    return compatibilityField.getText();
+  }
 
-    @Step
-    public boolean isSchemaHeaderVisible(String schemaName) {
-        return isVisible($x(String.format(schemaHeaderLocator, schemaName)));
-    }
+  @Step
+  public boolean isSchemaHeaderVisible(String schemaName) {
+    return isVisible($x(String.format(schemaHeaderLocator, schemaName)));
+  }
 
-    @Step
-    public int getLatestVersion() {
-        return Integer.parseInt(latestVersionField.getText());
-    }
+  @Step
+  public int getLatestVersion() {
+    return Integer.parseInt(latestVersionField.getText());
+  }
 
-    @Step
-    public String getSchemaType() {
-        return schemaTypeField.getText();
-    }
+  @Step
+  public String getSchemaType() {
+    return schemaTypeField.getText();
+  }
 
-    @Step
-    public SchemaDetails openEditSchema() {
-        editSchemaBtn.shouldBe(Condition.visible).click();
-        return this;
-    }
+  @Step
+  public SchemaDetails openEditSchema() {
+    editSchemaBtn.shouldBe(Condition.visible).click();
+    return this;
+  }
 
-    @Step
-    public SchemaDetails openCompareVersionMenu() {
-        compareVersionBtn.shouldBe(Condition.enabled).click();
-        return this;
-    }
+  @Step
+  public SchemaDetails openCompareVersionMenu() {
+    compareVersionBtn.shouldBe(Condition.enabled).click();
+    return this;
+  }
 
-    @Step
-    public SchemaDetails removeSchema() {
-        clickByJavaScript(dotMenuBtn);
-        removeBtn.shouldBe(Condition.enabled).click();
-        confirmBtn.shouldBe(Condition.visible).click();
-        confirmBtn.shouldBe(Condition.disappear);
-        return this;
-    }
+  @Step
+  public SchemaDetails removeSchema() {
+    clickByJavaScript(dotMenuBtn);
+    removeBtn.shouldBe(Condition.enabled).click();
+    confirmBtn.shouldBe(Condition.visible).click();
+    confirmBtn.shouldBe(Condition.disappear);
+    return this;
+  }
 }

+ 30 - 30
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaRegistryList.java

@@ -1,42 +1,42 @@
 package com.provectus.kafka.ui.pages.schemas;
 
+import static com.codeborne.selenide.Selenide.$x;
+import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.SCHEMA_REGISTRY;
+
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.SelenideElement;
 import com.provectus.kafka.ui.pages.BasePage;
 import io.qameta.allure.Step;
 
-import static com.codeborne.selenide.Selenide.$x;
-import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.SCHEMA_REGISTRY;
-
 public class SchemaRegistryList extends BasePage {
 
-    protected SelenideElement createSchemaBtn = $x("//button[contains(text(),'Create Schema')]");
-
-    @Step
-    public SchemaRegistryList waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        getPageTitleFromHeader(SCHEMA_REGISTRY).shouldBe(Condition.visible);
-        return this;
-    }
-
-    @Step
-    public SchemaRegistryList clickCreateSchema() {
-        clickByJavaScript(createSchemaBtn);
-        return this;
-    }
-
-    @Step
-    public SchemaRegistryList openSchema(String schemaName) {
-        getTableElement(schemaName)
-                .shouldBe(Condition.enabled).click();
-        return this;
-    }
-
-    @Step
-    public boolean isSchemaVisible(String schemaName) {
-        tableGrid.shouldBe(Condition.visible);
-        return isVisible(getTableElement(schemaName));
-    }
+  protected SelenideElement createSchemaBtn = $x("//button[contains(text(),'Create Schema')]");
+
+  @Step
+  public SchemaRegistryList waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    getPageTitleFromHeader(SCHEMA_REGISTRY).shouldBe(Condition.visible);
+    return this;
+  }
+
+  @Step
+  public SchemaRegistryList clickCreateSchema() {
+    clickByJavaScript(createSchemaBtn);
+    return this;
+  }
+
+  @Step
+  public SchemaRegistryList openSchema(String schemaName) {
+    getTableElement(schemaName)
+        .shouldBe(Condition.enabled).click();
+    return this;
+  }
+
+  @Step
+  public boolean isSchemaVisible(String schemaName) {
+    tableGrid.shouldBe(Condition.visible);
+    return isVisible(getTableElement(schemaName));
+  }
 }
 
 

+ 45 - 46
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/ProduceMessagePanel.java

@@ -1,57 +1,56 @@
 package com.provectus.kafka.ui.pages.topics;
 
+import static com.codeborne.selenide.Selenide.$x;
+import static com.codeborne.selenide.Selenide.refresh;
+
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.SelenideElement;
 import com.provectus.kafka.ui.pages.BasePage;
 import io.qameta.allure.Step;
-
 import java.util.Arrays;
 
-import static com.codeborne.selenide.Selenide.$x;
-import static com.codeborne.selenide.Selenide.refresh;
-
 public class ProduceMessagePanel extends BasePage {
 
-    protected SelenideElement keyTextArea = $x("//div[@id='key']/textarea");
-    protected SelenideElement contentTextArea = $x("//div[@id='content']/textarea");
-    protected SelenideElement headersTextArea = $x("//div[@id='headers']/textarea");
-    protected SelenideElement submitBtn = headersTextArea.$x("../../../..//button[@type='submit']");
-    protected SelenideElement partitionDdl = $x("//ul[@name='partition']");
-    protected SelenideElement keySerdeDdl = $x("//ul[@name='keySerde']");
-    protected SelenideElement contentSerdeDdl = $x("//ul[@name='valueSerde']");
-
-    @Step
-    public ProduceMessagePanel waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        Arrays.asList(partitionDdl, keySerdeDdl, contentSerdeDdl).forEach(element -> element.shouldBe(Condition.visible));
-        return this;
-    }
-
-    @Step
-    public ProduceMessagePanel setKeyField(String value) {
-        clearByKeyboard(keyTextArea);
-        keyTextArea.setValue(value);
-        return this;
-    }
-
-    @Step
-    public ProduceMessagePanel setContentFiled(String value) {
-        clearByKeyboard(contentTextArea);
-        contentTextArea.setValue(value);
-        return this;
-    }
-
-    @Step
-    public ProduceMessagePanel setHeaderFiled(String value) {
-        headersTextArea.setValue(value);
-        return this;
-    }
-
-    @Step
-    public ProduceMessagePanel submitProduceMessage() {
-        clickByActions(submitBtn);
-        submitBtn.shouldBe(Condition.disappear);
-        refresh();
-        return this;
-    }
+  protected SelenideElement keyTextArea = $x("//div[@id='key']/textarea");
+  protected SelenideElement valueTextArea = $x("//div[@id='content']/textarea");
+  protected SelenideElement headersTextArea = $x("//div[@id='headers']/textarea");
+  protected SelenideElement submitBtn = headersTextArea.$x("../../../..//button[@type='submit']");
+  protected SelenideElement partitionDdl = $x("//ul[@name='partition']");
+  protected SelenideElement keySerdeDdl = $x("//ul[@name='keySerde']");
+  protected SelenideElement contentSerdeDdl = $x("//ul[@name='valueSerde']");
+
+  @Step
+  public ProduceMessagePanel waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    Arrays.asList(partitionDdl, keySerdeDdl, contentSerdeDdl).forEach(element -> element.shouldBe(Condition.visible));
+    return this;
+  }
+
+  @Step
+  public ProduceMessagePanel setKeyField(String value) {
+    clearByKeyboard(keyTextArea);
+    keyTextArea.setValue(value);
+    return this;
+  }
+
+  @Step
+  public ProduceMessagePanel setValueFiled(String value) {
+    clearByKeyboard(valueTextArea);
+    valueTextArea.setValue(value);
+    return this;
+  }
+
+  @Step
+  public ProduceMessagePanel setHeadersFld(String value) {
+    headersTextArea.setValue(value);
+    return this;
+  }
+
+  @Step
+  public ProduceMessagePanel submitProduceMessage() {
+    clickByActions(submitBtn);
+    submitBtn.shouldBe(Condition.disappear);
+    refresh();
+    return this;
+  }
 }

+ 268 - 262
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicCreateEditForm.java

@@ -1,6 +1,15 @@
 package com.provectus.kafka.ui.pages.topics;
 
-import com.codeborne.selenide.*;
+import static com.codeborne.selenide.Selenide.$;
+import static com.codeborne.selenide.Selenide.$$;
+import static com.codeborne.selenide.Selenide.$x;
+import static org.openqa.selenium.By.id;
+
+import com.codeborne.selenide.ClickOptions;
+import com.codeborne.selenide.CollectionCondition;
+import com.codeborne.selenide.Condition;
+import com.codeborne.selenide.ElementsCollection;
+import com.codeborne.selenide.SelenideElement;
 import com.provectus.kafka.ui.pages.BasePage;
 import com.provectus.kafka.ui.pages.topics.enums.CleanupPolicyValue;
 import com.provectus.kafka.ui.pages.topics.enums.CustomParameterType;
@@ -8,267 +17,264 @@ import com.provectus.kafka.ui.pages.topics.enums.MaxSizeOnDisk;
 import com.provectus.kafka.ui.pages.topics.enums.TimeToRetain;
 import io.qameta.allure.Step;
 
-import static com.codeborne.selenide.Selenide.*;
-import static org.openqa.selenium.By.id;
-
 public class TopicCreateEditForm extends BasePage {
 
-    protected SelenideElement timeToRetainField = $x("//input[@id='timeToRetain']");
-    protected SelenideElement partitionsField = $x("//input[@name='partitions']");
-    protected SelenideElement nameField = $(id("topicFormName"));
-    protected SelenideElement maxMessageBytesField = $x("//input[@name='maxMessageBytes']");
-    protected SelenideElement minInSyncReplicasField = $x("//input[@name='minInSyncReplicas']");
-    protected SelenideElement cleanUpPolicyDdl = $x("//ul[@id='topicFormCleanupPolicy']");
-    protected SelenideElement maxSizeOnDiscDdl = $x("//ul[@id='topicFormRetentionBytes']");
-    protected SelenideElement customParameterDdl = $x("//ul[contains(@name,'customParams')]");
-    protected SelenideElement deleteCustomParameterBtn = $x("//span[contains(@title,'Delete customParam')]");
-    protected SelenideElement addCustomParameterTypeBtn = $x("//button[contains(text(),'Add Custom Parameter')]");
-    protected SelenideElement customParameterValueField = $x("//input[@placeholder='Value']");
-    protected SelenideElement validationCustomParameterValueMsg = $x("//p[contains(text(),'Value is required')]");
-    protected String ddlElementLocator = "//li[@value='%s']";
-    protected String btnTimeToRetainLocator = "//button[@class][text()='%s']";
-
-
-    @Step
-    public TopicCreateEditForm waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        nameField.shouldBe(Condition.visible);
-        return this;
-    }
-
-    public boolean isCreateTopicButtonEnabled() {
-        return isEnabled(submitBtn);
-    }
-
-    public boolean isDeleteCustomParameterButtonEnabled() {
-        return isEnabled(deleteCustomParameterBtn);
-    }
-
-    public boolean isNameFieldEnabled() {
-        return isEnabled(nameField);
-    }
-
-    @Step
-    public TopicCreateEditForm setTopicName(String topicName) {
-        sendKeysAfterClear(nameField, topicName);
-        return this;
-    }
-
-    @Step
-    public TopicCreateEditForm setMinInsyncReplicas(Integer minInsyncReplicas) {
-        minInSyncReplicasField.setValue(minInsyncReplicas.toString());
-        return this;
-    }
-
-    @Step
-    public TopicCreateEditForm setTimeToRetainDataInMs(Long ms) {
-        timeToRetainField.setValue(ms.toString());
-        return this;
-    }
-
-    @Step
-    public TopicCreateEditForm setTimeToRetainDataInMs(String ms) {
-        timeToRetainField.setValue(ms);
-        return this;
-    }
-
-    @Step
-    public TopicCreateEditForm setMaxSizeOnDiskInGB(MaxSizeOnDisk MaxSizeOnDisk) {
-        maxSizeOnDiscDdl.shouldBe(Condition.visible).click();
-        $x(String.format(ddlElementLocator, MaxSizeOnDisk.getOptionValue())).shouldBe(Condition.visible).click();
-        return this;
-    }
-
-    @Step
-    public TopicCreateEditForm clickAddCustomParameterTypeButton() {
-        addCustomParameterTypeBtn.click();
-        return this;
-    }
-
-    @Step
-    public TopicCreateEditForm openCustomParameterTypeDdl() {
-        customParameterDdl.shouldBe(Condition.visible).click();
-        ddlOptions.shouldHave(CollectionCondition.sizeGreaterThan(0));
-        return this;
-    }
-
-    @Step
-    public ElementsCollection getAllDdlOptions() {
-        return getDdlOptions();
-    }
-
-    @Step
-    public TopicCreateEditForm setCustomParameterType(CustomParameterType customParameterType) {
-        openCustomParameterTypeDdl();
-        $x(String.format(ddlElementLocator, customParameterType.getOptionValue())).shouldBe(Condition.visible).click();
-        return this;
-    }
-
-    @Step
-    public TopicCreateEditForm clearCustomParameterValue() {
-        clearByKeyboard(customParameterValueField);
-        return this;
-    }
-
-    @Step
-    public TopicCreateEditForm setNumberOfPartitions(int partitions) {
-        partitionsField.shouldBe(Condition.enabled).clear();
-        partitionsField.sendKeys(String.valueOf(partitions));
-        return this;
-    }
-
-    @Step
-    public TopicCreateEditForm setTimeToRetainDataByButtons(TimeToRetain timeToRetain) {
-        $x(String.format(btnTimeToRetainLocator, timeToRetain.getButton())).shouldBe(Condition.enabled).click();
-        return this;
-    }
-
-    @Step
-    public TopicCreateEditForm selectCleanupPolicy(CleanupPolicyValue cleanupPolicyOptionValue) {
-        cleanUpPolicyDdl.shouldBe(Condition.visible).click();
-        $x(String.format(ddlElementLocator, cleanupPolicyOptionValue.getOptionValue())).shouldBe(Condition.visible).click();
-        return this;
-    }
-
-    @Step
-    public TopicCreateEditForm selectRetentionBytes(String visibleValue) {
-        return selectFromDropDownByVisibleText("retentionBytes", visibleValue);
-    }
-
-    @Step
-    public TopicCreateEditForm selectRetentionBytes(Long optionValue) {
-        return selectFromDropDownByOptionValue("retentionBytes", optionValue.toString());
-    }
-
-    @Step
-    public TopicCreateEditForm clickCreateTopicBtn() {
-        clickSubmitBtn();
-        return this;
-    }
-
-    @Step
-    public TopicCreateEditForm addCustomParameter(String customParameterName,
-                                                  String customParameterValue) {
-        ElementsCollection customParametersElements =
-                $$("ul[role=listbox][name^=customParams][name$=name]");
-        KafkaUISelectElement kafkaUISelectElement = null;
-        if (customParametersElements.size() == 1) {
-            if ("Select".equals(customParametersElements.first().getText())) {
-                kafkaUISelectElement = new KafkaUISelectElement(customParametersElements.first());
-            }
-        } else {
-            $$("button")
-                    .find(Condition.exactText("Add Custom Parameter"))
-                    .click();
-            customParametersElements = $$("ul[role=listbox][name^=customParams][name$=name]");
-            kafkaUISelectElement = new KafkaUISelectElement(customParametersElements.last());
-        }
-        if (kafkaUISelectElement != null) {
-            kafkaUISelectElement.selectByVisibleText(customParameterName);
-        }
-        $(String.format("input[name=\"customParams.%d.value\"]", customParametersElements.size() - 1))
-                .setValue(customParameterValue);
-        return this;
-    }
-
-    @Step
-    public TopicCreateEditForm updateCustomParameter(String customParameterName,
-                                                     String customParameterValue) {
-        SelenideElement selenideElement = $$("ul[role=listbox][name^=customParams][name$=name]")
-                .find(Condition.exactText(customParameterName));
-        String name = selenideElement.getAttribute("name");
-        if (name != null) {
-            name = name.substring(0, name.lastIndexOf("."));
-        }
-        $(String.format("input[name^=%s]", name)).setValue(customParameterValue);
-        return this;
-    }
-
-    @Step
-    public String getCleanupPolicy() {
-        return new KafkaUISelectElement("cleanupPolicy").getCurrentValue();
-    }
-
-    @Step
-    public String getTimeToRetain() {
-        return timeToRetainField.getValue();
-    }
-
-    @Step
-    public String getMaxSizeOnDisk() {
-        return new KafkaUISelectElement("retentionBytes").getCurrentValue();
-    }
-
-    @Step
-    public String getMaxMessageBytes() {
-        return maxMessageBytesField.getValue();
-    }
-
-    @Step
-    public TopicCreateEditForm setMaxMessageBytes(Long bytes) {
-        maxMessageBytesField.setValue(bytes.toString());
-        return this;
-    }
-
-    @Step
-    public TopicCreateEditForm setMaxMessageBytes(String bytes) {
-        return setMaxMessageBytes(Long.parseLong(bytes));
-    }
-
-    @Step
-    public boolean isValidationMessageCustomParameterValueVisible() {
-        return isVisible(validationCustomParameterValueMsg);
-    }
-
-    @Step
-    public String getCustomParameterValue() {
-        return customParameterValueField.getValue();
-    }
-
-    private TopicCreateEditForm selectFromDropDownByOptionValue(String dropDownElementName,
-                                                                String optionValue) {
-        KafkaUISelectElement select = new KafkaUISelectElement(dropDownElementName);
-        select.selectByOptionValue(optionValue);
-        return this;
-    }
-
-    private TopicCreateEditForm selectFromDropDownByVisibleText(String dropDownElementName,
-                                                                String visibleText) {
-        KafkaUISelectElement select = new KafkaUISelectElement(dropDownElementName);
-        select.selectByVisibleText(visibleText);
-        return this;
-    }
-
-    private static class KafkaUISelectElement {
-
-        private final SelenideElement selectElement;
-
-        public KafkaUISelectElement(String selectElementName) {
-            this.selectElement = $("ul[role=listbox][name=" + selectElementName + "]");
-        }
-
-        public KafkaUISelectElement(SelenideElement selectElement) {
-            this.selectElement = selectElement;
-        }
-
-        public void selectByOptionValue(String optionValue) {
-            selectElement.click();
-            selectElement
-                    .$$x(".//ul/li[@role='option']")
-                    .find(Condition.attribute("value", optionValue))
-                    .click(ClickOptions.usingJavaScript());
-        }
-
-        public void selectByVisibleText(String visibleText) {
-            selectElement.click();
-            selectElement
-                    .$$("ul>li[role=option]")
-                    .find(Condition.exactText(visibleText))
-                    .click();
-        }
-
-        public String getCurrentValue() {
-            return selectElement.$("li").getText();
-        }
-    }
+  protected SelenideElement timeToRetainField = $x("//input[@id='timeToRetain']");
+  protected SelenideElement partitionsField = $x("//input[@name='partitions']");
+  protected SelenideElement nameField = $(id("topicFormName"));
+  protected SelenideElement maxMessageBytesField = $x("//input[@name='maxMessageBytes']");
+  protected SelenideElement minInSyncReplicasField = $x("//input[@name='minInSyncReplicas']");
+  protected SelenideElement cleanUpPolicyDdl = $x("//ul[@id='topicFormCleanupPolicy']");
+  protected SelenideElement maxSizeOnDiscDdl = $x("//ul[@id='topicFormRetentionBytes']");
+  protected SelenideElement customParameterDdl = $x("//ul[contains(@name,'customParams')]");
+  protected SelenideElement deleteCustomParameterBtn = $x("//span[contains(@title,'Delete customParam')]");
+  protected SelenideElement addCustomParameterTypeBtn = $x("//button[contains(text(),'Add Custom Parameter')]");
+  protected SelenideElement customParameterValueField = $x("//input[@placeholder='Value']");
+  protected SelenideElement validationCustomParameterValueMsg = $x("//p[contains(text(),'Value is required')]");
+  protected String ddlElementLocator = "//li[@value='%s']";
+  protected String btnTimeToRetainLocator = "//button[@class][text()='%s']";
+
+
+  @Step
+  public TopicCreateEditForm waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    nameField.shouldBe(Condition.visible);
+    return this;
+  }
+
+  public boolean isCreateTopicButtonEnabled() {
+    return isEnabled(submitBtn);
+  }
+
+  public boolean isDeleteCustomParameterButtonEnabled() {
+    return isEnabled(deleteCustomParameterBtn);
+  }
+
+  public boolean isNameFieldEnabled() {
+    return isEnabled(nameField);
+  }
+
+  @Step
+  public TopicCreateEditForm setTopicName(String topicName) {
+    sendKeysAfterClear(nameField, topicName);
+    return this;
+  }
+
+  @Step
+  public TopicCreateEditForm setMinInsyncReplicas(Integer minInsyncReplicas) {
+    minInSyncReplicasField.setValue(minInsyncReplicas.toString());
+    return this;
+  }
+
+  @Step
+  public TopicCreateEditForm setTimeToRetainDataInMs(Long ms) {
+    timeToRetainField.setValue(ms.toString());
+    return this;
+  }
+
+  @Step
+  public TopicCreateEditForm setTimeToRetainDataInMs(String ms) {
+    timeToRetainField.setValue(ms);
+    return this;
+  }
+
+  @Step
+  public TopicCreateEditForm setMaxSizeOnDiskInGB(MaxSizeOnDisk maxSizeOnDisk) {
+    maxSizeOnDiscDdl.shouldBe(Condition.visible).click();
+    $x(String.format(ddlElementLocator, maxSizeOnDisk.getOptionValue())).shouldBe(Condition.visible).click();
+    return this;
+  }
+
+  @Step
+  public TopicCreateEditForm clickAddCustomParameterTypeButton() {
+    addCustomParameterTypeBtn.click();
+    return this;
+  }
+
+  @Step
+  public TopicCreateEditForm openCustomParameterTypeDdl() {
+    customParameterDdl.shouldBe(Condition.visible).click();
+    ddlOptions.shouldHave(CollectionCondition.sizeGreaterThan(0));
+    return this;
+  }
+
+  @Step
+  public ElementsCollection getAllDdlOptions() {
+    return getDdlOptions();
+  }
+
+  @Step
+  public TopicCreateEditForm setCustomParameterType(CustomParameterType customParameterType) {
+    openCustomParameterTypeDdl();
+    $x(String.format(ddlElementLocator, customParameterType.getOptionValue())).shouldBe(Condition.visible).click();
+    return this;
+  }
+
+  @Step
+  public TopicCreateEditForm clearCustomParameterValue() {
+    clearByKeyboard(customParameterValueField);
+    return this;
+  }
+
+  @Step
+  public TopicCreateEditForm setNumberOfPartitions(int partitions) {
+    partitionsField.shouldBe(Condition.enabled).clear();
+    partitionsField.sendKeys(String.valueOf(partitions));
+    return this;
+  }
+
+  @Step
+  public TopicCreateEditForm setTimeToRetainDataByButtons(TimeToRetain timeToRetain) {
+    $x(String.format(btnTimeToRetainLocator, timeToRetain.getButton())).shouldBe(Condition.enabled).click();
+    return this;
+  }
+
+  @Step
+  public TopicCreateEditForm selectCleanupPolicy(CleanupPolicyValue cleanupPolicyOptionValue) {
+    cleanUpPolicyDdl.shouldBe(Condition.visible).click();
+    $x(String.format(ddlElementLocator, cleanupPolicyOptionValue.getOptionValue())).shouldBe(Condition.visible).click();
+    return this;
+  }
+
+  @Step
+  public TopicCreateEditForm selectRetentionBytes(String visibleValue) {
+    return selectFromDropDownByVisibleText("retentionBytes", visibleValue);
+  }
+
+  @Step
+  public TopicCreateEditForm selectRetentionBytes(Long optionValue) {
+    return selectFromDropDownByOptionValue("retentionBytes", optionValue.toString());
+  }
+
+  @Step
+  public TopicCreateEditForm clickSaveTopicBtn() {
+    clickSubmitBtn();
+    return this;
+  }
+
+  @Step
+  public TopicCreateEditForm addCustomParameter(String customParameterName,
+                                                String customParameterValue) {
+    ElementsCollection customParametersElements =
+        $$("ul[role=listbox][name^=customParams][name$=name]");
+    KafkaUiSelectElement kafkaUiSelectElement = null;
+    if (customParametersElements.size() == 1) {
+      if ("Select".equals(customParametersElements.first().getText())) {
+        kafkaUiSelectElement = new KafkaUiSelectElement(customParametersElements.first());
+      }
+    } else {
+      $$("button")
+          .find(Condition.exactText("Add Custom Parameter"))
+          .click();
+      customParametersElements = $$("ul[role=listbox][name^=customParams][name$=name]");
+      kafkaUiSelectElement = new KafkaUiSelectElement(customParametersElements.last());
+    }
+    if (kafkaUiSelectElement != null) {
+      kafkaUiSelectElement.selectByVisibleText(customParameterName);
+    }
+    $(String.format("input[name=\"customParams.%d.value\"]", customParametersElements.size() - 1))
+        .setValue(customParameterValue);
+    return this;
+  }
+
+  @Step
+  public TopicCreateEditForm updateCustomParameter(String customParameterName,
+                                                   String customParameterValue) {
+    SelenideElement selenideElement = $$("ul[role=listbox][name^=customParams][name$=name]")
+        .find(Condition.exactText(customParameterName));
+    String name = selenideElement.getAttribute("name");
+    if (name != null) {
+      name = name.substring(0, name.lastIndexOf("."));
+    }
+    $(String.format("input[name^=%s]", name)).setValue(customParameterValue);
+    return this;
+  }
+
+  @Step
+  public String getCleanupPolicy() {
+    return new KafkaUiSelectElement("cleanupPolicy").getCurrentValue();
+  }
+
+  @Step
+  public String getTimeToRetain() {
+    return timeToRetainField.getValue();
+  }
+
+  @Step
+  public String getMaxSizeOnDisk() {
+    return new KafkaUiSelectElement("retentionBytes").getCurrentValue();
+  }
+
+  @Step
+  public String getMaxMessageBytes() {
+    return maxMessageBytesField.getValue();
+  }
+
+  @Step
+  public TopicCreateEditForm setMaxMessageBytes(Long bytes) {
+    maxMessageBytesField.setValue(bytes.toString());
+    return this;
+  }
+
+  @Step
+  public TopicCreateEditForm setMaxMessageBytes(String bytes) {
+    return setMaxMessageBytes(Long.parseLong(bytes));
+  }
+
+  @Step
+  public boolean isValidationMessageCustomParameterValueVisible() {
+    return isVisible(validationCustomParameterValueMsg);
+  }
+
+  @Step
+  public String getCustomParameterValue() {
+    return customParameterValueField.getValue();
+  }
+
+  private TopicCreateEditForm selectFromDropDownByOptionValue(String dropDownElementName,
+                                                              String optionValue) {
+    KafkaUiSelectElement select = new KafkaUiSelectElement(dropDownElementName);
+    select.selectByOptionValue(optionValue);
+    return this;
+  }
+
+  private TopicCreateEditForm selectFromDropDownByVisibleText(String dropDownElementName,
+                                                              String visibleText) {
+    KafkaUiSelectElement select = new KafkaUiSelectElement(dropDownElementName);
+    select.selectByVisibleText(visibleText);
+    return this;
+  }
+
+  private static class KafkaUiSelectElement {
+
+    private final SelenideElement selectElement;
+
+    public KafkaUiSelectElement(String selectElementName) {
+      this.selectElement = $("ul[role=listbox][name=" + selectElementName + "]");
+    }
+
+    public KafkaUiSelectElement(SelenideElement selectElement) {
+      this.selectElement = selectElement;
+    }
+
+    public void selectByOptionValue(String optionValue) {
+      selectElement.click();
+      selectElement
+          .$$x(".//ul/li[@role='option']")
+          .find(Condition.attribute("value", optionValue))
+          .click(ClickOptions.usingJavaScript());
+    }
+
+    public void selectByVisibleText(String visibleText) {
+      selectElement.click();
+      selectElement
+          .$$("ul>li[role=option]")
+          .find(Condition.exactText(visibleText))
+          .click();
+    }
+
+    public String getCurrentValue() {
+      return selectElement.$("li").getText();
+    }
+  }
 }

+ 411 - 398
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicDetails.java

@@ -1,462 +1,475 @@
 package com.provectus.kafka.ui.pages.topics;
 
+import static com.codeborne.selenide.Selenide.$$x;
+import static com.codeborne.selenide.Selenide.$x;
+import static com.codeborne.selenide.Selenide.sleep;
+import static com.provectus.kafka.ui.pages.topics.TopicDetails.TopicMenu.OVERVIEW;
+import static org.testcontainers.shaded.org.apache.commons.lang3.RandomUtils.nextInt;
+
 import com.codeborne.selenide.CollectionCondition;
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.ElementsCollection;
 import com.codeborne.selenide.SelenideElement;
 import com.provectus.kafka.ui.pages.BasePage;
 import io.qameta.allure.Step;
-
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.YearMonth;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatterBuilder;
-import java.util.*;
-
-import static com.codeborne.selenide.Selenide.*;
-import static com.provectus.kafka.ui.pages.topics.TopicDetails.TopicMenu.OVERVIEW;
-import static org.testcontainers.shaded.org.apache.commons.lang3.RandomUtils.nextInt;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
 
 public class TopicDetails extends BasePage {
 
-    protected SelenideElement clearMessagesBtn = $x(("//div[contains(text(), 'Clear messages')]"));
-    protected SelenideElement recreateTopicBtn = $x("//div[text()='Recreate Topic']");
-    protected SelenideElement messageAmountCell = $x("//tbody/tr/td[5]");
-    protected SelenideElement seekTypeDdl = $x("//ul[@id='selectSeekType']/li");
-    protected SelenideElement seekTypeField = $x("//label[text()='Seek Type']//..//div/input");
-    protected SelenideElement addFiltersBtn = $x("//button[text()='Add Filters']");
-    protected SelenideElement savedFiltersLink = $x("//div[text()='Saved Filters']");
-    protected SelenideElement addFilterCodeModalTitle = $x("//label[text()='Filter code']");
-    protected SelenideElement addFilterCodeInput = $x("//div[@id='ace-editor']//textarea");
-    protected SelenideElement saveThisFilterCheckBoxAddFilterMdl = $x("//input[@name='saveFilter']");
-    protected SelenideElement displayNameInputAddFilterMdl = $x("//input[@placeholder='Enter Name']");
-    protected SelenideElement cancelBtnAddFilterMdl = $x("//button[text()='Cancel']");
-    protected SelenideElement addFilterBtnAddFilterMdl = $x("//button[text()='Add filter']");
-    protected SelenideElement addFiltersBtnMessages = $x("//button[text()='Add Filters']");
-    protected SelenideElement selectFilterBtnAddFilterMdl = $x("//button[text()='Select filter']");
-    protected SelenideElement editSettingsMenu = $x("//li[@role][contains(text(),'Edit settings')]");
-    protected SelenideElement removeTopicBtn = $x("//ul[@role='menu']//div[contains(text(),'Remove Topic')]");
-    protected SelenideElement produceMessageBtn = $x("//div//button[text()='Produce Message']");
-    protected SelenideElement contentMessageTab = $x("//html//div[@id='root']/div/main//table//p");
-    protected SelenideElement cleanUpPolicyField = $x("//div[contains(text(),'Clean Up Policy')]/../span/*");
-    protected SelenideElement partitionsField = $x("//div[contains(text(),'Partitions')]/../span");
-    protected SelenideElement backToCreateFiltersLink = $x("//div[text()='Back To create filters']");
-    protected ElementsCollection messageGridItems = $$x("//tbody//tr");
-    protected SelenideElement actualCalendarDate = $x("//div[@class='react-datepicker__current-month']");
-    protected SelenideElement previousMonthButton = $x("//button[@aria-label='Previous Month']");
-    protected SelenideElement nextMonthButton = $x("//button[@aria-label='Next Month']");
-    protected SelenideElement calendarTimeFld = $x("//input[@placeholder='Time']");
-    protected String detailsTabLtr = "//nav//a[contains(text(),'%s')]";
-    protected String dayCellLtr = "//div[@role='option'][contains(text(),'%d')]";
-    protected String seekFilterDdlLocator = "//ul[@id='selectSeekType']/ul/li[text()='%s']";
-    protected String savedFilterNameLocator = "//div[@role='savedFilter']/div[contains(text(),'%s')]";
-    protected String consumerIdLocator = "//a[@title='%s']";
-    protected String topicHeaderLocator = "//h1[contains(text(),'%s')]";
-    protected String activeFilterNameLocator = "//div[@data-testid='activeSmartFilter'][contains(text(),'%s')]";
-    protected String settingsGridValueLocator = "//tbody/tr/td/span[text()='%s']//ancestor::tr/td[2]/span";
-
-    @Step
-    public TopicDetails waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        $x(String.format(detailsTabLtr, OVERVIEW)).shouldBe(Condition.visible);
-        return this;
-    }
-
-    @Step
-    public TopicDetails openDetailsTab(TopicMenu menu) {
-        $x(String.format(detailsTabLtr, menu.toString())).shouldBe(Condition.enabled).click();
-        waitUntilSpinnerDisappear();
-        return this;
-    }
-
-    @Step
-    public String getSettingsGridValueByKey(String key) {
-        return $x(String.format(settingsGridValueLocator, key)).scrollTo().shouldBe(Condition.visible).getText();
-    }
-
-    @Step
-    public TopicDetails openDotMenu() {
-        clickByJavaScript(dotMenuBtn);
-        return this;
-    }
-
-    @Step
-    public boolean isAlertWithMessageVisible(AlertHeader header, String message) {
-        return isAlertVisible(header, message);
-    }
-
-    @Step
-    public TopicDetails clickEditSettingsMenu() {
-        editSettingsMenu.shouldBe(Condition.visible).click();
-        return this;
-    }
-
-    @Step
-    public boolean isConfirmationMdlVisible() {
-        return isConfirmationModalVisible();
-    }
-
-    @Step
-    public TopicDetails clickClearMessagesMenu() {
-        clearMessagesBtn.shouldBe(Condition.visible).click();
-        return this;
-    }
+  protected SelenideElement clearMessagesBtn = $x(("//div[contains(text(), 'Clear messages')]"));
+  protected SelenideElement recreateTopicBtn = $x("//div[text()='Recreate Topic']");
+  protected SelenideElement messageAmountCell = $x("//tbody/tr/td[5]");
+  protected SelenideElement overviewTab = $x("//a[contains(text(),'Overview')]");
+  protected SelenideElement messagesTab = $x("//a[contains(text(),'Messages')]");
+  protected SelenideElement seekTypeDdl = $x("//ul[@id='selectSeekType']//li");
+  protected SelenideElement seekTypeField = $x("//label[text()='Seek Type']//..//div/input");
+  protected SelenideElement addFiltersBtn = $x("//button[text()='Add Filters']");
+  protected SelenideElement savedFiltersLink = $x("//div[text()='Saved Filters']");
+  protected SelenideElement addFilterCodeModalTitle = $x("//label[text()='Filter code']");
+  protected SelenideElement addFilterCodeInput = $x("//div[@id='ace-editor']//textarea");
+  protected SelenideElement saveThisFilterCheckBoxAddFilterMdl = $x("//input[@name='saveFilter']");
+  protected SelenideElement displayNameInputAddFilterMdl = $x("//input[@placeholder='Enter Name']");
+  protected SelenideElement cancelBtnAddFilterMdl = $x("//button[text()='Cancel']");
+  protected SelenideElement addFilterBtnAddFilterMdl = $x("//button[text()='Add filter']");
+  protected SelenideElement addFiltersBtnMessages = $x("//button[text()='Add Filters']");
+  protected SelenideElement selectFilterBtnAddFilterMdl = $x("//button[text()='Select filter']");
+  protected SelenideElement editSettingsMenu = $x("//li[@role][contains(text(),'Edit settings')]");
+  protected SelenideElement removeTopicBtn = $x("//ul[@role='menu']//div[contains(text(),'Remove Topic')]");
+  protected SelenideElement produceMessageBtn = $x("//div//button[text()='Produce Message']");
+  protected SelenideElement contentMessageTab = $x("//html//div[@id='root']/div/main//table//p");
+  protected SelenideElement cleanUpPolicyField = $x("//div[contains(text(),'Clean Up Policy')]/../span/*");
+  protected SelenideElement partitionsField = $x("//div[contains(text(),'Partitions')]/../span");
+  protected SelenideElement backToCreateFiltersLink = $x("//div[text()='Back To create filters']");
+  protected ElementsCollection messageGridItems = $$x("//tbody//tr");
+  protected SelenideElement actualCalendarDate = $x("//div[@class='react-datepicker__current-month']");
+  protected SelenideElement previousMonthButton = $x("//button[@aria-label='Previous Month']");
+  protected SelenideElement nextMonthButton = $x("//button[@aria-label='Next Month']");
+  protected SelenideElement calendarTimeFld = $x("//input[@placeholder='Time']");
+  protected String detailsTabLtr = "//nav//a[contains(text(),'%s')]";
+  protected String dayCellLtr = "//div[@role='option'][contains(text(),'%d')]";
+  protected String seekFilterDdlLocator = "//ul[@id='selectSeekType']/ul/li[text()='%s']";
+  protected String savedFilterNameLocator = "//div[@role='savedFilter']/div[contains(text(),'%s')]";
+  protected String consumerIdLocator = "//a[@title='%s']";
+  protected String topicHeaderLocator = "//h1[contains(text(),'%s')]";
+  protected String activeFilterNameLocator = "//div[@data-testid='activeSmartFilter'][contains(text(),'%s')]";
+  protected String settingsGridValueLocator = "//tbody/tr/td/span[text()='%s']//ancestor::tr/td[2]/span";
+
+  @Step
+  public TopicDetails waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    $x(String.format(detailsTabLtr, OVERVIEW)).shouldBe(Condition.visible);
+    return this;
+  }
+
+  @Step
+  public TopicDetails openDetailsTab(TopicMenu menu) {
+    $x(String.format(detailsTabLtr, menu.toString())).shouldBe(Condition.enabled).click();
+    waitUntilSpinnerDisappear();
+    return this;
+  }
+
+  @Step
+  public String getSettingsGridValueByKey(String key) {
+    return $x(String.format(settingsGridValueLocator, key)).scrollTo().shouldBe(Condition.visible).getText();
+  }
+
+  @Step
+  public TopicDetails openDotMenu() {
+    clickByJavaScript(dotMenuBtn);
+    return this;
+  }
+
+  @Step
+  public boolean isAlertWithMessageVisible(AlertHeader header, String message) {
+    return isAlertVisible(header, message);
+  }
+
+  @Step
+  public TopicDetails clickEditSettingsMenu() {
+    editSettingsMenu.shouldBe(Condition.visible).click();
+    return this;
+  }
+
+  @Step
+  public boolean isConfirmationMdlVisible() {
+    return isConfirmationModalVisible();
+  }
+
+  @Step
+  public TopicDetails clickClearMessagesMenu() {
+    clearMessagesBtn.shouldBe(Condition.visible).click();
+    return this;
+  }
+
+  @Step
+  public boolean isClearMessagesMenuEnabled() {
+    return !Objects.requireNonNull(clearMessagesBtn.shouldBe(Condition.visible)
+            .$x("./..").getAttribute("class"))
+        .contains("disabled");
+  }
+
+  @Step
+  public TopicDetails clickRecreateTopicMenu() {
+    recreateTopicBtn.shouldBe(Condition.visible).click();
+    return this;
+  }
+
+  @Step
+  public String getCleanUpPolicy() {
+    return cleanUpPolicyField.getText();
+  }
+
+  @Step
+  public int getPartitions() {
+    return Integer.parseInt(partitionsField.getText().trim());
+  }
+
+  @Step
+  public boolean isTopicHeaderVisible(String topicName) {
+    return isVisible($x(String.format(topicHeaderLocator, topicName)));
+  }
+
+  @Step
+  public TopicDetails clickDeleteTopicMenu() {
+    removeTopicBtn.shouldBe(Condition.visible).click();
+    return this;
+  }
+
+  @Step
+  public TopicDetails clickConfirmBtnMdl() {
+    clickConfirmButton();
+    return this;
+  }
+
+  @Step
+  public TopicDetails clickProduceMessageBtn() {
+    clickByJavaScript(produceMessageBtn);
+    return this;
+  }
+
+  @Step
+  public TopicDetails selectSeekTypeDdlMessagesTab(String seekTypeName) {
+    seekTypeDdl.shouldBe(Condition.enabled).click();
+    $x(String.format(seekFilterDdlLocator, seekTypeName)).shouldBe(Condition.visible).click();
+    return this;
+  }
+
+  @Step
+  public TopicDetails setSeekTypeValueFldMessagesTab(String seekTypeValue) {
+    seekTypeField.shouldBe(Condition.enabled).sendKeys(seekTypeValue);
+    return this;
+  }
+
+  @Step
+  public TopicDetails clickSubmitFiltersBtnMessagesTab() {
+    clickByJavaScript(submitBtn);
+    waitUntilSpinnerDisappear();
+    return this;
+  }
+
+  @Step
+  public TopicDetails clickMessagesAddFiltersBtn() {
+    addFiltersBtn.shouldBe(Condition.enabled).click();
+    return this;
+  }
+
+  @Step
+  public TopicDetails clickNextButton() {
+    nextBtn.shouldBe(Condition.enabled).click();
+    waitUntilSpinnerDisappear();
+    return this;
+  }
+
+  @Step
+  public TopicDetails openSavedFiltersListMdl() {
+    savedFiltersLink.shouldBe(Condition.enabled).click();
+    backToCreateFiltersLink.shouldBe(Condition.visible);
+    return this;
+  }
+
+  @Step
+  public boolean isFilterVisibleAtSavedFiltersMdl(String filterName) {
+    return isVisible($x(String.format(savedFilterNameLocator, filterName)));
+  }
+
+  @Step
+  public TopicDetails selectFilterAtSavedFiltersMdl(String filterName) {
+    $x(String.format(savedFilterNameLocator, filterName)).shouldBe(Condition.enabled).click();
+    return this;
+  }
+
+  @Step
+  public TopicDetails clickSelectFilterBtnAtSavedFiltersMdl() {
+    selectFilterBtnAddFilterMdl.shouldBe(Condition.enabled).click();
+    addFilterCodeModalTitle.shouldBe(Condition.disappear);
+    return this;
+  }
+
+  @Step
+  public TopicDetails waitUntilAddFiltersMdlVisible() {
+    addFilterCodeModalTitle.shouldBe(Condition.visible);
+    return this;
+  }
+
+  @Step
+  public TopicDetails setFilterCodeFieldAddFilterMdl(String filterCode) {
+    addFilterCodeInput.shouldBe(Condition.enabled).sendKeys(filterCode);
+    return this;
+  }
+
+  @Step
+  public TopicDetails selectSaveThisFilterCheckboxMdl(boolean select) {
+    selectElement(saveThisFilterCheckBoxAddFilterMdl, select);
+    return this;
+  }
+
+  @Step
+  public boolean isSaveThisFilterCheckBoxSelected() {
+    return isSelected(saveThisFilterCheckBoxAddFilterMdl);
+  }
+
+  @Step
+  public TopicDetails setDisplayNameFldAddFilterMdl(String displayName) {
+    displayNameInputAddFilterMdl.shouldBe(Condition.enabled).sendKeys(displayName);
+    return this;
+  }
+
+  @Step
+  public TopicDetails clickAddFilterBtnAndCloseMdl(boolean closeModal) {
+    addFilterBtnAddFilterMdl.shouldBe(Condition.enabled).click();
+    if (closeModal) {
+      addFilterCodeModalTitle.shouldBe(Condition.hidden);
+    } else {
+      addFilterCodeModalTitle.shouldBe(Condition.visible);
+    }
+    return this;
+  }
+
+  @Step
+  public boolean isAddFilterBtnAddFilterMdlEnabled() {
+    return isEnabled(addFilterBtnAddFilterMdl);
+  }
+
+  @Step
+  public boolean isBackButtonEnabled() {
+    return isEnabled(backBtn);
+  }
+
+  @Step
+  public boolean isNextButtonEnabled() {
+    return isEnabled(nextBtn);
+  }
+
+  @Step
+  public boolean isActiveFilterVisible(String activeFilterName) {
+    return isVisible($x(String.format(activeFilterNameLocator, activeFilterName)));
+  }
+
+  public List<SelenideElement> getAllAddFilterModalVisibleElements() {
+    return Arrays.asList(savedFiltersLink, displayNameInputAddFilterMdl, addFilterBtnAddFilterMdl,
+        cancelBtnAddFilterMdl);
+  }
+
+  public List<SelenideElement> getAllAddFilterModalEnabledElements() {
+    return Arrays.asList(displayNameInputAddFilterMdl, cancelBtnAddFilterMdl);
+  }
+
+  public List<SelenideElement> getAllAddFilterModalDisabledElements() {
+    return Collections.singletonList(addFilterBtnAddFilterMdl);
+  }
+
+  @Step
+  public TopicDetails openConsumerGroup(String consumerId) {
+    $x(String.format(consumerIdLocator, consumerId)).click();
+    return this;
+  }
+
+  private void selectYear(int expectedYear) {
+    while (getActualCalendarDate().getYear() > expectedYear) {
+      clickByJavaScript(previousMonthButton);
+      sleep(1000);
+      if (LocalTime.now().plusMinutes(3).isBefore(LocalTime.now())) {
+        throw new IllegalArgumentException("Unable to select year");
+      }
+    }
+  }
+
+  private void selectMonth(int expectedMonth) {
+    while (getActualCalendarDate().getMonthValue() > expectedMonth) {
+      clickByJavaScript(previousMonthButton);
+      sleep(1000);
+      if (LocalTime.now().plusMinutes(3).isBefore(LocalTime.now())) {
+        throw new IllegalArgumentException("Unable to select month");
+      }
+    }
+  }
+
+  private void selectDay(int expectedDay) {
+    Objects.requireNonNull($$x(String.format(dayCellLtr, expectedDay)).stream()
+        .filter(day -> !Objects.requireNonNull(day.getAttribute("class")).contains("outside-month"))
+        .findFirst().orElseThrow()).shouldBe(Condition.enabled).click();
+  }
+
+  private void setTime(LocalDateTime dateTime) {
+    calendarTimeFld.shouldBe(Condition.enabled)
+        .sendKeys(String.valueOf(dateTime.getHour()), String.valueOf(dateTime.getMinute()));
+  }
+
+  @Step
+  public TopicDetails selectDateAndTimeByCalendar(LocalDateTime dateTime) {
+    setTime(dateTime);
+    selectYear(dateTime.getYear());
+    selectMonth(dateTime.getMonthValue());
+    selectDay(dateTime.getDayOfMonth());
+    return this;
+  }
+
+  private LocalDate getActualCalendarDate() {
+    String monthAndYearStr = actualCalendarDate.getText().trim();
+    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
+        .parseCaseInsensitive()
+        .append(DateTimeFormatter.ofPattern("MMMM yyyy"))
+        .toFormatter(Locale.ENGLISH);
+    YearMonth yearMonth = formatter.parse(monthAndYearStr, YearMonth::from);
+    return yearMonth.atDay(1);
+  }
 
-    @Step
-    public TopicDetails clickRecreateTopicMenu() {
-        recreateTopicBtn.shouldBe(Condition.visible).click();
-        return this;
-    }
+  @Step
+  public TopicDetails openCalendarSeekType() {
+    seekTypeField.shouldBe(Condition.enabled).click();
+    actualCalendarDate.shouldBe(Condition.visible);
+    return this;
+  }
 
-    @Step
-    public String getCleanUpPolicy() {
-        return cleanUpPolicyField.getText();
-    }
+  @Step
+  public int getMessageCountAmount() {
+    return Integer.parseInt(messageAmountCell.getText().trim());
+  }
 
-    @Step
-    public int getPartitions() {
-        return Integer.parseInt(partitionsField.getText().trim());
-    }
+  private List<TopicDetails.MessageGridItem> initItems() {
+    List<TopicDetails.MessageGridItem> gridItemList = new ArrayList<>();
+    gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0))
+        .forEach(item -> gridItemList.add(new TopicDetails.MessageGridItem(item)));
+    return gridItemList;
+  }
 
-    @Step
-    public boolean isTopicHeaderVisible(String topicName) {
-        return isVisible($x(String.format(topicHeaderLocator, topicName)));
-    }
+  @Step
+  public TopicDetails.MessageGridItem getMessageByOffset(int offset) {
+    return initItems().stream()
+        .filter(e -> e.getOffset() == offset)
+        .findFirst().orElseThrow();
+  }
 
-    @Step
-    public TopicDetails clickDeleteTopicMenu() {
-        removeTopicBtn.shouldBe(Condition.visible).click();
-        return this;
-    }
+  @Step
+  public TopicDetails.MessageGridItem getMessageByKey(String key) {
+    return initItems().stream()
+        .filter(e -> e.getKey().equals(key))
+        .findFirst().orElseThrow();
+  }
 
-    @Step
-    public TopicDetails clickConfirmBtnMdl() {
-        clickConfirmButton();
-        return this;
-    }
+  @Step
+  public List<MessageGridItem> getAllMessages() {
+    return initItems();
+  }
 
-    @Step
-    public TopicDetails clickProduceMessageBtn() {
-        clickByJavaScript(produceMessageBtn);
-        return this;
-    }
+  @Step
+  public TopicDetails.MessageGridItem getRandomMessage() {
+    return getMessageByOffset(nextInt(0, initItems().size() - 1));
+  }
 
-    @Step
-    public TopicDetails selectSeekTypeDdlMessagesTab(String seekTypeName) {
-        seekTypeDdl.shouldBe(Condition.enabled).click();
-        $x(String.format(seekFilterDdlLocator, seekTypeName)).shouldBe(Condition.visible).click();
-        return this;
-    }
+  public enum TopicMenu {
+    OVERVIEW("Overview"),
+    MESSAGES("Messages"),
+    CONSUMERS("Consumers"),
+    SETTINGS("Settings");
 
-    @Step
-    public TopicDetails setSeekTypeValueFldMessagesTab(String seekTypeValue) {
-        seekTypeField.shouldBe(Condition.enabled).sendKeys(seekTypeValue);
-        return this;
-    }
+    private final String value;
 
-    @Step
-    public TopicDetails clickSubmitFiltersBtnMessagesTab() {
-        clickByJavaScript(submitBtn);
-        waitUntilSpinnerDisappear();
-        return this;
+    TopicMenu(String value) {
+      this.value = value;
     }
 
-    @Step
-    public TopicDetails clickMessagesAddFiltersBtn() {
-        addFiltersBtn.shouldBe(Condition.enabled).click();
-        return this;
+    public String toString() {
+      return value;
     }
+  }
 
-    @Step
-    public TopicDetails clickNextButton() {
-        nextBtn.shouldBe(Condition.enabled).click();
-        waitUntilSpinnerDisappear();
-        return this;
-    }
+  public static class MessageGridItem extends BasePage {
 
-    @Step
-    public TopicDetails openSavedFiltersListMdl() {
-        savedFiltersLink.shouldBe(Condition.enabled).click();
-        backToCreateFiltersLink.shouldBe(Condition.visible);
-        return this;
-    }
+    private final SelenideElement element;
 
-    @Step
-    public boolean isFilterVisibleAtSavedFiltersMdl(String filterName) {
-        return isVisible($x(String.format(savedFilterNameLocator, filterName)));
+    private MessageGridItem(SelenideElement element) {
+      this.element = element;
     }
 
     @Step
-    public TopicDetails selectFilterAtSavedFiltersMdl(String filterName) {
-        $x(String.format(savedFilterNameLocator, filterName)).shouldBe(Condition.enabled).click();
-        return this;
+    public MessageGridItem clickExpand() {
+      clickByJavaScript(element.$x("./td[1]/span"));
+      return this;
     }
 
-    @Step
-    public TopicDetails clickSelectFilterBtnAtSavedFiltersMdl() {
-        selectFilterBtnAddFilterMdl.shouldBe(Condition.enabled).click();
-        addFilterCodeModalTitle.shouldBe(Condition.disappear);
-        return this;
+    private SelenideElement getOffsetElm() {
+      return element.$x("./td[2]");
     }
 
     @Step
-    public TopicDetails waitUntilAddFiltersMdlVisible() {
-        addFilterCodeModalTitle.shouldBe(Condition.visible);
-        return this;
+    public int getOffset() {
+      return Integer.parseInt(getOffsetElm().getText().trim());
     }
 
     @Step
-    public TopicDetails setFilterCodeFieldAddFilterMdl(String filterCode) {
-        addFilterCodeInput.shouldBe(Condition.enabled).sendKeys(filterCode);
-        return this;
+    public int getPartition() {
+      return Integer.parseInt(element.$x("./td[3]").getText().trim());
     }
 
     @Step
-    public TopicDetails selectSaveThisFilterCheckboxMdl(boolean select) {
-        selectElement(saveThisFilterCheckBoxAddFilterMdl, select);
-        return this;
+    public LocalDateTime getTimestamp() {
+      String timestampValue = element.$x("./td[4]/div").getText().trim();
+      DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy, HH:mm:ss");
+      return LocalDateTime.parse(timestampValue, formatter);
     }
 
     @Step
-    public boolean isSaveThisFilterCheckBoxSelected() {
-        return isSelected(saveThisFilterCheckBoxAddFilterMdl);
+    public String getKey() {
+      return element.$x("./td[5]").getText().trim();
     }
 
     @Step
-    public TopicDetails setDisplayNameFldAddFilterMdl(String displayName) {
-        displayNameInputAddFilterMdl.shouldBe(Condition.enabled).sendKeys(displayName);
-        return this;
+    public String getValue() {
+      return element.$x("./td[6]").getAttribute("title");
     }
 
     @Step
-    public TopicDetails clickAddFilterBtnAndCloseMdl(boolean closeModal) {
-        addFilterBtnAddFilterMdl.shouldBe(Condition.enabled).click();
-        if (closeModal) {
-            addFilterCodeModalTitle.shouldBe(Condition.hidden);
-        } else {
-            addFilterCodeModalTitle.shouldBe(Condition.visible);
-        }
-        return this;
+    public MessageGridItem openDotMenu() {
+      getOffsetElm().hover();
+      element.$x("./td[7]/div/button[@aria-label='Dropdown Toggle']")
+          .shouldBe(Condition.visible).click();
+      return this;
     }
 
     @Step
-    public boolean isAddFilterBtnAddFilterMdlEnabled() {
-        return isEnabled(addFilterBtnAddFilterMdl);
+    public MessageGridItem clickCopyToClipBoard() {
+      clickByJavaScript(element.$x("./td[7]//li[text() = 'Copy to clipboard']")
+          .shouldBe(Condition.visible));
+      return this;
     }
 
     @Step
-    public boolean isBackButtonEnabled() {
-        return isEnabled(backBtn);
-    }
-
-    @Step
-    public boolean isNextButtonEnabled() {
-        return isEnabled(nextBtn);
-    }
-
-    @Step
-    public boolean isActiveFilterVisible(String activeFilterName) {
-        return isVisible($x(String.format(activeFilterNameLocator, activeFilterName)));
-    }
-
-    public List<SelenideElement> getAllAddFilterModalVisibleElements() {
-        return Arrays.asList(savedFiltersLink, displayNameInputAddFilterMdl, addFilterBtnAddFilterMdl, cancelBtnAddFilterMdl);
-    }
-
-    public List<SelenideElement> getAllAddFilterModalEnabledElements() {
-        return Arrays.asList(displayNameInputAddFilterMdl, cancelBtnAddFilterMdl);
-    }
-
-    public List<SelenideElement> getAllAddFilterModalDisabledElements() {
-        return Collections.singletonList(addFilterBtnAddFilterMdl);
-    }
-
-    @Step
-    public TopicDetails openConsumerGroup(String consumerId) {
-        $x(String.format(consumerIdLocator, consumerId)).click();
-        return this;
-    }
-
-    @Step
-    public boolean isKeyMessageVisible(String keyMessage) {
-        return keyMessage.equals($("td[title]").getText());
-    }
-
-    @Step
-    public boolean isContentMessageVisible(String contentMessage) {
-        return contentMessage.matches(contentMessageTab.getText().trim());
-    }
-
-    private void selectYear(int expectedYear) {
-        while (getActualCalendarDate().getYear() > expectedYear) {
-            clickByJavaScript(previousMonthButton);
-            sleep(1000);
-            if (LocalTime.now().plusMinutes(3).isBefore(LocalTime.now())) {
-                throw new IllegalArgumentException("Unable to select year");
-            }
-        }
-    }
-
-    private void selectMonth(int expectedMonth) {
-        while (getActualCalendarDate().getMonthValue() > expectedMonth) {
-            clickByJavaScript(previousMonthButton);
-            sleep(1000);
-            if (LocalTime.now().plusMinutes(3).isBefore(LocalTime.now())) {
-                throw new IllegalArgumentException("Unable to select month");
-            }
-        }
-    }
-
-    private void selectDay(int expectedDay) {
-        Objects.requireNonNull($$x(String.format(dayCellLtr, expectedDay)).stream()
-                .filter(day -> !Objects.requireNonNull(day.getAttribute("class")).contains("outside-month"))
-                .findFirst().orElseThrow()).shouldBe(Condition.enabled).click();
-    }
-
-    private void setTime(LocalDateTime dateTime) {
-        calendarTimeFld.shouldBe(Condition.enabled)
-                .sendKeys(String.valueOf(dateTime.getHour()), String.valueOf(dateTime.getMinute()));
-    }
-
-    @Step
-    public TopicDetails selectDateAndTimeByCalendar(LocalDateTime dateTime) {
-        setTime(dateTime);
-        selectYear(dateTime.getYear());
-        selectMonth(dateTime.getMonthValue());
-        selectDay(dateTime.getDayOfMonth());
-        return this;
-    }
-
-    private LocalDate getActualCalendarDate() {
-        String monthAndYearStr = actualCalendarDate.getText().trim();
-        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
-                .parseCaseInsensitive()
-                .append(DateTimeFormatter.ofPattern("MMMM yyyy"))
-                .toFormatter(Locale.ENGLISH);
-        YearMonth yearMonth = formatter.parse(monthAndYearStr, YearMonth::from);
-        return yearMonth.atDay(1);
-    }
-
-    @Step
-    public TopicDetails openCalendarSeekType() {
-        seekTypeField.shouldBe(Condition.enabled).click();
-        actualCalendarDate.shouldBe(Condition.visible);
-        return this;
-    }
-
-    @Step
-    public int getMessageCountAmount() {
-        return Integer.parseInt(messageAmountCell.getText().trim());
-    }
-
-    private List<TopicDetails.MessageGridItem> initItems() {
-        List<TopicDetails.MessageGridItem> gridItemList = new ArrayList<>();
-        gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0))
-                .forEach(item -> gridItemList.add(new TopicDetails.MessageGridItem(item)));
-        return gridItemList;
-    }
-
-    @Step
-    public TopicDetails.MessageGridItem getMessageByOffset(int offset) {
-        return initItems().stream()
-                .filter(e -> e.getOffset() == offset)
-                .findFirst().orElseThrow();
-    }
-
-    @Step
-    public List<MessageGridItem> getAllMessages() {
-        return initItems();
-    }
-
-    @Step
-    public TopicDetails.MessageGridItem getRandomMessage() {
-        return getMessageByOffset(nextInt(0, initItems().size() - 1));
-    }
-
-    public enum TopicMenu {
-        OVERVIEW("Overview"),
-        MESSAGES("Messages"),
-        CONSUMERS("Consumers"),
-        SETTINGS("Settings");
-
-        private final String value;
-
-        TopicMenu(String value) {
-            this.value = value;
-        }
-
-        public String toString() {
-            return value;
-        }
-    }
-
-    public static class MessageGridItem extends BasePage {
-
-        private final SelenideElement element;
-
-        private MessageGridItem(SelenideElement element) {
-            this.element = element;
-        }
-
-        @Step
-        public MessageGridItem clickExpand() {
-            clickByJavaScript(element.$x("./td[1]/span"));
-            return this;
-        }
-
-        private SelenideElement getOffsetElm() {
-            return element.$x("./td[2]");
-        }
-
-        @Step
-        public int getOffset() {
-            return Integer.parseInt(getOffsetElm().getText().trim());
-        }
-
-        @Step
-        public int getPartition() {
-            return Integer.parseInt(element.$x("./td[3]").getText().trim());
-        }
-
-        @Step
-        public LocalDateTime getTimestamp() {
-            String timestampValue = element.$x("./td[4]/div").getText().trim();
-            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy, HH:mm:ss");
-            return LocalDateTime.parse(timestampValue, formatter);
-        }
-
-        @Step
-        public String getKey() {
-            return element.$x("./td[5]").getText().trim();
-        }
-
-        @Step
-        public String getValue() {
-            return element.$x("./td[6]/span/p").getText().trim();
-        }
-
-        @Step
-        public MessageGridItem openDotMenu() {
-            getOffsetElm().hover();
-            element.$x("./td[7]/div/button[@aria-label='Dropdown Toggle']")
-                    .shouldBe(Condition.visible).click();
-            return this;
-        }
-
-        @Step
-        public MessageGridItem clickCopyToClipBoard() {
-            clickByJavaScript(element.$x("./td[7]//li[text() = 'Copy to clipboard']")
-                    .shouldBe(Condition.visible));
-            return this;
-        }
-
-        @Step
-        public MessageGridItem clickSaveAsFile() {
-            clickByJavaScript(element.$x("./td[7]//li[text() = 'Save as a file']")
-                    .shouldBe(Condition.visible));
-            return this;
-        }
+    public MessageGridItem clickSaveAsFile() {
+      clickByJavaScript(element.$x("./td[7]//li[text() = 'Save as a file']")
+          .shouldBe(Condition.visible));
+      return this;
     }
+  }
 }

+ 41 - 42
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicSettingsTab.java

@@ -1,66 +1,65 @@
 package com.provectus.kafka.ui.pages.topics;
 
+import static com.codeborne.selenide.Selenide.$x;
+
 import com.codeborne.selenide.CollectionCondition;
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.SelenideElement;
 import com.provectus.kafka.ui.pages.BasePage;
 import io.qameta.allure.Step;
-
 import java.util.ArrayList;
 import java.util.List;
 
-import static com.codeborne.selenide.Selenide.$x;
-
 public class TopicSettingsTab extends BasePage {
 
-    protected SelenideElement defaultValueColumnHeaderLocator = $x("//div[text() = 'Default Value']");
+  protected SelenideElement defaultValueColumnHeaderLocator = $x("//div[text() = 'Default Value']");
 
-    @Step
-    public TopicSettingsTab waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        defaultValueColumnHeaderLocator.shouldBe(Condition.visible);
-        return this;
-    }
+  @Step
+  public TopicSettingsTab waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    defaultValueColumnHeaderLocator.shouldBe(Condition.visible);
+    return this;
+  }
 
-    private List<SettingsGridItem> initGridItems() {
-        List<SettingsGridItem> gridItemList = new ArrayList<>();
-        gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0))
-                .forEach(item -> gridItemList.add(new SettingsGridItem(item)));
-        return gridItemList;
-    }
+  private List<SettingsGridItem> initGridItems() {
+    List<SettingsGridItem> gridItemList = new ArrayList<>();
+    gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0))
+        .forEach(item -> gridItemList.add(new SettingsGridItem(item)));
+    return gridItemList;
+  }
 
-    private TopicSettingsTab.SettingsGridItem getItemByKey(String key) {
-        return initGridItems().stream()
-                .filter(e -> e.getKey().equals(key))
-                .findFirst().orElseThrow();
-    }
+  private TopicSettingsTab.SettingsGridItem getItemByKey(String key) {
+    return initGridItems().stream()
+        .filter(e -> e.getKey().equals(key))
+        .findFirst().orElseThrow();
+  }
 
-    @Step
-    public String getValueByKey(String key) {
-        return getItemByKey(key).getValue();
-    }
+  @Step
+  public String getValueByKey(String key) {
+    return getItemByKey(key).getValue();
+  }
 
-    public static class SettingsGridItem extends BasePage {
+  public static class SettingsGridItem extends BasePage {
 
-        private final SelenideElement element;
+    private final SelenideElement element;
 
-        public SettingsGridItem(SelenideElement element) {
-            this.element = element;
-        }
+    public SettingsGridItem(SelenideElement element) {
+      this.element = element;
+    }
 
-        @Step
-        public String getKey() {
-            return element.$x("./td[1]/span").getText().trim();
-        }
+    @Step
+    public String getKey() {
+      return element.$x("./td[1]/span").getText().trim();
+    }
 
-        @Step
-        public String getValue() {
-            return element.$x("./td[2]/span").getText().trim();
-        }
+    @Step
+    public String getValue() {
+      return element.$x("./td[2]/span").getText().trim();
+    }
 
-        @Step
-        public String getDefaultValue() {
-            return element.$x("./td[3]/span").getText().trim();
-        }
+    @Step
+    public String getDefaultValue() {
+      return element.$x("./td[3]/span").getText().trim();
     }
+  }
 }

+ 232 - 231
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/TopicsList.java

@@ -1,282 +1,283 @@
 package com.provectus.kafka.ui.pages.topics;
 
+import static com.codeborne.selenide.Condition.visible;
+import static com.codeborne.selenide.Selenide.$x;
+import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.TOPICS;
+
 import com.codeborne.selenide.CollectionCondition;
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.SelenideElement;
 import com.provectus.kafka.ui.pages.BasePage;
 import io.qameta.allure.Step;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import static com.codeborne.selenide.Condition.visible;
-import static com.codeborne.selenide.Selenide.$x;
-import static com.provectus.kafka.ui.pages.panels.enums.MenuItem.TOPICS;
-
 public class TopicsList extends BasePage {
 
-    protected SelenideElement addTopicBtn = $x("//button[normalize-space(text()) ='Add a Topic']");
-    protected SelenideElement searchField = $x("//input[@placeholder='Search by Topic Name']");
-    protected SelenideElement showInternalRadioBtn = $x("//input[@name='ShowInternalTopics']");
-    protected SelenideElement deleteSelectedTopicsBtn = $x("//button[text()='Delete selected topics']");
-    protected SelenideElement copySelectedTopicBtn = $x("//button[text()='Copy selected topic']");
-    protected SelenideElement purgeMessagesOfSelectedTopicsBtn = $x("//button[text()='Purge messages of selected topics']");
-    protected SelenideElement clearMessagesBtn = $x("//ul[contains(@class ,'open')]//div[text()='Clear Messages']");
-    protected SelenideElement recreateTopicBtn = $x("//ul[contains(@class ,'open')]//div[text()='Recreate Topic']");
-    protected SelenideElement removeTopicBtn = $x("//ul[contains(@class ,'open')]//div[text()='Remove Topic']");
-
-    @Step
-    public TopicsList waitUntilScreenReady() {
-        waitUntilSpinnerDisappear();
-        getPageTitleFromHeader(TOPICS).shouldBe(visible);
-        return this;
-    }
-
-    @Step
-    public TopicsList clickAddTopicBtn() {
-        clickByJavaScript(addTopicBtn);
-        return this;
-    }
-
-    @Step
-    public boolean isTopicVisible(String topicName) {
-        tableGrid.shouldBe(visible);
-        return isVisible(getTableElement(topicName));
-    }
-
-    @Step
-    public boolean isShowInternalRadioBtnSelected() {
-        return isSelected(showInternalRadioBtn);
-    }
-
-    @Step
-    public TopicsList setShowInternalRadioButton(boolean select) {
-        if (select) {
-            if (!showInternalRadioBtn.isSelected()) {
-                clickByJavaScript(showInternalRadioBtn);
-                waitUntilSpinnerDisappear(1);
-            }
-        } else {
-            if (showInternalRadioBtn.isSelected()) {
-                clickByJavaScript(showInternalRadioBtn);
-                waitUntilSpinnerDisappear(1);
-            }
-        }
-        return this;
-    }
-
-    @Step
-    public TopicsList openTopic(String topicName) {
-        getTopicItem(topicName).openItem();
-        return this;
-    }
-
-    @Step
-    public TopicsList openDotMenuByTopicName(String topicName) {
-        getTopicItem(topicName).openDotMenu();
-        return this;
+  protected SelenideElement addTopicBtn = $x("//button[normalize-space(text()) ='Add a Topic']");
+  protected SelenideElement searchField = $x("//input[@placeholder='Search by Topic Name']");
+  protected SelenideElement showInternalRadioBtn = $x("//input[@name='ShowInternalTopics']");
+  protected SelenideElement deleteSelectedTopicsBtn = $x("//button[text()='Delete selected topics']");
+  protected SelenideElement copySelectedTopicBtn = $x("//button[text()='Copy selected topic']");
+  protected SelenideElement purgeMessagesOfSelectedTopicsBtn =
+      $x("//button[text()='Purge messages of selected topics']");
+  protected SelenideElement clearMessagesBtn = $x("//ul[contains(@class ,'open')]//div[text()='Clear Messages']");
+  protected SelenideElement recreateTopicBtn = $x("//ul[contains(@class ,'open')]//div[text()='Recreate Topic']");
+  protected SelenideElement removeTopicBtn = $x("//ul[contains(@class ,'open')]//div[text()='Remove Topic']");
+
+  @Step
+  public TopicsList waitUntilScreenReady() {
+    waitUntilSpinnerDisappear();
+    getPageTitleFromHeader(TOPICS).shouldBe(visible);
+    return this;
+  }
+
+  @Step
+  public TopicsList clickAddTopicBtn() {
+    clickByJavaScript(addTopicBtn);
+    return this;
+  }
+
+  @Step
+  public boolean isTopicVisible(String topicName) {
+    tableGrid.shouldBe(visible);
+    return isVisible(getTableElement(topicName));
+  }
+
+  @Step
+  public boolean isShowInternalRadioBtnSelected() {
+    return isSelected(showInternalRadioBtn);
+  }
+
+  @Step
+  public TopicsList setShowInternalRadioButton(boolean select) {
+    if (select) {
+      if (!showInternalRadioBtn.isSelected()) {
+        clickByJavaScript(showInternalRadioBtn);
+        waitUntilSpinnerDisappear(1);
+      }
+    } else {
+      if (showInternalRadioBtn.isSelected()) {
+        clickByJavaScript(showInternalRadioBtn);
+        waitUntilSpinnerDisappear(1);
+      }
     }
-
-    @Step
-    public boolean isCopySelectedTopicBtnEnabled() {
-        return isEnabled(copySelectedTopicBtn);
+    return this;
+  }
+
+  @Step
+  public TopicsList openTopic(String topicName) {
+    getTopicItem(topicName).openItem();
+    return this;
+  }
+
+  @Step
+  public TopicsList openDotMenuByTopicName(String topicName) {
+    getTopicItem(topicName).openDotMenu();
+    return this;
+  }
+
+  @Step
+  public boolean isCopySelectedTopicBtnEnabled() {
+    return isEnabled(copySelectedTopicBtn);
+  }
+
+  @Step
+  public List<SelenideElement> getActionButtons() {
+    return Stream.of(deleteSelectedTopicsBtn, copySelectedTopicBtn, purgeMessagesOfSelectedTopicsBtn)
+        .collect(Collectors.toList());
+  }
+
+  @Step
+  public TopicsList clickCopySelectedTopicBtn() {
+    copySelectedTopicBtn.shouldBe(Condition.enabled).click();
+    return this;
+  }
+
+  @Step
+  public TopicsList clickPurgeMessagesOfSelectedTopicsBtn() {
+    purgeMessagesOfSelectedTopicsBtn.shouldBe(Condition.enabled).click();
+    return this;
+  }
+
+  @Step
+  public TopicsList clickClearMessagesBtn() {
+    clickByJavaScript(clearMessagesBtn.shouldBe(visible));
+    return this;
+  }
+
+  @Step
+  public TopicsList clickRecreateTopicBtn() {
+    clickByJavaScript(recreateTopicBtn.shouldBe(visible));
+    return this;
+  }
+
+  @Step
+  public TopicsList clickRemoveTopicBtn() {
+    clickByJavaScript(removeTopicBtn.shouldBe(visible));
+    return this;
+  }
+
+  @Step
+  public TopicsList clickConfirmBtnMdl() {
+    clickConfirmButton();
+    return this;
+  }
+
+  @Step
+  public TopicsList clickCancelBtnMdl() {
+    clickCancelButton();
+    return this;
+  }
+
+  @Step
+  public boolean isConfirmationMdlVisible() {
+    return isConfirmationModalVisible();
+  }
+
+  @Step
+  public boolean isAlertWithMessageVisible(AlertHeader header, String message) {
+    return isAlertVisible(header, message);
+  }
+
+  private List<SelenideElement> getVisibleColumnHeaders() {
+    return Stream.of("Replication Factor", "Number of messages", "Topic Name", "Partitions", "Out of sync replicas",
+            "Size")
+        .map(name -> $x(String.format(columnHeaderLocator, name)))
+        .collect(Collectors.toList());
+  }
+
+  private List<SelenideElement> getEnabledColumnHeaders() {
+    return Stream.of("Topic Name", "Partitions", "Out of sync replicas", "Size")
+        .map(name -> $x(String.format(columnHeaderLocator, name)))
+        .collect(Collectors.toList());
+  }
+
+  @Step
+  public List<SelenideElement> getAllVisibleElements() {
+    List<SelenideElement> visibleElements = new ArrayList<>(getVisibleColumnHeaders());
+    visibleElements.addAll(Arrays.asList(searchField, addTopicBtn, tableGrid));
+    visibleElements.addAll(getActionButtons());
+    return visibleElements;
+  }
+
+  @Step
+  public List<SelenideElement> getAllEnabledElements() {
+    List<SelenideElement> enabledElements = new ArrayList<>(getEnabledColumnHeaders());
+    enabledElements.addAll(Arrays.asList(searchField, showInternalRadioBtn, addTopicBtn));
+    return enabledElements;
+  }
+
+  private List<TopicGridItem> initGridItems() {
+    List<TopicGridItem> gridItemList = new ArrayList<>();
+    gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0))
+        .forEach(item -> gridItemList.add(new TopicGridItem(item)));
+    return gridItemList;
+  }
+
+  @Step
+  public TopicGridItem getTopicItem(String name) {
+    TopicGridItem topicGridItem = initGridItems().stream()
+        .filter(e -> e.getName().equals(name))
+        .findFirst().orElse(null);
+    if (topicGridItem == null) {
+      searchItem(name);
+      topicGridItem = initGridItems().stream()
+          .filter(e -> e.getName().equals(name))
+          .findFirst().orElseThrow();
     }
-
-    @Step
-    public List<SelenideElement> getActionButtons() {
-        return Stream.of(deleteSelectedTopicsBtn, copySelectedTopicBtn, purgeMessagesOfSelectedTopicsBtn)
-                .collect(Collectors.toList());
+    return topicGridItem;
+  }
+
+  @Step
+  public TopicGridItem getAnyNonInternalTopic() {
+    return getNonInternalTopics().stream()
+        .findAny().orElseThrow();
+  }
+
+  @Step
+  public List<TopicGridItem> getNonInternalTopics() {
+    return initGridItems().stream()
+        .filter(e -> !e.isInternal())
+        .collect(Collectors.toList());
+  }
+
+  @Step
+  public List<TopicGridItem> getInternalTopics() {
+    return initGridItems().stream()
+        .filter(TopicGridItem::isInternal)
+        .collect(Collectors.toList());
+  }
+
+  public static class TopicGridItem extends BasePage {
+
+    private final SelenideElement element;
+
+    public TopicGridItem(SelenideElement element) {
+      this.element = element;
     }
 
     @Step
-    public TopicsList clickCopySelectedTopicBtn() {
-        copySelectedTopicBtn.shouldBe(Condition.enabled).click();
-        return this;
+    public TopicsList selectItem(boolean select) {
+      selectElement(element.$x("./td[1]/input"), select);
+      return new TopicsList();
     }
 
-    @Step
-    public TopicsList clickPurgeMessagesOfSelectedTopicsBtn() {
-        purgeMessagesOfSelectedTopicsBtn.shouldBe(Condition.enabled).click();
-        return this;
+    private SelenideElement getNameElm() {
+      return element.$x("./td[2]");
     }
 
     @Step
-    public TopicsList clickClearMessagesBtn() {
-        clickByJavaScript(clearMessagesBtn.shouldBe(visible));
-        return this;
+    public boolean isInternal() {
+      boolean internal = false;
+      try {
+        internal = getNameElm().$x("./a/span").isDisplayed();
+      } catch (Throwable ignored) {
+      }
+      return internal;
     }
 
     @Step
-    public TopicsList clickRecreateTopicBtn() {
-        clickByJavaScript(recreateTopicBtn.shouldBe(visible));
-        return this;
+    public String getName() {
+      return getNameElm().$x("./a").getAttribute("title");
     }
 
     @Step
-    public TopicsList clickRemoveTopicBtn() {
-        clickByJavaScript(removeTopicBtn.shouldBe(visible));
-        return this;
+    public void openItem() {
+      getNameElm().click();
     }
 
     @Step
-    public TopicsList clickConfirmBtnMdl() {
-        clickConfirmButton();
-        return this;
+    public int getPartition() {
+      return Integer.parseInt(element.$x("./td[3]").getText().trim());
     }
 
     @Step
-    public TopicsList clickCancelBtnMdl() {
-        clickCancelButton();
-        return this;
+    public int getOutOfSyncReplicas() {
+      return Integer.parseInt(element.$x("./td[4]").getText().trim());
     }
 
     @Step
-    public boolean isConfirmationMdlVisible() {
-        return isConfirmationModalVisible();
+    public int getReplicationFactor() {
+      return Integer.parseInt(element.$x("./td[5]").getText().trim());
     }
 
     @Step
-    public boolean isAlertWithMessageVisible(AlertHeader header, String message) {
-        return isAlertVisible(header, message);
-    }
-
-    private List<SelenideElement> getVisibleColumnHeaders() {
-        return Stream.of("Replication Factor", "Number of messages", "Topic Name", "Partitions", "Out of sync replicas", "Size")
-                .map(name -> $x(String.format(columnHeaderLocator, name)))
-                .collect(Collectors.toList());
-    }
-
-    private List<SelenideElement> getEnabledColumnHeaders() {
-        return Stream.of("Topic Name", "Partitions", "Out of sync replicas", "Size")
-                .map(name -> $x(String.format(columnHeaderLocator, name)))
-                .collect(Collectors.toList());
+    public int getNumberOfMessages() {
+      return Integer.parseInt(element.$x("./td[6]").getText().trim());
     }
 
     @Step
-    public List<SelenideElement> getAllVisibleElements() {
-        List<SelenideElement> visibleElements = new ArrayList<>(getVisibleColumnHeaders());
-        visibleElements.addAll(Arrays.asList(searchField, addTopicBtn, tableGrid));
-        visibleElements.addAll(getActionButtons());
-        return visibleElements;
+    public int getSize() {
+      return Integer.parseInt(element.$x("./td[7]").getText().trim());
     }
 
     @Step
-    public List<SelenideElement> getAllEnabledElements() {
-        List<SelenideElement> enabledElements = new ArrayList<>(getEnabledColumnHeaders());
-        enabledElements.addAll(Arrays.asList(searchField, showInternalRadioBtn, addTopicBtn));
-        return enabledElements;
-    }
-
-    private List<TopicGridItem> initGridItems() {
-        List<TopicGridItem> gridItemList = new ArrayList<>();
-        gridItems.shouldHave(CollectionCondition.sizeGreaterThan(0))
-                .forEach(item -> gridItemList.add(new TopicGridItem(item)));
-        return gridItemList;
-    }
-
-    @Step
-    public TopicGridItem getTopicItem(String name) {
-        TopicGridItem topicGridItem = initGridItems().stream()
-                .filter(e -> e.getName().equals(name))
-                .findFirst().orElse(null);
-        if (topicGridItem == null) {
-            searchItem(name);
-            topicGridItem = initGridItems().stream()
-                    .filter(e -> e.getName().equals(name))
-                    .findFirst().orElseThrow();
-        }
-        return topicGridItem;
-    }
-
-    @Step
-    public TopicGridItem getAnyNonInternalTopic() {
-        return getNonInternalTopics().stream()
-                .findAny().orElseThrow();
-    }
-
-    @Step
-    public List<TopicGridItem> getNonInternalTopics() {
-        return initGridItems().stream()
-                .filter(e -> !e.isInternal())
-                .collect(Collectors.toList());
-    }
-
-    @Step
-    public List<TopicGridItem> getInternalTopics() {
-        return initGridItems().stream()
-                .filter(TopicGridItem::isInternal)
-                .collect(Collectors.toList());
-    }
-
-    public static class TopicGridItem extends BasePage {
-
-        private final SelenideElement element;
-
-        public TopicGridItem(SelenideElement element) {
-            this.element = element;
-        }
-
-        @Step
-        public TopicsList selectItem(boolean select) {
-            selectElement(element.$x("./td[1]/input"), select);
-            return new TopicsList();
-        }
-
-        private SelenideElement getNameElm() {
-            return element.$x("./td[2]");
-        }
-
-        @Step
-        public boolean isInternal() {
-            boolean internal = false;
-            try {
-                internal = getNameElm().$x("./a/span").isDisplayed();
-            } catch (Throwable ignored) {
-            }
-            return internal;
-        }
-
-        @Step
-        public String getName() {
-            return getNameElm().$x("./a").getAttribute("title");
-        }
-
-        @Step
-        public void openItem() {
-            getNameElm().click();
-        }
-
-        @Step
-        public int getPartition() {
-            return Integer.parseInt(element.$x("./td[3]").getText().trim());
-        }
-
-        @Step
-        public int getOutOfSyncReplicas() {
-            return Integer.parseInt(element.$x("./td[4]").getText().trim());
-        }
-
-        @Step
-        public int getReplicationFactor() {
-            return Integer.parseInt(element.$x("./td[5]").getText().trim());
-        }
-
-        @Step
-        public int getNumberOfMessages() {
-            return Integer.parseInt(element.$x("./td[6]").getText().trim());
-        }
-
-        @Step
-        public int getSize() {
-            return Integer.parseInt(element.$x("./td[7]").getText().trim());
-        }
-
-        @Step
-        public void openDotMenu() {
-            element.$x("./td[8]//button").click();
-        }
+    public void openDotMenu() {
+      element.$x("./td[8]//button").click();
     }
+  }
 }

+ 15 - 15
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/CleanupPolicyValue.java

@@ -2,24 +2,24 @@ package com.provectus.kafka.ui.pages.topics.enums;
 
 public enum CleanupPolicyValue {
 
-    DELETE("delete", "Delete"),
-    COMPACT("compact", "Compact"),
-    COMPACT_DELETE("compact,delete", "Compact,Delete");
+  DELETE("delete", "Delete"),
+  COMPACT("compact", "Compact"),
+  COMPACT_DELETE("compact,delete", "Compact,Delete");
 
-    private final String optionValue;
-    private final String visibleText;
+  private final String optionValue;
+  private final String visibleText;
 
-    CleanupPolicyValue(String optionValue, String visibleText) {
-        this.optionValue = optionValue;
-        this.visibleText = visibleText;
-    }
+  CleanupPolicyValue(String optionValue, String visibleText) {
+    this.optionValue = optionValue;
+    this.visibleText = visibleText;
+  }
 
-    public String getOptionValue() {
-        return optionValue;
-    }
+  public String getOptionValue() {
+    return optionValue;
+  }
 
-    public String getVisibleText() {
-        return visibleText;
-    }
+  public String getVisibleText() {
+    return visibleText;
+  }
 }
 

+ 29 - 29
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/CustomParameterType.java

@@ -2,36 +2,36 @@ package com.provectus.kafka.ui.pages.topics.enums;
 
 public enum CustomParameterType {
 
-    COMPRESSION_TYPE("compression.type"),
-    DELETE_RETENTION_MS("delete.retention.ms"),
-    FILE_DELETE_DELAY_MS("file.delete.delay.ms"),
-    FLUSH_MESSAGES("flush.messages"),
-    FLUSH_MS("flush.ms"),
-    FOLLOWER_REPLICATION_THROTTLED_REPLICAS("follower.replication.throttled.replicas"),
-    INDEX_INTERVAL_BYTES("index.interval.bytes"),
-    LEADER_REPLICATION_THROTTLED_REPLICAS("leader.replication.throttled.replicas"),
-    MAX_COMPACTION_LAG_MS("max.compaction.lag.ms"),
-    MESSAGE_DOWNCONVERSION_ENABLE("message.downconversion.enable"),
-    MESSAGE_FORMAT_VERSION("message.format.version"),
-    MESSAGE_TIMESTAMP_DIFFERENCE_MAX_MS("message.timestamp.difference.max.ms"),
-    MESSAGE_TIMESTAMP_TYPE("message.timestamp.type"),
-    MIN_CLEANABLE_DIRTY_RATIO("min.cleanable.dirty.ratio"),
-    MIN_COMPACTION_LAG_MS("min.compaction.lag.ms"),
-    PREALLOCATE("preallocate"),
-    RETENTION_BYTES("retention.bytes"),
-    SEGMENT_BYTES("segment.bytes"),
-    SEGMENT_INDEX_BYTES("segment.index.bytes"),
-    SEGMENT_JITTER_MS("segment.jitter.ms"),
-    SEGMENT_MS("segment.ms"),
-    UNCLEAN_LEADER_ELECTION_ENABLE("unclean.leader.election.enable");
+  COMPRESSION_TYPE("compression.type"),
+  DELETE_RETENTION_MS("delete.retention.ms"),
+  FILE_DELETE_DELAY_MS("file.delete.delay.ms"),
+  FLUSH_MESSAGES("flush.messages"),
+  FLUSH_MS("flush.ms"),
+  FOLLOWER_REPLICATION_THROTTLED_REPLICAS("follower.replication.throttled.replicas"),
+  INDEX_INTERVAL_BYTES("index.interval.bytes"),
+  LEADER_REPLICATION_THROTTLED_REPLICAS("leader.replication.throttled.replicas"),
+  MAX_COMPACTION_LAG_MS("max.compaction.lag.ms"),
+  MESSAGE_DOWNCONVERSION_ENABLE("message.downconversion.enable"),
+  MESSAGE_FORMAT_VERSION("message.format.version"),
+  MESSAGE_TIMESTAMP_DIFFERENCE_MAX_MS("message.timestamp.difference.max.ms"),
+  MESSAGE_TIMESTAMP_TYPE("message.timestamp.type"),
+  MIN_CLEANABLE_DIRTY_RATIO("min.cleanable.dirty.ratio"),
+  MIN_COMPACTION_LAG_MS("min.compaction.lag.ms"),
+  PREALLOCATE("preallocate"),
+  RETENTION_BYTES("retention.bytes"),
+  SEGMENT_BYTES("segment.bytes"),
+  SEGMENT_INDEX_BYTES("segment.index.bytes"),
+  SEGMENT_JITTER_MS("segment.jitter.ms"),
+  SEGMENT_MS("segment.ms"),
+  UNCLEAN_LEADER_ELECTION_ENABLE("unclean.leader.election.enable");
 
-    private final String optionValue;
+  private final String optionValue;
 
-    CustomParameterType(String optionValue) {
-        this.optionValue = optionValue;
-    }
+  CustomParameterType(String optionValue) {
+    this.optionValue = optionValue;
+  }
 
-    public String getOptionValue() {
-        return optionValue;
-    }
+  public String getOptionValue() {
+    return optionValue;
+  }
 }

+ 17 - 17
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/MaxSizeOnDisk.java

@@ -2,26 +2,26 @@ package com.provectus.kafka.ui.pages.topics.enums;
 
 public enum MaxSizeOnDisk {
 
-    NOT_SET("-1", "Not Set"),
-    SIZE_1_GB("1073741824", "1 GB"),
-    SIZE_10_GB("10737418240", "10 GB"),
-    SIZE_20_GB("21474836480", "20 GB"),
-    SIZE_50_GB("53687091200", "50 GB");
+  NOT_SET("-1", "Not Set"),
+  SIZE_1_GB("1073741824", "1 GB"),
+  SIZE_10_GB("10737418240", "10 GB"),
+  SIZE_20_GB("21474836480", "20 GB"),
+  SIZE_50_GB("53687091200", "50 GB");
 
-    private final String optionValue;
-    private final String visibleText;
+  private final String optionValue;
+  private final String visibleText;
 
-    MaxSizeOnDisk(String optionValue, String visibleText) {
-        this.optionValue = optionValue;
-        this.visibleText = visibleText;
-    }
+  MaxSizeOnDisk(String optionValue, String visibleText) {
+    this.optionValue = optionValue;
+    this.visibleText = visibleText;
+  }
 
-    public String getOptionValue() {
-        return optionValue;
-    }
+  public String getOptionValue() {
+    return optionValue;
+  }
 
-    public String getVisibleText() {
-        return visibleText;
-    }
+  public String getVisibleText() {
+    return visibleText;
+  }
 }
 

+ 17 - 17
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/enums/TimeToRetain.java

@@ -2,25 +2,25 @@ package com.provectus.kafka.ui.pages.topics.enums;
 
 public enum TimeToRetain {
 
-    BTN_12_HOURS("12 hours", "43200000"),
-    BTN_1_DAY("1 day", "86400000"),
-    BTN_2_DAYS("2 days", "172800000"),
-    BTN_7_DAYS("7 days", "604800000"),
-    BTN_4_WEEKS("4 weeks", "2419200000");
+  BTN_12_HOURS("12 hours", "43200000"),
+  BTN_1_DAY("1 day", "86400000"),
+  BTN_2_DAYS("2 days", "172800000"),
+  BTN_7_DAYS("7 days", "604800000"),
+  BTN_4_WEEKS("4 weeks", "2419200000");
 
-    private final String button;
-    private final String value;
+  private final String button;
+  private final String value;
 
-    TimeToRetain(String button, String value) {
-        this.button = button;
-        this.value = value;
-    }
+  TimeToRetain(String button, String value) {
+    this.button = button;
+    this.value = value;
+  }
 
-    public String getButton() {
-        return button;
-    }
+  public String getButton() {
+    return button;
+  }
 
-    public String getValue() {
-        return value;
-    }
+  public String getValue() {
+    return value;
+  }
 }

+ 232 - 222
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/services/ApiService.java

@@ -1,272 +1,282 @@
 package com.provectus.kafka.ui.services;
 
+import static com.codeborne.selenide.Selenide.sleep;
+import static com.provectus.kafka.ui.utilities.FileUtils.fileToString;
+
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.provectus.kafka.ui.api.ApiClient;
-import com.provectus.kafka.ui.api.api.*;
-import com.provectus.kafka.ui.api.model.*;
+import com.provectus.kafka.ui.api.api.KafkaConnectApi;
+import com.provectus.kafka.ui.api.api.KsqlApi;
+import com.provectus.kafka.ui.api.api.MessagesApi;
+import com.provectus.kafka.ui.api.api.SchemasApi;
+import com.provectus.kafka.ui.api.api.TopicsApi;
+import com.provectus.kafka.ui.api.model.CreateTopicMessage;
+import com.provectus.kafka.ui.api.model.KsqlCommandV2;
+import com.provectus.kafka.ui.api.model.KsqlCommandV2Response;
+import com.provectus.kafka.ui.api.model.KsqlResponse;
+import com.provectus.kafka.ui.api.model.NewConnector;
+import com.provectus.kafka.ui.api.model.NewSchemaSubject;
+import com.provectus.kafka.ui.api.model.TopicCreation;
 import com.provectus.kafka.ui.models.Connector;
 import com.provectus.kafka.ui.models.Schema;
 import com.provectus.kafka.ui.models.Topic;
-import com.provectus.kafka.ui.pages.ksqlDb.models.Stream;
-import com.provectus.kafka.ui.pages.ksqlDb.models.Table;
+import com.provectus.kafka.ui.pages.ksqldb.models.Stream;
+import com.provectus.kafka.ui.pages.ksqldb.models.Table;
 import com.provectus.kafka.ui.settings.BaseSource;
 import io.qameta.allure.Step;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.reactive.function.client.WebClientResponseException;
-
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-
-import static com.codeborne.selenide.Selenide.sleep;
-import static com.provectus.kafka.ui.utilities.FileUtils.fileToString;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
 
 
 @Slf4j
 public class ApiService extends BaseSource {
 
-    @SneakyThrows
-    private TopicsApi topicApi() {
-        return new TopicsApi(new ApiClient().setBasePath(BASE_API_URL));
-    }
+  @SneakyThrows
+  private TopicsApi topicApi() {
+    return new TopicsApi(new ApiClient().setBasePath(BASE_API_URL));
+  }
 
-    @SneakyThrows
-    private SchemasApi schemaApi() {
-        return new SchemasApi(new ApiClient().setBasePath(BASE_API_URL));
-    }
+  @SneakyThrows
+  private SchemasApi schemaApi() {
+    return new SchemasApi(new ApiClient().setBasePath(BASE_API_URL));
+  }
 
-    @SneakyThrows
-    private KafkaConnectApi connectorApi() {
-        return new KafkaConnectApi(new ApiClient().setBasePath(BASE_API_URL));
-    }
+  @SneakyThrows
+  private KafkaConnectApi connectorApi() {
+    return new KafkaConnectApi(new ApiClient().setBasePath(BASE_API_URL));
+  }
 
-    @SneakyThrows
-    private MessagesApi messageApi() {
-        return new MessagesApi(new ApiClient().setBasePath(BASE_API_URL));
-    }
+  @SneakyThrows
+  private MessagesApi messageApi() {
+    return new MessagesApi(new ApiClient().setBasePath(BASE_API_URL));
+  }
 
-    @SneakyThrows
-    private KsqlApi ksqlApi() {
-        return new KsqlApi(new ApiClient().setBasePath(BASE_API_URL));
-    }
+  @SneakyThrows
+  private KsqlApi ksqlApi() {
+    return new KsqlApi(new ApiClient().setBasePath(BASE_API_URL));
+  }
 
-    @SneakyThrows
-    private void createTopic(String clusterName, String topicName) {
-        TopicCreation topic = new TopicCreation();
-        topic.setName(topicName);
-        topic.setPartitions(1);
-        topic.setReplicationFactor(1);
-        try {
-            topicApi().createTopic(clusterName, topic).block();
-            sleep(2000);
-        } catch (WebClientResponseException ex) {
-            ex.printStackTrace();
-        }
+  @SneakyThrows
+  private void createTopic(String clusterName, String topicName) {
+    TopicCreation topic = new TopicCreation();
+    topic.setName(topicName);
+    topic.setPartitions(1);
+    topic.setReplicationFactor(1);
+    try {
+      topicApi().createTopic(clusterName, topic).block();
+      sleep(2000);
+    } catch (WebClientResponseException ex) {
+      ex.printStackTrace();
     }
+  }
 
-    @Step
-    public ApiService createTopic(Topic topic) {
-        createTopic(CLUSTER_NAME, topic.getName());
-        return this;
-    }
+  @Step
+  public ApiService createTopic(Topic topic) {
+    createTopic(CLUSTER_NAME, topic.getName());
+    return this;
+  }
 
-    @SneakyThrows
-    private void deleteTopic(String clusterName, String topicName) {
-        try {
-            topicApi().deleteTopic(clusterName, topicName).block();
-        } catch (WebClientResponseException ignore) {
-        }
+  @SneakyThrows
+  private void deleteTopic(String clusterName, String topicName) {
+    try {
+      topicApi().deleteTopic(clusterName, topicName).block();
+    } catch (WebClientResponseException ignored) {
     }
+  }
 
-    @Step
-    public ApiService deleteTopic(String topicName) {
-        deleteTopic(CLUSTER_NAME, topicName);
-        return this;
-    }
+  @Step
+  public ApiService deleteTopic(String topicName) {
+    deleteTopic(CLUSTER_NAME, topicName);
+    return this;
+  }
 
-    @SneakyThrows
-    private void createSchema(String clusterName, Schema schema) {
-        NewSchemaSubject schemaSubject = new NewSchemaSubject();
-        schemaSubject.setSubject(schema.getName());
-        schemaSubject.setSchema(fileToString(schema.getValuePath()));
-        schemaSubject.setSchemaType(schema.getType());
-        try {
-            schemaApi().createNewSchema(clusterName, schemaSubject).block();
-        } catch (WebClientResponseException ex) {
-            ex.printStackTrace();
-        }
+  @SneakyThrows
+  private void createSchema(String clusterName, Schema schema) {
+    NewSchemaSubject schemaSubject = new NewSchemaSubject();
+    schemaSubject.setSubject(schema.getName());
+    schemaSubject.setSchema(fileToString(schema.getValuePath()));
+    schemaSubject.setSchemaType(schema.getType());
+    try {
+      schemaApi().createNewSchema(clusterName, schemaSubject).block();
+    } catch (WebClientResponseException ex) {
+      ex.printStackTrace();
     }
+  }
 
-    @Step
-    public ApiService createSchema(Schema schema) {
-        createSchema(CLUSTER_NAME, schema);
-        return this;
-    }
+  @Step
+  public ApiService createSchema(Schema schema) {
+    createSchema(CLUSTER_NAME, schema);
+    return this;
+  }
 
-    @SneakyThrows
-    private void deleteSchema(String clusterName, String schemaName) {
-        try {
-            schemaApi().deleteSchema(clusterName, schemaName).block();
-        } catch (WebClientResponseException ignore) {
-        }
+  @SneakyThrows
+  private void deleteSchema(String clusterName, String schemaName) {
+    try {
+      schemaApi().deleteSchema(clusterName, schemaName).block();
+    } catch (WebClientResponseException ignored) {
     }
+  }
 
-    @Step
-    public ApiService deleteSchema(String schemaName) {
-        deleteSchema(CLUSTER_NAME, schemaName);
-        return this;
-    }
+  @Step
+  public ApiService deleteSchema(String schemaName) {
+    deleteSchema(CLUSTER_NAME, schemaName);
+    return this;
+  }
 
-    @SneakyThrows
-    private void deleteConnector(String clusterName, String connectName, String connectorName) {
-        try {
-            connectorApi().deleteConnector(clusterName, connectName, connectorName).block();
-        } catch (WebClientResponseException ignore) {
-        }
+  @SneakyThrows
+  private void deleteConnector(String clusterName, String connectName, String connectorName) {
+    try {
+      connectorApi().deleteConnector(clusterName, connectName, connectorName).block();
+    } catch (WebClientResponseException ignored) {
     }
+  }
 
-    @Step
-    public ApiService deleteConnector(String connectName, String connectorName) {
-        deleteConnector(CLUSTER_NAME, connectName, connectorName);
-        return this;
-    }
+  @Step
+  public ApiService deleteConnector(String connectName, String connectorName) {
+    deleteConnector(CLUSTER_NAME, connectName, connectorName);
+    return this;
+  }
 
-    @Step
-    public ApiService deleteConnector(String connectorName) {
-        deleteConnector(CLUSTER_NAME, CONNECT_NAME, connectorName);
-        return this;
-    }
+  @Step
+  public ApiService deleteConnector(String connectorName) {
+    deleteConnector(CLUSTER_NAME, CONNECT_NAME, connectorName);
+    return this;
+  }
 
-    @SneakyThrows
-    private void createConnector(String clusterName, String connectName, Connector connector) {
-        NewConnector connectorProperties = new NewConnector();
-        connectorProperties.setName(connector.getName());
-        Map<String, Object> configMap = new ObjectMapper().readValue(connector.getConfig(), HashMap.class);
-        connectorProperties.setConfig(configMap);
-        try {
-            connectorApi().deleteConnector(clusterName, connectName, connector.getName()).block();
-        } catch (WebClientResponseException ignored) {
-        }
-        connectorApi().createConnector(clusterName, connectName, connectorProperties).block();
+  @SneakyThrows
+  private void createConnector(String clusterName, String connectName, Connector connector) {
+    NewConnector connectorProperties = new NewConnector();
+    connectorProperties.setName(connector.getName());
+    Map<String, Object> configMap = new ObjectMapper().readValue(connector.getConfig(), HashMap.class);
+    connectorProperties.setConfig(configMap);
+    try {
+      connectorApi().deleteConnector(clusterName, connectName, connector.getName()).block();
+    } catch (WebClientResponseException ignored) {
     }
+    connectorApi().createConnector(clusterName, connectName, connectorProperties).block();
+  }
 
-    @Step
-    public ApiService createConnector(String connectName, Connector connector) {
-        createConnector(CLUSTER_NAME, connectName, connector);
-        return this;
-    }
+  @Step
+  public ApiService createConnector(String connectName, Connector connector) {
+    createConnector(CLUSTER_NAME, connectName, connector);
+    return this;
+  }
 
-    @Step
-    public ApiService createConnector(Connector connector) {
-        createConnector(CLUSTER_NAME, CONNECT_NAME, connector);
-        return this;
-    }
+  @Step
+  public ApiService createConnector(Connector connector) {
+    createConnector(CLUSTER_NAME, CONNECT_NAME, connector);
+    return this;
+  }
 
-    @Step
-    public String getFirstConnectName(String clusterName) {
-        return Objects.requireNonNull(connectorApi().getConnects(clusterName).blockFirst()).getName();
-    }
+  @Step
+  public String getFirstConnectName(String clusterName) {
+    return Objects.requireNonNull(connectorApi().getConnects(clusterName).blockFirst()).getName();
+  }
 
-    @SneakyThrows
-    private void sendMessage(String clusterName, Topic topic) {
-        CreateTopicMessage createMessage = new CreateTopicMessage();
-        createMessage.setPartition(0);
-        createMessage.setKeySerde("String");
-        createMessage.setValueSerde("String");
-        createMessage.setKey(topic.getMessageKey());
-        createMessage.setContent(topic.getMessageContent());
-        try {
-            messageApi().sendTopicMessages(clusterName, topic.getName(), createMessage).block();
-        } catch (WebClientResponseException ex) {
-            ex.getRawStatusCode();
-        }
+  @SneakyThrows
+  private void sendMessage(String clusterName, Topic topic) {
+    CreateTopicMessage createMessage = new CreateTopicMessage();
+    createMessage.setPartition(0);
+    createMessage.setKeySerde("String");
+    createMessage.setValueSerde("String");
+    createMessage.setKey(topic.getMessageKey());
+    createMessage.setContent(topic.getMessageValue());
+    try {
+      messageApi().sendTopicMessages(clusterName, topic.getName(), createMessage).block();
+    } catch (WebClientResponseException ex) {
+      ex.getRawStatusCode();
     }
+  }
 
-    @Step
-    public ApiService sendMessage(Topic topic) {
-        sendMessage(CLUSTER_NAME, topic);
-        return this;
-    }
+  @Step
+  public ApiService sendMessage(Topic topic) {
+    sendMessage(CLUSTER_NAME, topic);
+    return this;
+  }
 
-    @Step
-    public ApiService createStream(Stream stream) {
-        KsqlCommandV2Response pipeIdStream = ksqlApi()
-                .executeKsql(CLUSTER_NAME, new KsqlCommandV2()
-                        .ksql(String.format("CREATE STREAM %s (profileId VARCHAR, latitude DOUBLE, longitude DOUBLE) ",
-                                stream.getName())
-                                + String.format("WITH (kafka_topic='%s', value_format='json', partitions=1);",
-                                stream.getTopicName())))
-                .block();
-        assert pipeIdStream != null;
-        List<KsqlResponse> responseListStream = ksqlApi()
-                .openKsqlResponsePipe(CLUSTER_NAME, pipeIdStream.getPipeId())
-                .collectList()
-                .block();
-        assert Objects.requireNonNull(responseListStream).size() != 0;
-        return this;
-    }
+  @Step
+  public ApiService createStream(Stream stream) {
+    KsqlCommandV2Response pipeIdStream = ksqlApi()
+        .executeKsql(CLUSTER_NAME, new KsqlCommandV2()
+            .ksql(String.format("CREATE STREAM %s (profileId VARCHAR, latitude DOUBLE, longitude DOUBLE) ",
+                stream.getName())
+                + String.format("WITH (kafka_topic='%s', value_format='json', partitions=1);",
+                stream.getTopicName())))
+        .block();
+    assert pipeIdStream != null;
+    List<KsqlResponse> responseListStream = ksqlApi()
+        .openKsqlResponsePipe(CLUSTER_NAME, pipeIdStream.getPipeId())
+        .collectList()
+        .block();
+    assert Objects.requireNonNull(responseListStream).size() != 0;
+    return this;
+  }
 
-    @Step
-    public ApiService createTables(Table firstTable, Table secondTable) {
-        KsqlCommandV2Response pipeIdTable1 = ksqlApi()
-                .executeKsql(CLUSTER_NAME, new KsqlCommandV2()
-                        .ksql(String.format("CREATE TABLE %s AS ", firstTable.getName())
-                                + "  SELECT profileId, "
-                                + "         LATEST_BY_OFFSET(latitude) AS la, "
-                                + "         LATEST_BY_OFFSET(longitude) AS lo "
-                                + String.format("  FROM %s ", firstTable.getStreamName())
-                                + "  GROUP BY profileId "
-                                + "  EMIT CHANGES;"))
-                .block();
-        assert pipeIdTable1 != null;
-        List<KsqlResponse> responseListTable = ksqlApi()
-                .openKsqlResponsePipe(CLUSTER_NAME, pipeIdTable1.getPipeId())
-                .collectList()
-                .block();
-        assert Objects.requireNonNull(responseListTable).size() != 0;
-        KsqlCommandV2Response pipeIdTable2 = ksqlApi()
-                .executeKsql(CLUSTER_NAME, new KsqlCommandV2()
-                        .ksql(String.format("CREATE TABLE %s AS ", secondTable.getName())
-                                + "  SELECT ROUND(GEO_DISTANCE(la, lo, 37.4133, -122.1162), -1) AS distanceInMiles, "
-                                + "         COLLECT_LIST(profileId) AS riders, "
-                                + "         COUNT(*) AS count "
-                                + String.format("  FROM %s ", firstTable.getName())
-                                + "  GROUP BY ROUND(GEO_DISTANCE(la, lo, 37.4133, -122.1162), -1);"))
-                .block();
-        assert pipeIdTable2 != null;
-        List<KsqlResponse> responseListTable2 = ksqlApi()
-                .openKsqlResponsePipe(CLUSTER_NAME, pipeIdTable2.getPipeId())
-                .collectList()
-                .block();
-        assert Objects.requireNonNull(responseListTable2).size() != 0;
-        return this;
-    }
+  @Step
+  public ApiService createTables(Table firstTable, Table secondTable) {
+    KsqlCommandV2Response pipeIdTable1 = ksqlApi()
+        .executeKsql(CLUSTER_NAME, new KsqlCommandV2()
+            .ksql(String.format("CREATE TABLE %s AS ", firstTable.getName())
+                + "  SELECT profileId, "
+                + "         LATEST_BY_OFFSET(latitude) AS la, "
+                + "         LATEST_BY_OFFSET(longitude) AS lo "
+                + String.format("  FROM %s ", firstTable.getStreamName())
+                + "  GROUP BY profileId "
+                + "  EMIT CHANGES;"))
+        .block();
+    assert pipeIdTable1 != null;
+    List<KsqlResponse> responseListTable = ksqlApi()
+        .openKsqlResponsePipe(CLUSTER_NAME, pipeIdTable1.getPipeId())
+        .collectList()
+        .block();
+    assert Objects.requireNonNull(responseListTable).size() != 0;
+    KsqlCommandV2Response pipeIdTable2 = ksqlApi()
+        .executeKsql(CLUSTER_NAME, new KsqlCommandV2()
+            .ksql(String.format("CREATE TABLE %s AS ", secondTable.getName())
+                + "  SELECT ROUND(GEO_DISTANCE(la, lo, 37.4133, -122.1162), -1) AS distanceInMiles, "
+                + "         COLLECT_LIST(profileId) AS riders, "
+                + "         COUNT(*) AS count "
+                + String.format("  FROM %s ", firstTable.getName())
+                + "  GROUP BY ROUND(GEO_DISTANCE(la, lo, 37.4133, -122.1162), -1);"))
+        .block();
+    assert pipeIdTable2 != null;
+    List<KsqlResponse> responseListTable2 = ksqlApi()
+        .openKsqlResponsePipe(CLUSTER_NAME, pipeIdTable2.getPipeId())
+        .collectList()
+        .block();
+    assert Objects.requireNonNull(responseListTable2).size() != 0;
+    return this;
+  }
 
-    @Step
-    public ApiService insertInto(Stream stream) {
-        String streamName = stream.getName();
-        KsqlCommandV2Response pipeIdInsert = ksqlApi()
-                .executeKsql(CLUSTER_NAME, new KsqlCommandV2()
-                        .ksql("INSERT INTO " + streamName + " (profileId, latitude, longitude) VALUES ('c2309eec', 37.7877, -122.4205);"
-                                + "INSERT INTO " + streamName +
-                                " (profileId, latitude, longitude) VALUES ('18f4ea86', 37.3903, -122.0643); "
-                                + "INSERT INTO " + streamName +
-                                " (profileId, latitude, longitude) VALUES ('4ab5cbad', 37.3952, -122.0813); "
-                                + "INSERT INTO " + streamName +
-                                " (profileId, latitude, longitude) VALUES ('8b6eae59', 37.3944, -122.0813); "
-                                + "INSERT INTO " + streamName +
-                                " (profileId, latitude, longitude) VALUES ('4a7c7b41', 37.4049, -122.0822); "
-                                + "INSERT INTO " + streamName +
-                                " (profileId, latitude, longitude) VALUES ('4ddad000', 37.7857, -122.4011);"))
-                .block();
-        assert pipeIdInsert != null;
-        List<KsqlResponse> responseListInsert = ksqlApi()
-                .openKsqlResponsePipe(CLUSTER_NAME, pipeIdInsert.getPipeId())
-                .collectList()
-                .block();
-        assert Objects.requireNonNull(responseListInsert).size() != 0;
-        return this;
-    }
+  @Step
+  public ApiService insertInto(Stream stream) {
+    String streamName = stream.getName();
+    KsqlCommandV2Response pipeIdInsert = ksqlApi()
+        .executeKsql(CLUSTER_NAME, new KsqlCommandV2()
+            .ksql("INSERT INTO " + streamName
+                + " (profileId, latitude, longitude) VALUES ('c2309eec', 37.7877, -122.4205);"
+                + "INSERT INTO " + streamName
+                + " (profileId, latitude, longitude) VALUES ('18f4ea86', 37.3903, -122.0643); "
+                + "INSERT INTO " + streamName
+                + " (profileId, latitude, longitude) VALUES ('4ab5cbad', 37.3952, -122.0813); "
+                + "INSERT INTO " + streamName
+                + " (profileId, latitude, longitude) VALUES ('8b6eae59', 37.3944, -122.0813); "
+                + "INSERT INTO " + streamName
+                + " (profileId, latitude, longitude) VALUES ('4a7c7b41', 37.4049, -122.0822); "
+                + "INSERT INTO " + streamName
+                + " (profileId, latitude, longitude) VALUES ('4ddad000', 37.7857, -122.4011);"))
+        .block();
+    assert pipeIdInsert != null;
+    List<KsqlResponse> responseListInsert = ksqlApi()
+        .openKsqlResponsePipe(CLUSTER_NAME, pipeIdInsert.getPipeId())
+        .collectList()
+        .block();
+    assert Objects.requireNonNull(responseListInsert).size() != 0;
+    return this;
+  }
 }

+ 19 - 19
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/BaseSource.java

@@ -1,29 +1,29 @@
 package com.provectus.kafka.ui.settings;
 
+import static com.provectus.kafka.ui.variables.Browser.LOCAL;
+
 import com.provectus.kafka.ui.settings.configs.Config;
 import org.aeonbits.owner.ConfigFactory;
 
-import static com.provectus.kafka.ui.variables.Browser.LOCAL;
-
 public abstract class BaseSource {
 
-    public static final String CLUSTER_NAME = "local";
-    public static final String CONNECT_NAME = "first";
-    private static final String LOCAL_HOST = "localhost";
-    private static Config config;
-    public static final String BROWSER = config().browser();
-    public static final String SUITE_NAME = config().suite();
-    public static final String BASE_HOST = BROWSER.equals(LOCAL)
-            ? LOCAL_HOST
-            : "host.docker.internal";
-    public static final String REMOTE_URL = String.format("http://%s:4444/wd/hub", LOCAL_HOST);
-    public static final String BASE_API_URL = String.format("http://%s:8080", LOCAL_HOST);
-    public static final String BASE_UI_URL = String.format("http://%s:8080", BASE_HOST);
+  public static final String CLUSTER_NAME = "local";
+  public static final String CONNECT_NAME = "first";
+  private static final String LOCAL_HOST = "localhost";
+  public static final String REMOTE_URL = String.format("http://%s:4444/wd/hub", LOCAL_HOST);
+  public static final String BASE_API_URL = String.format("http://%s:8080", LOCAL_HOST);
+  private static Config config;
+  public static final String BROWSER = config().browser();
+  public static final String BASE_HOST = BROWSER.equals(LOCAL)
+      ? LOCAL_HOST
+      : "host.docker.internal";
+  public static final String BASE_UI_URL = String.format("http://%s:8080", BASE_HOST);
+  public static final String SUITE_NAME = config().suite();
 
-    private static Config config() {
-        if (config == null) {
-            config = ConfigFactory.create(Config.class, System.getProperties());
-        }
-        return config;
+  private static Config config() {
+    if (config == null) {
+      config = ConfigFactory.create(Config.class, System.getProperties());
     }
+    return config;
+  }
 }

+ 8 - 8
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/configs/Profiles.java

@@ -1,17 +1,17 @@
 package com.provectus.kafka.ui.settings.configs;
 
-import org.aeonbits.owner.Config;
-
 import static com.provectus.kafka.ui.variables.Browser.CONTAINER;
 import static com.provectus.kafka.ui.variables.Suite.CUSTOM;
 
+import org.aeonbits.owner.Config;
+
 public interface Profiles extends Config {
 
-    @Key("browser")
-    @DefaultValue(CONTAINER)
-    String browser();
+  @Key("browser")
+  @DefaultValue(CONTAINER)
+  String browser();
 
-    @Key("suite")
-    @DefaultValue(CUSTOM)
-    String suite();
+  @Key("suite")
+  @DefaultValue(CUSTOM)
+  String suite();
 }

+ 77 - 72
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/drivers/WebDriver.java

@@ -1,96 +1,101 @@
 package com.provectus.kafka.ui.settings.drivers;
 
+import static com.codeborne.selenide.Selenide.clearBrowserCookies;
+import static com.codeborne.selenide.Selenide.clearBrowserLocalStorage;
+import static com.codeborne.selenide.Selenide.refresh;
+import static com.provectus.kafka.ui.settings.BaseSource.BROWSER;
+import static com.provectus.kafka.ui.settings.BaseSource.REMOTE_URL;
+import static com.provectus.kafka.ui.variables.Browser.CONTAINER;
+import static com.provectus.kafka.ui.variables.Browser.LOCAL;
+
 import com.codeborne.selenide.Configuration;
 import com.codeborne.selenide.Selenide;
 import com.codeborne.selenide.WebDriverRunner;
 import com.codeborne.selenide.logevents.SelenideLogger;
 import io.qameta.allure.Step;
 import io.qameta.allure.selenide.AllureSelenide;
+import lombok.extern.slf4j.Slf4j;
 import org.openqa.selenium.chrome.ChromeOptions;
 import org.openqa.selenium.remote.DesiredCapabilities;
 
-import static com.codeborne.selenide.Selenide.*;
-import static com.provectus.kafka.ui.settings.BaseSource.BROWSER;
-import static com.provectus.kafka.ui.settings.BaseSource.REMOTE_URL;
-import static com.provectus.kafka.ui.variables.Browser.CONTAINER;
-import static com.provectus.kafka.ui.variables.Browser.LOCAL;
-
+@Slf4j
 public abstract class WebDriver {
 
-    @Step
-    public static void browserSetup() {
-        Configuration.headless = false;
-        Configuration.browser = "chrome";
-        Configuration.browserSize = "1920x1080";
-        /**screenshots and savePageSource config is needed for local debug
-         * optionally can be set as 'false' to not duplicate Allure report
-         */
-        Configuration.screenshots = true;
-        Configuration.savePageSource = false;
-        Configuration.pageLoadTimeout = 120000;
-        ChromeOptions options = new ChromeOptions()
-                .addArguments("--no-sandbox")
-                .addArguments("--verbose")
-                .addArguments("--remote-allow-origins=*")
-                .addArguments("--disable-dev-shm-usage")
-                .addArguments("--disable-gpu")
-                .addArguments("--lang=en_US");
-        switch (BROWSER) {
-            case (LOCAL) -> Configuration.browserCapabilities = options;
-            case (CONTAINER) -> {
-                Configuration.remote = REMOTE_URL;
-                Configuration.remoteConnectionTimeout = 180000;
-                DesiredCapabilities capabilities = new DesiredCapabilities();
-                capabilities.setCapability("enableVNC", true);
-                capabilities.setCapability("enableVideo", false);
-                Configuration.browserCapabilities = capabilities.merge(options);
-            }
-            default -> throw new IllegalStateException("Unexpected value: " + BROWSER);
-        }
+  @Step
+  public static void browserSetup() {
+    Configuration.headless = false;
+    Configuration.browser = "chrome";
+    Configuration.browserSize = "1920x1080";
+    Configuration.screenshots = true;
+    Configuration.savePageSource = false;
+    Configuration.pageLoadTimeout = 120000;
+    ChromeOptions options = new ChromeOptions()
+        .addArguments("--no-sandbox")
+        .addArguments("--verbose")
+        .addArguments("--remote-allow-origins=*")
+        .addArguments("--disable-dev-shm-usage")
+        .addArguments("--disable-gpu")
+        .addArguments("--lang=en_US");
+    switch (BROWSER) {
+      case (LOCAL) -> Configuration.browserCapabilities = options;
+      case (CONTAINER) -> {
+        Configuration.remote = REMOTE_URL;
+        Configuration.remoteConnectionTimeout = 180000;
+        DesiredCapabilities capabilities = new DesiredCapabilities();
+        capabilities.setCapability("enableVNC", true);
+        capabilities.setCapability("enableVideo", false);
+        Configuration.browserCapabilities = capabilities.merge(options);
+      }
+      default -> throw new IllegalStateException("Unexpected value: " + BROWSER);
     }
+  }
 
-    private static org.openqa.selenium.WebDriver getWebDriver() {
-        try {
-            return WebDriverRunner.getWebDriver();
-        } catch (IllegalStateException ex) {
-            browserSetup();
-            Selenide.open();
-            return WebDriverRunner.getWebDriver();
-        }
+  private static org.openqa.selenium.WebDriver getWebDriver() {
+    try {
+      return WebDriverRunner.getWebDriver();
+    } catch (IllegalStateException ex) {
+      browserSetup();
+      Selenide.open();
+      return WebDriverRunner.getWebDriver();
     }
+  }
 
-    @Step
-    public static void openUrl(String url) {
-        org.openqa.selenium.WebDriver driver = getWebDriver();
-        if (!driver.getCurrentUrl().equals(url)) driver.get(url);
+  @Step
+  public static void openUrl(String url) {
+    org.openqa.selenium.WebDriver driver = getWebDriver();
+    if (!driver.getCurrentUrl().equals(url)) {
+      driver.get(url);
     }
+  }
 
-    @Step
-    public static void browserInit() {
-        getWebDriver();
-    }
+  @Step
+  public static void browserInit() {
+    getWebDriver();
+  }
 
-    @Step
-    public static void browserClear() {
-        clearBrowserLocalStorage();
-        clearBrowserCookies();
-        refresh();
-    }
+  @Step
+  public static void browserClear() {
+    clearBrowserLocalStorage();
+    clearBrowserCookies();
+    refresh();
+  }
 
-    @Step
-    public static void browserQuit() {
-        org.openqa.selenium.WebDriver driver = null;
-        try {
-            driver = WebDriverRunner.getWebDriver();
-        } catch (Throwable ignored) {
-        }
-        if (driver != null) driver.quit();
+  @Step
+  public static void browserQuit() {
+    org.openqa.selenium.WebDriver driver = null;
+    try {
+      driver = WebDriverRunner.getWebDriver();
+    } catch (Throwable ignored) {
     }
-
-    @Step
-    public static void loggerSetup() {
-        SelenideLogger.addListener("AllureSelenide", new AllureSelenide()
-                .screenshots(true)
-                .savePageSource(false));
+    if (driver != null) {
+      driver.quit();
     }
+  }
+
+  @Step
+  public static void loggerSetup() {
+    SelenideLogger.addListener("AllureSelenide", new AllureSelenide()
+        .screenshots(true)
+        .savePageSource(false));
+  }
 }

+ 25 - 21
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/AllureListener.java

@@ -1,35 +1,39 @@
 package com.provectus.kafka.ui.settings.listeners;
 
+import static java.nio.file.Files.newInputStream;
+
 import com.codeborne.selenide.Screenshots;
 import io.qameta.allure.Allure;
 import io.qameta.allure.testng.AllureTestNg;
-import org.testng.ITestListener;
-import org.testng.ITestResult;
-
 import java.io.File;
 import java.io.IOException;
-import java.util.Objects;
-
-import static java.nio.file.Files.newInputStream;
+import lombok.extern.slf4j.Slf4j;
+import org.testng.ITestListener;
+import org.testng.ITestResult;
 
+@Slf4j
 public class AllureListener extends AllureTestNg implements ITestListener {
 
-    private void takeScreenshot() {
-        File screenshot = Screenshots.takeScreenShotAsFile();
-        try {
-            Allure.addAttachment(Objects.requireNonNull(screenshot).getName(), newInputStream(screenshot.toPath()));
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
+  private void takeScreenshot() {
+    File screenshot = Screenshots.takeScreenShotAsFile();
+    try {
+      if (screenshot != null) {
+        Allure.addAttachment(screenshot.getName(), newInputStream(screenshot.toPath()));
+      } else {
+        log.warn("Unable to take screenshot");
+      }
+    } catch (IOException e) {
+      throw new RuntimeException(e);
     }
+  }
 
-    @Override
-    public void onTestFailure(ITestResult result) {
-        takeScreenshot();
-    }
+  @Override
+  public void onTestFailure(ITestResult result) {
+    takeScreenshot();
+  }
 
-    @Override
-    public void onTestSkipped(ITestResult result) {
-        takeScreenshot();
-    }
+  @Override
+  public void onTestSkipped(ITestResult result) {
+    takeScreenshot();
+  }
 }

+ 24 - 24
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/LoggerListener.java

@@ -7,31 +7,31 @@ import org.testng.TestListenerAdapter;
 @Slf4j
 public class LoggerListener extends TestListenerAdapter {
 
-    @Override
-    public void onTestStart(final ITestResult testResult) {
-        log.info(String.format("\n------------------------------------------------------------------------ " +
-                        "\nTEST STARTED: %s.%s \n------------------------------------------------------------------------ \n",
-                testResult.getInstanceName(), testResult.getName()));
-    }
+  @Override
+  public void onTestStart(final ITestResult testResult) {
+    log.info(String.format("\n------------------------------------------------------------------------ "
+            + "\nTEST STARTED: %s.%s \n------------------------------------------------------------------------ \n",
+        testResult.getInstanceName(), testResult.getName()));
+  }
 
-    @Override
-    public void onTestSuccess(final ITestResult testResult) {
-        log.info(String.format("\n------------------------------------------------------------------------ " +
-                        "\nTEST PASSED: %s.%s \n------------------------------------------------------------------------ \n",
-                testResult.getInstanceName(), testResult.getName()));
-    }
+  @Override
+  public void onTestSuccess(final ITestResult testResult) {
+    log.info(String.format("\n------------------------------------------------------------------------ "
+            + "\nTEST PASSED: %s.%s \n------------------------------------------------------------------------ \n",
+        testResult.getInstanceName(), testResult.getName()));
+  }
 
-    @Override
-    public void onTestFailure(final ITestResult testResult) {
-        log.info(String.format("\n------------------------------------------------------------------------ " +
-                        "\nTEST FAILED: %s.%s \n------------------------------------------------------------------------ \n",
-                testResult.getInstanceName(), testResult.getName()));
-    }
+  @Override
+  public void onTestFailure(final ITestResult testResult) {
+    log.info(String.format("\n------------------------------------------------------------------------ "
+            + "\nTEST FAILED: %s.%s \n------------------------------------------------------------------------ \n",
+        testResult.getInstanceName(), testResult.getName()));
+  }
 
-    @Override
-    public void onTestSkipped(final ITestResult testResult) {
-        log.info(String.format("\n------------------------------------------------------------------------ " +
-                        "\nTEST SKIPPED: %s.%s \n------------------------------------------------------------------------ \n",
-                testResult.getInstanceName(), testResult.getName()));
-    }
+  @Override
+  public void onTestSkipped(final ITestResult testResult) {
+    log.info(String.format("\n------------------------------------------------------------------------ "
+            + "\nTEST SKIPPED: %s.%s \n------------------------------------------------------------------------ \n",
+        testResult.getInstanceName(), testResult.getName()));
+  }
 }

+ 105 - 92
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/QaseCreateListener.java

@@ -1,14 +1,28 @@
 package com.provectus.kafka.ui.settings.listeners;
 
-import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Automation;
-import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Status;
-import com.provectus.kafka.ui.utilities.qaseUtils.annotations.Suite;
+import static io.qase.api.utils.IntegrationUtils.getCaseTitle;
+
+import com.provectus.kafka.ui.utilities.qase.annotations.Automation;
+import com.provectus.kafka.ui.utilities.qase.annotations.Status;
+import com.provectus.kafka.ui.utilities.qase.annotations.Suite;
 import io.qase.api.QaseClient;
 import io.qase.api.StepStorage;
 import io.qase.api.annotation.QaseId;
 import io.qase.client.ApiClient;
 import io.qase.client.api.CasesApi;
-import io.qase.client.model.*;
+import io.qase.client.model.GetCasesFiltersParameter;
+import io.qase.client.model.ResultCreateStepsInner;
+import io.qase.client.model.TestCase;
+import io.qase.client.model.TestCaseCreate;
+import io.qase.client.model.TestCaseCreateStepsInner;
+import io.qase.client.model.TestCaseListResponse;
+import io.qase.client.model.TestCaseListResponseAllOfResult;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.testng.Assert;
@@ -16,108 +30,107 @@ import org.testng.ITestListener;
 import org.testng.ITestResult;
 import org.testng.TestListenerAdapter;
 
-import java.lang.reflect.Method;
-import java.util.*;
-
-import static io.qase.api.utils.IntegrationUtils.getCaseTitle;
-
 @Slf4j
 public class QaseCreateListener extends TestListenerAdapter implements ITestListener {
 
-    private static final CasesApi QASE_API = getQaseApi();
+  private static final CasesApi QASE_API = getQaseApi();
 
-    private static CasesApi getQaseApi() {
-        ApiClient apiClient = QaseClient.getApiClient();
-        apiClient.setApiKey(System.getProperty("QASEIO_API_TOKEN"));
-        return new CasesApi(apiClient);
-    }
+  private static CasesApi getQaseApi() {
+    ApiClient apiClient = QaseClient.getApiClient();
+    apiClient.setApiKey(System.getProperty("QASEIO_API_TOKEN"));
+    return new CasesApi(apiClient);
+  }
 
-    private static int getStatus(Method method) {
-        if (method.isAnnotationPresent(Status.class))
-            return method.getDeclaredAnnotation(Status.class).status().getValue();
-        return 1;
+  private static int getStatus(Method method) {
+    if (method.isAnnotationPresent(Status.class)) {
+      return method.getDeclaredAnnotation(Status.class).status().getValue();
     }
+    return 1;
+  }
 
-    private static int getAutomation(Method method) {
-        if (method.isAnnotationPresent(Automation.class))
-            return method.getDeclaredAnnotation(Automation.class).state().getValue();
-        return 0;
+  private static int getAutomation(Method method) {
+    if (method.isAnnotationPresent(Automation.class)) {
+      return method.getDeclaredAnnotation(Automation.class).state().getValue();
     }
+    return 0;
+  }
 
-    @SneakyThrows
-    private static HashMap<Long, String> getCaseTitlesAndIdsFromQase() {
-        HashMap<Long, String> cases = new HashMap<>();
-        boolean getCases = true;
-        int offSet = 0;
-        while (getCases) {
-            getCases = false;
-            TestCaseListResponse response = QASE_API.getCases(System.getProperty("QASE_PROJECT_CODE"),
-                    new GetCasesFiltersParameter().status(GetCasesFiltersParameter.SERIALIZED_NAME_STATUS), 100, offSet);
-            TestCaseListResponseAllOfResult result = response.getResult();
-            Assert.assertNotNull(result);
-            List<TestCase> entities = result.getEntities();
-            Assert.assertNotNull(entities);
-            if (entities.size() > 0) {
-                for (TestCase testCase : entities) {
-                    cases.put(testCase.getId(), testCase.getTitle());
-                }
-                offSet = offSet + 100;
-                getCases = true;
-            }
+  @SneakyThrows
+  private static HashMap<Long, String> getCaseTitlesAndIdsFromQase() {
+    HashMap<Long, String> cases = new HashMap<>();
+    boolean getCases = true;
+    int offSet = 0;
+    while (getCases) {
+      getCases = false;
+      TestCaseListResponse response = QASE_API.getCases(System.getProperty("QASE_PROJECT_CODE"),
+          new GetCasesFiltersParameter().status(GetCasesFiltersParameter.SERIALIZED_NAME_STATUS), 100, offSet);
+      TestCaseListResponseAllOfResult result = response.getResult();
+      Assert.assertNotNull(result);
+      List<TestCase> entities = result.getEntities();
+      Assert.assertNotNull(entities);
+      if (entities.size() > 0) {
+        for (TestCase testCase : entities) {
+          cases.put(testCase.getId(), testCase.getTitle());
         }
-        return cases;
+        offSet = offSet + 100;
+        getCases = true;
+      }
     }
+    return cases;
+  }
 
-    private static boolean isCaseWithTitleExistInQase(Method method) {
-        HashMap<Long, String> cases = getCaseTitlesAndIdsFromQase();
-        String title = getCaseTitle(method);
-        if (cases.containsValue(title)) {
-            for (Map.Entry<Long, String> map : cases.entrySet()) {
-                if (map.getValue().matches(title)) {
-                    long id = map.getKey();
-                    log.warn(String.format("Test case with @QaseTitle='%s' already exists with @QaseId=%d. " +
-                            "Please verify @QaseTitle annotation", title, id));
-                    return true;
-                }
-            }
+  private static boolean isCaseWithTitleExistInQase(Method method) {
+    HashMap<Long, String> cases = getCaseTitlesAndIdsFromQase();
+    String title = getCaseTitle(method);
+    if (cases.containsValue(title)) {
+      for (Map.Entry<Long, String> map : cases.entrySet()) {
+        if (map.getValue().matches(title)) {
+          long id = map.getKey();
+          log.warn(String.format("Test case with @QaseTitle='%s' already exists with @QaseId=%d. "
+              + "Please verify @QaseTitle annotation", title, id));
+          return true;
         }
-        return false;
+      }
     }
+    return false;
+  }
 
-    @Override
-    @SneakyThrows
-    public void onTestSuccess(final ITestResult testResult) {
-        Method method = testResult.getMethod()
-                .getConstructorOrMethod()
-                .getMethod();
-        String title = getCaseTitle(method);
-        if (!method.isAnnotationPresent(QaseId.class)) {
-            if (title != null) {
-                if (!isCaseWithTitleExistInQase(method)) {
-                    LinkedList<ResultCreateStepsInner> resultSteps = StepStorage.stopSteps();
-                    LinkedList<TestCaseCreateStepsInner> createSteps = new LinkedList<>();
-                    resultSteps.forEach(step -> {
-                        TestCaseCreateStepsInner caseStep = new TestCaseCreateStepsInner();
-                        caseStep.setAction(step.getAction());
-                        caseStep.setExpectedResult(step.getExpectedResult());
-                        createSteps.add(caseStep);
-                    });
-                    TestCaseCreate newCase = new TestCaseCreate();
-                    newCase.setTitle(title);
-                    newCase.setStatus(getStatus(method));
-                    newCase.setAutomation(getAutomation(method));
-                    newCase.setSteps(createSteps);
-                    if (method.isAnnotationPresent(Suite.class)) {
-                        long suiteId = method.getDeclaredAnnotation(Suite.class).id();
-                        newCase.suiteId(suiteId);
-                    }
-                    Long id = Objects.requireNonNull(QASE_API.createCase(System.getProperty("QASE_PROJECT_CODE"),
-                            newCase).getResult()).getId();
-                    log.info(String.format("New test case '%s' was created with @QaseId=%d", title, id));
-                }
-            } else
-                log.warn("To create new test case in Qase.io please add @QaseTitle annotation");
-        } else
-            log.warn("To create new test case in Qase.io please remove @QaseId annotation");
+  @Override
+  @SneakyThrows
+  public void onTestSuccess(final ITestResult testResult) {
+    Method method = testResult.getMethod()
+        .getConstructorOrMethod()
+        .getMethod();
+    String title = getCaseTitle(method);
+    if (!method.isAnnotationPresent(QaseId.class)) {
+      if (title != null) {
+        if (!isCaseWithTitleExistInQase(method)) {
+          LinkedList<ResultCreateStepsInner> resultSteps = StepStorage.stopSteps();
+          LinkedList<TestCaseCreateStepsInner> createSteps = new LinkedList<>();
+          resultSteps.forEach(step -> {
+            TestCaseCreateStepsInner caseStep = new TestCaseCreateStepsInner();
+            caseStep.setAction(step.getAction());
+            caseStep.setExpectedResult(step.getExpectedResult());
+            createSteps.add(caseStep);
+          });
+          TestCaseCreate newCase = new TestCaseCreate();
+          newCase.setTitle(title);
+          newCase.setStatus(getStatus(method));
+          newCase.setAutomation(getAutomation(method));
+          newCase.setSteps(createSteps);
+          if (method.isAnnotationPresent(Suite.class)) {
+            long suiteId = method.getDeclaredAnnotation(Suite.class).id();
+            newCase.suiteId(suiteId);
+          }
+          Long id = Objects.requireNonNull(QASE_API.createCase(System.getProperty("QASE_PROJECT_CODE"),
+              newCase).getResult()).getId();
+          log.info(String.format("New test case '%s' was created with @QaseId=%d", title, id));
+        }
+      } else {
+        log.warn("To create new test case in Qase.io please add @QaseTitle annotation");
+      }
+    } else {
+      log.warn("To create new test case in Qase.io please remove @QaseId annotation");
     }
+  }
 }

+ 74 - 71
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/QaseResultListener.java

@@ -1,5 +1,12 @@
 package com.provectus.kafka.ui.settings.listeners;
 
+import static io.qase.api.utils.IntegrationUtils.getCaseId;
+import static io.qase.api.utils.IntegrationUtils.getCaseTitle;
+import static io.qase.api.utils.IntegrationUtils.getStacktrace;
+import static io.qase.client.model.ResultCreate.StatusEnum.FAILED;
+import static io.qase.client.model.ResultCreate.StatusEnum.PASSED;
+import static io.qase.client.model.ResultCreate.StatusEnum.SKIPPED;
+
 import io.qase.api.StepStorage;
 import io.qase.api.config.QaseConfig;
 import io.qase.api.services.QaseTestCaseListener;
@@ -7,6 +14,9 @@ import io.qase.client.model.ResultCreate;
 import io.qase.client.model.ResultCreateCase;
 import io.qase.client.model.ResultCreateStepsInner;
 import io.qase.testng.guice.module.TestNgModule;
+import java.lang.reflect.Method;
+import java.util.LinkedList;
+import java.util.Optional;
 import lombok.AccessLevel;
 import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
@@ -15,88 +25,81 @@ import org.testng.ITestListener;
 import org.testng.ITestResult;
 import org.testng.TestListenerAdapter;
 
-import java.lang.reflect.Method;
-import java.util.LinkedList;
-import java.util.Optional;
-
-import static io.qase.api.utils.IntegrationUtils.*;
-import static io.qase.client.model.ResultCreate.StatusEnum.*;
-
 @Slf4j
 public class QaseResultListener extends TestListenerAdapter implements ITestListener {
 
-    private static final String REPORTER_NAME = "TestNG";
+  private static final String REPORTER_NAME = "TestNG";
 
-    static {
-        System.setProperty(QaseConfig.QASE_CLIENT_REPORTER_NAME_KEY, REPORTER_NAME);
-    }
+  static {
+    System.setProperty(QaseConfig.QASE_CLIENT_REPORTER_NAME_KEY, REPORTER_NAME);
+  }
 
-    @Getter(lazy = true, value = AccessLevel.PRIVATE)
-    private final QaseTestCaseListener qaseTestCaseListener = createQaseListener();
+  @Getter(lazy = true, value = AccessLevel.PRIVATE)
+  private final QaseTestCaseListener qaseTestCaseListener = createQaseListener();
 
-    private static QaseTestCaseListener createQaseListener() {
-        return TestNgModule.getInjector().getInstance(QaseTestCaseListener.class);
-    }
+  private static QaseTestCaseListener createQaseListener() {
+    return TestNgModule.getInjector().getInstance(QaseTestCaseListener.class);
+  }
 
-    @Override
-    public void onTestStart(ITestResult tr) {
-        getQaseTestCaseListener().onTestCaseStarted();
-        super.onTestStart(tr);
-    }
+  @Override
+  public void onTestStart(ITestResult tr) {
+    getQaseTestCaseListener().onTestCaseStarted();
+    super.onTestStart(tr);
+  }
 
-    @Override
-    public void onTestSuccess(ITestResult tr) {
-        getQaseTestCaseListener()
-                .onTestCaseFinished(resultCreate -> setupResultItem(resultCreate, tr, PASSED));
-        super.onTestSuccess(tr);
-    }
+  @Override
+  public void onTestSuccess(ITestResult tr) {
+    getQaseTestCaseListener()
+        .onTestCaseFinished(resultCreate -> setupResultItem(resultCreate, tr, PASSED));
+    super.onTestSuccess(tr);
+  }
 
-    @Override
-    public void onTestSkipped(ITestResult tr) {
-        getQaseTestCaseListener()
-                .onTestCaseFinished(resultCreate -> setupResultItem(resultCreate, tr, SKIPPED));
-        super.onTestSuccess(tr);
-    }
+  @Override
+  public void onTestSkipped(ITestResult tr) {
+    getQaseTestCaseListener()
+        .onTestCaseFinished(resultCreate -> setupResultItem(resultCreate, tr, SKIPPED));
+    super.onTestSuccess(tr);
+  }
 
-    @Override
-    public void onTestFailure(ITestResult tr) {
-        getQaseTestCaseListener()
-                .onTestCaseFinished(resultCreate -> setupResultItem(resultCreate, tr, FAILED));
-        super.onTestFailure(tr);
-    }
+  @Override
+  public void onTestFailure(ITestResult tr) {
+    getQaseTestCaseListener()
+        .onTestCaseFinished(resultCreate -> setupResultItem(resultCreate, tr, FAILED));
+    super.onTestFailure(tr);
+  }
 
-    @Override
-    public void onFinish(ITestContext testContext) {
-        getQaseTestCaseListener().onTestCasesSetFinished();
-        super.onFinish(testContext);
-    }
+  @Override
+  public void onFinish(ITestContext testContext) {
+    getQaseTestCaseListener().onTestCasesSetFinished();
+    super.onFinish(testContext);
+  }
 
-    private void setupResultItem(ResultCreate resultCreate, ITestResult result, ResultCreate.StatusEnum status) {
-        Optional<Throwable> resultThrowable = Optional.ofNullable(result.getThrowable());
-        String comment = resultThrowable
-                .flatMap(throwable -> Optional.of(throwable.toString())).orElse(null);
-        Boolean isDefect = resultThrowable
-                .flatMap(throwable -> Optional.of(throwable instanceof AssertionError))
-                .orElse(false);
-        String stacktrace = resultThrowable
-                .flatMap(throwable -> Optional.of(getStacktrace(throwable)))
-                .orElse(null);
-        Method method = result.getMethod()
-                .getConstructorOrMethod()
-                .getMethod();
-        Long caseId = getCaseId(method);
-        String caseTitle = null;
-        if (caseId == null) {
-            caseTitle = getCaseTitle(method);
-        }
-        LinkedList<ResultCreateStepsInner> steps = StepStorage.stopSteps();
-        resultCreate
-                ._case(caseTitle == null ? null : new ResultCreateCase().title(caseTitle))
-                .caseId(caseId)
-                .status(status)
-                .comment(comment)
-                .stacktrace(stacktrace)
-                .steps(steps.isEmpty() ? null : steps)
-                .defect(isDefect);
+  private void setupResultItem(ResultCreate resultCreate, ITestResult result, ResultCreate.StatusEnum status) {
+    Optional<Throwable> resultThrowable = Optional.ofNullable(result.getThrowable());
+    String comment = resultThrowable
+        .flatMap(throwable -> Optional.of(throwable.toString())).orElse(null);
+    Boolean isDefect = resultThrowable
+        .flatMap(throwable -> Optional.of(throwable instanceof AssertionError))
+        .orElse(false);
+    String stacktrace = resultThrowable
+        .flatMap(throwable -> Optional.of(getStacktrace(throwable)))
+        .orElse(null);
+    Method method = result.getMethod()
+        .getConstructorOrMethod()
+        .getMethod();
+    Long caseId = getCaseId(method);
+    String caseTitle = null;
+    if (caseId == null) {
+      caseTitle = getCaseTitle(method);
     }
+    LinkedList<ResultCreateStepsInner> steps = StepStorage.stopSteps();
+    resultCreate
+        ._case(caseTitle == null ? null : new ResultCreateCase().title(caseTitle))
+        .caseId(caseId)
+        .status(status)
+        .comment(comment)
+        .stacktrace(stacktrace)
+        .steps(steps.isEmpty() ? null : steps)
+        .defect(isDefect);
+  }
 }

+ 14 - 15
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/FileUtils.java

@@ -1,27 +1,26 @@
 package com.provectus.kafka.ui.utilities;
 
-import org.testcontainers.shaded.org.apache.commons.io.IOUtils;
+import static org.apache.kafka.common.utils.Utils.readFileAsString;
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
-
-import static org.apache.kafka.common.utils.Utils.readFileAsString;
+import org.testcontainers.shaded.org.apache.commons.io.IOUtils;
 
 public class FileUtils {
 
-    public static String getResourceAsString(String resourceFileName) {
-        try {
-            return IOUtils.resourceToString("/" + resourceFileName, StandardCharsets.UTF_8);
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
+  public static String getResourceAsString(String resourceFileName) {
+    try {
+      return IOUtils.resourceToString("/" + resourceFileName, StandardCharsets.UTF_8);
+    } catch (IOException e) {
+      throw new RuntimeException(e);
     }
+  }
 
-    public static String fileToString(String path) {
-        try {
-            return readFileAsString(path);
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
+  public static String fileToString(String path) {
+    try {
+      return readFileAsString(path);
+    } catch (IOException e) {
+      throw new RuntimeException(e);
     }
+  }
 }

+ 7 - 8
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/TimeUtils.java

@@ -1,17 +1,16 @@
 package com.provectus.kafka.ui.utilities;
 
-import lombok.extern.slf4j.Slf4j;
+import static com.codeborne.selenide.Selenide.sleep;
 
 import java.time.LocalTime;
-
-import static com.codeborne.selenide.Selenide.sleep;
+import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
 public class TimeUtils {
 
-    public static void waitUntilNewMinuteStarted() {
-        int secondsLeft = 60 - LocalTime.now().getSecond();
-        log.debug("\nwaitUntilNewMinuteStarted: {}s", secondsLeft);
-        sleep(secondsLeft * 1000);
-    }
+  public static void waitUntilNewMinuteStarted() {
+    int secondsLeft = 60 - LocalTime.now().getSecond();
+    log.debug("\nwaitUntilNewMinuteStarted: {}s", secondsLeft);
+    sleep(secondsLeft * 1000);
+  }
 }

+ 83 - 78
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/WebUtils.java

@@ -1,105 +1,110 @@
 package com.provectus.kafka.ui.utilities;
 
+import static com.codeborne.selenide.Selenide.executeJavaScript;
+
 import com.codeborne.selenide.Condition;
 import com.codeborne.selenide.SelenideElement;
 import com.codeborne.selenide.WebDriverRunner;
+import java.time.Duration;
 import lombok.extern.slf4j.Slf4j;
 import org.openqa.selenium.Keys;
 import org.openqa.selenium.interactions.Actions;
 
-import java.time.Duration;
-
-import static com.codeborne.selenide.Selenide.executeJavaScript;
-
 @Slf4j
 public class WebUtils {
 
-    public static int getTimeout(int... timeoutInSeconds) {
-        return (timeoutInSeconds != null && timeoutInSeconds.length > 0) ? timeoutInSeconds[0] : 4;
-    }
+  public static int getTimeout(int... timeoutInSeconds) {
+    return (timeoutInSeconds != null && timeoutInSeconds.length > 0) ? timeoutInSeconds[0] : 4;
+  }
 
-    public static void sendKeysAfterClear(SelenideElement element, String keys) {
-        log.debug("\nsendKeysAfterClear: {} \nsend keys '{}'", element.getSearchCriteria(), keys);
-        element.shouldBe(Condition.enabled).clear();
-        if (keys != null) element.sendKeys(keys);
+  public static void sendKeysAfterClear(SelenideElement element, String keys) {
+    log.debug("\nsendKeysAfterClear: {} \nsend keys '{}'", element.getSearchCriteria(), keys);
+    element.shouldBe(Condition.enabled).clear();
+    if (keys != null) {
+      element.sendKeys(keys);
     }
+  }
 
-    public static void clickByActions(SelenideElement element) {
-        log.debug("\nclickByActions: {}", element.getSearchCriteria());
-        element.shouldBe(Condition.enabled);
-        new Actions(WebDriverRunner.getWebDriver())
-                .moveToElement(element)
-                .click(element)
-                .perform();
-    }
+  public static void clickByActions(SelenideElement element) {
+    log.debug("\nclickByActions: {}", element.getSearchCriteria());
+    element.shouldBe(Condition.enabled);
+    new Actions(WebDriverRunner.getWebDriver())
+        .moveToElement(element)
+        .click(element)
+        .perform();
+  }
 
-    public static void sendKeysByActions(SelenideElement element, String keys) {
-        log.debug("\nsendKeysByActions: {} \nsend keys '{}'", element.getSearchCriteria(), keys);
-        element.shouldBe(Condition.enabled);
-        new Actions(WebDriverRunner.getWebDriver())
-                .moveToElement(element)
-                .sendKeys(element, keys)
-                .perform();
-    }
+  public static void sendKeysByActions(SelenideElement element, String keys) {
+    log.debug("\nsendKeysByActions: {} \nsend keys '{}'", element.getSearchCriteria(), keys);
+    element.shouldBe(Condition.enabled);
+    new Actions(WebDriverRunner.getWebDriver())
+        .moveToElement(element)
+        .sendKeys(element, keys)
+        .perform();
+  }
 
-    public static void clickByJavaScript(SelenideElement element) {
-        log.debug("\nclickByJavaScript: {}", element.getSearchCriteria());
-        element.shouldBe(Condition.enabled);
-        String script = "arguments[0].click();";
-        executeJavaScript(script, element);
-    }
+  public static void clickByJavaScript(SelenideElement element) {
+    log.debug("\nclickByJavaScript: {}", element.getSearchCriteria());
+    element.shouldBe(Condition.enabled);
+    String script = "arguments[0].click();";
+    executeJavaScript(script, element);
+  }
 
-    public static void clearByKeyboard(SelenideElement field) {
-        log.debug("\nclearByKeyboard: {}", field.getSearchCriteria());
-        field.shouldBe(Condition.enabled).sendKeys(Keys.END);
-        field.sendKeys(Keys.chord(Keys.CONTROL + "a"), Keys.DELETE);
-    }
+  public static void clearByKeyboard(SelenideElement field) {
+    log.debug("\nclearByKeyboard: {}", field.getSearchCriteria());
+    field.shouldBe(Condition.enabled).sendKeys(Keys.END);
+    field.sendKeys(Keys.chord(Keys.CONTROL + "a"), Keys.DELETE);
+  }
 
-    public static boolean isVisible(SelenideElement element, int... timeoutInSeconds) {
-        log.debug("\nisVisible: {}", element.getSearchCriteria());
-        boolean isVisible = false;
-        try {
-            element.shouldBe(Condition.visible,
-                    Duration.ofSeconds(getTimeout(timeoutInSeconds)));
-            isVisible = true;
-        } catch (Throwable e) {
-            log.debug("{} is not visible", element.getSearchCriteria());
-        }
-        return isVisible;
+  public static boolean isVisible(SelenideElement element, int... timeoutInSeconds) {
+    log.debug("\nisVisible: {}", element.getSearchCriteria());
+    boolean isVisible = false;
+    try {
+      element.shouldBe(Condition.visible,
+          Duration.ofSeconds(getTimeout(timeoutInSeconds)));
+      isVisible = true;
+    } catch (Throwable e) {
+      log.debug("{} is not visible", element.getSearchCriteria());
     }
+    return isVisible;
+  }
 
-    public static boolean isEnabled(SelenideElement element, int... timeoutInSeconds) {
-        log.debug("\nisEnabled: {}", element.getSearchCriteria());
-        boolean isEnabled = false;
-        try {
-            element.shouldBe(Condition.enabled,
-                    Duration.ofSeconds(getTimeout(timeoutInSeconds)));
-            isEnabled = true;
-        } catch (Throwable e) {
-            log.debug("{} is not enabled", element.getSearchCriteria());
-        }
-        return isEnabled;
+  public static boolean isEnabled(SelenideElement element, int... timeoutInSeconds) {
+    log.debug("\nisEnabled: {}", element.getSearchCriteria());
+    boolean isEnabled = false;
+    try {
+      element.shouldBe(Condition.enabled,
+          Duration.ofSeconds(getTimeout(timeoutInSeconds)));
+      isEnabled = true;
+    } catch (Throwable e) {
+      log.debug("{} is not enabled", element.getSearchCriteria());
     }
+    return isEnabled;
+  }
 
-    public static boolean isSelected(SelenideElement element, int... timeoutInSeconds) {
-        log.debug("\nisSelected: {}", element.getSearchCriteria());
-        boolean isSelected = false;
-        try {
-            element.shouldBe(Condition.selected,
-                    Duration.ofSeconds(getTimeout(timeoutInSeconds)));
-            isSelected = true;
-        } catch (Throwable e) {
-            log.debug("{} is not selected", element.getSearchCriteria());
-        }
-        return isSelected;
+  public static boolean isSelected(SelenideElement element, int... timeoutInSeconds) {
+    log.debug("\nisSelected: {}", element.getSearchCriteria());
+    boolean isSelected = false;
+    try {
+      element.shouldBe(Condition.selected,
+          Duration.ofSeconds(getTimeout(timeoutInSeconds)));
+      isSelected = true;
+    } catch (Throwable e) {
+      log.debug("{} is not selected", element.getSearchCriteria());
     }
+    return isSelected;
+  }
 
-    public static boolean selectElement(SelenideElement element, boolean select) {
-        if (select) {
-            if (!element.isSelected()) clickByJavaScript(element);
-        } else {
-            if (element.isSelected()) clickByJavaScript(element);
-        }
-        return true;
+  public static boolean selectElement(SelenideElement element, boolean select) {
+    if (select) {
+      if (!element.isSelected()) {
+        clickByJavaScript(element);
+      }
+    } else {
+      if (element.isSelected()) {
+        clickByJavaScript(element);
+      }
     }
+    return true;
+  }
 }

+ 33 - 0
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/QaseSetup.java

@@ -0,0 +1,33 @@
+package com.provectus.kafka.ui.utilities.qase;
+
+import static com.provectus.kafka.ui.settings.BaseSource.SUITE_NAME;
+import static com.provectus.kafka.ui.variables.Suite.MANUAL;
+import static org.apache.commons.lang3.BooleanUtils.FALSE;
+import static org.apache.commons.lang3.BooleanUtils.TRUE;
+import static org.apache.commons.lang3.StringUtils.isEmpty;
+
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class QaseSetup {
+
+  public static void qaseIntegrationSetup() {
+    String qaseApiToken = System.getProperty("QASEIO_API_TOKEN");
+    if (isEmpty(qaseApiToken)) {
+      log.warn("Integration with Qase is disabled due to run config or token wasn't defined.");
+      System.setProperty("QASE_ENABLE", FALSE);
+    } else {
+      log.warn("Integration with Qase is enabled. Find this run at https://app.qase.io/run/KAFKAUI.");
+      String automation = SUITE_NAME.equalsIgnoreCase(MANUAL) ? "" : "Automation ";
+      System.setProperty("QASE_ENABLE", TRUE);
+      System.setProperty("QASE_PROJECT_CODE", "KAFKAUI");
+      System.setProperty("QASE_API_TOKEN", qaseApiToken);
+      System.setProperty("QASE_USE_BULK", TRUE);
+      System.setProperty("QASE_RUN_NAME", DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
+          .format(OffsetDateTime.now(ZoneOffset.UTC)) + ": " + automation + SUITE_NAME.toUpperCase() + " suite");
+    }
+  }
+}

+ 3 - 4
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/annotations/Automation.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/annotations/Automation.java

@@ -1,7 +1,6 @@
-package com.provectus.kafka.ui.utilities.qaseUtils.annotations;
-
-import com.provectus.kafka.ui.utilities.qaseUtils.enums.State;
+package com.provectus.kafka.ui.utilities.qase.annotations;
 
+import com.provectus.kafka.ui.utilities.qase.enums.State;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -11,5 +10,5 @@ import java.lang.annotation.Target;
 @Retention(RetentionPolicy.RUNTIME)
 public @interface Automation {
 
-    State state();
+  State state();
 }

+ 2 - 2
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/annotations/Status.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/annotations/Status.java

@@ -1,4 +1,4 @@
-package com.provectus.kafka.ui.utilities.qaseUtils.annotations;
+package com.provectus.kafka.ui.utilities.qase.annotations;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -9,5 +9,5 @@ import java.lang.annotation.Target;
 @Retention(RetentionPolicy.RUNTIME)
 public @interface Status {
 
-    com.provectus.kafka.ui.utilities.qaseUtils.enums.Status status();
+  com.provectus.kafka.ui.utilities.qase.enums.Status status();
 }

+ 2 - 2
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/annotations/Suite.java → kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/annotations/Suite.java

@@ -1,4 +1,4 @@
-package com.provectus.kafka.ui.utilities.qaseUtils.annotations;
+package com.provectus.kafka.ui.utilities.qase.annotations;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -9,5 +9,5 @@ import java.lang.annotation.Target;
 @Retention(RetentionPolicy.RUNTIME)
 public @interface Suite {
 
-    long id();
+  long id();
 }

+ 18 - 0
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/enums/State.java

@@ -0,0 +1,18 @@
+package com.provectus.kafka.ui.utilities.qase.enums;
+
+public enum State {
+
+  NOT_AUTOMATED(0),
+  TO_BE_AUTOMATED(1),
+  AUTOMATED(2);
+
+  private final int value;
+
+  State(int value) {
+    this.value = value;
+  }
+
+  public int getValue() {
+    return value;
+  }
+}

+ 18 - 0
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qase/enums/Status.java

@@ -0,0 +1,18 @@
+package com.provectus.kafka.ui.utilities.qase.enums;
+
+public enum Status {
+
+  ACTUAL(0),
+  DRAFT(1),
+  DEPRECATED(2);
+
+  private final int value;
+
+  Status(int value) {
+    this.value = value;
+  }
+
+  public int getValue() {
+    return value;
+  }
+}

+ 0 - 34
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/QaseSetup.java

@@ -1,34 +0,0 @@
-package com.provectus.kafka.ui.utilities.qaseUtils;
-
-import lombok.extern.slf4j.Slf4j;
-
-import java.time.OffsetDateTime;
-import java.time.ZoneOffset;
-import java.time.format.DateTimeFormatter;
-
-import static com.provectus.kafka.ui.settings.BaseSource.SUITE_NAME;
-import static com.provectus.kafka.ui.variables.Suite.MANUAL;
-import static org.apache.commons.lang3.BooleanUtils.FALSE;
-import static org.apache.commons.lang3.BooleanUtils.TRUE;
-import static org.apache.commons.lang3.StringUtils.isEmpty;
-
-@Slf4j
-public class QaseSetup {
-
-    public static void qaseIntegrationSetup() {
-        String qaseApiToken = System.getProperty("QASEIO_API_TOKEN");
-        if (isEmpty(qaseApiToken)) {
-            log.warn("Integration with Qase is disabled due to run config or token wasn't defined.");
-            System.setProperty("QASE_ENABLE", FALSE);
-        } else {
-            log.warn("Integration with Qase is enabled. Find this run at https://app.qase.io/run/KAFKAUI.");
-            String automation = SUITE_NAME.equalsIgnoreCase(MANUAL) ? "" : "Automation ";
-            System.setProperty("QASE_ENABLE", TRUE);
-            System.setProperty("QASE_PROJECT_CODE", "KAFKAUI");
-            System.setProperty("QASE_API_TOKEN", qaseApiToken);
-            System.setProperty("QASE_USE_BULK", TRUE);
-            System.setProperty("QASE_RUN_NAME", DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
-                    .format(OffsetDateTime.now(ZoneOffset.UTC)) + ": " + automation + SUITE_NAME.toUpperCase() + " suite");
-        }
-    }
-}

+ 0 - 18
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/enums/State.java

@@ -1,18 +0,0 @@
-package com.provectus.kafka.ui.utilities.qaseUtils.enums;
-
-public enum State {
-
-    NOT_AUTOMATED(0),
-    TO_BE_AUTOMATED(1),
-    AUTOMATED(2);
-
-    private final int value;
-
-    State(int value) {
-        this.value = value;
-    }
-
-    public int getValue() {
-        return value;
-    }
-}

+ 0 - 18
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/qaseUtils/enums/Status.java

@@ -1,18 +0,0 @@
-package com.provectus.kafka.ui.utilities.qaseUtils.enums;
-
-public enum Status {
-
-    ACTUAL(0),
-    DRAFT(1),
-    DEPRECATED(2);
-
-    private final int value;
-
-    Status(int value) {
-        this.value = value;
-    }
-
-    public int getValue() {
-        return value;
-    }
-}

+ 2 - 2
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Browser.java

@@ -2,6 +2,6 @@ package com.provectus.kafka.ui.variables;
 
 public interface Browser {
 
-    String CONTAINER = "container";
-    String LOCAL = "local";
+  String CONTAINER = "container";
+  String LOCAL = "local";
 }

+ 5 - 5
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Suite.java

@@ -2,9 +2,9 @@ package com.provectus.kafka.ui.variables;
 
 public interface Suite {
 
-    String CUSTOM = "custom";
-    String MANUAL = "manual";
-    String REGRESSION = "regression";
-    String SANITY = "sanity";
-    String SMOKE = "smoke";
+  String CUSTOM = "custom";
+  String MANUAL = "manual";
+  String REGRESSION = "regression";
+  String SANITY = "sanity";
+  String SMOKE = "smoke";
 }

+ 6 - 6
kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/variables/Url.java

@@ -2,10 +2,10 @@ package com.provectus.kafka.ui.variables;
 
 public interface Url {
 
-    String BROKERS_LIST_URL = "http://%s:8080/ui/clusters/local/brokers";
-    String TOPICS_LIST_URL = "http://%s:8080/ui/clusters/local/all-topics";
-    String CONSUMERS_LIST_URL = "http://%s:8080/ui/clusters/local/consumer-groups";
-    String SCHEMA_REGISTRY_LIST_URL = "http://%s:8080/ui/clusters/local/schemas";
-    String KAFKA_CONNECT_LIST_URL = "http://%s:8080/ui/clusters/local/connectors";
-    String KSQL_DB_LIST_URL = "http://%s:8080/ui/clusters/local/ksqldb/tables";
+  String BROKERS_LIST_URL = "http://%s:8080/ui/clusters/local/brokers";
+  String TOPICS_LIST_URL = "http://%s:8080/ui/clusters/local/all-topics";
+  String CONSUMERS_LIST_URL = "http://%s:8080/ui/clusters/local/consumer-groups";
+  String SCHEMA_REGISTRY_LIST_URL = "http://%s:8080/ui/clusters/local/schemas";
+  String KAFKA_CONNECT_LIST_URL = "http://%s:8080/ui/clusters/local/connectors";
+  String KSQL_DB_LIST_URL = "http://%s:8080/ui/clusters/local/ksqldb/tables";
 }

+ 1 - 1
kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_create_connector.json

@@ -15,4 +15,4 @@
   "insert.mode": "upsert",
   "errors.log.enable": "true",
   "errors.log.include.messages": "true"
-}
+}

+ 1 - 1
kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_create_connector_via_api.json

@@ -4,4 +4,4 @@
   "connection.user": "dev_user",
   "connection.password": "12345",
   "topics": "topic_for_connector"
-}
+}

+ 1 - 1
kafka-ui-e2e-checks/src/main/resources/testData/connectors/delete_connector_config.json

@@ -15,4 +15,4 @@
   "insert.mode": "upsert",
   "errors.log.enable": "true",
   "errors.log.include.messages": "true"
-}
+}

Some files were not shown because too many files changed in this diff