Browse Source

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
Arsen Simonyan 3 years ago
parent
commit
521ba0cb2f

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

@@ -129,6 +129,8 @@ const Filters: React.FC<FiltersProps> = ({
       : MessageFilterType.STRING_CONTAINS
   );
   const [query, setQuery] = React.useState<string>(searchParams.get('q') || '');
+  const [isTailing, setIsTailing] = React.useState<boolean>(isLive);
+
   const isSeekTypeControlVisible = React.useMemo(
     () => selectedPartitions.length > 0,
     [selectedPartitions]
@@ -136,11 +138,13 @@ const Filters: React.FC<FiltersProps> = ({
 
   const isSubmitDisabled = React.useMemo(() => {
     if (isSeekTypeControlVisible) {
-      return currentSeekType === SeekType.TIMESTAMP && !timestamp;
+      return (
+        (currentSeekType === SeekType.TIMESTAMP && !timestamp) || isTailing
+      );
     }
 
     return false;
-  }, [isSeekTypeControlVisible, currentSeekType, timestamp]);
+  }, [isSeekTypeControlVisible, currentSeekType, timestamp, isTailing]);
 
   const partitionMap = React.useMemo(
     () =>
@@ -345,6 +349,10 @@ const Filters: React.FC<FiltersProps> = ({
     handleFiltersSubmit(offset);
   }, [handleFiltersSubmit, seekDirection]);
 
+  React.useEffect(() => {
+    setIsTailing(isLive);
+  }, [isLive]);
+
   return (
     <S.FiltersWrapper>
       <div>
@@ -352,6 +360,7 @@ const Filters: React.FC<FiltersProps> = ({
           <Search
             placeholder="Search"
             value={query}
+            disabled={isTailing}
             handleSearch={(value: string) => setQuery(value)}
           />
           <S.SeekTypeSelectorWrapper>
@@ -362,7 +371,7 @@ const Filters: React.FC<FiltersProps> = ({
               selectSize="M"
               minWidth="100px"
               options={SeekTypeOptions}
-              disabled={isLive}
+              disabled={isTailing}
             />
             {currentSeekType === SeekType.OFFSET ? (
               <Input
@@ -373,7 +382,7 @@ const Filters: React.FC<FiltersProps> = ({
                 className="offset-selector"
                 placeholder="Offset"
                 onChange={({ target: { value } }) => setOffset(value)}
-                disabled={isLive}
+                disabled={isTailing}
               />
             ) : (
               <DatePicker
@@ -384,7 +393,7 @@ const Filters: React.FC<FiltersProps> = ({
                 dateFormat="MMMM d, yyyy HH:mm"
                 className="date-picker"
                 placeholderText="Select timestamp"
-                disabled={isLive}
+                disabled={isTailing}
               />
             )}
           </S.SeekTypeSelectorWrapper>
@@ -397,6 +406,7 @@ const Filters: React.FC<FiltersProps> = ({
             value={selectedPartitions}
             onChange={setSelectedPartitions}
             labelledBy="Select partitions"
+            disabled={isTailing}
           />
           <S.ClearAll onClick={handleClearAllFilters}>Clear all</S.ClearAll>
           {isFetching ? (
@@ -465,13 +475,13 @@ const Filters: React.FC<FiltersProps> = ({
             isFetching &&
             phaseMessage}
         </p>
-        <S.MessageLoading isLive={isLive}>
+        <S.MessageLoading isLive={isTailing}>
           <S.MessageLoadingSpinner isFetching={isFetching} />
           Loading messages.
           <S.StopLoading
             onClick={() => {
-              changeSeekDirection(SeekDirection.FORWARD);
-              setIsFetching(false);
+              handleSSECancel();
+              setIsTailing(false);
             }}
           >
             Stop loading

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

@@ -9,8 +9,14 @@ const MultiSelect = styled(ReactMultiSelect)<{ minWidth?: string }>`
   & > .dropdown-container {
     height: 32px;
 
+    * {
+      cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
+    }
+
     & > .dropdown-heading {
       height: 32px;
+      color: ${({ disabled, theme }) =>
+        disabled ? theme.select.color.disabled : theme.select.color.active};
     }
   }
 `;

+ 61 - 0
kafka-ui-react-app/src/components/common/MultiSelect/__test__/MultiSelect.styled.spec.tsx

@@ -0,0 +1,61 @@
+import React from 'react';
+import { render } from 'lib/testHelpers';
+import MultiSelect from 'components/common/MultiSelect/MultiSelect.styled';
+import { ISelectProps } from 'react-multi-select-component/dist/lib/interfaces';
+
+const Option1 = { value: 1, label: 'option 1' };
+const Option2 = { value: 2, label: 'option 2' };
+
+interface IMultiSelectProps extends ISelectProps {
+  minWidth?: string;
+}
+
+const DefaultProps: IMultiSelectProps = {
+  options: [Option1, Option2],
+  labelledBy: 'multi-select',
+  value: [Option1, Option2],
+};
+
+describe('MultiSelect.Styled', () => {
+  const setUpComponent = (props: IMultiSelectProps = DefaultProps) => {
+    const { container } = render(<MultiSelect {...props} />);
+    const multiSelect = container.firstChild;
+    const dropdownContainer = multiSelect?.firstChild?.firstChild;
+
+    return { container, multiSelect, dropdownContainer };
+  };
+
+  it('should have 200px minWidth by default', () => {
+    const { container } = setUpComponent();
+    const multiSelect = container.firstChild;
+
+    expect(multiSelect).toHaveStyle('min-width: 200px');
+  });
+
+  it('should have the provided minWidth in styles', () => {
+    const minWidth = '400px';
+    const { container } = setUpComponent({ ...DefaultProps, minWidth });
+    const multiSelect = container.firstChild;
+
+    expect(multiSelect).toHaveStyle(`min-width: ${minWidth}`);
+  });
+
+  describe('when not disabled', () => {
+    it('should have cursor pointer', () => {
+      const { dropdownContainer } = setUpComponent();
+
+      expect(dropdownContainer).toHaveStyle(`cursor: pointer`);
+    });
+  });
+
+  describe('when disabled', () => {
+    it('should have cursor not-allowed', () => {
+      const { dropdownContainer } = setUpComponent({
+        ...DefaultProps,
+        disabled: true,
+      });
+
+      expect(dropdownContainer).toHaveStyle(`cursor: not-allowed`);
+    });
+  });
+});

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

@@ -6,12 +6,14 @@ interface SearchProps {
   handleSearch: (value: string) => void;
   placeholder?: string;
   value: string;
+  disabled?: boolean;
 }
 
 const Search: React.FC<SearchProps> = ({
   handleSearch,
   placeholder = 'Search',
   value,
+  disabled = false,
 }) => {
   const onChange = useDebouncedCallback(
     (e) => handleSearch(e.target.value),
@@ -26,6 +28,7 @@ const Search: React.FC<SearchProps> = ({
       defaultValue={value}
       leftIcon="fas fa-search"
       inputSize="M"
+      disabled={disabled}
     />
   );
 };