diff options
Diffstat (limited to 'web/react/components')
-rw-r--r-- | web/react/components/edit_channel_header_modal.jsx | 52 | ||||
-rw-r--r-- | web/react/components/invite_member_modal.jsx | 19 | ||||
-rw-r--r-- | web/react/components/post_attachment_oembed.jsx | 9 | ||||
-rw-r--r-- | web/react/components/post_body.jsx | 6 | ||||
-rw-r--r-- | web/react/components/providers.json | 4 | ||||
-rw-r--r-- | web/react/components/sidebar.jsx | 50 | ||||
-rw-r--r-- | web/react/components/team_general_tab.jsx | 133 | ||||
-rw-r--r-- | web/react/components/user_settings/manage_outgoing_hooks.jsx | 2 |
8 files changed, 167 insertions, 108 deletions
diff --git a/web/react/components/edit_channel_header_modal.jsx b/web/react/components/edit_channel_header_modal.jsx index 209e30fcc..e4817f6e4 100644 --- a/web/react/components/edit_channel_header_modal.jsx +++ b/web/react/components/edit_channel_header_modal.jsx @@ -1,8 +1,9 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. +import AppDispatcher from '../dispatcher/app_dispatcher.jsx'; import * as Client from '../utils/client.jsx'; -import * as AsyncClient from '../utils/async_client.jsx'; +import Constants from '../utils/constants.jsx'; import * as Utils from '../utils/utils.jsx'; const Modal = ReactBootstrap.Modal; @@ -11,12 +12,14 @@ export default class EditChannelHeaderModal extends React.Component { constructor(props) { super(props); - this.handleEdit = this.handleEdit.bind(this); + this.handleChange = this.handleChange.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); this.onShow = this.onShow.bind(this); this.onHide = this.onHide.bind(this); this.state = { + header: props.channel.header, serverError: '' }; } @@ -27,27 +30,38 @@ export default class EditChannelHeaderModal extends React.Component { } } + componentWillReceiveProps(nextProps) { + if (this.props.channel.header !== nextProps.channel.header) { + this.setState({ + header: nextProps.channel.header + }); + } + } + componentDidUpdate(prevProps) { if (this.props.show && !prevProps.show) { this.onShow(); } } - handleEdit() { - var data = {}; - data.channel_id = this.props.channel.id; - - if (data.channel_id.length !== 26) { - return; - } - - data.channel_header = ReactDOM.findDOMNode(this.refs.textarea).value; + handleChange(e) { + this.setState({ + header: e.target.value + }); + } - Client.updateChannelHeader(data, - () => { + handleSubmit() { + Client.updateChannelHeader( + this.props.channel.id, + this.state.header, + (channel) => { this.setState({serverError: ''}); - AsyncClient.getChannel(this.props.channel.id); this.onHide(); + + AppDispatcher.handleServerAction({ + type: Constants.ActionTypes.RECIEVED_CHANNEL, + channel + }); }, (err) => { if (err.message === 'Invalid channel_header parameter') { @@ -66,7 +80,8 @@ export default class EditChannelHeaderModal extends React.Component { onHide() { this.setState({ - serverError: '' + serverError: '', + header: this.props.channel.header }); this.props.onHide(); @@ -94,7 +109,8 @@ export default class EditChannelHeaderModal extends React.Component { rows='6' id='edit_header' maxLength='1024' - defaultValue={this.props.channel.header} + value={this.state.header} + onChange={this.handleChange} /> {serverError} </Modal.Body> @@ -102,14 +118,14 @@ export default class EditChannelHeaderModal extends React.Component { <button type='button' className='btn btn-default' - onClick={this.props.onHide} + onClick={this.onHide} > {'Cancel'} </button> <button type='button' className='btn btn-primary' - onClick={this.handleEdit} + onClick={this.handleSubmit} > {'Save'} </button> diff --git a/web/react/components/invite_member_modal.jsx b/web/react/components/invite_member_modal.jsx index 649ec7321..56bc00a7e 100644 --- a/web/react/components/invite_member_modal.jsx +++ b/web/react/components/invite_member_modal.jsx @@ -33,6 +33,7 @@ export default class InviteMemberModal extends React.Component { firstNameErrors: {}, lastNameErrors: {}, emailEnabled: global.window.mm_config.SendEmailNotifications === 'true', + userCreationEnabled: global.window.mm_config.EnableUserCreation === 'true', showConfirmModal: false, isSendingEmails: false }; @@ -252,7 +253,7 @@ export default class InviteMemberModal extends React.Component { ref={'first_name' + index} placeholder='First name' maxLength='64' - disabled={!this.state.emailEnabled} + disabled={!this.state.emailEnabled || !this.state.userCreationEnabled} spellCheck='false' /> {firstNameError} @@ -266,7 +267,7 @@ export default class InviteMemberModal extends React.Component { ref={'last_name' + index} placeholder='Last name' maxLength='64' - disabled={!this.state.emailEnabled} + disabled={!this.state.emailEnabled || !this.state.userCreationEnabled} spellCheck='false' /> {lastNameError} @@ -285,7 +286,7 @@ export default class InviteMemberModal extends React.Component { className='form-control' placeholder='email@domain.com' maxLength='64' - disabled={!this.state.emailEnabled} + disabled={!this.state.emailEnabled || !this.state.userCreationEnabled} spellCheck='false' /> {emailError} @@ -303,7 +304,7 @@ export default class InviteMemberModal extends React.Component { var content = null; var sendButton = null; - if (this.state.emailEnabled) { + if (this.state.emailEnabled && this.state.userCreationEnabled) { content = ( <div> {serverError} @@ -337,7 +338,7 @@ export default class InviteMemberModal extends React.Component { {sendButtonLabel} </button> ); - } else { + } else if (this.state.userCreationEnabled) { var teamInviteLink = null; if (currentUser && TeamStore.getCurrent().type === 'O') { var link = ( @@ -358,10 +359,16 @@ export default class InviteMemberModal extends React.Component { content = ( <div> - <p>Email is currently disabled for your team, and email invitations cannot be sent. Contact your system administrator to enable email and email invitations.</p> + <p>{'Email is currently disabled for your team, and email invitations cannot be sent. Contact your system administrator to enable email and email invitations.'}</p> {teamInviteLink} </div> ); + } else { + content = ( + <div> + <p>{'User creation has been disabled for your team. Please ask your team administrator for details.'}</p> + </div> + ); } return ( diff --git a/web/react/components/post_attachment_oembed.jsx b/web/react/components/post_attachment_oembed.jsx index 13c32f744..4b12ee95e 100644 --- a/web/react/components/post_attachment_oembed.jsx +++ b/web/react/components/post_attachment_oembed.jsx @@ -14,7 +14,14 @@ export default class PostAttachmentOEmbed extends React.Component { } componentWillReceiveProps(nextProps) { - this.fetchData(nextProps.link); + if (nextProps.link !== this.props.link) { + this.isLoading = false; + this.fetchData(nextProps.link); + } + } + + componentDidMount() { + this.fetchData(this.props.link); } fetchData(link) { diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx index 35a7727e9..dcbe56399 100644 --- a/web/react/components/post_body.jsx +++ b/web/react/components/post_body.jsx @@ -214,14 +214,14 @@ export default class PostBody extends React.Component { } createYoutubeEmbed(link) { - const ytRegex = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|watch\?(?:[a-zA-Z-_]+=[a-zA-Z0-9-_]+&)+v=)([^#\&\?]*).*/; + const ytRegex = /(?:http|https):\/\/(?:www\.)?(?:(?:youtube\.com\/(?:(?:v\/)|(\/u\/\w\/)|(?:(?:watch|embed\/watch)(?:\/|.*v=))|(?:embed\/)|(?:user\/[^\/]+\/u\/[0-9]\/)))|(?:youtu\.be\/))([^#\&\?]*)/; const match = link.trim().match(ytRegex); - if (!match || match[1].length !== 11) { + if (!match || match[2].length !== 11) { return null; } - const youtubeId = match[1]; + const youtubeId = match[2]; const time = this.handleYoutubeTime(link); function onClick(e) { diff --git a/web/react/components/providers.json b/web/react/components/providers.json index 33e377a39..b5899c225 100644 --- a/web/react/components/providers.json +++ b/web/react/components/providers.json @@ -11,7 +11,7 @@ "https?://soundcloud.com/.*/.*" ], "name": "SoundCloud", - "height": 110 + "height": 140 }, { "patterns": [ @@ -349,7 +349,7 @@ "https?://vine.co/v/[a-zA-Z0-9]+" ], "name": "Vine", - "height": 110 + "height": 490 }, { "patterns": [ diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index 3d7f449d1..8393440cb 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -71,49 +71,47 @@ export default class Sidebar extends React.Component { getStateFromStores() { const members = ChannelStore.getAllMembers(); const currentChannelId = ChannelStore.getCurrentId(); + const currentUserId = UserStore.getCurrentId(); const channels = Object.assign([], ChannelStore.getAll()); channels.sort((a, b) => a.display_name.localeCompare(b.display_name)); const publicChannels = channels.filter((channel) => channel.type === Constants.OPEN_CHANNEL); const privateChannels = channels.filter((channel) => channel.type === Constants.PRIVATE_CHANNEL); - const directChannels = channels.filter((channel) => channel.type === Constants.DM_CHANNEL); const preferences = PreferenceStore.getPreferences(Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW); - var visibleDirectChannels = []; - for (var i = 0; i < directChannels.length; i++) { - const dm = directChannels[i]; - const teammate = Utils.getDirectTeammate(dm.id); - if (!teammate) { + const directChannels = []; + for (const preference of preferences) { + if (preference.value !== 'true') { continue; } - const member = members[dm.id]; - const msgCount = dm.total_msg_count - member.msg_count; + const teammateId = preference.name; - // always show a channel if either it is the current one or if it is unread, but it is not currently being left - const forceShow = (currentChannelId === dm.id || msgCount > 0) && !this.isLeaving.get(dm.id); - const preferenceShow = preferences.some((preference) => (preference.name === teammate.id && preference.value !== 'false')); + let directChannel = channels.find(Utils.isDirectChannelForUser.bind(null, teammateId)); - if (preferenceShow || forceShow) { - dm.display_name = Utils.displayUsername(teammate.id); - dm.teammate_id = teammate.id; - dm.status = UserStore.getStatus(teammate.id); + // a direct channel doesn't exist yet so create a fake one + if (!directChannel) { + directChannel = { + name: Utils.getDirectChannelName(currentUserId, teammateId), + last_post_at: 0, + total_msg_count: 0, + type: Constants.DM_CHANNEL, + fake: true + }; + } - visibleDirectChannels.push(dm); + directChannel.display_name = Utils.displayUsername(teammateId); + directChannel.teammate_id = teammateId; + directChannel.status = UserStore.getStatus(teammateId); - if (forceShow && !preferenceShow) { - // make sure that unread direct channels are visible - const preference = PreferenceStore.setPreference(Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, teammate.id, 'true'); - AsyncClient.savePreferences([preference]); - } - } + directChannels.push(directChannel); } - const hiddenDirectChannelCount = UserStore.getActiveOnlyProfileList(true).length - visibleDirectChannels.length; + directChannels.sort(this.sortChannelsByDisplayName); - visibleDirectChannels.sort(this.sortChannelsByDisplayName); + const hiddenDirectChannelCount = UserStore.getActiveOnlyProfileList(true).length - directChannels.length; const tutorialPref = PreferenceStore.getPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), {value: '999'}); @@ -122,7 +120,7 @@ export default class Sidebar extends React.Component { members, publicChannels, privateChannels, - visibleDirectChannels, + directChannels, hiddenDirectChannelCount, unreadCounts: JSON.parse(JSON.stringify(ChannelStore.getUnreadCounts())), showTutorialTip: parseInt(tutorialPref.value, 10) === TutorialSteps.CHANNEL_POPOVER @@ -484,7 +482,7 @@ export default class Sidebar extends React.Component { const privateChannelItems = this.state.privateChannels.map(this.createChannelElement); - const directMessageItems = this.state.visibleDirectChannels.map((channel, index, arr) => { + const directMessageItems = this.state.directChannels.map((channel, index, arr) => { return this.createChannelElement(channel, index, arr, this.handleLeaveDirectChannel); }); diff --git a/web/react/components/team_general_tab.jsx b/web/react/components/team_general_tab.jsx index 03715d585..dc615f2e8 100644 --- a/web/react/components/team_general_tab.jsx +++ b/web/react/components/team_general_tab.jsx @@ -12,6 +12,7 @@ export default class GeneralTab extends React.Component { constructor(props) { super(props); + this.updateSection = this.updateSection.bind(this); this.handleNameSubmit = this.handleNameSubmit.bind(this); this.handleInviteIdSubmit = this.handleInviteIdSubmit.bind(this); this.handleOpenInviteSubmit = this.handleOpenInviteSubmit.bind(this); @@ -27,11 +28,22 @@ export default class GeneralTab extends React.Component { this.handleTeamListingRadio = this.handleTeamListingRadio.bind(this); this.handleGenerateInviteId = this.handleGenerateInviteId.bind(this); - this.state = { - name: props.team.display_name, - invite_id: props.team.invite_id, - allow_open_invite: props.team.allow_open_invite, - allow_team_listing: props.team.allow_team_listing, + this.state = this.setupInitialState(props); + } + + updateSection(section) { + this.setState(this.setupInitialState(this.props)); + this.props.updateSection(section); + } + + setupInitialState(props) { + const team = props.team; + + return { + name: team.display_name, + invite_id: team.invite_id, + allow_open_invite: team.allow_open_invite, + allow_team_listing: team.allow_team_listing, serverError: '', clientError: '' }; @@ -71,7 +83,7 @@ export default class GeneralTab extends React.Component { (team) => { TeamStore.saveTeam(team); TeamStore.emitChange(); - this.props.updateSection(''); + this.updateSection(''); }, (err) => { state.serverError = err.message; @@ -91,7 +103,7 @@ export default class GeneralTab extends React.Component { (team) => { TeamStore.saveTeam(team); TeamStore.emitChange(); - this.props.updateSection(''); + this.updateSection(''); }, (err) => { state.serverError = err.message; @@ -129,7 +141,7 @@ export default class GeneralTab extends React.Component { (team) => { TeamStore.saveTeam(team); TeamStore.emitChange(); - this.props.updateSection(''); + this.updateSection(''); }, (err) => { state.serverError = err.message; @@ -164,7 +176,7 @@ export default class GeneralTab extends React.Component { (team) => { TeamStore.saveTeam(team); TeamStore.emitChange(); - this.props.updateSection(''); + this.updateSection(''); }, (err) => { state.serverError = err.message; @@ -180,8 +192,7 @@ export default class GeneralTab extends React.Component { } handleClose() { - this.setState({clientError: '', serverError: ''}); - this.props.updateSection(''); + this.updateSection(''); } componentDidMount() { @@ -195,36 +206,36 @@ export default class GeneralTab extends React.Component { onUpdateNameSection(e) { e.preventDefault(); if (this.props.activeSection === 'name') { - this.props.updateSection(''); + this.updateSection(''); } else { - this.props.updateSection('name'); + this.updateSection('name'); } } onUpdateInviteIdSection(e) { e.preventDefault(); if (this.props.activeSection === 'invite_id') { - this.props.updateSection(''); + this.updateSection(''); } else { - this.props.updateSection('invite_id'); + this.updateSection('invite_id'); } } onUpdateOpenInviteSection(e) { e.preventDefault(); if (this.props.activeSection === 'open_invite') { - this.props.updateSection(''); + this.updateSection(''); } else { - this.props.updateSection('open_invite'); + this.updateSection('open_invite'); } } onUpdateTeamListingSection(e) { e.preventDefault(); if (this.props.activeSection === 'team_listing') { - this.props.updateSection(''); + this.updateSection(''); } else { - this.props.updateSection('team_listing'); + this.updateSection('team_listing'); } } @@ -248,44 +259,59 @@ export default class GeneralTab extends React.Component { serverError = this.state.serverError; } + const enableTeamListing = global.window.mm_config.EnableTeamListing === 'true'; + let teamListingSection; if (this.props.activeSection === 'team_listing') { - const inputs = [ - <div key='userTeamListingOptions'> - <div className='radio'> - <label> - <input - name='userTeamListingOptions' - type='radio' - defaultChecked={this.state.allow_team_listing} - onChange={this.handleTeamListingRadio.bind(this, true)} - /> - {'Yes'} - </label> - <br/> + const inputs = []; + let submitHandle = null; + + if (enableTeamListing) { + submitHandle = this.handleTeamListingSubmit; + + inputs.push( + <div key='userTeamListingOptions'> + <div className='radio'> + <label> + <input + name='userTeamListingOptions' + type='radio' + defaultChecked={this.state.allow_team_listing} + onChange={this.handleTeamListingRadio.bind(this, true)} + /> + {'Yes'} + </label> + <br/> + </div> + <div className='radio'> + <label> + <input + ref='teamListingRadioNo' + name='userTeamListingOptions' + type='radio' + defaultChecked={!this.state.allow_team_listing} + onChange={this.handleTeamListingRadio.bind(this, false)} + /> + {'No'} + </label> + <br/> + </div> + <div><br/>{'Including this team will display the team name from the Team Directory section of the Home Page, and provide a link to the sign-in page.'}</div> </div> - <div className='radio'> - <label> - <input - ref='teamListingRadioNo' - name='userTeamListingOptions' - type='radio' - defaultChecked={!this.state.allow_team_listing} - onChange={this.handleTeamListingRadio.bind(this, false)} - /> - {'No'} - </label> - <br/> + ); + } else { + inputs.push( + <div key='userTeamListingOptions'> + <div><br/>{'Contact your system administrator to turn on the team directory on the system home page.'}</div> </div> - <div><br/>{'Including this team will display the team name from the Team Directory section of the Home Page, and provide a link to the sign-in page.'}</div> - </div> - ]; + ); + } teamListingSection = ( <SettingItemMax title='Include this team in the Team Directory' inputs={inputs} - submit={this.handleTeamListingSubmit} + submit={submitHandle} server_error={serverError} client_error={clientError} updateSection={this.onUpdateTeamListingSection} @@ -293,10 +319,15 @@ export default class GeneralTab extends React.Component { ); } else { let describe = ''; - if (this.state.allow_team_listing === true) { - describe = 'Yes'; + + if (enableTeamListing) { + if (this.state.allow_team_listing === true) { + describe = 'Yes'; + } else { + describe = 'No'; + } } else { - describe = 'No'; + describe = 'Team directory is turned off for this system.'; } teamListingSection = ( diff --git a/web/react/components/user_settings/manage_outgoing_hooks.jsx b/web/react/components/user_settings/manage_outgoing_hooks.jsx index 9c0fe3709..fdbac9831 100644 --- a/web/react/components/user_settings/manage_outgoing_hooks.jsx +++ b/web/react/components/user_settings/manage_outgoing_hooks.jsx @@ -1,4 +1,4 @@ -// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. import LoadingScreen from '../loading_screen.jsx'; |