From 9b139b632098e6741b10fa87ff6224dcb5045947 Mon Sep 17 00:00:00 2001 From: f0x52 Date: Wed, 18 Jan 2023 14:45:14 +0100 Subject: [frogend] Settings refactor (#1318) * yakshave new form field structure * fully refactor user profile settings form * use rtk query api for profile settings * refactor user post settings * refactor password change form * refactor admin settings * FormWithData structure for user forms * admin actions refactor * whitespace * fix user settings data prop * remove superfluous logging * cleanup old code * refactor federation/suspend (overview, detail) * mostly abstracted (emoji) checkbox list * refactor parse-from-toot * refactor custom-emoji, progress on federation bulk * loading icon styling to prevent big spinny * refactor federation import-export interface * cleanup old files * [chore] Update/add license headers for 2023 * redux fixes * text-field exports * appease the linter * refactor authentication with RTK Query * fix login/logout state transition weirdness * fixes/cleanup * small linter-related fixes * add eslint license header check, fix existing files * remove old code, clarify comment * clarify suspend on subdomains * collapse if/else * fa-fw width info comment --- .../settings/components/authorization/index.jsx | 76 ++++++++++ .../settings/components/authorization/login.jsx | 67 +++++++++ web/source/settings/components/back-button.jsx | 2 +- web/source/settings/components/check-list.jsx | 58 +++++++ web/source/settings/components/combo-box.jsx | 8 +- web/source/settings/components/error.jsx | 45 +++++- web/source/settings/components/fake-profile.jsx | 17 +-- web/source/settings/components/fake-toot.jsx | 13 +- web/source/settings/components/form-fields.jsx | 167 --------------------- web/source/settings/components/form/combobox.jsx | 41 ----- web/source/settings/components/form/file.jsx | 78 ---------- web/source/settings/components/form/index.js | 37 ----- web/source/settings/components/form/inputs.jsx | 141 +++++++++++++++++ .../settings/components/form/mutation-button.jsx | 49 ++++++ web/source/settings/components/form/text.jsx | 56 ------- web/source/settings/components/loading.jsx | 2 +- web/source/settings/components/login.jsx | 102 ------------- web/source/settings/components/mutation-button.jsx | 42 ------ web/source/settings/components/nav-button.jsx | 2 +- web/source/settings/components/submit.jsx | 35 ----- 20 files changed, 456 insertions(+), 582 deletions(-) create mode 100644 web/source/settings/components/authorization/index.jsx create mode 100644 web/source/settings/components/authorization/login.jsx create mode 100644 web/source/settings/components/check-list.jsx delete mode 100644 web/source/settings/components/form-fields.jsx delete mode 100644 web/source/settings/components/form/combobox.jsx delete mode 100644 web/source/settings/components/form/file.jsx delete mode 100644 web/source/settings/components/form/index.js create mode 100644 web/source/settings/components/form/inputs.jsx create mode 100644 web/source/settings/components/form/mutation-button.jsx delete mode 100644 web/source/settings/components/form/text.jsx delete mode 100644 web/source/settings/components/login.jsx delete mode 100644 web/source/settings/components/mutation-button.jsx delete mode 100644 web/source/settings/components/submit.jsx (limited to 'web/source/settings/components') diff --git a/web/source/settings/components/authorization/index.jsx b/web/source/settings/components/authorization/index.jsx new file mode 100644 index 000000000..8bcf68e09 --- /dev/null +++ b/web/source/settings/components/authorization/index.jsx @@ -0,0 +1,76 @@ +/* + GoToSocial + Copyright (C) 2021-2023 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 . +*/ + +"use strict"; + +const React = require("react"); +const Redux = require("react-redux"); + +const query = require("../../lib/query"); + +const Login = require("./login"); +const Loading = require("../loading"); +const { Error } = require("../error"); + +module.exports = function Authorization({ App }) { + const loginState = Redux.useSelector((state) => state.oauth.loginState); + const [hasStoredLogin] = React.useState(loginState != "none" && loginState != "logout"); + + const { isLoading, isSuccess, data: account, error } = query.useVerifyCredentialsQuery(undefined, { + skip: loginState == "none" || loginState == "logout" + }); + + let showLogin = true; + let content = null; + + if (isLoading && hasStoredLogin) { + showLogin = false; + + let loadingInfo; + if (loginState == "callback") { + loadingInfo = "Processing OAUTH callback."; + } else if (loginState == "login") { + loadingInfo = "Verifying stored login."; + } + + content = ( +
+ {loadingInfo} +
+ ); + } else if (error != undefined) { + content = ( +
+ + You can attempt logging in again below: +
+ ); + } + + if (loginState == "login" && isSuccess) { + return ; + } else { + return ( +
+

GoToSocial Settings

+ {content} + {showLogin && } +
+ ); + } +}; \ No newline at end of file diff --git a/web/source/settings/components/authorization/login.jsx b/web/source/settings/components/authorization/login.jsx new file mode 100644 index 000000000..3115c5da2 --- /dev/null +++ b/web/source/settings/components/authorization/login.jsx @@ -0,0 +1,67 @@ +/* + GoToSocial + Copyright (C) 2021-2023 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 . +*/ + +"use strict"; + +const React = require("react"); + +const query = require("../../lib/query"); +const { useTextInput, useValue } = require("../../lib/form"); +const useFormSubmit = require("../../lib/form/submit"); +const { TextInput } = require("../form/inputs"); +const MutationButton = require("../form/mutation-button"); +const Loading = require("../loading"); + +module.exports = function Login({ }) { + const form = { + instance: useTextInput("instance", { + defaultValue: window.location.origin + }), + scopes: useValue("scopes", "user admin") + }; + + const [formSubmit, result] = useFormSubmit( + form, + query.useAuthorizeFlowMutation(), + { changedOnly: false } + ); + + if (result.isLoading) { + return ( +
+ Checking instance. +
+ ); + } else if (result.isSuccess) { + return ( +
+ Redirecting to instance authorization page. +
+ ); + } + + return ( +
+ + + + ); +}; \ No newline at end of file diff --git a/web/source/settings/components/back-button.jsx b/web/source/settings/components/back-button.jsx index d95f82a73..9e849dee0 100644 --- a/web/source/settings/components/back-button.jsx +++ b/web/source/settings/components/back-button.jsx @@ -21,7 +21,7 @@ const React = require("react"); const { Link } = require("wouter"); -module.exports = function BackButton({to}) { +module.exports = function BackButton({ to }) { return ( < back diff --git a/web/source/settings/components/check-list.jsx b/web/source/settings/components/check-list.jsx new file mode 100644 index 000000000..1276d5dbf --- /dev/null +++ b/web/source/settings/components/check-list.jsx @@ -0,0 +1,58 @@ +/* + GoToSocial + Copyright (C) 2021-2023 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 . +*/ + +"use strict"; + +const React = require("react"); + +module.exports = function CheckList({ field, Component, header = " All", ...componentProps }) { + return ( +
+ + {Object.values(field.value).map((entry) => ( + field.onChange(entry.key, value)} + entry={entry} + Component={Component} + componentProps={componentProps} + /> + ))} +
+ ); +}; + +function CheckListEntry({ entry, onChange, Component, componentProps }) { + return ( + + ); +} \ No newline at end of file diff --git a/web/source/settings/components/combo-box.jsx b/web/source/settings/components/combo-box.jsx index 07d4abb6c..aaa56daac 100644 --- a/web/source/settings/components/combo-box.jsx +++ b/web/source/settings/components/combo-box.jsx @@ -26,21 +26,21 @@ const { ComboboxPopover, } = require("ariakit/combobox"); -module.exports = function ComboBox({state, items, label, placeHolder, children}) { +module.exports = function ComboBox({ field, items, label, children, ...inputProps }) { return (
- + {items.map(([key, value]) => ( {value} diff --git a/web/source/settings/components/error.jsx b/web/source/settings/components/error.jsx index 5d808c467..bc64bf9ec 100644 --- a/web/source/settings/components/error.jsx +++ b/web/source/settings/components/error.jsx @@ -20,7 +20,7 @@ const React = require("react"); -module.exports = function ErrorFallback({error, resetErrorBoundary}) { +function ErrorFallback({ error, resetErrorBoundary }) { return (

@@ -28,7 +28,7 @@ module.exports = function ErrorFallback({error, resetErrorBoundary}) { GoToSocial issue tracker {" or "} Matrix support room. -
Include the details below: +
Include the details below:

 				{error.name}: {error.message}
@@ -41,4 +41,43 @@ module.exports = function ErrorFallback({error, resetErrorBoundary}) {
 			

); -}; \ No newline at end of file +} + +function Error({ error }) { + /* eslint-disable-next-line no-console */ + console.error("Rendering error:", error); + let message; + + if (error.data != undefined) { // RTK Query error with data + if (error.status) { + message = (<> + {error.status}: {error.data.error} + {error.data.error_description && +

+ {error.data.error_description} +

+ } + ); + } else { + message = error.data.error; + } + } else if (error.name != undefined || error.type != undefined) { // JS error + message = (<> + {error.type && error.name}: {error.message} + ); + } else if (error.status && typeof error.error == "string") { + message = (<> + {error.status}: {error.error} + ); + } else { + message = error.message ?? error; + } + + return ( +
+ {message} +
+ ); +} + +module.exports = { ErrorFallback, Error }; \ No newline at end of file diff --git a/web/source/settings/components/fake-profile.jsx b/web/source/settings/components/fake-profile.jsx index 8afccf2cc..c326605d9 100644 --- a/web/source/settings/components/fake-profile.jsx +++ b/web/source/settings/components/fake-profile.jsx @@ -19,24 +19,21 @@ "use strict"; const React = require("react"); -const Redux = require("react-redux"); - -module.exports = function FakeProfile({}) { - const account = Redux.useSelector(state => state.user.profile); +module.exports = function FakeProfile({ avatar, header, display_name, username, role }) { return ( // Keep in sync with web/template/profile.tmpl
- {account.header + {header
- {account.avatar -
{account.display_name.trim().length > 0 ? account.display_name : account.username}
+ {avatar +
{display_name.trim().length > 0 ? display_name : username}
-
@{account.username}
- {(account.role && account.role != "user") && -
{account.role}
+
@{username}
+ {(role && role != "user") && +
{role}
}
diff --git a/web/source/settings/components/fake-toot.jsx b/web/source/settings/components/fake-toot.jsx index 836ac62f8..b6e05154e 100644 --- a/web/source/settings/components/fake-toot.jsx +++ b/web/source/settings/components/fake-toot.jsx @@ -19,16 +19,21 @@ "use strict"; const React = require("react"); -const Redux = require("react-redux"); -module.exports = function FakeToot({children}) { - const account = Redux.useSelector((state) => state.user.profile); +const query = require("../lib/query"); + +module.exports = function FakeToot({ children }) { + const { data: account = { + avatar: "/assets/default_avatars/GoToSocial_icon1.png", + display_name: "", + username: "" + } } = query.useVerifyCredentialsQuery(); return (
- + {account.display_name.trim().length > 0 ? account.display_name : account.username} @{account.username} diff --git a/web/source/settings/components/form-fields.jsx b/web/source/settings/components/form-fields.jsx deleted file mode 100644 index 7b393b3ef..000000000 --- a/web/source/settings/components/form-fields.jsx +++ /dev/null @@ -1,167 +0,0 @@ -/* - GoToSocial - Copyright (C) 2021-2023 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 . -*/ - -"use strict"; - -const React = require("react"); -const Redux = require("react-redux"); -const d = require("dotty"); -const prettierBytes = require("prettier-bytes"); - -function eventListeners(dispatch, setter, obj) { - return { - onTextChange: function (key) { - return function (e) { - dispatch(setter([key, e.target.value])); - }; - }, - - onCheckChange: function (key) { - return function (e) { - dispatch(setter([key, e.target.checked])); - }; - }, - - onFileChange: function (key, withPreview) { - return function (e) { - let file = e.target.files[0]; - if (withPreview) { - let old = d.get(obj, key); - if (old != undefined) { - URL.revokeObjectURL(old); // no error revoking a non-Object URL as provided by instance - } - let objectURL = URL.createObjectURL(file); - dispatch(setter([key, objectURL])); - } - dispatch(setter([`${key}File`, file])); - }; - } - }; -} - -function get(state, id, defaultVal) { - let value; - if (id.includes(".")) { - value = d.get(state, id); - } else { - value = state[id]; - } - if (value == undefined) { - value = defaultVal; - } - return value; -} - -// function removeFile(name) { -// return function(e) { -// e.preventDefault(); -// dispatch(user.setProfileVal([name, ""])); -// dispatch(user.setProfileVal([`${name}File`, ""])); -// }; -// } - -module.exports = { - formFields: function formFields(setter, selector) { - function FormField({ - type, id, name, className="", placeHolder="", fileType="", children=null, - options=null, inputProps={}, withPreview=true, showSize=false, maxSize=Infinity - }) { - const dispatch = Redux.useDispatch(); - let state = Redux.useSelector(selector); - let { - onTextChange, - onCheckChange, - onFileChange - } = eventListeners(dispatch, setter, state); - - let field; - let defaultLabel = true; - if (type == "text") { - field = ; - } else if (type == "textarea") { - field =