sforkowany z mirror/soapbox
FeaturesEditor: allow saving changes
rodzic
ef86b27435
commit
829bbc7f48
|
@ -0,0 +1,60 @@
|
|||
import { Map as ImmutableMap } from 'immutable';
|
||||
import React, { useState } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { updateSoapboxConfig } from 'soapbox/actions/admin';
|
||||
import { getHost } from 'soapbox/actions/instance';
|
||||
import { fetchSoapboxConfig } from 'soapbox/actions/soapbox';
|
||||
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
|
||||
import toast from 'soapbox/toast';
|
||||
|
||||
import FeaturesPanel from '../features-panel';
|
||||
|
||||
const messages = defineMessages({
|
||||
saved: { id: 'features_editor.saved', defaultMessage: 'Features updated!' },
|
||||
});
|
||||
|
||||
interface IFeaturesEditor {
|
||||
}
|
||||
|
||||
/** Admin feature editor. */
|
||||
const FeaturesEditor: React.FC<IFeaturesEditor> = () => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
|
||||
const host = useAppSelector(state => getHost(state));
|
||||
const rawConfig = useAppSelector(state => state.soapbox);
|
||||
|
||||
const userFeatures: Record<string, boolean> = useAppSelector(state => {
|
||||
return (state.soapbox.get('features') || ImmutableMap()).toJS();
|
||||
});
|
||||
|
||||
const updateFeatures = async (features: Record<string, boolean>) => {
|
||||
const params = rawConfig.set('features', features).toJS();
|
||||
await dispatch(updateSoapboxConfig(params));
|
||||
};
|
||||
|
||||
const handleChange = async(features: Record<string, boolean>) => {
|
||||
setSubmitting(true);
|
||||
|
||||
try {
|
||||
await dispatch(fetchSoapboxConfig(host));
|
||||
await updateFeatures(features);
|
||||
toast.success(intl.formatMessage(messages.saved));
|
||||
setSubmitting(false);
|
||||
} catch (e) {
|
||||
setSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<FeaturesPanel
|
||||
features={userFeatures}
|
||||
onChange={handleChange}
|
||||
disabled={submitting}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default FeaturesEditor;
|
|
@ -1,21 +0,0 @@
|
|||
import { Map as ImmutableMap } from 'immutable';
|
||||
import React from 'react';
|
||||
|
||||
import { useSettings } from 'soapbox/hooks';
|
||||
|
||||
import FeaturesPanel from '../features-panel';
|
||||
|
||||
interface IFeaturesEditor {
|
||||
}
|
||||
|
||||
/** Developers feature editor. */
|
||||
const FeaturesEditor: React.FC<IFeaturesEditor> = () => {
|
||||
const settings = useSettings();
|
||||
const features = (settings.get('features') || ImmutableMap()).toJS() as Record<string, any>;
|
||||
|
||||
return (
|
||||
<FeaturesPanel features={features} />
|
||||
);
|
||||
};
|
||||
|
||||
export default FeaturesEditor;
|
|
@ -12,10 +12,15 @@ const messages = defineMessages({
|
|||
interface IFeaturesPanel {
|
||||
features: Record<string, boolean>,
|
||||
onChange?: (features: Record<string, boolean>) => void,
|
||||
disabled?: boolean,
|
||||
}
|
||||
|
||||
/** A UI for managing conditional feature flags. */
|
||||
const FeaturesPanel: React.FC<IFeaturesPanel> = ({ features: userFeatures, onChange }) => {
|
||||
const FeaturesPanel: React.FC<IFeaturesPanel> = ({
|
||||
features: userFeatures,
|
||||
onChange,
|
||||
disabled = false,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const autoFeatures = useFeatures();
|
||||
|
||||
|
@ -36,7 +41,11 @@ const FeaturesPanel: React.FC<IFeaturesPanel> = ({ features: userFeatures, onCha
|
|||
<List>
|
||||
{Object.keys(autoFeatures).map(key => (
|
||||
<ListItem label={key}>
|
||||
<Toggle checked={features[key]} onChange={handleChange(key)} />
|
||||
<Toggle
|
||||
checked={features[key]}
|
||||
onChange={handleChange(key)}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
|
|
|
@ -109,7 +109,7 @@ import {
|
|||
ThemeEditor,
|
||||
Quotes,
|
||||
ServiceWorkerInfo,
|
||||
DevelopersFeaturesEditor,
|
||||
FeaturesEditor,
|
||||
EventInformation,
|
||||
EventDiscussion,
|
||||
Events,
|
||||
|
@ -297,13 +297,13 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
|
|||
<WrappedRoute path='/soapbox/admin/reports' staffOnly page={AdminPage} component={Dashboard} content={children} exact />
|
||||
<WrappedRoute path='/soapbox/admin/log' staffOnly page={AdminPage} component={ModerationLog} content={children} exact />
|
||||
<WrappedRoute path='/soapbox/admin/users' staffOnly page={AdminPage} component={UserIndex} content={children} exact />
|
||||
<WrappedRoute path='/soapbox/admin/theme' staffOnly page={AdminPage} component={ThemeEditor} content={children} exact />
|
||||
<WrappedRoute path='/soapbox/admin/theme' adminOnly page={AdminPage} component={ThemeEditor} content={children} exact />
|
||||
<WrappedRoute path='/soapbox/admin/features' adminOnly page={AdminPage} component={FeaturesEditor} content={children} />
|
||||
<WrappedRoute path='/info' page={EmptyPage} component={ServerInfo} content={children} />
|
||||
|
||||
<WrappedRoute path='/developers/apps/create' developerOnly page={DefaultPage} component={CreateApp} content={children} />
|
||||
<WrappedRoute path='/developers/settings_store' developerOnly page={DefaultPage} component={SettingsStore} content={children} />
|
||||
<WrappedRoute path='/developers/timeline' developerOnly page={DefaultPage} component={TestTimeline} content={children} />
|
||||
<WrappedRoute path='/developers/features' developerOnly page={DefaultPage} component={DevelopersFeaturesEditor} content={children} />
|
||||
<WrappedRoute path='/developers/sw' developerOnly page={DefaultPage} component={ServiceWorkerInfo} content={children} />
|
||||
<WrappedRoute path='/developers' page={DefaultPage} component={Developers} content={children} />
|
||||
<WrappedRoute path='/error/network' developerOnly page={EmptyPage} component={() => new Promise((_resolve, reject) => reject())} content={children} />
|
||||
|
|
|
@ -310,6 +310,10 @@ export function ModerationLog() {
|
|||
return import(/* webpackChunkName: "features/admin/moderation_log" */'../../admin/moderation-log');
|
||||
}
|
||||
|
||||
export function FeaturesEditor() {
|
||||
return import(/* webpackChunkName: "features/admin" */'../../admin/features-editor');
|
||||
}
|
||||
|
||||
export function ThemeEditor() {
|
||||
return import(/* webpackChunkName: "features/theme-editor" */'../../theme-editor');
|
||||
}
|
||||
|
@ -474,10 +478,6 @@ export function ServiceWorkerInfo() {
|
|||
return import(/* webpackChunkName: "features/developers" */'../../developers/service-worker-info');
|
||||
}
|
||||
|
||||
export function DevelopersFeaturesEditor() {
|
||||
return import(/* webpackChunkName: "features/developers" */'../../developers/features-editor');
|
||||
}
|
||||
|
||||
export function DatePicker() {
|
||||
return import(/* webpackChunkName: "date_picker" */'../../birthdays/date-picker');
|
||||
}
|
||||
|
|
|
@ -120,6 +120,8 @@ export const SoapboxConfigRecord = ImmutableRecord({
|
|||
* On some platforms this can be too blurry without additional configuration.
|
||||
*/
|
||||
mediaPreview: false,
|
||||
/** Features overrides. */
|
||||
features: ImmutableMap<string, boolean>(),
|
||||
}, 'SoapboxConfig');
|
||||
|
||||
type SoapboxConfigMap = ImmutableMap<string, any>;
|
||||
|
|
Ładowanie…
Reference in New Issue