diff options
author | 2023-01-18 14:45:14 +0100 | |
---|---|---|
committer | 2023-01-18 14:45:14 +0100 | |
commit | 9b139b632098e6741b10fa87ff6224dcb5045947 (patch) | |
tree | c72b5c666ed01db7d1a18e531e5e01e07f504a46 /web/source/settings/admin/federation.js | |
parent | [chore] Change default sqlite busy timeout to 5m (#1352) (diff) | |
download | gotosocial-9b139b632098e6741b10fa87ff6224dcb5045947.tar.xz |
[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
Diffstat (limited to 'web/source/settings/admin/federation.js')
-rw-r--r-- | web/source/settings/admin/federation.js | 394 |
1 files changed, 0 insertions, 394 deletions
diff --git a/web/source/settings/admin/federation.js b/web/source/settings/admin/federation.js deleted file mode 100644 index b7658f444..000000000 --- a/web/source/settings/admin/federation.js +++ /dev/null @@ -1,394 +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 <http://www.gnu.org/licenses/>. -*/ - -"use strict"; - -const Promise = require("bluebird"); -const React = require("react"); -const Redux = require("react-redux"); -const {Switch, Route, Link, Redirect, useRoute, useLocation} = require("wouter"); -const fileDownload = require("js-file-download"); - -const { formFields } = require("../components/form-fields"); - -const api = require("../lib/api"); -const adminActions = require("../redux/reducers/admin").actions; -const submit = require("../lib/submit"); -const BackButton = require("../components/back-button"); -const Loading = require("../components/loading"); -const { matchSorter } = require("match-sorter"); - -const base = "/settings/admin/federation"; - -// const { -// TextInput, -// TextArea, -// File -// } = require("../components/form-fields").formFields(adminActions.setAdminSettingsVal, (state) => state.instances.adminSettings); - -module.exports = function AdminSettings() { - const dispatch = Redux.useDispatch(); - // const instance = Redux.useSelector(state => state.instances.adminSettings); - const loadedBlockedInstances = Redux.useSelector(state => state.admin.loadedBlockedInstances); - - React.useEffect(() => { - if (!loadedBlockedInstances ) { - Promise.try(() => { - return dispatch(api.admin.fetchDomainBlocks()); - }); - } - }, [dispatch, loadedBlockedInstances]); - - if (!loadedBlockedInstances) { - return ( - <div> - <h1>Federation</h1> - <div> - <Loading/> - </div> - </div> - ); - } - - return ( - <Switch> - <Route path={`${base}/:domain`}> - <InstancePageWrapped /> - </Route> - <InstanceOverview /> - </Switch> - ); -}; - -function InstanceOverview() { - const [filter, setFilter] = React.useState(""); - const blockedInstances = Redux.useSelector(state => state.admin.blockedInstances); - const [_location, setLocation] = useLocation(); - - const filteredInstances = React.useMemo(() => { - return matchSorter(Object.values(blockedInstances), filter, {keys: ["domain"]}); - }, [blockedInstances, filter]); - - function filterFormSubmit(e) { - e.preventDefault(); - setLocation(`${base}/${filter}`); - } - - return ( - <> - <h1>Federation</h1> - Here you can see an overview of blocked instances. - - <div className="instance-list"> - <h2>Blocked instances</h2> - <form action={`${base}/view`} className="filter" role="search" onSubmit={filterFormSubmit}> - <input name="domain" value={filter} onChange={(e) => setFilter(e.target.value)}/> - <Link to={`${base}/${filter}`}><a className="button">Add block</a></Link> - </form> - <div className="list"> - {filteredInstances.map((entry) => { - return ( - <Link key={entry.domain} to={`${base}/${entry.domain}`}> - <a className="entry nounderline"> - <span id="domain"> - {entry.domain} - </span> - <span id="date"> - {new Date(entry.created_at).toLocaleString()} - </span> - </a> - </Link> - ); - })} - </div> - </div> - - <BulkBlocking/> - </> - ); -} - -const Bulk = formFields(adminActions.updateBulkBlockVal, (state) => state.admin.bulkBlock); -function BulkBlocking() { - const dispatch = Redux.useDispatch(); - const {bulkBlock, blockedInstances} = Redux.useSelector(state => state.admin); - - const [errorMsg, setError] = React.useState(""); - const [statusMsg, setStatus] = React.useState(""); - - function importBlocks() { - setStatus("Processing"); - setError(""); - return Promise.try(() => { - return dispatch(api.admin.bulkDomainBlock()); - }).then(({success, invalidDomains}) => { - return Promise.try(() => { - return resetBulk(); - }).then(() => { - dispatch(adminActions.updateBulkBlockVal(["list", invalidDomains.join("\n")])); - - let stat = ""; - if (success == 0) { - return setError("No valid domains in import"); - } else if (success == 1) { - stat = "Imported 1 domain"; - } else { - stat = `Imported ${success} domains`; - } - - if (invalidDomains.length > 0) { - if (invalidDomains.length == 1) { - stat += ", input contained 1 invalid domain."; - } else { - stat += `, input contained ${invalidDomains.length} invalid domains.`; - } - } else { - stat += "!"; - } - - setStatus(stat); - }); - }).catch((e) => { - console.error(e); - setError(e.message); - setStatus(""); - }); - } - - function exportBlocks() { - return Promise.try(() => { - setStatus("Exporting"); - setError(""); - let asJSON = bulkBlock.exportType.startsWith("json"); - let _asCSV = bulkBlock.exportType.startsWith("csv"); - - let exportList = Object.values(blockedInstances).map((entry) => { - if (asJSON) { - return { - domain: entry.domain, - public_comment: entry.public_comment - }; - } else { - return entry.domain; - } - }); - - if (bulkBlock.exportType == "json") { - return dispatch(adminActions.updateBulkBlockVal(["list", JSON.stringify(exportList)])); - } else if (bulkBlock.exportType == "json-download") { - return fileDownload(JSON.stringify(exportList), "block-export.json"); - } else if (bulkBlock.exportType == "plain") { - return dispatch(adminActions.updateBulkBlockVal(["list", exportList.join("\n")])); - } - }).then(() => { - setStatus("Exported!"); - }).catch((e) => { - setError(e.message); - setStatus(""); - }); - } - - function resetBulk(e) { - if (e != undefined) { - e.preventDefault(); - } - return dispatch(adminActions.resetBulkBlockVal()); - } - - function disableInfoFields(props={}) { - if (bulkBlock.list[0] == "[") { - return { - ...props, - disabled: true, - placeHolder: "Domain list is a JSON import, input disabled" - }; - } else { - return props; - } - } - - return ( - <div className="bulk"> - <h2>Import / Export <a onClick={resetBulk}>reset</a></h2> - <Bulk.TextArea - id="list" - name="Domains, one per line" - placeHolder={`google.com\nfacebook.com`} - /> - - <Bulk.TextArea - id="public_comment" - name="Public comment" - inputProps={disableInfoFields({rows: 3})} - /> - - <Bulk.TextArea - id="private_comment" - name="Private comment" - inputProps={disableInfoFields({rows: 3})} - /> - - <Bulk.Checkbox - id="obfuscate" - name="Obfuscate domains? " - inputProps={disableInfoFields()} - /> - - <div className="hidden"> - <Bulk.File - id="json" - fileType="application/json" - withPreview={false} - /> - </div> - - <div className="messagebutton"> - <div> - <button type="submit" onClick={importBlocks}>Import</button> - </div> - - <div> - <button type="submit" onClick={exportBlocks}>Export</button> - - <Bulk.Select id="exportType" name="Export type" options={ - <> - <option value="plain">One per line in text field</option> - <option value="json">JSON in text field</option> - <option value="json-download">JSON file download</option> - <option disabled value="csv">CSV in text field (glitch-soc)</option> - <option disabled value="csv-download">CSV file download (glitch-soc)</option> - </> - }/> - </div> - <br/> - <div> - {errorMsg.length > 0 && - <div className="error accent">{errorMsg}</div> - } - {statusMsg.length > 0 && - <div className="accent">{statusMsg}</div> - } - </div> - </div> - </div> - ); -} - -function InstancePageWrapped() { - /* We wrap the component to generate formFields with a setter depending on the domain - if formFields() is used inside the same component that is re-rendered with their state, - inputs get re-created on every change, causing them to lose focus, and bad performance - */ - let [_match, {domain}] = useRoute(`${base}/:domain`); - - if (domain == "view") { // from form field submission - let realDomain = (new URL(document.location)).searchParams.get("domain"); - if (realDomain == undefined) { - return <Redirect to={base}/>; - } else { - domain = realDomain; - } - } - - function alterDomain([key, val]) { - return adminActions.updateDomainBlockVal([domain, key, val]); - } - - const fields = formFields(alterDomain, (state) => state.admin.newInstanceBlocks[domain]); - - return <InstancePage domain={domain} Form={fields} />; -} - -function InstancePage({domain, Form}) { - const dispatch = Redux.useDispatch(); - const entry = Redux.useSelector(state => state.admin.newInstanceBlocks[domain]); - const [_location, setLocation] = useLocation(); - - React.useEffect(() => { - if (entry == undefined) { - dispatch(api.admin.getEditableDomainBlock(domain)); - } - }, [dispatch, domain, entry]); - - const [errorMsg, setError] = React.useState(""); - const [statusMsg, setStatus] = React.useState(""); - - if (entry == undefined) { - return <Loading/>; - } - - const updateBlock = submit( - () => dispatch(api.admin.updateDomainBlock(domain)), - {setStatus, setError} - ); - - const removeBlock = submit( - () => dispatch(api.admin.removeDomainBlock(domain)), - {setStatus, setError, startStatus: "Removing", successStatus: "Removed!", onSuccess: () => { - setLocation(base); - }} - ); - - return ( - <div> - <h1><BackButton to={base}/> Federation settings for: {domain}</h1> - {entry.new - ? "No stored block yet, you can add one below:" - : <b className="error">Editing domain blocks is not implemented yet, <a href="https://github.com/superseriousbusiness/gotosocial/issues/1198" target="_blank" rel="noopener noreferrer">check here for progress</a>.</b> - } - - <Form.TextArea - id="public_comment" - name="Public comment" - inputProps={{ - disabled: !entry.new - }} - /> - - <Form.TextArea - id="private_comment" - name="Private comment" - inputProps={{ - disabled: !entry.new - }} - /> - - <Form.Checkbox - id="obfuscate" - name="Obfuscate domain? " - inputProps={{ - disabled: !entry.new - }} - /> - - <div className="messagebutton"> - {entry.new - ? <button type="submit" onClick={updateBlock}>{entry.new ? "Add block" : "Save block"}</button> - : <button className="danger" onClick={removeBlock}>Remove block</button> - } - - {errorMsg.length > 0 && - <div className="error accent">{errorMsg}</div> - } - {statusMsg.length > 0 && - <div className="accent">{statusMsg}</div> - } - </div> - </div> - ); -}
\ No newline at end of file |