Sync Packages with Radarr

This commit is contained in:
Qstick 2020-06-27 17:51:59 -04:00
commit 0a32b7eaf7
66 changed files with 2278 additions and 1939 deletions

View file

@ -268,7 +268,7 @@
"react/jsx-curly-spacing": [2, "never"],
"react/jsx-equals-spacing": [2, "never"],
"react/jsx-indent-props": [2, 2],
"react/jsx-indent": [2, 2],
"react/jsx-indent": [2, 2, { "indentLogicalExpressions": true }],
"react/jsx-key": 2,
"react/jsx-no-bind": [2, { "allowArrowFunctions": true }],
"react/jsx-no-duplicate-props": [2, { "ignoreCase": true }],

View file

@ -10,8 +10,7 @@ gulp.task('build',
'webpack',
'copyHtml',
'copyFonts',
'copyImages',
'copyJs'
'copyImages'
)
)
);

View file

@ -5,17 +5,6 @@ const cache = require('gulp-cached');
const livereload = require('gulp-livereload');
const paths = require('./helpers/paths.js');
gulp.task('copyJs', () => {
return gulp.src(
[
path.join(paths.src.root, 'polyfills.js')
], { base: paths.src.root })
.pipe(cache('copyJs'))
.pipe(print())
.pipe(gulp.dest(paths.dest.root))
.pipe(livereload());
});
gulp.task('copyHtml', () => {
return gulp.src(paths.src.html, { base: paths.src.root })
.pipe(cache('copyHtml'))

View file

@ -14,6 +14,7 @@ const frontendFolder = path.join(__dirname, '..');
const srcFolder = path.join(frontendFolder, 'src');
const isProduction = process.argv.indexOf('--production') > -1;
const isProfiling = isProduction && process.argv.indexOf('--profile') > -1;
const inlineWebWorkers = true;
const distFolder = path.resolve(frontendFolder, '..', '_output', uiFolder);
@ -124,7 +125,9 @@ const config = {
use: {
loader: 'worker-loader',
options: {
name: '[name].js'
name: '[name].js',
inline: inlineWebWorkers,
fallback: !inlineWebWorkers
}
}
},

View file

@ -99,16 +99,16 @@ class RemoveQueueItemsModal extends Component {
{
blacklist &&
<FormGroup>
<FormLabel>Skip Redownload</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="skipredownload"
value={skipredownload}
helpText="Prevents Lidarr from trying download alternative releases for the removed items"
onChange={this.onSkipReDownloadChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>Skip Redownload</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="skipredownload"
value={skipredownload}
helpText="Prevents Lidarr from trying download alternative releases for the removed items"
onChange={this.onSkipReDownloadChange}
/>
</FormGroup>
}
</ModalBody>

View file

@ -71,10 +71,10 @@ class TrackActionsCell extends Component {
}
{
trackFilePath &&
<IconButton
name={icons.DELETE}
onPress={this.onDeleteFilePress}
/>
<IconButton
name={icons.DELETE}
onPress={this.onDeleteFilePress}
/>
}
<FileDetailsModal

View file

@ -108,7 +108,7 @@ class ArtistIndexBannerOptionsModalContent extends Component {
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
Options
Options
</ModalHeader>
<ModalBody>

View file

@ -127,10 +127,10 @@ class ArtistIndexOverview extends Component {
<div className={styles.posterContainer}>
{
status === 'ended' &&
<div
className={styles.ended}
title="Ended"
/>
<div
className={styles.ended}
title="Ended"
/>
}
<Link

View file

@ -183,19 +183,19 @@ function ArtistIndexOverviewInfo(props) {
<div className={styles.infos}>
{
!!nextAiring &&
<ArtistIndexOverviewInfoRow
title={formatDateTime(nextAiring, longDateFormat, timeFormat)}
iconName={icons.SCHEDULED}
label={getRelativeDate(
nextAiring,
shortDateFormat,
showRelativeDates,
{
timeFormat,
timeForToday: true
}
)}
/>
<ArtistIndexOverviewInfoRow
title={formatDateTime(nextAiring, longDateFormat, timeFormat)}
iconName={icons.SCHEDULED}
label={getRelativeDate(
nextAiring,
shortDateFormat,
showRelativeDates,
{
timeFormat,
timeForToday: true
}
)}
/>
}
{

View file

@ -11,7 +11,7 @@ function NoArtist(props) {
return (
<div>
<div className={styles.message}>
All artists are hidden due to the applied filter.
All artists are hidden due to the applied filter.
</div>
</div>
);

View file

@ -135,9 +135,9 @@ class CalendarPage extends Component {
>
{
artistError &&
<div className={styles.errorMessage}>
{getErrorMessage(artistError, 'Failed to load artist from API')}
</div>
<div className={styles.errorMessage}>
{getErrorMessage(artistError, 'Failed to load artist from API')}
</div>
}
{

View file

@ -94,11 +94,11 @@ class CalendarEvent extends Component {
{
!queueItem && grabbed &&
<Icon
className={styles.statusIcon}
name={icons.DOWNLOADING}
title="Album is downloading"
/>
<Icon
className={styles.statusIcon}
name={icons.DOWNLOADING}
title="Album is downloading"
/>
}
</div>

View file

@ -24,7 +24,7 @@ function CustomFiltersModalContent(props) {
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
Custom Filters
Custom Filters
</ModalHeader>
<ModalBody>
@ -58,7 +58,7 @@ function CustomFiltersModalContent(props) {
<Button
onPress={onModalClose}
>
Close
Close
</Button>
</ModalFooter>
</ModalContent>

View file

@ -59,7 +59,7 @@ class RootFolderSelectInputConnector extends Component {
//
// Lifecycle
componentWillMount() {
UNSAFE_componentWillMount() {
const {
value,
values,

View file

@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import styles from './LoadingIndicator.css';
function LoadingIndicator({ className, size }) {
function LoadingIndicator({ className, rippleClassName, size }) {
const sizeInPx = `${size}px`;
const width = sizeInPx;
const height = sizeInPx;
@ -17,17 +17,17 @@ function LoadingIndicator({ className, size }) {
style={{ width, height }}
>
<div
className={styles.ripple}
className={rippleClassName}
style={{ width, height }}
/>
<div
className={styles.ripple}
className={rippleClassName}
style={{ width, height }}
/>
<div
className={styles.ripple}
className={rippleClassName}
style={{ width, height }}
/>
</div>
@ -37,11 +37,13 @@ function LoadingIndicator({ className, size }) {
LoadingIndicator.propTypes = {
className: PropTypes.string,
rippleClassName: PropTypes.string,
size: PropTypes.number
};
LoadingIndicator.defaultProps = {
className: styles.loading,
rippleClassName: styles.ripple,
size: 50
};

View file

@ -61,7 +61,7 @@ class FilterMenuContent extends Component {
{
showCustomFilters &&
<MenuItem onPress={onCustomFiltersPress}>
Custom Filters
Custom Filters
</MenuItem>
}
</MenuContent>

View file

@ -1,6 +1,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import React, { useEffect } from 'react';
import { kinds, sizes } from 'Helpers/Props';
import keyboardShortcuts from 'Components/keyboardShortcuts';
import Button from 'Components/Link/Button';
import SpinnerButton from 'Components/Link/SpinnerButton';
import Modal from 'Components/Modal/Modal';
@ -21,9 +22,19 @@ function ConfirmModal(props) {
hideCancelButton,
isSpinning,
onConfirm,
onCancel
onCancel,
bindShortcut,
unbindShortcut
} = props;
useEffect(() => {
if (isOpen) {
bindShortcut('enter', onConfirm);
} else {
unbindShortcut('enter', onConfirm);
}
}, [onConfirm]);
return (
<Modal
isOpen={isOpen}
@ -49,7 +60,7 @@ function ConfirmModal(props) {
}
<SpinnerButton
data-autofocus={true}
autoFocus={true}
kind={kind}
isSpinning={isSpinning}
onPress={onConfirm}
@ -74,7 +85,9 @@ ConfirmModal.propTypes = {
hideCancelButton: PropTypes.bool,
isSpinning: PropTypes.bool.isRequired,
onConfirm: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired
onCancel: PropTypes.func.isRequired,
bindShortcut: PropTypes.func.isRequired,
unbindShortcut: PropTypes.func.isRequired
};
ConfirmModal.defaultProps = {
@ -85,4 +98,4 @@ ConfirmModal.defaultProps = {
isSpinning: false
};
export default ConfirmModal;
export default keyboardShortcuts(ConfirmModal);

View file

@ -1,6 +1,7 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import FocusLock from 'react-focus-lock';
import classNames from 'classnames';
import elementClass from 'element-class';
import getUniqueElememtId from 'Utilities/getUniqueElementId';
@ -181,31 +182,33 @@ class Modal extends Component {
}
return ReactDOM.createPortal(
<div
className={styles.modalContainer}
>
<FocusLock disabled={false}>
<div
ref={this._setBackgroundRef}
className={backdropClassName}
onMouseDown={this.onBackdropBeginPress}
onMouseUp={this.onBackdropEndPress}
className={styles.modalContainer}
>
<div
className={classNames(
className,
styles[size]
)}
style={style}
ref={this._setBackgroundRef}
className={backdropClassName}
onMouseDown={this.onBackdropBeginPress}
onMouseUp={this.onBackdropEndPress}
>
<ErrorBoundary
errorComponent={ModalError}
onModalClose={onModalClose}
<div
className={classNames(
className,
styles[size]
)}
style={style}
>
{children}
</ErrorBoundary>
<ErrorBoundary
errorComponent={ModalError}
onModalClose={onModalClose}
>
{children}
</ErrorBoundary>
</div>
</div>
</div>
</div>,
</FocusLock>,
this._node
);
}

View file

@ -3,6 +3,18 @@
align-items: center;
}
.loading {
margin-top: 18px;
margin-bottom: 18px;
text-align: center;
}
.ripple {
composes: ripple from '~Components/Loading/LoadingIndicator.css';
border: 2px solid $toolbarColor;
}
.input {
margin-left: 8px;
width: 200px;

View file

@ -74,7 +74,11 @@ class ArtistSearchInput extends Component {
if (item.type === LOADING_TYPE) {
return (
<LoadingIndicator />
<LoadingIndicator
className={styles.loading}
rippleClassName={styles.ripple}
size={30}
/>
);
}
@ -124,7 +128,7 @@ class ArtistSearchInput extends Component {
highlightedSuggestionIndex
} = this._autosuggest.state;
if (!suggestions.length || suggestions[0].type === LOADING_TYPE || highlightedSectionIndex) {
if (!suggestions.length || highlightedSectionIndex) {
this.props.onGoToAddNewArtist(value);
this._autosuggest.input.blur();
this.reset();

View file

@ -6,7 +6,6 @@ const fuseOptions = {
threshold: 0.3,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: [
'artistName',

View file

@ -17,12 +17,18 @@ class Scroller extends Component {
componentDidMount() {
const {
scrollDirection,
autoFocus,
scrollTop
} = this.props;
if (this.props.scrollTop != null) {
this._scroller.scrollTop = scrollTop;
}
if (autoFocus && scrollDirection !== scrollDirections.NONE) {
this._scroller.focus({ preventScroll: true });
}
}
//
@ -58,6 +64,7 @@ class Scroller extends Component {
styles[scrollDirection],
autoScroll && styles.autoScroll
)}
tabIndex={-1}
{...otherProps}
>
{children}
@ -70,6 +77,7 @@ class Scroller extends Component {
Scroller.propTypes = {
className: PropTypes.string,
scrollDirection: PropTypes.oneOf(scrollDirections.all).isRequired,
autoFocus: PropTypes.bool.isRequired,
autoScroll: PropTypes.bool.isRequired,
scrollTop: PropTypes.number,
children: PropTypes.node,
@ -79,6 +87,7 @@ Scroller.propTypes = {
Scroller.defaultProps = {
scrollDirection: scrollDirections.VERTICAL,
autoFocus: true,
autoScroll: true,
registerScroller: () => {}
};

View file

@ -136,7 +136,7 @@ class TableOptionsModal extends Component {
isOpen ?
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
Table Options
Table Options
</ModalHeader>
<ModalBody>
@ -231,7 +231,7 @@ class TableOptionsModal extends Component {
<Button
onPress={onModalClose}
>
Close
Close
</Button>
</ModalFooter>
</ModalContent> :

View file

@ -8,6 +8,16 @@ export const shortcuts = {
name: 'Open This Modal'
},
CLOSE_MODAL: {
key: 'Esc',
name: 'Close Current Modal'
},
ACCEPT_CONFIRM_MODAL: {
key: 'Enter',
name: 'Accept Confirmation Modal'
},
ARTIST_SEARCH_INPUT: {
key: 's',
name: 'Focus Search Box'

View file

@ -72,9 +72,9 @@ class ConfirmImportModalContent extends Component {
{
!isFetching && isPopulated &&
<ModalHeader>
Are you sure?
</ModalHeader>
<ModalHeader>
Are you sure?
</ModalHeader>
}
<ModalBody>

View file

@ -177,7 +177,7 @@ function InteractiveSearch(props) {
{
totalReleasesCount !== items.length && !!items.length ?
<div className={styles.filteredMessage}>
Some results are hidden by the applied filter
Some results are hidden by the applied filter
</div> :
null
}

View file

@ -103,11 +103,11 @@ class AddNewAlbumSearchResult extends Component {
<div className={styles.overlay}>
{
!isSmallScreen &&
<AlbumCover
className={styles.poster}
images={images}
size={250}
/>
<AlbumCover
className={styles.poster}
images={images}
size={250}
/>
}
<div className={styles.content}>
@ -116,7 +116,7 @@ class AddNewAlbumSearchResult extends Component {
{
!!disambiguation &&
<span className={styles.year}>({disambiguation})</span>
<span className={styles.year}>({disambiguation})</span>
}
{

View file

@ -124,7 +124,7 @@ class AddNewArtistSearchResult extends Component {
{
!!disambiguation &&
<span className={styles.year}>({disambiguation})</span>
<span className={styles.year}>({disambiguation})</span>
}
{

View file

@ -44,90 +44,90 @@ function ProxySettings(props) {
{
proxyEnabled.value &&
<div>
<FormGroup>
<FormLabel>Proxy Type</FormLabel>
<div>
<FormGroup>
<FormLabel>Proxy Type</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="proxyType"
values={proxyTypeOptions}
onChange={onInputChange}
{...proxyType}
/>
</FormGroup>
<FormInputGroup
type={inputTypes.SELECT}
name="proxyType"
values={proxyTypeOptions}
onChange={onInputChange}
{...proxyType}
/>
</FormGroup>
<FormGroup>
<FormLabel>Hostname</FormLabel>
<FormGroup>
<FormLabel>Hostname</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="proxyHostname"
onChange={onInputChange}
{...proxyHostname}
/>
</FormGroup>
<FormInputGroup
type={inputTypes.TEXT}
name="proxyHostname"
onChange={onInputChange}
{...proxyHostname}
/>
</FormGroup>
<FormGroup>
<FormLabel>Port</FormLabel>
<FormGroup>
<FormLabel>Port</FormLabel>
<FormInputGroup
type={inputTypes.NUMBER}
name="proxyPort"
min={1}
max={65535}
onChange={onInputChange}
{...proxyPort}
/>
</FormGroup>
<FormInputGroup
type={inputTypes.NUMBER}
name="proxyPort"
min={1}
max={65535}
onChange={onInputChange}
{...proxyPort}
/>
</FormGroup>
<FormGroup>
<FormLabel>Username</FormLabel>
<FormGroup>
<FormLabel>Username</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="proxyUsername"
helpText="You only need to enter a username and password if one is required. Leave them blank otherwise."
onChange={onInputChange}
{...proxyUsername}
/>
</FormGroup>
<FormInputGroup
type={inputTypes.TEXT}
name="proxyUsername"
helpText="You only need to enter a username and password if one is required. Leave them blank otherwise."
onChange={onInputChange}
{...proxyUsername}
/>
</FormGroup>
<FormGroup>
<FormLabel>Password</FormLabel>
<FormGroup>
<FormLabel>Password</FormLabel>
<FormInputGroup
type={inputTypes.PASSWORD}
name="proxyPassword"
helpText="You only need to enter a username and password if one is required. Leave them blank otherwise."
onChange={onInputChange}
{...proxyPassword}
/>
</FormGroup>
<FormInputGroup
type={inputTypes.PASSWORD}
name="proxyPassword"
helpText="You only need to enter a username and password if one is required. Leave them blank otherwise."
onChange={onInputChange}
{...proxyPassword}
/>
</FormGroup>
<FormGroup>
<FormLabel>Ignored Addresses</FormLabel>
<FormGroup>
<FormLabel>Ignored Addresses</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="proxyBypassFilter"
helpText="Use ',' as a separator, and '*.' as a wildcard for subdomains"
onChange={onInputChange}
{...proxyBypassFilter}
/>
</FormGroup>
<FormInputGroup
type={inputTypes.TEXT}
name="proxyBypassFilter"
helpText="Use ',' as a separator, and '*.' as a wildcard for subdomains"
onChange={onInputChange}
{...proxyBypassFilter}
/>
</FormGroup>
<FormGroup size={sizes.MEDIUM}>
<FormLabel>Bypass Proxy for Local Addresses</FormLabel>
<FormGroup size={sizes.MEDIUM}>
<FormLabel>Bypass Proxy for Local Addresses</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="proxyBypassLocalAddresses"
onChange={onInputChange}
{...proxyBypassLocalAddresses}
/>
</FormGroup>
</div>
<FormInputGroup
type={inputTypes.CHECK}
name="proxyBypassLocalAddresses"
onChange={onInputChange}
{...proxyBypassLocalAddresses}
/>
</FormGroup>
</div>
}
</FieldSet>
);

View file

@ -93,32 +93,32 @@ class SecuritySettings extends Component {
{
authenticationEnabled &&
<FormGroup>
<FormLabel>Username</FormLabel>
<FormGroup>
<FormLabel>Username</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="username"
helpTextWarning="Requires restart to take effect"
onChange={onInputChange}
{...username}
/>
</FormGroup>
<FormInputGroup
type={inputTypes.TEXT}
name="username"
helpTextWarning="Requires restart to take effect"
onChange={onInputChange}
{...username}
/>
</FormGroup>
}
{
authenticationEnabled &&
<FormGroup>
<FormLabel>Password</FormLabel>
<FormGroup>
<FormLabel>Password</FormLabel>
<FormInputGroup
type={inputTypes.PASSWORD}
name="password"
helpTextWarning="Requires restart to take effect"
onChange={onInputChange}
{...password}
/>
</FormGroup>
<FormInputGroup
type={inputTypes.PASSWORD}
name="password"
helpTextWarning="Requires restart to take effect"
onChange={onInputChange}
{...password}
/>
</FormGroup>
}
<FormGroup>

View file

@ -72,58 +72,58 @@ function UpdateSettings(props) {
{
!isWindows &&
<div>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
size={sizes.MEDIUM}
>
<FormLabel>Automatic</FormLabel>
<div>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
size={sizes.MEDIUM}
>
<FormLabel>Automatic</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="updateAutomatically"
helpText="Automatically download and install updates. You will still be able to install from System: Updates"
onChange={onInputChange}
{...updateAutomatically}
/>
</FormGroup>
<FormInputGroup
type={inputTypes.CHECK}
name="updateAutomatically"
helpText="Automatically download and install updates. You will still be able to install from System: Updates"
onChange={onInputChange}
{...updateAutomatically}
/>
</FormGroup>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>Mechanism</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="updateMechanism"
values={updateOptions}
helpText="Use Lidarr's built-in updater or a script"
helpLink="https://github.com/Lidarr/Lidarr/wiki/Updating"
onChange={onInputChange}
{...updateMechanism}
/>
</FormGroup>
{
updateMechanism.value === 'script' &&
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>Script Path</FormLabel>
<FormLabel>Mechanism</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="updateScriptPath"
helpText="Path to a custom script that takes an extracted update package and handle the remainder of the update process"
type={inputTypes.SELECT}
name="updateMechanism"
values={updateOptions}
helpText="Use Lidarr's built-in updater or a script"
helpLink="https://github.com/Lidarr/Lidarr/wiki/Updating"
onChange={onInputChange}
{...updateScriptPath}
{...updateMechanism}
/>
</FormGroup>
}
</div>
{
updateMechanism.value === 'script' &&
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>Script Path</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="updateScriptPath"
helpText="Path to a custom script that takes an extracted update package and handle the remainder of the update process"
onChange={onInputChange}
{...updateScriptPath}
/>
</FormGroup>
}
</div>
}
</FieldSet>
);

View file

@ -199,23 +199,23 @@ function EditImportListModalContent(props) {
{
!!fields && !!fields.length &&
<div>
{
fields.map((field) => {
return (
<ProviderFieldFormGroup
key={field.name}
advancedSettings={advancedSettings}
provider="importList"
providerData={item}
section="settings.importLists"
{...field}
onChange={onFieldChange}
/>
);
})
}
</div>
<div>
{
fields.map((field) => {
return (
<ProviderFieldFormGroup
key={field.name}
advancedSettings={advancedSettings}
provider="importList"
providerData={item}
section="settings.importLists"
{...field}
onChange={onFieldChange}
/>
);
})
}
</div>
}
</Form>

View file

@ -96,12 +96,12 @@ class Indexer extends Component {
{
!enableRss && !enableAutomaticSearch && !enableInteractiveSearch &&
<Label
kind={kinds.DISABLED}
outline={true}
>
Disabled
</Label>
<Label
kind={kinds.DISABLED}
outline={true}
>
Disabled
</Label>
}
</div>

View file

@ -43,23 +43,23 @@ function MetadataProvider(props) {
<Form>
{
advancedSettings &&
<FieldSet legend="Metadata Provider Source">
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>Metadata Source</FormLabel>
<FieldSet legend="Metadata Provider Source">
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>Metadata Source</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="metadataSource"
helpText="Alternative Metadata Source (Leave blank for default)"
helpLink="https://github.com/Lidarr/Lidarr/wiki/Metadata-Source"
onChange={onInputChange}
{...settings.metadataSource}
/>
</FormGroup>
</FieldSet>
<FormInputGroup
type={inputTypes.TEXT}
name="metadataSource"
helpText="Alternative Metadata Source (Leave blank for default)"
helpLink="https://github.com/Lidarr/Lidarr/wiki/Metadata-Source"
onChange={onInputChange}
{...settings.metadataSource}
/>
</FormGroup>
</FieldSet>
}
<FieldSet legend="Write Metadata to Audio Files">

View file

@ -141,12 +141,12 @@ class Notification extends Component {
{
!onGrab && !onReleaseImport && !onRename && !onTrackRetag &&
!onHealthIssue && !onDownloadFailure && !onImportFailure &&
<Label
kind={kinds.DISABLED}
outline={true}
>
Disabled
</Label>
<Label
kind={kinds.DISABLED}
outline={true}
>
Disabled
</Label>
}
<EditNotificationModalConnector

View file

@ -1,6 +1,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import React, { useEffect } from 'react';
import { kinds } from 'Helpers/Props';
import keyboardShortcuts from 'Components/keyboardShortcuts';
import Button from 'Components/Link/Button';
import Modal from 'Components/Modal/Modal';
import ModalContent from 'Components/Modal/ModalContent';
@ -12,9 +13,14 @@ function PendingChangesModal(props) {
const {
isOpen,
onConfirm,
onCancel
onCancel,
bindShortcut
} = props;
useEffect(() => {
bindShortcut('enter', onConfirm);
}, [onConfirm]);
return (
<Modal
isOpen={isOpen}
@ -36,6 +42,7 @@ function PendingChangesModal(props) {
</Button>
<Button
autoFocus={true}
kind={kinds.DANGER}
onPress={onConfirm}
>
@ -52,11 +59,12 @@ PendingChangesModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
kind: PropTypes.oneOf(kinds.all),
onConfirm: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired
onCancel: PropTypes.func.isRequired,
bindShortcut: PropTypes.func.isRequired
};
PendingChangesModal.defaultProps = {
kind: kinds.PRIMARY
};
export default PendingChangesModal;
export default keyboardShortcuts(PendingChangesModal);

View file

@ -174,7 +174,7 @@ class EditQualityProfileModalContent extends Component {
upgradeAllowed.value &&
<FormGroup size={sizes.EXTRA_SMALL}>
<FormLabel size={sizes.SMALL}>
Upgrade Until
Upgrade Until
</FormLabel>
<FormInputGroup

View file

@ -167,7 +167,7 @@ function TagDetailsModalContent(props) {
isDisabled={isTagUsed}
onPress={onDeleteTagPress}
>
Delete
Delete
</Button>
}

View file

@ -200,7 +200,7 @@ class RestoreBackupModalContent extends Component {
</div>
<Button onPress={onModalClose}>
Cancel
Cancel
</Button>
<SpinnerButton
@ -209,7 +209,7 @@ class RestoreBackupModalContent extends Component {
isSpinning={isRestoring}
onPress={this.onRestorePress}
>
Restore
Restore
</SpinnerButton>
</ModalFooter>
</ModalContent>

View file

@ -76,45 +76,45 @@ function LogsTable(props) {
<PageContentBodyConnector>
{
isFetching && !isPopulated &&
<LoadingIndicator />
<LoadingIndicator />
}
{
isPopulated && !error && !items.length &&
<div>
No logs found
</div>
<div>
No logs found
</div>
}
{
isPopulated && !error && !!items.length &&
<div>
<Table
columns={columns}
canModifyColumns={false}
{...otherProps}
>
<TableBody>
{
items.map((item) => {
return (
<LogsTableRow
key={item.id}
columns={columns}
{...item}
/>
);
})
}
</TableBody>
</Table>
<div>
<Table
columns={columns}
canModifyColumns={false}
{...otherProps}
>
<TableBody>
{
items.map((item) => {
return (
<LogsTableRow
key={item.id}
columns={columns}
{...item}
/>
);
})
}
</TableBody>
</Table>
<TablePager
totalRecords={totalRecords}
isFetching={isFetching}
{...otherProps}
/>
</div>
<TablePager
totalRecords={totalRecords}
isFetching={isFetching}
{...otherProps}
/>
</div>
}
</PageContentBodyConnector>
</PageContent>

View file

@ -54,27 +54,27 @@ function QueuedTasks(props) {
<FieldSet legend="Queue">
{
isFetching && !isPopulated &&
<LoadingIndicator />
<LoadingIndicator />
}
{
isPopulated &&
<Table
columns={columns}
>
<TableBody>
{
items.map((item) => {
return (
<QueuedTaskRowConnector
key={item.id}
{...item}
/>
);
})
}
</TableBody>
</Table>
<Table
columns={columns}
>
<TableBody>
{
items.map((item) => {
return (
<QueuedTaskRowConnector
key={item.id}
{...item}
/>
);
})
}
</TableBody>
</Table>
}
</FieldSet>
);

View file

@ -49,27 +49,27 @@ function ScheduledTasks(props) {
<FieldSet legend="Scheduled">
{
isFetching && !isPopulated &&
<LoadingIndicator />
<LoadingIndicator />
}
{
isPopulated &&
<Table
columns={columns}
>
<TableBody>
{
items.map((item) => {
return (
<ScheduledTaskRowConnector
key={item.id}
{...item}
/>
);
})
}
</TableBody>
</Table>
<Table
columns={columns}
>
<TableBody>
{
items.map((item) => {
return (
<ScheduledTaskRowConnector
key={item.id}
{...item}
/>
);
})
}
</TableBody>
</Table>
}
</FieldSet>
);

View file

@ -79,6 +79,5 @@
</body>
<script src="/initialize.js" data-no-hash></script>
<script src="/polyfills.js"></script>
<!-- webpack bundles body -->
</html>

View file

@ -1,4 +1,6 @@
import './preload.js';
import './preload';
import './polyfills';
import React from 'react';
import { render } from 'react-dom';
import { createBrowserHistory } from 'history';