Skip to content

Commit 521ba0c

Browse files
authored
Improve live tailing. (#1898)
* disable filter options when live tailing mode is enabled * prevent seek direction change when stop loading is pressed on live mode * disable submit button while tailing * write tests for MultiSelect.styled component to achieve 100% coverage
1 parent 247fd23 commit 521ba0c

File tree

4 files changed

+88
-8
lines changed

4 files changed

+88
-8
lines changed

kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.tsx

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,18 +129,22 @@ const Filters: React.FC<FiltersProps> = ({
129129
: MessageFilterType.STRING_CONTAINS
130130
);
131131
const [query, setQuery] = React.useState<string>(searchParams.get('q') || '');
132+
const [isTailing, setIsTailing] = React.useState<boolean>(isLive);
133+
132134
const isSeekTypeControlVisible = React.useMemo(
133135
() => selectedPartitions.length > 0,
134136
[selectedPartitions]
135137
);
136138

137139
const isSubmitDisabled = React.useMemo(() => {
138140
if (isSeekTypeControlVisible) {
139-
return currentSeekType === SeekType.TIMESTAMP && !timestamp;
141+
return (
142+
(currentSeekType === SeekType.TIMESTAMP && !timestamp) || isTailing
143+
);
140144
}
141145

142146
return false;
143-
}, [isSeekTypeControlVisible, currentSeekType, timestamp]);
147+
}, [isSeekTypeControlVisible, currentSeekType, timestamp, isTailing]);
144148

