PLT-3466 E10: Add announcement bar feature (#6509)
* E10 - Add announcement bar feature * Updates per feedback * Add component tests and snapshots * Update snapshots * Updating color picker UI (#6543) * Add class to body tag when banner is not dismissable and clean up localstorage items when banner changes * Fixing links (#6544) * Updating UI for fixed error bar (#6552) * Truncating text on fixed banner (#6561) * Plt 3466 - Error bar link states (#6577) * Updating error bar hover state * Updating error bar link states
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
0f3bd85b8d
Коммит
abd0466a42
@@ -1,12 +1,11 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import 'bootstrap';
|
||||
|
||||
import ErrorBar from 'components/error_bar.jsx';
|
||||
import AnnouncementBar from 'components/announcement_bar';
|
||||
import AdminStore from 'stores/admin_store.jsx';
|
||||
import * as AsyncClient from 'utils/async_client.jsx';
|
||||
|
||||
@@ -52,7 +51,7 @@ export default class AdminConsole extends React.Component {
|
||||
if (config && Object.keys(config).length === 0 && config.constructor === 'Object') {
|
||||
return (
|
||||
<div className='admin-console__wrapper'>
|
||||
<ErrorBar/>
|
||||
<AnnouncementBar/>
|
||||
<div className='admin-console'/>
|
||||
</div>
|
||||
);
|
||||
@@ -64,7 +63,7 @@ export default class AdminConsole extends React.Component {
|
||||
});
|
||||
return (
|
||||
<div className='admin-console__wrapper'>
|
||||
<ErrorBar/>
|
||||
<AnnouncementBar/>
|
||||
<div className='admin-console'>
|
||||
<AdminSidebar/>
|
||||
{children}
|
||||
|
||||
119
webapp/components/admin_console/color_setting.jsx
Обычный файл
119
webapp/components/admin_console/color_setting.jsx
Обычный файл
@@ -0,0 +1,119 @@
|
||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import Setting from './setting.jsx';
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {ChromePicker} from 'react-color';
|
||||
|
||||
export default class ColorSetting extends React.PureComponent {
|
||||
static propTypes = {
|
||||
|
||||
/*
|
||||
* The unique identifer for the admin console setting
|
||||
*/
|
||||
id: PropTypes.string.isRequired,
|
||||
|
||||
/*
|
||||
* The text/jsx display name for the setting
|
||||
*/
|
||||
label: PropTypes.node.isRequired,
|
||||
|
||||
/*
|
||||
* The text/jsx help text to display underneath the setting
|
||||
*/
|
||||
helpText: PropTypes.node,
|
||||
|
||||
/*
|
||||
* The hex color value
|
||||
*/
|
||||
value: PropTypes.string.isRequired,
|
||||
|
||||
/*
|
||||
* Function called when the input changes
|
||||
*/
|
||||
onChange: PropTypes.func,
|
||||
|
||||
/*
|
||||
* Set to disable the setting
|
||||
*/
|
||||
disabled: PropTypes.bool
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
showPicker: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
document.addEventListener('click', this.closePicker);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('click', this.closePicker);
|
||||
}
|
||||
|
||||
handleChange = (color) => {
|
||||
this.props.onChange(this.props.id, color.hex);
|
||||
}
|
||||
|
||||
togglePicker = () => {
|
||||
if (this.props.disabled) {
|
||||
this.setState({showPicker: false});
|
||||
}
|
||||
this.setState({showPicker: !this.state.showPicker});
|
||||
}
|
||||
|
||||
closePicker = (e) => {
|
||||
if (!e.target.closest('.picker-' + this.props.id)) {
|
||||
this.setState({showPicker: false});
|
||||
}
|
||||
}
|
||||
|
||||
onTextInput = (e) => {
|
||||
this.props.onChange(this.props.id, e.target.value);
|
||||
}
|
||||
|
||||
render() {
|
||||
let picker;
|
||||
if (this.state.showPicker) {
|
||||
picker = (
|
||||
<div className={'color-picker__popover picker-' + this.props.id}>
|
||||
<ChromePicker
|
||||
color={this.props.value}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Setting
|
||||
label={this.props.label}
|
||||
helpText={this.props.helpText}
|
||||
inputId={this.props.id}
|
||||
>
|
||||
<div className='input-group color-picker colorpicker-element'>
|
||||
<input
|
||||
type='text'
|
||||
className='form-control'
|
||||
value={this.props.value}
|
||||
onChange={this.onTextInput}
|
||||
disabled={this.props.disabled}
|
||||
/>
|
||||
<span
|
||||
className={'input-group-addon picker-' + this.props.id}
|
||||
onClick={this.togglePicker}
|
||||
>
|
||||
<i style={{backgroundColor: this.props.value}}/>
|
||||
</span>
|
||||
{picker}
|
||||
</div>
|
||||
</Setting>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,9 @@ import SettingsGroup from './settings_group.jsx';
|
||||
import DropdownSetting from './dropdown_setting.jsx';
|
||||
import RadioSetting from './radio_setting.jsx';
|
||||
import PostEditSetting from './post_edit_setting.jsx';
|
||||
import BooleanSetting from './boolean_setting.jsx';
|
||||
import TextSetting from './text_setting.jsx';
|
||||
import ColorSetting from './color_setting.jsx';
|
||||
|
||||
import Constants from 'utils/constants.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
@@ -35,6 +38,11 @@ export default class PolicySettings extends AdminSettings {
|
||||
config.TeamSettings.RestrictPublicChannelDeletion = this.state.restrictPublicChannelDeletion;
|
||||
config.TeamSettings.RestrictPrivateChannelDeletion = this.state.restrictPrivateChannelDeletion;
|
||||
config.TeamSettings.RestrictPrivateChannelManageMembers = this.state.restrictPrivateChannelManageMembers;
|
||||
config.AnnouncementSettings.EnableBanner = this.state.enableBanner;
|
||||
config.AnnouncementSettings.BannerText = this.state.bannerText;
|
||||
config.AnnouncementSettings.BannerColor = this.state.bannerColor;
|
||||
config.AnnouncementSettings.BannerTextColor = this.state.bannerTextColor;
|
||||
config.AnnouncementSettings.AllowBannerDismissal = this.state.allowBannerDismissal;
|
||||
|
||||
return config;
|
||||
}
|
||||
@@ -51,7 +59,12 @@ export default class PolicySettings extends AdminSettings {
|
||||
restrictPrivateChannelManagement: config.TeamSettings.RestrictPrivateChannelManagement,
|
||||
restrictPublicChannelDeletion: config.TeamSettings.RestrictPublicChannelDeletion,
|
||||
restrictPrivateChannelDeletion: config.TeamSettings.RestrictPrivateChannelDeletion,
|
||||
restrictPrivateChannelManageMembers: config.TeamSettings.RestrictPrivateChannelManageMembers
|
||||
restrictPrivateChannelManageMembers: config.TeamSettings.RestrictPrivateChannelManageMembers,
|
||||
enableBanner: config.AnnouncementSettings.EnableBanner,
|
||||
bannerText: config.AnnouncementSettings.BannerText,
|
||||
bannerColor: config.AnnouncementSettings.BannerColor,
|
||||
bannerTextColor: config.AnnouncementSettings.BannerTextColor,
|
||||
allowBannerDismissal: config.AnnouncementSettings.AllowBannerDismissal
|
||||
};
|
||||
}
|
||||
|
||||
@@ -317,6 +330,83 @@ export default class PolicySettings extends AdminSettings {
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<BooleanSetting
|
||||
id='enableBanner'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='admin.general.policy.enableBannerTitle'
|
||||
defaultMessage='Enable Announcement Banner:'
|
||||
/>
|
||||
}
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id='admin.general.policy.enableBannerDesc'
|
||||
defaultMessage='Enable an announcement banner across all teams.'
|
||||
/>
|
||||
}
|
||||
value={this.state.enableBanner}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<TextSetting
|
||||
id='bannerText'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='admin.general.policy.bannerTextTitle'
|
||||
defaultMessage='Banner Text:'
|
||||
/>
|
||||
}
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id='admin.general.policy.bannerTextDesc'
|
||||
defaultMessage='Text that will appear in the announcement banner.'
|
||||
/>
|
||||
}
|
||||
value={this.state.bannerText}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.enableBanner}
|
||||
/>
|
||||
<ColorSetting
|
||||
id='bannerColor'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='admin.general.policy.bannerColorTitle'
|
||||
defaultMessage='Banner Color:'
|
||||
/>
|
||||
}
|
||||
value={this.state.bannerColor}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.enableBanner}
|
||||
/>
|
||||
<ColorSetting
|
||||
id='bannerTextColor'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='admin.general.policy.bannerTextColorTitle'
|
||||
defaultMessage='Banner Text Color:'
|
||||
/>
|
||||
}
|
||||
value={this.state.bannerTextColor}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.enableBanner}
|
||||
/>
|
||||
<BooleanSetting
|
||||
id='allowBannerDismissal'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='admin.general.policy.allowBannerDismissalTitle'
|
||||
defaultMessage='Allow Banner Dismissal:'
|
||||
/>
|
||||
}
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id='admin.general.policy.allowBannerDismissalDesc'
|
||||
defaultMessage='When true, users can dismiss the banner until its next update. When false, the banner is permanently visible until it is turned off by the System Admin.'
|
||||
/>
|
||||
}
|
||||
value={this.state.allowBannerDismissal}
|
||||
onChange={this.handleChange}
|
||||
disabled={!this.state.enableBanner}
|
||||
/>
|
||||
</SettingsGroup>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,19 @@ const RENEWAL_LINK = 'https://licensing.mattermost.com/renew';
|
||||
|
||||
const BAR_DEVELOPER_TYPE = 'developer';
|
||||
const BAR_CRITICAL_TYPE = 'critical';
|
||||
const BAR_ANNOUNCEMENT_TYPE = 'announcement';
|
||||
|
||||
const ANNOUNCEMENT_KEY = 'announcement--';
|
||||
|
||||
export default class AnnouncementBar extends React.PureComponent {
|
||||
static propTypes = {
|
||||
|
||||
/*
|
||||
* Set if the user is logged in
|
||||
*/
|
||||
isLoggedIn: React.PropTypes.bool.isRequired
|
||||
}
|
||||
|
||||
export default class ErrorBar extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
@@ -31,7 +42,7 @@ export default class ErrorBar extends React.Component {
|
||||
|
||||
this.setInitialError();
|
||||
|
||||
this.state = ErrorStore.getLastError() || {};
|
||||
this.state = this.getState();
|
||||
}
|
||||
|
||||
setInitialError() {
|
||||
@@ -62,11 +73,38 @@ export default class ErrorBar extends React.Component {
|
||||
} else if (isLicenseExpired() && isSystemAdmin) {
|
||||
ErrorStore.storeLastError({notification: true, message: ErrorBarTypes.LICENSE_EXPIRED, type: BAR_CRITICAL_TYPE});
|
||||
} else if (isLicenseExpiring() && isSystemAdmin) {
|
||||
ErrorStore.storeLastError({notification: true, message: ErrorBarTypes.LICENSE_EXPIRING});
|
||||
ErrorStore.storeLastError({notification: true, message: ErrorBarTypes.LICENSE_EXPIRING, type: BAR_CRITICAL_TYPE});
|
||||
}
|
||||
}
|
||||
|
||||
isValidError(s) {
|
||||
getState() {
|
||||
const error = ErrorStore.getLastError();
|
||||
if (error) {
|
||||
return {message: error.message, color: null, textColor: null, type: error.type, allowDismissal: true};
|
||||
}
|
||||
|
||||
const bannerText = global.window.mm_config.BannerText || '';
|
||||
const allowDismissal = global.window.mm_config.AllowBannerDismissal === 'true';
|
||||
const bannerDismissed = localStorage.getItem(ANNOUNCEMENT_KEY + global.window.mm_config.BannerText);
|
||||
|
||||
if (global.window.mm_config.EnableBanner === 'true' &&
|
||||
bannerText.length > 0 &&
|
||||
(!bannerDismissed || !allowDismissal)) {
|
||||
// Remove old local storage items
|
||||
Utils.removePrefixFromLocalStorage(ANNOUNCEMENT_KEY);
|
||||
return {
|
||||
message: bannerText,
|
||||
color: global.window.mm_config.BannerColor,
|
||||
textColor: global.window.mm_config.BannerTextColor,
|
||||
type: BAR_ANNOUNCEMENT_TYPE,
|
||||
allowDismissal
|
||||
};
|
||||
}
|
||||
|
||||
return {message: null, color: null, colorText: null, textColor: null, type: null, allowDismissal: true};
|
||||
}
|
||||
|
||||
isValidState(s) {
|
||||
if (!s) {
|
||||
return false;
|
||||
}
|
||||
@@ -83,26 +121,38 @@ export default class ErrorBar extends React.Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.isLoggedIn && !this.state.allowDismissal) {
|
||||
document.body.classList.add('error-bar--fixed');
|
||||
}
|
||||
|
||||
ErrorStore.addChangeListener(this.onErrorChange);
|
||||
AnalyticsStore.addChangeListener(this.onAnalyticsChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.body.classList.remove('error-bar--fixed');
|
||||
ErrorStore.removeChangeListener(this.onErrorChange);
|
||||
AnalyticsStore.removeChangeListener(this.onAnalyticsChange);
|
||||
}
|
||||
|
||||
onErrorChange() {
|
||||
var newState = ErrorStore.getLastError();
|
||||
|
||||
if (newState) {
|
||||
if (newState.message === ErrorBarTypes.LICENSE_EXPIRING && !this.state.totalUsers) {
|
||||
AsyncClient.getStandardAnalytics();
|
||||
}
|
||||
this.setState(newState);
|
||||
} else {
|
||||
this.setState({message: null});
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (!this.props.isLoggedIn) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!prevState.allowDismissal && this.state.allowDismissal) {
|
||||
document.body.classList.remove('error-bar--fixed');
|
||||
} else if (prevState.allowDismissal && !this.state.allowDismissal) {
|
||||
document.body.classList.add('error-bar--fixed');
|
||||
}
|
||||
}
|
||||
|
||||
onErrorChange() {
|
||||
const newState = this.getState();
|
||||
if (newState.message === ErrorBarTypes.LICENSE_EXPIRING && !this.state.totalUsers) {
|
||||
AsyncClient.getStandardAnalytics();
|
||||
}
|
||||
this.setState(newState);
|
||||
}
|
||||
|
||||
onAnalyticsChange() {
|
||||
@@ -115,28 +165,57 @@ export default class ErrorBar extends React.Component {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
if (this.state.type === BAR_ANNOUNCEMENT_TYPE) {
|
||||
localStorage.setItem(ANNOUNCEMENT_KEY + this.state.message, true);
|
||||
}
|
||||
|
||||
if (ErrorStore.getLastError() && ErrorStore.getLastError().notification) {
|
||||
ErrorStore.clearNotificationError();
|
||||
} else {
|
||||
ErrorStore.clearLastError();
|
||||
}
|
||||
|
||||
this.setState({message: null});
|
||||
this.setState(this.getState());
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.isValidError(this.state)) {
|
||||
if (!this.isValidState(this.state)) {
|
||||
return <div/>;
|
||||
}
|
||||
|
||||
var errClass = 'error-bar';
|
||||
if (!this.props.isLoggedIn && this.state.type === BAR_ANNOUNCEMENT_TYPE) {
|
||||
return <div/>;
|
||||
}
|
||||
|
||||
if (this.state.type === BAR_DEVELOPER_TYPE) {
|
||||
let errClass = 'error-bar';
|
||||
let dismissClass = ' error-bar--fixed';
|
||||
const barStyle = {};
|
||||
const linkStyle = {};
|
||||
if (this.state.color && this.state.textColor) {
|
||||
barStyle.backgroundColor = this.state.color;
|
||||
barStyle.color = this.state.textColor;
|
||||
linkStyle.color = this.state.textColor;
|
||||
} else if (this.state.type === BAR_DEVELOPER_TYPE) {
|
||||
errClass = 'error-bar-developer';
|
||||
} else if (this.state.type === BAR_CRITICAL_TYPE) {
|
||||
errClass = 'error-bar-critical';
|
||||
}
|
||||
|
||||
let closeButton;
|
||||
if (this.state.allowDismissal) {
|
||||
dismissClass = '';
|
||||
closeButton = (
|
||||
<a
|
||||
href='#'
|
||||
className='error-bar__close'
|
||||
style={linkStyle}
|
||||
onClick={this.handleClose}
|
||||
>
|
||||
{'×'}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
const renewalLink = RENEWAL_LINK + '?id=' + global.window.mm_license.Id + '&user_count=' + this.state.totalUsers;
|
||||
|
||||
let message = this.state.message;
|
||||
@@ -217,15 +296,12 @@ export default class ErrorBar extends React.Component {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={errClass}>
|
||||
<div
|
||||
className={errClass + dismissClass}
|
||||
style={barStyle}
|
||||
>
|
||||
<span>{message}</span>
|
||||
<a
|
||||
href='#'
|
||||
className='error-bar__close'
|
||||
onClick={this.handleClose}
|
||||
>
|
||||
{'×'}
|
||||
</a>
|
||||
{closeButton}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
16
webapp/components/announcement_bar/index.js
Обычный файл
16
webapp/components/announcement_bar/index.js
Обычный файл
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
import AnnouncementBar from './announcement_bar.jsx';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
...ownProps,
|
||||
isLoggedIn: Boolean(getCurrentUserId(state))
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(AnnouncementBar);
|
||||
@@ -10,7 +10,7 @@ import UserStore from 'stores/user_store.jsx';
|
||||
|
||||
import BackstageSidebar from './components/backstage_sidebar.jsx';
|
||||
import BackstageNavbar from './components/backstage_navbar.jsx';
|
||||
import ErrorBar from 'components/error_bar.jsx';
|
||||
import AnnouncementBar from 'components/announcement_bar';
|
||||
|
||||
export default class BackstageController extends React.Component {
|
||||
static get propTypes() {
|
||||
@@ -55,7 +55,7 @@ export default class BackstageController extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div className='backstage'>
|
||||
<ErrorBar/>
|
||||
<AnnouncementBar/>
|
||||
<BackstageNavbar team={this.state.team}/>
|
||||
<div className='backstage-body'>
|
||||
<BackstageSidebar
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import ErrorBar from 'components/error_bar.jsx';
|
||||
import AnnouncementBar from 'components/announcement_bar';
|
||||
import ChannelStore from 'stores/channel_store.jsx';
|
||||
import TeamStore from 'stores/team_store.jsx';
|
||||
|
||||
@@ -63,7 +63,7 @@ export default class CreateTeamController extends React.Component {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ErrorBar/>
|
||||
<AnnouncementBar/>
|
||||
<div className='signup-header'>
|
||||
<Link to={url}>
|
||||
<span className='fa fa-chevron-left'/>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import LoginMfa from './components/login_mfa.jsx';
|
||||
import ErrorBar from 'components/error_bar.jsx';
|
||||
import AnnouncementBar from 'components/announcement_bar';
|
||||
import FormError from 'components/form_error.jsx';
|
||||
|
||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||
@@ -621,7 +621,7 @@ export default class LoginController extends React.Component {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ErrorBar/>
|
||||
<AnnouncementBar/>
|
||||
<div className='col-sm-12'>
|
||||
<div className={'signup-team__container ' + customClass}>
|
||||
<div className='signup__markdown'>
|
||||
|
||||
@@ -23,7 +23,7 @@ import Constants from 'utils/constants.jsx';
|
||||
const TutorialSteps = Constants.TutorialSteps;
|
||||
const Preferences = Constants.Preferences;
|
||||
|
||||
import ErrorBar from 'components/error_bar.jsx';
|
||||
import AnnouncementBar from 'components/announcement_bar';
|
||||
import SidebarRight from 'components/sidebar_right.jsx';
|
||||
import SidebarRightMenu from 'components/sidebar_right_menu.jsx';
|
||||
import Navbar from 'components/navbar.jsx';
|
||||
@@ -211,7 +211,7 @@ export default class NeedsTeam extends React.Component {
|
||||
|
||||
return (
|
||||
<div className='channel-view'>
|
||||
<ErrorBar/>
|
||||
<AnnouncementBar/>
|
||||
<WebrtcNotification/>
|
||||
<div className='container-fluid'>
|
||||
<SidebarRight channel={channel}/>
|
||||
|
||||
@@ -5,7 +5,7 @@ import UserStore from 'stores/user_store.jsx';
|
||||
import TeamStore from 'stores/team_store.jsx';
|
||||
import * as UserAgent from 'utils/user_agent.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import ErrorBar from 'components/error_bar.jsx';
|
||||
import AnnouncementBar from 'components/announcement_bar';
|
||||
import LoadingScreen from 'components/loading_screen.jsx';
|
||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||
import SelectTeamItem from './components/select_team_item.jsx';
|
||||
@@ -218,7 +218,7 @@ export default class SelectTeam extends React.Component {
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<ErrorBar/>
|
||||
<AnnouncementBar/>
|
||||
<div className='signup-header'>
|
||||
{headerButton}
|
||||
</div>
|
||||
|
||||
@@ -18,7 +18,7 @@ import {addUserToTeamFromInvite, getInviteInfo} from 'actions/team_actions.jsx';
|
||||
import {loadMe} from 'actions/user_actions.jsx';
|
||||
|
||||
import logoImage from 'images/logo.png';
|
||||
import ErrorBar from 'components/error_bar.jsx';
|
||||
import AnnouncementBar from 'components/announcement_bar';
|
||||
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {browserHistory, Link} from 'react-router/es6';
|
||||
@@ -319,7 +319,7 @@ export default class SignupController extends React.Component {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ErrorBar/>
|
||||
<AnnouncementBar/>
|
||||
<div className='signup-header'>
|
||||
<Link to='/'>
|
||||
<span className='fa fa-chevron-left'/>
|
||||
|
||||
Ссылка в новой задаче
Block a user