MM-62046 Associate most labels with controls and enable label-has-associated-control ESLint rule (#29510)

* Remove label from add_user_to_channel_modal.tsx

The label isn't needed here because it was incorrectly used for error
text. I had to add the display: block to the .modal__error class to
ensure the top margin was the same as before, but I could remove the
font-weight from that class since it was only needed to counteract
the weight that Bootstrap adds for labels.
:

* Remove label from bleve_settings.tsx and replace with SettingSet

It doesn't seem correct to use a label here because it isn't tied to a
single form field. Since this component is a set of fields (a fieldset,
if you will) that looks like a setting, it seemed like a good place to
use SettingSet.

* Remove label from brand_image_setting.tsx, replace with SettingSet, and improve a11y of upload button

Like the last commit for BleveSettings, this setting is multiple inputs,
so it makes more sense as a fieldset/SettingSet.

While doing that, I also changed how the file upload button in
BrandImageSetting works because the new HTML broke how it worked before.
Previously, we overlayed an transparent file input over the button for it,
but the sizing for that got messed up, and that causes some weird
accessibility and breaks some things like hover effects. Instead, the
file input is now fully hidden, and clicking on the button triggers the
file input programatically. The behaviour is otherwise the same, but the
button now shows the hover style and there's only one keyboard focus for
the button.

* Remove some more labels from PluginManagement and use SettingSet there

* Add for attribute to labels in compliance_reports.tsx

* Use SettingSet and add the for attribute to another label in DatabaseSettings

* Use SettingSet in ElasticsearchSettings

* Add for attribute to label in GroupProfile

* Don't use label for help text in TeamEditionRightPanel

For this, I had to add a new CSS class to make the element appear as if
it was a label element as affected by Bootstrap. There's likely some
cases that this won't work, but it applies the same margin and
font-weight.

* Don't use label for help text in TrialBanner

* Don't use label for a heading in PasswordSettings

* Don't use label element in table in ChannelModeration

This text is more like a legend element in SettingSet, but I didn't use
that because it's in a table. This could possibly be given its own
CSS class.

* Don't use label element for error text in AdvancedTextEditor and MessageSubmitError

* Don't use label for help text and add for attribute in RenameChannelModal

* Don't use label for error text in SelectTeam

* Add for attribute to labels in various components

* Turn jsx-a11y/label-has-associated-control to an error

* Fix E2E test
Этот коммит содержится в:
Harrison Healey
2024-12-17 16:50:06 -05:00
коммит произвёл GitHub
родитель 0e4e7ca0b9
Коммит f11ed97a5c
40 изменённых файлов: 1373 добавлений и 1568 удалений

Просмотреть файл

@@ -36,7 +36,7 @@ describe('Customization', () => {
cy.findByTestId('CustomBrandImage').should('be.visible').within(() => { cy.findByTestId('CustomBrandImage').should('be.visible').within(() => {
// * Verify that setting is visible and matches text content // * Verify that setting is visible and matches text content
cy.get('label').should('be.visible').and('have.text', 'Custom Brand Image:'); cy.get('legend').should('be.visible').and('have.text', 'Custom Brand Image:');
// * Verify that help setting is visible and matches text content // * Verify that help setting is visible and matches text content
const contents = 'Customize your user experience by adding a custom image to your login screen. Recommended maximum image size is less than 2 MB.'; const contents = 'Customize your user experience by adding a custom image to your login screen. Recommended maximum image size is less than 2 MB.';

Просмотреть файл

@@ -95,9 +95,7 @@ exports[`components/AddUserToChannelModal should match snapshot 1`] = `
value="" value=""
/> />
</div> </div>
<div> <div />
<br />
</div>
</ModalBody> </ModalBody>
<ModalFooter <ModalFooter
bsClass="modal-footer" bsClass="modal-footer"

Просмотреть файл

@@ -224,16 +224,16 @@ export default class AddUserToChannelModal extends React.PureComponent<Props, St
if (!this.state.saving) { if (!this.state.saving) {
if (this.state.submitError) { if (this.state.submitError) {
errorMsg = ( errorMsg = (
<label <span
id='add-user-to-channel-modal__invite-error' id='add-user-to-channel-modal__invite-error'
className='modal__error has-error control-label' className='modal__error has-error control-label'
> >
{this.state.submitError} {this.state.submitError}
</label> </span>
); );
} else if (targetUserIsMemberOfSelectedChannel) { } else if (targetUserIsMemberOfSelectedChannel) {
errorMsg = ( errorMsg = (
<label <span
id='add-user-to-channel-modal__user-is-member' id='add-user-to-channel-modal__user-is-member'
className='modal__error has-error control-label' className='modal__error has-error control-label'
> >
@@ -244,7 +244,7 @@ export default class AddUserToChannelModal extends React.PureComponent<Props, St
name, name,
}} }}
/> />
</label> </span>
); );
} }
} }
@@ -317,7 +317,6 @@ export default class AddUserToChannelModal extends React.PureComponent<Props, St
</div> </div>
<div> <div>
{errorMsg} {errorMsg}
<br/>
</div> </div>
</Modal.Body> </Modal.Body>
<Modal.Footer> <Modal.Footer>

Просмотреть файл

@@ -57,43 +57,36 @@ exports[`components/BleveSettings should match snapshot, disabled 1`] = `
setByEnv={false} setByEnv={false}
value="" value=""
/> />
<div <SettingSet
className="form-group" label={
> <Memo(MemoizedFormattedMessage)
<label
className="control-label col-sm-4"
>
<MemoizedFormattedMessage
defaultMessage="Bulk Indexing:" defaultMessage="Bulk Indexing:"
id="admin.bleve.bulkIndexingTitle" id="admin.bleve.bulkIndexingTitle"
/> />
</label> }
>
<div <div
className="col-sm-8" className="job-table-setting"
> >
<div <Connect(JobTable)
className="job-table-setting" createJobButtonText={
> <Memo(MemoizedFormattedMessage)
<Connect(JobTable) defaultMessage="Index Now"
createJobButtonText={ id="admin.bleve.createJob.title"
<Memo(MemoizedFormattedMessage) />
defaultMessage="Index Now" }
id="admin.bleve.createJob.title" createJobHelpText={
/> <Memo(MemoizedFormattedMessage)
} defaultMessage="All users, channels and posts in the database will be indexed from oldest to newest. Bleve is available during indexing but search results may be incomplete until the indexing job is complete."
createJobHelpText={ id="admin.bleve.createJob.help"
<Memo(MemoizedFormattedMessage) />
defaultMessage="All users, channels and posts in the database will be indexed from oldest to newest. Bleve is available during indexing but search results may be incomplete until the indexing job is complete." }
id="admin.bleve.createJob.help" disabled={true}
/> getExtraInfoText={[Function]}
} jobType="bleve_post_indexing"
disabled={true} />
getExtraInfoText={[Function]}
jobType="bleve_post_indexing"
/>
</div>
</div> </div>
</div> </SettingSet>
<RequestButton <RequestButton
buttonText={ buttonText={
<Memo(MemoizedFormattedMessage) <Memo(MemoizedFormattedMessage)
@@ -260,43 +253,36 @@ exports[`components/BleveSettings should match snapshot, enabled 1`] = `
setByEnv={false} setByEnv={false}
value="bleve.idx" value="bleve.idx"
/> />
<div <SettingSet
className="form-group" label={
> <Memo(MemoizedFormattedMessage)
<label
className="control-label col-sm-4"
>
<MemoizedFormattedMessage
defaultMessage="Bulk Indexing:" defaultMessage="Bulk Indexing:"
id="admin.bleve.bulkIndexingTitle" id="admin.bleve.bulkIndexingTitle"
/> />
</label> }
>
<div <div
className="col-sm-8" className="job-table-setting"
> >
<div <Connect(JobTable)
className="job-table-setting" createJobButtonText={
> <Memo(MemoizedFormattedMessage)
<Connect(JobTable) defaultMessage="Index Now"
createJobButtonText={ id="admin.bleve.createJob.title"
<Memo(MemoizedFormattedMessage) />
defaultMessage="Index Now" }
id="admin.bleve.createJob.title" createJobHelpText={
/> <Memo(MemoizedFormattedMessage)
} defaultMessage="All users, channels and posts in the database will be indexed from oldest to newest. Bleve is available during indexing but search results may be incomplete until the indexing job is complete."
createJobHelpText={ id="admin.bleve.createJob.help"
<Memo(MemoizedFormattedMessage) />
defaultMessage="All users, channels and posts in the database will be indexed from oldest to newest. Bleve is available during indexing but search results may be incomplete until the indexing job is complete." }
id="admin.bleve.createJob.help" disabled={false}
/> getExtraInfoText={[Function]}
} jobType="bleve_post_indexing"
disabled={false} />
getExtraInfoText={[Function]}
jobType="bleve_post_indexing"
/>
</div>
</div> </div>
</div> </SettingSet>
<RequestButton <RequestButton
buttonText={ buttonText={
<Memo(MemoizedFormattedMessage) <Memo(MemoizedFormattedMessage)

Просмотреть файл

@@ -340,39 +340,33 @@ exports[`components/DatabaseSettings should match snapshot 1`] = `
setByEnv={false} setByEnv={false}
value={true} value={true}
/> />
<div <SettingSet
className="form-group" label={
> <Memo(MemoizedFormattedMessage)
<label
className="control-label col-sm-4"
>
<MemoizedFormattedMessage
defaultMessage="Schema Migrations:" defaultMessage="Schema Migrations:"
id="admin.database.migrations_table.title" id="admin.database.migrations_table.title"
/> />
</label> }
>
<div <div
className="col-sm-8" className="migrations-table-setting"
> >
<div <Connect(Component)
className="migrations-table-setting" createHelpText={
> <Memo(MemoizedFormattedMessage)
<Connect(Component) defaultMessage="All applied migrations."
createHelpText={ id="admin.database.migrations_table.help_text"
<Memo(MemoizedFormattedMessage) />
defaultMessage="All applied migrations." }
id="admin.database.migrations_table.help_text" />
/>
}
/>
</div>
</div> </div>
</div> </SettingSet>
<div <div
className="form-group" className="form-group"
> >
<label <label
className="control-label col-sm-4" className="control-label col-sm-4"
htmlFor="activeSearchBackend"
> >
<MemoizedFormattedMessage <MemoizedFormattedMessage
defaultMessage="Active Search Backend:" defaultMessage="Active Search Backend:"
@@ -385,6 +379,7 @@ exports[`components/DatabaseSettings should match snapshot 1`] = `
<input <input
className="form-control" className="form-control"
disabled={true} disabled={true}
id="activeSearchBackend"
type="text" type="text"
value="" value=""
/> />

Просмотреть файл

@@ -288,43 +288,36 @@ exports[`components/ElasticSearchSettings should match snapshot, disabled 1`] =
} }
} }
/> />
<div <SettingSet
className="form-group" label={
> <Memo(MemoizedFormattedMessage)
<label
className="control-label col-sm-4"
>
<MemoizedFormattedMessage
defaultMessage="Bulk Indexing:" defaultMessage="Bulk Indexing:"
id="admin.elasticsearch.bulkIndexingTitle" id="admin.elasticsearch.bulkIndexingTitle"
/> />
</label> }
>
<div <div
className="col-sm-8" className="job-table-setting"
> >
<div <Connect(JobTable)
className="job-table-setting" createJobButtonText={
> <Memo(MemoizedFormattedMessage)
<Connect(JobTable) defaultMessage="Index Now"
createJobButtonText={ id="admin.elasticsearch.createJob.title"
<Memo(MemoizedFormattedMessage) />
defaultMessage="Index Now" }
id="admin.elasticsearch.createJob.title" createJobHelpText={
/> <Memo(MemoizedFormattedMessage)
} defaultMessage="All users, channels and posts in the database will be indexed from oldest to newest. Elasticsearch is available during indexing but search results may be incomplete until the indexing job is complete."
createJobHelpText={ id="admin.elasticsearch.createJob.help"
<Memo(MemoizedFormattedMessage) />
defaultMessage="All users, channels and posts in the database will be indexed from oldest to newest. Elasticsearch is available during indexing but search results may be incomplete until the indexing job is complete." }
id="admin.elasticsearch.createJob.help" disabled={true}
/> getExtraInfoText={[Function]}
} jobType="elasticsearch_post_indexing"
disabled={true} />
getExtraInfoText={[Function]}
jobType="elasticsearch_post_indexing"
/>
</div>
</div> </div>
</div> </SettingSet>
<RequestButton <RequestButton
buttonText={ buttonText={
<Memo(MemoizedFormattedMessage) <Memo(MemoizedFormattedMessage)
@@ -790,42 +783,35 @@ exports[`components/ElasticSearchSettings should match snapshot, enabled 1`] = `
} }
} }
/> />
<div <SettingSet
className="form-group" label={
> <Memo(MemoizedFormattedMessage)
<label
className="control-label col-sm-4"
>
<MemoizedFormattedMessage
defaultMessage="Bulk Indexing:" defaultMessage="Bulk Indexing:"
id="admin.elasticsearch.bulkIndexingTitle" id="admin.elasticsearch.bulkIndexingTitle"
/> />
</label> }
>
<div <div
className="col-sm-8" className="job-table-setting"
> >
<div <Connect(JobTable)
className="job-table-setting" createJobButtonText={
> <Memo(MemoizedFormattedMessage)
<Connect(JobTable) defaultMessage="Index Now"
createJobButtonText={ id="admin.elasticsearch.createJob.title"
<Memo(MemoizedFormattedMessage) />
defaultMessage="Index Now" }
id="admin.elasticsearch.createJob.title" createJobHelpText={
/> <Memo(MemoizedFormattedMessage)
} defaultMessage="All users, channels and posts in the database will be indexed from oldest to newest. Elasticsearch is available during indexing but search results may be incomplete until the indexing job is complete."
createJobHelpText={ id="admin.elasticsearch.createJob.help"
<Memo(MemoizedFormattedMessage) />
defaultMessage="All users, channels and posts in the database will be indexed from oldest to newest. Elasticsearch is available during indexing but search results may be incomplete until the indexing job is complete." }
id="admin.elasticsearch.createJob.help" getExtraInfoText={[Function]}
/> jobType="elasticsearch_post_indexing"
} />
getExtraInfoText={[Function]}
jobType="elasticsearch_post_indexing"
/>
</div>
</div> </div>
</div> </SettingSet>
<RequestButton <RequestButton
buttonText={ buttonText={
<Memo(MemoizedFormattedMessage) <Memo(MemoizedFormattedMessage)

Просмотреть файл

@@ -18,6 +18,7 @@ import JobsTable from './jobs';
import OLDAdminSettings from './old_admin_settings'; import OLDAdminSettings from './old_admin_settings';
import type {BaseProps, BaseState} from './old_admin_settings'; import type {BaseProps, BaseState} from './old_admin_settings';
import RequestButton from './request_button/request_button'; import RequestButton from './request_button/request_button';
import SettingSet from './setting_set';
import SettingsGroup from './settings_group'; import SettingsGroup from './settings_group';
import TextSetting from './text_setting'; import TextSetting from './text_setting';
@@ -174,27 +175,24 @@ export default class BleveSettings extends OLDAdminSettings<Props, State> {
setByEnv={this.isSetByEnv('BleveSettings.IndexDir')} setByEnv={this.isSetByEnv('BleveSettings.IndexDir')}
disabled={this.props.isDisabled} disabled={this.props.isDisabled}
/> />
<div className='form-group'> <SettingSet
<label className='control-label col-sm-4'> label={<FormattedMessage {...messages.bulkIndexingTitle}/>}
<FormattedMessage {...messages.bulkIndexingTitle}/> >
</label> <div className='job-table-setting'>
<div className='col-sm-8'> <JobsTable
<div className='job-table-setting'> jobType={JobTypes.BLEVE_POST_INDEXING}
<JobsTable disabled={!this.state.canPurgeAndIndex || Boolean(this.props.isDisabled)}
jobType={JobTypes.BLEVE_POST_INDEXING} createJobButtonText={
disabled={!this.state.canPurgeAndIndex || Boolean(this.props.isDisabled)} <FormattedMessage
createJobButtonText={ id='admin.bleve.createJob.title'
<FormattedMessage defaultMessage='Index Now'
id='admin.bleve.createJob.title' />
defaultMessage='Index Now' }
/> createJobHelpText={<FormattedMessage {...messages.createJob_help}/>}
} getExtraInfoText={this.getExtraInfo}
createJobHelpText={<FormattedMessage {...messages.createJob_help}/>} />
getExtraInfoText={this.getExtraInfo}
/>
</div>
</div> </div>
</div> </SettingSet>
<RequestButton <RequestButton
id='purgeIndexesSection' id='purgeIndexesSection'
requestAction={blevePurgeIndexes} requestAction={blevePurgeIndexes}

Просмотреть файл

@@ -8,6 +8,7 @@ import {Client4} from 'mattermost-redux/client';
import {uploadBrandImage, deleteBrandImage} from 'actions/admin_actions.jsx'; import {uploadBrandImage, deleteBrandImage} from 'actions/admin_actions.jsx';
import SettingSet from 'components/admin_console/setting_set';
import FormError from 'components/form_error'; import FormError from 'components/form_error';
import WithTooltip from 'components/with_tooltip'; import WithTooltip from 'components/with_tooltip';
@@ -110,6 +111,10 @@ export default class BrandImageSetting extends React.PureComponent<Props, State>
} }
} }
handleSelectClick = () => {
this.fileInputRef.current?.click();
};
handleImageChange = () => { handleImageChange = () => {
if (!this.fileInputRef.current) { if (!this.fileInputRef.current) {
return; return;
@@ -234,50 +239,47 @@ export default class BrandImageSetting extends React.PureComponent<Props, State>
} }
return ( return (
<div <SettingSet
data-testid={this.props.id} inputId={this.props.id}
className='form-group' helpText={
> <FormattedMessage
<label className='control-label col-sm-4'> id='admin.team.uploadDesc'
defaultMessage='Customize your user experience by adding a custom image to your login screen. Recommended maximum image size is less than 2 MB.'
/>
}
label={
<FormattedMessage <FormattedMessage
id='admin.team.brandImageTitle' id='admin.team.brandImageTitle'
defaultMessage='Custom Brand Image:' defaultMessage='Custom Brand Image:'
/> />
</label> }
<div className='col-sm-8'> setByEnv={false}
>
<div>
<div className='remove-image'>{img}</div> <div className='remove-image'>{img}</div>
</div> </div>
<div className='col-sm-4'/> <div className='file__upload mt-5'>
<div className='col-sm-8'> <button
<div className='file__upload mt-5'> type='button'
<button className='btn btn-tertiary'
type='button' disabled={this.props.disabled}
className='btn btn-tertiary' onClick={this.handleSelectClick}
disabled={this.props.disabled} >
>
<FormattedMessage
id='admin.team.chooseImage'
defaultMessage='Select Image'
/>
</button>
<input
ref={this.fileInputRef}
type='file'
accept={Constants.ACCEPT_STATIC_IMAGE}
disabled={this.props.disabled}
onChange={this.handleImageChange}
/>
</div>
<br/>
<FormError error={this.state.error}/>
<p className='help-text m-0'>
<FormattedMessage <FormattedMessage
id='admin.team.uploadDesc' id='admin.team.chooseImage'
defaultMessage='Customize your user experience by adding a custom image to your login screen. Recommended maximum image size is less than 2 MB.' defaultMessage='Select Image'
/> />
</p> </button>
<input
ref={this.fileInputRef}
type='file'
accept={Constants.ACCEPT_STATIC_IMAGE}
disabled={this.props.disabled}
onChange={this.handleImageChange}
/>
</div> </div>
</div> <FormError error={this.state.error}/>
</SettingSet>
); );
} }
} }

Просмотреть файл

@@ -338,7 +338,7 @@ export default class ComplianceReports extends React.PureComponent<Props, State>
</h4> </h4>
<div className='row'> <div className='row'>
<div className='col-sm-6 col-md-4 form-group'> <div className='col-sm-6 col-md-4 form-group'>
<label> <label htmlFor='desc'>
<FormattedMessage <FormattedMessage
id='admin.compliance_reports.desc' id='admin.compliance_reports.desc'
defaultMessage='Job Name:' defaultMessage='Job Name:'
@@ -354,7 +354,7 @@ export default class ComplianceReports extends React.PureComponent<Props, State>
/> />
</div> </div>
<div className='col-sm-3 col-md-2 form-group'> <div className='col-sm-3 col-md-2 form-group'>
<label> <label htmlFor='from'>
<FormattedMessage <FormattedMessage
id='admin.compliance_reports.from' id='admin.compliance_reports.from'
defaultMessage='From:' defaultMessage='From:'
@@ -370,7 +370,7 @@ export default class ComplianceReports extends React.PureComponent<Props, State>
/> />
</div> </div>
<div className='col-sm-3 col-md-2 form-group'> <div className='col-sm-3 col-md-2 form-group'>
<label> <label htmlFor='to'>
<FormattedMessage <FormattedMessage
id='admin.compliance_reports.to' id='admin.compliance_reports.to'
defaultMessage='To:' defaultMessage='To:'
@@ -388,7 +388,7 @@ export default class ComplianceReports extends React.PureComponent<Props, State>
</div> </div>
<div className='row'> <div className='row'>
<div className='col-sm-6 col-md-4 form-group'> <div className='col-sm-6 col-md-4 form-group'>
<label> <label htmlFor='emails'>
<FormattedMessage <FormattedMessage
id='admin.compliance_reports.emails' id='admin.compliance_reports.emails'
defaultMessage='Emails:' defaultMessage='Emails:'
@@ -404,7 +404,7 @@ export default class ComplianceReports extends React.PureComponent<Props, State>
/> />
</div> </div>
<div className='col-sm-6 col-md-4 form-group'> <div className='col-sm-6 col-md-4 form-group'>
<label> <label htmlFor='keywords'>
<FormattedMessage <FormattedMessage
id='admin.compliance_reports.keywords' id='admin.compliance_reports.keywords'
defaultMessage='Keywords:' defaultMessage='Keywords:'

Просмотреть файл

@@ -18,6 +18,7 @@ import MigrationsTable from './database';
import type {BaseState} from './old_admin_settings'; import type {BaseState} from './old_admin_settings';
import OLDAdminSettings from './old_admin_settings'; import OLDAdminSettings from './old_admin_settings';
import RequestButton from './request_button/request_button'; import RequestButton from './request_button/request_button';
import SettingSet from './setting_set';
import SettingsGroup from './settings_group'; import SettingsGroup from './settings_group';
import TextSetting from './text_setting'; import TextSetting from './text_setting';
@@ -378,31 +379,29 @@ export default class DatabaseSettings extends OLDAdminSettings<Props, State> {
setByEnv={this.isSetByEnv('SqlSettings.DisableDatabaseSearch')} setByEnv={this.isSetByEnv('SqlSettings.DisableDatabaseSearch')}
disabled={this.props.isDisabled} disabled={this.props.isDisabled}
/> />
<div className='form-group'> <SettingSet
<label label={
className='control-label col-sm-4'
>
<FormattedMessage <FormattedMessage
id='admin.database.migrations_table.title' id='admin.database.migrations_table.title'
defaultMessage='Schema Migrations:' defaultMessage='Schema Migrations:'
/> />
</label> }
<div className='col-sm-8'> >
<div className='migrations-table-setting'> <div className='migrations-table-setting'>
<MigrationsTable <MigrationsTable
createHelpText={ createHelpText={
<FormattedMessage <FormattedMessage
id='admin.database.migrations_table.help_text' id='admin.database.migrations_table.help_text'
defaultMessage='All applied migrations.' defaultMessage='All applied migrations.'
/> />
} }
/> />
</div>
</div> </div>
</div> </SettingSet>
<div className='form-group'> <div className='form-group'>
<label <label
className='control-label col-sm-4' className='control-label col-sm-4'
htmlFor='activeSearchBackend'
> >
<FormattedMessage <FormattedMessage
id='admin.database.search_backend.title' id='admin.database.search_backend.title'
@@ -411,6 +410,7 @@ export default class DatabaseSettings extends OLDAdminSettings<Props, State> {
</label> </label>
<div className='col-sm-8'> <div className='col-sm-8'>
<input <input
id='activeSearchBackend'
type='text' type='text'
className='form-control' className='form-control'
value={this.state.searchBackend} value={this.state.searchBackend}

Просмотреть файл

@@ -19,6 +19,7 @@ import JobsTable from './jobs';
import OLDAdminSettings from './old_admin_settings'; import OLDAdminSettings from './old_admin_settings';
import type {BaseProps, BaseState} from './old_admin_settings'; import type {BaseProps, BaseState} from './old_admin_settings';
import RequestButton from './request_button/request_button'; import RequestButton from './request_button/request_button';
import SettingSet from './setting_set';
import SettingsGroup from './settings_group'; import SettingsGroup from './settings_group';
import TextSetting from './text_setting'; import TextSetting from './text_setting';
@@ -419,27 +420,24 @@ export default class ElasticsearchSettings extends OLDAdminSettings<Props, State
})} })}
disabled={!this.state.enableIndexing} disabled={!this.state.enableIndexing}
/> />
<div className='form-group'> <SettingSet
<label className='control-label col-sm-4'> label={<FormattedMessage {...messages.bulkIndexingTitle}/>}
<FormattedMessage {...messages.bulkIndexingTitle}/> >
</label> <div className='job-table-setting'>
<div className='col-sm-8'> <JobsTable
<div className='job-table-setting'> jobType={JobTypes.ELASTICSEARCH_POST_INDEXING as JobType}
<JobsTable disabled={!this.state.canPurgeAndIndex || this.props.isDisabled!}
jobType={JobTypes.ELASTICSEARCH_POST_INDEXING as JobType} createJobButtonText={
disabled={!this.state.canPurgeAndIndex || this.props.isDisabled!} <FormattedMessage
createJobButtonText={ id='admin.elasticsearch.createJob.title'
<FormattedMessage defaultMessage='Index Now'
id='admin.elasticsearch.createJob.title' />
defaultMessage='Index Now' }
/> createJobHelpText={<FormattedMessage {...messages.help}/>}
} getExtraInfoText={this.getExtraInfo}
createJobHelpText={<FormattedMessage {...messages.help}/>} />
getExtraInfoText={this.getExtraInfo}
/>
</div>
</div> </div>
</div> </SettingSet>
<RequestButton <RequestButton
id='rebuildChannelsIndexButton' id='rebuildChannelsIndexButton'
requestAction={rebuildChannelsIndex} requestAction={rebuildChannelsIndex}