145149
const partitionMap = React.useMemo(
146150
() =>
@@ -345,13 +349,18 @@ const Filters: React.FC<FiltersProps> = ({
345349
handleFiltersSubmit(offset);
346350
}, [handleFiltersSubmit, seekDirection]);
347351

352+
React.useEffect(() => {
353+
setIsTailing(isLive);
354+
}, [isLive]);
355+
348356
return (
349357
<S.FiltersWrapper>
350358
<div>
351359
<S.FilterInputs>
352360
<Search
353361
placeholder="Search"
354362
value={query}
363+
disabled={isTailing}
355364
handleSearch={(value: string) => setQuery(value)}
356365
/>
357366
<S.SeekTypeSelectorWrapper>
@@ -362,7 +371,7 @@ const Filters: React.FC<FiltersProps> = ({
362371
selectSize="M"
363372
minWidth="100px"
364373
options={SeekTypeOptions}
365-
disabled={isLive}
374+
disabled={isTailing}
366375
/>
367376
{currentSeekType === SeekType.OFFSET ? (
368377
<Input
@@ -373,7 +382,7 @@ const Filters: React.FC<FiltersProps> = ({
373382
className="offset-selector"
374383
placeholder="Offset"
375384
onChange={({ target: { value } }) => setOffset(value)}
376-
disabled={isLive}
385+
disabled={isTailing}
377386
/>
378387
) : (
379388
<DatePicker
@@ -384,7 +393,7 @@ const Filters: React.FC<FiltersProps> = ({
384393
dateFormat="MMMM d, yyyy HH:mm"
385394
className="date-picker"
386395
placeholderText="Select timestamp"
387-
disabled={isLive}
396+
disabled={isTailing}
388397
/>
389398
)}
390399
</S.SeekTypeSelectorWrapper>
@@ -397,6 +406,7 @@ const Filters: React.FC<FiltersProps> = ({
397406
value={selectedPartitions}
398407
onChange={setSelectedPartitions}
399408
labelledBy="Select partitions"
409+
disabled={isTailing}
400410
/>
401411
<S.ClearAll onClick={handleClearAllFilters}>Clear all</S.ClearAll>
402412
{isFetching ? (
@@ -465,13 +475,13 @@ const Filters: React.FC<FiltersProps> = ({
465475
isFetching &&
466476
phaseMessage}
467477
</p>
468-
<S.MessageLoading isLive={isLive}>
478+
<S.MessageLoading isLive={isTailing}>
469479
<S.MessageLoadingSpinner isFetching={isFetching} />
470480
Loading messages.
471481
<S.StopLoading
472482
onClick={() => {
473-
changeSeekDirection(SeekDirection.FORWARD);
474-
setIsFetching(false);
483+
handleSSECancel();
484+
setIsTailing(false);
475485
}}
476486
>
477487
Stop loading

kafka-ui-react-app/src/components/common/MultiSelect/MultiSelect.styled.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,14 @@ const MultiSelect = styled(ReactMultiSelect)<{ minWidth?: string }>`
99
& > .dropdown-container {
1010
height: 32px;
1111
12+
* {
13+
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
14+
}
15+
1216
& > .dropdown-heading {
1317
height: 32px;
18+
color: ${({ disabled, theme }) =>
19+
disabled ? theme.select.color.disabled : theme.select.color.active};
1420
}
1521
}
1622
`;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import React from 'react';
2+
import { render } from 'lib/testHelpers';
3+
import MultiSelect from 'components/common/MultiSelect/MultiSelect.styled';
4+
import { ISelectProps } from 'react-multi-select-component/dist/lib/interfaces';
5+
6+
const Option1 = { value: 1, label: 'option 1' };
7+
const Option2 = { value: 2, label: 'option 2' };
8+
9+
interface IMultiSelectProps extends ISelectProps {
10+
minWidth?: string;
11+
}
12+
13+
const DefaultProps: IMultiSelectProps = {
14+
options: [Option1, Option2],
15+
labelledBy: 'multi-select',
16+
value: [Option1, Option2],
17+
};
18+
19+
describe('MultiSelect.Styled', () => {
20+
const setUpComponent = (props: IMultiSelectProps = DefaultProps) => {
21+
const { container } = render(<MultiSelect {...props} />);
22+
const multiSelect = container.firstChild;
23+
const dropdownContainer = multiSelect?.firstChild?.firstChild;
24+
25+
return { container, multiSelect, dropdownContainer };
26+
};
27+
28+
it('should have 200px minWidth by default', () => {
29+
const { container } = setUpComponent();
30+
const multiSelect = container.firstChild;
31+
32+
expect(multiSelect).toHaveStyle('min-width: 200px');
33+
});
34+
35+
it('should have the provided minWidth in styles', () => {
36+
const minWidth = '400px';
37+
const { container } = setUpComponent({ ...DefaultProps, minWidth });
38+
const multiSelect = container.firstChild;
39+
40+
expect(multiSelect).toHaveStyle(`min-width: ${minWidth}`);
41+
});
42+
43+
describe('when not disabled', () => {
44+
it('should have cursor pointer', () => {
45+
const { dropdownContainer } = setUpComponent();
46+
47+
expect(dropdownContainer).toHaveStyle(`cursor: pointer`);
48+
});
49+
});
50+
51+
describe('when disabled', () => {
52+
it('should have cursor not-allowed', () => {
53+
const { dropdownContainer } = setUpComponent({
54+
...DefaultProps,
55+
disabled: true,
56+
});
57+
58+
expect(dropdownContainer).toHaveStyle(`cursor: not-allowed`);
59+
});
60+
});
61+
});

kafka-ui-react-app/src/components/common/Search/Search.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ interface SearchProps {
66
handleSearch: (value: string) => void;
77
placeholder?: string;
88
value: string;
9+
disabled?: boolean;
910
}
1011

1112
const Search: React.FC<SearchProps> = ({
1213
handleSearch,
1314
placeholder = 'Search',
1415
value,
16+
disabled = false,
1517
}) => {
1618
const onChange = useDebouncedCallback(
1719
(e) => handleSearch(e.target.value),
@@ -26,6 +28,7 @@ const Search: React.FC<SearchProps> = ({
2628
defaultValue={value}
2729
leftIcon="fas fa-search"
2830
inputSize="M"
31+
disabled={disabled}
2932
/>
3033
);
3134
};

0 commit comments

Comments
 (0)