diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.styled.ts b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.styled.ts index 5d9810aba2..528b5f0720 100644 --- a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.styled.ts +++ b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.styled.ts @@ -1,5 +1,13 @@ import styled from 'styled-components'; +interface MessageLoadingProps { + isLive: boolean; +} + +interface MessageLoadingSpinnerProps { + isFetching: boolean; +} + export const FiltersWrapper = styled.div` display: flex; flex-direction: column; @@ -83,3 +91,36 @@ export const MetricsIcon = styled.div` padding-right: 6px; height: 12px; `; + +export const MessageLoading = styled.div` + color: ${({ theme }) => theme.heading.h3.color}; + font-size: ${({ theme }) => theme.heading.h3.fontSize}; + display: ${(props) => (props.isLive ? 'flex' : 'none')}; + justify-content: space-around; + width: 250px; +`; + +export const StopLoading = styled.div` + color: ${({ theme }) => theme.pageLoader.borderColor}; + font-size: ${({ theme }) => theme.heading.h3.fontSize}; + cursor: pointer; +`; + +export const MessageLoadingSpinner = styled.div` + display: ${(props) => (props.isFetching ? 'block' : 'none')}; + border: 3px solid ${({ theme }) => theme.pageLoader.borderColor}; + border-bottom: 3px solid ${({ theme }) => theme.pageLoader.borderBottomColor}; + border-radius: 50%; + width: 20px; + height: 20px; + animation: spin 1.3s linear infinite; + + @keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } + } +`; diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.tsx index 2dba1028f6..d730800950 100644 --- a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.tsx +++ b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.tsx @@ -53,8 +53,9 @@ const SeekTypeOptions = [ { value: SeekType.TIMESTAMP, label: 'Timestamp' }, ]; const SeekDirectionOptions = [ - { value: SeekDirection.FORWARD, label: 'Oldest First' }, - { value: SeekDirection.BACKWARD, label: 'Newest First' }, + { value: SeekDirection.FORWARD, label: 'Oldest First', isLive: false }, + { value: SeekDirection.BACKWARD, label: 'Newest First', isLive: false }, + { value: SeekDirection.TAILING, label: 'Live Mode', isLive: true }, ]; const Filters: React.FC = ({ @@ -100,7 +101,6 @@ const Filters: React.FC = ({ (searchParams.get('seekDirection') as SeekDirection) || SeekDirection.FORWARD ); - const isSeekTypeControlVisible = React.useMemo( () => selectedPartitions.length > 0, [selectedPartitions] @@ -167,14 +167,21 @@ const Filters: React.FC = ({ search: `?${qs}`, }); // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [seekDirection]); const toggleSeekDirection = (val: string) => { - const nextSeekDirectionValue = - val === SeekDirection.FORWARD - ? SeekDirection.FORWARD - : SeekDirection.BACKWARD; - setSeekDirection(nextSeekDirectionValue); + switch (val) { + case SeekDirection.FORWARD: + setSeekDirection(SeekDirection.FORWARD); + break; + case SeekDirection.BACKWARD: + setSeekDirection(SeekDirection.BACKWARD); + break; + case SeekDirection.TAILING: + setSeekDirection(SeekDirection.TAILING); + break; + default: + } }; const handleSSECancel = () => { @@ -228,6 +235,7 @@ const Filters: React.FC = ({ }, [ clusterName, topicName, + seekDirection, location, setIsFetching, resetMessages, @@ -268,6 +276,7 @@ const Filters: React.FC = ({ selectSize="M" minWidth="100px" options={SeekTypeOptions} + disabled={seekDirection === SeekDirection.TAILING} /> {currentSeekType === SeekType.OFFSET ? ( = ({ inputSize="M" value={offset} className="offset-selector" + placeholder="Offset" onChange={({ target: { value } }) => setOffset(value)} + disabled={seekDirection === SeekDirection.TAILING} /> ) : ( = ({ dateFormat="MMMM d, yyyy HH:mm" className="date-picker" placeholderText="Select timestamp" + disabled={seekDirection === SeekDirection.TAILING} /> )} @@ -331,10 +343,27 @@ const Filters: React.FC = ({ value={seekDirection} minWidth="120px" options={SeekDirectionOptions} + isLive={seekDirection === SeekDirection.TAILING} /> -

{isFetching && phaseMessage}

+

+ {seekDirection !== SeekDirection.TAILING && + isFetching && + phaseMessage} +

+ + + Loading messages. + { + setSeekDirection(SeekDirection.FORWARD); + setIsFetching(false); + }} + > + Stop loading + + diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/__tests__/Filters.spec.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/__tests__/Filters.spec.tsx index d428eeaadb..2c7a3ca662 100644 --- a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/__tests__/Filters.spec.tsx +++ b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/__tests__/Filters.spec.tsx @@ -3,31 +3,103 @@ import Filters, { FiltersProps, } from 'components/Topics/Topic/Details/Messages/Filters/Filters'; import { render } from 'lib/testHelpers'; +import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; -const setupWrapper = (props?: Partial) => ( - -); +const setupWrapper = (props?: Partial) => + render( + + ); describe('Filters component', () => { - it('matches the snapshot', () => { - const component = render(setupWrapper()); - expect(component.baseElement).toMatchSnapshot(); + it('renders component', () => { + setupWrapper(); }); describe('when fetching', () => { - it('matches the snapshot', () => { - const component = render(setupWrapper({ isFetching: true })); - expect(component.baseElement).toMatchSnapshot(); + it('shows cancel button while fetching', () => { + setupWrapper({ isFetching: true }); + expect(screen.getByText('Cancel')).toBeInTheDocument(); + }); + }); + describe('when fetching is over', () => { + it('shows submit button while fetching is over', () => { + setupWrapper(); + expect(screen.getByText('Submit')).toBeInTheDocument(); + }); + }); + describe('Input elements', () => { + it('search input', () => { + setupWrapper(); + const SearchInput = screen.getByPlaceholderText('Search'); + expect(SearchInput).toBeInTheDocument(); + expect(SearchInput).toHaveValue(''); + userEvent.type(SearchInput, 'Hello World!'); + expect(SearchInput).toHaveValue('Hello World!'); + }); + it('offset input', () => { + setupWrapper(); + const OffsetInput = screen.getByPlaceholderText('Offset'); + expect(OffsetInput).toBeInTheDocument(); + expect(OffsetInput).toHaveValue(''); + userEvent.type(OffsetInput, 'Hello World!'); + expect(OffsetInput).toHaveValue('Hello World!'); + }); + it('timestamp input', () => { + setupWrapper(); + const seekTypeSelect = screen.getAllByRole('listbox'); + const option = screen.getAllByRole('option'); + userEvent.click(seekTypeSelect[0]); + userEvent.selectOptions(seekTypeSelect[0], ['Timestamp']); + expect(option[0]).toHaveTextContent('Timestamp'); + const TimestampInput = screen.getByPlaceholderText('Select timestamp'); + expect(TimestampInput).toBeInTheDocument(); + expect(TimestampInput).toHaveValue(''); + userEvent.type(TimestampInput, 'Hello World!'); + expect(TimestampInput).toHaveValue('Hello World!'); + expect(screen.getByText('Submit')).toBeInTheDocument(); + }); + }); + describe('Select elements', () => { + it('seekType select', () => { + setupWrapper(); + const seekTypeSelect = screen.getAllByRole('listbox'); + const option = screen.getAllByRole('option'); + expect(option[0]).toHaveTextContent('Offset'); + userEvent.click(seekTypeSelect[0]); + userEvent.selectOptions(seekTypeSelect[0], ['Timestamp']); + expect(option[0]).toHaveTextContent('Timestamp'); + expect(screen.getByText('Submit')).toBeInTheDocument(); + }); + it('seekDirection select', () => { + setupWrapper(); + const seekDirectionSelect = screen.getAllByRole('listbox'); + const option = screen.getAllByRole('option'); + userEvent.click(seekDirectionSelect[1]); + userEvent.selectOptions(seekDirectionSelect[1], ['Newest First']); + expect(option[1]).toHaveTextContent('Newest First'); + }); + }); + + describe('when live mode is active', () => { + it('stop loading', () => { + setupWrapper(); + const StopLoading = screen.getByText('Stop loading'); + expect(StopLoading).toBeInTheDocument(); + userEvent.click(StopLoading); + const option = screen.getAllByRole('option'); + expect(option[1]).toHaveTextContent('Oldest First'); + expect(screen.getByText('Submit')).toBeInTheDocument(); }); }); }); 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 deleted file mode 100644 index 20a4a48c71..0000000000 --- a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/__tests__/__snapshots__/Filters.spec.tsx.snap +++ /dev/null @@ -1,1289 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Filters component matches the snapshot 1`] = ` -.c9 { - min-width: 200px; - height: 32px; - font-size: 14px; -} - -.c9 > .dropdown-container { - height: 32px; -} - -.c9 > .dropdown-container > .dropdown-heading { - height: 32px; -} - -.c3 { - position: absolute; - top: 50%; - line-height: 0; - z-index: 1; - left: 12px; - right: unset; - height: 11px; - width: 11px; - color: #454F54; -} - -.c4 { - border: 1px #ABB5BA solid; - border-radius: 4px; - height: 32px; - width: 100%; - padding-left: 36px; - font-size: 14px; -} - -.c4::-webkit-input-placeholder { - color: #ABB5BA; - font-size: 14px; -} - -.c4::-moz-placeholder { - color: #ABB5BA; - font-size: 14px; -} - -.c4:-ms-input-placeholder { - color: #ABB5BA; - font-size: 14px; -} - -.c4::placeholder { - color: #ABB5BA; - font-size: 14px; -} - -.c4:hover { - border-color: #73848C; -} - -.c4:focus { - outline: none; - border-color: #454F54; -} - -.c4:focus::-webkit-input-placeholder { - color: transparent; -} - -.c4:focus::-moz-placeholder { - color: transparent; -} - -.c4:focus:-ms-input-placeholder { - color: transparent; -} - -.c4:focus::placeholder { - color: transparent; -} - -.c4:disabled { - color: #ABB5BA; - border-color: #E3E6E8; - cursor: not-allowed; -} - -.c4:read-only { - color: #171A1C; - border: none; - background-color: #F1F2F3; - cursor: not-allowed; -} - -.c4:-moz-read-only:focus::placeholder { - color: #ABB5BA; -} - -.c4:read-only:focus::placeholder { - color: #ABB5BA; -} - -.c8 { - border: 1px #ABB5BA solid; - border-radius: 4px; - height: 32px; - width: 100%; - padding-left: 12px; - font-size: 14px; -} - -.c8::-webkit-input-placeholder { - color: #ABB5BA; - font-size: 14px; -} - -.c8::-moz-placeholder { - color: #ABB5BA; - font-size: 14px; -} - -.c8:-ms-input-placeholder { - color: #ABB5BA; - font-size: 14px; -} - -.c8::placeholder { - color: #ABB5BA; - font-size: 14px; -} - -.c8:hover { - border-color: #73848C; -} - -.c8:focus { - outline: none; - border-color: #454F54; -} - -.c8:focus::-webkit-input-placeholder { - color: transparent; -} - -.c8:focus::-moz-placeholder { - color: transparent; -} - -.c8:focus:-ms-input-placeholder { - color: transparent; -} - -.c8:focus::placeholder { - color: transparent; -} - -.c8:disabled { - color: #ABB5BA; - border-color: #E3E6E8; - cursor: not-allowed; -} - -.c8:read-only { - color: #171A1C; - border: none; - background-color: #F1F2F3; - cursor: not-allowed; -} - -.c8:-moz-read-only:focus::placeholder { - color: #ABB5BA; -} - -.c8:read-only:focus::placeholder { - color: #ABB5BA; -} - -.c2 { - position: relative; -} - -.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: -webkit-fit-content; - width: -moz-fit-content; - width: fit-content; - padding-left: 12px; - padding-right: 16px; - color: #171A1C; - 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; -} - -.c6:hover { - color: #171A1C; - border-color: #73848C; -} - -.c6:focus { - outline: none; - color: #171A1C; - border-color: #454F54; -} - -.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: -webkit-fit-content; - width: -moz-fit-content; - width: fit-content; - padding-left: 12px; - padding-right: 16px; - color: #171A1C; - min-width: 120px; - 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; -} - -.c11:hover { - color: #171A1C; - border-color: #73848C; -} - -.c11:focus { - outline: none; - color: #171A1C; - border-color: #454F54; -} - -.c11:disabled { - color: #ABB5BA; - border-color: #E3E6E8; - cursor: not-allowed; -} - -.c7 { - padding-right: 16px; - list-style-position: inside; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.c10 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-direction: row; - -ms-flex-direction: row; - flex-direction: row; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - padding: 0px 12px; - border: none; - border-radius: 4px; - white-space: nowrap; - background: #F1F2F3; - color: #171A1C; - font-size: 14px; - font-weight: 500; - height: 32px; -} - -.c10:hover:enabled { - background: #E3E6E8; - color: #171A1C; - cursor: pointer; -} - -.c10:active:enabled { - background: #D5DADD; - color: #171A1C; -} - -.c10:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.c10 a { - color: #FFFFFF; -} - -.c10 i { - margin-right: 7px; -} - -.c0 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - padding-left: 16px; - padding-right: 16px; -} - -.c0 > div:first-child { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-pack: justify; - -webkit-justify-content: space-between; - -ms-flex-pack: justify; - justify-content: space-between; - padding-top: 16px; -} - -.c1 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - gap: 8px; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - width: 90%; -} - -.c1 > div:first-child { - width: 25%; -} - -.c5 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; -} - -.c5 .select-wrapper { - width: 40% !important; -} - -.c5 .select-wrapper > select { - border-radius: 4px 0 0 4px !important; -} - -.c5 .offset-selector { - border-radius: 0 4px 4px 0 !important; - border-left: none; -} - -.c5 .date-picker { - height: 32px; - border: 1px #ABB5BA solid; - border-left: none; - border-radius: 0 4px 4px 0; - font-size: 14px; - width: 100%; - padding-left: 12px; - color: #171A1C; - 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: 96% !important; - background-position-y: 55% !important; - -webkit-appearance: none !important; - -moz-appearance: none !important; - appearance: none !important; -} - -.c5 .date-picker:hover { - cursor: pointer; -} - -.c5 .date-picker:focus { - outline: none; -} - -.c12 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-pack: end; - -webkit-justify-content: flex-end; - -ms-flex-pack: end; - justify-content: flex-end; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - gap: 22px; - padding-top: 16px; - padding-bottom: 16px; -} - -.c13 { - color: #73848C; - font-size: 12px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; -} - -.c14 { - color: #171A1C; - padding-right: 6px; - height: 12px; -} - - -
-
-
-
-
- - -
-
-
-
    -
  • - Offset -
  • -
-
-
- -
-
-
- -
- -
-
-
    -
  • - Oldest First -
  • -
-
-
-
-

-

-
- -
- - 0 - ms - -
-
-
- -
- - 0Bytes - -
-
-
- -
- - messages - -
-
-
-
- -`; - -exports[`Filters component when fetching matches the snapshot 1`] = ` - - .c9 { - min-width: 200px; - height: 32px; - font-size: 14px; -} - -.c9 > .dropdown-container { - height: 32px; -} - -.c9 > .dropdown-container > .dropdown-heading { - height: 32px; -} - -.c3 { - position: absolute; - top: 50%; - line-height: 0; - z-index: 1; - left: 12px; - right: unset; - height: 11px; - width: 11px; - color: #454F54; -} - -.c4 { - border: 1px #ABB5BA solid; - border-radius: 4px; - height: 32px; - width: 100%; - padding-left: 36px; - font-size: 14px; -} - -.c4::-webkit-input-placeholder { - color: #ABB5BA; - font-size: 14px; -} - -.c4::-moz-placeholder { - color: #ABB5BA; - font-size: 14px; -} - -.c4:-ms-input-placeholder { - color: #ABB5BA; - font-size: 14px; -} - -.c4::placeholder { - color: #ABB5BA; - font-size: 14px; -} - -.c4:hover { - border-color: #73848C; -} - -.c4:focus { - outline: none; - border-color: #454F54; -} - -.c4:focus::-webkit-input-placeholder { - color: transparent; -} - -.c4:focus::-moz-placeholder { - color: transparent; -} - -.c4:focus:-ms-input-placeholder { - color: transparent; -} - -.c4:focus::placeholder { - color: transparent; -} - -.c4:disabled { - color: #ABB5BA; - border-color: #E3E6E8; - cursor: not-allowed; -} - -.c4:read-only { - color: #171A1C; - border: none; - background-color: #F1F2F3; - cursor: not-allowed; -} - -.c4:-moz-read-only:focus::placeholder { - color: #ABB5BA; -} - -.c4:read-only:focus::placeholder { - color: #ABB5BA; -} - -.c8 { - border: 1px #ABB5BA solid; - border-radius: 4px; - height: 32px; - width: 100%; - padding-left: 12px; - font-size: 14px; -} - -.c8::-webkit-input-placeholder { - color: #ABB5BA; - font-size: 14px; -} - -.c8::-moz-placeholder { - color: #ABB5BA; - font-size: 14px; -} - -.c8:-ms-input-placeholder { - color: #ABB5BA; - font-size: 14px; -} - -.c8::placeholder { - color: #ABB5BA; - font-size: 14px; -} - -.c8:hover { - border-color: #73848C; -} - -.c8:focus { - outline: none; - border-color: #454F54; -} - -.c8:focus::-webkit-input-placeholder { - color: transparent; -} - -.c8:focus::-moz-placeholder { - color: transparent; -} - -.c8:focus:-ms-input-placeholder { - color: transparent; -} - -.c8:focus::placeholder { - color: transparent; -} - -.c8:disabled { - color: #ABB5BA; - border-color: #E3E6E8; - cursor: not-allowed; -} - -.c8:read-only { - color: #171A1C; - border: none; - background-color: #F1F2F3; - cursor: not-allowed; -} - -.c8:-moz-read-only:focus::placeholder { - color: #ABB5BA; -} - -.c8:read-only:focus::placeholder { - color: #ABB5BA; -} - -.c2 { - position: relative; -} - -.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: -webkit-fit-content; - width: -moz-fit-content; - width: fit-content; - padding-left: 12px; - padding-right: 16px; - color: #171A1C; - 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; -} - -.c6:hover { - color: #171A1C; - border-color: #73848C; -} - -.c6:focus { - outline: none; - color: #171A1C; - border-color: #454F54; -} - -.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: -webkit-fit-content; - width: -moz-fit-content; - width: fit-content; - padding-left: 12px; - padding-right: 16px; - color: #171A1C; - min-width: 120px; - 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; -} - -.c11:hover { - color: #171A1C; - border-color: #73848C; -} - -.c11:focus { - outline: none; - color: #171A1C; - border-color: #454F54; -} - -.c11:disabled { - color: #ABB5BA; - border-color: #E3E6E8; - cursor: not-allowed; -} - -.c7 { - padding-right: 16px; - list-style-position: inside; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.c10 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-direction: row; - -ms-flex-direction: row; - flex-direction: row; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - padding: 0px 12px; - border: none; - border-radius: 4px; - white-space: nowrap; - background: #F1F2F3; - color: #171A1C; - font-size: 14px; - font-weight: 500; - height: 32px; -} - -.c10:hover:enabled { - background: #E3E6E8; - color: #171A1C; - cursor: pointer; -} - -.c10:active:enabled { - background: #D5DADD; - color: #171A1C; -} - -.c10:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.c10 a { - color: #FFFFFF; -} - -.c10 i { - margin-right: 7px; -} - -.c0 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; - padding-left: 16px; - padding-right: 16px; -} - -.c0 > div:first-child { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-pack: justify; - -webkit-justify-content: space-between; - -ms-flex-pack: justify; - justify-content: space-between; - padding-top: 16px; -} - -.c1 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - gap: 8px; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - width: 90%; -} - -.c1 > div:first-child { - width: 25%; -} - -.c5 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; -} - -.c5 .select-wrapper { - width: 40% !important; -} - -.c5 .select-wrapper > select { - border-radius: 4px 0 0 4px !important; -} - -.c5 .offset-selector { - border-radius: 0 4px 4px 0 !important; - border-left: none; -} - -.c5 .date-picker { - height: 32px; - border: 1px #ABB5BA solid; - border-left: none; - border-radius: 0 4px 4px 0; - font-size: 14px; - width: 100%; - padding-left: 12px; - color: #171A1C; - 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: 96% !important; - background-position-y: 55% !important; - -webkit-appearance: none !important; - -moz-appearance: none !important; - appearance: none !important; -} - -.c5 .date-picker:hover { - cursor: pointer; -} - -.c5 .date-picker:focus { - outline: none; -} - -.c12 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-pack: end; - -webkit-justify-content: flex-end; - -ms-flex-pack: end; - justify-content: flex-end; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - gap: 22px; - padding-top: 16px; - padding-bottom: 16px; -} - -.c13 { - color: #73848C; - font-size: 12px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; -} - -.c14 { - color: #171A1C; - padding-right: 6px; - height: 12px; -} - -
-
-
-
-
- - -
-
-
-
    -
  • - Offset -
  • -
-
-
- -
-
-
- -
- -
-
-
    -
  • - Oldest First -
  • -
-
-
-
-

-

-
- -
- - 0 - ms - -
-
-
- -
- - 0Bytes - -
-
-
- -
- - messages - -
-
-
-
- -`; diff --git a/kafka-ui-react-app/src/components/common/Select/LiveIcon.styled.tsx b/kafka-ui-react-app/src/components/common/Select/LiveIcon.styled.tsx index 0168da6304..cc7aa481b6 100644 --- a/kafka-ui-react-app/src/components/common/Select/LiveIcon.styled.tsx +++ b/kafka-ui-react-app/src/components/common/Select/LiveIcon.styled.tsx @@ -5,10 +5,14 @@ interface Props { className?: string; } +const SVGWrapper = styled.i` + display: flex; +`; + const LiveIcon: React.FC = () => { const theme = useTheme(); return ( - + = () => { - + ); }; diff --git a/kafka-ui-react-app/src/components/common/Select/Select.styled.ts b/kafka-ui-react-app/src/components/common/Select/Select.styled.ts index e730f0528f..c50e417d35 100644 --- a/kafka-ui-react-app/src/components/common/Select/Select.styled.ts +++ b/kafka-ui-react-app/src/components/common/Select/Select.styled.ts @@ -15,6 +15,7 @@ export const Select = styled.ul` position: relative; list-style: none; display: flex; + gap: ${(props) => (props.isLive ? '5px' : '0')}; align-items: center; height: ${(props) => (props.selectSize === 'M' ? '32px' : '40px')}; border: 1px @@ -26,7 +27,7 @@ export const Select = styled.ul` border-radius: 4px; font-size: 14px; width: fit-content; - padding-left: ${(props) => (props.isLive ? '36px' : '12px')}; + padding-left: 16px; padding-right: 16px; color: ${({ theme, disabled }) => disabled ? theme.select.color.disabled : theme.select.color.normal}; @@ -38,8 +39,8 @@ export const Select = styled.ul` background-repeat: no-repeat !important; background-position-x: calc(100% - 8px) !important; background-position-y: 55% !important; - - &:hover { + cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')}; + &:hover:enabled { color: ${(props) => props.theme.select.color.hover}; border-color: ${(props) => props.theme.select.borderColor.hover}; } @@ -51,7 +52,6 @@ export const Select = styled.ul` &:disabled { color: ${(props) => props.theme.select.color.disabled}; border-color: ${(props) => props.theme.select.borderColor.disabled}; - cursor: not-allowed; } `; @@ -71,7 +71,6 @@ export const OptionList = styled.ul` z-index: 10; max-width: 300px; min-width: 100%; - &::-webkit-scrollbar { -webkit-appearance: none; width: 7px; @@ -89,10 +88,12 @@ export const OptionList = styled.ul` `; export const Option = styled.li` + display: flex; list-style: none; padding: 10px 12px; transition: all 0.2s ease-in-out; cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')}; + gap: 5px; &:hover { background-color: ${(props) => props.theme.select.backgroundColor.hover}; diff --git a/kafka-ui-react-app/src/components/common/Select/Select.tsx b/kafka-ui-react-app/src/components/common/Select/Select.tsx index 0b02c1c411..ae9824e291 100644 --- a/kafka-ui-react-app/src/components/common/Select/Select.tsx +++ b/kafka-ui-react-app/src/components/common/Select/Select.tsx @@ -22,6 +22,7 @@ export interface SelectOption { label: string | number; value: string | number; disabled?: boolean; + isLive?: boolean; } const Select: React.FC = ({ @@ -53,10 +54,12 @@ const Select: React.FC = ({ if (onChange) onChange(option.value); setShowOptions(false); }; + React.useEffect(() => { + setSelectedOption(value); + }, [isLive, value]); return (
- {isLive && } = ({ onKeyDown={showOptionsHandler} {...props} > + {isLive && } {options.find( (option) => option.value === (defaultValue || selectedOption) @@ -82,6 +86,7 @@ const Select: React.FC = ({ tabIndex={0} role="option" > + {option.isLive && } {option.label} ))} diff --git a/kafka-ui-react-app/src/components/common/Select/__tests__/Select.spec.tsx b/kafka-ui-react-app/src/components/common/Select/__tests__/Select.spec.tsx index 27dd508b74..5ace7a2846 100644 --- a/kafka-ui-react-app/src/components/common/Select/__tests__/Select.spec.tsx +++ b/kafka-ui-react-app/src/components/common/Select/__tests__/Select.spec.tsx @@ -1,6 +1,8 @@ import Select, { SelectProps } from 'components/common/Select/Select'; import React from 'react'; import { render } from 'lib/testHelpers'; +import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; jest.mock('react-hook-form', () => ({ useFormContext: () => ({ @@ -8,26 +10,47 @@ jest.mock('react-hook-form', () => ({ }), })); -const setupWrapper = (props?: Partial) => ( - ); describe('Custom Select', () => { + it('renders component', () => { + renderComponent(); + expect(screen.getByRole('listbox')).toBeInTheDocument(); + }); + it('show select options when select is being clicked', () => { + renderComponent({ + options, + }); + expect(screen.getByRole('option')).toBeInTheDocument(); + userEvent.click(screen.getByRole('listbox')); + expect(screen.getAllByRole('option')).toHaveLength(3); + }); + it('checking select option change', () => { + renderComponent({ + options, + }); + userEvent.click(screen.getByRole('listbox')); + userEvent.selectOptions(screen.getByRole('listbox'), ['test-label1']); + expect(screen.getByRole('option')).toHaveTextContent('test-label1'); + }); + describe('when non-live', () => { - it('matches the snapshot', () => { - const component = render(setupWrapper()); - expect(component.baseElement).toMatchSnapshot(); + it('there is not live icon', () => { + renderComponent({ isLive: false }); + expect(screen.queryByTestId('liveIcon')).not.toBeInTheDocument(); }); }); describe('when live', () => { - it('matches the snapshot', () => { - const component = render( - setupWrapper({ - isLive: true, - }) - ); - expect(component.baseElement).toMatchSnapshot(); + it('there is live icon', () => { + renderComponent({ isLive: true }); + expect(screen.getByTestId('liveIcon')).toBeInTheDocument(); }); }); }); diff --git a/kafka-ui-react-app/src/components/common/Select/__tests__/__snapshots__/Select.spec.tsx.snap b/kafka-ui-react-app/src/components/common/Select/__tests__/__snapshots__/Select.spec.tsx.snap deleted file mode 100644 index 8d5f5686c7..0000000000 --- a/kafka-ui-react-app/src/components/common/Select/__tests__/__snapshots__/Select.spec.tsx.snap +++ /dev/null @@ -1,169 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Custom Select when live matches the snapshot 1`] = ` - - .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: -webkit-fit-content; - width: -moz-fit-content; - width: fit-content; - padding-left: 36px; - padding-right: 16px; - color: #171A1C; - min-width: auto; - 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; -} - -.c0:hover { - color: #171A1C; - border-color: #73848C; -} - -.c0:focus { - outline: none; - color: #171A1C; - border-color: #454F54; -} - -.c0:disabled { - color: #ABB5BA; - border-color: #E3E6E8; - cursor: not-allowed; -} - -.c1 { - padding-right: 16px; - list-style-position: inside; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -
-
- - - - - - -
    -
  • -
-
-
- -`; - -exports[`Custom Select when non-live matches the snapshot 1`] = ` -.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: -webkit-fit-content; - width: -moz-fit-content; - width: fit-content; - padding-left: 12px; - padding-right: 16px; - color: #171A1C; - min-width: auto; - 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; -} - -.c0:hover { - color: #171A1C; - border-color: #73848C; -} - -.c0:focus { - outline: none; - color: #171A1C; - border-color: #454F54; -} - -.c0:disabled { - color: #ABB5BA; - border-color: #E3E6E8; - cursor: not-allowed; -} - -.c1 { - padding-right: 16px; - list-style-position: inside; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - - -
-
-
    -
  • -
-
-
- -`;