EmailList: let csv links be clickable, add combined.csv support, conditionally display elements

datepicker-css
Alex Gleason 2021-06-15 15:02:36 -05:00
rodzic 6255ba4976
commit eb006202e7
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
6 zmienionych plików z 81 dodań i 7 usunięć

Wyświetl plik

@ -0,0 +1,19 @@
import api from '../api';
export function getSubscribersCsv() {
return (dispatch, getState) => {
return api(getState).get('/api/v1/pleroma/admin/email_list/subscribers.csv');
};
}
export function getUnsubscribersCsv() {
return (dispatch, getState) => {
return api(getState).get('/api/v1/pleroma/admin/email_list/unsubscribers.csv');
};
}
export function getCombinedCsv() {
return (dispatch, getState) => {
return api(getState).get('/api/v1/pleroma/admin/email_list/combined.csv');
};
}

Wyświetl plik

@ -8,6 +8,19 @@ import Column from '../ui/components/column';
import RegistrationModePicker from './components/registration_mode_picker';
import { parseVersion } from 'soapbox/utils/features';
import sourceCode from 'soapbox/utils/code';
import { getSubscribersCsv, getUnsubscribersCsv, getCombinedCsv } from 'soapbox/actions/email_list';
import { getFeatures } from 'soapbox/utils/features';
// https://stackoverflow.com/a/53230807
const download = (response, filename) => {
const url = URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', filename);
document.body.appendChild(link);
link.click();
link.remove();
};
const messages = defineMessages({
heading: { id: 'column.admin.dashboard', defaultMessage: 'Dashboard' },
@ -15,6 +28,7 @@ const messages = defineMessages({
const mapStateToProps = (state, props) => ({
instance: state.get('instance'),
supportsEmailList: getFeatures(state.get('instance')).emailList,
});
export default @connect(mapStateToProps)
@ -24,10 +38,32 @@ class Dashboard extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
instance: ImmutablePropTypes.map.isRequired,
supportsEmailList: PropTypes.bool,
};
handleSubscribersClick = e => {
this.props.dispatch(getSubscribersCsv()).then((response) => {
download(response, 'subscribers.csv');
}).catch(() => {});
e.preventDefault();
}
handleUnsubscribersClick = e => {
this.props.dispatch(getUnsubscribersCsv()).then((response) => {
download(response, 'unsubscribers.csv');
}).catch(() => {});
e.preventDefault();
}
handleCombinedClick = e => {
this.props.dispatch(getCombinedCsv()).then((response) => {
download(response, 'combined.csv');
}).catch(() => {});
e.preventDefault();
}
render() {
const { intl, instance } = this.props;
const { intl, instance, supportsEmailList } = this.props;
const v = parseVersion(instance.get('version'));
const userCount = instance.getIn(['stats', 'user_count']);
const mau = instance.getIn(['pleroma', 'stats', 'mau']);
@ -96,6 +132,14 @@ class Dashboard extends ImmutablePureComponent {
<li>{v.software} <span className='pull-right'>{v.version}</span></li>
</ul>
</div>
{supportsEmailList && <div className='dashwidget'>
<h4><FormattedMessage id='admin.dashwidgets.email_list_header' defaultMessage='Email list' /></h4>
<ul>
<li><a href='#' onClick={this.handleSubscribersClick} target='_blank'>subscribers.csv</a></li>
<li><a href='#' onClick={this.handleUnsubscribersClick} target='_blank'>unsubscribers.csv</a></li>
<li><a href='#' onClick={this.handleCombinedClick} target='_blank'>combined.csv</a></li>
</ul>
</div>}
</div>
</Column>
);

Wyświetl plik

@ -24,6 +24,7 @@ import { updateNotificationSettings } from 'soapbox/actions/accounts';
import { unescape } from 'lodash';
import { isVerified } from 'soapbox/utils/accounts';
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
import { getFeatures } from 'soapbox/utils/features';
const messages = defineMessages({
heading: { id: 'column.edit_profile', defaultMessage: 'Edit profile' },
@ -41,6 +42,7 @@ const mapStateToProps = state => {
account,
maxFields: state.getIn(['instance', 'pleroma', 'metadata', 'fields_limits', 'max_fields'], 4),
verifiedCanEditName: soapbox.get('verifiedCanEditName'),
supportsEmailList: getFeatures(state.get('instance')).emailList,
};
};
@ -182,7 +184,7 @@ class EditProfile extends ImmutablePureComponent {
}
render() {
const { intl, maxFields, account, verifiedCanEditName } = this.props;
const { intl, maxFields, account, verifiedCanEditName, supportsEmailList } = this.props;
const verified = isVerified(account);
const canEditName = verifiedCanEditName || !verified;
@ -249,13 +251,13 @@ class EditProfile extends ImmutablePureComponent {
checked={this.state.stranger_notifications}
onChange={this.handleCheckboxChange}
/>
<Checkbox
{supportsEmailList && <Checkbox
label={<FormattedMessage id='edit_profile.fields.accepts_email_list_label' defaultMessage='Subscribe to newsletter' />}
hint={<FormattedMessage id='edit_profile.hints.accepts_email_list' defaultMessage='Opt-in to news and marketing updates.' />}
name='accepts_email_list'
checked={this.state.accepts_email_list}
onChange={this.handleCheckboxChange}
/>
/>}
</FieldsGroup>
<FieldsGroup>
<div className='fields-row__column fields-group'>

Wyświetl plik

@ -18,6 +18,7 @@ import { Map as ImmutableMap } from 'immutable';
import { v4 as uuidv4 } from 'uuid';
import { getSettings } from 'soapbox/actions/settings';
import { openModal } from 'soapbox/actions/modal';
import { getFeatures } from 'soapbox/utils/features';
const messages = defineMessages({
username: { id: 'registration.fields.username_placeholder', defaultMessage: 'Username' },
@ -36,6 +37,7 @@ const mapStateToProps = (state, props) => ({
locale: getSettings(state).get('locale'),
needsConfirmation: state.getIn(['instance', 'pleroma', 'metadata', 'account_activation_required']),
needsApproval: state.getIn(['instance', 'approval_required']),
supportsEmailList: getFeatures(state.get('instance')).emailList,
});
export default @connect(mapStateToProps)
@ -136,7 +138,7 @@ class RegistrationForm extends ImmutablePureComponent {
}
render() {
const { instance, intl } = this.props;
const { instance, intl, supportsEmailList } = this.props;
const { params } = this.state;
const isOpen = instance.get('registrations');
const isLoading = this.state.captchaLoading || this.state.submissionLoading;
@ -233,11 +235,11 @@ class RegistrationForm extends ImmutablePureComponent {
onChange={this.onCheckboxChange}
required
/>
<Checkbox
{supportsEmailList && <Checkbox
label={intl.formatMessage(messages.newsletter)}
name='accepts_email_list'
onChange={this.onCheckboxChange}
/>
/>}
</div>
<div className='actions'>
<button name='button' type='submit' className='btn button button-primary'>

Wyświetl plik

@ -1,8 +1,10 @@
// Detect backend features to conditionally render elements
import gte from 'semver/functions/gte';
import { List as ImmutableList } from 'immutable';
export const getFeatures = instance => {
const v = parseVersion(instance.get('version'));
const f = instance.getIn(['pleroma', 'metadata', 'features'], ImmutableList());
return {
suggestions: v.software === 'Mastodon' && gte(v.compatVersion, '2.4.3'),
trends: v.software === 'Mastodon' && gte(v.compatVersion, '3.0.0'),
@ -11,6 +13,7 @@ export const getFeatures = instance => {
attachmentLimit: v.software === 'Pleroma' ? Infinity : 4,
focalPoint: v.software === 'Mastodon' && gte(v.compatVersion, '2.3.0'),
importMutes: v.software === 'Pleroma' && gte(v.version, '2.2.0'),
emailList: f.includes('email_list'),
};
};

Wyświetl plik

@ -68,6 +68,10 @@
margin-bottom: 8px;
border-bottom: 1px solid var(--accent-color--med);
}
a {
color: var(--brand-color);
}
}
.unapproved-account {