diff options
Diffstat (limited to 'web/source/settings/views/user')
| -rw-r--r-- | web/source/settings/views/user/export-import/export.tsx | 173 | ||||
| -rw-r--r-- | web/source/settings/views/user/export-import/index.tsx | 57 | ||||
| -rw-r--r-- | web/source/settings/views/user/menu.tsx | 5 | ||||
| -rw-r--r-- | web/source/settings/views/user/router.tsx | 3 | 
4 files changed, 238 insertions, 0 deletions
| diff --git a/web/source/settings/views/user/export-import/export.tsx b/web/source/settings/views/user/export-import/export.tsx new file mode 100644 index 000000000..70bda60f2 --- /dev/null +++ b/web/source/settings/views/user/export-import/export.tsx @@ -0,0 +1,173 @@ +/* +	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 <http://www.gnu.org/licenses/>. +*/ + +import React from "react"; +import { +	useExportFollowingMutation, +	useExportFollowersMutation, +	useExportListsMutation, +	useExportBlocksMutation, +	useExportMutesMutation, +} from "../../../lib/query/user/export-import"; +import MutationButton from "../../../components/form/mutation-button"; +import useFormSubmit from "../../../lib/form/submit"; +import { useValue } from "../../../lib/form"; +import { AccountExportStats } from "../../../lib/types/account"; + +export default function Export({ exportStats }: { exportStats: AccountExportStats }) { +	const [exportFollowing, exportFollowingResult] = useFormSubmit( +		// Use a dummy value. +		{ type: useValue("exportFollowing", "exportFollowing") }, +		// Mutation we're wrapping. +		useExportFollowingMutation(), +		// Form never changes but +		// we want to always trigger. +		{ changedOnly: false }, +	); + +	const [exportFollowers, exportFollowersResult] = useFormSubmit( +		// Use a dummy value. +		{ type: useValue("exportFollowers", "exportFollowers") }, +		// Mutation we're wrapping. +		useExportFollowersMutation(), +		// Form never changes but +		// we want to always trigger. +		{ changedOnly: false }, +	); + +	const [exportLists, exportListsResult] = useFormSubmit( +		// Use a dummy value. +		{ type: useValue("exportLists", "exportLists") }, +		// Mutation we're wrapping. +		useExportListsMutation(), +		// Form never changes but +		// we want to always trigger. +		{ changedOnly: false }, +	); + + +	const [exportBlocks, exportBlocksResult] = useFormSubmit( +		// Use a dummy value. +		{ type: useValue("exportBlocks", "exportBlocks") }, +		// Mutation we're wrapping. +		useExportBlocksMutation(), +		// Form never changes but +		// we want to always trigger. +		{ changedOnly: false }, +	); + +	const [exportMutes, exportMutesResult] = useFormSubmit( +		// Use a dummy value. +		{ type: useValue("exportMutes", "exportMutes") }, +		// Mutation we're wrapping. +		useExportMutesMutation(), +		// Form never changes but +		// we want to always trigger. +		{ changedOnly: false }, +	); +	 +	return ( +		<form className="export-data"> +			<div className="form-section-docs"> +				<h3>Export Data</h3> +				<a +					href="https://docs.gotosocial.org/en/latest/user_guide/export-import#export" +					target="_blank" +					className="docslink" +					rel="noreferrer" +				> +				Learn more about this section (opens in a new tab) +				</a> +			</div> +			 +			<div className="export-buttons-wrapper"> +				<div className="stats-and-button"> +					<span className="text-cutoff"> +						Following {exportStats.following_count} account{ exportStats.following_count !== 1 && "s" } +					</span> +					<MutationButton +						className="text-cutoff" +						label="Download following.csv" +						type="button" +						onClick={() => exportFollowing()} +						result={exportFollowingResult} +						showError={true} +						disabled={exportStats.following_count === 0} +					/> +				</div> +				<div className="stats-and-button"> +					<span className="text-cutoff"> +						Followed by {exportStats.followers_count} account{ exportStats.followers_count !== 1 && "s" } +					</span> +					<MutationButton +						className="text-cutoff" +						label="Download followers.csv" +						type="button" +						onClick={() => exportFollowers()} +						result={exportFollowersResult} +						showError={true} +						disabled={exportStats.followers_count === 0} +					/> +				</div> +				<div className="stats-and-button"> +					<span className="text-cutoff"> +						Created {exportStats.lists_count} list{ exportStats.lists_count !== 1 && "s" } +					</span> +					<MutationButton +						className="text-cutoff" +						label="Download lists.csv" +						type="button" +						onClick={() => exportLists()} +						result={exportListsResult} +						showError={true} +						disabled={exportStats.lists_count === 0} +					/> +				</div> +				<div className="stats-and-button"> +					<span className="text-cutoff"> +						Blocking {exportStats.blocks_count} account{ exportStats.blocks_count !== 1 && "s" } +					</span> +					<MutationButton +						className="text-cutoff" +						label="Download blocks.csv" +						type="button" +						onClick={() => exportBlocks()} +						result={exportBlocksResult} +						showError={true} +						disabled={exportStats.blocks_count === 0} +					/> +				</div> +				<div className="stats-and-button"> +					<span className="text-cutoff"> +						Muting {exportStats.mutes_count} account{ exportStats.mutes_count !== 1 && "s" } +					</span> +					<MutationButton +						className="text-cutoff" +						label="Download mutes.csv" +						type="button" +						onClick={() => exportMutes()} +						result={exportMutesResult} +						showError={true} +						disabled={exportStats.mutes_count === 0} +					/> +				</div> +			</div> +		</form> +	); +} diff --git a/web/source/settings/views/user/export-import/index.tsx b/web/source/settings/views/user/export-import/index.tsx new file mode 100644 index 000000000..2e3533318 --- /dev/null +++ b/web/source/settings/views/user/export-import/index.tsx @@ -0,0 +1,57 @@ +/* +	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 <http://www.gnu.org/licenses/>. +*/ + +import React from "react"; +import Export from "./export"; +import Loading from "../../../components/loading"; +import { Error } from "../../../components/error"; +import { useExportStatsQuery } from "../../../lib/query/user/export-import"; + +export default function ExportImport() { +	const { +		data: exportStats, +		isLoading, +		isFetching, +		isError, +		error, +	} = useExportStatsQuery(); + +	if (isLoading || isFetching) { +		return <Loading />; +	} + +	if (isError) { +		return <Error error={error} />; +	} + +	if (exportStats === undefined) { +		throw "undefined account export stats"; +	} +	 +	return ( +		<> +			<h1>Export & Import</h1> +			<p> +				On this page you can export data from your GoToSocial account, or import data into +				your GoToSocial account. All exports and imports use Mastodon-compatible CSV files. +			</p> +			<Export exportStats={exportStats} /> +		</> +	); +} diff --git a/web/source/settings/views/user/menu.tsx b/web/source/settings/views/user/menu.tsx index 3d90bfe21..a0526d652 100644 --- a/web/source/settings/views/user/menu.tsx +++ b/web/source/settings/views/user/menu.tsx @@ -53,6 +53,11 @@ export default function UserMenu() {  				itemUrl="migration"  				icon="fa-exchange"  			/> +			<MenuItem +				name="Export & Import" +				itemUrl="export-import" +				icon="fa-floppy-o" +			/>  		</MenuItem>  	);  } diff --git a/web/source/settings/views/user/router.tsx b/web/source/settings/views/user/router.tsx index 5b74aee68..7b995b3b7 100644 --- a/web/source/settings/views/user/router.tsx +++ b/web/source/settings/views/user/router.tsx @@ -25,12 +25,14 @@ import UserProfile from "./profile";  import UserMigration from "./migration";  import PostSettings from "./posts";  import EmailPassword from "./emailpassword"; +import ExportImport from "./export-import";  /**   * - /settings/user/profile   * - /settings/user/posts   * - /settings/user/emailpassword   * - /settings/user/migration + * - /settings/user/export-import   */  export default function UserRouter() {  	const baseUrl = useBaseUrl(); @@ -46,6 +48,7 @@ export default function UserRouter() {  						<Route path="/posts" component={PostSettings} />  						<Route path="/emailpassword" component={EmailPassword} />  						<Route path="/migration" component={UserMigration} /> +						<Route path="/export-import" component={ExportImport} />  						<Route><Redirect to="/profile" /></Route>  					</Switch>  				</ErrorBoundary> | 
