summaryrefslogtreecommitdiff
path: root/web/source/panels/admin/settings.js
diff options
context:
space:
mode:
authorLibravatar f0x52 <f0x@cthu.lu>2022-06-09 12:51:19 +0200
committerLibravatar GitHub <noreply@github.com>2022-06-09 12:51:19 +0200
commitb43f9ceca9f7e02248f1d88245ede5267e8b72c8 (patch)
tree1d6b64603e74c45785bf44dde194315344843e1e /web/source/panels/admin/settings.js
parent[chore] gitignore shell.nix (#639) (diff)
downloadgotosocial-b43f9ceca9f7e02248f1d88245ede5267e8b72c8.tar.xz
[frontend] Restructure Frontend Sources (#634)
* 🐸restructure frontend stuff, include admin and future user panel in main repo, properly deduplicate bundles for css+js across uses * rename bundled to dist, caught by gitignore * re-include status.css for profile template * default to localhost * serve frontend panels * add todo message for abstraction * refactor oauth registration flow * oauth restructure * update footer template * change panel routes * remove superfluous css imports * write bundle to disk from test server, use forked budo-express * wrap all page content in container for robustness with addons etc injection other elements in body * update documentation, goreleaser, Dockerfile * update template meta tags * add AGPL-3.0+ license header everywhere * only attach update listener on EventEmitter * cleaner config for various frontend bundles * fix bundler script paths * Merge commit 'd191931932b9293ce1be44ed08a1e69b9fcc1e25' * fix up dockerfile, goreleaser * go mod tidy * add uglifyify * move status hide/show js to frontend bundle * fix stylesheet color( func regressions * update contributing docs for new build path * update goreleaser + docker building * resolve dependency paths properly * update package name * use api errorhandler Co-authored-by: tsmethurst <tobi.smethurst@protonmail.com>
Diffstat (limited to 'web/source/panels/admin/settings.js')
-rw-r--r--web/source/panels/admin/settings.js175
1 files changed, 175 insertions, 0 deletions
diff --git a/web/source/panels/admin/settings.js b/web/source/panels/admin/settings.js
new file mode 100644
index 000000000..2a10951a7
--- /dev/null
+++ b/web/source/panels/admin/settings.js
@@ -0,0 +1,175 @@
+/*
+ GoToSocial
+ Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+"use strict";
+
+const Promise = require("bluebird");
+const React = require("react");
+
+module.exports = function Settings({oauth}) {
+ const [info, setInfo] = React.useState({});
+ const [errorMsg, setError] = React.useState("");
+ const [statusMsg, setStatus] = React.useState("Fetching instance info");
+
+ React.useEffect(() => {
+ Promise.try(() => {
+ return oauth.apiRequest("/api/v1/instance", "GET");
+ }).then((json) => {
+ setInfo(json);
+ }).catch((e) => {
+ setError(e.message);
+ setStatus("");
+ });
+ }, []);
+
+ function submit() {
+ setStatus("PATCHing");
+ setError("");
+ return Promise.try(() => {
+ let formDataInfo = new FormData();
+ Object.entries(info).forEach(([key, val]) => {
+ if (key == "contact_account") {
+ key = "contact_username";
+ val = val.username;
+ }
+ if (key == "email") {
+ key = "contact_email";
+ }
+ if (typeof val != "object") {
+ formDataInfo.append(key, val);
+ }
+ });
+ return oauth.apiRequest("/api/v1/instance", "PATCH", formDataInfo, "form");
+ }).then((json) => {
+ setStatus("Config saved");
+ console.log(json);
+ }).catch((e) => {
+ setError(e.message);
+ setStatus("");
+ });
+ }
+
+ return (
+ <section className="info login">
+ <h1>Instance Information <button onClick={submit}>Save</button></h1>
+ <div className="error accent">
+ {errorMsg}
+ </div>
+ <div>
+ {statusMsg}
+ </div>
+ <form onSubmit={(e) => e.preventDefault()}>
+ {editableObject(info)}
+ </form>
+ </section>
+ );
+};
+
+function editableObject(obj, path=[]) {
+ const readOnlyKeys = ["uri", "version", "urls_streaming_api", "stats"];
+ const hiddenKeys = ["contact_account_", "urls"];
+ const explicitShownKeys = ["contact_account_username"];
+ const implementedKeys = "title, contact_account_username, email, short_description, description, terms, avatar, header".split(", ");
+
+ let listing = Object.entries(obj).map(([key, val]) => {
+ let fullkey = [...path, key].join("_");
+
+ if (
+ hiddenKeys.includes(fullkey) ||
+ hiddenKeys.includes(path.join("_")+"_") // also match just parent path
+ ) {
+ if (!explicitShownKeys.includes(fullkey)) {
+ return null;
+ }
+ }
+
+ if (Array.isArray(val)) {
+ // FIXME: handle this
+ } else if (typeof val == "object") {
+ return (<React.Fragment key={fullkey}>
+ {editableObject(val, [...path, key])}
+ </React.Fragment>);
+ }
+
+ let isImplemented = "";
+ if (!implementedKeys.includes(fullkey)) {
+ isImplemented = " notImplemented";
+ }
+
+ let isReadOnly = (
+ readOnlyKeys.includes(fullkey) ||
+ readOnlyKeys.includes(path.join("_")) ||
+ isImplemented != ""
+ );
+
+ let label = key.replace(/_/g, " ");
+ if (path.length > 0) {
+ label = `\u00A0`.repeat(4 * path.length) + label;
+ }
+
+ let inputProps;
+ let changeFunc;
+ if (val === true || val === false) {
+ inputProps = {
+ type: "checkbox",
+ defaultChecked: val,
+ disabled: isReadOnly
+ };
+ changeFunc = (e) => e.target.checked;
+ } else if (val.length != 0 && !isNaN(val)) {
+ inputProps = {
+ type: "number",
+ defaultValue: val,
+ readOnly: isReadOnly
+ };
+ changeFunc = (e) => e.target.value;
+ } else {
+ inputProps = {
+ type: "text",
+ defaultValue: val,
+ readOnly: isReadOnly
+ };
+ changeFunc = (e) => e.target.value;
+ }
+
+ function setRef(element) {
+ if (element != null) {
+ element.addEventListener("change", (e) => {
+ obj[key] = changeFunc(e);
+ });
+ }
+ }
+
+ return (
+ <React.Fragment key={fullkey}>
+ <label htmlFor={key} className="capitalize">{label}</label>
+ <div className={isImplemented}>
+ <input className={isImplemented} ref={setRef} {...inputProps} />
+ </div>
+ </React.Fragment>
+ );
+ });
+ return (
+ <React.Fragment>
+ {path != "" &&
+ <><b>{path}:</b> <span id="filler"></span></>
+ }
+ {listing}
+ </React.Fragment>
+ );
+} \ No newline at end of file