From 205d8d000ded60f8443007a68c9cf70dd2abe413 Mon Sep 17 00:00:00 2001 From: Ekaterina Petrova <32833172+Hurenka@users.noreply.github.com> Date: Thu, 20 Jan 2022 16:41:20 +0300 Subject: [PATCH] Bugfix/select (#1397) * new select styles init * Custom select compound component * Select component fix styles * Added react hook form controller * Moved from compound component * fixed vslues & onChange for controller * fixed tests & code cleanup * fix review * fixed linter * fixed discussions Co-authored-by: Ekaterina Petrova --- .../__snapshots__/ListItem.spec.tsx.snap | 5 + .../src/components/Connect/New/New.tsx | 27 ++- .../ConsumerGroups/Details/Details.tsx | 4 +- .../Details/ResetOffsets/ResetOffsets.tsx | 55 +++-- .../__test__/ResetOffsets.spec.tsx | 7 +- .../Details/__tests__/Details.spec.tsx | 8 +- .../src/components/Schemas/Edit/Edit.tsx | 53 +++-- .../GlobalSchemaSelector.tsx | 24 +-- .../__test__/GlobalSchemaSelector.spec.tsx | 19 +- .../src/components/Schemas/New/New.tsx | 37 ++-- .../Messages/Filters/Filters.styled.ts | 4 - .../Details/Messages/Filters/Filters.tsx | 42 ++-- .../__snapshots__/Filters.spec.tsx.snap | 202 ++++++++++-------- .../__snapshots__/Details.spec.tsx.snap | 5 + .../Form/CustomParams/CustomParamField.tsx | 49 +++-- .../__tests__/CustomParamField.spec.tsx | 24 ++- .../__tests__/CustomParams.spec.tsx | 124 +++++------ .../Topics/shared/Form/TopicForm.tsx | 59 +++-- .../Form/{Form.styles.ts => Form.styled.ts} | 0 .../common/Select/LiveIcon.styled.tsx | 4 +- .../components/common/Select/Select.styled.ts | 74 ++++++- .../src/components/common/Select/Select.tsx | 112 ++++++---- .../__snapshots__/Select.spec.tsx.snap | 114 ++++++---- .../src/lib/hooks/useClickOutside.ts | 29 +++ kafka-ui-react-app/src/theme/theme.ts | 5 + 25 files changed, 674 insertions(+), 412 deletions(-) rename kafka-ui-react-app/src/components/common/Form/{Form.styles.ts => Form.styled.ts} (100%) create mode 100644 kafka-ui-react-app/src/lib/hooks/useClickOutside.ts diff --git a/kafka-ui-react-app/src/components/Connect/List/__tests__/__snapshots__/ListItem.spec.tsx.snap b/kafka-ui-react-app/src/components/Connect/List/__tests__/__snapshots__/ListItem.spec.tsx.snap index 6cd4d47769..90e15c1d01 100644 --- a/kafka-ui-react-app/src/components/Connect/List/__tests__/__snapshots__/ListItem.spec.tsx.snap +++ b/kafka-ui-react-app/src/components/Connect/List/__tests__/__snapshots__/ListItem.spec.tsx.snap @@ -227,6 +227,11 @@ exports[`Connectors ListItem matches snapshot 1`] = ` }, }, "selectStyles": Object { + "backgroundColor": Object { + "active": "#E3E6E8", + "hover": "#E3E6E8", + "normal": "#FFFFFF", + }, "borderColor": Object { "active": "#454F54", "disabled": "#E3E6E8", diff --git a/kafka-ui-react-app/src/components/Connect/New/New.tsx b/kafka-ui-react-app/src/components/Connect/New/New.tsx index 0e25e934cb..88b1efef59 100644 --- a/kafka-ui-react-app/src/components/Connect/New/New.tsx +++ b/kafka-ui-react-app/src/components/Connect/New/New.tsx @@ -112,6 +112,11 @@ const New: React.FC = ({ return null; } + const connectOptions = connects.map(({ name: connectName }) => ({ + value: connectName, + label: connectName, + })); + return ( @@ -121,13 +126,21 @@ const New: React.FC = ({ >
Connect * - + ( + - {uniqueTopics.map((topic) => ( - - ))} - + Topic + ( + - {Object.values(ConsumerGroupOffsetsResetType).map((type) => ( - - ))} - + Reset Type + ( + - {Object.keys(SchemaType).map((type: string) => ( - - ))} - + render={({ field: { name, onChange } }) => ( + - {Object.keys(CompatibilityLevelCompatibilityEnum).map( - (level: string) => ( - - ) + render={({ field: { name, onChange } }) => ( + + />
diff --git a/kafka-ui-react-app/src/components/Schemas/List/GlobalSchemaSelector/GlobalSchemaSelector.tsx b/kafka-ui-react-app/src/components/Schemas/List/GlobalSchemaSelector/GlobalSchemaSelector.tsx index 66edb6f046..9c5a7ab4e3 100644 --- a/kafka-ui-react-app/src/components/Schemas/List/GlobalSchemaSelector/GlobalSchemaSelector.tsx +++ b/kafka-ui-react-app/src/components/Schemas/List/GlobalSchemaSelector/GlobalSchemaSelector.tsx @@ -45,12 +45,8 @@ const GlobalSchemaSelector: React.FC = () => { fetchData(); }, []); - const handleChangeCompatibilityLevel = ( - event: React.ChangeEvent - ) => { - setNextCompatibilityLevel( - event.target.value as CompatibilityLevelCompatibilityEnum - ); + const handleChangeCompatibilityLevel = (level: string | number) => { + setNextCompatibilityLevel(level as CompatibilityLevelCompatibilityEnum); setIsConfirmationVisible(true); }; @@ -62,10 +58,10 @@ const GlobalSchemaSelector: React.FC = () => { clusterName, compatibilityLevel: { compatibility: nextCompatibilityLevel }, }); - dispatch(fetchSchemas(clusterName)); setCurrentCompatibilityLevel(nextCompatibilityLevel); setNextCompatibilityLevel(undefined); setIsConfirmationVisible(false); + dispatch(fetchSchemas(clusterName)); } catch (e) { const err = await getResponse(e as Response); dispatch(serverErrorAlertAdded(err)); @@ -81,18 +77,14 @@ const GlobalSchemaSelector: React.FC = () => {
Global Compatibility Level:
+ /> setIsConfirmationVisible(false)} diff --git a/kafka-ui-react-app/src/components/Schemas/List/GlobalSchemaSelector/__test__/GlobalSchemaSelector.spec.tsx b/kafka-ui-react-app/src/components/Schemas/List/GlobalSchemaSelector/__test__/GlobalSchemaSelector.spec.tsx index 0d8c6715c0..9e44931e00 100644 --- a/kafka-ui-react-app/src/components/Schemas/List/GlobalSchemaSelector/__test__/GlobalSchemaSelector.spec.tsx +++ b/kafka-ui-react-app/src/components/Schemas/List/GlobalSchemaSelector/__test__/GlobalSchemaSelector.spec.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { screen, waitFor } from '@testing-library/react'; +import { screen, waitFor, within } from '@testing-library/react'; import { render } from 'lib/testHelpers'; import { CompatibilityLevelCompatibilityEnum } from 'generated-sources'; import GlobalSchemaSelector from 'components/Schemas/List/GlobalSchemaSelector/GlobalSchemaSelector'; @@ -10,15 +10,20 @@ import fetchMock from 'fetch-mock'; const clusterName = 'testClusterName'; -const selectForwardOption = () => - userEvent.selectOptions( - screen.getByRole('listbox'), - CompatibilityLevelCompatibilityEnum.FORWARD +const selectForwardOption = () => { + const dropdownElement = screen.getByRole('listbox'); + // clicks to open dropdown + userEvent.click(within(dropdownElement).getByRole('option')); + userEvent.click( + screen.getByText(CompatibilityLevelCompatibilityEnum.FORWARD) ); +}; const expectOptionIsSelected = (option: string) => { - const optionElement: HTMLOptionElement = screen.getByText(option); - expect(optionElement.selected).toBeTruthy(); + const dropdownElement = screen.getByRole('listbox'); + const selectedOption = within(dropdownElement).getAllByRole('option'); + expect(selectedOption.length).toEqual(1); + expect(selectedOption[0]).toHaveTextContent(option); }; describe('GlobalSchemaSelector', () => { diff --git a/kafka-ui-react-app/src/components/Schemas/New/New.tsx b/kafka-ui-react-app/src/components/Schemas/New/New.tsx index 28ca79d247..db14356630 100644 --- a/kafka-ui-react-app/src/components/Schemas/New/New.tsx +++ b/kafka-ui-react-app/src/components/Schemas/New/New.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { NewSchemaSubjectRaw } from 'redux/interfaces'; -import { FormProvider, useForm } from 'react-hook-form'; +import { FormProvider, useForm, Controller } from 'react-hook-form'; import { ErrorMessage } from '@hookform/error-message'; import { clusterSchemaPath } from 'lib/paths'; import { SchemaType } from 'generated-sources'; @@ -9,7 +9,7 @@ import { useHistory, useParams } from 'react-router'; import { InputLabel } from 'components/common/Input/InputLabel.styled'; import Input from 'components/common/Input/Input'; import { FormError } from 'components/common/Input/Input.styled'; -import Select from 'components/common/Select/Select'; +import Select, { SelectOption } from 'components/common/Select/Select'; import { Button } from 'components/common/Button/Button'; import { Textarea } from 'components/common/Textbox/Textarea.styled'; import PageHeading from 'components/common/PageHeading/PageHeading'; @@ -23,6 +23,12 @@ import { getResponse } from 'lib/errorHandling'; import * as S from './New.styled'; +const SchemaTypeOptions: Array = [ + { value: SchemaType.AVRO, label: 'AVRO' }, + { value: SchemaType.JSON, label: 'JSON' }, + { value: SchemaType.PROTOBUF, label: 'PROTOBUF' }, +]; + const New: React.FC = () => { const { clusterName } = useParams<{ clusterName: string }>(); const history = useHistory(); @@ -31,6 +37,7 @@ const New: React.FC = () => { const { register, handleSubmit, + control, formState: { isDirty, isSubmitting, errors }, } = methods; @@ -91,18 +98,22 @@ const New: React.FC = () => {
Schema Type * - + render={({ field: { name, onChange } }) => ( + - setSeekType(value as SeekType) - } - value={seekType} + onChange={(option) => setCurrentSeekType(option as SeekType)} + value={currentSeekType} selectSize="M" - > - - - - {seekType === SeekType.OFFSET ? ( + minWidth="100px" + options={SeekTypeOptions} + /> + {currentSeekType === SeekType.OFFSET ? ( = ({ + options={SeekDirectionOptions} + />

{isFetching && phaseMessage}

diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/__tests__/__snapshots__/Filters.spec.tsx.snap b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/__tests__/__snapshots__/Filters.spec.tsx.snap index 97693628fb..0955c7c852 100644 --- a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/__tests__/__snapshots__/Filters.spec.tsx.snap +++ b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/__tests__/__snapshots__/Filters.spec.tsx.snap @@ -181,48 +181,69 @@ exports[`Filters component matches the snapshot 1`] = ` position: relative; } -.c7 { +.c6 { + position: relative; + list-style: none; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; height: 32px; border: 1px #ABB5BA solid; border-radius: 4px; font-size: 14px; - width: 100%; + width: -webkit-fit-content; + width: -moz-fit-content; + width: fit-content; padding-left: 12px; padding-right: 16px; color: #171A1C; - min-width: auto; + min-width: 100px; background-image: url('data:image/svg+xml,%3Csvg width="10" height="6" viewBox="0 0 10 6" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M1 1L5 5L9 1" stroke="%23454F54"/%3E%3C/svg%3E%0A') !important; background-repeat: no-repeat !important; background-position-x: calc(100% - 8px) !important; background-position-y: 55% !important; - -webkit-appearance: none !important; - -moz-appearance: none !important; - appearance: none !important; } -.c7:hover { +.c6:hover { color: #171A1C; border-color: #73848C; } -.c7:focus { +.c6:focus { outline: none; color: #171A1C; border-color: #454F54; } -.c7:disabled { +.c6:disabled { color: #ABB5BA; border-color: #E3E6E8; cursor: not-allowed; } .c11 { + position: relative; + list-style: none; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; height: 32px; border: 1px #ABB5BA solid; border-radius: 4px; font-size: 14px; - width: 100%; + width: -webkit-fit-content; + width: -moz-fit-content; + width: fit-content; padding-left: 12px; padding-right: 16px; color: #171A1C; @@ -231,9 +252,6 @@ exports[`Filters component matches the snapshot 1`] = ` background-repeat: no-repeat !important; background-position-x: calc(100% - 8px) !important; background-position-y: 55% !important; - -webkit-appearance: none !important; - -moz-appearance: none !important; - appearance: none !important; } .c11:hover { @@ -253,8 +271,12 @@ exports[`Filters component matches the snapshot 1`] = ` cursor: not-allowed; } -.c6 { - position: relative; +.c7 { + padding-right: 16px; + list-style-position: inside; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .c10 { @@ -332,10 +354,6 @@ exports[`Filters component matches the snapshot 1`] = ` padding-top: 16px; } -.c0 > div:first-child > div:last-child { - width: 10%; -} - .c1 { display: -webkit-box; display: -webkit-flex; @@ -458,25 +476,19 @@ exports[`Filters component matches the snapshot 1`] = `
-
- + +
-
- + +
div:first-child > div:last-child { - width: 10%; -} - .c1 { display: -webkit-box; display: -webkit-flex; @@ -1094,25 +1119,19 @@ exports[`Filters component when fetching matches the snapshot 1`] = `
-
- + +
-
- + +
= ({ formState: { errors }, setValue, watch, + control, } = useFormContext(); const nameValue = watch(`customParams.${index}.name`); const prevName = useRef(nameValue); @@ -49,7 +50,9 @@ const CustomParamField: React.FC = ({ prevName.current = nameValue; newExistingFields.push(nameValue); setExistingFields(newExistingFields); - setValue(`customParams.${index}.value`, TOPIC_CUSTOM_PARAMS[nameValue]); + setValue(`customParams.${index}.value`, TOPIC_CUSTOM_PARAMS[nameValue], { + shouldValidate: true, + }); } }, [nameValue]); @@ -58,27 +61,27 @@ const CustomParamField: React.FC = ({ <>
Custom Parameter - + ( + - - - - + ( + - - - - - - + ( + + > +
  • +
  • `; exports[`Custom Select when non-live matches the snapshot 1`] = ` -.c1 { +.c0 { + position: relative; + list-style: none; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; height: 40px; border: 1px #ABB5BA solid; border-radius: 4px; font-size: 14px; - width: 100%; + width: -webkit-fit-content; + width: -moz-fit-content; + width: fit-content; padding-left: 12px; padding-right: 16px; color: #171A1C; @@ -104,41 +122,47 @@ exports[`Custom Select when non-live matches the snapshot 1`] = ` background-repeat: no-repeat !important; background-position-x: calc(100% - 8px) !important; background-position-y: 55% !important; - -webkit-appearance: none !important; - -moz-appearance: none !important; - appearance: none !important; } -.c1:hover { +.c0:hover { color: #171A1C; border-color: #73848C; } -.c1:focus { +.c0:focus { outline: none; color: #171A1C; border-color: #454F54; } -.c1:disabled { +.c0:disabled { color: #ABB5BA; border-color: #E3E6E8; cursor: not-allowed; } -.c0 { - position: relative; +.c1 { + padding-right: 16px; + list-style-position: inside; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; }
    -
    -