From f51da4bb61ceac755ed0ec6f439b52b0233e9538 Mon Sep 17 00:00:00 2001 From: Victoria Salova <38016232+vict-o-ria@users.noreply.github.com> Date: Tue, 14 Mar 2023 15:49:40 +0300 Subject: [PATCH 1/8] [FE] Fix "Saved filters" invalid font (#3412) Co-authored-by: Roman Zabaluev --- .../components/Topics/Topic/Messages/Filters/Filters.styled.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Messages/Filters/Filters.styled.ts b/kafka-ui-react-app/src/components/Topics/Topic/Messages/Filters/Filters.styled.ts index d1230febf9..6e1d50b3bf 100644 --- a/kafka-ui-react-app/src/components/Topics/Topic/Messages/Filters/Filters.styled.ts +++ b/kafka-ui-react-app/src/components/Topics/Topic/Messages/Filters/Filters.styled.ts @@ -184,6 +184,7 @@ export const CreatedFilter = styled.p` margin: 25px 0 10px; font-size: 14px; line-height: 20px; + color: ${({ theme }) => theme.list.meta.color}; `; export const SavedFiltersContainer = styled.div` From f8083e25b7c5856b27a8898b5beb00e71096b91b Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Tue, 14 Mar 2023 14:54:19 +0200 Subject: [PATCH 2/8] [BE] Chore: Fix typo (#3493) `croups` -> `groups` Signed-off-by: Yarden Shoham --- kafka-ui-contract/src/main/resources/swagger/kafka-ui-api.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kafka-ui-contract/src/main/resources/swagger/kafka-ui-api.yaml b/kafka-ui-contract/src/main/resources/swagger/kafka-ui-api.yaml index 9773db26f1..71c595e525 100644 --- a/kafka-ui-contract/src/main/resources/swagger/kafka-ui-api.yaml +++ b/kafka-ui-contract/src/main/resources/swagger/kafka-ui-api.yaml @@ -775,7 +775,7 @@ paths: get: tags: - Consumer Groups - summary: Get consumer croups with paging support + summary: Get consumer groups with paging support operationId: getConsumerGroupsPage parameters: - name: clusterName From 3d1e7a0979c4f4634c836359b03cd4ad05aafc4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Mar 2023 17:12:42 +0400 Subject: [PATCH 3/8] Bump docker/build-push-action from 3 to 4 (#3488) Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3 to 4. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v3...v4) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/branch-deploy.yml | 2 +- .github/workflows/build-public-image.yml | 2 +- .github/workflows/cve.yaml | 2 +- .github/workflows/master.yaml | 2 +- .github/workflows/release.yaml | 2 +- .github/workflows/separate_env_public_create.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/branch-deploy.yml b/.github/workflows/branch-deploy.yml index 1cc5fee39b..0e4a171aec 100644 --- a/.github/workflows/branch-deploy.yml +++ b/.github/workflows/branch-deploy.yml @@ -55,7 +55,7 @@ jobs: uses: aws-actions/amazon-ecr-login@v1 - name: Build and push id: docker_build_and_push - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: builder: ${{ steps.buildx.outputs.name }} context: kafka-ui-api diff --git a/.github/workflows/build-public-image.yml b/.github/workflows/build-public-image.yml index c79996d2ac..e965f6c672 100644 --- a/.github/workflows/build-public-image.yml +++ b/.github/workflows/build-public-image.yml @@ -54,7 +54,7 @@ jobs: registry-type: 'public' - name: Build and push id: docker_build_and_push - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: builder: ${{ steps.buildx.outputs.name }} context: kafka-ui-api diff --git a/.github/workflows/cve.yaml b/.github/workflows/cve.yaml index 5b0e2779dd..c5f9ca7aed 100644 --- a/.github/workflows/cve.yaml +++ b/.github/workflows/cve.yaml @@ -40,7 +40,7 @@ jobs: ${{ runner.os }}-buildx- - name: Build docker image - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: builder: ${{ steps.buildx.outputs.name }} context: kafka-ui-api diff --git a/.github/workflows/master.yaml b/.github/workflows/master.yaml index 01651ee76d..122956c7d9 100644 --- a/.github/workflows/master.yaml +++ b/.github/workflows/master.yaml @@ -53,7 +53,7 @@ jobs: - name: Build and push id: docker_build_and_push - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: builder: ${{ steps.buildx.outputs.name }} context: kafka-ui-api diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 1990fbdbc5..19128550c0 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -72,7 +72,7 @@ jobs: - name: Build and push id: docker_build_and_push - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: builder: ${{ steps.buildx.outputs.name }} context: kafka-ui-api diff --git a/.github/workflows/separate_env_public_create.yml b/.github/workflows/separate_env_public_create.yml index e10b1a382c..1b7085d936 100644 --- a/.github/workflows/separate_env_public_create.yml +++ b/.github/workflows/separate_env_public_create.yml @@ -57,7 +57,7 @@ jobs: uses: aws-actions/amazon-ecr-login@v1 - name: Build and push id: docker_build_and_push - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: builder: ${{ steps.buildx.outputs.name }} context: kafka-ui-api From 41dabf3858ce44a0a56eb1b8f92ebb6c14b99336 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Mar 2023 17:13:41 +0400 Subject: [PATCH 4/8] Bump aquasecurity/trivy-action from 0.9.1 to 0.9.2 (#3486) Bumps [aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action) from 0.9.1 to 0.9.2. - [Release notes](https://github.com/aquasecurity/trivy-action/releases) - [Commits](https://github.com/aquasecurity/trivy-action/compare/0.9.1...0.9.2) --- updated-dependencies: - dependency-name: aquasecurity/trivy-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/cve.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cve.yaml b/.github/workflows/cve.yaml index c5f9ca7aed..77eae14bda 100644 --- a/.github/workflows/cve.yaml +++ b/.github/workflows/cve.yaml @@ -55,7 +55,7 @@ jobs: cache-to: type=local,dest=/tmp/.buildx-cache - name: Run CVE checks - uses: aquasecurity/trivy-action@0.9.1 + uses: aquasecurity/trivy-action@0.9.2 with: image-ref: "provectuslabs/kafka-ui:${{ steps.build.outputs.version }}" format: "table" From 51f89cb9004db011901a6fd4a47679e421cf9f4b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Mar 2023 17:14:24 +0400 Subject: [PATCH 5/8] Bump docker-maven-plugin from 0.40.2 to 0.42.0 (#3477) Bumps [docker-maven-plugin](https://github.com/fabric8io/docker-maven-plugin) from 0.40.2 to 0.42.0. - [Release notes](https://github.com/fabric8io/docker-maven-plugin/releases) - [Changelog](https://github.com/fabric8io/docker-maven-plugin/blob/master/doc/changelog.md) - [Commits](https://github.com/fabric8io/docker-maven-plugin/compare/v0.40.2...v0.42.0) --- updated-dependencies: - dependency-name: io.fabric8:docker-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dc1f50f1a2..e3f6e9e0e7 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ v7.4.0 - 0.40.2 + 0.42.0 1.12.1 3.2.0 3.10.1 From 4c2d37dd525b38c75135917b96afcb8e8fe72e46 Mon Sep 17 00:00:00 2001 From: Ilya Kuramshin Date: Tue, 14 Mar 2023 17:36:11 +0400 Subject: [PATCH 6/8] [BE] Chore: UtilityClass annotation removed (#3479) * @UtilityClass usage removed * @UtilityClass usage removed --------- Co-authored-by: iliax --- .../ui/service/integration/odd/Oddrn.java | 24 ++-- .../integration/odd/schema/AvroExtractor.java | 118 +++++++++--------- .../odd/schema/DataSetFieldsExtractors.java | 9 +- .../odd/schema/JsonSchemaExtractor.java | 108 ++++++++-------- .../odd/schema/ProtoExtractor.java | 94 +++++++------- .../ui/util/KafkaServicesValidation.java | 36 +++--- .../provectus/kafka/ui/util/KafkaVersion.java | 7 +- .../kafka/ui/util/SslPropertiesUtil.java | 22 +--- 8 files changed, 202 insertions(+), 216 deletions(-) diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/Oddrn.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/Oddrn.java index d228843b21..00b29b3b8b 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/Oddrn.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/Oddrn.java @@ -4,36 +4,34 @@ import com.provectus.kafka.ui.model.KafkaCluster; import java.net.URI; import java.util.stream.Collectors; import java.util.stream.Stream; -import lombok.experimental.UtilityClass; -import org.opendatadiscovery.oddrn.Generator; import org.opendatadiscovery.oddrn.model.AwsS3Path; import org.opendatadiscovery.oddrn.model.KafkaConnectorPath; import org.opendatadiscovery.oddrn.model.KafkaPath; -@UtilityClass -public class Oddrn { +public final class Oddrn { - private static final Generator GENERATOR = new Generator(); + private Oddrn() { + } - String clusterOddrn(KafkaCluster cluster) { + static String clusterOddrn(KafkaCluster cluster) { return KafkaPath.builder() .cluster(bootstrapServersForOddrn(cluster.getBootstrapServers())) .build() .oddrn(); } - KafkaPath topicOddrnPath(KafkaCluster cluster, String topic) { + static KafkaPath topicOddrnPath(KafkaCluster cluster, String topic) { return KafkaPath.builder() .cluster(bootstrapServersForOddrn(cluster.getBootstrapServers())) .topic(topic) .build(); } - String topicOddrn(KafkaCluster cluster, String topic) { + static String topicOddrn(KafkaCluster cluster, String topic) { return topicOddrnPath(cluster, topic).oddrn(); } - String awsS3Oddrn(String bucket, String key) { + static String awsS3Oddrn(String bucket, String key) { return AwsS3Path.builder() .bucket(bucket) .key(key) @@ -41,14 +39,14 @@ public class Oddrn { .oddrn(); } - String connectDataSourceOddrn(String connectUrl) { + static String connectDataSourceOddrn(String connectUrl) { return KafkaConnectorPath.builder() .host(normalizedConnectHosts(connectUrl)) .build() .oddrn(); } - private String normalizedConnectHosts(String connectUrlStr) { + private static String normalizedConnectHosts(String connectUrlStr) { return Stream.of(connectUrlStr.split(",")) .map(String::trim) .sorted() @@ -61,7 +59,7 @@ public class Oddrn { .collect(Collectors.joining(",")); } - String connectorOddrn(String connectUrl, String connectorName) { + static String connectorOddrn(String connectUrl, String connectorName) { return KafkaConnectorPath.builder() .host(normalizedConnectHosts(connectUrl)) .connector(connectorName) @@ -69,7 +67,7 @@ public class Oddrn { .oddrn(); } - private String bootstrapServersForOddrn(String bootstrapServers) { + private static String bootstrapServersForOddrn(String bootstrapServers) { return Stream.of(bootstrapServers.split(",")) .map(String::trim) .sorted() diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/schema/AvroExtractor.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/schema/AvroExtractor.java index 538bbde1a8..cc799a9e10 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/schema/AvroExtractor.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/schema/AvroExtractor.java @@ -1,18 +1,18 @@ package com.provectus.kafka.ui.service.integration.odd.schema; import com.google.common.collect.ImmutableSet; -import com.provectus.kafka.ui.service.integration.odd.Oddrn; import com.provectus.kafka.ui.sr.model.SchemaSubject; import java.util.ArrayList; import java.util.List; -import lombok.experimental.UtilityClass; import org.apache.avro.Schema; import org.opendatadiscovery.client.model.DataSetField; import org.opendatadiscovery.client.model.DataSetFieldType; import org.opendatadiscovery.oddrn.model.KafkaPath; -@UtilityClass -class AvroExtractor { +final class AvroExtractor { + + private AvroExtractor() { + } static List extract(SchemaSubject subject, KafkaPath topicOddrn, boolean isKey) { var schema = new Schema.Parser().parse(subject.getSchema()); @@ -31,14 +31,14 @@ class AvroExtractor { return result; } - private void extract(Schema schema, - String parentOddr, - String oddrn, //null for root - String name, - String doc, - Boolean nullable, - ImmutableSet registeredRecords, - List sink + private static void extract(Schema schema, + String parentOddr, + String oddrn, //null for root + String name, + String doc, + Boolean nullable, + ImmutableSet registeredRecords, + List sink ) { switch (schema.getType()) { case RECORD -> extractRecord(schema, parentOddr, oddrn, name, doc, nullable, registeredRecords, sink); @@ -49,12 +49,12 @@ class AvroExtractor { } } - private DataSetField createDataSetField(String name, - String doc, - String parentOddrn, - String oddrn, - Schema schema, - Boolean nullable) { + private static DataSetField createDataSetField(String name, + String doc, + String parentOddrn, + String oddrn, + Schema schema, + Boolean nullable) { return new DataSetField() .name(name) .description(doc) @@ -63,14 +63,14 @@ class AvroExtractor { .type(mapSchema(schema, nullable)); } - private void extractRecord(Schema schema, - String parentOddr, - String oddrn, //null for root - String name, - String doc, - Boolean nullable, - ImmutableSet registeredRecords, - List sink) { + private static void extractRecord(Schema schema, + String parentOddr, + String oddrn, //null for root + String name, + String doc, + Boolean nullable, + ImmutableSet registeredRecords, + List sink) { boolean isRoot = oddrn == null; if (!isRoot) { sink.add(createDataSetField(name, doc, parentOddr, oddrn, schema, nullable)); @@ -99,13 +99,13 @@ class AvroExtractor { )); } - private void extractUnion(Schema schema, - String parentOddr, - String oddrn, //null for root - String name, - String doc, - ImmutableSet registeredRecords, - List sink) { + private static void extractUnion(Schema schema, + String parentOddr, + String oddrn, //null for root + String name, + String doc, + ImmutableSet registeredRecords, + List sink) { boolean isRoot = oddrn == null; boolean containsNull = schema.getTypes().stream().map(Schema::getType).anyMatch(t -> t == Schema.Type.NULL); // if it is not root and there is only 2 values for union (null and smth else) @@ -149,14 +149,14 @@ class AvroExtractor { } } - private void extractArray(Schema schema, - String parentOddr, - String oddrn, //null for root - String name, - String doc, - Boolean nullable, - ImmutableSet registeredRecords, - List sink) { + private static void extractArray(Schema schema, + String parentOddr, + String oddrn, //null for root + String name, + String doc, + Boolean nullable, + ImmutableSet registeredRecords, + List sink) { boolean isRoot = oddrn == null; oddrn = isRoot ? parentOddr + "/array" : oddrn; if (isRoot) { @@ -176,14 +176,14 @@ class AvroExtractor { ); } - private void extractMap(Schema schema, - String parentOddr, - String oddrn, //null for root - String name, - String doc, - Boolean nullable, - ImmutableSet registeredRecords, - List sink) { + private static void extractMap(Schema schema, + String parentOddr, + String oddrn, //null for root + String name, + String doc, + Boolean nullable, + ImmutableSet registeredRecords, + List sink) { boolean isRoot = oddrn == null; oddrn = isRoot ? parentOddr + "/map" : oddrn; if (isRoot) { @@ -214,13 +214,13 @@ class AvroExtractor { } - private void extractPrimitive(Schema schema, - String parentOddr, - String oddrn, //null for root - String name, - String doc, - Boolean nullable, - List sink) { + private static void extractPrimitive(Schema schema, + String parentOddr, + String oddrn, //null for root + String name, + String doc, + Boolean nullable, + List sink) { boolean isRoot = oddrn == null; String primOddrn = isRoot ? (parentOddr + "/" + schema.getType()) : oddrn; if (isRoot) { @@ -231,7 +231,7 @@ class AvroExtractor { } } - private DataSetFieldType.TypeEnum mapType(Schema.Type type) { + private static DataSetFieldType.TypeEnum mapType(Schema.Type type) { return switch (type) { case INT, LONG -> DataSetFieldType.TypeEnum.INTEGER; case FLOAT, DOUBLE, FIXED -> DataSetFieldType.TypeEnum.NUMBER; @@ -246,14 +246,14 @@ class AvroExtractor { }; } - private DataSetFieldType mapSchema(Schema schema, Boolean nullable) { + private static DataSetFieldType mapSchema(Schema schema, Boolean nullable) { return new DataSetFieldType() .logicalType(logicalType(schema)) .isNullable(nullable) .type(mapType(schema.getType())); } - private String logicalType(Schema schema) { + private static String logicalType(Schema schema) { return schema.getType() == Schema.Type.RECORD ? schema.getFullName() : schema.getType().toString().toLowerCase(); diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/schema/DataSetFieldsExtractors.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/schema/DataSetFieldsExtractors.java index 746f172b57..e357db3079 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/schema/DataSetFieldsExtractors.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/schema/DataSetFieldsExtractors.java @@ -1,19 +1,16 @@ package com.provectus.kafka.ui.service.integration.odd.schema; -import com.provectus.kafka.ui.service.integration.odd.Oddrn; import com.provectus.kafka.ui.sr.model.SchemaSubject; import com.provectus.kafka.ui.sr.model.SchemaType; import java.util.List; import java.util.Optional; -import lombok.experimental.UtilityClass; import org.opendatadiscovery.client.model.DataSetField; import org.opendatadiscovery.client.model.DataSetFieldType; import org.opendatadiscovery.oddrn.model.KafkaPath; -@UtilityClass -public class DataSetFieldsExtractors { +public final class DataSetFieldsExtractors { - public List extract(SchemaSubject subject, KafkaPath topicOddrn, boolean isKey) { + public static List extract(SchemaSubject subject, KafkaPath topicOddrn, boolean isKey) { SchemaType schemaType = Optional.ofNullable(subject.getSchemaType()).orElse(SchemaType.AVRO); return switch (schemaType) { case AVRO -> AvroExtractor.extract(subject, topicOddrn, isKey); @@ -23,7 +20,7 @@ public class DataSetFieldsExtractors { } - DataSetField rootField(KafkaPath topicOddrn, boolean isKey) { + static DataSetField rootField(KafkaPath topicOddrn, boolean isKey) { var rootOddrn = topicOddrn.oddrn() + "/columns/" + (isKey ? "key" : "value"); return new DataSetField() .name(isKey ? "key" : "value") diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/schema/JsonSchemaExtractor.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/schema/JsonSchemaExtractor.java index f92e1fc876..06201b1ce7 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/schema/JsonSchemaExtractor.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/schema/JsonSchemaExtractor.java @@ -1,7 +1,6 @@ package com.provectus.kafka.ui.service.integration.odd.schema; import com.google.common.collect.ImmutableSet; -import com.provectus.kafka.ui.service.integration.odd.Oddrn; import com.provectus.kafka.ui.sr.model.SchemaSubject; import io.confluent.kafka.schemaregistry.json.JsonSchema; import java.net.URI; @@ -10,7 +9,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; import javax.annotation.Nullable; -import lombok.experimental.UtilityClass; import org.everit.json.schema.ArraySchema; import org.everit.json.schema.BooleanSchema; import org.everit.json.schema.CombinedSchema; @@ -27,8 +25,10 @@ import org.opendatadiscovery.client.model.DataSetFieldType; import org.opendatadiscovery.client.model.MetadataExtension; import org.opendatadiscovery.oddrn.model.KafkaPath; -@UtilityClass -class JsonSchemaExtractor { +final class JsonSchemaExtractor { + + private JsonSchemaExtractor() { + } static List extract(SchemaSubject subject, KafkaPath topicOddrn, boolean isKey) { Schema schema = new JsonSchema(subject.getSchema()).rawSchema(); @@ -46,13 +46,13 @@ class JsonSchemaExtractor { return result; } - private void extract(Schema schema, - String parentOddr, - String oddrn, //null for root - String name, - Boolean nullable, - ImmutableSet registeredRecords, - List sink) { + private static void extract(Schema schema, + String parentOddr, + String oddrn, //null for root + String name, + Boolean nullable, + ImmutableSet registeredRecords, + List sink) { if (schema instanceof ReferenceSchema s) { Optional.ofNullable(s.getReferredSchema()) .ifPresent(refSchema -> extract(refSchema, parentOddr, oddrn, name, nullable, registeredRecords, sink)); @@ -73,12 +73,12 @@ class JsonSchemaExtractor { } } - private void extractPrimitive(Schema schema, - String parentOddr, - String oddrn, //null for root - String name, - Boolean nullable, - List sink) { + private static void extractPrimitive(Schema schema, + String parentOddr, + String oddrn, //null for root + String name, + Boolean nullable, + List sink) { boolean isRoot = oddrn == null; sink.add( createDataSetField( @@ -93,12 +93,12 @@ class JsonSchemaExtractor { ); } - private void extractUnknown(Schema schema, - String parentOddr, - String oddrn, //null for root - String name, - Boolean nullable, - List sink) { + private static void extractUnknown(Schema schema, + String parentOddr, + String oddrn, //null for root + String name, + Boolean nullable, + List sink) { boolean isRoot = oddrn == null; sink.add( createDataSetField( @@ -113,13 +113,13 @@ class JsonSchemaExtractor { ); } - private void extractObject(ObjectSchema schema, - String parentOddr, - String oddrn, //null for root - String name, - Boolean nullable, - ImmutableSet registeredRecords, - List sink) { + private static void extractObject(ObjectSchema schema, + String parentOddr, + String oddrn, //null for root + String name, + Boolean nullable, + ImmutableSet registeredRecords, + List sink) { boolean isRoot = oddrn == null; // schemaLocation can be null for empty object schemas (like if it used in anyOf) @Nullable var schemaLocation = schema.getSchemaLocation(); @@ -162,13 +162,13 @@ class JsonSchemaExtractor { }); } - private void extractArray(ArraySchema schema, - String parentOddr, - String oddrn, //null for root - String name, - Boolean nullable, - ImmutableSet registeredRecords, - List sink) { + private static void extractArray(ArraySchema schema, + String parentOddr, + String oddrn, //null for root + String name, + Boolean nullable, + ImmutableSet registeredRecords, + List sink) { boolean isRoot = oddrn == null; oddrn = isRoot ? parentOddr + "/array" : oddrn; if (isRoot) { @@ -208,13 +208,13 @@ class JsonSchemaExtractor { } } - private void extractCombined(CombinedSchema schema, - String parentOddr, - String oddrn, //null for root - String name, - Boolean nullable, - ImmutableSet registeredRecords, - List sink) { + private static void extractCombined(CombinedSchema schema, + String parentOddr, + String oddrn, //null for root + String name, + Boolean nullable, + ImmutableSet registeredRecords, + List sink) { String combineType = "unknown"; if (schema.getCriterion() == CombinedSchema.ALL_CRITERION) { combineType = "allOf"; @@ -255,24 +255,24 @@ class JsonSchemaExtractor { } } - private String getDescription(Schema schema) { + private static String getDescription(Schema schema) { return Optional.ofNullable(schema.getTitle()) .orElse(schema.getDescription()); } - private String logicalTypeName(Schema schema) { + private static String logicalTypeName(Schema schema) { return schema.getClass() .getSimpleName() .replace("Schema", ""); } - private DataSetField createDataSetField(Schema schema, - String name, - String parentOddrn, - String oddrn, - DataSetFieldType.TypeEnum type, - String logicalType, - Boolean nullable) { + private static DataSetField createDataSetField(Schema schema, + String name, + String parentOddrn, + String oddrn, + DataSetFieldType.TypeEnum type, + String logicalType, + Boolean nullable) { return new DataSetField() .name(name) .parentFieldOddrn(parentOddrn) @@ -286,7 +286,7 @@ class JsonSchemaExtractor { ); } - private DataSetFieldType.TypeEnum mapType(Schema type) { + private static DataSetFieldType.TypeEnum mapType(Schema type) { if (type instanceof NumberSchema) { return DataSetFieldType.TypeEnum.NUMBER; } diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/schema/ProtoExtractor.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/schema/ProtoExtractor.java index b4a5378239..c1316172f3 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/schema/ProtoExtractor.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/service/integration/odd/schema/ProtoExtractor.java @@ -15,20 +15,17 @@ import com.google.protobuf.Timestamp; import com.google.protobuf.UInt32Value; import com.google.protobuf.UInt64Value; import com.google.protobuf.Value; -import com.provectus.kafka.ui.service.integration.odd.Oddrn; import com.provectus.kafka.ui.sr.model.SchemaSubject; import io.confluent.kafka.schemaregistry.protobuf.ProtobufSchema; import java.util.ArrayList; import java.util.List; import java.util.Set; -import lombok.experimental.UtilityClass; import org.opendatadiscovery.client.model.DataSetField; import org.opendatadiscovery.client.model.DataSetFieldType; import org.opendatadiscovery.client.model.DataSetFieldType.TypeEnum; import org.opendatadiscovery.oddrn.model.KafkaPath; -@UtilityClass -class ProtoExtractor { +final class ProtoExtractor { private static final Set PRIMITIVES_WRAPPER_TYPE_NAMES = Set.of( BoolValue.getDescriptor().getFullName(), @@ -42,7 +39,10 @@ class ProtoExtractor { DoubleValue.getDescriptor().getFullName() ); - List extract(SchemaSubject subject, KafkaPath topicOddrn, boolean isKey) { + private ProtoExtractor() { + } + + static List extract(SchemaSubject subject, KafkaPath topicOddrn, boolean isKey) { Descriptor schema = new ProtobufSchema(subject.getSchema()).toDescriptor(); List result = new ArrayList<>(); result.add(DataSetFieldsExtractors.rootField(topicOddrn, isKey)); @@ -60,14 +60,14 @@ class ProtoExtractor { return result; } - private void extract(Descriptors.FieldDescriptor field, - String parentOddr, - String oddrn, //null for root - String name, - boolean nullable, - boolean repeated, - ImmutableSet registeredRecords, - List sink) { + private static void extract(Descriptors.FieldDescriptor field, + String parentOddr, + String oddrn, //null for root + String name, + boolean nullable, + boolean repeated, + ImmutableSet registeredRecords, + List sink) { if (repeated) { extractRepeated(field, parentOddr, oddrn, name, nullable, registeredRecords, sink); } else if (field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE) { @@ -79,12 +79,12 @@ class ProtoExtractor { // converts some(!) Protobuf Well-known type (from google.protobuf.* packages) // see JsonFormat::buildWellKnownTypePrinters for impl details - private boolean extractProtoWellKnownType(Descriptors.FieldDescriptor field, - String parentOddr, - String oddrn, //null for root - String name, - boolean nullable, - List sink) { + private static boolean extractProtoWellKnownType(Descriptors.FieldDescriptor field, + String parentOddr, + String oddrn, //null for root + String name, + boolean nullable, + List sink) { // all well-known types are messages if (field.getType() != Descriptors.FieldDescriptor.Type.MESSAGE) { return false; @@ -111,13 +111,13 @@ class ProtoExtractor { return false; } - private void extractRepeated(Descriptors.FieldDescriptor field, - String parentOddr, - String oddrn, //null for root - String name, - boolean nullable, - ImmutableSet registeredRecords, - List sink) { + private static void extractRepeated(Descriptors.FieldDescriptor field, + String parentOddr, + String oddrn, //null for root + String name, + boolean nullable, + ImmutableSet registeredRecords, + List sink) { sink.add(createDataSetField(name, parentOddr, oddrn, TypeEnum.LIST, "repeated", nullable)); String itemName = field.getType() == Descriptors.FieldDescriptor.Type.MESSAGE @@ -136,13 +136,13 @@ class ProtoExtractor { ); } - private void extractMessage(Descriptors.FieldDescriptor field, - String parentOddr, - String oddrn, //null for root - String name, - boolean nullable, - ImmutableSet registeredRecords, - List sink) { + private static void extractMessage(Descriptors.FieldDescriptor field, + String parentOddr, + String oddrn, //null for root + String name, + boolean nullable, + ImmutableSet registeredRecords, + List sink) { if (extractProtoWellKnownType(field, parentOddr, oddrn, name, nullable, sink)) { return; } @@ -173,12 +173,12 @@ class ProtoExtractor { }); } - private void extractPrimitive(Descriptors.FieldDescriptor field, - String parentOddr, - String oddrn, - String name, - boolean nullable, - List sink) { + private static void extractPrimitive(Descriptors.FieldDescriptor field, + String parentOddr, + String oddrn, + String name, + boolean nullable, + List sink) { sink.add( createDataSetField( name, @@ -191,18 +191,18 @@ class ProtoExtractor { ); } - private String getLogicalTypeName(Descriptors.FieldDescriptor f) { + private static String getLogicalTypeName(Descriptors.FieldDescriptor f) { return f.getType() == Descriptors.FieldDescriptor.Type.MESSAGE ? f.getMessageType().getFullName() : f.getType().name().toLowerCase(); } - private DataSetField createDataSetField(String name, - String parentOddrn, - String oddrn, - TypeEnum type, - String logicalType, - Boolean nullable) { + private static DataSetField createDataSetField(String name, + String parentOddrn, + String oddrn, + TypeEnum type, + String logicalType, + Boolean nullable) { return new DataSetField() .name(name) .parentFieldOddrn(parentOddrn) @@ -216,7 +216,7 @@ class ProtoExtractor { } - private TypeEnum mapType(Descriptors.FieldDescriptor.Type type) { + private static TypeEnum mapType(Descriptors.FieldDescriptor.Type type) { return switch (type) { case INT32, INT64, SINT32, SFIXED32, SINT64, UINT32, UINT64, FIXED32, FIXED64, SFIXED64 -> TypeEnum.INTEGER; case FLOAT, DOUBLE -> TypeEnum.NUMBER; diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/KafkaServicesValidation.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/KafkaServicesValidation.java index 7f5b8c45f2..31d90244eb 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/KafkaServicesValidation.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/KafkaServicesValidation.java @@ -1,6 +1,7 @@ package com.provectus.kafka.ui.util; -import com.provectus.kafka.ui.config.ClustersProperties; +import static com.provectus.kafka.ui.config.ClustersProperties.TruststoreConfig; + import com.provectus.kafka.ui.connect.api.KafkaConnectClientApi; import com.provectus.kafka.ui.model.ApplicationPropertyValidationDTO; import com.provectus.kafka.ui.service.ReactiveAdminClient; @@ -13,38 +14,36 @@ import java.util.Optional; import java.util.Properties; import java.util.function.Supplier; import javax.annotation.Nullable; -import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; -import lombok.experimental.UtilityClass; import lombok.extern.slf4j.Slf4j; import org.apache.kafka.clients.admin.AdminClient; import org.apache.kafka.clients.admin.AdminClientConfig; import org.springframework.util.ResourceUtils; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import reactor.util.function.Tuple2; -import reactor.util.function.Tuples; @Slf4j -@UtilityClass -public class KafkaServicesValidation { +public final class KafkaServicesValidation { - private Mono valid() { + private KafkaServicesValidation() { + } + + private static Mono valid() { return Mono.just(new ApplicationPropertyValidationDTO().error(false)); } - private Mono invalid(String errorMsg) { + private static Mono invalid(String errorMsg) { return Mono.just(new ApplicationPropertyValidationDTO().error(true).errorMessage(errorMsg)); } - private Mono invalid(Throwable th) { + private static Mono invalid(Throwable th) { return Mono.just(new ApplicationPropertyValidationDTO().error(true).errorMessage(th.getMessage())); } /** * Returns error msg, if any. */ - public Optional validateTruststore(ClustersProperties.TruststoreConfig truststoreConfig) { + public static Optional validateTruststore(TruststoreConfig truststoreConfig) { if (truststoreConfig.getTruststoreLocation() != null && truststoreConfig.getTruststorePassword() != null) { try { KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); @@ -63,10 +62,10 @@ public class KafkaServicesValidation { return Optional.empty(); } - public Mono validateClusterConnection(String bootstrapServers, - Properties clusterProps, - @Nullable - ClustersProperties.TruststoreConfig ssl) { + public static Mono validateClusterConnection(String bootstrapServers, + Properties clusterProps, + @Nullable + TruststoreConfig ssl) { Properties properties = new Properties(); SslPropertiesUtil.addKafkaSslProperties(ssl, properties); properties.putAll(clusterProps); @@ -93,7 +92,7 @@ public class KafkaServicesValidation { }); } - public Mono validateSchemaRegistry( + public static Mono validateSchemaRegistry( Supplier> clientSupplier) { ReactiveFailover client; try { @@ -108,7 +107,7 @@ public class KafkaServicesValidation { .onErrorResume(KafkaServicesValidation::invalid); } - public Mono validateConnect( + public static Mono validateConnect( Supplier> clientSupplier) { ReactiveFailover client; try { @@ -123,7 +122,8 @@ public class KafkaServicesValidation { .onErrorResume(KafkaServicesValidation::invalid); } - public Mono validateKsql(Supplier> clientSupplier) { + public static Mono validateKsql( + Supplier> clientSupplier) { ReactiveFailover client; try { client = clientSupplier.get(); diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/KafkaVersion.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/KafkaVersion.java index 48ff7ff121..5ed21c6a6e 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/KafkaVersion.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/KafkaVersion.java @@ -1,11 +1,12 @@ package com.provectus.kafka.ui.util; -import lombok.experimental.UtilityClass; import lombok.extern.slf4j.Slf4j; -@UtilityClass @Slf4j -public class KafkaVersion { +public final class KafkaVersion { + + private KafkaVersion() { + } public static float parse(String version) throws NumberFormatException { log.trace("Parsing cluster version [{}]", version); diff --git a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/SslPropertiesUtil.java b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/SslPropertiesUtil.java index ea12007637..4d157fbcb5 100644 --- a/kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/SslPropertiesUtil.java +++ b/kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/SslPropertiesUtil.java @@ -1,27 +1,17 @@ package com.provectus.kafka.ui.util; import com.provectus.kafka.ui.config.ClustersProperties; -import io.netty.handler.ssl.SslContext; -import io.netty.handler.ssl.SslContextBuilder; -import java.io.FileInputStream; -import java.security.KeyStore; import java.util.Properties; import javax.annotation.Nullable; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManagerFactory; -import lombok.SneakyThrows; -import lombok.experimental.UtilityClass; import org.apache.kafka.common.config.SslConfigs; -import org.springframework.http.client.reactive.ReactorClientHttpConnector; -import org.springframework.util.ResourceUtils; -import reactor.netty.http.client.HttpClient; -@UtilityClass -public class SslPropertiesUtil { +public final class SslPropertiesUtil { - public void addKafkaSslProperties(@Nullable ClustersProperties.TruststoreConfig truststoreConfig, - Properties sink) { + private SslPropertiesUtil() { + } + + public static void addKafkaSslProperties(@Nullable ClustersProperties.TruststoreConfig truststoreConfig, + Properties sink) { if (truststoreConfig != null && truststoreConfig.getTruststoreLocation() != null) { sink.put(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG, truststoreConfig.getTruststoreLocation()); if (truststoreConfig.getTruststorePassword() != null) { From 1117b296a7843272a8827099b9220aee4e5d9ab5 Mon Sep 17 00:00:00 2001 From: David <58771979+David-DB88@users.noreply.github.com> Date: Tue, 14 Mar 2023 22:03:05 +0400 Subject: [PATCH 7/8] UI: Implement a dark theme (#2996) --------- Co-authored-by: davitbejanyan Co-authored-by: Mgrdich Co-authored-by: Roman Zabaluev Co-authored-by: VladSenyuta Co-authored-by: Vlad Senyuta <66071557+VladSenyuta@users.noreply.github.com> Co-authored-by: Oleg Shur --- .../com/provectus/kafka/ui/models/Schema.java | 6 +- .../provectus/kafka/ui/pages/BasePage.java | 15 +- .../pages/connectors/ConnectorCreateForm.java | 17 +- .../ui/pages/schemas/SchemaCreateForm.java | 28 +- .../ui/pages/topics/ProduceMessagePanel.java | 2 +- .../ui/settings/drivers/LocalWebDriver.java | 87 +- .../listeners/QaseResultListener.java | 4 +- .../kafka/ui/utilities/WebUtils.java | 9 + .../config_for_create_connector.json | 0 .../config_for_create_connector_via_api.json | 0 .../config_for_update_connector.json | 0 .../connectors}/delete_connector_config.json | 0 .../{ => schemas}/schema_avro_for_update.json | 11 +- .../{ => schemas}/schema_avro_value.json | 0 .../schema_json_Value.json} | 0 .../{ => schemas}/schema_protobuf_value.txt | 0 .../topics}/message_content_create_topic.json | 0 .../smokeSuite/connectors/ConnectorsTest.java | 8 +- .../ui/smokeSuite/schemas/SchemasTest.java | 11 +- .../ui/smokeSuite/topics/MessagesTest.java | 2 +- kafka-ui-react-app/src/components/App.tsx | 18 +- .../Connect/Details/Actions/Action.styled.ts | 4 +- .../components/Connect/List/TopicsCell.tsx | 2 +- .../TopicContents/TopicContent.styled.ts | 7 +- .../components/Dashboard/Dashboard.styled.ts | 1 + .../components/ErrorPage/ErrorPage.styled.ts | 2 +- .../Query/QueryForm/QueryForm.styled.ts | 33 +- .../KsqlDb/Query/QueryForm/QueryForm.tsx | 2 + .../Nav/ClusterTab/ClusterTab.styled.ts | 1 + .../__tests__/ClusterTab.styled.spec.tsx | 2 +- .../src/components/NavBar/NavBar.styled.ts | 11 +- .../src/components/NavBar/NavBar.tsx | 85 +- .../components/NavBar/UserInfo/UserInfo.tsx | 8 +- .../NavBar/__tests__/NavBar.spec.tsx | 10 +- .../PageContainer/PageContainer.tsx | 6 +- .../__tests__/PageContainer.spec.tsx | 9 +- .../LatestVersionItem.styled.tsx | 11 +- .../components/Schemas/Diff/Diff.styled.ts | 37 +- .../components/Schemas/Edit/Edit.styled.ts | 3 +- .../GlobalSchemaSelector.styled.ts | 3 + .../Edit/DangerZone/DangerZone.styled.tsx | 2 +- .../Topic/Messages/Filters/Filters.styled.ts | 52 +- .../Topics/Topic/Messages/Filters/Filters.tsx | 6 +- .../Topic/Messages/Filters/SavedFilters.tsx | 4 +- .../Filters/__tests__/Filters.styled.spec.tsx | 2 +- .../MessageContent/MessageContent.styled.ts | 6 +- .../__tests__/MessageContent.spec.tsx | 2 +- .../Topic/Messages/PreviewModal.styled.ts | 1 + .../Topic/Overview/__test__/Overview.spec.tsx | 2 +- .../Topics/Topic/Statistics/Metrics.tsx | 2 +- .../Topics/shared/Form/TopicForm.styled.ts | 9 +- .../Topics/shared/Form/TopicForm.tsx | 3 +- .../Form/__tests__/TimeToRetainBtn.spec.tsx | 6 +- .../Form/__tests__/TopicForm.styled.spec.tsx | 6 +- .../src/components/Version/Version.styled.ts | 24 +- .../src/components/Version/Version.tsx | 9 +- .../src/components/__tests__/App.spec.tsx | 6 + .../components/common/Button/Button.styled.ts | 62 +- .../common/Button/__tests__/Button.spec.tsx | 8 +- .../ConfirmationModal.styled.tsx | 6 +- .../ControlPanel/ControlPanel.styled.ts | 5 +- .../common/Dropdown/Dropdown.styled.ts | 3 +- .../src/components/common/Editor/Editor.tsx | 32 + .../EditorViewer/EditorViewer.styled.ts | 9 +- .../components/common/Icons/ArrowDownIcon.tsx | 27 +- .../src/components/common/Icons/AutoIcon.tsx | 28 + .../components/common/Icons/CancelIcon.tsx | 4 +- .../components/common/Icons/CheckmarkIcon.tsx | 2 +- .../src/components/common/Icons/ClockIcon.tsx | 27 +- .../components/common/Icons/DeleteIcon.tsx | 2 +- .../common/Icons/DropdownArrowIcon.tsx | 16 +- .../src/components/common/Icons/EditIcon.tsx | 6 +- .../src/components/common/Icons/FileIcon.tsx | 27 +- .../src/components/common/Icons/InfoIcon.tsx | 53 +- .../common/Icons/MessageToggleIcon.styled.ts | 13 +- .../common/Icons/MessageToggleIcon.tsx | 1 + .../src/components/common/Icons/MoonIcon.tsx | 22 + .../src/components/common/Icons/SavedIcon.tsx | 2 +- .../src/components/common/Icons/SunIcon.tsx | 54 + .../components/common/Icons/WarningIcon.tsx | 28 +- .../components/common/Input/Input.styled.ts | 11 +- .../common/Metrics/Metrics.styled.tsx | 5 +- .../Metrics/__tests__/Indicator.spec.tsx | 2 +- .../common/Metrics/__tests__/Section.spec.tsx | 3 +- .../common/MultiSelect/MultiSelect.styled.ts | 33 +- .../common/Navigation/Navbar.styled.ts | 16 +- .../common/NewTable/ExpanderCell.tsx | 55 +- .../common/NewTable/Table.styled.ts | 25 +- .../common/ProgressBar/ProgressBar.styled.ts | 4 +- .../PropertiesList/PropertiesList.styled.tsx | 7 +- .../components/common/Select/Select.styled.ts | 86 +- .../src/components/common/Select/Select.tsx | 23 +- .../SlidingSidebar/SlidingSidebar.styled.ts | 4 +- .../components/common/Switch/Switch.styled.ts | 42 +- .../src/components/common/Switch/Switch.tsx | 22 +- .../src/components/common/Tag/Tag.styled.tsx | 4 +- .../common/Textbox/Textarea.styled.ts | 2 + .../common/table/Table/Table.styled.ts | 2 +- .../common/table/Table/TableKeyLink.styled.ts | 3 + .../TableHeaderCell/TableHeaderCell.styled.ts | 8 +- .../__test__/TableHeaderCell.styled.spec.tsx | 2 +- .../table/__tests__/TableHeaderCell.spec.tsx | 2 +- .../src/components/globalCss.ts | 11 +- kafka-ui-react-app/src/lib/testHelpers.tsx | 2 +- kafka-ui-react-app/src/theme/theme.ts | 992 ++++++++++++++---- .../ClusterConfigForm.styled.ts | 4 +- 106 files changed, 1736 insertions(+), 668 deletions(-) rename kafka-ui-e2e-checks/src/main/resources/{ => testData/connectors}/config_for_create_connector.json (100%) rename kafka-ui-e2e-checks/src/main/resources/{ => testData/connectors}/config_for_create_connector_via_api.json (100%) rename kafka-ui-e2e-checks/src/main/resources/{ => testData/connectors}/config_for_update_connector.json (100%) rename kafka-ui-e2e-checks/src/main/resources/{ => testData/connectors}/delete_connector_config.json (100%) rename kafka-ui-e2e-checks/src/main/resources/testData/{ => schemas}/schema_avro_for_update.json (61%) rename kafka-ui-e2e-checks/src/main/resources/testData/{ => schemas}/schema_avro_value.json (100%) rename kafka-ui-e2e-checks/src/main/resources/testData/{schema_Json_Value.json => schemas/schema_json_Value.json} (100%) rename kafka-ui-e2e-checks/src/main/resources/testData/{ => schemas}/schema_protobuf_value.txt (100%) rename kafka-ui-e2e-checks/src/main/resources/{ => testData/topics}/message_content_create_topic.json (100%) create mode 100644 kafka-ui-react-app/src/components/common/Icons/AutoIcon.tsx create mode 100644 kafka-ui-react-app/src/components/common/Icons/MoonIcon.tsx create mode 100644 kafka-ui-react-app/src/components/common/Icons/SunIcon.tsx diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Schema.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Schema.java index cd573037ba..19dc44a028 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Schema.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/models/Schema.java @@ -16,18 +16,18 @@ public class Schema { public static Schema createSchemaAvro() { return new Schema().setName("schema_avro-" + randomAlphabetic(5)) .setType(SchemaType.AVRO) - .setValuePath(System.getProperty("user.dir") + "/src/main/resources/testData/schema_avro_value.json"); + .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/schema_Json_Value.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/schema_protobuf_value.txt"); + .setValuePath(System.getProperty("user.dir") + "/src/main/resources/testData/schemas/schema_protobuf_value.txt"); } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/BasePage.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/BasePage.java index c131bd8e0d..979302fd27 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/BasePage.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/BasePage.java @@ -3,8 +3,11 @@ package com.provectus.kafka.ui.pages; 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.utilities.WebUtils; import lombok.extern.slf4j.Slf4j; +import org.openqa.selenium.Keys; +import org.openqa.selenium.interactions.Actions; import java.time.Duration; @@ -34,7 +37,7 @@ public abstract class BasePage extends WebUtils { protected void waitUntilSpinnerDisappear() { log.debug("\nwaitUntilSpinnerDisappear"); if (isVisible(loadingSpinner)) { - loadingSpinner.shouldBe(Condition.disappear, Duration.ofSeconds(30)); + loadingSpinner.shouldBe(Condition.disappear, Duration.ofSeconds(60)); } } @@ -42,6 +45,16 @@ public abstract class BasePage extends WebUtils { 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)); diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/ConnectorCreateForm.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/ConnectorCreateForm.java index 7bc2aa88aa..fbbea0f1c0 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/ConnectorCreateForm.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/connectors/ConnectorCreateForm.java @@ -21,11 +21,22 @@ public class ConnectorCreateForm extends BasePage { } @Step - public ConnectorCreateForm setConnectorDetails(String connectName, String configJson) { + public ConnectorCreateForm setName(String connectName) { nameField.shouldBe(Condition.enabled).setValue(connectName); + return this; + } + + @Step + public ConnectorCreateForm setConfig(String configJson) { configField.shouldBe(Condition.enabled).click(); - contentTextArea.setValue(configJson); - nameField.shouldBe(Condition.enabled).click(); + setJsonInputValue(contentTextArea, configJson); + return this; + } + + @Step + public ConnectorCreateForm setConnectorDetails(String connectName, String configJson) { + setName(connectName); + setConfig(configJson); return this; } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaCreateForm.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaCreateForm.java index b823b6b992..52bfe0971f 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaCreateForm.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/schemas/SchemaCreateForm.java @@ -2,16 +2,20 @@ package com.provectus.kafka.ui.pages.schemas; import com.codeborne.selenide.Condition; import com.codeborne.selenide.SelenideElement; +import com.codeborne.selenide.WebDriverRunner; 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; public class SchemaCreateForm extends BasePage { @@ -23,7 +27,8 @@ public class SchemaCreateForm extends BasePage { protected SelenideElement compatibilityLevelList = $x("//ul[@name='compatibilityLevel']"); protected SelenideElement newSchemaTextArea = $x("//div[@id='newSchema']"); protected SelenideElement latestSchemaTextArea = $x("//div[@id='latestSchema']"); - protected SelenideElement schemaVersionDdl = $$x("//ul[@role='listbox']/li[text()='Version 2']").first(); + protected SelenideElement leftVersionDdl = $(id("left-select")); + protected SelenideElement rightVersionDdl = $(id("right-select")); protected List visibleMarkers = $$x("//div[@class='ace_scroller']//div[contains(@class,'codeMarker')]"); protected List elementsCompareVersionDdl = $$x("//ul[@role='listbox']/ul/li"); protected String ddlElementLocator = "//li[@value='%s']"; @@ -68,8 +73,14 @@ public class SchemaCreateForm extends BasePage { } @Step - public SchemaCreateForm openSchemaVersionDdl() { - schemaVersionDdl.shouldBe(Condition.enabled).click(); + public SchemaCreateForm openLeftVersionDdl() { + leftVersionDdl.shouldBe(Condition.enabled).click(); + return this; + } + + @Step + public SchemaCreateForm openRightVersionDdl() { + rightVersionDdl.shouldBe(Condition.enabled).click(); return this; } @@ -92,8 +103,15 @@ public class SchemaCreateForm extends BasePage { @Step public SchemaCreateForm setNewSchemaValue(String configJson) { newSchemaTextArea.shouldBe(Condition.visible).click(); - clearByKeyboard(newSchemaInput); - newSchemaInput.setValue(configJson); + 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; } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/ProduceMessagePanel.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/ProduceMessagePanel.java index a16d2c83a0..651c514eef 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/ProduceMessagePanel.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/pages/topics/ProduceMessagePanel.java @@ -49,7 +49,7 @@ public class ProduceMessagePanel extends BasePage { @Step public ProduceMessagePanel submitProduceMessage() { - submitBtn.shouldBe(Condition.enabled).click(); + clickByActions(submitBtn); submitBtn.shouldBe(Condition.disappear); refresh(); return this; diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/drivers/LocalWebDriver.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/drivers/LocalWebDriver.java index b1dabffc84..e96213dd06 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/drivers/LocalWebDriver.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/drivers/LocalWebDriver.java @@ -14,54 +14,55 @@ import org.openqa.selenium.chrome.ChromeOptions; public abstract class LocalWebDriver { - private static org.openqa.selenium.WebDriver getWebDriver() { - try { - return WebDriverRunner.getWebDriver(); - } catch (IllegalStateException ex) { - 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 = true; - Configuration.pageLoadTimeout = 120000; - Configuration.browserCapabilities = new ChromeOptions() - .addArguments("--lang=en_US"); - open(); - return WebDriverRunner.getWebDriver(); + private static org.openqa.selenium.WebDriver getWebDriver() { + try { + return WebDriverRunner.getWebDriver(); + } catch (IllegalStateException ex) { + 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 = true; + Configuration.pageLoadTimeout = 120000; + Configuration.browserCapabilities = new ChromeOptions() + .addArguments("--remote-allow-origins=*") + .addArguments("--lang=en_US"); + open(); + return WebDriverRunner.getWebDriver(); + } } - } - @Step - public static void openUrl(String url) { - if (!getWebDriver().getCurrentUrl().equals(url)) { - getWebDriver().get(url); + @Step + public static void openUrl(String url) { + if (!getWebDriver().getCurrentUrl().equals(url)) { + getWebDriver().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() { - getWebDriver().quit(); - } + @Step + public static void browserQuit() { + getWebDriver().quit(); + } - @Step - public static void loggerSetup() { - SelenideLogger.addListener("AllureSelenide", new AllureSelenide() - .screenshots(true) - .savePageSource(false)); - } + @Step + public static void loggerSetup() { + SelenideLogger.addListener("AllureSelenide", new AllureSelenide() + .screenshots(true) + .savePageSource(false)); + } } diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/QaseResultListener.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/QaseResultListener.java index abab897bfc..72056db922 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/QaseResultListener.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/settings/listeners/QaseResultListener.java @@ -39,9 +39,9 @@ public class QaseResultListener extends TestListenerAdapter implements ITestList } @Override - public void onTestStart(ITestResult result) { + public void onTestStart(ITestResult tr) { getQaseTestCaseListener().onTestCaseStarted(); - super.onTestStart(result); + super.onTestStart(tr); } @Override diff --git a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/WebUtils.java b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/WebUtils.java index 7e0de1ac65..8358880503 100644 --- a/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/WebUtils.java +++ b/kafka-ui-e2e-checks/src/main/java/com/provectus/kafka/ui/utilities/WebUtils.java @@ -21,6 +21,15 @@ public class WebUtils { .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); diff --git a/kafka-ui-e2e-checks/src/main/resources/config_for_create_connector.json b/kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_create_connector.json similarity index 100% rename from kafka-ui-e2e-checks/src/main/resources/config_for_create_connector.json rename to kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_create_connector.json diff --git a/kafka-ui-e2e-checks/src/main/resources/config_for_create_connector_via_api.json b/kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_create_connector_via_api.json similarity index 100% rename from kafka-ui-e2e-checks/src/main/resources/config_for_create_connector_via_api.json rename to kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_create_connector_via_api.json diff --git a/kafka-ui-e2e-checks/src/main/resources/config_for_update_connector.json b/kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_update_connector.json similarity index 100% rename from kafka-ui-e2e-checks/src/main/resources/config_for_update_connector.json rename to kafka-ui-e2e-checks/src/main/resources/testData/connectors/config_for_update_connector.json diff --git a/kafka-ui-e2e-checks/src/main/resources/delete_connector_config.json b/kafka-ui-e2e-checks/src/main/resources/testData/connectors/delete_connector_config.json similarity index 100% rename from kafka-ui-e2e-checks/src/main/resources/delete_connector_config.json rename to kafka-ui-e2e-checks/src/main/resources/testData/connectors/delete_connector_config.json diff --git a/kafka-ui-e2e-checks/src/main/resources/testData/schema_avro_for_update.json b/kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_avro_for_update.json similarity index 61% rename from kafka-ui-e2e-checks/src/main/resources/testData/schema_avro_for_update.json rename to kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_avro_for_update.json index 2979d69a9b..9971559ba7 100644 --- a/kafka-ui-e2e-checks/src/main/resources/testData/schema_avro_for_update.json +++ b/kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_avro_for_update.json @@ -5,19 +5,12 @@ "fields": [ { "name": "text", - "type": [ - "null", - "string" - ], + "type": "string", "default": null }, { "name": "value", - "type": [ - "null", - "string", - "long" - ], + "type": "string", "default": null } ] diff --git a/kafka-ui-e2e-checks/src/main/resources/testData/schema_avro_value.json b/kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_avro_value.json similarity index 100% rename from kafka-ui-e2e-checks/src/main/resources/testData/schema_avro_value.json rename to kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_avro_value.json diff --git a/kafka-ui-e2e-checks/src/main/resources/testData/schema_Json_Value.json b/kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_json_Value.json similarity index 100% rename from kafka-ui-e2e-checks/src/main/resources/testData/schema_Json_Value.json rename to kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_json_Value.json diff --git a/kafka-ui-e2e-checks/src/main/resources/testData/schema_protobuf_value.txt b/kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_protobuf_value.txt similarity index 100% rename from kafka-ui-e2e-checks/src/main/resources/testData/schema_protobuf_value.txt rename to kafka-ui-e2e-checks/src/main/resources/testData/schemas/schema_protobuf_value.txt diff --git a/kafka-ui-e2e-checks/src/main/resources/message_content_create_topic.json b/kafka-ui-e2e-checks/src/main/resources/testData/topics/message_content_create_topic.json similarity index 100% rename from kafka-ui-e2e-checks/src/main/resources/message_content_create_topic.json rename to kafka-ui-e2e-checks/src/main/resources/testData/topics/message_content_create_topic.json diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/connectors/ConnectorsTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/connectors/ConnectorsTest.java index c54138d8c5..db1fea805a 100644 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/connectors/ConnectorsTest.java +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/connectors/ConnectorsTest.java @@ -21,7 +21,7 @@ public class ConnectorsTest extends BaseTest { private static final String CONNECT_NAME = "first"; private static final List TOPIC_LIST = new ArrayList<>(); private static final List CONNECTOR_LIST = new ArrayList<>(); - private static final String MESSAGE_CONTENT = "message_content_create_topic.json"; + private static final String MESSAGE_CONTENT = "testData/topics/message_content_create_topic.json"; private static final String MESSAGE_KEY = " "; private static final Topic TOPIC_FOR_CREATE = new Topic() .setName("topic_for_create_connector-" + randomAlphabetic(5)) @@ -34,10 +34,10 @@ public class ConnectorsTest extends BaseTest { .setMessageContent(MESSAGE_CONTENT).setMessageKey(MESSAGE_KEY); private static final Connector CONNECTOR_FOR_DELETE = new Connector() .setName("sink_postgres_activities_e2e_checks_for_delete-" + randomAlphabetic(5)) - .setConfig(getResourceAsString("delete_connector_config.json")); + .setConfig(getResourceAsString("testData/connectors/delete_connector_config.json")); private static final Connector CONNECTOR_FOR_UPDATE = new Connector() .setName("sink_postgres_activities_e2e_checks_for_update-" + randomAlphabetic(5)) - .setConfig(getResourceAsString("config_for_create_connector_via_api.json")); + .setConfig(getResourceAsString("testData/connectors/config_for_create_connector_via_api.json")); @BeforeClass(alwaysRun = true) public void beforeClass() { @@ -56,7 +56,7 @@ public class ConnectorsTest extends BaseTest { public void createConnector() { Connector connectorForCreate = new Connector() .setName("sink_postgres_activities_e2e_checks-" + randomAlphabetic(5)) - .setConfig(getResourceAsString("config_for_create_connector.json")); + .setConfig(getResourceAsString("testData/connectors/config_for_create_connector.json")); navigateToConnectors(); kafkaConnectList .clickCreateConnectorBtn(); diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/schemas/SchemasTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/schemas/SchemasTest.java index a253bc4b67..9b2a1618c2 100644 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/schemas/SchemasTest.java +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/schemas/SchemasTest.java @@ -57,7 +57,7 @@ public class SchemasTest extends BaseTest { @QaseId(186) @Test(priority = 2) public void updateSchemaAvro() { - AVRO_API.setValuePath(System.getProperty("user.dir") + "/src/main/resources/testData/schema_avro_for_update.json"); + AVRO_API.setValuePath(System.getProperty("user.dir") + "/src/main/resources/testData/schemas/schema_avro_for_update.json"); navigateToSchemaRegistryAndOpenDetails(AVRO_API.getName()); schemaDetails .openEditSchema(); @@ -74,7 +74,8 @@ public class SchemasTest extends BaseTest { .clickSubmitButton(); schemaDetails .waitUntilScreenReady(); - Assert.assertEquals(CompatibilityLevel.CompatibilityEnum.NONE.toString(), schemaDetails.getCompatibility(), "getCompatibility()"); + Assert.assertEquals(schemaDetails.getCompatibility(), CompatibilityLevel.CompatibilityEnum.NONE.toString(), + "getCompatibility()"); } @QaseId(44) @@ -88,12 +89,12 @@ public class SchemasTest extends BaseTest { .openCompareVersionMenu(); int versionsNumberFromDdl = schemaCreateForm .waitUntilScreenReady() - .openSchemaVersionDdl() + .openLeftVersionDdl() .getVersionsNumberFromList(); - Assert.assertEquals(latestVersion, versionsNumberFromDdl, "Versions number is not matched"); + Assert.assertEquals(versionsNumberFromDdl, latestVersion, "Versions number is not matched"); schemaCreateForm .selectVersionFromDropDown(1); - Assert.assertEquals(53, schemaCreateForm.getMarkedLinesNumber(), "getAllMarkedLines()"); + Assert.assertEquals(schemaCreateForm.getMarkedLinesNumber(), 42, "getAllMarkedLines()"); } @QaseId(187) diff --git a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/topics/MessagesTest.java b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/topics/MessagesTest.java index dc7fc403c8..18219d965d 100644 --- a/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/topics/MessagesTest.java +++ b/kafka-ui-e2e-checks/src/test/java/com/provectus/kafka/ui/smokeSuite/topics/MessagesTest.java @@ -32,7 +32,7 @@ public class MessagesTest extends BaseTest { .setMessageKey(randomAlphabetic(5)) .setMessageContent(randomAlphabetic(10)); private static final Topic TOPIC_TO_CLEAR_AND_PURGE_MESSAGES = new Topic() - .setName("topic-to-clear-and-purge-messages-attribute-" + randomAlphabetic(5)) + .setName("topic-to-clear-and-purge-messages-" + randomAlphabetic(5)) .setMessageKey(randomAlphabetic(5)) .setMessageContent(randomAlphabetic(10)); private static final Topic TOPIC_FOR_CHECK_FILTERS = new Topic() diff --git a/kafka-ui-react-app/src/components/App.tsx b/kafka-ui-react-app/src/components/App.tsx index e971b15e2b..6107e3ade7 100644 --- a/kafka-ui-react-app/src/components/App.tsx +++ b/kafka-ui-react-app/src/components/App.tsx @@ -11,7 +11,7 @@ import PageLoader from 'components/common/PageLoader/PageLoader'; import Dashboard from 'components/Dashboard/Dashboard'; import ClusterPage from 'components/ClusterPage/ClusterPage'; import { ThemeProvider } from 'styled-components'; -import theme from 'theme/theme'; +import { theme, darkTheme } from 'theme/theme'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { showServerError } from 'lib/errorHandling'; import { Toaster } from 'react-hot-toast'; @@ -39,16 +39,18 @@ const queryClient = new QueryClient({ }, }); const App: React.FC = () => { + const [isDarkMode, setDarkMode] = React.useState(false); + return ( - - }> - + + + }> - + {['/', '/ui', '/ui/clusters'].map((path) => ( { - - - + + + ); }; diff --git a/kafka-ui-react-app/src/components/Connect/Details/Actions/Action.styled.ts b/kafka-ui-react-app/src/components/Connect/Details/Actions/Action.styled.ts index a2998acdc2..77165abd9f 100644 --- a/kafka-ui-react-app/src/components/Connect/Details/Actions/Action.styled.ts +++ b/kafka-ui-react-app/src/components/Connect/Details/Actions/Action.styled.ts @@ -15,8 +15,8 @@ export const RestartButton = styled.div` border-radius: 4px; display: flex; -webkit-align-items: center; - background: #e8e8fc; - color: #171a1c; + background: ${({ theme }) => theme.button.primary.backgroundColor.normal}; + color: ${({ theme }) => theme.button.primary.color.normal}; font-size: 14px; font-weight: 500; height: 32px; diff --git a/kafka-ui-react-app/src/components/Connect/List/TopicsCell.tsx b/kafka-ui-react-app/src/components/Connect/List/TopicsCell.tsx index ee48c2d2d3..f5f634b7f2 100644 --- a/kafka-ui-react-app/src/components/Connect/List/TopicsCell.tsx +++ b/kafka-ui-react-app/src/components/Connect/List/TopicsCell.tsx @@ -27,7 +27,7 @@ const TopicsCell: React.FC> = ({ return ( {topics?.map((t) => ( - + navigateToTopic(e, t)} diff --git a/kafka-ui-react-app/src/components/ConsumerGroups/Details/TopicContents/TopicContent.styled.ts b/kafka-ui-react-app/src/components/ConsumerGroups/Details/TopicContents/TopicContent.styled.ts index 67b03ab127..af36dfbee7 100644 --- a/kafka-ui-react-app/src/components/ConsumerGroups/Details/TopicContents/TopicContent.styled.ts +++ b/kafka-ui-react-app/src/components/ConsumerGroups/Details/TopicContents/TopicContent.styled.ts @@ -1,16 +1,17 @@ import styled, { css } from 'styled-components'; export const TopicContentWrapper = styled.tr` - background-color: ${({ theme }) => - theme.consumerTopicContent.backgroundColor}; + background-color: ${({ theme }) => theme.default.backgroundColor}; & > td { padding: 16px !important; + background-color: ${({ theme }) => + theme.consumerTopicContent.td.backgroundColor}; } `; export const ContentBox = styled.div( ({ theme }) => css` - background-color: ${theme.menu.backgroundColor.normal}; + background-color: ${theme.default.backgroundColor}; padding: 20px; border-radius: 8px; ` diff --git a/kafka-ui-react-app/src/components/Dashboard/Dashboard.styled.ts b/kafka-ui-react-app/src/components/Dashboard/Dashboard.styled.ts index a35424b1bb..6bdd80d4de 100644 --- a/kafka-ui-react-app/src/components/Dashboard/Dashboard.styled.ts +++ b/kafka-ui-react-app/src/components/Dashboard/Dashboard.styled.ts @@ -5,4 +5,5 @@ export const Toolbar = styled.div` display: flex; justify-content: space-between; align-items: center; + color: ${({ theme }) => theme.default.color.normal}; `; diff --git a/kafka-ui-react-app/src/components/ErrorPage/ErrorPage.styled.ts b/kafka-ui-react-app/src/components/ErrorPage/ErrorPage.styled.ts index e8f8a0339a..fc6e0332db 100644 --- a/kafka-ui-react-app/src/components/ErrorPage/ErrorPage.styled.ts +++ b/kafka-ui-react-app/src/components/ErrorPage/ErrorPage.styled.ts @@ -11,7 +11,7 @@ export const Wrapper = styled.div` export const Number = styled.div` font-size: 100px; - color: ${({ theme }) => theme.errorPage.text}; + color: ${({ theme }) => theme.default.color.normal}; line-height: initial; `; diff --git a/kafka-ui-react-app/src/components/KsqlDb/Query/QueryForm/QueryForm.styled.ts b/kafka-ui-react-app/src/components/KsqlDb/Query/QueryForm/QueryForm.styled.ts index 3fc59fcecf..b1066e481c 100644 --- a/kafka-ui-react-app/src/components/KsqlDb/Query/QueryForm/QueryForm.styled.ts +++ b/kafka-ui-react-app/src/components/KsqlDb/Query/QueryForm/QueryForm.styled.ts @@ -19,6 +19,7 @@ export const KSQLInputsWrapper = styled.div` export const KSQLInputHeader = styled.div` display: flex; justify-content: space-between; + color: ${({ theme }) => theme.default.color.normal}; `; export const KSQLButtons = styled.div` @@ -31,6 +32,7 @@ export const StreamPropertiesContainer = styled.label` flex-direction: column; gap: 10px; width: 50%; + color: ${({ theme }) => theme.default.color.normal}; `; export const InputsContainer = styled.div` @@ -49,9 +51,18 @@ export const StreamPropertiesInputWrapper = styled.div` width: 100%; height: 40px; border: 1px solid grey; + &:focus { + outline: none; + border-color: ${({ theme }) => theme.input.borderColor.focus}; + &::placeholder { + color: transparent; + } + } border-radius: 4px; font-size: 16px; padding-left: 15px; + background-color: ${({ theme }) => theme.input.backgroundColor.normal}; + color: ${({ theme }) => theme.input.color.normal}; } `; @@ -73,8 +84,28 @@ export const SQLEditor = styled(BaseSQLEditor)( css` background: ${readOnly && theme.ksqlDb.query.editor.readonly.background}; .ace-cursor { - ${readOnly && theme.ksqlDb.query.editor.readonly.cursor} + ${readOnly && `background: ${theme.default.transparentColor} `} } + + .ace_content { + background-color: ${theme.default.backgroundColor}; + color: ${theme.default.color.normal}; + } + .ace_line { + background-color: ${theme.ksqlDb.query.editor.activeLine + .backgroundColor}; + } + .ace_gutter-cell { + background-color: ${theme.ksqlDb.query.editor.cell.backgroundColor}; + } + .ace_gutter-layer { + background-color: ${theme.ksqlDb.query.editor.layer.backgroundColor}; + color: ${theme.default.color.normal}; + } + .ace_cursor { + color: ${theme.ksqlDb.query.editor.cursor}; + } + .ace_print-margin { display: none; } diff --git a/kafka-ui-react-app/src/components/KsqlDb/Query/QueryForm/QueryForm.tsx b/kafka-ui-react-app/src/components/KsqlDb/Query/QueryForm/QueryForm.tsx index 26622881f7..3530921088 100644 --- a/kafka-ui-react-app/src/components/KsqlDb/Query/QueryForm/QueryForm.tsx +++ b/kafka-ui-react-app/src/components/KsqlDb/Query/QueryForm/QueryForm.tsx @@ -146,6 +146,7 @@ const QueryForm: React.FC = ({ placeholder="Key" aria-label="key" type="text" + autoComplete="off" /> )} /> @@ -166,6 +167,7 @@ const QueryForm: React.FC = ({ placeholder="Value" aria-label="value" type="text" + autoComplete="off" /> )} /> diff --git a/kafka-ui-react-app/src/components/Nav/ClusterTab/ClusterTab.styled.ts b/kafka-ui-react-app/src/components/Nav/ClusterTab/ClusterTab.styled.ts index 9b61878bba..5ef2467889 100644 --- a/kafka-ui-react-app/src/components/Nav/ClusterTab/ClusterTab.styled.ts +++ b/kafka-ui-react-app/src/components/Nav/ClusterTab/ClusterTab.styled.ts @@ -36,6 +36,7 @@ export const Title = styled.div` max-width: 110px; overflow: hidden; text-overflow: ellipsis; + color: ${({ theme }) => theme.menu.titleColor}; `; export const StatusIconWrapper = styled.svg.attrs({ diff --git a/kafka-ui-react-app/src/components/Nav/ClusterTab/__tests__/ClusterTab.styled.spec.tsx b/kafka-ui-react-app/src/components/Nav/ClusterTab/__tests__/ClusterTab.styled.spec.tsx index 68ff3b5efe..c3bdf8b582 100644 --- a/kafka-ui-react-app/src/components/Nav/ClusterTab/__tests__/ClusterTab.styled.spec.tsx +++ b/kafka-ui-react-app/src/components/Nav/ClusterTab/__tests__/ClusterTab.styled.spec.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { render } from 'lib/testHelpers'; -import theme from 'theme/theme'; +import { theme } from 'theme/theme'; import { screen } from '@testing-library/react'; import * as S from 'components/Nav/ClusterTab/ClusterTab.styled'; import { ServerStatus } from 'generated-sources'; diff --git a/kafka-ui-react-app/src/components/NavBar/NavBar.styled.ts b/kafka-ui-react-app/src/components/NavBar/NavBar.styled.ts index a665468fce..8c4dd6f5b2 100644 --- a/kafka-ui-react-app/src/components/NavBar/NavBar.styled.ts +++ b/kafka-ui-react-app/src/components/NavBar/NavBar.styled.ts @@ -28,11 +28,11 @@ export const NavbarBrand = styled.div` `; export const SocialLink = styled.a( - ({ theme: { layout, icons } }) => css` + ({ theme: { icons } }) => css` display: block; margin-top: 5px; cursor: pointer; - fill: ${layout.socialLink.color}; + fill: ${icons.discord.normal}; &:hover { ${DiscordIcon} { @@ -60,7 +60,7 @@ export const NavbarSocial = styled.div` display: flex; align-items: center; gap: 10px; - margin: 10px; + margin: 5px 10px 5px; `; export const NavbarItem = styled.div` @@ -138,7 +138,10 @@ export const Hyperlink = styled(Link)( font-weight: bold; font-size: 12px; line-height: 16px; - color: ${theme.menu.color.active}; + color: ${theme.default.color.normal}; + &:hover { + color: ${theme.default.color.normal}; + } text-decoration: none; word-break: break-word; cursor: pointer; diff --git a/kafka-ui-react-app/src/components/NavBar/NavBar.tsx b/kafka-ui-react-app/src/components/NavBar/NavBar.tsx index 275e77f5e3..2e36350128 100644 --- a/kafka-ui-react-app/src/components/NavBar/NavBar.tsx +++ b/kafka-ui-react-app/src/components/NavBar/NavBar.tsx @@ -1,17 +1,92 @@ import React from 'react'; +import Select from 'components/common/Select/Select'; import Logo from 'components/common/Logo/Logo'; import Version from 'components/Version/Version'; import GitIcon from 'components/common/Icons/GitIcon'; import DiscordIcon from 'components/common/Icons/DiscordIcon'; +import AutoIcon from 'components/common/Icons/AutoIcon'; +import SunIcon from 'components/common/Icons/SunIcon'; +import MoonIcon from 'components/common/Icons/MoonIcon'; -import * as S from './NavBar.styled'; import UserInfo from './UserInfo/UserInfo'; +import * as S from './NavBar.styled'; interface Props { onBurgerClick: () => void; + setDarkMode: (value: boolean) => void; } -const NavBar: React.FC = ({ onBurgerClick }) => { +type ThemeDropDownValue = 'auto_theme' | 'light_theme' | 'dark_theme'; + +const options = [ + { + label: ( + <> + +
Auto theme
+ + ), + value: 'auto_theme', + }, + { + label: ( + <> + +
Light theme
+ + ), + value: 'light_theme', + }, + { + label: ( + <> + +
Dark theme
+ + ), + value: 'dark_theme', + }, +]; + +const NavBar: React.FC = ({ onBurgerClick, setDarkMode }) => { + const matchDark = window.matchMedia('(prefers-color-scheme: dark)'); + const [themeMode, setThemeMode] = React.useState(); + + React.useLayoutEffect(() => { + const mode = localStorage.getItem('mode'); + if (mode) { + setThemeMode(mode as ThemeDropDownValue); + if (mode === 'auto_theme') { + setDarkMode(matchDark.matches); + } else if (mode === 'light_theme') { + setDarkMode(false); + } else if (mode === 'dark_theme') { + setDarkMode(true); + } + } else { + setThemeMode('auto_theme'); + } + }, []); + + React.useEffect(() => { + if (themeMode === 'auto_theme') { + setDarkMode(matchDark.matches); + matchDark.addListener((e) => { + setDarkMode(e.matches); + }); + } + }, [matchDark, themeMode]); + + const onChangeThemeMode = (value: string | number) => { + setThemeMode(value as ThemeDropDownValue); + localStorage.setItem('mode', value as string); + if (value === 'light_theme') { + setDarkMode(false); + } else if (value === 'dark_theme') { + setDarkMode(true); + } + }; + return ( @@ -39,6 +114,12 @@ const NavBar: React.FC = ({ onBurgerClick }) => { +