Skip to content
This repository has been archived by the owner on Mar 13, 2024. It is now read-only.

MM-24086:Disable changing picture if LDAP sync'ed #5465

Merged
merged 7 commits into from
May 20, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Disable changing picture if LDAP sync'ed
  • Loading branch information
sbishel committed May 8, 2020
commit 9e5699a47fe95a19eb5da27a1bc50a1def3c76c5
678 changes: 320 additions & 358 deletions components/__snapshots__/setting_picture.test.jsx.snap

Large diffs are not rendered by default.

123 changes: 53 additions & 70 deletions components/setting_picture.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,14 @@ import {FormattedMessage} from 'react-intl';
import {Tooltip} from 'react-bootstrap';

import {Constants} from 'utils/constants';
import {fileSizeToString, localizeMessage} from 'utils/utils.jsx';
import {localizeMessage} from 'utils/utils.jsx';
import * as FileUtils from 'utils/file_utils.jsx';

import FormError from 'components/form_error';
import FormattedMarkdownMessage from 'components/formatted_markdown_message.jsx';
import OverlayTrigger from 'components/overlay_trigger';
import LoadingWrapper from 'components/widgets/loading/loading_wrapper';

export default class SettingPicture extends Component {
static defaultProps = {
imageContext: 'profile',
};

static propTypes = {
clientError: PropTypes.string,
serverError: PropTypes.string,
Expand All @@ -34,8 +29,8 @@ export default class SettingPicture extends Component {
title: PropTypes.string,
onFileChange: PropTypes.func,
updateSection: PropTypes.func,
imageContext: PropTypes.string,
maxFileSize: PropTypes.number,
helpText: PropTypes.object,
};

constructor(props) {
Expand Down Expand Up @@ -243,8 +238,6 @@ export default class SettingPicture extends Component {
}

render() {
const imageContext = this.props.imageContext;

const img = this.renderImg();

let confirmButtonClass = 'btn btn-sm';
Expand All @@ -256,24 +249,6 @@ export default class SettingPicture extends Component {
disableSaveButtonFocus = true;
}

let helpText;
if (imageContext === 'team') {
helpText = (
<FormattedMarkdownMessage
id={'setting_picture.help.team'}
defaultMessage='Upload a team icon in BMP, JPG or PNG format.\nSquare images with a solid background color are recommended.'
/>
);
} else {
helpText = (
<FormattedMessage
id={'setting_picture.help.profile'}
defaultMessage='Upload a picture in BMP, JPG or PNG format. Maximum file size: {max}'
values={{max: fileSizeToString(this.props.maxFileSize)}}
/>
);
}

let imgRender;
if (img) {
imgRender = (
Expand All @@ -286,6 +261,55 @@ export default class SettingPicture extends Component {
);
}

let buttonRender;
if (this.props.onSubmit) {
buttonRender = (
<span>
<input
data-testid='uploadPicture'
ref={this.selectInput}
className='hidden'
accept='.jpg,.png,.bmp'
type='file'
onChange={this.handleFileChange}
disabled={this.props.loadingPicture}
aria-hidden={true}
tabIndex='-1'
/>
<button
data-testid='inputSettingPictureButton'
className='btn btn-sm btn-primary btn-file sel-btn'
disabled={this.props.loadingPicture}
onClick={this.handleInputFile}
aria-label={localizeMessage('setting_picture.select', 'Select')}
>
<FormattedMessage
id='setting_picture.select'
defaultMessage='Select'
/>
</button>
<button
tabIndex={disableSaveButtonFocus ? '-1' : '0'}
data-testid='saveSettingPicture'
disabled={disableSaveButtonFocus}
ref={this.confirmButton}
className={confirmButtonClass}
onClick={this.props.loadingPicture ? () => true : this.handleSave}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The () => true function will create a new function every time causing unnecessary re-renders downstream vs creating a this.returnTrue method on the SettingPicture component.

aria-label={this.props.loadingPicture ? localizeMessage('setting_picture.uploading', 'Uploading...') : localizeMessage('setting_picture.save', 'Save')}
>
<LoadingWrapper
loading={this.props.loadingPicture}
text={localizeMessage('setting_picture.uploading', 'Uploading...')}
>
<FormattedMessage
id='setting_picture.save'
defaultMessage='Save'
/>
</LoadingWrapper>
</button>
</span>
);
}
return (
<section className='section-max form-horizontal'>
<h4 className='col-xs-12 section-title'>
Expand All @@ -304,7 +328,7 @@ export default class SettingPicture extends Component {
id='setting-picture__helptext'
className='setting-list-item pt-3'
>
{helpText}
{this.props.helpText}
</div>
<div
className='setting-list-item'
Expand All @@ -314,48 +338,7 @@ export default class SettingPicture extends Component {
errors={[this.props.clientError, this.props.serverError]}
type={'modal'}
/>
<input
data-testid='uploadPicture'
ref={this.selectInput}
className='hidden'
accept='.jpg,.png,.bmp'
type='file'
onChange={this.handleFileChange}
disabled={this.props.loadingPicture}
aria-hidden={true}
tabIndex='-1'
/>
<button
data-testid='inputSettingPictureButton'
className='btn btn-sm btn-primary btn-file sel-btn'
disabled={this.props.loadingPicture}
onClick={this.handleInputFile}
aria-label={localizeMessage('setting_picture.select', 'Select')}
>
<FormattedMessage
id='setting_picture.select'
defaultMessage='Select'
/>
</button>
<button
tabIndex={disableSaveButtonFocus ? '-1' : '0'}
data-testid='saveSettingPicture'
disabled={disableSaveButtonFocus}
ref={this.confirmButton}
className={confirmButtonClass}
onClick={this.props.loadingPicture ? () => true : this.handleSave}
aria-label={this.props.loadingPicture ? localizeMessage('setting_picture.uploading', 'Uploading...') : localizeMessage('setting_picture.save', 'Save')}
>
<LoadingWrapper
loading={this.props.loadingPicture}
text={localizeMessage('setting_picture.uploading', 'Uploading...')}
>
<FormattedMessage
id='setting_picture.save'
defaultMessage='Save'
/>
</LoadingWrapper>
</button>
{buttonRender}
<button
data-testid='cancelSettingPicture'
className='btn btn-link btn-sm theme'
Expand Down
10 changes: 10 additions & 0 deletions components/setting_picture.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,17 @@
import React from 'react';
import {shallow} from 'enzyme';

import FormattedMarkdownMessage from 'components/formatted_markdown_message.jsx';
import SettingPicture from 'components/setting_picture.jsx';

const helpText = (
<FormattedMarkdownMessage
id={'setting_picture.help.profile'}
defaultMessage='Upload a picture in BMP, JPG or PNG format. Maximum file size: {max}'
values={{max: 52428800}}
/>
);

describe('components/SettingItemMin', () => {
const baseProps = {
clientError: '',
Expand All @@ -18,6 +27,7 @@ describe('components/SettingItemMin', () => {
onFileChange: () => {}, // eslint-disable-line no-empty-function
updateSection: () => {}, // eslint-disable-line no-empty-function
maxFileSize: 209715200,
helpText: {helpText}
};

test('should match snapshot, profile picture on source', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ exports[`components/TeamSettings hide invite code if no permissions for team inv
<SettingPicture
clientError=""
file={null}
helpText={
<injectIntl(FormattedMarkdownMessage)
defaultMessage="Upload a team icon in BMP, JPG or PNG format.\\\\nSquare images with a solid background color are recommended."
id="setting_picture.help.team"
/>
}
imageContext="team"
loadingPicture={false}
onFileChange={[Function]}
Expand Down Expand Up @@ -209,6 +215,12 @@ exports[`components/TeamSettings hide invite code if no permissions for team inv
<SettingPicture
clientError=""
file={null}
helpText={
<injectIntl(FormattedMarkdownMessage)
defaultMessage="Upload a team icon in BMP, JPG or PNG format.\\\\nSquare images with a solid background color are recommended."
id="setting_picture.help.team"
/>
}
imageContext="team"
loadingPicture={false}
onFileChange={[Function]}
Expand Down Expand Up @@ -328,6 +340,12 @@ exports[`components/TeamSettings should match snapshot when team is group constr
<SettingPicture
clientError=""
file={null}
helpText={
<injectIntl(FormattedMarkdownMessage)
defaultMessage="Upload a team icon in BMP, JPG or PNG format.\\\\nSquare images with a solid background color are recommended."
id="setting_picture.help.team"
/>
}
imageContext="team"
loadingPicture={false}
onFileChange={[Function]}
Expand Down
8 changes: 7 additions & 1 deletion components/team_general_tab/team_general_tab.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -649,9 +649,14 @@ export default class GeneralTab extends React.Component {

let teamIconSection;
if (this.props.activeSection === 'team_icon') {
const helpText = (
<FormattedMarkdownMessage
id={'setting_picture.help.team'}
defaultMessage='Upload a team icon in BMP, JPG or PNG format.\nSquare images with a solid background color are recommended.'
/>
);
teamIconSection = (
<SettingPicture
imageContext='team'
title={Utils.localizeMessage('general_tab.teamIcon', 'Team Icon')}
src={Utils.imageURLForTeam(team)}
file={this.state.teamIconFile}
Expand All @@ -666,6 +671,7 @@ export default class GeneralTab extends React.Component {
onFileChange={this.updateTeamIcon}
onSubmit={this.handleTeamIconSubmit}
onRemove={this.handleTeamIconRemove}
helpText={helpText}
/>
);
} else {
Expand Down
10 changes: 9 additions & 1 deletion components/team_general_tab/team_general_tab.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,22 @@
import React from 'react';
import {shallow} from 'enzyme';

import FormattedMarkdownMessage from 'components/formatted_markdown_message.jsx';
import GeneralTab from 'components/team_general_tab/team_general_tab.jsx';

const helpText = (
<FormattedMarkdownMessage
id='setting_picture.help.team'
defaultMessage='Upload a team icon in BMP, JPG or PNG format.\\nSquare images with a solid background color are recommended.'
/>
);

describe('components/TeamSettings', () => {
const getTeam = jest.fn().mockResolvedValue({data: true});
const patchTeam = jest.fn().mockReturnValue({data: true});
const regenerateTeamInviteId = jest.fn().mockReturnValue({data: true});
const removeTeamIcon = jest.fn().mockReturnValue({data: true});
const setTeamIcon = jest.fn().mockReturnValue({data: true});

const baseActions = {
getTeam,
patchTeam,
Expand All @@ -28,6 +35,7 @@ describe('components/TeamSettings', () => {
collapseModal: jest.fn(),
actions: baseActions,
canInviteTeamMembers: true,
helpText: {helpText}
};

test('should handle bad updateTeamIcon function call', () => {
Expand Down
2 changes: 2 additions & 0 deletions components/user_settings/general/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ function mapStateToProps(state) {
const samlNicknameAttributeSet = config.SamlNicknameAttributeSet === 'true';
const samlPositionAttributeSet = config.SamlPositionAttributeSet === 'true';
const ldapPositionAttributeSet = config.LdapPositionAttributeSet === 'true';
const ldapPictureAttributeSet = config.LdapPictureAttributeSet === 'true';

return {
requireEmailVerification,
Expand All @@ -40,6 +41,7 @@ function mapStateToProps(state) {
samlNicknameAttributeSet,
samlPositionAttributeSet,
ldapPositionAttributeSet,
ldapPictureAttributeSet,
};
}

Expand Down
Loading