mirror of
https://github.com/prymitive/karma
synced 2026-05-17 04:16:42 +00:00
feat(ui): allow saving custom filter set as default
This commit is contained in:
@@ -4,6 +4,7 @@ import PropTypes from "prop-types";
|
||||
import { Provider } from "mobx-react";
|
||||
|
||||
import { AlertStore, DecodeLocationSearch } from "Stores/AlertStore";
|
||||
import { Settings } from "Stores/Settings";
|
||||
import { NavBar } from "Components/NavBar";
|
||||
import { Grid } from "Components/Grid";
|
||||
import { Fetcher } from "Components/Fetcher";
|
||||
@@ -20,6 +21,8 @@ class App extends Component {
|
||||
|
||||
const { defaultFilters } = this.props;
|
||||
|
||||
this.settingsStore = new Settings();
|
||||
|
||||
let filters;
|
||||
|
||||
// parse and decode request query args
|
||||
@@ -27,8 +30,12 @@ class App extends Component {
|
||||
|
||||
// p.defaultsUsed means that unsee URI didn't have ?q=foo query args
|
||||
if (p.defaultsUsed) {
|
||||
// no ?q=foo set, use defaults from backend config
|
||||
filters = defaultFilters;
|
||||
// no ?q=foo set, use defaults saved by the user or from backend config
|
||||
if (this.settingsStore.savedFilters.present) {
|
||||
filters = this.settingsStore.savedFilters.filters;
|
||||
} else {
|
||||
filters = defaultFilters;
|
||||
}
|
||||
} else {
|
||||
// user passed ?q=foo, use it as initial filters
|
||||
filters = p.params.q;
|
||||
@@ -40,7 +47,10 @@ class App extends Component {
|
||||
render() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<NavBar alertStore={this.alertStore} />
|
||||
<NavBar
|
||||
alertStore={this.alertStore}
|
||||
settingsStore={this.settingsStore}
|
||||
/>
|
||||
<Provider alertStore={this.alertStore}>
|
||||
<Grid alertStore={this.alertStore} />
|
||||
</Provider>
|
||||
|
||||
@@ -10,8 +10,12 @@ import onClickOutside from "react-onclickoutside";
|
||||
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faCaretDown } from "@fortawesome/free-solid-svg-icons/faCaretDown";
|
||||
import { faSave } from "@fortawesome/free-regular-svg-icons/faSave";
|
||||
import { faUndoAlt } from "@fortawesome/free-solid-svg-icons/faUndoAlt";
|
||||
import { faTrash } from "@fortawesome/free-solid-svg-icons/faTrash";
|
||||
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { Settings } from "Stores/Settings";
|
||||
import { HistoryLabel } from "Components/Labels/HistoryLabel";
|
||||
|
||||
const defaultHistory = {
|
||||
@@ -36,7 +40,9 @@ const HistoryMenu = onClickOutside(
|
||||
popperStyle,
|
||||
filters,
|
||||
alertStore,
|
||||
afterClick
|
||||
settingsStore,
|
||||
afterClick,
|
||||
onClear
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
@@ -70,6 +76,38 @@ const HistoryMenu = onClickOutside(
|
||||
</button>
|
||||
))
|
||||
)}
|
||||
<div className="dropdown-divider" />
|
||||
<div className="container text-center">
|
||||
<button className="btn btn-sm btn-success mr-4">
|
||||
<FontAwesomeIcon
|
||||
icon={faSave}
|
||||
onClick={() => {
|
||||
settingsStore.saveFilters(
|
||||
alertStore.filters.values.map(f => f.raw)
|
||||
);
|
||||
afterClick();
|
||||
}}
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-sm btn-danger mr-4"
|
||||
onClick={() => {
|
||||
settingsStore.clearSavedFilters();
|
||||
afterClick();
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon icon={faUndoAlt} />
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-sm btn-dark"
|
||||
onClick={() => {
|
||||
onClear();
|
||||
afterClick();
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon icon={faTrash} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -80,13 +118,16 @@ HistoryMenu.propTypes = {
|
||||
popperStyle: PropTypes.object,
|
||||
filters: PropTypes.array.isRequired,
|
||||
alertStore: PropTypes.instanceOf(AlertStore).isRequired,
|
||||
afterClick: PropTypes.func.isRequired
|
||||
settingsStore: PropTypes.instanceOf(Settings).isRequired,
|
||||
afterClick: PropTypes.func.isRequired,
|
||||
onClear: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
const History = observer(
|
||||
class History extends Component {
|
||||
static propTypes = {
|
||||
alertStore: PropTypes.instanceOf(AlertStore).isRequired
|
||||
alertStore: PropTypes.instanceOf(AlertStore).isRequired,
|
||||
settingsStore: PropTypes.instanceOf(Settings).isRequired
|
||||
};
|
||||
|
||||
// how many filter sets do we store in local storage and render in the
|
||||
@@ -137,6 +178,10 @@ const History = observer(
|
||||
this.history.filters = newHistory;
|
||||
});
|
||||
|
||||
clearHistory = action(() => {
|
||||
this.history.filters = [];
|
||||
});
|
||||
|
||||
componentDidUpdate() {
|
||||
// every time this component updates we will rewrite history
|
||||
// (if there are changes)
|
||||
@@ -148,7 +193,7 @@ const History = observer(
|
||||
});
|
||||
|
||||
render() {
|
||||
const { alertStore } = this.props;
|
||||
const { alertStore, settingsStore } = this.props;
|
||||
|
||||
return (
|
||||
// data-filters is there to register filters for observation in mobx
|
||||
@@ -189,7 +234,9 @@ const History = observer(
|
||||
popperRef={ref}
|
||||
popperStyle={style}
|
||||
filters={this.history.filters}
|
||||
onClear={this.clearHistory}
|
||||
alertStore={alertStore}
|
||||
settingsStore={settingsStore}
|
||||
afterClick={this.collapse.hide}
|
||||
handleClickOutside={this.collapse.hide}
|
||||
outsideClickIgnoreClass="components-navbar-history"
|
||||
|
||||
@@ -14,6 +14,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faSearch } from "@fortawesome/free-solid-svg-icons/faSearch";
|
||||
|
||||
import { AlertStore, FormatUnseeBackendURI } from "Stores/AlertStore";
|
||||
import { Settings } from "Stores/Settings";
|
||||
import { FilterInputLabel } from "Components/Labels/FilterInputLabel";
|
||||
import { AutosuggestTheme } from "./Constants";
|
||||
import { History } from "./History";
|
||||
@@ -23,7 +24,8 @@ import "./index.css";
|
||||
const FilterInput = observer(
|
||||
class FilterInput extends Component {
|
||||
static propTypes = {
|
||||
alertStore: PropTypes.instanceOf(AlertStore).isRequired
|
||||
alertStore: PropTypes.instanceOf(AlertStore).isRequired,
|
||||
settingsStore: PropTypes.instanceOf(Settings).isRequired
|
||||
};
|
||||
|
||||
inputStore = observable(
|
||||
@@ -103,7 +105,12 @@ const FilterInput = observer(
|
||||
};
|
||||
|
||||
renderInputComponent = inputProps => {
|
||||
var { inputReference, alertStore, ...otherProps } = inputProps;
|
||||
var {
|
||||
inputReference,
|
||||
alertStore,
|
||||
settingsStore,
|
||||
...otherProps
|
||||
} = inputProps;
|
||||
|
||||
return (
|
||||
<div className="input-group input-group-sm mr-2">
|
||||
@@ -132,14 +139,14 @@ const FilterInput = observer(
|
||||
/>
|
||||
</div>
|
||||
<div className="input-group-append">
|
||||
<History alertStore={alertStore} />
|
||||
<History alertStore={alertStore} settingsStore={settingsStore} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { alertStore } = this.props;
|
||||
const { alertStore, settingsStore } = this.props;
|
||||
|
||||
return (
|
||||
// data-filters is there to register filters for observation in mobx
|
||||
@@ -163,7 +170,8 @@ const FilterInput = observer(
|
||||
value: this.inputStore.value,
|
||||
onChange: this.onChange,
|
||||
inputReference: this.inputStore.ref,
|
||||
alertStore: alertStore
|
||||
alertStore: alertStore,
|
||||
settingsStore: settingsStore
|
||||
}}
|
||||
theme={AutosuggestTheme}
|
||||
/>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { observer } from "mobx-react";
|
||||
import ReactResizeDetector from "react-resize-detector";
|
||||
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { Settings } from "Stores/Settings";
|
||||
import { FetchIndicator } from "./FetchIndicator";
|
||||
import { FilterInput } from "./FilterInput";
|
||||
import { MainModal } from "Components/MainModal";
|
||||
@@ -19,11 +20,12 @@ const navbarResize = function(width, height) {
|
||||
const NavBar = observer(
|
||||
class NavBar extends Component {
|
||||
static propTypes = {
|
||||
alertStore: PropTypes.instanceOf(AlertStore).isRequired
|
||||
alertStore: PropTypes.instanceOf(AlertStore).isRequired,
|
||||
settingsStore: PropTypes.instanceOf(Settings).isRequired
|
||||
};
|
||||
|
||||
render() {
|
||||
const { alertStore } = this.props;
|
||||
const { alertStore, settingsStore } = this.props;
|
||||
return (
|
||||
<div className="container">
|
||||
<nav className="navbar fixed-top navbar-expand navbar-dark p-1 bg-primary-transparent">
|
||||
@@ -32,7 +34,10 @@ const NavBar = observer(
|
||||
{alertStore.info.totalAlerts}
|
||||
<FetchIndicator status={alertStore.status.value.toString()} />
|
||||
</span>
|
||||
<FilterInput alertStore={alertStore} />
|
||||
<FilterInput
|
||||
alertStore={alertStore}
|
||||
settingsStore={settingsStore}
|
||||
/>
|
||||
<MainModal />
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
26
ui/src/Stores/Settings.js
Normal file
26
ui/src/Stores/Settings.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { localStored } from "mobx-stored";
|
||||
|
||||
import { action } from "mobx";
|
||||
|
||||
const defaultSavedFilters = {
|
||||
filters: [],
|
||||
present: false
|
||||
};
|
||||
|
||||
class Settings {
|
||||
savedFilters = localStored("savedFilters", defaultSavedFilters, {
|
||||
delay: 100
|
||||
});
|
||||
|
||||
saveFilters = action(newFilters => {
|
||||
this.savedFilters.filters = newFilters;
|
||||
this.savedFilters.present = true;
|
||||
});
|
||||
|
||||
clearSavedFilters = action(() => {
|
||||
this.savedFilters.filters = [];
|
||||
this.savedFilters.present = false;
|
||||
});
|
||||
}
|
||||
|
||||
export { Settings };
|
||||
Reference in New Issue
Block a user