Account backups

fix/tabs-bar-issues
Alex Gleason 2021-01-07 14:17:06 -06:00
rodzic af50ad4639
commit ddac13d308
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
8 zmienionych plików z 173 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,31 @@
import api from '../api';
export const BACKUPS_FETCH_REQUEST = 'BACKUPS_FETCH_REQUEST';
export const BACKUPS_FETCH_SUCCESS = 'BACKUPS_FETCH_SUCCESS';
export const BACKUPS_FETCH_FAIL = 'BACKUPS_FETCH_FAIL';
export const BACKUPS_CREATE_REQUEST = 'BACKUPS_CREATE_REQUEST';
export const BACKUPS_CREATE_SUCCESS = 'BACKUPS_CREATE_SUCCESS';
export const BACKUPS_CREATE_FAIL = 'BACKUPS_CREATE_FAIL';
export function fetchBackups() {
return (dispatch, getState) => {
dispatch({ type: BACKUPS_FETCH_REQUEST });
return api(getState).get('/api/v1/pleroma/backups').then(({ data: backups }) => {
dispatch({ type: BACKUPS_FETCH_SUCCESS, backups });
}).catch(error => {
dispatch({ type: BACKUPS_FETCH_FAIL, error });
});
};
}
export function createBackup() {
return (dispatch, getState) => {
dispatch({ type: BACKUPS_CREATE_REQUEST });
return api(getState).post('/api/v1/pleroma/backups').then(({ data: backups }) => {
dispatch({ type: BACKUPS_CREATE_SUCCESS, backups });
}).catch(error => {
dispatch({ type: BACKUPS_CREATE_FAIL, error });
});
};
}

Wyświetl plik

@ -0,0 +1,93 @@
import React from 'react';
import { connect } from 'react-redux';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import PropTypes from 'prop-types';
import Column from '../ui/components/better_column';
import {
fetchBackups,
createBackup,
} from 'soapbox/actions/backups';
import ScrollableList from 'soapbox/components/scrollable_list';
import classNames from 'classnames';
const messages = defineMessages({
heading: { id: 'column.backups', defaultMessage: 'Backups' },
create: { id: 'backups.actions.create', defaultMessage: 'Create backup' },
emptyMessage: { id: 'backups.empty_message', defaultMessage: 'No backups found. {action}' },
emptyMessageAction: { id: 'backups.empty_message.action', defaultMessage: 'Create one now?' },
pending: { id: 'backups.pending', defaultMessage: 'Pending' },
});
const mapStateToProps = state => ({
backups: state.get('backups').toList().sortBy(backup => backup.get('inserted_at')),
});
export default @connect(mapStateToProps)
@injectIntl
class Backups extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
};
state = {
isLoading: true,
}
handleCreateBackup = e => {
this.props.dispatch(createBackup());
e.preventDefault();
}
componentDidMount() {
this.props.dispatch(fetchBackups()).then(() => {
this.setState({ isLoading: false });
}).catch(() => {});
}
makeColumnMenu = () => {
const { intl } = this.props;
return [{
text: intl.formatMessage(messages.create),
action: this.handleCreateBackup,
}];
}
render() {
const { intl, backups } = this.props;
const { isLoading } = this.state;
const showLoading = isLoading && backups.count() === 0;
const emptyMessageAction = (
<a href='#' onClick={this.handleCreateBackup}>
{intl.formatMessage(messages.emptyMessageAction)}
</a>
);
return (
<Column icon='cloud-download' heading={intl.formatMessage(messages.heading)} menu={this.makeColumnMenu()}>
<ScrollableList
isLoading={isLoading}
showLoading={showLoading}
scrollKey='backups'
emptyMessage={intl.formatMessage(messages.emptyMessage, { action: emptyMessageAction })}
>
{backups.map(backup => (
<div
className={classNames('backup', { 'backup--pending': !backup.get('processed') })}
key={backup.get('id')}
>
{backup.get('processed')
? <a href={backup.get('url')} target='_blank'>{backup.get('inserted_at')}</a>
: <div>{intl.formatMessage(messages.pending)}: {backup.get('inserted_at')}</div>
}
</div>
))}
</ScrollableList>
</Column>
);
}
}

Wyświetl plik

@ -81,6 +81,7 @@ import {
EditProfile,
SoapboxConfig,
ImportData,
Backups,
PasswordReset,
SecurityForm,
MfaForm,
@ -277,6 +278,7 @@ class SwitchingColumnsArea extends React.PureComponent {
<WrappedRoute path='/settings/preferences' layout={LAYOUT.DEFAULT} component={Preferences} content={children} />
<WrappedRoute path='/settings/profile' layout={LAYOUT.DEFAULT} component={EditProfile} content={children} />
<WrappedRoute path='/settings/import' layout={LAYOUT.DEFAULT} component={ImportData} content={children} />
<WrappedRoute path='/backups' layout={LAYOUT.DEFAULT} component={Backups} content={children} />
<WrappedRoute path='/soapbox/config' layout={LAYOUT.DEFAULT} component={SoapboxConfig} content={children} />
<Redirect from='/admin/dashboard' to='/admin' exact />

Wyświetl plik

@ -194,6 +194,10 @@ export function ImportData() {
return import(/* webpackChunkName: "features/import_data" */'../../import_data');
}
export function Backups() {
return import(/* webpackChunkName: "features/backups" */'../../backups');
}
export function PasswordReset() {
return import(/* webpackChunkName: "features/auth_login" */'../../auth_login/components/password_reset');
}

Wyświetl plik

@ -0,0 +1,27 @@
import {
BACKUPS_FETCH_SUCCESS,
BACKUPS_CREATE_SUCCESS,
} from '../actions/backups';
import { Map as ImmutableMap, fromJS } from 'immutable';
const initialState = ImmutableMap();
const importBackup = (state, backup) => {
return state.set(backup.get('inserted_at'), backup);
};
const importBackups = (state, backups) => {
return state.withMutations(mutable => {
backups.forEach(backup => importBackup(mutable, backup));
});
};
export default function backups(state = initialState, action) {
switch(action.type) {
case BACKUPS_FETCH_SUCCESS:
case BACKUPS_CREATE_SUCCESS:
return importBackups(state, fromJS(action.backups));
default:
return state;
}
};

Wyświetl plik

@ -49,6 +49,7 @@ import chats from './chats';
import chat_messages from './chat_messages';
import chat_message_lists from './chat_message_lists';
import profile_hover_card from './profile_hover_card';
import backups from './backups';
const appReducer = combineReducers({
dropdown_menu,
@ -99,6 +100,7 @@ const appReducer = combineReducers({
chat_messages,
chat_message_lists,
profile_hover_card,
backups,
});
// Clear the state (mostly) when the user logs out

Wyświetl plik

@ -80,6 +80,7 @@
@import 'components/accordion';
@import 'components/server-info';
@import 'components/admin';
@import 'components/backups';
// Holiday
@import 'holiday/halloween';

Wyświetl plik

@ -0,0 +1,13 @@
.backup {
padding: 15px;
border-bottom: 1px solid var(--brand-color--faint);
a {
color: var(--brand-color--hicontrast);
}
&--pending {
font-style: italic;
color: var(--primary-text-color--faint);
}
}