Skip to content

Commit 415d852

Browse files
committed
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 83b11bd commit 415d852

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
() =>
@@ -369,13 +373,18 @@ const Filters: React.FC<FiltersProps> = ({
369373
seekDirection,
370374
]);
371375

376+
React.useEffect(() => {
377+
setIsTailing(isLive);
378+
}, [isLive]);
379+
372380
return (
373381
<S.FiltersWrapper>
374382
<div>
375383
<S.FilterInputs>
376384
<Search
377385
placeholder="Search"
378386
value={query}
387+
disabled={isTailing}
379388
handleSearch={(value: string) => setQuery(value)}
380389
/>
381390
<S.SeekTypeSelectorWrapper>
@@ -386,7 +395,7 @@ const Filters: React.FC<FiltersProps> = ({
386395
selectSize="M"
387396
minWidth="100px"
388397
options={SeekTypeOptions}
389-
disabled={isLive}
398+
disabled={isTailing}
390399
/>
391400
{currentSeekType === SeekType.OFFSET ? (
392401
<Input
@@ -397,7 +406,7 @@ const Filters: React.FC<FiltersProps> = ({
397406
className="offset-selector"
398407
placeholder="Offset"
399408
onChange={({ target: { value } }) => setOffset(value)}
400-
disabled={isLive}
409+
disabled={isTailing}
401410
/>
402411
) : (
403412
<DatePicker
@@ -408,7 +417,7 @@ const Filters: React.FC<FiltersProps> = ({
408417
dateFormat="MMMM d, yyyy HH:mm"
409418
className="date-picker"
410419
placeholderText="Select timestamp"
411-
disabled={isLive}
420+
disabled={isTailing}
412421
/>
413422
)}
414423
</S.SeekTypeSelectorWrapper>
@@ -421,6 +430,7 @@ const Filters: React.FC<FiltersProps> = ({
421430
value={selectedPartitions}
422431
onChange={setSelectedPartitions}
423432
labelledBy="Select partitions"
433+
disabled={isTailing}
424434
/>
425435
<S.ClearAll onClick={handleClearAllFilters}>Clear all</S.ClearAll>
426436
{isFetching ? (
@@ -489,13 +499,13 @@ const Filters: React.FC<FiltersProps> = ({
489499
isFetching &&
490500
phaseMessage}
491501
</p>
492-
<S.MessageLoading isLive={isLive}>
502+
<S.MessageLoading isLive={isTailing}>
493503
<S.MessageLoadingSpinner isFetching={isFetching} />
494504
Loading messages.
495505
<S.StopLoading
496506
onClick={() => {
497-
changeSeekDirection(SeekDirection.FORWARD);
498-
setIsFetching(false);
507+
handleSSECancel();
508+
setIsTailing(false);
499509
}}
500510
>
501511
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)