From 7a1e6394831fb07e303c5ed0900dfe1ea4820de5 Mon Sep 17 00:00:00 2001 From: tobi <31960611+tsmethurst@users.noreply.github.com> Date: Wed, 24 Apr 2024 12:12:47 +0200 Subject: [PATCH] [chore] Refactor settings panel routing (and other fixes) (#2864) --- .vscode/settings.json | 13 +- web/source/index.js | 2 +- web/source/package.json | 8 +- .../admin/domain-permissions/index.tsx | 49 ----- .../settings/admin/emoji/category-select.jsx | 96 --------- .../settings/admin/emoji/local/overview.js | 153 ------------- web/source/settings/admin/settings/rules.tsx | 174 --------------- .../settings/components/account-list.tsx | 6 +- .../settings/components/back-button.jsx | 12 +- web/source/settings/index.js | 124 ----------- web/source/settings/index.tsx | 84 ++++++++ .../settings/lib/navigation/components.jsx | 201 ------------------ web/source/settings/lib/navigation/error.tsx | 98 +++++++++ web/source/settings/lib/navigation/index.js | 136 ------------ web/source/settings/lib/navigation/menu.tsx | 175 +++++++++++++++ web/source/settings/lib/navigation/util.ts | 45 +++- web/source/settings/lib/query/admin/index.ts | 13 +- web/source/settings/lib/types/custom-emoji.ts | 8 + .../local/index.tsx => lib/types/rules.ts} | 24 +-- web/source/settings/style.css | 23 +- .../admin/actions/keys/expireremote.tsx | 13 +- .../{ => views}/admin/actions/keys/index.tsx | 0 .../admin/actions/media/cleanup.tsx | 12 +- .../{ => views}/admin/actions/media/index.tsx | 0 .../views/admin/emoji/category-select.tsx | 134 ++++++++++++ .../admin/emoji/local/detail.tsx} | 54 +++-- .../admin/emoji/local/new-emoji.tsx | 20 +- .../views/admin/emoji/local/overview.tsx | 173 +++++++++++++++ .../admin/emoji/local/use-shortcode.ts} | 12 +- .../{ => views}/admin/emoji/remote/index.tsx | 26 +-- .../admin/emoji/remote/steal-this-look.tsx} | 26 +-- web/source/settings/views/admin/routes.tsx | 177 +++++++++++++++ .../{ => views}/admin/settings/index.tsx | 24 +-- .../settings/views/admin/settings/rules.tsx | 151 +++++++++++++ .../moderation}/accounts/detail/actions.tsx | 12 +- .../accounts/detail/handlesignup.tsx | 18 +- .../moderation}/accounts/detail/index.tsx | 52 ++--- .../moderation}/accounts/index.tsx | 16 +- .../moderation}/accounts/pending/index.tsx | 4 +- .../moderation}/accounts/search/index.tsx | 26 ++- .../moderation}/domain-permissions/detail.tsx | 68 +++--- .../export-format-table.tsx} | 8 +- .../moderation}/domain-permissions/form.tsx | 12 +- .../domain-permissions/import-export.tsx | 26 ++- .../domain-permissions/overview.tsx | 61 +++--- .../domain-permissions/process.tsx | 42 ++-- .../moderation}/reports/detail.tsx | 51 ++--- .../moderation/reports/overview.tsx} | 74 +++---- .../moderation}/reports/username.tsx | 0 .../settings/views/moderation/routes.tsx | 201 ++++++++++++++++++ .../settings/{ => views}/user/migration.tsx | 64 +++--- .../settings/{ => views}/user/profile.tsx | 22 +- web/source/settings/views/user/routes.tsx | 80 +++++++ .../settings/{ => views}/user/settings.tsx | 52 +++-- web/source/yarn.lock | 78 +++++-- 55 files changed, 1788 insertions(+), 1445 deletions(-) delete mode 100644 web/source/settings/admin/domain-permissions/index.tsx delete mode 100644 web/source/settings/admin/emoji/category-select.jsx delete mode 100644 web/source/settings/admin/emoji/local/overview.js delete mode 100644 web/source/settings/admin/settings/rules.tsx delete mode 100644 web/source/settings/index.js create mode 100644 web/source/settings/index.tsx delete mode 100644 web/source/settings/lib/navigation/components.jsx create mode 100644 web/source/settings/lib/navigation/error.tsx delete mode 100644 web/source/settings/lib/navigation/index.js create mode 100644 web/source/settings/lib/navigation/menu.tsx rename web/source/settings/{admin/emoji/local/index.tsx => lib/types/rules.ts} (70%) rename web/source/settings/{ => views}/admin/actions/keys/expireremote.tsx (85%) rename web/source/settings/{ => views}/admin/actions/keys/index.tsx (100%) rename web/source/settings/{ => views}/admin/actions/media/cleanup.tsx (84%) rename web/source/settings/{ => views}/admin/actions/media/index.tsx (100%) create mode 100644 web/source/settings/views/admin/emoji/category-select.tsx rename web/source/settings/{admin/emoji/local/detail.js => views/admin/emoji/local/detail.tsx} (74%) rename web/source/settings/{ => views}/admin/emoji/local/new-emoji.tsx (86%) create mode 100644 web/source/settings/views/admin/emoji/local/overview.tsx rename web/source/settings/{admin/emoji/local/use-shortcode.js => views/admin/emoji/local/use-shortcode.ts} (85%) rename web/source/settings/{ => views}/admin/emoji/remote/index.tsx (65%) rename web/source/settings/{admin/emoji/remote/parse-from-toot.tsx => views/admin/emoji/remote/steal-this-look.tsx} (87%) create mode 100644 web/source/settings/views/admin/routes.tsx rename web/source/settings/{ => views}/admin/settings/index.tsx (88%) create mode 100644 web/source/settings/views/admin/settings/rules.tsx rename web/source/settings/{admin => views/moderation}/accounts/detail/actions.tsx (86%) rename web/source/settings/{admin => views/moderation}/accounts/detail/handlesignup.tsx (85%) rename web/source/settings/{admin => views/moderation}/accounts/detail/index.tsx (78%) rename web/source/settings/{admin => views/moderation}/accounts/index.tsx (79%) rename web/source/settings/{admin => views/moderation}/accounts/pending/index.tsx (90%) rename web/source/settings/{admin => views/moderation}/accounts/search/index.tsx (82%) rename web/source/settings/{admin => views/moderation}/domain-permissions/detail.tsx (78%) rename web/source/settings/{admin/domain-permissions/export-format-table.jsx => views/moderation/domain-permissions/export-format-table.tsx} (91%) rename web/source/settings/{admin => views/moderation}/domain-permissions/form.tsx (92%) rename web/source/settings/{admin => views/moderation}/domain-permissions/import-export.tsx (79%) rename web/source/settings/{admin => views/moderation}/domain-permissions/overview.tsx (79%) rename web/source/settings/{admin => views/moderation}/domain-permissions/process.tsx (91%) rename web/source/settings/{admin => views/moderation}/reports/detail.tsx (87%) rename web/source/settings/{admin/reports/index.tsx => views/moderation/reports/overview.tsx} (63%) rename web/source/settings/{admin => views/moderation}/reports/username.tsx (100%) create mode 100644 web/source/settings/views/moderation/routes.tsx rename web/source/settings/{ => views}/user/migration.tsx (81%) rename web/source/settings/{ => views}/user/profile.tsx (92%) create mode 100644 web/source/settings/views/user/routes.tsx rename web/source/settings/{ => views}/user/settings.tsx (76%) diff --git a/.vscode/settings.json b/.vscode/settings.json index b2adc1cb8..beb76548d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,5 +10,14 @@ }, "eslint.workingDirectories": ["web/source"], "eslint.lintTask.enable": true, - "eslint.lintTask.options": "${workspaceFolder}/web/source" -} \ No newline at end of file + "eslint.lintTask.options": "${workspaceFolder}/web/source", + "eslint.validate": [ + "javascript", + "javascriptreact", + "typescript", + "typescriptreact" + ], + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + } +} diff --git a/web/source/index.js b/web/source/index.js index dcdb701ee..d9ef70ff9 100644 --- a/web/source/index.js +++ b/web/source/index.js @@ -78,7 +78,7 @@ skulk({ // commonjs here, no need for the typescript preset. ["babelify", { global: true, - ignore: [/node_modules\/(?!nanoid)/], + ignore: [/node_modules\/(?!(nanoid)|(wouter))/], }] ], presets: [ diff --git a/web/source/package.json b/web/source/package.json index 20f525228..d72cf7764 100644 --- a/web/source/package.json +++ b/web/source/package.json @@ -13,7 +13,6 @@ "dependencies": { "@reduxjs/toolkit": "^1.8.6", "ariakit": "^2.0.0-next.41", - "bluebird": "^3.7.2", "get-by-dot": "^1.0.2", "is-valid-domain": "^0.1.6", "js-file-download": "^0.4.12", @@ -33,9 +32,7 @@ "redux": "^4.2.0", "redux-persist": "^6.0.0", "skulk": "^0.0.8-fix", - "split-filter-n": "^1.1.3", - "syncpipe": "^1.0.0", - "wouter": "^2.8.0-alpha.2" + "wouter": "^3.1.0" }, "devDependencies": { "@babel/core": "^7.23.0", @@ -45,14 +42,13 @@ "@browserify/envify": "^6.0.0", "@browserify/uglifyify": "^6.0.0", "@joepie91/eslint-config": "^1.1.1", - "@types/bluebird": "^3.5.39", "@types/is-valid-domain": "^0.0.2", "@types/papaparse": "^5.3.9", "@types/psl": "^1.1.1", "@types/react-dom": "^18.2.8", "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", - "autoprefixer": "^10.4.13", + "autoprefixer": "^10.4.19", "babelify": "^10.0.0", "css-extract": "^2.0.0", "eslint": "^8.26.0", diff --git a/web/source/settings/admin/domain-permissions/index.tsx b/web/source/settings/admin/domain-permissions/index.tsx deleted file mode 100644 index 7d790cfc8..000000000 --- a/web/source/settings/admin/domain-permissions/index.tsx +++ /dev/null @@ -1,49 +0,0 @@ -/* - GoToSocial - Copyright (C) GoToSocial Authors admin@gotosocial.org - SPDX-License-Identifier: AGPL-3.0-or-later - - 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 . -*/ - -import React from "react"; -import { Switch, Route } from "wouter"; - -import DomainPermissionsOverview from "./overview"; -import { PermType } from "../../lib/types/domain-permission"; -import DomainPermDetail from "./detail"; - -export default function DomainPermissions({ baseUrl }: { baseUrl: string }) { - return ( - - - {params => ( - - )} - - - {params => ( - - )} - - - ); -} diff --git a/web/source/settings/admin/emoji/category-select.jsx b/web/source/settings/admin/emoji/category-select.jsx deleted file mode 100644 index e5cf29939..000000000 --- a/web/source/settings/admin/emoji/category-select.jsx +++ /dev/null @@ -1,96 +0,0 @@ -/* - GoToSocial - Copyright (C) GoToSocial Authors admin@gotosocial.org - SPDX-License-Identifier: AGPL-3.0-or-later - - 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 . -*/ - -const React = require("react"); -const splitFilterN = require("split-filter-n"); -const syncpipe = require('syncpipe'); -const { matchSorter } = require("match-sorter"); - -const ComboBox = require("../../components/combo-box"); -const { useListEmojiQuery } = require("../../lib/query/admin/custom-emoji"); - -function useEmojiByCategory(emoji) { - // split all emoji over an object keyed by the category names (or Unsorted) - return React.useMemo(() => splitFilterN( - emoji, - [], - (entry) => entry.category ?? "Unsorted" - ), [emoji]); -} - -function CategorySelect({ field, children }) { - const { value, setIsNew } = field; - - const { - data: emoji = [], - isLoading, - isSuccess, - error - } = useListEmojiQuery({ filter: "domain:local" }); - - const emojiByCategory = useEmojiByCategory(emoji); - - const categories = React.useMemo(() => new Set(Object.keys(emojiByCategory)), [emojiByCategory]); - - // data used by the ComboBox element to select an emoji category - const categoryItems = React.useMemo(() => { - return syncpipe(emojiByCategory, [ - (_) => Object.keys(_), // just emoji category names - (_) => matchSorter(_, value, { threshold: matchSorter.rankings.NO_MATCH }), // sorted by complex algorithm - (_) => _.map((categoryName) => [ // map to input value, and selectable element with icon - categoryName, - <> - - {categoryName} - - ]) - ]); - }, [emojiByCategory, value]); - - React.useEffect(() => { - if (value != undefined && isSuccess && value.trim().length > 0) { - setIsNew(!categories.has(value.trim())); - } - }, [categories, value, isSuccess, setIsNew]); - - if (error) { // fall back to plain text input, but this would almost certainly have caused a bigger error message elsewhere - return ( - <> - { field.value = e.target.value; }} />; - - ); - } else if (isLoading) { - return ; - } - - return ( - - ); -} - -module.exports = { - useEmojiByCategory, - CategorySelect -}; \ No newline at end of file diff --git a/web/source/settings/admin/emoji/local/overview.js b/web/source/settings/admin/emoji/local/overview.js deleted file mode 100644 index 45bfd614d..000000000 --- a/web/source/settings/admin/emoji/local/overview.js +++ /dev/null @@ -1,153 +0,0 @@ -/* - GoToSocial - Copyright (C) GoToSocial Authors admin@gotosocial.org - SPDX-License-Identifier: AGPL-3.0-or-later - - 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 . -*/ - -const React = require("react"); -const { Link } = require("wouter"); -const syncpipe = require("syncpipe"); -const { matchSorter } = require("match-sorter"); - -const NewEmojiForm = require("./new-emoji").default; -const { useTextInput } = require("../../../lib/form"); - -const { useEmojiByCategory } = require("../category-select"); -const { useBaseUrl } = require("../../../lib/navigation/util"); - -const Loading = require("../../../components/loading"); -const { Error } = require("../../../components/error"); -const { TextInput } = require("../../../components/form/inputs"); -const { useListEmojiQuery } = require("../../../lib/query/admin/custom-emoji"); - -module.exports = function EmojiOverview({ }) { - const { - data: emoji = [], - isLoading, - isError, - error - } = useListEmojiQuery({ filter: "domain:local" }); - - let content = null; - - if (isLoading) { - content = ; - } else if (isError) { - content = ; - } else { - content = ( - <> - - - - ); - } - - return ( - <> -

Local Custom Emoji

-

- To use custom emoji in your toots they have to be 'local' to the instance. - You can either upload them here directly, or copy from those already - present on other (known) instances through the Remote Emoji page. -

-

- Be warned! If you upload more than about 300-400 custom emojis in - total on your instance, this may lead to rate-limiting issues for users and clients - if they try to load all the emoji images at once (which is what many clients do). -

- {content} - - ); -}; - -function EmojiList({ emoji }) { - const filterField = useTextInput("filter"); - const filter = filterField.value; - - const emojiByCategory = useEmojiByCategory(emoji); - - /* Filter emoji based on shortcode match with user input, hiding empty categories */ - const { filteredEmoji, hidden } = React.useMemo(() => { - let hidden = emoji.length; - const filteredEmoji = syncpipe(emojiByCategory, [ - (_) => Object.entries(emojiByCategory), - (_) => _.map(([category, entries]) => { - let filteredEntries = matchSorter(entries, filter, { keys: ["shortcode"] }); - if (filteredEntries.length == 0) { - return null; - } else { - hidden -= filteredEntries.length; - return [category, filteredEntries]; - } - }), - (_) => _.filter((value) => value !== null) - ]); - - return { filteredEmoji, hidden }; - }, [filter, emojiByCategory, emoji.length]); - - return ( -
-

Overview

- {emoji.length > 0 - ? {emoji.length} custom emoji {hidden > 0 && `(${hidden} filtered)`} - : No custom emoji yet, you can add one below. - } -
-
- -
-
- {filteredEmoji.length > 0 - ? ( -
- {filteredEmoji.map(([category, entries]) => { - return ; - })} -
- ) - :
No local emoji matched your filter.
- } -
-
-
- ); -} - -function EmojiCategory({ category, entries }) { - const baseUrl = useBaseUrl(); - return ( -
- {category} -
- {entries.map((e) => { - return ( - - - {e.shortcode} - - - ); - })} -
-
- ); -} \ No newline at end of file diff --git a/web/source/settings/admin/settings/rules.tsx b/web/source/settings/admin/settings/rules.tsx deleted file mode 100644 index e5e4d17c5..000000000 --- a/web/source/settings/admin/settings/rules.tsx +++ /dev/null @@ -1,174 +0,0 @@ -/* - GoToSocial - Copyright (C) GoToSocial Authors admin@gotosocial.org - SPDX-License-Identifier: AGPL-3.0-or-later - - 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 . -*/ - -import React from "react"; -import { Switch, Route, Link, Redirect, useRoute } from "wouter"; - -import { useInstanceRulesQuery, useAddInstanceRuleMutation, useUpdateInstanceRuleMutation, useDeleteInstanceRuleMutation } from "../../lib/query"; -import FormWithData from "../../lib/form/form-with-data"; -import { useBaseUrl } from "../../lib/navigation/util"; - -import { useValue, useTextInput } from "../../lib/form"; -import useFormSubmit from "../../lib/form/submit"; - -import { TextArea } from "../../components/form/inputs"; -import MutationButton from "../../components/form/mutation-button"; -import { Error } from "../../components/error"; - -export default function InstanceRulesData({ baseUrl }) { - return ( - - ); -} - -function InstanceRules({ baseUrl, data: rules }) { - return ( - - - - - -
-

Instance Rules

-
-

- The rules for your instance are listed on the about page, and can be selected when submitting reports. -

-
- -
-
-
- ); -} - -function InstanceRuleList({ rules }) { - const newRule = useTextInput("text", {}); - - const [submitForm, result] = useFormSubmit({ newRule }, useAddInstanceRuleMutation(), { - changedOnly: true, - onFinish: () => newRule.reset() - }); - - return ( - <> -
-
    - {Object.values(rules).map((rule: any) => ( - - ))} -
-