Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into fix/AG-10327
Browse files Browse the repository at this point in the history
  • Loading branch information
Mizzick committed Oct 1, 2021
2 parents a50858b + 91236e4 commit 257be2c
Show file tree
Hide file tree
Showing 21 changed files with 411 additions and 157 deletions.
5 changes: 4 additions & 1 deletion Extension/_locales/en/messages.json
Expand Up @@ -419,6 +419,9 @@
"filtering_log_search_string": {
"message": "Enter the search string"
},
"filtering_log_search_tabs_placeholder": {
"message": "Search in tabs"
},
"filtering_log_preserve_log_off": {
"message": "Preserve log: OFF"
},
Expand Down Expand Up @@ -1004,4 +1007,4 @@
"blocking_pages_btn_proceed": {
"message": "Proceed anyway"
}
}
}
3 changes: 3 additions & 0 deletions Extension/src/common/constants.js
Expand Up @@ -173,3 +173,6 @@ export const CUSTOM_FILTERS_GROUP_DISPLAY_NUMBER = 99;
* @type {number}
*/
export const CUSTOM_FILTERS_START_ID = 1000;

// Unnecessary characters that will be replaced
export const WASTE_CHARACTERS = /[.*+?^${}()|[\]\\]/g;
13 changes: 6 additions & 7 deletions Extension/src/pages/common/components/ui/Icons.jsx
Expand Up @@ -11,8 +11,9 @@ export const Icons = () => {
</g>
</symbol>

<symbol id="cross" viewBox="0 0 15.642 15.642" xmlns="http://www.w3.org/2000/svg">
<path fillRule="evenodd" d="M8.882 7.821l6.541-6.541A.75.75 0 1 0 14.362.219L7.821 6.76 1.28.22A.75.75 0 1 0 .219 1.281L6.76 7.822l-6.54 6.54a.75.75 0 0 0 1.06 1.061l6.541-6.541 6.541 6.541a.75.75 0 1 0 1.06-1.061l-6.54-6.541z" fill="currentColor" />
<symbol id="cross" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M6.42857 6.42857L17.6043 17.6043" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
<path d="M6.42871 17.5714L17.6045 6.39563" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
</symbol>

<symbol id="setting-0" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
Expand Down Expand Up @@ -124,11 +125,9 @@ export const Icons = () => {
</g>
</symbol>

<symbol id="magnifying" viewBox="0 0 17 16">
<g fill="none" fillRule="evenodd" stroke="currentColor" transform="translate(1 1)">
<circle cx="5.5" cy="5.5" r="5.5" />
<path d="m10 10 5 5" strokeLinecap="round" />
</g>
<symbol id="magnifying" viewBox="0 0 24 24">
<circle cx="9.5" cy="9.5" r="5.5" fill="none" stroke="currentColor" strokeWidth="1.5" />
<path d="M14 14L19 19" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
</symbol>

<symbol id="tick" viewBox="0 0 512 512">
Expand Down
17 changes: 17 additions & 0 deletions Extension/src/pages/common/hooks/useKeyDown.js
@@ -0,0 +1,17 @@
import { useEffect, useCallback } from 'react';

export const useKeyDown = (ref, key, callback) => {
const handleKeyDown = useCallback((e) => {
if (ref.current && e.key === key) {
callback();
}
}, [ref, key, callback]);

useEffect(() => {
document.addEventListener('keydown', handleKeyDown);

return () => {
document.removeEventListener('keydown', handleKeyDown);
};
}, [handleKeyDown]);
};
Expand Up @@ -7,6 +7,15 @@
box-sizing: border-box;
}

.list {
-ms-overflow-style: none;
scrollbar-width: none;

&::-webkit-scrollbar {
display: none;
}
}

&__inner {
table-layout: fixed;
width: 100%;
Expand Down Expand Up @@ -130,8 +139,6 @@
display: flex;
align-items: center;
justify-content: center;
position: relative;
z-index: 10;
}

&__empty-in {
Expand Down
@@ -1,56 +1,28 @@
import React, { useContext, useRef } from 'react';
import React, { useContext } from 'react';
import { observer } from 'mobx-react';

import { rootStore } from '../../../stores/RootStore';
import { Icon } from '../../../../common/components/ui/Icon';
import { reactTranslator } from '../../../../../common/translators/reactTranslator';

import './events-search.pcss';
import { Search } from '../../Search';

const EventsSearch = observer(() => {
const { logStore } = useContext(rootStore);

const searchInputRef = useRef();

const onSubmit = (e) => {
e.preventDefault();
};

const changeHandler = (e) => {
logStore.setEventsSearchValue(e.currentTarget.value);
};

const handleClear = () => {
logStore.setEventsSearchValue('');
searchInputRef.current.focus();
};

return (
<form
className="events-search"
onSubmit={onSubmit}
>
{logStore.eventsSearchValue
? (
<button
type="button"
className="events-search__clear"
onClick={handleClear}
>
<Icon id="#cross" classname="events-search__cross" />
</button>
)
: <Icon id="#magnifying" classname="events-search__ico" />}
<input
type="text"
id="events-search"
name="events-search"
placeholder={reactTranslator.getMessage('filtering_log_search_string')}
ref={searchInputRef}
onChange={changeHandler}
value={logStore.eventsSearchValue}
/>
</form>
<Search
changeHandler={changeHandler}
handleClear={handleClear}
value={logStore.eventsSearchValue}
placeholder={reactTranslator.getMessage('filtering_log_search_string')}
/>
);
});

Expand Down
Expand Up @@ -2,75 +2,164 @@
eslint-disable jsx-a11y/click-events-have-key-events,
jsx-a11y/no-noninteractive-element-interactions
*/
import React, { useContext, useEffect } from 'react';
import React, {
useContext, useEffect, useState, useRef,
} from 'react';
import cn from 'classnames';
import { observer } from 'mobx-react';

import { rootStore } from '../../../stores/RootStore';
import { Icon } from '../../../../common/components/ui/Icon';
import { reactTranslator } from '../../../../../common/translators/reactTranslator';
import { useOutsideClick } from '../../../../common/hooks/useOutsideClick';
import { useKeyDown } from '../../../../common/hooks/useKeyDown';
import { WASTE_CHARACTERS } from '../../../../../common/constants';

import { Search } from '../../Search';

import './tab-selector.pcss';

const TabSelector = observer(() => {
const { logStore } = useContext(rootStore);
const { logStore, wizardStore } = useContext(rootStore);
const refSelector = useRef(null);
const refResult = useRef(null);
const { tabs, selectedTabId, selectIsOpen } = logStore;

const [prevTabTitle, setPrevTabTitle] = useState('');
const [searchValue, setSearchValue] = useState('');
const [resultItems, setResultItems] = useState([]);
const [currentStep, setCurrentStep] = useState(0);

const SELECTED_CLASS_NAME = 'selected';

useEffect(() => {
if (refResult.current?.childNodes) {
setResultItems(Array.from(refResult.current.childNodes));
}
}, [searchValue]);

useEffect(() => {
if (resultItems) {
resultItems.forEach(
(el) => el.classList.remove(SELECTED_CLASS_NAME),
);

const currentEl = resultItems[currentStep];

currentEl?.classList.add(SELECTED_CLASS_NAME);
currentEl?.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
}
}, [currentStep, resultItems]);

useKeyDown(refResult, 'Enter', () => {
const targetElem = resultItems?.find(
(el) => el.classList.contains(SELECTED_CLASS_NAME),
);
if (targetElem) {
(async () => {
await selectionHandlerSearch(Number(targetElem.id));
})();
document.activeElement.blur();
}
});

useKeyDown(refResult, 'ArrowDown', () => {
const lastIndex = resultItems.length - 1;
const step = lastIndex > currentStep
? currentStep + 1 : 0;
setCurrentStep(step);
});

useKeyDown(refResult, 'ArrowUp', () => {
const lastIndex = resultItems.length - 1;
const step = currentStep > 0
? currentStep - 1 : lastIndex;
setCurrentStep(step);
});

useOutsideClick(refSelector, () => {
if (
searchValue.length === 0
|| !tabs.find((tab) => tab.title === searchValue)
) {
setSearchValue(prevTabTitle);
}
logStore.setSelectIsOpenState(false);
setCurrentStep(0);
});

const { tabs, selectedTabId } = logStore;
useEffect(() => {
const selectedTab = tabs.find((tab) => tab.tabId === selectedTabId);
const title = selectedTab?.title || '';
setPrevTabTitle(title);
if (!selectIsOpen) {
setSearchValue(title);
}
}, [selectedTabId, tabs, selectIsOpen]);

const selectionHandlerSearch = async (id) => {
logStore.setSelectIsOpenState(false);
setCurrentStep(0);
if (selectedTabId === id) {
setSearchValue(prevTabTitle);
}
await logStore.setSelectedTabId(id);
};

const renderOptions = () => {
const renderSearchResult = () => {
const searchValueString = searchValue.replace(WASTE_CHARACTERS, '\\$&');
const searchQuery = new RegExp(searchValueString, 'ig');
return tabs.map((tab) => {
const { title, tabId } = tab;
return (
<option
key={tabId}
value={tabId}
>
{title}
</option>

const itemClassName = cn(
'tab-selector__result-item',
{ 'tab-selector__result-item--active': tabId === selectedTabId },
);
});
};

const selectionHandler = async (e) => {
e.preventDefault();
await logStore.setSelectedTabId(e.target.value);
};
if (title.match(searchQuery)) {
return (
<button
key={tabId}
id={tabId}
type="button"
className={itemClassName}
onClick={() => { selectionHandlerSearch(tabId); }}
>
{title}
</button>
);
}

const onFocus = () => {
logStore.setSelectIsOpenState(true);
return null;
});
};

const onClick = () => {
logStore.setSelectIsOpenState(true);
const searchChangeHandler = (e) => {
setCurrentStep(0);
setSearchValue(e.currentTarget.value);
};

const onBlur = () => {
logStore.setSelectIsOpenState(false);
const handleClear = () => {
setSearchValue('');
wizardStore.closeModal();
logStore.setSelectIsOpenState(true);
};

return (
<div className="tab-selector">
<div className="tab-selector__select">
<Icon id="#arrow-bottom" classname="tab-selector__select-ico" />
<label
htmlFor="tab-selector"
onFocus={onFocus}
onBlur={onBlur}
onClick={onClick}
>
<select
className="tab-selector__select-in"
name="tab-selector"
id="tab-selector"
onChange={selectionHandler}
value={selectedTabId || ''}
>
{renderOptions()}
</select>
</label>
</div>
<div id="tab-selector" className="tab-selector" ref={refSelector}>
<Search
select
changeHandler={searchChangeHandler}
value={searchValue}
placeholder={reactTranslator.getMessage('filtering_log_search_tabs_placeholder')}
handleClear={handleClear}
onFocus={handleClear}
/>
{selectIsOpen && (
<div className="tab-selector__result" ref={refResult}>
{renderSearchResult()}
</div>
)}
</div>
);
});
Expand Down

0 comments on commit 257be2c

Please sign in to comment.