import {useCallback, useContext, useEffect, useState} from "react";
import {LocaleContext} from "shared/locale";
import {
Box, Button, Checkbox,
CircularProgress, FormControl, FormControlLabel,
FormGroup, FormLabel, Grid, IconButton,
Paper, Select, styled,
Tab,
Table,
TableBody,
TableCell,
TableHead,
TableContainer,
TableRow,
Tabs, TextField,
Autocomplete,
Chip
} from "@mui/material";
import {Link} from "react-router-dom";
import {
Add,
Delete,
Google,
LibraryBooks,
Mail,
RestartAlt,
Save,
Send,
SettingsApplications
} from "@mui/icons-material";
import TIME_ZONES from "shared/time-zones";
import ButtonBar from "../elements/button-bar";
const SettingsFormGroup = styled(FormGroup)((props) => ({
marginBottom: props.theme.spacing(1),
}));
export default function SettingsView(props) {
// meta
const api = props.api;
const showDialog = props.showDialog;
const {translate: L, requestModules, currentLocale} = useContext(LocaleContext);
const KNOWN_SETTING_KEYS = {
"general": [
"base_url",
"site_name",
"user_registration_enabled",
"time_zone",
"allowed_extensions",
"trusted_domains",
],
"mail": [
"mail_enabled",
"mail_footer",
"mail_from",
"mail_host",
"mail_port",
"mail_username",
"mail_password",
"mail_async",
],
"recaptcha": [
"recaptcha_enabled",
"recaptcha_private_key",
"recaptcha_public_key",
],
"hidden": ["installation_completed", "mail_last_sync"]
};
// data
const [fetchSettings, setFetchSettings] = useState(true);
const [settings, setSettings] = useState(null);
const [extra, setExtra] = useState({});
const [uncategorizedKeys, setUncategorizedKeys] = useState([]);
// ui
const [selectedTab, setSelectedTab] = useState("general");
const [hasChanged, setChanged] = useState(false);
const [isSaving, setSaving] = useState(false);
const [newKey, setNewKey] = useState("");
const [testMailAddress, setTestMailAddress] = useState("");
const [isSending, setSending] = useState(false);
const isUncategorized = (key) => {
return !(Object.values(KNOWN_SETTING_KEYS).reduce((acc, arr) => {
return [ ...acc, ...arr ];
}, [])).includes(key);
}
useEffect(() => {
requestModules(props.api, ["general", "settings"], currentLocale).then(data => {
if (!data.success) {
showDialog("Error fetching translations: " + data.msg);
}
});
}, [currentLocale]);
const onFetchSettings = useCallback((force = false) => {
if (fetchSettings || force) {
setFetchSettings(false);
api.getSettings().then(data => {
if (!data.success) {
showDialog(data.msg, L("settings.fetch_settings_error"));
} else {
setSettings(Object.keys(data.settings)
.filter(key => !KNOWN_SETTING_KEYS.hidden.includes(key))
.reduce((obj, key) => {
obj[key] = data.settings[key];
return obj;
}, {})
);
setUncategorizedKeys(Object.keys(data.settings).filter(key => isUncategorized(key)));
}
});
}
}, [api, showDialog, fetchSettings]);
useEffect(() => {
onFetchSettings();
}, [fetchSettings]);
const onChangeValue = useCallback((key, value) => {
setChanged(true);
setSettings({...settings, [key]: value});
}, [settings]);
const onSaveSettings = useCallback(() => {
setSaving(true);
api.saveSettings(settings).then(data => {
setSaving(false);
if (data.success) {
showDialog(L("settings.save_settings_success"), L("general.success"));
setChanged(false);
} else {
showDialog(data.msg, L("settings.save_settings_error"));
}
});
}, [api, showDialog, settings]);
const onDeleteKey = useCallback(key => {
if (key && settings.hasOwnProperty(key)) {
let index = uncategorizedKeys.indexOf(key);
if (index !== -1) {
let newUncategorizedKeys = [...uncategorizedKeys];
newUncategorizedKeys.splice(index, 1);
setUncategorizedKeys(newUncategorizedKeys);
}
setChanged(true);
setSettings({...settings, [key]: null});
}
}, [settings, uncategorizedKeys]);
const onAddKey = useCallback(key => {
if (key) {
if (!isUncategorized(key) || !settings.hasOwnProperty(key) || settings[key] === null) {
setChanged(true);
setSettings({...settings, [key]: ""});
setUncategorizedKeys([...uncategorizedKeys, key]);
setNewKey("");
} else {
showDialog("This key is already defined", L("general.error"));
}
}
}, [settings, uncategorizedKeys, showDialog]);
const onChangeKey = useCallback((oldKey, newKey) => {
if (settings.hasOwnProperty(oldKey) && !settings.hasOwnProperty(newKey)) {
let newSettings = {...settings, [newKey]: settings[oldKey]};
delete newSettings[oldKey];
setChanged(true);
setSettings(newSettings);
}
}, [settings]);
const onSendTestMail = useCallback(() => {
if (!isSending) {
setSending(true);
api.sendTestMail(testMailAddress).then(data => {
setSending(false);
if (!data.success) {
showDialog(<>
{data.msg}
{data.output}
>, L("settings.send_test_email_error"));
} else {
showDialog(L("settings.send_test_email_success"), L("general.success"));
setTestMailAddress("");
}
});
}
}, [api, showDialog, testMailAddress, isSending]);
const onReset = useCallback(() => {
setFetchSettings(true);
setNewKey("");
setChanged(false);
setExtra({});
}, []);
const parseBool = (v) => v !== undefined && (v === true || v === 1 || ["true", "1", "yes"].includes(v.toString().toLowerCase()));
const renderTextInput = (key_name, disabled=false, props={}) => {
return