feat(logs): support search/filter logs
This commit is contained in:
parent
eb76f7c194
commit
fd07fae633
7 changed files with 63 additions and 48 deletions
7
src/components/LogSearch.js
Normal file
7
src/components/LogSearch.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import Search from './Search';
|
||||
import { getSearchText, updateSearchText } from 'd/logs';
|
||||
|
||||
const mapStateToProps = s => ({ searchText: getSearchText(s) });
|
||||
const actions = { updateSearchText };
|
||||
|
||||
export default Search({ mapStateToProps, actions });
|
|
@ -10,6 +10,7 @@ import ContentHeader from 'c/ContentHeader';
|
|||
import useRemainingViewPortHeight from '../hooks/useRemainingViewPortHeight';
|
||||
// TODO move this into a redux action
|
||||
import { fetchLogs } from '../api/logs';
|
||||
import LogSearch from './LogSearch';
|
||||
import { getLogsForDisplay, appendLog } from 'd/logs';
|
||||
|
||||
import yacd from 's/yacd.svg';
|
||||
|
@ -72,6 +73,7 @@ export default function Logs() {
|
|||
return (
|
||||
<div>
|
||||
<ContentHeader title="Logs" />
|
||||
<LogSearch />
|
||||
<div ref={refLogsContainer} style={{ paddingBottom }}>
|
||||
{logs.length === 0 ? (
|
||||
<div
|
||||
|
|
|
@ -1,49 +1,7 @@
|
|||
import React, { useState, useMemo } from 'react';
|
||||
import Icon from 'c/Icon';
|
||||
|
||||
import search from 's/search.svg';
|
||||
import { useActions, useStoreState } from 'm/store';
|
||||
|
||||
import debounce from 'lodash-es/debounce';
|
||||
|
||||
import s0 from './RuleSearch.module.scss';
|
||||
|
||||
import Search from './Search';
|
||||
import { getSearchText, updateSearchText } from 'd/rules';
|
||||
|
||||
const mapStateToProps = s => ({
|
||||
searchText: getSearchText(s)
|
||||
});
|
||||
|
||||
const mapStateToProps = s => ({ searchText: getSearchText(s) });
|
||||
const actions = { updateSearchText };
|
||||
|
||||
export default React.memo(function RuleSearch() {
|
||||
const { updateSearchText } = useActions(actions);
|
||||
const updateSearchTextDebounced = useMemo(
|
||||
() => debounce(updateSearchText, 300),
|
||||
[updateSearchText]
|
||||
);
|
||||
const { searchText } = useStoreState(mapStateToProps);
|
||||
const [text, setText] = useState(searchText);
|
||||
const onChange = e => {
|
||||
setText(e.target.value);
|
||||
updateSearchTextDebounced(e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={s0.RuleSearch}>
|
||||
<div className={s0.RuleSearchContainer}>
|
||||
<div className={s0.inputWrapper}>
|
||||
<input
|
||||
type="text"
|
||||
value={text}
|
||||
onChange={onChange}
|
||||
className={s0.input}
|
||||
/>
|
||||
</div>
|
||||
<div className={s0.iconWrapper}>
|
||||
<Icon id={search.id} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
export default Search({ mapStateToProps, actions });
|
||||
|
|
45
src/components/Search.js
Normal file
45
src/components/Search.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
import React, { memo, useState, useMemo } from 'react';
|
||||
import Icon from 'c/Icon';
|
||||
|
||||
import search from 's/search.svg';
|
||||
import { useActions, useStoreState } from 'm/store';
|
||||
|
||||
import debounce from 'lodash-es/debounce';
|
||||
|
||||
import s0 from './Search.module.scss';
|
||||
|
||||
function getSerachComponent({ mapStateToProps, actions }) {
|
||||
return memo(function RuleSearch() {
|
||||
const { updateSearchText } = useActions(actions);
|
||||
const updateSearchTextDebounced = useMemo(
|
||||
() => debounce(updateSearchText, 300),
|
||||
[updateSearchText]
|
||||
);
|
||||
const { searchText } = useStoreState(mapStateToProps);
|
||||
const [text, setText] = useState(searchText);
|
||||
const onChange = e => {
|
||||
setText(e.target.value);
|
||||
updateSearchTextDebounced(e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={s0.RuleSearch}>
|
||||
<div className={s0.RuleSearchContainer}>
|
||||
<div className={s0.inputWrapper}>
|
||||
<input
|
||||
type="text"
|
||||
value={text}
|
||||
onChange={onChange}
|
||||
className={s0.input}
|
||||
/>
|
||||
</div>
|
||||
<div className={s0.iconWrapper}>
|
||||
<Icon id={search.id} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default getSerachComponent;
|
|
@ -7,10 +7,12 @@ const LogSize = 300;
|
|||
|
||||
const getLogs = s => s.logs.logs;
|
||||
const getTail = s => s.logs.tail;
|
||||
export const getSearchText = s => s.logs.searchText;
|
||||
export const getLogsForDisplay = createSelector(
|
||||
getLogs,
|
||||
getTail,
|
||||
(logs, tail) => {
|
||||
getSearchText,
|
||||
(logs, tail, searchText) => {
|
||||
const x = [];
|
||||
for (let i = tail; i >= 0; i--) {
|
||||
x.push(logs[i]);
|
||||
|
@ -20,7 +22,9 @@ export const getLogsForDisplay = createSelector(
|
|||
x.push(logs[i]);
|
||||
}
|
||||
}
|
||||
return x;
|
||||
|
||||
if (searchText === '') return x;
|
||||
return x.filter(r => r.payload.toLowerCase().indexOf(searchText) >= 0);
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import * as rulesAPI from 'a/rules';
|
||||
import { getClashAPIConfig } from 'd/app';
|
||||
import invariant from 'invariant';
|
||||
// import { debounce } from 'lodash-es';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
export const getAllRules = s => s.rules.allRules;
|
||||
|
|
Loading…
Reference in a new issue