FeaturesEditor: allow saving changes

features
Alex Gleason 2023-01-13 21:37:18 -06:00
rodzic ef86b27435
commit 829bbc7f48
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
6 zmienionych plików z 80 dodań i 30 usunięć

Wyświetl plik

@ -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;

Wyświetl plik

@ -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;

Wyświetl plik

@ -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>

Wyświetl plik

@ -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} />

Wyświetl plik

@ -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');
}

Wyświetl plik

@ -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>;