Support data import on GoToSocial

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2024-08-19 19:41:38 +02:00
parent e73341d1a9
commit 2bc0d52eff
8 changed files with 44 additions and 22 deletions

View file

@ -133,7 +133,7 @@
"multiselect-react-dropdown": "^2.0.25",
"object-to-formdata": "^4.5.1",
"path-browserify": "^1.0.1",
"pl-api": "^0.0.6",
"pl-api": "^0.0.7",
"postcss": "^8.4.29",
"process": "^0.11.10",
"punycode": "^2.1.1",

View file

@ -38,10 +38,10 @@ const messages = defineMessages({
mutesSuccess: { id: 'import_data.success.mutes', defaultMessage: 'Mutes imported successfully' },
});
const importFollows = (list: File | string) =>
const importFollows = (list: File | string, overwrite?: boolean) =>
(dispatch: React.Dispatch<ImportDataActions>, getState: () => RootState) => {
dispatch({ type: IMPORT_FOLLOWS_REQUEST });
return getClient(getState).settings.importFollows(list).then(response => {
return getClient(getState).settings.importFollows(list, overwrite ? 'overwrite' : 'merge').then(response => {
toast.success(messages.followersSuccess);
dispatch({ type: IMPORT_FOLLOWS_SUCCESS, response });
}).catch(error => {
@ -49,10 +49,10 @@ const importFollows = (list: File | string) =>
});
};
const importBlocks = (list: File | string) =>
const importBlocks = (list: File | string, overwrite?: boolean) =>
(dispatch: React.Dispatch<ImportDataActions>, getState: () => RootState) => {
dispatch({ type: IMPORT_BLOCKS_REQUEST });
return getClient(getState).settings.importBlocks(list).then(response => {
return getClient(getState).settings.importBlocks(list, overwrite ? 'overwrite' : 'merge').then(response => {
toast.success(messages.blocksSuccess);
dispatch({ type: IMPORT_BLOCKS_SUCCESS, response });
}).catch(error => {

View file

@ -133,7 +133,7 @@ const accountToCredentials = (account: Account): AccountCredentials => {
note: account.__meta.source?.note ?? '',
fields_attributes: [...account.__meta.source?.fields ?? []],
stranger_notifications: account.__meta.pleroma?.notification_settings?.block_from_strangers === true,
accepts_email_list: account.__meta.pleroma.accepts_email_list === true,
accepts_email_list: account.__meta.pleroma?.accepts_email_list === true,
hide_followers: hideNetwork,
hide_follows: hideNetwork,
hide_followers_count: hideNetwork,

View file

@ -1,8 +1,9 @@
import React, { useState } from 'react';
import { MessageDescriptor, useIntl } from 'react-intl';
import { FormattedMessage, MessageDescriptor, useIntl } from 'react-intl';
import { Button, FileInput, Form, FormActions, FormGroup, Text } from 'soapbox/components/ui';
import { useAppDispatch } from 'soapbox/hooks';
import List, { ListItem } from 'soapbox/components/list';
import { Button, FileInput, Form, FormActions, FormGroup, Text, Toggle } from 'soapbox/components/ui';
import { useAppDispatch, useFeatures } from 'soapbox/hooks';
import type { AppDispatch, RootState } from 'soapbox/store';
@ -12,20 +13,23 @@ interface IDataImporter {
input_hint: MessageDescriptor;
submit: MessageDescriptor;
};
action: (list: File | string) => (dispatch: AppDispatch, getState: () => RootState) => Promise<void>;
action: (list: File | string, overwrite?: boolean) => (dispatch: AppDispatch, getState: () => RootState) => Promise<void>;
accept?: string;
allowOverwrite?: boolean;
}
const DataImporter: React.FC<IDataImporter> = ({ messages, action, accept = '.csv,text/csv' }) => {
const DataImporter: React.FC<IDataImporter> = ({ messages, action, accept = '.csv,text/csv', allowOverwrite }) => {
const dispatch = useAppDispatch();
const intl = useIntl();
const features = useFeatures();
const [isLoading, setIsLoading] = useState(false);
const [file, setFile] = useState<File | null | undefined>(null);
const [overwrite, setOverwrite] = useState(false);
const handleSubmit: React.FormEventHandler = (event) => {
setIsLoading(true);
dispatch(action(file!)).then(() => {
dispatch(action(file!, overwrite)).then(() => {
setIsLoading(false);
}).catch(() => {
setIsLoading(false);
@ -51,6 +55,20 @@ const DataImporter: React.FC<IDataImporter> = ({ messages, action, accept = '.cs
required
/>
</FormGroup>
{features.importOverwrite && (
<List>
<ListItem
label={<FormattedMessage id='import_data.overwrite' defaultMessage='Overwrite instead of appending' />}
>
<Toggle
checked={overwrite}
onChange={({ target }) => setOverwrite(target.checked)}
/>
</ListItem>
</List>
)}
<FormActions>
<Button type='submit' theme='primary' disabled={isLoading}>
{intl.formatMessage(messages.submit)}

View file

@ -7,6 +7,7 @@ import {
importMutes,
} from 'soapbox/actions/import-data';
import { Column } from 'soapbox/components/ui';
import { useFeatures } from 'soapbox/hooks';
import DataImporter from './components/data-importer';
@ -35,12 +36,13 @@ const muteMessages = defineMessages({
const ImportData = () => {
const intl = useIntl();
const features = useFeatures();
return (
<Column label={intl.formatMessage(messages.heading)}>
<DataImporter action={importFollows} messages={followMessages} />
<DataImporter action={importBlocks} messages={blockMessages} />
<DataImporter action={importMutes} messages={muteMessages} />
{features.importFollows && <DataImporter action={importFollows} messages={followMessages} allowOverwrite />}
{features.importBlocks && <DataImporter action={importBlocks} messages={blockMessages} allowOverwrite />}
{features.importMutes && <DataImporter action={importMutes} messages={muteMessages} />}
</Column>
);
};

View file

@ -140,7 +140,9 @@ const Settings = () => {
</CardBody>
{any([
features.importData,
features.importBlocks,
features.importFollows,
features.importMutes,
features.exportData,
features.accountBackups,
features.federating && features.accountMoving,
@ -154,7 +156,7 @@ const Settings = () => {
<CardBody>
<List>
{features.importData && (
{(features.importBlocks || features.importFollows || features.importMutes) && (
<ListItem label={intl.formatMessage(messages.importData)} to='/settings/import' />
)}

View file

@ -288,7 +288,7 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
<WrappedRoute path='/settings/profile' page={DefaultPage} component={EditProfile} content={children} />
{features.exportData && <WrappedRoute path='/settings/export' page={DefaultPage} component={ExportData} content={children} />}
{features.importData && <WrappedRoute path='/settings/import' page={DefaultPage} component={ImportData} content={children} />}
{(features.importBlocks || features.importFollows || features.importMutes) && <WrappedRoute path='/settings/import' page={DefaultPage} component={ImportData} content={children} />}
{features.manageAccountAliases && <WrappedRoute path='/settings/aliases' page={DefaultPage} component={Aliases} content={children} />}
{features.accountMoving && <WrappedRoute path='/settings/migration' page={DefaultPage} component={Migration} content={children} />}
{features.accountBackups && <WrappedRoute path='/settings/backups' page={DefaultPage} component={Backups} content={children} />}

View file

@ -8390,10 +8390,10 @@ pkg-types@^1.0.3:
mlly "^1.2.0"
pathe "^1.1.0"
pl-api@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/pl-api/-/pl-api-0.0.6.tgz#9f5c59e68666376e973403419a0d82ab322869e1"
integrity sha512-jSM+GkxeQW31A/cnCtX5E7SBhZy3nh7iHKvcqebSZJFH/LKpkpsaFbH6oNWsr5IWMX5uAJAW2W8u/VsaoOev/g==
pl-api@^0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/pl-api/-/pl-api-0.0.7.tgz#603dbe8d0c2b8ec0e500fe5eae26e30d77f958ba"
integrity sha512-8Wh+uIyfcHhLLOT9s8i/Rjh/vcmjio7OEqNsUbYpJD/9n4TgW1zj/hOImlqGFDhGVdteAUx9cVr4jjQbLhtG/A==
dependencies:
blurhash "^2.0.5"
http-link-header "^1.1.3"