Merge branch 'account-fqn' into 'develop'
Make FQN for local accounts configurable See merge request soapbox-pub/soapbox-fe!471
This commit is contained in:
commit
0b87296c15
11 changed files with 83 additions and 26 deletions
|
@ -24,6 +24,8 @@ const allowedEmojiRGI = ImmutableList([
|
|||
'😩',
|
||||
]);
|
||||
|
||||
const year = new Date().getFullYear();
|
||||
|
||||
export const defaultConfig = ImmutableMap({
|
||||
logo: '',
|
||||
banner: '',
|
||||
|
@ -34,12 +36,13 @@ export const defaultConfig = ImmutableMap({
|
|||
}),
|
||||
extensions: ImmutableMap(),
|
||||
defaultSettings: ImmutableMap(),
|
||||
copyright: '♥2020. Copying is an act of love. Please copy and share.',
|
||||
copyright: `♥${year}. Copying is an act of love. Please copy and share.`,
|
||||
navlinks: ImmutableMap({
|
||||
homeFooter: ImmutableList(),
|
||||
}),
|
||||
allowedEmoji: allowedEmoji,
|
||||
verifiedCanEditName: false,
|
||||
displayFqn: true,
|
||||
});
|
||||
|
||||
export function getSoapboxConfig(state) {
|
||||
|
|
|
@ -1,21 +1,31 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import VerificationBadge from './verification_badge';
|
||||
import { acctFull } from '../utils/accounts';
|
||||
import { getAcct } from '../utils/accounts';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import HoverRefWrapper from 'soapbox/components/hover_ref_wrapper';
|
||||
import { displayFqn } from 'soapbox/utils/state';
|
||||
|
||||
export default class DisplayName extends React.PureComponent {
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
displayFqn: displayFqn(state),
|
||||
};
|
||||
};
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
class DisplayName extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
displayFqn: PropTypes.bool,
|
||||
others: ImmutablePropTypes.list,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
render() {
|
||||
const { account, others, children } = this.props;
|
||||
const { account, displayFqn, others, children } = this.props;
|
||||
|
||||
let displayName, suffix;
|
||||
const verified = account.getIn(['pleroma', 'tags'], ImmutableList()).includes('verified');
|
||||
|
@ -38,7 +48,7 @@ export default class DisplayName extends React.PureComponent {
|
|||
{verified && <VerificationBadge />}
|
||||
</>
|
||||
);
|
||||
suffix = <span className='display-name__account'>@{acctFull(account)}</span>;
|
||||
suffix = <span className='display-name__account'>@{getAcct(account, displayFqn)}</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -6,13 +6,14 @@ import { injectIntl } from 'react-intl';
|
|||
import { Link } from 'react-router-dom';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import Avatar from 'soapbox/components/avatar';
|
||||
import { acctFull } from 'soapbox/utils/accounts';
|
||||
import { getAcct } from 'soapbox/utils/accounts';
|
||||
import { fetchChat, markChatRead } from 'soapbox/actions/chats';
|
||||
import ChatBox from './components/chat_box';
|
||||
import Column from 'soapbox/components/column';
|
||||
import ColumnBackButton from 'soapbox/components/column_back_button';
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
import { makeGetChat } from 'soapbox/selectors';
|
||||
import { displayFqn } from 'soapbox/utils/state';
|
||||
|
||||
const mapStateToProps = (state, { params }) => {
|
||||
const getChat = makeGetChat();
|
||||
|
@ -21,6 +22,7 @@ const mapStateToProps = (state, { params }) => {
|
|||
return {
|
||||
me: state.get('me'),
|
||||
chat: getChat(state, chat),
|
||||
displayFqn: displayFqn(state),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -32,6 +34,7 @@ class ChatRoom extends ImmutablePureComponent {
|
|||
dispatch: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
chat: ImmutablePropTypes.map,
|
||||
displayFqn: PropTypes.bool,
|
||||
me: PropTypes.node,
|
||||
}
|
||||
|
||||
|
@ -68,7 +71,7 @@ class ChatRoom extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { chat } = this.props;
|
||||
const { chat, displayFqn } = this.props;
|
||||
if (!chat) return null;
|
||||
const account = chat.get('account');
|
||||
|
||||
|
@ -79,7 +82,7 @@ class ChatRoom extends ImmutablePureComponent {
|
|||
<Link to={`/@${account.get('acct')}`} className='chatroom__header'>
|
||||
<Avatar account={account} size={18} />
|
||||
<div className='chatroom__title'>
|
||||
@{acctFull(account)}
|
||||
@{getAcct(account, displayFqn)}
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@ import { injectIntl } from 'react-intl';
|
|||
import { Link } from 'react-router-dom';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import Avatar from 'soapbox/components/avatar';
|
||||
import { acctFull } from 'soapbox/utils/accounts';
|
||||
import { getAcct } from 'soapbox/utils/accounts';
|
||||
import IconButton from 'soapbox/components/icon_button';
|
||||
import {
|
||||
closeChat,
|
||||
|
@ -14,11 +14,13 @@ import {
|
|||
} from 'soapbox/actions/chats';
|
||||
import ChatBox from './chat_box';
|
||||
import { shortNumberFormat } from 'soapbox/utils/numbers';
|
||||
import { displayFqn } from 'soapbox/utils/state';
|
||||
import HoverRefWrapper from 'soapbox/components/hover_ref_wrapper';
|
||||
|
||||
const mapStateToProps = (state, { pane }) => ({
|
||||
me: state.get('me'),
|
||||
chat: state.getIn(['chats', pane.get('chat_id')]),
|
||||
displayFqn: displayFqn(state),
|
||||
});
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
|
@ -32,6 +34,7 @@ class ChatWindow extends ImmutablePureComponent {
|
|||
idx: PropTypes.number,
|
||||
chat: ImmutablePropTypes.map,
|
||||
me: PropTypes.node,
|
||||
displayFqn: PropTypes.bool,
|
||||
}
|
||||
|
||||
state = {
|
||||
|
@ -73,7 +76,7 @@ class ChatWindow extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { pane, idx, chat } = this.props;
|
||||
const { pane, idx, chat, displayFqn } = this.props;
|
||||
const account = pane.getIn(['chat', 'account']);
|
||||
if (!chat || !account) return null;
|
||||
|
||||
|
@ -99,7 +102,7 @@ class ChatWindow extends ImmutablePureComponent {
|
|||
<div className='pane__header'>
|
||||
{unreadCount > 0 ? unreadIcon : avatar }
|
||||
<button className='pane__title' onClick={this.handleChatToggle(chat.get('id'))}>
|
||||
@{acctFull(account)}
|
||||
@{getAcct(account, displayFqn)}
|
||||
</button>
|
||||
<div className='pane__close'>
|
||||
<IconButton icon='close' title='Close chat' onClick={this.handleChatClose(chat.get('id'))} />
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { acctFull } from 'soapbox/utils/accounts';
|
||||
import { getAcct } from 'soapbox/utils/accounts';
|
||||
import StillImage from 'soapbox/components/still_image';
|
||||
import VerificationBadge from 'soapbox/components/verification_badge';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import { displayFqn } from 'soapbox/utils/state';
|
||||
|
||||
const ProfilePreview = ({ account }) => (
|
||||
const mapStateToProps = state => ({
|
||||
displayFqn: displayFqn(state),
|
||||
});
|
||||
|
||||
const ProfilePreview = ({ account, displayFqn }) => (
|
||||
<div className='card h-card'>
|
||||
<a target='_blank' rel='noopener' href={account.get('url')}>
|
||||
<div className='card__img'>
|
||||
|
@ -23,7 +30,7 @@ const ProfilePreview = ({ account }) => (
|
|||
{account.getIn(['pleroma', 'tags'], ImmutableList()).includes('verified') && <VerificationBadge />}
|
||||
</strong>
|
||||
</bdi>
|
||||
<span>{acctFull(account)}</span>
|
||||
<span>@{getAcct(account, displayFqn)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
@ -32,6 +39,7 @@ const ProfilePreview = ({ account }) => (
|
|||
|
||||
ProfilePreview.propTypes = {
|
||||
account: ImmutablePropTypes.map,
|
||||
displayFqn: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default ProfilePreview;
|
||||
export default connect(mapStateToProps)(ProfilePreview);
|
||||
|
|
|
@ -41,6 +41,7 @@ const messages = defineMessages({
|
|||
rawJSONLabel: { id: 'soapbox_config.raw_json_label', defaultMessage: 'Advanced: Edit raw JSON data' },
|
||||
rawJSONHint: { id: 'soapbox_config.raw_json_hint', defaultMessage: 'Edit the settings data directly. Changes made directly to the JSON file will override the form fields above. Click "Save" to apply your changes.' },
|
||||
verifiedCanEditNameLabel: { id: 'soapbox_config.verified_can_edit_name_label', defaultMessage: 'Allow verified users to edit their own display name.' },
|
||||
displayFqnLabel: { id: 'soapbox_config.display_fqn_label', defaultMessage: 'Display domain even for local accounts.' },
|
||||
});
|
||||
|
||||
const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
|
||||
|
@ -241,6 +242,12 @@ class SoapboxConfig extends ImmutablePureComponent {
|
|||
checked={soapbox.get('verifiedCanEditName') === true}
|
||||
onChange={this.handleChange(['verifiedCanEditName'], (e) => e.target.checked)}
|
||||
/>
|
||||
<Checkbox
|
||||
name='verifiedCanEditName'
|
||||
label={intl.formatMessage(messages.displayFqnLabel)}
|
||||
checked={soapbox.get('displayFqn') === true}
|
||||
onChange={this.handleChange(['displayFqn'], (e) => e.target.checked)}
|
||||
/>
|
||||
</FieldsGroup>
|
||||
<FieldsGroup>
|
||||
<div className='input with_block_label popup'>
|
||||
|
|
|
@ -10,7 +10,8 @@ import Icon from 'soapbox/components/icon';
|
|||
import VerificationBadge from 'soapbox/components/verification_badge';
|
||||
import Badge from 'soapbox/components/badge';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import { acctFull, isAdmin, isModerator } from 'soapbox/utils/accounts';
|
||||
import { getAcct, isAdmin, isModerator } from 'soapbox/utils/accounts';
|
||||
import { displayFqn } from 'soapbox/utils/state';
|
||||
import classNames from 'classnames';
|
||||
|
||||
const messages = defineMessages({
|
||||
|
@ -36,10 +37,11 @@ class ProfileInfoPanel extends ImmutablePureComponent {
|
|||
identity_proofs: ImmutablePropTypes.list,
|
||||
intl: PropTypes.object.isRequired,
|
||||
username: PropTypes.string,
|
||||
displayFqn: PropTypes.bool,
|
||||
};
|
||||
|
||||
render() {
|
||||
const { account, intl, identity_proofs, username } = this.props;
|
||||
const { account, displayFqn, intl, identity_proofs, username } = this.props;
|
||||
|
||||
if (!account) {
|
||||
return (
|
||||
|
@ -73,7 +75,7 @@ class ProfileInfoPanel extends ImmutablePureComponent {
|
|||
<span dangerouslySetInnerHTML={displayNameHtml} className='profile-info-panel__name-content' />
|
||||
{verified && <VerificationBadge />}
|
||||
{account.get('bot') && <Badge slug='bot' title={intl.formatMessage(messages.bot)} />}
|
||||
{ <small>@{acctFull(account)} {lockedIcon}</small> }
|
||||
{ <small>@{getAcct(account, displayFqn)} {lockedIcon}</small> }
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
|
@ -144,6 +146,7 @@ const mapStateToProps = (state, { account }) => {
|
|||
return {
|
||||
identity_proofs,
|
||||
domain: state.getIn(['meta', 'domain']),
|
||||
displayFqn: displayFqn(state),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import Avatar from 'soapbox/components/avatar';
|
||||
import { shortNumberFormat } from 'soapbox/utils/numbers';
|
||||
import { acctFull } from 'soapbox/utils/accounts';
|
||||
import { getAcct } from 'soapbox/utils/accounts';
|
||||
import { displayFqn } from 'soapbox/utils/state';
|
||||
import StillImage from 'soapbox/components/still_image';
|
||||
import VerificationBadge from 'soapbox/components/verification_badge';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
|
@ -17,12 +18,13 @@ class UserPanel extends ImmutablePureComponent {
|
|||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map,
|
||||
displayFqn: PropTypes.bool,
|
||||
intl: PropTypes.object.isRequired,
|
||||
domain: PropTypes.string,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { account, intl, domain } = this.props;
|
||||
const { account, displayFqn, intl, domain } = this.props;
|
||||
if (!account) return null;
|
||||
const displayNameHtml = { __html: account.get('display_name_html') };
|
||||
const acct = account.get('acct').indexOf('@') === -1 && domain ? `${account.get('acct')}@${domain}` : account.get('acct');
|
||||
|
@ -49,7 +51,7 @@ class UserPanel extends ImmutablePureComponent {
|
|||
<Link to={`/@${account.get('acct')}`}>
|
||||
<span className='user-panel__account__name' dangerouslySetInnerHTML={displayNameHtml} />
|
||||
{verified && <VerificationBadge />}
|
||||
<small className='user-panel__account__username'>@{acctFull(account)}</small>
|
||||
<small className='user-panel__account__username'>@{getAcct(account, displayFqn)}</small>
|
||||
</Link>
|
||||
</h1>
|
||||
</div>
|
||||
|
@ -93,6 +95,7 @@ const makeMapStateToProps = () => {
|
|||
|
||||
const mapStateToProps = (state, { accountId }) => ({
|
||||
account: getAccount(state, accountId),
|
||||
displayFqn: displayFqn(state),
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
|
|
|
@ -10,7 +10,8 @@ import LinkFooter from '../features/ui/components/link_footer';
|
|||
import SignUpPanel from '../features/ui/components/sign_up_panel';
|
||||
import ProfileInfoPanel from '../features/ui/components/profile_info_panel';
|
||||
import ProfileMediaPanel from '../features/ui/components/profile_media_panel';
|
||||
import { acctFull } from 'soapbox/utils/accounts';
|
||||
import { getAcct } from 'soapbox/utils/accounts';
|
||||
import { displayFqn } from 'soapbox/utils/state';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
import { makeGetAccount } from '../selectors';
|
||||
import { Redirect } from 'react-router-dom';
|
||||
|
@ -47,6 +48,7 @@ const mapStateToProps = (state, { params: { username }, withReplies = false }) =
|
|||
accountUsername,
|
||||
features: getFeatures(state.get('instance')),
|
||||
realAccount,
|
||||
displayFqn: displayFqn(state),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -56,11 +58,12 @@ class ProfilePage extends ImmutablePureComponent {
|
|||
static propTypes = {
|
||||
account: ImmutablePropTypes.map,
|
||||
accountUsername: PropTypes.string.isRequired,
|
||||
displayFqn: PropTypes.bool,
|
||||
features: PropTypes.object,
|
||||
};
|
||||
|
||||
render() {
|
||||
const { children, accountId, account, accountUsername, features, realAccount } = this.props;
|
||||
const { children, accountId, account, displayFqn, accountUsername, features, realAccount } = this.props;
|
||||
const bg = account ? account.getIn(['customizations', 'background']) : undefined;
|
||||
|
||||
if (realAccount) {
|
||||
|
@ -70,7 +73,7 @@ class ProfilePage extends ImmutablePureComponent {
|
|||
return (
|
||||
<div className={bg && `page page--customization page--${bg}` || 'page'}>
|
||||
{account && <Helmet>
|
||||
<title>@{acctFull(account)}</title>
|
||||
<title>@{getAcct(account, displayFqn)}</title>
|
||||
</Helmet>}
|
||||
|
||||
<div className='page__top'>
|
||||
|
|
|
@ -16,13 +16,21 @@ export const getDomain = account => {
|
|||
return domain;
|
||||
};
|
||||
|
||||
// user@domain even for local users
|
||||
export const acctFull = account => {
|
||||
export const guessFqn = account => {
|
||||
const [user, domain] = account.get('acct').split('@');
|
||||
if (!domain) return [user, guessDomain(account)].join('@');
|
||||
return account.get('acct');
|
||||
};
|
||||
|
||||
// user@domain even for local users
|
||||
export const acctFull = account => (
|
||||
account.get('fqn') || guessFqn(account)
|
||||
);
|
||||
|
||||
export const getAcct = (account, displayFqn) => (
|
||||
displayFqn === true ? acctFull(account) : account.get('acct')
|
||||
);
|
||||
|
||||
export const isStaff = (account = ImmutableMap()) => (
|
||||
[isAdmin, isModerator].some(f => f(account) === true)
|
||||
);
|
||||
|
|
6
app/soapbox/utils/state.js
Normal file
6
app/soapbox/utils/state.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { getSoapboxConfig } from'soapbox/actions/soapbox';
|
||||
|
||||
export const displayFqn = state => {
|
||||
const soapbox = getSoapboxConfig(state);
|
||||
return soapbox.get('displayFqn');
|
||||
};
|
Loading…
Reference in a new issue