React bootstrap upgrade to v1, migrate to react-beautiful-dnd (#1639)
* Upgrade packages, fix errors, still WIP * WIP * Bootstrap v4 upgrade * Switch to react-beautiful-dnd * Fixed some issues * Added to generate signed Mac build for UX * PR feedback * Missed one * PR feedback
This commit is contained in:
@@ -446,6 +446,7 @@ workflows:
|
|||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- /^release-\d+(\.\d+){1,2}(-rc.*)?/
|
- /^release-\d+(\.\d+){1,2}(-rc.*)?/
|
||||||
|
- react_bootstrap_upgrade
|
||||||
|
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
# for master/PR builds
|
# for master/PR builds
|
||||||
@@ -453,6 +454,7 @@ workflows:
|
|||||||
- build-linux
|
- build-linux
|
||||||
- build-win-no-installer
|
- build-win-no-installer
|
||||||
- build-mac-no-dmg
|
- build-mac-no-dmg
|
||||||
|
- mac_installer
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
ignore:
|
ignore:
|
||||||
|
714
package-lock.json
generated
714
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -70,7 +70,7 @@
|
|||||||
"@types/electron-devtools-installer": "^2.2.0",
|
"@types/electron-devtools-installer": "^2.2.0",
|
||||||
"@types/hapi__joi": "^17.1.6",
|
"@types/hapi__joi": "^17.1.6",
|
||||||
"@types/react": "^17.0.11",
|
"@types/react": "^17.0.11",
|
||||||
"@types/react-bootstrap": "^0.32.25",
|
"@types/react-beautiful-dnd": "^13.0.0",
|
||||||
"@types/react-dom": "^17.0.8",
|
"@types/react-dom": "^17.0.8",
|
||||||
"@types/underscore": "^1.11.2",
|
"@types/underscore": "^1.11.2",
|
||||||
"@types/valid-url": "^1.0.3",
|
"@types/valid-url": "^1.0.3",
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hapi/joi": "^16.1.8",
|
"@hapi/joi": "^16.1.8",
|
||||||
"auto-launch": "^5.0.5",
|
"auto-launch": "^5.0.5",
|
||||||
"bootstrap": "^3.3.7",
|
"bootstrap": "^4.6.0",
|
||||||
"brace-expansion": "^2.0.0",
|
"brace-expansion": "^2.0.0",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"electron-context-menu": "^2.5.0",
|
"electron-context-menu": "^2.5.0",
|
||||||
@@ -132,9 +132,9 @@
|
|||||||
"font-awesome": "^4.7.0",
|
"font-awesome": "^4.7.0",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^16.14.0",
|
"react": "^16.14.0",
|
||||||
"react-bootstrap": "~0.32.4",
|
"react-beautiful-dnd": "^13.1.0",
|
||||||
|
"react-bootstrap": "^1.6.1",
|
||||||
"react-dom": "^16.14.0",
|
"react-dom": "^16.14.0",
|
||||||
"react-smooth-dnd": "github:mattermost/react-smooth-dnd#af6b471295007274560a375799622c1cd52d678a",
|
|
||||||
"react-transition-group": "^2.5.0",
|
"react-transition-group": "^2.5.0",
|
||||||
"semver": "^5.5.0",
|
"semver": "^5.5.0",
|
||||||
"underscore": "^1.9.1",
|
"underscore": "^1.9.1",
|
||||||
|
@@ -43,7 +43,7 @@ export default function AutoSaveIndicator(props: Props) {
|
|||||||
<Alert
|
<Alert
|
||||||
className={className}
|
className={className}
|
||||||
{...rest}
|
{...rest}
|
||||||
bsStyle={savingState === 'error' ? 'danger' : 'info'}
|
variant={savingState === 'error' ? 'danger' : 'info'}
|
||||||
>
|
>
|
||||||
{message}
|
{message}
|
||||||
</Alert>
|
</Alert>
|
||||||
|
@@ -14,15 +14,15 @@ storiesOf('Button', module).
|
|||||||
<Button onClick={action('clicked default')}>{'Default'}</Button>
|
<Button onClick={action('clicked default')}>{'Default'}</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={action('clicked primary')}
|
onClick={action('clicked primary')}
|
||||||
bsStyle='primary'
|
variant='primary'
|
||||||
>{'Primary'}</Button>
|
>{'Primary'}</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={action('clicked danger')}
|
onClick={action('clicked danger')}
|
||||||
bsStyle='danger'
|
variant='danger'
|
||||||
>{'Danger'}</Button>
|
>{'Danger'}</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={action('clicked link')}
|
onClick={action('clicked link')}
|
||||||
bsStyle='link'
|
variant='link'
|
||||||
>{'Link'}</Button>
|
>{'Link'}</Button>
|
||||||
</ButtonToolbar>
|
</ButtonToolbar>
|
||||||
));
|
));
|
||||||
|
@@ -11,8 +11,8 @@ type Props = {
|
|||||||
acceptLabel: string;
|
acceptLabel: string;
|
||||||
cancelLabel: string;
|
cancelLabel: string;
|
||||||
onHide: () => void;
|
onHide: () => void;
|
||||||
onAccept: React.MouseEventHandler<Button>;
|
onAccept: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
onCancel: React.MouseEventHandler<Button>;
|
onCancel: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function DestructiveConfirmationModal(props: Props) {
|
export default function DestructiveConfirmationModal(props: Props) {
|
||||||
@@ -36,11 +36,11 @@ export default function DestructiveConfirmationModal(props: Props) {
|
|||||||
{body}
|
{body}
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button
|
<Button
|
||||||
bsStyle='link'
|
variant='link'
|
||||||
onClick={onCancel}
|
onClick={onCancel}
|
||||||
>{cancelLabel}</Button>
|
>{cancelLabel}</Button>
|
||||||
<Button
|
<Button
|
||||||
bsStyle='danger'
|
variant='danger'
|
||||||
onClick={onAccept}
|
onClick={onAccept}
|
||||||
>{acceptLabel}</Button>
|
>{acceptLabel}</Button>
|
||||||
</Modal.Footer>
|
</Modal.Footer>
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
// ErrorCode: https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h
|
// ErrorCode: https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Grid, Row, Col} from 'react-bootstrap';
|
import {Container, Row, Col} from 'react-bootstrap';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
errorInfo?: string;
|
errorInfo?: string;
|
||||||
@@ -22,9 +22,8 @@ export default function ErrorView(props: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid
|
<Container
|
||||||
id={props.id}
|
id={props.id}
|
||||||
bsClass={classNames.join(' ')}
|
|
||||||
>
|
>
|
||||||
<div className='ErrorView-table'>
|
<div className='ErrorView-table'>
|
||||||
<div className='ErrorView-cell'>
|
<div className='ErrorView-cell'>
|
||||||
@@ -82,6 +81,6 @@ export default function ErrorView(props: Props) {
|
|||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -34,8 +34,8 @@ export default class ExtraBar extends React.PureComponent<Props> {
|
|||||||
onClick={this.handleBack}
|
onClick={this.handleBack}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
bsStyle={'link'}
|
variant={'link'}
|
||||||
bsSize={'xsmall'}
|
size={'sm'}
|
||||||
>
|
>
|
||||||
<span className={'backIcon fa fa-1x fa-angle-left'}/>
|
<span className={'backIcon fa fa-1x fa-angle-left'}/>
|
||||||
<span className={'backLabel'}>
|
<span className={'backLabel'}>
|
||||||
|
@@ -3,10 +3,10 @@
|
|||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React, {Fragment} from 'react';
|
import React, {Fragment} from 'react';
|
||||||
import {Grid, Row} from 'react-bootstrap';
|
import {Container, Row} from 'react-bootstrap';
|
||||||
|
import {DropResult} from 'react-beautiful-dnd';
|
||||||
import DotsVerticalIcon from 'mdi-react/DotsVerticalIcon';
|
import DotsVerticalIcon from 'mdi-react/DotsVerticalIcon';
|
||||||
import {IpcRendererEvent} from 'electron/renderer';
|
import {IpcRendererEvent} from 'electron/renderer';
|
||||||
import {DropResult} from 'react-smooth-dnd';
|
|
||||||
|
|
||||||
import {Team} from 'types/config';
|
import {Team} from 'types/config';
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ enum Status {
|
|||||||
type Props = {
|
type Props = {
|
||||||
teams: Team[];
|
teams: Team[];
|
||||||
showAddServerButton: boolean;
|
showAddServerButton: boolean;
|
||||||
moveTabs: (originalOrder: number, newOrder: number) => Promise<number | undefined>;
|
moveTabs: (originalOrder: number, newOrder: number) => number | undefined;
|
||||||
openMenu: () => void;
|
openMenu: () => void;
|
||||||
darkMode: boolean;
|
darkMode: boolean;
|
||||||
appName: string;
|
appName: string;
|
||||||
@@ -256,19 +256,18 @@ export default class MainPage extends React.PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleDragAndDrop = async (dropResult: DropResult) => {
|
handleDragAndDrop = async (dropResult: DropResult) => {
|
||||||
const {removedIndex, addedIndex} = dropResult;
|
const removedIndex = dropResult.source.index;
|
||||||
if (removedIndex === null || addedIndex === null) {
|
const addedIndex = dropResult.destination?.index;
|
||||||
|
if (addedIndex === undefined || removedIndex === addedIndex) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (removedIndex !== addedIndex) {
|
const teamIndex = this.props.moveTabs(removedIndex, addedIndex < this.props.teams.length ? addedIndex : this.props.teams.length - 1);
|
||||||
const teamIndex = await this.props.moveTabs(removedIndex, addedIndex < this.props.teams.length ? addedIndex : this.props.teams.length - 1);
|
|
||||||
if (!teamIndex) {
|
if (!teamIndex) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const name = this.props.teams[teamIndex].name;
|
const name = this.props.teams[teamIndex].name;
|
||||||
this.handleSelect(name, teamIndex);
|
this.handleSelect(name, teamIndex);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
handleClose = (e: React.MouseEvent<HTMLDivElement>) => {
|
handleClose = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||||
e.stopPropagation(); // since it is our button, the event goes into MainPage's onclick event, getting focus back.
|
e.stopPropagation(); // since it is our button, the event goes into MainPage's onclick event, getting focus back.
|
||||||
@@ -471,10 +470,10 @@ export default class MainPage extends React.PureComponent<Props, State> {
|
|||||||
className='MainPage'
|
className='MainPage'
|
||||||
onClick={this.focusOnWebView}
|
onClick={this.focusOnWebView}
|
||||||
>
|
>
|
||||||
<Grid fluid={true}>
|
<Container fluid={true}>
|
||||||
{topRow}
|
{topRow}
|
||||||
{viewsRow}
|
{viewsRow}
|
||||||
</Grid>
|
</Container>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Modal, Button, FormGroup, FormControl, ControlLabel, HelpBlock} from 'react-bootstrap';
|
import {Modal, Button, FormGroup, FormControl, FormLabel, FormText} from 'react-bootstrap';
|
||||||
|
|
||||||
import {TeamWithIndex} from 'types/config';
|
import {TeamWithIndex} from 'types/config';
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ export default class NewTeamModal extends React.PureComponent<Props, State> {
|
|||||||
return this.getTeamNameValidationError() === null ? null : 'error';
|
return this.getTeamNameValidationError() === null ? null : 'error';
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTeamNameChange = (e: React.ChangeEvent<FormControl & HTMLInputElement>) => {
|
handleTeamNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
teamName: e.target.value,
|
teamName: e.target.value,
|
||||||
});
|
});
|
||||||
@@ -95,7 +95,7 @@ export default class NewTeamModal extends React.PureComponent<Props, State> {
|
|||||||
return this.getTeamUrlValidationError() === null ? null : 'error';
|
return this.getTeamUrlValidationError() === null ? null : 'error';
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTeamUrlChange = (e: React.ChangeEvent<FormControl & HTMLInputElement>) => {
|
handleTeamUrlChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
teamUrl: e.target.value,
|
teamUrl: e.target.value,
|
||||||
});
|
});
|
||||||
@@ -165,7 +165,7 @@ export default class NewTeamModal extends React.PureComponent<Props, State> {
|
|||||||
onEntered={() => this.teamNameInputRef?.focus()}
|
onEntered={() => this.teamNameInputRef?.focus()}
|
||||||
onHide={this.props.onClose}
|
onHide={this.props.onClose}
|
||||||
restoreFocus={this.props.restoreFocus}
|
restoreFocus={this.props.restoreFocus}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e: React.KeyboardEvent) => {
|
||||||
switch (e.key) {
|
switch (e.key) {
|
||||||
case 'Enter':
|
case 'Enter':
|
||||||
this.save();
|
this.save();
|
||||||
@@ -186,47 +186,46 @@ export default class NewTeamModal extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
<Modal.Body>
|
<Modal.Body>
|
||||||
<form>
|
<form>
|
||||||
<FormGroup
|
<FormGroup>
|
||||||
validationState={this.getTeamNameValidationState()}
|
<FormLabel>{'Server Display Name'}</FormLabel>
|
||||||
>
|
|
||||||
<ControlLabel>{'Server Display Name'}</ControlLabel>
|
|
||||||
<FormControl
|
<FormControl
|
||||||
id='teamNameInput'
|
id='teamNameInput'
|
||||||
type='text'
|
type='text'
|
||||||
value={this.state.teamName}
|
value={this.state.teamName}
|
||||||
placeholder='Server Name'
|
placeholder='Server Name'
|
||||||
onChange={this.handleTeamNameChange}
|
onChange={this.handleTeamNameChange}
|
||||||
inputRef={(ref) => {
|
ref={(ref: HTMLInputElement) => {
|
||||||
this.teamNameInputRef = ref;
|
this.teamNameInputRef = ref;
|
||||||
if (this.props.setInputRef) {
|
if (this.props.setInputRef) {
|
||||||
this.props.setInputRef(ref);
|
this.props.setInputRef(ref);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onClick={(e) => {
|
onClick={(e: React.MouseEvent<HTMLInputElement>) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}}
|
}}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
|
isInvalid={Boolean(this.getTeamNameValidationState())}
|
||||||
/>
|
/>
|
||||||
<FormControl.Feedback/>
|
<FormControl.Feedback/>
|
||||||
<HelpBlock>{'The name of the server displayed on your desktop app tab bar.'}</HelpBlock>
|
<FormText>{'The name of the server displayed on your desktop app tab bar.'}</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
className='NewTeamModal-noBottomSpace'
|
className='NewTeamModal-noBottomSpace'
|
||||||
validationState={this.getTeamUrlValidationState()}
|
|
||||||
>
|
>
|
||||||
<ControlLabel>{'Server URL'}</ControlLabel>
|
<FormLabel>{'Server URL'}</FormLabel>
|
||||||
<FormControl
|
<FormControl
|
||||||
id='teamUrlInput'
|
id='teamUrlInput'
|
||||||
type='text'
|
type='text'
|
||||||
value={this.state.teamUrl}
|
value={this.state.teamUrl}
|
||||||
placeholder='https://example.com'
|
placeholder='https://example.com'
|
||||||
onChange={this.handleTeamUrlChange}
|
onChange={this.handleTeamUrlChange}
|
||||||
onClick={(e) => {
|
onClick={(e: React.MouseEvent<HTMLInputElement>) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}}
|
}}
|
||||||
|
isInvalid={Boolean(this.getTeamUrlValidationState())}
|
||||||
/>
|
/>
|
||||||
<FormControl.Feedback/>
|
<FormControl.Feedback/>
|
||||||
<HelpBlock className='NewTeamModal-noBottomSpace'>{'The URL of your Mattermost server. Must start with http:// or https://.'}</HelpBlock>
|
<FormText className='NewTeamModal-noBottomSpace'>{'The URL of your Mattermost server. Must start with http:// or https://.'}</FormText>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</form>
|
</form>
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
@@ -241,12 +240,13 @@ export default class NewTeamModal extends React.PureComponent<Props, State> {
|
|||||||
<Button
|
<Button
|
||||||
id='cancelNewServerModal'
|
id='cancelNewServerModal'
|
||||||
onClick={this.props.onClose}
|
onClick={this.props.onClose}
|
||||||
|
variant='link'
|
||||||
>{'Cancel'}</Button>
|
>{'Cancel'}</Button>
|
||||||
<Button
|
<Button
|
||||||
id='saveNewServerModal'
|
id='saveNewServerModal'
|
||||||
onClick={this.save}
|
onClick={this.save}
|
||||||
disabled={!this.validateForm()}
|
disabled={!this.validateForm()}
|
||||||
bsStyle='primary'
|
variant='primary'
|
||||||
>{this.getSaveButtonLabel()}</Button>
|
>{this.getSaveButtonLabel()}</Button>
|
||||||
</Modal.Footer>
|
</Modal.Footer>
|
||||||
|
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Button, Modal} from 'react-bootstrap';
|
import {Modal} from 'react-bootstrap';
|
||||||
|
|
||||||
import DestructiveConfirmationModal from './DestructiveConfirmModal';
|
import DestructiveConfirmationModal from './DestructiveConfirmModal';
|
||||||
|
|
||||||
@@ -11,8 +11,8 @@ type Props = {
|
|||||||
show: boolean;
|
show: boolean;
|
||||||
serverName: string;
|
serverName: string;
|
||||||
onHide: () => void;
|
onHide: () => void;
|
||||||
onAccept: React.MouseEventHandler<Button>;
|
onAccept: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
onCancel: React.MouseEventHandler<Button>;
|
onCancel: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function RemoveServerModal(props: Props) {
|
export default function RemoveServerModal(props: Props) {
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
import 'renderer/css/settings.css';
|
import 'renderer/css/settings.css';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Checkbox, Col, FormGroup, Grid, HelpBlock, Navbar, Radio, Row, Button} from 'react-bootstrap';
|
import {FormCheck, Col, FormGroup, FormText, Container, Row, Button} from 'react-bootstrap';
|
||||||
|
|
||||||
import {debounce} from 'underscore';
|
import {debounce} from 'underscore';
|
||||||
|
|
||||||
@@ -52,16 +52,16 @@ function backToIndex(serverName: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class SettingsPage extends React.PureComponent<Record<string, never>, State> {
|
export default class SettingsPage extends React.PureComponent<Record<string, never>, State> {
|
||||||
trayIconThemeRef: React.RefObject<FormGroup>;
|
trayIconThemeRef: React.RefObject<HTMLDivElement>;
|
||||||
downloadLocationRef: React.RefObject<HTMLInputElement>;
|
downloadLocationRef: React.RefObject<HTMLInputElement>;
|
||||||
showTrayIconRef: React.RefObject<Checkbox>;
|
showTrayIconRef: React.RefObject<HTMLInputElement>;
|
||||||
autostartRef: React.RefObject<Checkbox>;
|
autostartRef: React.RefObject<HTMLInputElement>;
|
||||||
minimizeToTrayRef: React.RefObject<Checkbox>;
|
minimizeToTrayRef: React.RefObject<HTMLInputElement>;
|
||||||
flashWindowRef: React.RefObject<Checkbox>;
|
flashWindowRef: React.RefObject<HTMLInputElement>;
|
||||||
bounceIconRef: React.RefObject<Checkbox>;
|
bounceIconRef: React.RefObject<HTMLInputElement>;
|
||||||
showUnreadBadgeRef: React.RefObject<Checkbox>;
|
showUnreadBadgeRef: React.RefObject<HTMLInputElement>;
|
||||||
useSpellCheckerRef: React.RefObject<Checkbox>;
|
useSpellCheckerRef: React.RefObject<HTMLInputElement>;
|
||||||
enableHardwareAccelerationRef: React.RefObject<Checkbox>;
|
enableHardwareAccelerationRef: React.RefObject<HTMLInputElement>;
|
||||||
|
|
||||||
saveQueue: SaveQueueItem[];
|
saveQueue: SaveQueueItem[];
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleChangeShowTrayIcon = () => {
|
handleChangeShowTrayIcon = () => {
|
||||||
const shouldShowTrayIcon = !this.showTrayIconRef.current?.props.checked;
|
const shouldShowTrayIcon = this.showTrayIconRef.current?.checked;
|
||||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'showTrayIcon', data: shouldShowTrayIcon});
|
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'showTrayIcon', data: shouldShowTrayIcon});
|
||||||
this.setState({
|
this.setState({
|
||||||
showTrayIcon: shouldShowTrayIcon,
|
showTrayIcon: shouldShowTrayIcon,
|
||||||
@@ -207,14 +207,14 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleChangeAutoStart = () => {
|
handleChangeAutoStart = () => {
|
||||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'autostart', data: !this.autostartRef.current?.props.checked});
|
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'autostart', data: this.autostartRef.current?.checked});
|
||||||
this.setState({
|
this.setState({
|
||||||
autostart: !this.autostartRef.current?.props.checked,
|
autostart: this.autostartRef.current?.checked,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChangeMinimizeToTray = () => {
|
handleChangeMinimizeToTray = () => {
|
||||||
const shouldMinimizeToTray = this.state.showTrayIcon && !this.minimizeToTrayRef.current?.props.checked;
|
const shouldMinimizeToTray = this.state.showTrayIcon && !this.minimizeToTrayRef.current?.checked;
|
||||||
|
|
||||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'minimizeToTray', data: shouldMinimizeToTray});
|
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'minimizeToTray', data: shouldMinimizeToTray});
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -240,13 +240,13 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
|||||||
key: 'notifications',
|
key: 'notifications',
|
||||||
data: {
|
data: {
|
||||||
...this.state.notifications,
|
...this.state.notifications,
|
||||||
flashWindow: this.flashWindowRef.current?.props.checked ? 0 : 2,
|
flashWindow: this.flashWindowRef.current?.checked ? 0 : 2,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
this.setState({
|
this.setState({
|
||||||
notifications: {
|
notifications: {
|
||||||
...this.state.notifications,
|
...this.state.notifications,
|
||||||
flashWindow: this.flashWindowRef.current?.props.checked ? 0 : 2,
|
flashWindow: this.flashWindowRef.current?.checked ? 0 : 2,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -256,18 +256,18 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
|||||||
key: 'notifications',
|
key: 'notifications',
|
||||||
data: {
|
data: {
|
||||||
...this.state.notifications,
|
...this.state.notifications,
|
||||||
bounceIcon: !this.bounceIconRef.current?.props.checked,
|
bounceIcon: this.bounceIconRef.current?.checked,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
this.setState({
|
this.setState({
|
||||||
notifications: {
|
notifications: {
|
||||||
...this.state.notifications,
|
...this.state.notifications,
|
||||||
bounceIcon: !this.bounceIconRef.current?.props.checked,
|
bounceIcon: this.bounceIconRef.current?.checked,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleBounceIconType = (event: React.ChangeEvent<Radio & HTMLInputElement>) => {
|
handleBounceIconType = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {
|
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {
|
||||||
key: 'notifications',
|
key: 'notifications',
|
||||||
data: {
|
data: {
|
||||||
@@ -284,23 +284,23 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleShowUnreadBadge = () => {
|
handleShowUnreadBadge = () => {
|
||||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'showUnreadBadge', data: !this.showUnreadBadgeRef.current?.props.checked});
|
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'showUnreadBadge', data: this.showUnreadBadgeRef.current?.checked});
|
||||||
this.setState({
|
this.setState({
|
||||||
showUnreadBadge: !this.showUnreadBadgeRef.current?.props.checked,
|
showUnreadBadge: this.showUnreadBadgeRef.current?.checked,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChangeUseSpellChecker = () => {
|
handleChangeUseSpellChecker = () => {
|
||||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'useSpellChecker', data: !this.useSpellCheckerRef.current?.props.checked});
|
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'useSpellChecker', data: this.useSpellCheckerRef.current?.checked});
|
||||||
this.setState({
|
this.setState({
|
||||||
useSpellChecker: !this.useSpellCheckerRef.current?.props.checked,
|
useSpellChecker: this.useSpellCheckerRef.current?.checked,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChangeEnableHardwareAcceleration = () => {
|
handleChangeEnableHardwareAcceleration = () => {
|
||||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'enableHardwareAcceleration', data: !this.enableHardwareAccelerationRef.current?.props.checked});
|
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'enableHardwareAcceleration', data: this.enableHardwareAccelerationRef.current?.checked});
|
||||||
this.setState({
|
this.setState({
|
||||||
enableHardwareAcceleration: !this.enableHardwareAccelerationRef.current?.props.checked,
|
enableHardwareAcceleration: this.enableHardwareAccelerationRef.current?.checked,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,10 +350,6 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const settingsPage = {
|
const settingsPage = {
|
||||||
navbar: {
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
position: 'relative' as const,
|
|
||||||
},
|
|
||||||
close: {
|
close: {
|
||||||
textDecoration: 'none',
|
textDecoration: 'none',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@@ -424,7 +420,6 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
|||||||
const serversRow = (
|
const serversRow = (
|
||||||
<Row>
|
<Row>
|
||||||
<Col
|
<Col
|
||||||
md={10}
|
|
||||||
xs={8}
|
xs={8}
|
||||||
>
|
>
|
||||||
<h2 style={settingsPage.sectionHeading}>{'Server Management'}</h2>
|
<h2 style={settingsPage.sectionHeading}>{'Server Management'}</h2>
|
||||||
@@ -437,7 +432,6 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
|||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
<Col
|
<Col
|
||||||
md={2}
|
|
||||||
xs={4}
|
xs={4}
|
||||||
>
|
>
|
||||||
<p className='text-right'>
|
<p className='text-right'>
|
||||||
@@ -468,66 +462,74 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
|||||||
// MacOS has an option in the Dock, to set the app to autostart, so we choose to not support this option for OSX
|
// MacOS has an option in the Dock, to set the app to autostart, so we choose to not support this option for OSX
|
||||||
if (window.process.platform === 'win32' || window.process.platform === 'linux') {
|
if (window.process.platform === 'win32' || window.process.platform === 'linux') {
|
||||||
options.push(
|
options.push(
|
||||||
<Checkbox
|
<FormCheck>
|
||||||
|
<FormCheck.Input
|
||||||
|
type='checkbox'
|
||||||
key='inputAutoStart'
|
key='inputAutoStart'
|
||||||
id='inputAutoStart'
|
id='inputAutoStart'
|
||||||
ref={this.autostartRef}
|
ref={this.autostartRef}
|
||||||
checked={this.state.autostart}
|
checked={this.state.autostart}
|
||||||
onChange={this.handleChangeAutoStart}
|
onChange={this.handleChangeAutoStart}
|
||||||
>
|
/>
|
||||||
{'Start app on login'}
|
{'Start app on login'}
|
||||||
<HelpBlock>
|
<FormText>
|
||||||
{'If enabled, the app starts automatically when you log in to your machine.'}
|
{'If enabled, the app starts automatically when you log in to your machine.'}
|
||||||
</HelpBlock>
|
</FormText>
|
||||||
</Checkbox>);
|
</FormCheck>);
|
||||||
}
|
}
|
||||||
|
|
||||||
options.push(
|
options.push(
|
||||||
<Checkbox
|
<FormCheck>
|
||||||
|
<FormCheck.Input
|
||||||
|
type='checkbox'
|
||||||
key='inputSpellChecker'
|
key='inputSpellChecker'
|
||||||
id='inputSpellChecker'
|
id='inputSpellChecker'
|
||||||
ref={this.useSpellCheckerRef}
|
ref={this.useSpellCheckerRef}
|
||||||
checked={this.state.useSpellChecker}
|
checked={this.state.useSpellChecker}
|
||||||
onChange={this.handleChangeUseSpellChecker}
|
onChange={this.handleChangeUseSpellChecker}
|
||||||
>
|
/>
|
||||||
{'Check spelling'}
|
{'Check spelling'}
|
||||||
<HelpBlock>
|
<FormText>
|
||||||
{'Highlight misspelled words in your messages based on your system language configuration. '}
|
{'Highlight misspelled words in your messages based on your system language configuration. '}
|
||||||
{'Setting takes effect after restarting the app.'}
|
{'Setting takes effect after restarting the app.'}
|
||||||
</HelpBlock>
|
</FormText>
|
||||||
</Checkbox>);
|
</FormCheck>);
|
||||||
|
|
||||||
if (window.process.platform === 'darwin' || window.process.platform === 'win32') {
|
if (window.process.platform === 'darwin' || window.process.platform === 'win32') {
|
||||||
const TASKBAR = window.process.platform === 'win32' ? 'taskbar' : 'Dock';
|
const TASKBAR = window.process.platform === 'win32' ? 'taskbar' : 'Dock';
|
||||||
options.push(
|
options.push(
|
||||||
<Checkbox
|
<FormCheck>
|
||||||
|
<FormCheck.Input
|
||||||
|
type='checkbox'
|
||||||
key='inputShowUnreadBadge'
|
key='inputShowUnreadBadge'
|
||||||
id='inputShowUnreadBadge'
|
id='inputShowUnreadBadge'
|
||||||
ref={this.showUnreadBadgeRef}
|
ref={this.showUnreadBadgeRef}
|
||||||
checked={this.state.showUnreadBadge}
|
checked={this.state.showUnreadBadge}
|
||||||
onChange={this.handleShowUnreadBadge}
|
onChange={this.handleShowUnreadBadge}
|
||||||
>
|
/>
|
||||||
{`Show red badge on ${TASKBAR} icon to indicate unread messages`}
|
{`Show red badge on ${TASKBAR} icon to indicate unread messages`}
|
||||||
<HelpBlock>
|
<FormText>
|
||||||
{`Regardless of this setting, mentions are always indicated with a red badge and item count on the ${TASKBAR} icon.`}
|
{`Regardless of this setting, mentions are always indicated with a red badge and item count on the ${TASKBAR} icon.`}
|
||||||
</HelpBlock>
|
</FormText>
|
||||||
</Checkbox>);
|
</FormCheck>);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.process.platform === 'win32' || window.process.platform === 'linux') {
|
if (window.process.platform === 'win32' || window.process.platform === 'linux') {
|
||||||
options.push(
|
options.push(
|
||||||
<Checkbox
|
<FormCheck>
|
||||||
|
<FormCheck.Input
|
||||||
|
type='checkbox'
|
||||||
key='flashWindow'
|
key='flashWindow'
|
||||||
id='inputflashWindow'
|
id='inputflashWindow'
|
||||||
ref={this.flashWindowRef}
|
ref={this.flashWindowRef}
|
||||||
checked={!this.state.notifications || this.state.notifications.flashWindow === 2}
|
checked={!this.state.notifications || this.state.notifications.flashWindow === 2}
|
||||||
onChange={this.handleFlashWindow}
|
onChange={this.handleFlashWindow}
|
||||||
>
|
/>
|
||||||
{'Flash app window and taskbar icon when a new message is received'}
|
{'Flash app window and taskbar icon when a new message is received'}
|
||||||
<HelpBlock>
|
<FormText>
|
||||||
{'If enabled, app window and taskbar icon flash for a few seconds when a new message is received.'}
|
{'If enabled, app window and taskbar icon flash for a few seconds when a new message is received.'}
|
||||||
</HelpBlock>
|
</FormText>
|
||||||
</Checkbox>);
|
</FormCheck>);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.process.platform === 'darwin') {
|
if (window.process.platform === 'darwin') {
|
||||||
@@ -535,7 +537,8 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
|||||||
<FormGroup
|
<FormGroup
|
||||||
key='OptionsForm'
|
key='OptionsForm'
|
||||||
>
|
>
|
||||||
<Checkbox
|
<FormCheck
|
||||||
|
type='checkbox'
|
||||||
inline={true}
|
inline={true}
|
||||||
key='bounceIcon'
|
key='bounceIcon'
|
||||||
id='inputBounceIcon'
|
id='inputBounceIcon'
|
||||||
@@ -543,10 +546,10 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
|||||||
checked={this.state.notifications ? this.state.notifications.bounceIcon : false}
|
checked={this.state.notifications ? this.state.notifications.bounceIcon : false}
|
||||||
onChange={this.handleBounceIcon}
|
onChange={this.handleBounceIcon}
|
||||||
style={{marginRight: '10px'}}
|
style={{marginRight: '10px'}}
|
||||||
>
|
label='Bounce the Dock icon'
|
||||||
{'Bounce the Dock icon'}
|
/>
|
||||||
</Checkbox>
|
<FormCheck
|
||||||
<Radio
|
type='radio'
|
||||||
inline={true}
|
inline={true}
|
||||||
name='bounceIconType'
|
name='bounceIconType'
|
||||||
value='informational'
|
value='informational'
|
||||||
@@ -557,43 +560,44 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
|||||||
this.state.notifications.bounceIconType === 'informational'
|
this.state.notifications.bounceIconType === 'informational'
|
||||||
}
|
}
|
||||||
onChange={this.handleBounceIconType}
|
onChange={this.handleBounceIconType}
|
||||||
>
|
label='once'
|
||||||
{'once'}
|
/>
|
||||||
</Radio>
|
|
||||||
{' '}
|
{' '}
|
||||||
<Radio
|
<FormCheck
|
||||||
|
type='radio'
|
||||||
inline={true}
|
inline={true}
|
||||||
name='bounceIconType'
|
name='bounceIconType'
|
||||||
value='critical'
|
value='critical'
|
||||||
disabled={!this.state.notifications || !this.state.notifications.bounceIcon}
|
disabled={!this.state.notifications || !this.state.notifications.bounceIcon}
|
||||||
defaultChecked={this.state.notifications && this.state.notifications.bounceIconType === 'critical'}
|
defaultChecked={this.state.notifications && this.state.notifications.bounceIconType === 'critical'}
|
||||||
onChange={this.handleBounceIconType}
|
onChange={this.handleBounceIconType}
|
||||||
>
|
label={'until I open the app'}
|
||||||
{'until I open the app'}
|
/>
|
||||||
</Radio>
|
<FormText
|
||||||
<HelpBlock
|
|
||||||
style={{marginLeft: '20px'}}
|
style={{marginLeft: '20px'}}
|
||||||
>
|
>
|
||||||
{'If enabled, the Dock icon bounces once or until the user opens the app when a new notification is received.'}
|
{'If enabled, the Dock icon bounces once or until the user opens the app when a new notification is received.'}
|
||||||
</HelpBlock>
|
</FormText>
|
||||||
</FormGroup>,
|
</FormGroup>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.process.platform === 'darwin' || window.process.platform === 'linux') {
|
if (window.process.platform === 'darwin' || window.process.platform === 'linux') {
|
||||||
options.push(
|
options.push(
|
||||||
<Checkbox
|
<FormCheck>
|
||||||
|
<FormCheck.Input
|
||||||
|
type='checkbox'
|
||||||
key='inputShowTrayIcon'
|
key='inputShowTrayIcon'
|
||||||
id='inputShowTrayIcon'
|
id='inputShowTrayIcon'
|
||||||
ref={this.showTrayIconRef}
|
ref={this.showTrayIconRef}
|
||||||
checked={this.state.showTrayIcon}
|
checked={this.state.showTrayIcon}
|
||||||
onChange={this.handleChangeShowTrayIcon}
|
onChange={this.handleChangeShowTrayIcon}
|
||||||
>
|
/>
|
||||||
{window.process.platform === 'darwin' ? `Show ${this.state.appName} icon in the menu bar` : 'Show icon in the notification area'}
|
{window.process.platform === 'darwin' ? `Show ${this.state.appName} icon in the menu bar` : 'Show icon in the notification area'}
|
||||||
<HelpBlock>
|
<FormText>
|
||||||
{'Setting takes effect after restarting the app.'}
|
{'Setting takes effect after restarting the app.'}
|
||||||
</HelpBlock>
|
</FormText>
|
||||||
</Checkbox>);
|
</FormCheck>);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.process.platform === 'linux') {
|
if (window.process.platform === 'linux') {
|
||||||
@@ -604,30 +608,33 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
|||||||
style={{marginLeft: '20px'}}
|
style={{marginLeft: '20px'}}
|
||||||
>
|
>
|
||||||
{'Icon theme: '}
|
{'Icon theme: '}
|
||||||
<Radio
|
<FormCheck
|
||||||
|
type='radio'
|
||||||
inline={true}
|
inline={true}
|
||||||
name='trayIconTheme'
|
name='trayIconTheme'
|
||||||
value='light'
|
value='light'
|
||||||
defaultChecked={this.state.trayIconTheme === 'light' || !this.state.trayIconTheme}
|
defaultChecked={this.state.trayIconTheme === 'light' || !this.state.trayIconTheme}
|
||||||
onChange={() => this.handleChangeTrayIconTheme('light')}
|
onChange={() => this.handleChangeTrayIconTheme('light')}
|
||||||
>
|
label={'Light'}
|
||||||
{'Light'}
|
/>
|
||||||
</Radio>
|
|
||||||
{' '}
|
{' '}
|
||||||
<Radio
|
<FormCheck
|
||||||
|
type='radio'
|
||||||
inline={true}
|
inline={true}
|
||||||
name='trayIconTheme'
|
name='trayIconTheme'
|
||||||
value='dark'
|
value='dark'
|
||||||
defaultChecked={this.state.trayIconTheme === 'dark'}
|
defaultChecked={this.state.trayIconTheme === 'dark'}
|
||||||
onChange={() => this.handleChangeTrayIconTheme('dark')}
|
onChange={() => this.handleChangeTrayIconTheme('dark')}
|
||||||
>{'Dark'}</Radio>
|
label={'Dark'}
|
||||||
|
/>
|
||||||
</FormGroup>,
|
</FormGroup>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.process.platform === 'linux') {
|
if (window.process.platform === 'linux') {
|
||||||
options.push(
|
options.push(
|
||||||
<Checkbox
|
<FormCheck
|
||||||
|
type='radio'
|
||||||
key='inputMinimizeToTray'
|
key='inputMinimizeToTray'
|
||||||
id='inputMinimizeToTray'
|
id='inputMinimizeToTray'
|
||||||
ref={this.minimizeToTrayRef}
|
ref={this.minimizeToTrayRef}
|
||||||
@@ -636,27 +643,29 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
|||||||
onChange={this.handleChangeMinimizeToTray}
|
onChange={this.handleChangeMinimizeToTray}
|
||||||
>
|
>
|
||||||
{'Leave app running in notification area when application window is closed'}
|
{'Leave app running in notification area when application window is closed'}
|
||||||
<HelpBlock>
|
<FormText>
|
||||||
{'If enabled, the app stays running in the notification area after app window is closed.'}
|
{'If enabled, the app stays running in the notification area after app window is closed.'}
|
||||||
{this.state.trayWasVisible || !this.state.showTrayIcon ? '' : ' Setting takes effect after restarting the app.'}
|
{this.state.trayWasVisible || !this.state.showTrayIcon ? '' : ' Setting takes effect after restarting the app.'}
|
||||||
</HelpBlock>
|
</FormText>
|
||||||
</Checkbox>);
|
</FormCheck>);
|
||||||
}
|
}
|
||||||
|
|
||||||
options.push(
|
options.push(
|
||||||
<Checkbox
|
<FormCheck>
|
||||||
|
<FormCheck.Input
|
||||||
|
type='checkbox'
|
||||||
key='inputEnableHardwareAcceleration'
|
key='inputEnableHardwareAcceleration'
|
||||||
id='inputEnableHardwareAcceleration'
|
id='inputEnableHardwareAcceleration'
|
||||||
ref={this.enableHardwareAccelerationRef}
|
ref={this.enableHardwareAccelerationRef}
|
||||||
checked={this.state.enableHardwareAcceleration}
|
checked={this.state.enableHardwareAcceleration}
|
||||||
onChange={this.handleChangeEnableHardwareAcceleration}
|
onChange={this.handleChangeEnableHardwareAcceleration}
|
||||||
>
|
/>
|
||||||
{'Use GPU hardware acceleration'}
|
{'Use GPU hardware acceleration'}
|
||||||
<HelpBlock>
|
<FormText>
|
||||||
{'If enabled, Mattermost UI is rendered more efficiently but can lead to decreased stability for some systems.'}
|
{'If enabled, Mattermost UI is rendered more efficiently but can lead to decreased stability for some systems.'}
|
||||||
{' Setting takes effect after restarting the app.'}
|
{' Setting takes effect after restarting the app.'}
|
||||||
</HelpBlock>
|
</FormText>
|
||||||
</Checkbox>,
|
</FormCheck>,
|
||||||
);
|
);
|
||||||
|
|
||||||
options.push(
|
options.push(
|
||||||
@@ -679,9 +688,9 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
|||||||
>
|
>
|
||||||
<span>{'Change'}</span>
|
<span>{'Change'}</span>
|
||||||
</Button>
|
</Button>
|
||||||
<HelpBlock>
|
<FormText>
|
||||||
{'Specify the folder where files will download.'}
|
{'Specify the folder where files will download.'}
|
||||||
</HelpBlock>
|
</FormText>
|
||||||
</div>,
|
</div>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -733,20 +742,16 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
|||||||
height: '100%',
|
height: '100%',
|
||||||
margin: '0 -15px',
|
margin: '0 -15px',
|
||||||
}}
|
}}
|
||||||
>
|
|
||||||
<Navbar
|
|
||||||
className='navbar-fixed-top'
|
|
||||||
style={settingsPage.navbar}
|
|
||||||
>
|
>
|
||||||
<div style={{position: 'relative'}}>
|
<div style={{position: 'relative'}}>
|
||||||
<h1 style={settingsPage.heading}>{'Settings'}</h1>
|
<h1 style={settingsPage.heading}>{'Settings'}</h1>
|
||||||
|
<hr/>
|
||||||
</div>
|
</div>
|
||||||
</Navbar>
|
<Container
|
||||||
<Grid
|
|
||||||
className='settingsPage'
|
className='settingsPage'
|
||||||
>
|
>
|
||||||
{waitForIpc}
|
{waitForIpc}
|
||||||
</Grid>
|
</Container>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -3,9 +3,10 @@
|
|||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Nav, NavItem} from 'react-bootstrap';
|
import {Nav, NavItem, NavLink} from 'react-bootstrap';
|
||||||
import {Container, Draggable, OnDropCallback} from 'react-smooth-dnd';
|
import {DragDropContext, Draggable, DraggingStyle, Droppable, DropResult, NotDraggingStyle} from 'react-beautiful-dnd';
|
||||||
import PlusIcon from 'mdi-react/PlusIcon';
|
import PlusIcon from 'mdi-react/PlusIcon';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import {Team} from 'types/config';
|
import {Team} from 'types/config';
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ type Props = {
|
|||||||
mentionCounts: Record<string, number>;
|
mentionCounts: Record<string, number>;
|
||||||
showAddServerButton: boolean;
|
showAddServerButton: boolean;
|
||||||
onAddServer: () => void;
|
onAddServer: () => void;
|
||||||
onDrop: OnDropCallback;
|
onDrop: (result: DropResult) => void;
|
||||||
tabsDisabled?: boolean;
|
tabsDisabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -30,9 +31,18 @@ type State = {
|
|||||||
hasGPOTeams: boolean;
|
hasGPOTeams: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class TabBar extends React.PureComponent<Props, State> { // need "this"
|
function getStyle(style?: DraggingStyle | NotDraggingStyle) {
|
||||||
container?: React.RefObject<Container>;
|
if (style?.transform) {
|
||||||
|
const axisLockX = `${style.transform.slice(0, style.transform.indexOf(','))}, 0px)`;
|
||||||
|
return {
|
||||||
|
...style,
|
||||||
|
transform: axisLockX,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class TabBar extends React.PureComponent<Props, State> { // need "this"
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -48,7 +58,7 @@ export default class TabBar extends React.PureComponent<Props, State> { // need
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const orderedTabs = this.props.teams.concat().sort((a, b) => a.order - b.order);
|
const orderedTabs = this.props.teams.concat().sort((a, b) => a.order - b.order);
|
||||||
const tabs = orderedTabs.map((team) => {
|
const tabs = orderedTabs.map((team, orderedIndex) => {
|
||||||
const index = this.props.teams.indexOf(team);
|
const index = this.props.teams.indexOf(team);
|
||||||
|
|
||||||
const sessionExpired = this.props.sessionsExpired[index];
|
const sessionExpired = this.props.sessionsExpired[index];
|
||||||
@@ -76,23 +86,35 @@ export default class TabBar extends React.PureComponent<Props, State> { // need
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = `teamTabItem${index}`;
|
return (
|
||||||
const navItem = () => (
|
<Draggable
|
||||||
<NavItem
|
|
||||||
key={index}
|
key={index}
|
||||||
id={id}
|
draggableId={`teamTabItem${index}`}
|
||||||
|
index={orderedIndex}
|
||||||
|
>
|
||||||
|
{(provided, snapshot) => (
|
||||||
|
<NavItem
|
||||||
|
ref={provided.innerRef}
|
||||||
|
as='li'
|
||||||
|
id={`teamTabItem${index}`}
|
||||||
|
draggable={false}
|
||||||
|
title={team.name}
|
||||||
|
className={classNames('teamTabItem', {
|
||||||
|
active: this.props.activeKey === index,
|
||||||
|
dragging: snapshot.isDragging,
|
||||||
|
})}
|
||||||
|
{...provided.draggableProps}
|
||||||
|
{...provided.dragHandleProps}
|
||||||
|
style={getStyle(provided.draggableProps.style)}
|
||||||
|
>
|
||||||
|
<NavLink
|
||||||
eventKey={index}
|
eventKey={index}
|
||||||
draggable={false}
|
draggable={false}
|
||||||
ref={id}
|
|
||||||
active={this.props.activeKey === index}
|
active={this.props.activeKey === index}
|
||||||
onMouseDown={() => {
|
disabled={this.props.tabsDisabled}
|
||||||
this.props.onSelect(team.name, index);
|
|
||||||
}}
|
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
this.props.onSelect(team.name, index);
|
this.props.onSelect(team.name, index);
|
||||||
}}
|
}}
|
||||||
title={team.name}
|
|
||||||
disabled={this.props.tabsDisabled}
|
|
||||||
>
|
>
|
||||||
<div className='TabBar-tabSeperator'>
|
<div className='TabBar-tabSeperator'>
|
||||||
<span>
|
<span>
|
||||||
@@ -100,59 +122,70 @@ export default class TabBar extends React.PureComponent<Props, State> { // need
|
|||||||
</span>
|
</span>
|
||||||
{ badgeDiv }
|
{ badgeDiv }
|
||||||
</div>
|
</div>
|
||||||
|
</NavLink>
|
||||||
</NavItem>
|
</NavItem>
|
||||||
|
)}
|
||||||
|
</Draggable>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
|
||||||
<Draggable
|
|
||||||
key={id}
|
|
||||||
render={navItem}
|
|
||||||
className='teamTabItem'
|
|
||||||
/>);
|
|
||||||
});
|
});
|
||||||
if (this.props.showAddServerButton === true) {
|
if (this.props.showAddServerButton === true) {
|
||||||
tabs.push(
|
tabs.push(
|
||||||
|
<Draggable
|
||||||
|
draggableId={'TabBar-addServerButton'}
|
||||||
|
index={this.props.teams.length}
|
||||||
|
isDragDisabled={true}
|
||||||
|
>
|
||||||
|
{(provided) => (
|
||||||
<NavItem
|
<NavItem
|
||||||
|
ref={provided.innerRef}
|
||||||
|
as='li'
|
||||||
className='TabBar-addServerButton'
|
className='TabBar-addServerButton'
|
||||||
key='addServerButton'
|
key='addServerButton'
|
||||||
id='addServerButton'
|
id='addServerButton'
|
||||||
eventKey='addServerButton'
|
|
||||||
draggable={false}
|
draggable={false}
|
||||||
title='Add new server'
|
title='Add new server'
|
||||||
|
{...provided.draggableProps}
|
||||||
|
{...provided.dragHandleProps}
|
||||||
|
>
|
||||||
|
<NavLink
|
||||||
|
eventKey='addServerButton'
|
||||||
|
draggable={false}
|
||||||
|
disabled={this.props.tabsDisabled}
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
this.props.onAddServer();
|
this.props.onAddServer();
|
||||||
}}
|
}}
|
||||||
disabled={this.props.tabsDisabled}
|
|
||||||
>
|
>
|
||||||
<div className='TabBar-tabSeperator'>
|
<div className='TabBar-tabSeperator'>
|
||||||
<PlusIcon size={20}/>
|
<PlusIcon size={20}/>
|
||||||
</div>
|
</div>
|
||||||
</NavItem>,
|
</NavLink>
|
||||||
|
</NavItem>
|
||||||
|
)}
|
||||||
|
</Draggable>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const navContainer = (ref: React.RefObject<Nav>) => (
|
return (
|
||||||
|
<DragDropContext onDragEnd={this.props.onDrop}>
|
||||||
|
<Droppable
|
||||||
|
isDropDisabled={this.state.hasGPOTeams || this.props.tabsDisabled}
|
||||||
|
droppableId='tabBar'
|
||||||
|
direction='horizontal'
|
||||||
|
>
|
||||||
|
{(provided) => (
|
||||||
<Nav
|
<Nav
|
||||||
ref={ref}
|
ref={provided.innerRef}
|
||||||
className={`smooth-dnd-container TabBar${this.props.isDarkMode ? ' darkMode' : ''}`}
|
className={`TabBar${this.props.isDarkMode ? ' darkMode' : ''}`}
|
||||||
id={this.props.id}
|
id={this.props.id}
|
||||||
bsStyle='tabs'
|
variant='tabs'
|
||||||
|
{...provided.droppableProps}
|
||||||
>
|
>
|
||||||
{tabs}
|
{tabs}
|
||||||
|
{provided.placeholder}
|
||||||
</Nav>
|
</Nav>
|
||||||
);
|
)}
|
||||||
return (
|
</Droppable>
|
||||||
<Container
|
</DragDropContext>
|
||||||
ref={this.container}
|
|
||||||
render={navContainer}
|
|
||||||
orientation='horizontal'
|
|
||||||
lockAxis={'x'}
|
|
||||||
onDrop={this.props.onDrop}
|
|
||||||
animationDuration={300}
|
|
||||||
shouldAcceptDrop={() => {
|
|
||||||
return !this.state.hasGPOTeams && !this.props.tabsDisabled;
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,7 +31,7 @@ export default class TeamListItem extends React.PureComponent<Props> {
|
|||||||
{ this.props.url }
|
{ this.props.url }
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className='pull-right'>
|
<div>
|
||||||
<a
|
<a
|
||||||
href='#'
|
href='#'
|
||||||
onClick={this.handleTeamEditing}
|
onClick={this.handleTeamEditing}
|
||||||
|
@@ -7,22 +7,22 @@ import {Button, Navbar, ProgressBar} from 'react-bootstrap';
|
|||||||
|
|
||||||
type InstallButtonProps = {
|
type InstallButtonProps = {
|
||||||
notifyOnly?: boolean;
|
notifyOnly?: boolean;
|
||||||
onClickInstall?: React.MouseEventHandler<Button>;
|
onClickInstall?: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
onClickDownload?: React.MouseEventHandler<Button>;
|
onClickDownload?: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
};
|
};
|
||||||
|
|
||||||
function InstallButton(props: InstallButtonProps) {
|
function InstallButton(props: InstallButtonProps) {
|
||||||
if (props.notifyOnly) {
|
if (props.notifyOnly) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
bsStyle='primary'
|
variant='primary'
|
||||||
onClick={props.onClickDownload}
|
onClick={props.onClickDownload}
|
||||||
>{'Download Update'}</Button>
|
>{'Download Update'}</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
bsStyle='primary'
|
variant='primary'
|
||||||
onClick={props.onClickInstall}
|
onClick={props.onClickInstall}
|
||||||
>{'Install Update'}</Button>
|
>{'Install Update'}</Button>
|
||||||
);
|
);
|
||||||
@@ -33,12 +33,12 @@ type UpdaterPageProps = {
|
|||||||
notifyOnly?: boolean;
|
notifyOnly?: boolean;
|
||||||
isDownloading?: boolean;
|
isDownloading?: boolean;
|
||||||
progress?: number;
|
progress?: number;
|
||||||
onClickInstall?: React.MouseEventHandler<Button>;
|
onClickInstall?: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
onClickDownload?: React.MouseEventHandler<Button>;
|
onClickDownload?: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
onClickReleaseNotes?: React.MouseEventHandler<HTMLAnchorElement>;
|
onClickReleaseNotes?: React.MouseEventHandler<HTMLAnchorElement>;
|
||||||
onClickRemind?: React.MouseEventHandler<Button>;
|
onClickRemind?: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
onClickSkip?: React.MouseEventHandler<Button>;
|
onClickSkip?: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
onClickCancel?: React.MouseEventHandler<Button>;
|
onClickCancel?: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
};
|
};
|
||||||
|
|
||||||
function UpdaterPage(props: UpdaterPageProps) {
|
function UpdaterPage(props: UpdaterPageProps) {
|
||||||
@@ -47,11 +47,10 @@ function UpdaterPage(props: UpdaterPageProps) {
|
|||||||
footer = (
|
footer = (
|
||||||
<Navbar
|
<Navbar
|
||||||
className='UpdaterPage-footer'
|
className='UpdaterPage-footer'
|
||||||
fixedBottom={true}
|
fixed='bottom'
|
||||||
fluid={true}
|
|
||||||
>
|
>
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
active={true}
|
animated={true}
|
||||||
now={props.progress}
|
now={props.progress}
|
||||||
label={`${props.progress}%`}
|
label={`${props.progress}%`}
|
||||||
/>
|
/>
|
||||||
@@ -66,17 +65,16 @@ function UpdaterPage(props: UpdaterPageProps) {
|
|||||||
footer = (
|
footer = (
|
||||||
<Navbar
|
<Navbar
|
||||||
className='UpdaterPage-footer'
|
className='UpdaterPage-footer'
|
||||||
fixedBottom={true}
|
fixed='bottom'
|
||||||
fluid={true}
|
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
className='UpdaterPage-skipButton'
|
className='UpdaterPage-skipButton'
|
||||||
bsStyle='link'
|
variant='link'
|
||||||
onClick={props.onClickSkip}
|
onClick={props.onClickSkip}
|
||||||
>{'Skip this version'}</Button>
|
>{'Skip this version'}</Button>
|
||||||
<div className='pull-right'>
|
<div className='pull-right'>
|
||||||
<Button
|
<Button
|
||||||
bsStyle='link'
|
variant='link'
|
||||||
onClick={props.onClickRemind}
|
onClick={props.onClickRemind}
|
||||||
>{'Remind me in 2 days'}</Button>
|
>{'Remind me in 2 days'}</Button>
|
||||||
<InstallButton
|
<InstallButton
|
||||||
@@ -91,7 +89,7 @@ function UpdaterPage(props: UpdaterPageProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='UpdaterPage'>
|
<div className='UpdaterPage'>
|
||||||
<Navbar fluid={true} >
|
<Navbar>
|
||||||
<h1 className='UpdaterPage-heading'>{'New update is available'}</h1>
|
<h1 className='UpdaterPage-heading'>{'New update is available'}</h1>
|
||||||
</Navbar>
|
</Navbar>
|
||||||
<div className='container-fluid'>
|
<div className='container-fluid'>
|
||||||
|
@@ -105,6 +105,7 @@ export default class ShowCertificateModal extends React.PureComponent<Props, Sta
|
|||||||
<Row>
|
<Row>
|
||||||
<Col>
|
<Col>
|
||||||
<Button
|
<Button
|
||||||
|
variant='primary'
|
||||||
onClick={this.handleOk}
|
onClick={this.handleOk}
|
||||||
className={'primary'}
|
className={'primary'}
|
||||||
>{'Close'}</Button>
|
>{'Close'}</Button>
|
||||||
|
@@ -72,7 +72,7 @@ label {
|
|||||||
outline: 0;
|
outline: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.help-block {
|
.form-text {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
@@ -173,7 +173,7 @@ button.default:focus {
|
|||||||
color: #a94442;
|
color: #a94442;
|
||||||
}
|
}
|
||||||
|
|
||||||
.has-error .form-control {
|
:invalid .form-control {
|
||||||
border-color: #a94442;
|
border-color: #a94442;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#extra-bar.hidden {
|
#extra-bar.hidden {
|
||||||
max-height: 0px;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
span.backLabel {
|
span.backLabel {
|
||||||
@@ -25,7 +25,6 @@ span.backLabel {
|
|||||||
|
|
||||||
span.backIcon {
|
span.backIcon {
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
font-size: 1.6rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.container-fluid button:first-child {
|
.container-fluid button:first-child {
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
min-width: 48px;
|
min-width: 48px;
|
||||||
max-width: 224px;
|
max-width: 224px;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.TabBar>li>a {
|
.TabBar>li>a {
|
||||||
@@ -41,6 +42,7 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
letter-spacing: -0.2px;
|
letter-spacing: -0.2px;
|
||||||
transition: 0.3s;
|
transition: 0.3s;
|
||||||
|
border: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.TabBar.darkMode>li>a {
|
.TabBar.darkMode>li>a {
|
||||||
@@ -80,7 +82,7 @@
|
|||||||
flex: 0 0 6px;
|
flex: 0 0 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.TabBar>li.teamTabItem.active:before, .TabBar>li.teamTabItem.smooth-dnd-ghost:before {
|
.TabBar>li.teamTabItem.active:before, .TabBar>li.teamTabItem.dragging:before {
|
||||||
left: -4px;
|
left: -4px;
|
||||||
border-bottom-right-radius: 6px;
|
border-bottom-right-radius: 6px;
|
||||||
border-right: 2px solid #fff;
|
border-right: 2px solid #fff;
|
||||||
@@ -88,12 +90,12 @@
|
|||||||
z-index: 9;
|
z-index: 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.TabBar.darkMode>li.teamTabItem.active:before, .TabBar.darkMode>li.teamTabItem.smooth-dnd-ghost:before {
|
.TabBar.darkMode>li.teamTabItem.active:before, .TabBar.darkMode>li.teamTabItem.dragging:before {
|
||||||
border-right: 2px solid #323639;
|
border-right: 2px solid #323639;
|
||||||
border-bottom: 2px solid #323639;
|
border-bottom: 2px solid #323639;
|
||||||
}
|
}
|
||||||
|
|
||||||
.TabBar>li.teamTabItem.active:after, .TabBar>li.teamTabItem.smooth-dnd-ghost:after {
|
.TabBar>li.teamTabItem.active:after, .TabBar>li.teamTabItem.dragging:after {
|
||||||
border-bottom-left-radius: 6px;
|
border-bottom-left-radius: 6px;
|
||||||
right: -5px;
|
right: -5px;
|
||||||
border-left: 2px solid #fff;
|
border-left: 2px solid #fff;
|
||||||
@@ -101,7 +103,7 @@
|
|||||||
z-index: 9;
|
z-index: 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.TabBar.darkMode>li.teamTabItem.active:after, .TabBar.darkMode>li.teamTabItem.smooth-dnd-ghost:after {
|
.TabBar.darkMode>li.teamTabItem.active:after, .TabBar.darkMode>li.teamTabItem.dragging:after {
|
||||||
border-left: 2px solid #323639;
|
border-left: 2px solid #323639;
|
||||||
border-bottom: 2px solid #323639;
|
border-bottom: 2px solid #323639;
|
||||||
}
|
}
|
||||||
@@ -113,8 +115,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.TabBar>li.TabBar-addServerButton{
|
.TabBar>li.TabBar-addServerButton{
|
||||||
transition: none !important;
|
|
||||||
transform: none !important;
|
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
min-width: 40px;
|
min-width: 40px;
|
||||||
}
|
}
|
||||||
@@ -124,6 +124,10 @@
|
|||||||
transition: opacity 0.3s ease-in;
|
transition: opacity 0.3s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.TabBar>li.TabBar-addServerButton>a.active{
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
.TabBar>li.TabBar-addServerButton svg{
|
.TabBar>li.TabBar-addServerButton svg{
|
||||||
margin: -2px;
|
margin: -2px;
|
||||||
}
|
}
|
||||||
@@ -132,7 +136,7 @@
|
|||||||
color: rgba(243,243,243,0.7);
|
color: rgba(243,243,243,0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
.TabBar>li.teamTabItem.active>a, .TabBar>li.teamTabItem.smooth-dnd-ghost>a {
|
.TabBar>li.teamTabItem.active>a, .TabBar>li.teamTabItem.dragging>a {
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 6px 6px 0 0;
|
border-radius: 6px 6px 0 0;
|
||||||
color: rgba(61,60,64,1);
|
color: rgba(61,60,64,1);
|
||||||
@@ -140,11 +144,7 @@
|
|||||||
z-index: 9;
|
z-index: 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.smooth-dnd-no-user-select li.TabBar-addServerButton>a {
|
.TabBar.darkMode>li.teamTabItem.active>a, .TabBar.darkMode>li.teamTabItem.dragging>a {
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.TabBar.darkMode>li.teamTabItem.active>a, .TabBar.darkMode>li.teamTabItem.smooth-dnd-ghost>a {
|
|
||||||
color: #f3f3f3;
|
color: #f3f3f3;
|
||||||
background-color: #323639;
|
background-color: #323639;
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,21 @@
|
|||||||
|
.TeamListItem {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.TeamListItem:hover {
|
.TeamListItem:hover {
|
||||||
background: #eee;
|
background: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.TeamListItem-left {
|
.TeamListItem-left {
|
||||||
display: inline-block;
|
flex-grow: 1;
|
||||||
width: calc(100% - 100px);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.TeamListItem p {
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TeamListItem h4 {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
};
|
||||||
|
@@ -45,6 +45,7 @@
|
|||||||
|
|
||||||
html {
|
html {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
@@ -68,8 +69,8 @@ body {
|
|||||||
transition: opacity 500ms ease-in-out;
|
transition: opacity 500ms ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.has-error .control-label,
|
:invalid .col-form-label,
|
||||||
.has-error .help-block {
|
:invalid .form-text {
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +87,7 @@ body {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
background-color: rgba(0,0,0,0.1);
|
background-color: rgba(0,0,0,0.1);
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topBar>.topBar-bg.unfocused {
|
.topBar>.topBar-bg.unfocused {
|
||||||
|
@@ -1,3 +1,8 @@
|
|||||||
body {
|
body {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: #166de0;
|
||||||
|
border-color: #166de0;
|
||||||
|
}
|
||||||
|
@@ -17,15 +17,6 @@
|
|||||||
transition: opacity 1s cubic-bezier(0.19, 1, 0.22, 1);
|
transition: opacity 1s cubic-bezier(0.19, 1, 0.22, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.TeamListItem p {
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
}
|
|
||||||
|
|
||||||
.TeamListItem h4 {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
};
|
|
||||||
|
|
||||||
.checkbox > label {
|
.checkbox > label {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
@@ -39,3 +30,8 @@ body {
|
|||||||
#content {
|
#content {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: #166de0;
|
||||||
|
border-color: #166de0;
|
||||||
|
}
|
||||||
|
@@ -46,7 +46,7 @@ class Root extends React.PureComponent<Record<string, never>, State> {
|
|||||||
this.setState({config});
|
this.setState({config});
|
||||||
}
|
}
|
||||||
|
|
||||||
moveTabs = async (originalOrder: number, newOrder: number): Promise<number | undefined> => {
|
moveTabs = (originalOrder: number, newOrder: number): number | undefined => {
|
||||||
if (!this.state.config) {
|
if (!this.state.config) {
|
||||||
throw new Error('No config');
|
throw new Error('No config');
|
||||||
}
|
}
|
||||||
@@ -61,20 +61,27 @@ class Root extends React.PureComponent<Record<string, never>, State> {
|
|||||||
const team = tabOrder.splice(originalOrder, 1);
|
const team = tabOrder.splice(originalOrder, 1);
|
||||||
tabOrder.splice(newOrder, 0, team[0]);
|
tabOrder.splice(newOrder, 0, team[0]);
|
||||||
|
|
||||||
let teamIndex;
|
let teamIndex: number | undefined;
|
||||||
tabOrder.forEach((t, order) => {
|
tabOrder.forEach((t, order) => {
|
||||||
if (order === newOrder) {
|
if (order === newOrder) {
|
||||||
teamIndex = t.index;
|
teamIndex = t.index;
|
||||||
}
|
}
|
||||||
teams[t.index].order = order;
|
teams[t.index].order = order;
|
||||||
});
|
});
|
||||||
await this.teamConfigChange(teams);
|
this.setState({
|
||||||
|
config: {
|
||||||
|
...this.state.config,
|
||||||
|
teams,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.teamConfigChange(teams);
|
||||||
return teamIndex;
|
return teamIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
teamConfigChange = async (updatedTeams: Team[]) => {
|
teamConfigChange = async (updatedTeams: Team[]) => {
|
||||||
await window.ipcRenderer.invoke(UPDATE_TEAMS, updatedTeams);
|
window.ipcRenderer.invoke(UPDATE_TEAMS, updatedTeams).then(() => {
|
||||||
await this.reloadConfig();
|
this.reloadConfig();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
reloadConfig = async () => {
|
reloadConfig = async () => {
|
||||||
|
@@ -164,6 +164,7 @@ export default class SelectCertificateModal extends React.PureComponent<Props, S
|
|||||||
<Row>
|
<Row>
|
||||||
<Col sm={4}>
|
<Col sm={4}>
|
||||||
<Button
|
<Button
|
||||||
|
variant='info'
|
||||||
disabled={this.state.selectedIndex === null}
|
disabled={this.state.selectedIndex === null}
|
||||||
onClick={this.handleCertificateInfo}
|
onClick={this.handleCertificateInfo}
|
||||||
className={'info'}
|
className={'info'}
|
||||||
@@ -171,10 +172,12 @@ export default class SelectCertificateModal extends React.PureComponent<Props, S
|
|||||||
</Col>
|
</Col>
|
||||||
<Col sm={8}>
|
<Col sm={8}>
|
||||||
<Button
|
<Button
|
||||||
|
variant='link'
|
||||||
onClick={this.props.onCancel}
|
onClick={this.props.onCancel}
|
||||||
className={'secondary'}
|
className={'secondary'}
|
||||||
>{'Cancel'}</Button>
|
>{'Cancel'}</Button>
|
||||||
<Button
|
<Button
|
||||||
|
variant='primary'
|
||||||
onClick={this.handleOk}
|
onClick={this.handleOk}
|
||||||
disabled={this.state.selectedIndex === null}
|
disabled={this.state.selectedIndex === null}
|
||||||
className={'primary'}
|
className={'primary'}
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
// Copyright (c) 2015-2016 Yuya Ochiai
|
// Copyright (c) 2015-2016 Yuya Ochiai
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Button, Col, ControlLabel, Form, FormGroup, FormControl, Modal} from 'react-bootstrap';
|
import {Button, Col, FormLabel, Form, FormGroup, FormControl, Modal} from 'react-bootstrap';
|
||||||
|
|
||||||
import {LoginModalData} from 'types/auth';
|
import {LoginModalData} from 'types/auth';
|
||||||
import {ModalMessage} from 'types/modals';
|
import {ModalMessage} from 'types/modals';
|
||||||
@@ -56,7 +56,7 @@ export default class LoginModal extends React.PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit = (event: React.MouseEvent<Button>) => {
|
handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.props.onLogin(this.state.request!, this.state.username, this.state.password);
|
this.props.onLogin(this.state.request!, this.state.username, this.state.password);
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -67,7 +67,7 @@ export default class LoginModal extends React.PureComponent<Props, State> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCancel = (event: React.MouseEvent<Button>) => {
|
handleCancel = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.props.onCancel(this.state.request!);
|
this.props.onCancel(this.state.request!);
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -78,11 +78,11 @@ export default class LoginModal extends React.PureComponent<Props, State> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setUsername = (e: React.ChangeEvent<FormControl & HTMLInputElement>) => {
|
setUsername = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
this.setState({username: e.target.value});
|
this.setState({username: e.target.value});
|
||||||
}
|
}
|
||||||
|
|
||||||
setPassword = (e: React.ChangeEvent<FormControl & HTMLInputElement>) => {
|
setPassword = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
this.setState({password: e.target.value});
|
this.setState({password: e.target.value});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +100,6 @@ export default class LoginModal extends React.PureComponent<Props, State> {
|
|||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
show={Boolean(this.state.request && this.state.authInfo)}
|
show={Boolean(this.state.request && this.state.authInfo)}
|
||||||
onHide={() => {}}
|
|
||||||
>
|
>
|
||||||
<Modal.Header>
|
<Modal.Header>
|
||||||
<Modal.Title>{'Authentication Required'}</Modal.Title>
|
<Modal.Title>{'Authentication Required'}</Modal.Title>
|
||||||
@@ -110,12 +109,11 @@ export default class LoginModal extends React.PureComponent<Props, State> {
|
|||||||
{ message }
|
{ message }
|
||||||
</p>
|
</p>
|
||||||
<Form
|
<Form
|
||||||
horizontal={true}
|
|
||||||
onSubmit={this.handleSubmit}
|
onSubmit={this.handleSubmit}
|
||||||
>
|
>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<Col
|
<Col
|
||||||
componentClass={ControlLabel}
|
as={FormLabel}
|
||||||
sm={2}
|
sm={2}
|
||||||
>{'User Name'}</Col>
|
>{'User Name'}</Col>
|
||||||
<Col sm={10}>
|
<Col sm={10}>
|
||||||
@@ -124,7 +122,7 @@ export default class LoginModal extends React.PureComponent<Props, State> {
|
|||||||
placeholder='User Name'
|
placeholder='User Name'
|
||||||
onChange={this.setUsername}
|
onChange={this.setUsername}
|
||||||
value={this.state.username}
|
value={this.state.username}
|
||||||
onClick={(e) => {
|
onClick={(e: React.MouseEvent<HTMLInputElement>) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -132,7 +130,7 @@ export default class LoginModal extends React.PureComponent<Props, State> {
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<Col
|
<Col
|
||||||
componentClass={ControlLabel}
|
as={FormLabel}
|
||||||
sm={2}
|
sm={2}
|
||||||
>{'Password'}</Col>
|
>{'Password'}</Col>
|
||||||
<Col sm={10}>
|
<Col sm={10}>
|
||||||
@@ -141,7 +139,7 @@ export default class LoginModal extends React.PureComponent<Props, State> {
|
|||||||
placeholder='Password'
|
placeholder='Password'
|
||||||
onChange={this.setPassword}
|
onChange={this.setPassword}
|
||||||
value={this.state.password}
|
value={this.state.password}
|
||||||
onClick={(e) => {
|
onClick={(e: React.MouseEvent<HTMLInputElement>) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -152,10 +150,13 @@ export default class LoginModal extends React.PureComponent<Props, State> {
|
|||||||
<div className='pull-right'>
|
<div className='pull-right'>
|
||||||
<Button
|
<Button
|
||||||
type='submit'
|
type='submit'
|
||||||
bsStyle='primary'
|
variant='primary'
|
||||||
>{'Login'}</Button>
|
>{'Login'}</Button>
|
||||||
{ ' ' }
|
{ ' ' }
|
||||||
<Button onClick={this.handleCancel}>{'Cancel'}</Button>
|
<Button
|
||||||
|
variant='link'
|
||||||
|
onClick={this.handleCancel}
|
||||||
|
>{'Cancel'}</Button>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
@@ -13,8 +13,8 @@ import {MODAL_INFO} from 'common/communication';
|
|||||||
import {PERMISSION_DESCRIPTION} from 'common/permissions';
|
import {PERMISSION_DESCRIPTION} from 'common/permissions';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
handleDeny: React.MouseEventHandler<Button>;
|
handleDeny: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
handleGrant: React.MouseEventHandler<Button>;
|
handleGrant: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
getPermissionInfo: () => void;
|
getPermissionInfo: () => void;
|
||||||
openExternalLink: (protocol: string, url: string) => void;
|
openExternalLink: (protocol: string, url: string) => void;
|
||||||
};
|
};
|
||||||
@@ -107,7 +107,7 @@ export default class PermissionModal extends React.PureComponent<Props, State> {
|
|||||||
onClick={this.props.handleDeny}
|
onClick={this.props.handleDeny}
|
||||||
>{'Cancel'}</Button>
|
>{'Cancel'}</Button>
|
||||||
<Button
|
<Button
|
||||||
bsStyle='primary'
|
variant='primary'
|
||||||
onClick={this.props.handleGrant}
|
onClick={this.props.handleGrant}
|
||||||
>{'Accept'}</Button>
|
>{'Accept'}</Button>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user