Przeglądaj źródła

[FE] SR: Display a warning in case of invalid syntax (#2599)

* No warning about filling the invalid data in case of editing the Schema / Producing the Message

* fixed test errors

* pull master

* fixed test problems

* use isJsonObject for validation

* fixed protobuf format bug

* fix setNewSchemaValue()

* test commit

* fix BaseTest

* upd global

* upd global

* upd global

* add local browser VM option

* fix TopicsList column header locator

* fix withStartupTimeout()

* switch e2e to TestNG

* upd pom

* upd page classes

* upd -pl kafka-ui-e2e-checks

* test commit

* Revert "test commit"

This reverts commit 4b505321ac5e164986a7a1886ac40c6744b8ecb1.

* fix workflow module

* upd test -f 'kafka-ui-e2e-checks'

* crt firstCase

* upd QaseUtils

* add -Dsuite

* add -Dsuite

* add -Dsuite

* add -Dsuite

* add isSuiteEnabled

* add isSuiteEnabled

* upd workflow

* upd readMe

* upd readMe

* upd readMe

* upd qaseSetup

* upd qaseSetup

* add schedule

* add schedule

* upd suites

* upd suites

* upd suites

* upd json input

* upd onTestStart

* Revert "fix setNewSchemaValue()"

This reverts commit 67d12d113409769ebe52c4decc4bc3b842fe4c9c.

* resolve conflicts

* upd localWebDriver

* added error message

* added ability to check Valid Enum

* swapped key Serde and Value Serde

* replace 'e' with 'enum', also added test cases

---------

Co-authored-by: VladSenyuta <vlad.senyuta@gmail.com>
Co-authored-by: Vlad Senyuta <66071557+VladSenyuta@users.noreply.github.com>
Co-authored-by: davitbejanyan <dbejanyan@provectus.com>
Co-authored-by: David <58771979+David-DB88@users.noreply.github.com>
Co-authored-by: Roman Zabaluev <rzabaluev@provectus.com>
Hrant Abrahamyan 2 lat temu
rodzic
commit
94da2f4e7f

+ 17 - 3
kafka-ui-react-app/src/components/Schemas/Edit/Form.tsx

@@ -10,6 +10,7 @@ import {
   clusterSchemasPath,
   ClusterSubjectParam,
 } from 'lib/paths';
+import yup from 'lib/yupExtended';
 import { NewSchemaSubjectRaw } from 'redux/interfaces';
 import Editor from 'components/common/Editor/Editor';
 import Select from 'components/common/Select/Select';
@@ -28,6 +29,9 @@ import {
 import PageLoader from 'components/common/PageLoader/PageLoader';
 import { schemasApiClient } from 'lib/api';
 import { showServerError } from 'lib/errorHandling';
+import { yupResolver } from '@hookform/resolvers/yup';
+import { FormError } from 'components/common/Input/Input.styled';
+import { ErrorMessage } from '@hookform/error-message';
 
 import * as S from './Edit.styled';
 
@@ -47,8 +51,16 @@ const Form: React.FC = () => {
       : JSON.stringify(JSON.parse(schema?.schema || '{}'), null, '\t');
   }, [schema]);
 
+  const validationSchema = () =>
+    yup.object().shape({
+      newSchema:
+        schema?.schemaType === SchemaType.PROTOBUF
+          ? yup.string().required().isEnum('Schema syntax is not valid')
+          : yup.string().required().isJsonObject('Schema syntax is not valid'),
+    });
   const methods = useForm<NewSchemaSubjectRaw>({
     mode: 'onChange',
+    resolver: yupResolver(validationSchema()),
     defaultValues: {
       schemaType: schema?.schemaType,
       compatibilityLevel:
@@ -58,11 +70,10 @@ const Form: React.FC = () => {
   });
 
   const {
-    formState: { isDirty, isSubmitting, dirtyFields },
+    formState: { isDirty, isSubmitting, dirtyFields, errors },
     control,
     handleSubmit,
   } = methods;
-
   const onSubmit = async (props: NewSchemaSubjectRaw) => {
     if (!schema) return;
 
@@ -191,11 +202,14 @@ const Form: React.FC = () => {
                   )}
                 />
               </S.EditorContainer>
+              <FormError>
+                <ErrorMessage errors={errors} name="newSchema" />
+              </FormError>
               <Button
                 buttonType="primary"
                 buttonSize="M"
                 type="submit"
-                disabled={!isDirty || isSubmitting}
+                disabled={!isDirty || isSubmitting || !!errors.newSchema}
               >
                 Submit
               </Button>

+ 32 - 1
kafka-ui-react-app/src/lib/__test__/yupExtended.spec.ts

@@ -1,5 +1,19 @@
-import { isValidJsonObject } from 'lib/yupExtended';
+import { isValidEnum, isValidJsonObject } from 'lib/yupExtended';
 
+const invalidEnum = `
+ennum SchemType {
+  AVRO = 0;
+  JSON = 1;
+  PROTOBUF = 3;
+}
+`;
+const validEnum = `
+enum SchemType {
+  AVRO = 0;
+  JSON = 1;
+  PROTOBUF = 3;
+}
+`;
 describe('yup extended', () => {
   describe('isValidJsonObject', () => {
     it('returns false for no value', () => {
@@ -21,4 +35,21 @@ describe('yup extended', () => {
       expect(isValidJsonObject('{ "foo": "bar" }')).toBeTruthy();
     });
   });
+
+  describe('isValidEnum', () => {
+    it('returns false for invalid enum', () => {
+      expect(isValidEnum(invalidEnum)).toBeFalsy();
+    });
+    it('returns false for no value', () => {
+      expect(isValidEnum()).toBeFalsy();
+    });
+    it('returns true should trim value', () => {
+      expect(
+        isValidEnum(`  enum SchemType {AVRO = 0; PROTOBUF = 3;}   `)
+      ).toBeTruthy();
+    });
+    it('returns true for valid enum', () => {
+      expect(isValidEnum(validEnum)).toBeTruthy();
+    });
+  });
 });

+ 30 - 3
kafka-ui-react-app/src/lib/yupExtended.ts

@@ -9,7 +9,8 @@ declare module 'yup' {
     TDefault = undefined,
     TFlags extends yup.Flags = ''
   > extends yup.Schema<TType, TContext, TDefault, TFlags> {
-    isJsonObject(): StringSchema<TType, TContext>;
+    isJsonObject(message?: string): StringSchema<TType, TContext>;
+    isEnum(message?: string): StringSchema<TType, TContext>;
   }
 }
 
@@ -31,15 +32,40 @@ export const isValidJsonObject = (value?: string) => {
   return false;
 };
 
-const isJsonObject = () => {
+const isJsonObject = (message?: string) => {
   return yup.string().test(
     'isJsonObject',
     // eslint-disable-next-line no-template-curly-in-string
-    '${path} is not JSON object',
+    message || '${path} is not JSON object',
     isValidJsonObject
   );
 };
 
+export const isValidEnum = (value?: string) => {
+  try {
+    if (!value) return false;
+    const trimmedValue = value.trim();
+    if (
+      trimmedValue.indexOf('enum') === 0 &&
+      trimmedValue.lastIndexOf('}') === trimmedValue.length - 1
+    ) {
+      return true;
+    }
+  } catch {
+    // do nothing
+  }
+  return false;
+};
+
+const isEnum = (message?: string) => {
+  return yup.string().test(
+    'isEnum',
+    // eslint-disable-next-line no-template-curly-in-string
+    message || '${path} is not Enum object',
+    isValidEnum
+  );
+};
+
 /**
  * due to yup rerunning all the object validiation during any render,
  * it makes sense to cache the async results
@@ -62,6 +88,7 @@ export function cacheTest(
 }
 
 yup.addMethod(yup.StringSchema, 'isJsonObject', isJsonObject);
+yup.addMethod(yup.StringSchema, 'isEnum', isEnum);
 
 export const topicFormValidationSchema = yup.object().shape({
   name: yup