Просмотреть файл

@@ -3,12 +3,14 @@
exports[`components/admin_console/group_settings/group_details/GroupProfile should match snapshot 1`] = ` exports[`components/admin_console/group_settings/group_details/GroupProfile should match snapshot 1`] = `
<div <div
className="group-profile form-horizontal" className="group-profile form-horizontal"
id="test"
> >
<div <div
className="group-profile-field form-group mb-0" className="group-profile-field form-group mb-0"
> >
<label <label
className="control-label col-sm-4" className="control-label col-sm-4"
htmlFor="testInput"
> >
<MemoizedFormattedMessage <MemoizedFormattedMessage
defaultMessage="Name:" defaultMessage="Name:"
@@ -29,6 +31,7 @@ exports[`components/admin_console/group_settings/group_details/GroupProfile shou
<input <input
className="form-control group-at-mention-input" className="form-control group-at-mention-input"
disabled={false} disabled={false}
id="testInput"
type="text" type="text"
value="Test" value="Test"
/> />

Просмотреть файл

@@ -10,6 +10,7 @@ describe('components/admin_console/group_settings/group_details/GroupProfile', (
test('should match snapshot', () => { test('should match snapshot', () => {
const wrapper = shallow( const wrapper = shallow(
<GroupProfile <GroupProfile
customID='test'
isDisabled={false} isDisabled={false}
name='Test' name='Test'
showAtMention={true} showAtMention={true}

Просмотреть файл

@@ -10,7 +10,7 @@ import MentionsIcon from 'components/widgets/icons/mentions_icon';
type Props = { type Props = {
name?: string; name?: string;
title: MessageDescriptor; title: MessageDescriptor;
customID?: string; customID: string;
isDisabled?: boolean; isDisabled?: boolean;
showAtMention: boolean; showAtMention: boolean;
onChange?: React.ChangeEventHandler<HTMLInputElement>; onChange?: React.ChangeEventHandler<HTMLInputElement>;
@@ -29,7 +29,10 @@ const GroupProfile = ({
id={customID} id={customID}
> >
<div className='group-profile-field form-group mb-0'> <div className='group-profile-field form-group mb-0'>
<label className='control-label col-sm-4'> <label
className='control-label col-sm-4'
htmlFor={customID + 'Input'}
>
<FormattedMessage {...title}/> <FormattedMessage {...title}/>
</label> </label>
<div className='col-sm-8'> <div className='col-sm-8'>
@@ -42,6 +45,7 @@ const GroupProfile = ({
)} )}
</div> </div>
<input <input
id={customID + 'Input'}
type='text' type='text'
className='form-control group-at-mention-input' className='form-control group-at-mention-input'
value={name} value={name}

Просмотреть файл

@@ -101,13 +101,12 @@ const TeamEditionRightPanel: React.FC<TeamEditionRightPanelProps> = ({
{upgradeError && ( {upgradeError && (
<div className='upgrade-error'> <div className='upgrade-error'>
<div className='form-group has-error'> <div className='form-group has-error'>
<label className='control-label'> <div
<span className='as-bs-label control-label'
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
__html: format(upgradeError), __html: format(upgradeError),
}} }}
/> />
</label>
</div> </div>
</div> </div>
)} )}
@@ -140,17 +139,17 @@ const TeamEditionRightPanel: React.FC<TeamEditionRightPanelProps> = ({
defaultMessage='Restart Server' defaultMessage='Restart Server'
/> />
</LoadingWrapper> </LoadingWrapper>
{restartError && (
<div className='col-sm-12'>
<div className='form-group has-error'>
<label className='control-label'>
{restartError}
</label>
</div>
</div>
)}
</button> </button>
</p> </p>
{restartError && (
<div className='upgrade-error'>
<div className='form-group has-error'>
<div className='as-bs-label control-label'>
{restartError}
</div>
</div>
</div>
)}
</div> </div>
); );
} }

Просмотреть файл

@@ -340,22 +340,21 @@ const TrialBanner = ({
{upgradeError && ( {upgradeError && (
<div className='upgrade-error'> <div className='upgrade-error'>
<div className='form-group has-error'> <div className='form-group has-error'>
<label className='control-label'> <div
<span className='as-bs-label control-label'
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
__html: format(upgradeError), __html: format(upgradeError),
}} }}
/> />
</label>
</div> </div>
</div> </div>
)} )}
{restartError && ( {restartError && (
<div className='col-sm-12'> <div className='upgrade-error'>
<div className='form-group has-error'> <div className='form-group has-error'>
<label className='control-label'> <div className='as-bs-label control-label'>
{restartError} {restartError}
</label> </div>
</div> </div>
</div> </div>
)} )}

Просмотреть файл

@@ -254,10 +254,9 @@ export default class PasswordSettings extends OLDAdminSettings<Props, State> {
</ul> </ul>
<div> <div>
<br/> <br/>
<label> <div className='password-settings__preview-heading'>
<FormattedMessage {...messages.preview}/> <FormattedMessage {...messages.preview}/>
</label> </div>
<br/>
{this.getSampleErrorMsg()} {this.getSampleErrorMsg()}
</div> </div>
</SettingSet> </SettingSet>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@@ -24,6 +24,7 @@ import * as Utils from 'utils/utils';
import BooleanSetting from '../boolean_setting'; import BooleanSetting from '../boolean_setting';
import OLDAdminSettings from '../old_admin_settings'; import OLDAdminSettings from '../old_admin_settings';
import type {BaseProps, BaseState} from '../old_admin_settings'; import type {BaseProps, BaseState} from '../old_admin_settings';
import SettingSet from '../setting_set';
import SettingsGroup from '../settings_group'; import SettingsGroup from '../settings_group';
import TextSetting from '../text_setting'; import TextSetting from '../text_setting';
@@ -556,6 +557,10 @@ class PluginManagement extends OLDAdminSettings<Props, State> {
} }
} }
handleChooseFileClick = () => {
this.fileInput.current?.click();
};
handleUpload = () => { handleUpload = () => {
this.setState({lastMessage: null, serverError: null}); this.setState({lastMessage: null, serverError: null});
const element = this.fileInput.current as HTMLInputElement; const element = this.fileInput.current as HTMLInputElement;
@@ -1018,18 +1023,15 @@ class PluginManagement extends OLDAdminSettings<Props, State> {
if (enable) { if (enable) {
pluginsContainer = ( pluginsContainer = (
<div className='form-group'> <SettingSet
<label className='control-label col-sm-4'> label={<FormattedMessage {...messages.installedTitle}/>}
<FormattedMessage {...messages.installedTitle}/> >
</label> <p className='help-text'>
<div className='col-sm-8'> <FormattedMessage {...messages.installedDesc}/>
<p className='help-text'> </p>
<FormattedMessage {...messages.installedDesc}/> <br/>
</p> {pluginsListContainer}
<br/> </SettingSet>
{pluginsListContainer}
</div>
</div>
); );
} }
@@ -1147,48 +1149,44 @@ class PluginManagement extends OLDAdminSettings<Props, State> {
onChange={this.handleChange} onChange={this.handleChange}
setByEnv={this.isSetByEnv('PluginSettings.AutomaticPrepackagedPlugins')} setByEnv={this.isSetByEnv('PluginSettings.AutomaticPrepackagedPlugins')}
/> />
<div className='form-group'> <SettingSet
<label className='control-label col-sm-4'> helpText={uploadHelpText}
<FormattedMessage {...messages.uploadTitle}/> label={<FormattedMessage {...messages.uploadTitle}/>}
</label> >
<div className='col-sm-8'> <div className='file__upload'>
<div className='file__upload'>
<button
type='button'
className={classNames(['btn', {'btn-tertiary': enableUploads}])}
disabled={!enableUploadButton || this.props.isDisabled}
>
<FormattedMessage
id='admin.plugin.choose'
defaultMessage='Choose File'
/>
</button>
<input
ref={this.fileInput}
type='file'
accept='.gz'
onChange={this.handleUpload}
disabled={!enableUploadButton || this.props.isDisabled}
/>
</div>
<button <button
className={btnClass} type='button'
id='uploadPlugin' className={classNames(['btn', {'btn-tertiary': enableUploads}])}
disabled={!this.state.fileSelected} onClick={this.handleChooseFileClick}
onClick={this.handleSubmitUpload} disabled={!enableUploadButton || this.props.isDisabled}
> >
{uploadButtonText} <FormattedMessage
id='admin.plugin.choose'
defaultMessage='Choose File'
/>
</button> </button>
<div className='help-text m-0'> <input
{fileName} ref={this.fileInput}
</div> type='file'
{serverError} accept='.gz'
{lastMessage} onChange={this.handleUpload}
<p className='help-text'> disabled={!enableUploadButton || this.props.isDisabled}
{uploadHelpText} />
</p>
</div> </div>
</div> <button
className={btnClass}
id='uploadPlugin'
disabled={!this.state.fileSelected}
onClick={this.handleSubmitUpload}
>
{uploadButtonText}
</button>
<div className='help-text m-0'>
{fileName}
</div>
{serverError}
{lastMessage}
</SettingSet>
<BooleanSetting <BooleanSetting
id='enableMarketplace' id='enableMarketplace'
label={<FormattedMessage {...messages.enableMarketplace}/>} label={<FormattedMessage {...messages.enableMarketplace}/>}

Просмотреть файл

@@ -259,14 +259,15 @@ exports[`admin_console/team_channel_settings/channel/ChannelModeration Should ma
exports[`admin_console/team_channel_settings/channel/ChannelModeration Should match second Snapshot 1`] = ` exports[`admin_console/team_channel_settings/channel/ChannelModeration Should match second Snapshot 1`] = `
<tr> <tr>
<td> <td>
<label <div
className="as-bs-label"
data-testid="admin-channel_settings-channel_moderation-createPosts" data-testid="admin-channel_settings-channel_moderation-createPosts"
> >
<MemoizedFormattedMessage <MemoizedFormattedMessage
defaultMessage="Create Posts" defaultMessage="Create Posts"
id="admin.channel_settings.channel_moderation.createPosts" id="admin.channel_settings.channel_moderation.createPosts"
/> />
</label> </div>
<div <div
data-testid="admin-channel_settings-channel_moderation-createPostsDesc" data-testid="admin-channel_settings-channel_moderation-createPostsDesc"
> >
@@ -303,14 +304,15 @@ exports[`admin_console/team_channel_settings/channel/ChannelModeration Should ma
exports[`admin_console/team_channel_settings/channel/ChannelModeration Should match seventh Snapshot 1`] = ` exports[`admin_console/team_channel_settings/channel/ChannelModeration Should match seventh Snapshot 1`] = `
<tr> <tr>
<td> <td>
<label <div
className="as-bs-label"
data-testid="admin-channel_settings-channel_moderation-createPosts" data-testid="admin-channel_settings-channel_moderation-createPosts"
> >
<MemoizedFormattedMessage <MemoizedFormattedMessage
defaultMessage="Create Posts" defaultMessage="Create Posts"
id="admin.channel_settings.channel_moderation.createPosts" id="admin.channel_settings.channel_moderation.createPosts"
/> />
</label> </div>
<div <div
data-testid="admin-channel_settings-channel_moderation-createPostsDesc" data-testid="admin-channel_settings-channel_moderation-createPostsDesc"
> >

Просмотреть файл

@@ -275,14 +275,15 @@ export const ChannelModerationTableRow = (props: ChannelModerationTableRow) => {
return ( return (
<tr> <tr>
<td> <td>
<label <div
className='as-bs-label'
data-testid={channelModerationPermissionMessages?.title?.id?.replace(PERIOD_TO_SLASH_REGEX, '-')} data-testid={channelModerationPermissionMessages?.title?.id?.replace(PERIOD_TO_SLASH_REGEX, '-')}
> >
<FormattedMessage <FormattedMessage
id={channelModerationPermissionMessages?.title?.id} id={channelModerationPermissionMessages?.title?.id}
defaultMessage={channelModerationPermissionMessages?.title?.defaultMessage} defaultMessage={channelModerationPermissionMessages?.title?.defaultMessage}
/> />
</label> </div>
<div <div
data-testid={channelModerationPermissionMessages?.description?.id?.replace(PERIOD_TO_SLASH_REGEX, '-')} data-testid={channelModerationPermissionMessages?.description?.id?.replace(PERIOD_TO_SLASH_REGEX, '-')}
> >

Просмотреть файл

@@ -196,11 +196,6 @@
.post-error { .post-error {
margin: 4px 0 0 0; margin: 4px 0 0 0;
color: var(--error-text); color: var(--error-text);
label {
margin: 0;
color: var(--error-text);
}
} }
} }

Просмотреть файл

@@ -699,9 +699,9 @@ const AdvancedTextEditor = ({
className='AdvancedTextEditor__footer' className='AdvancedTextEditor__footer'
> >
{postError && ( {postError && (
<label className={classNames('post-error', {errorClass})}> <div className={classNames('post-error', {errorClass})}>
{postError} {postError}
</label> </div>
)} )}
{serverError && ( {serverError && (
<MessageSubmitError <MessageSubmitError

Просмотреть файл

@@ -366,7 +366,10 @@ export default class Bot extends React.PureComponent<Props, State> {
onSubmit={this.handleCreateToken} onSubmit={this.handleCreateToken}
> >
<div className='row'> <div className='row'>
<label className='col-sm-auto control-label'> <label
className='col-sm-auto control-label'
htmlFor='botToken'
>
<FormattedMessage <FormattedMessage
id='user.settings.tokens.name' id='user.settings.tokens.name'
defaultMessage='Token Description: ' defaultMessage='Token Description: '
@@ -374,6 +377,7 @@ export default class Bot extends React.PureComponent<Props, State> {
</label> </label>
<div className='col-sm-4'> <div className='col-sm-4'>
<input <input
id='botToken'
autoFocus={true} autoFocus={true}
className='form-control form-sm' className='form-control form-sm'
type='text' type='text'

Просмотреть файл

@@ -21,7 +21,7 @@ function MessageSubmitError(props: Props) {
return ( return (
<div className='has-error'> <div className='has-error'>
<label className='control-label'> <div className='control-label'>
<FormattedMessage <FormattedMessage
id='message_submit_error.invalidCommand' id='message_submit_error.invalidCommand'
defaultMessage="Command with a trigger of ''{slashCommand}'' not found. " defaultMessage="Command with a trigger of ''{slashCommand}'' not found. "
@@ -31,6 +31,7 @@ function MessageSubmitError(props: Props) {
/> />
<a <a
href='#' href='#'
role='button'
onClick={props.handleSubmit} onClick={props.handleSubmit}
> >
<FormattedMessage <FormattedMessage
@@ -38,7 +39,7 @@ function MessageSubmitError(props: Props) {
defaultMessage='Click here to send as a message.' defaultMessage='Click here to send as a message.'
/> />
</a> </a>
</label> </div>
</div> </div>
); );
} }

Просмотреть файл

@@ -59,6 +59,7 @@ exports[`components/RenameChannelModal should match snapshot 1`] = `
> >
<label <label
className="control-label" className="control-label"
htmlFor="display_name"
> >
<MemoizedFormattedMessage <MemoizedFormattedMessage
defaultMessage="Display Name" defaultMessage="Display Name"
@@ -81,6 +82,7 @@ exports[`components/RenameChannelModal should match snapshot 1`] = `
> >
<label <label
className="control-label" className="control-label"
htmlFor="channel_name"
> >
URL URL
</label> </label>

Просмотреть файл

@@ -241,7 +241,7 @@ export class RenameChannelModal extends React.PureComponent<Props, State> {
let serverError = null; let serverError = null;
if (this.state.serverError) { if (this.state.serverError) {
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>; serverError = <div className='form-group has-error'><div className='as-bs-label control-label'>{this.state.serverError}</div></div>;
} }
const {formatMessage} = this.props.intl; const {formatMessage} = this.props.intl;
@@ -280,7 +280,10 @@ export class RenameChannelModal extends React.PureComponent<Props, State> {
<form role='form'> <form role='form'>
<Modal.Body> <Modal.Body>
<div className='form-group'> <div className='form-group'>
<label className='control-label'> <label
className='control-label'
htmlFor='display_name'
>
<FormattedMessage <FormattedMessage
id='rename_channel.displayName' id='rename_channel.displayName'
defaultMessage='Display Name' defaultMessage='Display Name'
@@ -303,7 +306,12 @@ export class RenameChannelModal extends React.PureComponent<Props, State> {
{displayNameError} {displayNameError}
</div> </div>
<div className='form-group'> <div className='form-group'>
<label className='control-label'>{urlInputLabel}</label> <label
className='control-label'
htmlFor='channel_name'
>
{urlInputLabel}
</label>
<div className={urlInputClass}> <div className={urlInputClass}>
<WithTooltip <WithTooltip

Просмотреть файл

@@ -233,11 +233,11 @@ exports[`components/select_team/SelectTeam should match snapshot, on error 1`] =
<div <div
className="form-group has-error" className="form-group has-error"
> >
<label <div
className="control-label" className="control-label"
> >
<Component /> <Component />
</label> </div>
</div> </div>
</div> </div>
<Memo(SystemPermissionGate) <Memo(SystemPermissionGate)
@@ -535,14 +535,14 @@ exports[`components/select_team/SelectTeam should match snapshot, on no joinable
<div <div
className="form-group has-error" className="form-group has-error"
> >
<label <div
className="control-label" className="control-label"
> >
<MemoizedFormattedMessage <MemoizedFormattedMessage
defaultMessage="Your guest account has no channels assigned. Please contact an administrator." defaultMessage="Your guest account has no channels assigned. Please contact an administrator."
id="signup_team.guest_without_channels" id="signup_team.guest_without_channels"
/> />
</label> </div>
</div> </div>
</div> </div>
<Memo(SystemPermissionGate) <Memo(SystemPermissionGate)

Просмотреть файл

@@ -201,7 +201,7 @@ export default class SelectTeam extends React.PureComponent<Props, State> {
openContent = ( openContent = (
<div className='signup__content'> <div className='signup__content'>
<div className={'form-group has-error'}> <div className={'form-group has-error'}>
<label className='control-label'>{this.state.error}</label> <div className='control-label'>{this.state.error}</div>
</div> </div>
</div> </div>
); );
@@ -209,12 +209,12 @@ export default class SelectTeam extends React.PureComponent<Props, State> {
openContent = ( openContent = (
<div className='signup__content'> <div className='signup__content'>
<div className={'form-group has-error'}> <div className={'form-group has-error'}>
<label className='control-label'> <div className='control-label'>
<FormattedMessage <FormattedMessage
id='signup_team.guest_without_channels' id='signup_team.guest_without_channels'
defaultMessage='Your guest account has no channels assigned. Please contact an administrator.' defaultMessage='Your guest account has no channels assigned. Please contact an administrator.'
/> />
</label> </div>
</div> </div>
</div> </div>
); );

Просмотреть файл

@@ -198,6 +198,7 @@ export class ManageLanguage extends React.PureComponent<Props, State> {
aria-label={interfaceLanguageLabelAria} aria-label={interfaceLanguageLabelAria}
className='control-label' className='control-label'
id='changeInterfaceLanguageLabel' id='changeInterfaceLanguageLabel'
htmlFor='displayLanguage'
> >
<FormattedMessage <FormattedMessage
id='user.settings.languages.change' id='user.settings.languages.change'

Просмотреть файл

@@ -385,6 +385,7 @@ exports[`components/user_settings/display/CustomThemeChooser should match, init
> >
<label <label
className="custom-label" className="custom-label"
htmlFor="codeThemeSelect"
> >
<MemoizedFormattedMessage <MemoizedFormattedMessage
defaultMessage="Code Theme" defaultMessage="Code Theme"
@@ -538,6 +539,7 @@ exports[`components/user_settings/display/CustomThemeChooser should match, init
> >
<label <label
className="custom-label" className="custom-label"
htmlFor="pasteBox"
> >
<MemoizedFormattedMessage <MemoizedFormattedMessage
defaultMessage="Copy to share or paste theme colors here:" defaultMessage="Copy to share or paste theme colors here:"

Просмотреть файл

@@ -312,7 +312,10 @@ export class CustomThemeChooser extends React.PureComponent<Props, State> {
className='col-sm-6 form-group' className='col-sm-6 form-group'
key={'custom-theme-key' + index} key={'custom-theme-key' + index}
> >
<label className='custom-label'> <label
className='custom-label'
htmlFor='codeThemeSelect'
>
<FormattedMessage {...messages[element.id]}/> <FormattedMessage {...messages[element.id]}/>
</label> </label>
<div <div
@@ -403,7 +406,10 @@ export class CustomThemeChooser extends React.PureComponent<Props, State> {
const pasteBox = ( const pasteBox = (
<div className='col-sm-12'> <div className='col-sm-12'>
<label className='custom-label'> <label
className='custom-label'
htmlFor='pasteBox'
>
<FormattedMessage <FormattedMessage
id='user.settings.custom_theme.copyPaste' id='user.settings.custom_theme.copyPaste'
defaultMessage='Copy to share or paste theme colors here:' defaultMessage='Copy to share or paste theme colors here:'

Просмотреть файл

@@ -494,14 +494,14 @@ export class UserSettingsGeneralTab extends PureComponent<Props, State> {
inputs.push( inputs.push(
<div key='currentEmailSetting'> <div key='currentEmailSetting'>
<div className='form-group'> <div className='form-group'>
<label className='col-sm-5 control-label'> <span className='as-bs-label col-sm-5 control-label'>
<FormattedMessage <FormattedMessage
id='user.settings.general.currentEmail' id='user.settings.general.currentEmail'
defaultMessage='Current Email' defaultMessage='Current Email'
/> />
</label> </span>
<div className='col-sm-7'> <div className='col-sm-7'>
<label className='control-label word-break--all text-left'>{this.state.originalEmail}</label> <span className='as-bs-label control-label word-break--all text-left'>{this.state.originalEmail}</span>
</div> </div>
</div> </div>
</div>, </div>,
@@ -510,7 +510,10 @@ export class UserSettingsGeneralTab extends PureComponent<Props, State> {
inputs.push( inputs.push(
<div key='emailSetting'> <div key='emailSetting'>
<div className='form-group'> <div className='form-group'>
<label className='col-sm-5 control-label'> <label
className='col-sm-5 control-label'
htmlFor='primaryEmail'
>
<FormattedMessage <FormattedMessage
id='user.settings.general.newEmail' id='user.settings.general.newEmail'
defaultMessage='New Email' defaultMessage='New Email'
@@ -535,7 +538,10 @@ export class UserSettingsGeneralTab extends PureComponent<Props, State> {
inputs.push( inputs.push(
<div key='confirmEmailSetting'> <div key='confirmEmailSetting'>
<div className='form-group'> <div className='form-group'>
<label className='col-sm-5 control-label'> <label
className='col-sm-5 control-label'
htmlFor='confirmEmail'
>
<FormattedMessage <FormattedMessage
id='user.settings.general.confirmEmail' id='user.settings.general.confirmEmail'
defaultMessage='Confirm Email' defaultMessage='Confirm Email'
@@ -559,7 +565,10 @@ export class UserSettingsGeneralTab extends PureComponent<Props, State> {
inputs.push( inputs.push(
<div key='currentPassword'> <div key='currentPassword'>
<div className='form-group'> <div className='form-group'>
<label className='col-sm-5 control-label'> <label
className='col-sm-5 control-label'
htmlFor='currentPassword'
>
<FormattedMessage <FormattedMessage
id='user.settings.general.currentPassword' id='user.settings.general.currentPassword'
defaultMessage='Current Password' defaultMessage='Current Password'
@@ -813,7 +822,10 @@ export class UserSettingsGeneralTab extends PureComponent<Props, State> {
key='firstNameSetting' key='firstNameSetting'
className='form-group' className='form-group'
> >
<label className='col-sm-5 control-label'> <label
className='col-sm-5 control-label'
htmlFor='firstName'
>
<FormattedMessage <FormattedMessage
id='user.settings.general.firstName' id='user.settings.general.firstName'
defaultMessage='First Name' defaultMessage='First Name'
@@ -840,7 +852,10 @@ export class UserSettingsGeneralTab extends PureComponent<Props, State> {
key='lastNameSetting' key='lastNameSetting'
className='form-group' className='form-group'
> >
<label className='col-sm-5 control-label'> <label
className='col-sm-5 control-label'
htmlFor='lastName'
>
<FormattedMessage <FormattedMessage
id='user.settings.general.lastName' id='user.settings.general.lastName'
defaultMessage='Last Name' defaultMessage='Last Name'

Просмотреть файл

@@ -518,7 +518,10 @@ export default class UserAccessTokenSection extends React.PureComponent<Props, S
newTokenSection = ( newTokenSection = (
<div className='pl-3'> <div className='pl-3'>
<div className='row'> <div className='row'>
<label className='col-sm-auto control-label pr-3'> <label
className='col-sm-auto control-label pr-3'
htmlFor='newTokenDescription'
>
<FormattedMessage <FormattedMessage
id='user.settings.tokens.name' id='user.settings.tokens.name'
defaultMessage='Token Description: ' defaultMessage='Token Description: '
@@ -526,6 +529,7 @@ export default class UserAccessTokenSection extends React.PureComponent<Props, S
</label> </label>
<div className='col-sm-5'> <div className='col-sm-5'>
<input <input
id='newTokenDescription'
autoFocus={true} autoFocus={true}
ref={this.newtokendescriptionRef} ref={this.newtokendescriptionRef}
className='form-control' className='form-control'

Просмотреть файл

@@ -258,7 +258,10 @@ export class SecurityTab extends React.PureComponent<Props, State> {
key='currentPasswordUpdateForm' key='currentPasswordUpdateForm'
className='form-group' className='form-group'
> >
<label className='col-sm-5 control-label'> <label
className='col-sm-5 control-label'
htmlFor='currentPassword'
>
<FormattedMessage <FormattedMessage
id='user.settings.security.currentPassword' id='user.settings.security.currentPassword'
defaultMessage='Current Password' defaultMessage='Current Password'
@@ -285,7 +288,10 @@ export class SecurityTab extends React.PureComponent<Props, State> {
key='newPasswordUpdateForm' key='newPasswordUpdateForm'
className='form-group' className='form-group'
> >
<label className='col-sm-5 control-label'> <label
className='col-sm-5 control-label'
htmlFor='newPassword'
>
<FormattedMessage <FormattedMessage
id='user.settings.security.newPassword' id='user.settings.security.newPassword'
defaultMessage='New Password' defaultMessage='New Password'
@@ -311,7 +317,10 @@ export class SecurityTab extends React.PureComponent<Props, State> {
key='retypeNewPasswordUpdateForm' key='retypeNewPasswordUpdateForm'
className='form-group' className='form-group'
> >
<label className='col-sm-5 control-label'> <label
className='col-sm-5 control-label'
htmlFor='confirmPassword'
>
<FormattedMessage <FormattedMessage
id='user.settings.security.retypePassword' id='user.settings.security.retypePassword'
defaultMessage='Retype New Password' defaultMessage='Retype New Password'

Просмотреть файл

@@ -117,11 +117,10 @@
} }
.modal__error { .modal__error {
display: inline-block;
margin-top: 6px; margin-top: 6px;
color: variables.$red; color: variables.$red;
float: left;
font-size: 0.95em; font-size: 0.95em;
font-weight: normal;
} }
.more-table { .more-table {

Просмотреть файл

@@ -239,24 +239,12 @@
} }
.file__upload { .file__upload {
position: relative;
display: inline-block; display: inline-block;
width: fit-content;
margin: 0 10px 10px 0; margin: 0 10px 10px 0;
input { input {
position: absolute; display: none;
z-index: 5;
top: 0;
left: 0;
width: 100%;
height: 100%;
padding-left: 100%;
cursor: pointer;
opacity: 0;
&[disabled] {
cursor: not-allowed;
}
} }
} }
@@ -1089,6 +1077,12 @@
margin-bottom: 20px; margin-bottom: 20px;
} }
.password-settings__preview-heading {
display: block;
margin-bottom: 5px;
font-weight: 600;
}
#error-tooltip { #error-tooltip {
.tooltip-inner { .tooltip-inner {
max-width: none; max-width: none;

Просмотреть файл

@@ -813,3 +813,10 @@
color: rgba(var(--center-channel-color-rgb), 0.4); color: rgba(var(--center-channel-color-rgb), 0.4);
} }
} }
.as-bs-label {
display: inline-block;
max-width: 100%;
margin-bottom: 5px;
font-weight: 700;
}

Просмотреть файл

@@ -283,6 +283,7 @@ body {
} }
.control-label { .control-label {
display: block;
width: 100%; width: 100%;
padding: 0.7em 1em; padding: 0.7em 1em;
border-radius: 3px; border-radius: 3px;
@@ -290,7 +291,6 @@ body {
background: #f2f2f2; background: #f2f2f2;
color: #999; color: #999;
font-size: 14px; font-size: 14px;
font-weight: normal;
&::before { &::before {
@extend %font-awesome; @extend %font-awesome;

Просмотреть файл

@@ -29,7 +29,7 @@
"jsx-a11y/iframe-has-title": "warn", "jsx-a11y/iframe-has-title": "warn",
"jsx-a11y/img-redundant-alt": "warn", "jsx-a11y/img-redundant-alt": "warn",
"jsx-a11y/interactive-supports-focus": "warn", "jsx-a11y/interactive-supports-focus": "warn",
"jsx-a11y/label-has-associated-control": "warn", "jsx-a11y/label-has-associated-control": "error",
"jsx-a11y/media-has-caption": "warn", "jsx-a11y/media-has-caption": "warn",
"jsx-a11y/mouse-events-have-key-events": "warn", "jsx-a11y/mouse-events-have-key-events": "warn",
"jsx-a11y/no-access-key": "error", "jsx-a11y/no-access-key": "error",