Developers: add ability to edit raw settings JSON

party-hat
Alex Gleason 2022-01-07 15:58:01 -06:00
rodzic c93c517586
commit d270e92927
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
6 zmienionych plików z 136 dodań i 1 usunięć

Wyświetl plik

@ -8,6 +8,7 @@ import { createSelector } from 'reselect';
export const SETTING_CHANGE = 'SETTING_CHANGE';
export const SETTING_SAVE = 'SETTING_SAVE';
export const SETTINGS_UPDATE = 'SETTINGS_UPDATE';
export const FE_NAME = 'soapbox_fe';

Wyświetl plik

@ -32,6 +32,16 @@ class Developers extends React.Component {
</div>
</Link>
</div>
<div className='dashcounter'>
<Link to='/developers/settings_store'>
<div className='dashcounter__icon'>
<Icon src={require('@tabler/icons/icons/code-plus.svg')} />
</div>
<div className='dashcounter__label'>
<FormattedMessage id='developers.navigation.settings_store_label' defaultMessage='Settings store' />
</div>
</Link>
</div>
<div className='dashcounter'>
<Link to='/error'>
<div className='dashcounter__icon'>

Wyświetl plik

@ -0,0 +1,111 @@
import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { injectIntl, FormattedMessage, defineMessages } from 'react-intl';
import Column from 'soapbox/features/ui/components/column';
import { SimpleForm, SimpleTextarea } from 'soapbox/features/forms';
import { showAlertForError } from 'soapbox/actions/alerts';
import { patchMe } from 'soapbox/actions/me';
import { FE_NAME, SETTINGS_UPDATE } from 'soapbox/actions/settings';
const isJSONValid = text => {
try {
JSON.parse(text);
return true;
} catch {
return false;
}
};
const messages = defineMessages({
heading: { id: 'column.settings_store', defaultMessage: 'Settings store' },
hint: { id: 'developers.settings_store.hint', defaultMessage: 'It is possible to directly edit your user settings here. BE CAREFUL! Editing this section can break your account, and you will only be able to recover through the API.' },
});
const mapStateToProps = state => {
return {
settingsStore: state.get('settings'),
};
};
export default @connect(mapStateToProps)
@injectIntl
class SettingsStore extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
settingsStore: ImmutablePropTypes.map.isRequired,
}
state = {
rawJSON: JSON.stringify(this.props.settingsStore, null, 2),
jsonValid: true,
isLoading: false,
}
componentDidUpdate(prevProps) {
const { settingsStore } = this.props;
if (settingsStore !== prevProps.settingsStore) {
this.setState({
rawJSON: JSON.stringify(settingsStore, null, 2),
jsonValid: true,
});
}
}
handleEditJSON = ({ target }) => {
const rawJSON = target.value;
this.setState({ rawJSON, jsonValid: isJSONValid(rawJSON) });
}
handleSubmit = e => {
const { dispatch } = this.props;
const { rawJSON } = this.state;
const settings = JSON.parse(rawJSON);
this.setState({ isLoading: true });
dispatch(patchMe({
pleroma_settings_store: {
[FE_NAME]: settings,
},
})).then(response => {
dispatch({ type: SETTINGS_UPDATE, settings });
this.setState({ isLoading: false });
}).catch(error => {
dispatch(showAlertForError(error));
this.setState({ isLoading: false });
});
}
render() {
const { intl } = this.props;
const { rawJSON, jsonValid, isLoading } = this.state;
return (
<Column heading={intl.formatMessage(messages.heading)}>
<SimpleForm onSubmit={this.handleSubmit} disabled={!jsonValid || isLoading}>
<div className={jsonValid ? 'code-editor' : 'code-editor code-editor--invalid'}>
<SimpleTextarea
hint={intl.formatMessage(messages.hint)}
value={rawJSON}
onChange={this.handleEditJSON}
disabled={isLoading}
rows={12}
/>
</div>
<div className='actions'>
<button name='button' type='submit' className='btn button button-primary' disabled={!jsonValid || isLoading}>
<FormattedMessage id='soapbox_config.save' defaultMessage='Save' />
</button>
</div>
</SimpleForm>
</Column>
);
}
}

Wyświetl plik

@ -116,6 +116,7 @@ import {
IntentionalError,
Developers,
CreateApp,
SettingsStore,
} from './util/async-components';
// Dummy import, to make sure that <Status /> ends up in the application bundle.
@ -322,6 +323,7 @@ class SwitchingColumnsArea extends React.PureComponent {
<WrappedRoute path='/info' page={EmptyPage} component={ServerInfo} content={children} />
<WrappedRoute path='/developers/apps/create' page={DefaultPage} component={CreateApp} content={children} />
<WrappedRoute path='/developers/settings_store' page={DefaultPage} component={SettingsStore} content={children} />
<WrappedRoute path='/developers' page={DefaultPage} component={Developers} content={children} />
<WrappedRoute path='/error' page={EmptyPage} component={IntentionalError} content={children} />

Wyświetl plik

@ -445,3 +445,7 @@ export function Developers() {
export function CreateApp() {
return import(/* webpackChunkName: "features/developers" */'../../developers/apps/create');
}
export function SettingsStore() {
return import(/* webpackChunkName: "features/developers" */'../../developers/settings_store');
}

Wyświetl plik

@ -1,4 +1,9 @@
import { SETTING_CHANGE, SETTING_SAVE, FE_NAME } from '../actions/settings';
import {
SETTING_CHANGE,
SETTING_SAVE,
SETTINGS_UPDATE,
FE_NAME,
} from '../actions/settings';
import { NOTIFICATIONS_FILTER_SET } from '../actions/notifications';
import { SEARCH_FILTER_SET } from '../actions/search';
import { EMOJI_USE } from '../actions/emojis';
@ -35,6 +40,8 @@ export default function settings(state = initialState, action) {
return updateFrequentEmojis(state, action.emoji);
case SETTING_SAVE:
return state.set('saved', true);
case SETTINGS_UPDATE:
return fromJS(action.settings);
default:
return state;
}