feat(ui): save last used silence author to local storage

Silence form should default to last used author email so there's no need to re-type it all the time
This commit is contained in:
Łukasz Mierzwa
2018-09-08 11:03:07 +01:00
parent 8183f78b82
commit 69229c079c
8 changed files with 84 additions and 11 deletions

View File

@@ -50,6 +50,7 @@ const NavBar = observer(
<SilenceModal
alertStore={alertStore}
silenceFormStore={silenceFormStore}
settingsStore={settingsStore}
/>
<MainModal
alertStore={alertStore}

View File

@@ -55,7 +55,8 @@ const SilenceForm = observer(
class SilenceForm extends Component {
static propTypes = {
alertStore: PropTypes.object.isRequired,
silenceFormStore: PropTypes.object.isRequired
silenceFormStore: PropTypes.object.isRequired,
settingsStore: PropTypes.object.isRequired
};
// store preview visibility state here, by default preview is collapsed
@@ -72,11 +73,16 @@ const SilenceForm = observer(
);
componentDidMount() {
const { silenceFormStore } = this.props;
const { silenceFormStore, settingsStore } = this.props;
if (silenceFormStore.data.matchers.length === 0) {
silenceFormStore.data.addEmptyMatcher();
}
if (silenceFormStore.data.author === "") {
silenceFormStore.data.author =
settingsStore.silenceFormConfig.config.author;
}
}
addMore = action(event => {
@@ -98,10 +104,12 @@ const SilenceForm = observer(
});
handleSubmit = action(event => {
const { silenceFormStore } = this.props;
const { silenceFormStore, settingsStore } = this.props;
event.preventDefault();
settingsStore.silenceFormConfig.saveAuthor(silenceFormStore.data.author);
if (silenceFormStore.data.isValid)
silenceFormStore.data.inProgress = true;

View File

@@ -3,26 +3,37 @@ import React from "react";
import { mount, shallow } from "enzyme";
import { AlertStore } from "Stores/AlertStore";
import { Settings } from "Stores/Settings";
import { SilenceFormStore, NewEmptyMatcher } from "Stores/SilenceFormStore";
import { SilenceForm } from "./SilenceForm";
let alertStore;
let settingsStore;
let silenceFormStore;
beforeEach(() => {
alertStore = new AlertStore([]);
settingsStore = new Settings();
silenceFormStore = new SilenceFormStore();
});
const ShallowSilenceForm = () => {
return shallow(
<SilenceForm alertStore={alertStore} silenceFormStore={silenceFormStore} />
<SilenceForm
alertStore={alertStore}
silenceFormStore={silenceFormStore}
settingsStore={settingsStore}
/>
);
};
const MountedSilenceForm = () => {
return mount(
<SilenceForm alertStore={alertStore} silenceFormStore={silenceFormStore} />
<SilenceForm
alertStore={alertStore}
silenceFormStore={silenceFormStore}
settingsStore={settingsStore}
/>
);
};
@@ -105,6 +116,22 @@ describe("<SilenceForm /> preview", () => {
});
describe("<SilenceForm /> inputs", () => {
it("default author value comes from Settings store", () => {
settingsStore.silenceFormConfig.config.author = "foo@example.com";
const tree = MountedSilenceForm();
const input = tree.find("input[placeholder='Author email']");
expect(input.props().value).toBe("foo@example.com");
expect(silenceFormStore.data.author).toBe("foo@example.com");
});
it("default author value is empty if nothing is stored in Settings", () => {
settingsStore.silenceFormConfig.config.author = "";
const tree = MountedSilenceForm();
const input = tree.find("input[placeholder='Author email']");
expect(input.text()).toBe("");
expect(silenceFormStore.data.author).toBe("");
});
it("changing author input updates SilenceFormStore", () => {
const tree = MountedSilenceForm();
const input = tree.find("input[placeholder='Author email']");
@@ -141,4 +168,13 @@ describe("<SilenceForm />", () => {
tree.simulate("submit", { preventDefault: jest.fn() });
expect(silenceFormStore.data.inProgress).toBe(true);
});
it("calling submit saves author value to the Settings store", () => {
silenceFormStore.data.author = "user@example.com";
const tree = ShallowSilenceForm();
tree.simulate("submit", { preventDefault: jest.fn() });
expect(settingsStore.silenceFormConfig.config.author).toBe(
"user@example.com"
);
});
});

View File

@@ -13,7 +13,8 @@ const SilenceModalContent = observer(
class SilenceModalContent extends Component {
static propTypes = {
alertStore: PropTypes.object.isRequired,
silenceFormStore: PropTypes.object.isRequired
silenceFormStore: PropTypes.object.isRequired,
settingsStore: PropTypes.object.isRequired
};
componentDidMount() {
@@ -25,7 +26,7 @@ const SilenceModalContent = observer(
}
render() {
const { alertStore, silenceFormStore } = this.props;
const { alertStore, silenceFormStore, settingsStore } = this.props;
return ReactDOM.createPortal(
<div className="modal d-block bg-primary-transparent-80" role="dialog">
@@ -50,6 +51,7 @@ const SilenceModalContent = observer(
<SilenceForm
alertStore={alertStore}
silenceFormStore={silenceFormStore}
settingsStore={settingsStore}
/>
)}
</div>

View File

@@ -3,14 +3,17 @@ import React from "react";
import { shallow } from "enzyme";
import { AlertStore } from "Stores/AlertStore";
import { Settings } from "Stores/Settings";
import { SilenceFormStore } from "Stores/SilenceFormStore";
import { SilenceModalContent } from "./SilenceModalContent";
let alertStore;
let settingsStore;
let silenceFormStore;
beforeEach(() => {
alertStore = new AlertStore([]);
settingsStore = new Settings();
silenceFormStore = new SilenceFormStore();
});
@@ -18,6 +21,7 @@ const ShallowSilenceModalContent = () => {
return shallow(
<SilenceModalContent
alertStore={alertStore}
settingsStore={settingsStore}
silenceFormStore={silenceFormStore}
/>
);

View File

@@ -14,7 +14,8 @@ const SilenceModal = observer(
class SilenceModal extends Component {
static propTypes = {
alertStore: PropTypes.object.isRequired,
silenceFormStore: PropTypes.object.isRequired
silenceFormStore: PropTypes.object.isRequired,
settingsStore: PropTypes.object.isRequired
};
componentDidUpdate() {
@@ -31,7 +32,7 @@ const SilenceModal = observer(
}
render() {
const { alertStore, silenceFormStore } = this.props;
const { alertStore, silenceFormStore, settingsStore } = this.props;
return (
<React.Fragment>
@@ -47,6 +48,7 @@ const SilenceModal = observer(
<SilenceModalContent
alertStore={alertStore}
silenceFormStore={silenceFormStore}
settingsStore={settingsStore}
/>
) : null}
</React.Fragment>

View File

@@ -3,26 +3,37 @@ import React from "react";
import { shallow, mount } from "enzyme";
import { AlertStore } from "Stores/AlertStore";
import { Settings } from "Stores/Settings";
import { SilenceFormStore } from "Stores/SilenceFormStore";
import { SilenceModal } from ".";
let alertStore;
let settingsStore;
let silenceFormStore;
beforeEach(() => {
alertStore = new AlertStore([]);
settingsStore = new Settings();
silenceFormStore = new SilenceFormStore();
});
const ShallowSilenceModal = () => {
return shallow(
<SilenceModal alertStore={alertStore} silenceFormStore={silenceFormStore} />
<SilenceModal
alertStore={alertStore}
silenceFormStore={silenceFormStore}
settingsStore={settingsStore}
/>
);
};
const MountedSilenceModal = () => {
return mount(
<SilenceModal alertStore={alertStore} silenceFormStore={silenceFormStore} />
<SilenceModal
alertStore={alertStore}
silenceFormStore={silenceFormStore}
settingsStore={settingsStore}
/>
);
};

View File

@@ -46,11 +46,20 @@ class AlertGroupConfig {
});
}
class SilenceFormConfig {
config = localStored("silenceFormConfig", { author: "" }, { delay: 100 });
saveAuthor = action(newAuthor => {
this.config.author = newAuthor;
});
}
class Settings {
constructor() {
this.savedFilters = new SavedFilters();
this.fetchConfig = new FetchConfig();
this.alertGroupConfig = new AlertGroupConfig();
this.silenceFormConfig = new SilenceFormConfig();
}
}