[MM-52696] Upgrade and clean up Desktop App dev dependencies (#2970)
* Upgrade to ESLint v8 * Upgrade TypeScript, api-types, react-intl * Remove unnecessary dependencies * Update to React 17.0.2 * npm audit fixes, remove storybook * Lock some packages * Remove nan patch * Remove some deprecated dependencies * Fix lint/type/tests * Merge'd * Fix bad use of spawn * Fix notarize * Fix afterpack, switch to tsc es2020 * Fix api types * Use @mattermost/eslint-plugin
This commit is contained in:
@@ -4,7 +4,8 @@
|
||||
|
||||
import React from 'react';
|
||||
import {Alert} from 'react-bootstrap';
|
||||
import {IntlShape, useIntl} from 'react-intl';
|
||||
import type {IntlShape} from 'react-intl';
|
||||
import {useIntl} from 'react-intl';
|
||||
|
||||
const baseClassName = 'AutoSaveIndicator';
|
||||
const leaveClassName = `${baseClassName}-Leave`;
|
||||
|
@@ -1,28 +0,0 @@
|
||||
// Copyright (c) 2015-2016 Yuya Ochiai
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {storiesOf} from '@storybook/react';
|
||||
|
||||
import {action} from '@storybook/addon-actions';
|
||||
import {Button, ButtonToolbar} from 'react-bootstrap';
|
||||
|
||||
storiesOf('Button', module).
|
||||
add('bsStyle', () => (
|
||||
<ButtonToolbar>
|
||||
<Button onClick={action('clicked default')}>{'Default'}</Button>
|
||||
<Button
|
||||
onClick={action('clicked primary')}
|
||||
variant='primary'
|
||||
>{'Primary'}</Button>
|
||||
<Button
|
||||
onClick={action('clicked danger')}
|
||||
variant='danger'
|
||||
>{'Danger'}</Button>
|
||||
<Button
|
||||
onClick={action('clicked link')}
|
||||
variant='link'
|
||||
>{'Link'}</Button>
|
||||
</ButtonToolbar>
|
||||
));
|
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useState, useEffect, useRef} from 'react';
|
||||
import classNames from 'classnames';
|
||||
import React, {useState, useEffect, useRef} from 'react';
|
||||
|
||||
import CarouselButton, {ButtonDirection} from './CarouselButton';
|
||||
import CarouselPaginationIndicator from './CarouselPaginationIndicator';
|
||||
|
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
|
||||
import 'renderer/css/components/Button.scss';
|
||||
import 'renderer/css/components/CarouselButton.scss';
|
||||
|
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useCallback} from 'react';
|
||||
import classNames from 'classnames';
|
||||
import React, {useCallback} from 'react';
|
||||
|
||||
import 'renderer/css/components/Button.scss';
|
||||
import 'renderer/css/components/CarouselPaginationIndicator.scss';
|
||||
|
@@ -1,21 +1,19 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import classNames from 'classnames';
|
||||
import React, {useState, useCallback, useEffect, useRef} from 'react';
|
||||
import {useIntl, FormattedMessage} from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import {UniqueServer} from 'types/config';
|
||||
|
||||
import {MODAL_TRANSITION_TIMEOUT, URLValidationStatus} from 'common/utils/constants';
|
||||
|
||||
import womanLaptop from 'renderer/assets/svg/womanLaptop.svg';
|
||||
|
||||
import Header from 'renderer/components/Header';
|
||||
import Input, {STATUS, SIZE} from 'renderer/components/Input';
|
||||
import LoadingBackground from 'renderer/components/LoadingScreen/LoadingBackground';
|
||||
import SaveButton from 'renderer/components/SaveButton/SaveButton';
|
||||
|
||||
import type {UniqueServer} from 'types/config';
|
||||
|
||||
import 'renderer/css/components/Button.scss';
|
||||
import 'renderer/css/components/ConfigureServer.scss';
|
||||
import 'renderer/css/components/LoadingScreen.css';
|
||||
|
@@ -2,7 +2,8 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {DownloadedItem} from 'types/downloads';
|
||||
|
||||
import type {DownloadedItem} from 'types/downloads';
|
||||
|
||||
import DownloadsDropdownItemFile from './DownloadsDropdownItemFile';
|
||||
import UpdateWrapper from './Update/UpdateWrapper';
|
||||
|
@@ -1,12 +1,12 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useState} from 'react';
|
||||
import {DownloadedItem} from 'types/downloads';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import React, {useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
|
||||
import type {DownloadedItem} from 'types/downloads';
|
||||
|
||||
import FileSizeAndStatus from './FileSizeAndStatus';
|
||||
import ProgressBar from './ProgressBar';
|
||||
import ThreeDotButton from './ThreeDotButton';
|
||||
|
@@ -4,10 +4,10 @@
|
||||
import React, {useCallback} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
|
||||
import {DownloadedItem} from 'types/downloads';
|
||||
|
||||
import {getDownloadingFileStatus, getFileSizeOrBytesProgress, prettyETA} from 'renderer/utils';
|
||||
|
||||
import type {DownloadedItem} from 'types/downloads';
|
||||
|
||||
type OwnProps = {
|
||||
item: DownloadedItem;
|
||||
}
|
||||
|
@@ -2,7 +2,8 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {DownloadedItem} from 'types/downloads';
|
||||
|
||||
import type {DownloadedItem} from 'types/downloads';
|
||||
|
||||
type OwnProps = {
|
||||
item: DownloadedItem;
|
||||
|
@@ -1,10 +1,10 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useRef} from 'react';
|
||||
import {DownloadedItem} from 'types/downloads';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import React, {useRef} from 'react';
|
||||
|
||||
import type {DownloadedItem} from 'types/downloads';
|
||||
|
||||
type OwnProps = {
|
||||
activeItem?: DownloadedItem;
|
||||
|
@@ -2,12 +2,13 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {DownloadedItem} from 'types/downloads';
|
||||
|
||||
import {CheckCircleIcon, CloseCircleIcon} from '@mattermost/compass-icons/components';
|
||||
|
||||
import {getIconClassName, isImageFile} from 'renderer/utils';
|
||||
|
||||
import type {DownloadedItem} from 'types/downloads';
|
||||
|
||||
type OwnProps = {
|
||||
item: DownloadedItem;
|
||||
}
|
||||
|
@@ -2,11 +2,10 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {DownloadedItem} from 'types/downloads';
|
||||
|
||||
import {Button} from 'react-bootstrap';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import {Button} from 'react-bootstrap';
|
||||
import type {DownloadedItem} from 'types/downloads';
|
||||
|
||||
import Thumbnail from '../Thumbnail';
|
||||
|
||||
|
@@ -1,17 +1,15 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
import {DownloadedItem} from 'types/downloads';
|
||||
|
||||
import {Button} from 'react-bootstrap';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
|
||||
import {Button} from 'react-bootstrap';
|
||||
import type {DownloadedItem} from 'types/downloads';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import Thumbnail from '../Thumbnail';
|
||||
import FileSizeAndStatus from '../FileSizeAndStatus';
|
||||
import Thumbnail from '../Thumbnail';
|
||||
|
||||
type OwnProps = {
|
||||
item: DownloadedItem;
|
||||
|
@@ -2,7 +2,8 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {DownloadedItem} from 'types/downloads';
|
||||
|
||||
import type {DownloadedItem} from 'types/downloads';
|
||||
|
||||
import UpdateAvailable from './UpdateAvailable';
|
||||
import UpdateDownloaded from './UpdateDownloaded';
|
||||
|
@@ -16,7 +16,7 @@ export default class ExtraBar extends React.PureComponent<Props> {
|
||||
if (this.props.goBack) {
|
||||
this.props.goBack();
|
||||
}
|
||||
}
|
||||
};
|
||||
render() {
|
||||
let barClass = 'clear-mode';
|
||||
if (!this.props.show) {
|
||||
|
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
|
||||
import Logo from 'renderer/components/Logo';
|
||||
|
||||
|
@@ -1,11 +1,10 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import classNames from 'classnames';
|
||||
import React, {useState, useEffect} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import 'renderer/css/components/Input.scss';
|
||||
|
||||
export enum STATUS {
|
||||
|
@@ -1,13 +1,13 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import useAnimationEnd from '../../hooks/useAnimationEnd';
|
||||
import React from 'react';
|
||||
|
||||
import LoadingIcon from './LoadingIcon';
|
||||
|
||||
import useAnimationEnd from '../../hooks/useAnimationEnd';
|
||||
|
||||
const LOADING_STATE = {
|
||||
INITIALIZING: 'initializing', // animation graphics are hidden
|
||||
LOADING: 'loading', // animation graphics fade in and animate
|
||||
|
@@ -1,15 +1,14 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import useTransitionEnd from '../../hooks/useTransitionEnd';
|
||||
|
||||
import LoadingAnimation from '../LoadingAnimation';
|
||||
import React from 'react';
|
||||
|
||||
import LoadingBackground from './LoadingBackground';
|
||||
|
||||
import useTransitionEnd from '../../hooks/useTransitionEnd';
|
||||
import LoadingAnimation from '../LoadingAnimation';
|
||||
|
||||
type Props = {
|
||||
loading?: boolean;
|
||||
darkMode?: boolean;
|
||||
|
@@ -6,26 +6,26 @@
|
||||
|
||||
import classNames from 'classnames';
|
||||
import React, {Fragment} from 'react';
|
||||
import type {DropResult} from 'react-beautiful-dnd';
|
||||
import {Container, Row} from 'react-bootstrap';
|
||||
import {DropResult} from 'react-beautiful-dnd';
|
||||
import {injectIntl, IntlShape} from 'react-intl';
|
||||
import type {IntlShape} from 'react-intl';
|
||||
import {injectIntl} from 'react-intl';
|
||||
|
||||
import {UniqueView, UniqueServer} from 'types/config';
|
||||
import {DownloadedItems} from 'types/downloads';
|
||||
import type {UniqueView, UniqueServer} from 'types/config';
|
||||
import type {DownloadedItems} from 'types/downloads';
|
||||
|
||||
import restoreButton from '../../assets/titlebar/chrome-restore.svg';
|
||||
import DownloadsDropdownButton from './DownloadsDropdown/DownloadsDropdownButton';
|
||||
import ErrorView from './ErrorView';
|
||||
import ExtraBar from './ExtraBar';
|
||||
import ServerDropdownButton from './ServerDropdownButton';
|
||||
import TabBar from './TabBar';
|
||||
|
||||
import closeButton from '../../assets/titlebar/chrome-close.svg';
|
||||
import maximizeButton from '../../assets/titlebar/chrome-maximize.svg';
|
||||
import minimizeButton from '../../assets/titlebar/chrome-minimize.svg';
|
||||
import closeButton from '../../assets/titlebar/chrome-close.svg';
|
||||
|
||||
import restoreButton from '../../assets/titlebar/chrome-restore.svg';
|
||||
import {playSound} from '../notificationSounds';
|
||||
|
||||
import TabBar from './TabBar';
|
||||
import ExtraBar from './ExtraBar';
|
||||
import ErrorView from './ErrorView';
|
||||
import ServerDropdownButton from './ServerDropdownButton';
|
||||
import DownloadsDropdownButton from './DownloadsDropdown/DownloadsDropdownButton';
|
||||
|
||||
import '../css/components/UpgradeButton.scss';
|
||||
|
||||
enum Status {
|
||||
@@ -141,19 +141,19 @@ class MainPage extends React.PureComponent<Props, State> {
|
||||
});
|
||||
this.setState({servers, tabs, tabViewStatus});
|
||||
return Boolean(servers.length);
|
||||
}
|
||||
};
|
||||
|
||||
setInitialActiveTab = async () => {
|
||||
const lastActive = await window.desktop.getLastActive();
|
||||
this.setActiveView(lastActive.server, lastActive.view);
|
||||
}
|
||||
};
|
||||
|
||||
updateServers = async () => {
|
||||
const hasServers = await this.getServersAndTabs();
|
||||
if (hasServers && !(this.state.activeServerId && this.state.activeTabId)) {
|
||||
await this.setInitialActiveTab();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
async componentDidMount() {
|
||||
// request downloads
|
||||
@@ -281,28 +281,28 @@ class MainPage extends React.PureComponent<Props, State> {
|
||||
return;
|
||||
}
|
||||
this.setState({activeServerId: serverId, activeTabId: tabId});
|
||||
}
|
||||
};
|
||||
|
||||
handleCloseDropdowns = () => {
|
||||
window.desktop.closeServersDropdown();
|
||||
this.closeDownloadsDropdown();
|
||||
}
|
||||
};
|
||||
|
||||
handleMaximizeState = (maximized: boolean) => {
|
||||
this.setState({maximized});
|
||||
}
|
||||
};
|
||||
|
||||
handleFullScreenState = (isFullScreen: boolean) => {
|
||||
this.setState({fullScreen: isFullScreen});
|
||||
}
|
||||
};
|
||||
|
||||
handleSelectTab = (tabId: string) => {
|
||||
window.desktop.switchTab(tabId);
|
||||
}
|
||||
};
|
||||
|
||||
handleCloseTab = (tabId: string) => {
|
||||
window.desktop.closeView(tabId);
|
||||
}
|
||||
};
|
||||
|
||||
handleDragAndDrop = async (dropResult: DropResult) => {
|
||||
const removedIndex = dropResult.source.index;
|
||||
@@ -326,43 +326,43 @@ class MainPage extends React.PureComponent<Props, State> {
|
||||
tabs.set(this.state.activeServerId, tabsCopy);
|
||||
this.setState({tabs});
|
||||
this.handleSelectTab(tab[0].id!);
|
||||
}
|
||||
};
|
||||
|
||||
handleClose = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
e.stopPropagation(); // since it is our button, the event goes into MainPage's onclick event, getting focus back.
|
||||
window.desktop.closeWindow();
|
||||
}
|
||||
};
|
||||
|
||||
handleMinimize = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
e.stopPropagation();
|
||||
window.desktop.minimizeWindow();
|
||||
}
|
||||
};
|
||||
|
||||
handleMaximize = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
e.stopPropagation();
|
||||
window.desktop.maximizeWindow();
|
||||
}
|
||||
};
|
||||
|
||||
handleRestore = () => {
|
||||
window.desktop.restoreWindow();
|
||||
}
|
||||
};
|
||||
|
||||
openMenu = () => {
|
||||
this.props.openMenu();
|
||||
}
|
||||
};
|
||||
|
||||
handleDoubleClick = () => {
|
||||
window.desktop.doubleClickOnWindow();
|
||||
}
|
||||
};
|
||||
|
||||
focusOnWebView = () => {
|
||||
window.desktop.focusCurrentView();
|
||||
this.handleCloseDropdowns();
|
||||
}
|
||||
};
|
||||
|
||||
reloadCurrentView = () => {
|
||||
window.desktop.reloadCurrentView();
|
||||
}
|
||||
};
|
||||
|
||||
showHideDownloadsBadge(value = false) {
|
||||
this.setState({showDownloadsBadge: value});
|
||||
@@ -382,14 +382,14 @@ class MainPage extends React.PureComponent<Props, State> {
|
||||
this.setState({
|
||||
threeDotsIsFocused: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
unFocusThreeDotsButton = () => {
|
||||
this.threeDotMenu.current?.blur();
|
||||
this.setState({
|
||||
threeDotsIsFocused: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {intl} = this.props;
|
||||
|
@@ -4,13 +4,14 @@
|
||||
|
||||
import React from 'react';
|
||||
import {Modal, Button, FormGroup, FormControl, FormLabel, FormText, Spinner} from 'react-bootstrap';
|
||||
import {FormattedMessage, injectIntl, IntlShape} from 'react-intl';
|
||||
|
||||
import {UniqueServer} from 'types/config';
|
||||
import {URLValidationResult} from 'types/server';
|
||||
import type {IntlShape} from 'react-intl';
|
||||
import {FormattedMessage, injectIntl} from 'react-intl';
|
||||
|
||||
import {URLValidationStatus} from 'common/utils/constants';
|
||||
|
||||
import type {UniqueServer} from 'types/config';
|
||||
import type {URLValidationResult} from 'types/server';
|
||||
|
||||
import 'renderer/css/components/NewServerModal.scss';
|
||||
|
||||
type Props = {
|
||||
@@ -80,19 +81,19 @@ class NewServerModal extends React.PureComponent<Props, State> {
|
||||
if (this.props.editMode && this.props.server) {
|
||||
this.validateServerURL(this.props.server.url);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleServerNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({
|
||||
serverName: e.target.value,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleServerUrlChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const serverUrl = e.target.value;
|
||||
this.setState({serverUrl, validationResult: undefined});
|
||||
this.validateServerURL(serverUrl);
|
||||
}
|
||||
};
|
||||
|
||||
validateServerURL = (serverUrl: string) => {
|
||||
clearTimeout(this.validationTimeout as unknown as number);
|
||||
@@ -112,12 +113,12 @@ class NewServerModal extends React.PureComponent<Props, State> {
|
||||
this.setState({validationResult, validationStarted: false, serverUrl: validationResult.validatedURL ?? serverUrl, serverName: this.state.serverName ? this.state.serverName : validationResult.serverName ?? ''});
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
isServerURLErrored = () => {
|
||||
return this.state.validationResult?.status === URLValidationStatus.Invalid ||
|
||||
this.state.validationResult?.status === URLValidationStatus.Missing;
|
||||
}
|
||||
};
|
||||
|
||||
getServerURLMessage = () => {
|
||||
if (this.state.validationStarted) {
|
||||
@@ -250,7 +251,7 @@ class NewServerModal extends React.PureComponent<Props, State> {
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
getServerNameMessage = () => {
|
||||
if (!this.state.serverName.length) {
|
||||
@@ -268,7 +269,7 @@ class NewServerModal extends React.PureComponent<Props, State> {
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
save = () => {
|
||||
if (!this.state.validationResult) {
|
||||
@@ -288,7 +289,7 @@ class NewServerModal extends React.PureComponent<Props, State> {
|
||||
id: this.state.serverId,
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
getSaveButtonLabel() {
|
||||
if (this.props.editMode) {
|
||||
|
@@ -12,7 +12,7 @@ type Props = {
|
||||
export default class LoadingSpinner extends React.PureComponent<Props> {
|
||||
public static defaultProps: Props = {
|
||||
text: null,
|
||||
}
|
||||
};
|
||||
|
||||
public render() {
|
||||
return (
|
||||
|
@@ -16,7 +16,7 @@ export default class LoadingWrapper extends React.PureComponent<Props> {
|
||||
loading: true,
|
||||
text: null,
|
||||
children: null,
|
||||
}
|
||||
};
|
||||
|
||||
public render() {
|
||||
const {text, loading, children} = this.props;
|
||||
|
@@ -1,9 +1,9 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import LoadingWrapper from './LoadingWrapper';
|
||||
|
||||
|
@@ -8,15 +8,17 @@ import 'renderer/css/settings.css';
|
||||
|
||||
import React from 'react';
|
||||
import {FormCheck, Col, FormGroup, FormText, Container, Row, Button, FormControl} from 'react-bootstrap';
|
||||
import {FormattedMessage, injectIntl, IntlShape} from 'react-intl';
|
||||
import ReactSelect, {ActionMeta, MultiValue} from 'react-select';
|
||||
|
||||
import {CombinedConfig, LocalConfiguration} from 'types/config';
|
||||
import {SaveQueueItem} from 'types/settings';
|
||||
import {DeepPartial} from 'types/utils';
|
||||
import type {IntlShape} from 'react-intl';
|
||||
import {FormattedMessage, injectIntl} from 'react-intl';
|
||||
import type {ActionMeta, MultiValue} from 'react-select';
|
||||
import ReactSelect from 'react-select';
|
||||
|
||||
import {localeTranslations} from 'common/utils/constants';
|
||||
|
||||
import type {CombinedConfig, LocalConfiguration} from 'types/config';
|
||||
import type {SaveQueueItem} from 'types/settings';
|
||||
import type {DeepPartial} from 'types/utils';
|
||||
|
||||
import AutoSaveIndicator, {SavingState} from './AutoSaveIndicator';
|
||||
|
||||
const CONFIG_TYPE_UPDATES = 'updates';
|
||||
@@ -129,7 +131,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
window.desktop.getLocalConfiguration().then((config) => {
|
||||
this.setState({ready: true, maximized: false, ...this.convertConfigDataToState(config as Partial<LocalConfiguration>, this.state) as Omit<State, 'ready'>});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
convertConfigDataToState = (configData: Partial<LocalConfiguration>, currentState: Partial<State> = {}) => {
|
||||
const newState = Object.assign({} as State, configData);
|
||||
@@ -139,7 +141,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
};
|
||||
this.selectedSpellCheckerLocales = configData.spellCheckerLocales?.map((language: string) => ({label: localeTranslations[language] || language, value: language})) || [];
|
||||
return newState;
|
||||
}
|
||||
};
|
||||
|
||||
saveSetting = (configType: 'updates' | 'appOptions', {key, data}: {key: keyof CombinedConfig; data: CombinedConfig[keyof CombinedConfig]}) => {
|
||||
this.saveQueue.push({
|
||||
@@ -149,7 +151,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
});
|
||||
this.updateSaveState();
|
||||
this.processSaveQueue();
|
||||
}
|
||||
};
|
||||
|
||||
processSaveQueue = () => {
|
||||
if (this.savingIsDebounced) {
|
||||
@@ -161,7 +163,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
this.savingIsDebounced = false;
|
||||
window.desktop.updateConfiguration(this.saveQueue.splice(0, this.saveQueue.length));
|
||||
}, 500);
|
||||
}
|
||||
};
|
||||
|
||||
updateSaveState = () => {
|
||||
let queuedUpdateCounts = {
|
||||
@@ -186,7 +188,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
});
|
||||
|
||||
this.setState({savingState});
|
||||
}
|
||||
};
|
||||
|
||||
resetSaveState = (configType: keyof SavingStateItems) => {
|
||||
if (this.resetSaveStateIsDebounced) {
|
||||
@@ -201,7 +203,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
this.setState({savingState});
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
};
|
||||
|
||||
handleChangeShowTrayIcon = () => {
|
||||
const shouldShowTrayIcon = this.showTrayIconRef.current?.checked;
|
||||
@@ -215,28 +217,28 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
minimizeToTray: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleChangeTrayIconTheme = (theme: string) => {
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'trayIconTheme', data: theme});
|
||||
this.setState({
|
||||
trayIconTheme: theme,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleChangeAutoStart = () => {
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'autostart', data: this.autostartRef.current?.checked});
|
||||
this.setState({
|
||||
autostart: this.autostartRef.current?.checked,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleChangeHideOnStart = () => {
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'hideOnStart', data: this.hideOnStartRef.current?.checked});
|
||||
this.setState({
|
||||
hideOnStart: this.hideOnStartRef.current?.checked,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleChangeMinimizeToTray = () => {
|
||||
const shouldMinimizeToTray = (process.platform === 'win32' || this.state.showTrayIcon) && this.minimizeToTrayRef.current?.checked;
|
||||
@@ -245,7 +247,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
this.setState({
|
||||
minimizeToTray: shouldMinimizeToTray,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleFlashWindow = () => {
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {
|
||||
@@ -253,7 +255,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
data: {
|
||||
...this.state.notifications,
|
||||
flashWindow: this.flashWindowRef.current?.checked ? 2 : 0,
|
||||
},
|
||||
} as CombinedConfig['notifications'],
|
||||
});
|
||||
this.setState({
|
||||
notifications: {
|
||||
@@ -261,7 +263,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
flashWindow: this.flashWindowRef.current?.checked ? 2 : 0,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleBounceIcon = () => {
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {
|
||||
@@ -269,7 +271,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
data: {
|
||||
...this.state.notifications,
|
||||
bounceIcon: this.bounceIconRef.current?.checked,
|
||||
},
|
||||
} as CombinedConfig['notifications'],
|
||||
});
|
||||
this.setState({
|
||||
notifications: {
|
||||
@@ -277,7 +279,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
bounceIcon: this.bounceIconRef.current?.checked,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleBounceIconType = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {
|
||||
@@ -285,7 +287,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
data: {
|
||||
...this.state.notifications,
|
||||
bounceIconType: event.target.value,
|
||||
},
|
||||
} as CombinedConfig['notifications'],
|
||||
});
|
||||
this.setState({
|
||||
notifications: {
|
||||
@@ -293,35 +295,35 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
bounceIconType: event.target.value as 'critical' | 'informational',
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleShowUnreadBadge = () => {
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'showUnreadBadge', data: this.showUnreadBadgeRef.current?.checked});
|
||||
this.setState({
|
||||
showUnreadBadge: this.showUnreadBadgeRef.current?.checked,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleChangeUseSpellChecker = () => {
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'useSpellChecker', data: this.useSpellCheckerRef.current?.checked});
|
||||
this.setState({
|
||||
useSpellChecker: this.useSpellCheckerRef.current?.checked,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleChangeLogLevel = () => {
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'logLevel', data: this.logLevelRef.current?.value});
|
||||
this.setState({
|
||||
logLevel: this.logLevelRef.current?.value,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleChangeAppLanguage = () => {
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'appLanguage', data: this.appLanguageRef.current?.value});
|
||||
this.setState({
|
||||
appLanguage: this.appLanguageRef.current?.value,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleChangeAutoCheckForUpdates = () => {
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_UPDATES, {key: 'autoCheckForUpdates', data: this.autoCheckForUpdatesRef.current?.checked});
|
||||
@@ -332,11 +334,11 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
this.checkForUpdates();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
checkForUpdates = () => {
|
||||
window.desktop.checkForUpdates();
|
||||
}
|
||||
};
|
||||
|
||||
handleChangeSpellCheckerLocales = (value: MultiValue<{label: string; value: string}>, actionMeta: ActionMeta<{label: string; value: string}>) => {
|
||||
switch (actionMeta.action) {
|
||||
@@ -352,21 +354,21 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
this.setState({
|
||||
spellCheckerLocales: values,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleChangeEnableHardwareAcceleration = () => {
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'enableHardwareAcceleration', data: this.enableHardwareAccelerationRef.current?.checked});
|
||||
this.setState({
|
||||
enableHardwareAcceleration: this.enableHardwareAccelerationRef.current?.checked,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleChangeStartInFullscreen = () => {
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'startInFullscreen', data: this.startInFullscreenRef.current?.checked});
|
||||
this.setState({
|
||||
startInFullscreen: this.startInFullscreenRef.current?.checked,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
saveDownloadLocation = (location: string) => {
|
||||
if (!location) {
|
||||
@@ -376,11 +378,11 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
downloadLocation: location,
|
||||
});
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'downloadLocation', data: location});
|
||||
}
|
||||
};
|
||||
|
||||
handleChangeDownloadLocation = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
this.saveDownloadLocation(e.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
selectDownloadLocation = () => {
|
||||
if (!this.state.userOpenedDownloadDialog) {
|
||||
@@ -388,18 +390,18 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
this.setState({userOpenedDownloadDialog: true});
|
||||
}
|
||||
this.setState({userOpenedDownloadDialog: false});
|
||||
}
|
||||
};
|
||||
|
||||
saveSpellCheckerURL = (): void => {
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'spellCheckerURL', data: this.state.spellCheckerURL});
|
||||
}
|
||||
};
|
||||
|
||||
resetSpellCheckerURL = (): void => {
|
||||
this.setState({spellCheckerURL: undefined, allowSaveSpellCheckerURL: false});
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'spellCheckerURL', data: null});
|
||||
}
|
||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'spellCheckerURL', data: undefined});
|
||||
};
|
||||
|
||||
handleChangeSpellCheckerURL= (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
handleChangeSpellCheckerURL = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
const dictionaryURL = e.target.value;
|
||||
let allowSaveSpellCheckerURL;
|
||||
try {
|
||||
@@ -413,11 +415,11 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||
spellCheckerURL: dictionaryURL,
|
||||
allowSaveSpellCheckerURL,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleDoubleClick = () => {
|
||||
window.desktop.doubleClickOnWindow('settings');
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {intl} = this.props;
|
||||
|
@@ -2,15 +2,18 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {Nav, NavItem, NavLink} from 'react-bootstrap';
|
||||
import {DragDropContext, Draggable, DraggingStyle, Droppable, DropResult, NotDraggingStyle} from 'react-beautiful-dnd';
|
||||
import {FormattedMessage, injectIntl, IntlShape} from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
import type {DraggingStyle, DropResult, NotDraggingStyle} from 'react-beautiful-dnd';
|
||||
import {DragDropContext, Draggable, Droppable} from 'react-beautiful-dnd';
|
||||
import {Nav, NavItem, NavLink} from 'react-bootstrap';
|
||||
import type {IntlShape} from 'react-intl';
|
||||
import {FormattedMessage, injectIntl} from 'react-intl';
|
||||
|
||||
import {UniqueView} from 'types/config';
|
||||
import type {ViewType} from 'common/views/View';
|
||||
import {canCloseView, getViewDisplayName} from 'common/views/View';
|
||||
|
||||
import {ViewType, canCloseView, getViewDisplayName} from 'common/views/View';
|
||||
import type {UniqueView} from 'types/config';
|
||||
|
||||
type Props = {
|
||||
activeTabId?: string;
|
||||
@@ -46,7 +49,7 @@ class TabBar extends React.PureComponent<Props> {
|
||||
event.stopPropagation();
|
||||
this.props.onCloseTab(id);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const tabs = this.props.tabs.map((tab, index) => {
|
||||
|
@@ -1,21 +1,19 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import classNames from 'classnames';
|
||||
import React, {useState, useEffect, useMemo} from 'react';
|
||||
import {useIntl, FormattedMessage} from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import {MODAL_TRANSITION_TIMEOUT} from 'common/utils/constants';
|
||||
import bullseye from 'renderer/assets/svg/bullseye.svg';
|
||||
import channels from 'renderer/assets/svg/channels.svg';
|
||||
import chat2 from 'renderer/assets/svg/chat2.svg';
|
||||
import clipboard from 'renderer/assets/svg/clipboard.svg';
|
||||
|
||||
import Carousel from 'renderer/components/Carousel';
|
||||
import Header from 'renderer/components/Header';
|
||||
import LoadingBackground from 'renderer/components/LoadingScreen/LoadingBackground';
|
||||
|
||||
import {MODAL_TRANSITION_TIMEOUT} from 'common/utils/constants';
|
||||
|
||||
import WelcomeScreenSlide from './WelcomeScreenSlide';
|
||||
|
||||
import 'renderer/css/components/Button.scss';
|
||||
|
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
|
||||
import 'renderer/css/components/WelcomeScreenSlide.scss';
|
||||
|
||||
|
@@ -1,10 +1,10 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type {Certificate} from 'electron/renderer';
|
||||
import React, {Fragment} from 'react';
|
||||
import {Modal, Button, Row, Col} from 'react-bootstrap';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {Certificate} from 'electron/renderer';
|
||||
|
||||
type Props = {
|
||||
certificate: Certificate;
|
||||
@@ -26,7 +26,7 @@ export default class ShowCertificateModal extends React.PureComponent<Props, Sta
|
||||
handleOk = () => {
|
||||
this.setState({certificate: undefined});
|
||||
this.props.onOk();
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const certificateSection = (descriptor: React.ReactNode) => {
|
||||
|
Reference in New Issue
Block a user