Clean setting
This commit is contained in:
parent
96649fef63
commit
df890379ca
5 changed files with 144 additions and 143 deletions
|
@ -1,4 +1,7 @@
|
|||
export default {
|
||||
// Settings
|
||||
SETTING_SET_SETTINGS: 'setting.set.settings',
|
||||
SETTING_SHOW_ERROR: 'setting.show.error',
|
||||
SETTING_SWITCH_TO_FORM: 'setting.switch.to.form',
|
||||
SETTING_SWITCH_TO_JSON: 'setting.switch.to.json',
|
||||
};
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import actions from 'settings/actions';
|
||||
import messages from 'shared/messages';
|
||||
import DefaultSettings from 'shared/settings/default';
|
||||
import * as settingsStorage from 'shared/settings/storage';
|
||||
import * as validator from 'shared/settings/validator';
|
||||
import KeymapsForm from '../components/form/keymaps-form';
|
||||
import * as settingsValues from 'shared/settings/values';
|
||||
import * as settingsStorage from 'shared/settings/storage';
|
||||
|
||||
const load = async() => {
|
||||
let settings = await settingsStorage.loadRaw();
|
||||
|
@ -10,6 +11,18 @@ const load = async() => {
|
|||
};
|
||||
|
||||
const save = async(settings) => {
|
||||
try {
|
||||
if (settings.source === 'json') {
|
||||
let value = JSON.parse(settings.json);
|
||||
validator.validate(value);
|
||||
}
|
||||
} catch (e) {
|
||||
return {
|
||||
type: actions.SETTING_SHOW_ERROR,
|
||||
error: e.toString(),
|
||||
json: settings.json,
|
||||
};
|
||||
}
|
||||
await settingsStorage.save(settings);
|
||||
await browser.runtime.sendMessage({
|
||||
type: messages.SETTINGS_RELOAD
|
||||
|
@ -17,21 +30,39 @@ const save = async(settings) => {
|
|||
return set(settings);
|
||||
};
|
||||
|
||||
const set = (settings) => {
|
||||
let value = JSON.parse(DefaultSettings.json);
|
||||
if (settings.source === 'json') {
|
||||
value = settingsValues.valueFromJson(settings.json);
|
||||
} else if (settings.source === 'form') {
|
||||
value = settingsValues.valueFromForm(settings.form);
|
||||
const switchToForm = (json) => {
|
||||
try {
|
||||
validator.validate(JSON.parse(json));
|
||||
// AllowdOps filters operations, this is dirty dependency
|
||||
let form = settingsValues.formFromJson(json, KeymapsForm.AllowdOps);
|
||||
return {
|
||||
type: actions.SETTING_SWITCH_TO_FORM,
|
||||
form,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
type: actions.SETTING_SHOW_ERROR,
|
||||
error: e.toString(),
|
||||
json,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const switchToJson = (form) => {
|
||||
let json = settingsValues.jsonFromForm(form);
|
||||
return {
|
||||
type: actions.SETTING_SWITCH_TO_JSON,
|
||||
json,
|
||||
};
|
||||
};
|
||||
|
||||
const set = (settings) => {
|
||||
return {
|
||||
type: actions.SETTING_SET_SETTINGS,
|
||||
source: settings.source,
|
||||
json: settings.json,
|
||||
form: settings.form,
|
||||
value,
|
||||
};
|
||||
};
|
||||
|
||||
export { load, save };
|
||||
export { load, save, switchToForm, switchToJson };
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import './site.scss';
|
||||
import { h, Component } from 'preact';
|
||||
import { connect } from 'preact-redux';
|
||||
import Input from './ui/input';
|
||||
import SearchForm from './form/search-form';
|
||||
import KeymapsForm from './form/keymaps-form';
|
||||
|
@ -7,63 +8,36 @@ import BlacklistForm from './form/blacklist-form';
|
|||
import PropertiesForm from './form/properties-form';
|
||||
import * as properties from 'shared/settings/properties';
|
||||
import * as settingActions from 'settings/actions/setting';
|
||||
import * as validator from 'shared/settings/validator';
|
||||
import * as settingsValues from 'shared/settings/values';
|
||||
|
||||
const DO_YOU_WANT_TO_CONTINUE =
|
||||
'Some settings in JSON can be lost when migrating. ' +
|
||||
'Do you want to continue?';
|
||||
|
||||
class SettingsComponent extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
settings: {
|
||||
json: '',
|
||||
},
|
||||
errors: {
|
||||
json: '',
|
||||
}
|
||||
};
|
||||
this.context.store.subscribe(this.stateChanged.bind(this));
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.context.store.dispatch(settingActions.load());
|
||||
this.props.dispatch(settingActions.load());
|
||||
}
|
||||
|
||||
stateChanged() {
|
||||
let settings = this.context.store.getState();
|
||||
this.setState({
|
||||
settings: {
|
||||
source: settings.source,
|
||||
json: settings.json,
|
||||
form: settings.form,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
renderFormFields() {
|
||||
renderFormFields(form) {
|
||||
return <div>
|
||||
<fieldset>
|
||||
<legend>Keybindings</legend>
|
||||
<KeymapsForm
|
||||
value={this.state.settings.form.keymaps}
|
||||
value={form.keymaps}
|
||||
onChange={value => this.bindForm('keymaps', value)}
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Search Engines</legend>
|
||||
<SearchForm
|
||||
value={this.state.settings.form.search}
|
||||
value={form.search}
|
||||
onChange={value => this.bindForm('search', value)}
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Blacklist</legend>
|
||||
<BlacklistForm
|
||||
value={this.state.settings.form.blacklist}
|
||||
value={form.blacklist}
|
||||
onChange={value => this.bindForm('blacklist', value)}
|
||||
/>
|
||||
</fieldset>
|
||||
|
@ -71,33 +45,33 @@ class SettingsComponent extends Component {
|
|||
<legend>Properties</legend>
|
||||
<PropertiesForm
|
||||
types={properties.types}
|
||||
value={this.state.settings.form.properties}
|
||||
value={form.properties}
|
||||
onChange={value => this.bindForm('properties', value)}
|
||||
/>
|
||||
</fieldset>
|
||||
</div>;
|
||||
}
|
||||
|
||||
renderJsonFields() {
|
||||
renderJsonFields(json, error) {
|
||||
return <div>
|
||||
<Input
|
||||
type='textarea'
|
||||
name='json'
|
||||
label='Plain JSON'
|
||||
spellCheck='false'
|
||||
error={this.state.errors.json}
|
||||
onChange={this.bindValue.bind(this)}
|
||||
value={this.state.settings.json}
|
||||
error={error}
|
||||
onChange={this.bindJson.bind(this)}
|
||||
value={json}
|
||||
/>
|
||||
</div>;
|
||||
}
|
||||
|
||||
render() {
|
||||
let fields = null;
|
||||
if (this.state.settings.source === 'form') {
|
||||
fields = this.renderFormFields();
|
||||
} else if (this.state.settings.source === 'json') {
|
||||
fields = this.renderJsonFields();
|
||||
if (this.props.source === 'form') {
|
||||
fields = this.renderFormFields(this.props.form);
|
||||
} else if (this.props.source === 'json') {
|
||||
fields = this.renderJsonFields(this.props.json, this.props.error);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
|
@ -108,7 +82,7 @@ class SettingsComponent extends Component {
|
|||
id='setting-source-form'
|
||||
name='source'
|
||||
label='Use form'
|
||||
checked={this.state.settings.source === 'form'}
|
||||
checked={this.props.source === 'form'}
|
||||
value='form'
|
||||
onChange={this.bindSource.bind(this)} />
|
||||
|
||||
|
@ -116,7 +90,7 @@ class SettingsComponent extends Component {
|
|||
type='radio'
|
||||
name='source'
|
||||
label='Use plain JSON'
|
||||
checked={this.state.settings.source === 'json'}
|
||||
checked={this.props.source === 'json'}
|
||||
value='json'
|
||||
onChange={this.bindSource.bind(this)} />
|
||||
|
||||
|
@ -126,98 +100,44 @@ class SettingsComponent extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
validate(target) {
|
||||
if (target.name === 'json') {
|
||||
let settings = JSON.parse(target.value);
|
||||
validator.validate(settings);
|
||||
}
|
||||
}
|
||||
|
||||
validateValue(e) {
|
||||
let next = { ...this.state };
|
||||
|
||||
next.errors.json = '';
|
||||
try {
|
||||
this.validate(e.target);
|
||||
} catch (err) {
|
||||
next.errors.json = err.message;
|
||||
}
|
||||
next.settings[e.target.name] = e.target.value;
|
||||
}
|
||||
|
||||
bindForm(name, value) {
|
||||
let next = { ...this.state,
|
||||
settings: { ...this.state.settings,
|
||||
form: { ...this.state.settings.form }}};
|
||||
next.settings.form[name] = value;
|
||||
this.setState(next);
|
||||
this.context.store.dispatch(settingActions.save(next.settings));
|
||||
let settings = {
|
||||
source: this.props.source,
|
||||
json: this.props.json,
|
||||
form: { ...this.props.form },
|
||||
};
|
||||
settings.form[name] = value;
|
||||
this.props.dispatch(settingActions.save(settings));
|
||||
}
|
||||
|
||||
bindValue(e) {
|
||||
let next = { ...this.state };
|
||||
let error = false;
|
||||
|
||||
next.errors.json = '';
|
||||
try {
|
||||
this.validate(e.target);
|
||||
} catch (err) {
|
||||
next.errors.json = err.message;
|
||||
error = true;
|
||||
}
|
||||
next.settings[e.target.name] = e.target.value;
|
||||
|
||||
this.setState(this.state);
|
||||
if (!error) {
|
||||
this.context.store.dispatch(settingActions.save(next.settings));
|
||||
}
|
||||
}
|
||||
|
||||
migrateToForm() {
|
||||
let b = window.confirm(DO_YOU_WANT_TO_CONTINUE);
|
||||
if (!b) {
|
||||
this.setState(this.state);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
validator.validate(JSON.parse(this.state.settings.json));
|
||||
} catch (err) {
|
||||
this.setState(this.state);
|
||||
return;
|
||||
}
|
||||
|
||||
let form = settingsValues.formFromJson(
|
||||
this.state.settings.json, KeymapsForm.AllowdOps);
|
||||
let next = { ...this.state };
|
||||
next.settings.form = form;
|
||||
next.settings.source = 'form';
|
||||
next.errors.json = '';
|
||||
|
||||
this.setState(next);
|
||||
this.context.store.dispatch(settingActions.save(next.settings));
|
||||
}
|
||||
|
||||
migrateToJson() {
|
||||
let json = settingsValues.jsonFromForm(this.state.settings.form);
|
||||
let next = { ...this.state };
|
||||
next.settings.json = json;
|
||||
next.settings.source = 'json';
|
||||
next.errors.json = '';
|
||||
|
||||
this.setState(next);
|
||||
this.context.store.dispatch(settingActions.save(next.settings));
|
||||
bindJson(e) {
|
||||
let settings = {
|
||||
source: this.props.source,
|
||||
json: e.target.value,
|
||||
form: this.props.form,
|
||||
};
|
||||
this.props.dispatch(settingActions.save(settings));
|
||||
}
|
||||
|
||||
bindSource(e) {
|
||||
let from = this.state.settings.source;
|
||||
let from = this.props.source;
|
||||
let to = e.target.value;
|
||||
|
||||
if (from === 'form' && to === 'json') {
|
||||
this.migrateToJson();
|
||||
this.props.dispatch(settingActions.switchToJson(this.props.form));
|
||||
} else if (from === 'json' && to === 'form') {
|
||||
this.migrateToForm();
|
||||
let b = window.confirm(DO_YOU_WANT_TO_CONTINUE);
|
||||
if (!b) {
|
||||
return;
|
||||
}
|
||||
this.props.dispatch(settingActions.switchToForm(this.props.json));
|
||||
}
|
||||
|
||||
let settings = this.context.store.getState();
|
||||
this.props.dispatch(settingActions.save(settings));
|
||||
}
|
||||
}
|
||||
|
||||
export default SettingsComponent;
|
||||
const mapStateToProps = state => state;
|
||||
|
||||
export default connect(mapStateToProps)(SettingsComponent);
|
||||
|
|
|
@ -4,20 +4,33 @@ const defaultState = {
|
|||
source: '',
|
||||
json: '',
|
||||
form: null,
|
||||
value: {}
|
||||
error: '',
|
||||
};
|
||||
|
||||
export default function reducer(state = defaultState, action = {}) {
|
||||
switch (action.type) {
|
||||
case actions.SETTING_SET_SETTINGS:
|
||||
return {
|
||||
return { ...state,
|
||||
source: action.source,
|
||||
json: action.json,
|
||||
form: action.form,
|
||||
value: action.value,
|
||||
};
|
||||
errors: '',
|
||||
error: '', };
|
||||
case actions.SETTING_SHOW_ERROR:
|
||||
return { ...state,
|
||||
error: action.text,
|
||||
json: action.json, };
|
||||
case actions.SETTING_SWITCH_TO_FORM:
|
||||
return { ...state,
|
||||
error: '',
|
||||
source: 'form',
|
||||
form: action.form, };
|
||||
case actions.SETTING_SWITCH_TO_JSON:
|
||||
return { ...state,
|
||||
error: '',
|
||||
source: 'json',
|
||||
json: action.json, };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +1,55 @@
|
|||
import actions from 'settings/actions';
|
||||
import settingReducer from 'settings/reducers/setting';
|
||||
|
||||
describe("setting reducer", () => {
|
||||
describe("settings setting reducer", () => {
|
||||
it('return the initial state', () => {
|
||||
let state = settingReducer(undefined, {});
|
||||
expect(state).to.have.deep.property('json', '');
|
||||
expect(state).to.have.deep.property('value', {});
|
||||
expect(state).to.have.deep.property('form', null);
|
||||
expect(state).to.have.deep.property('error', '');
|
||||
});
|
||||
|
||||
it('return next state for SETTING_SET_SETTINGS', () => {
|
||||
let action = {
|
||||
type: actions.SETTING_SET_SETTINGS,
|
||||
source: 'json',
|
||||
json: '{ "key": "value" }',
|
||||
value: { key: 123 },
|
||||
form: {},
|
||||
};
|
||||
let state = settingReducer(undefined, action);
|
||||
expect(state).to.have.deep.property('source', 'json');
|
||||
expect(state).to.have.deep.property('json', '{ "key": "value" }');
|
||||
expect(state).to.have.deep.property('value', { key: 123 });
|
||||
expect(state).to.have.deep.property('form', {});
|
||||
});
|
||||
|
||||
it('return next state for SETTING_SHOW_ERROR', () => {
|
||||
let action = {
|
||||
type: actions.SETTING_SHOW_ERROR,
|
||||
text: 'bad value',
|
||||
json: '{}',
|
||||
};
|
||||
let state = settingReducer(undefined, action);
|
||||
expect(state).to.have.deep.property('error', 'bad value');
|
||||
expect(state).to.have.deep.property('json', '{}');
|
||||
});
|
||||
|
||||
it('return next state for SETTING_SWITCH_TO_FORM', () => {
|
||||
let action = {
|
||||
type: actions.SETTING_SWITCH_TO_FORM,
|
||||
form: {},
|
||||
};
|
||||
let state = settingReducer(undefined, action);
|
||||
expect(state).to.have.deep.property('form', {});
|
||||
expect(state).to.have.deep.property('source', 'form');
|
||||
});
|
||||
|
||||
it('return next state for SETTING_SWITCH_TO_JSON', () => {
|
||||
let action = {
|
||||
type: actions.SETTING_SWITCH_TO_JSON,
|
||||
json: '{}',
|
||||
};
|
||||
let state = settingReducer(undefined, action);
|
||||
expect(state).to.have.deep.property('json', '{}');
|
||||
expect(state).to.have.deep.property('source', 'json');
|
||||
});
|
||||
});
|
||||
|
|
Reference in a new issue