mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-11 15:47:09 -07:00
New: UI Updates, Tag manager, More custom filters (#437)
* New: UI Updates, Tag manager, More custom filters * fixup! Fix ScanFixture Unit Tests * Fixed: Sentry Errors from UI don't have release, branch, environment * Changed: Bump Mobile Detect for New Device Detection * Fixed: Build on changes to package.json * fixup! Add MetadataProfile filter option * fixup! Tag Note, Blacklist, Manual Import * fixup: Remove connectSection * fixup: root folder comment
This commit is contained in:
parent
afa78b1d20
commit
6581b3a2c5
198 changed files with 3057 additions and 888 deletions
|
@ -9,9 +9,28 @@
|
|||
}
|
||||
|
||||
.inputContainer {
|
||||
position: relative;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.inputUnit {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 20px;
|
||||
margin-top: 7px;
|
||||
width: 75px;
|
||||
color: #c6c6c6;
|
||||
text-align: right;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.inputUnitNumber {
|
||||
composes: inputUnit;
|
||||
|
||||
right: 40px;
|
||||
}
|
||||
|
||||
.pendingChangesContainer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
|
|
@ -83,6 +83,7 @@ function FormInputGroup(props) {
|
|||
containerClassName,
|
||||
inputClassName,
|
||||
type,
|
||||
unit,
|
||||
buttons,
|
||||
helpText,
|
||||
helpTexts,
|
||||
|
@ -115,6 +116,19 @@ function FormInputGroup(props) {
|
|||
hasButton={hasButton}
|
||||
{...otherProps}
|
||||
/>
|
||||
|
||||
{
|
||||
unit &&
|
||||
<div
|
||||
className={
|
||||
type === inputTypes.NUMBER ?
|
||||
styles.inputUnitNumber :
|
||||
styles.inputUnit
|
||||
}
|
||||
>
|
||||
{unit}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
{
|
||||
|
@ -219,6 +233,7 @@ FormInputGroup.propTypes = {
|
|||
containerClassName: PropTypes.string.isRequired,
|
||||
inputClassName: PropTypes.string,
|
||||
type: PropTypes.string.isRequired,
|
||||
unit: PropTypes.string,
|
||||
buttons: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]),
|
||||
helpText: PropTypes.string,
|
||||
helpTexts: PropTypes.arrayOf(PropTypes.string),
|
||||
|
|
|
@ -48,12 +48,14 @@ class NumberInput extends Component {
|
|||
|
||||
render() {
|
||||
const {
|
||||
value,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<TextInput
|
||||
type="number"
|
||||
value={value == null ? '' : value}
|
||||
{...otherProps}
|
||||
onChange={this.onChange}
|
||||
onBlur={this.onBlur}
|
||||
|
|
|
@ -1,30 +1,39 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||
import SpinnerErrorButton from 'Components/Link/SpinnerErrorButton';
|
||||
|
||||
function OAuthInput(props) {
|
||||
const {
|
||||
label,
|
||||
authorizing,
|
||||
error,
|
||||
onPress
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SpinnerButton
|
||||
<SpinnerErrorButton
|
||||
kind={kinds.PRIMARY}
|
||||
isSpinning={authorizing}
|
||||
error={error}
|
||||
onPress={onPress}
|
||||
>
|
||||
Start OAuth
|
||||
</SpinnerButton>
|
||||
{label}
|
||||
</SpinnerErrorButton>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
OAuthInput.propTypes = {
|
||||
label: PropTypes.string.isRequired,
|
||||
authorizing: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
onPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
OAuthInput.defaultProps = {
|
||||
label: 'Start OAuth'
|
||||
};
|
||||
|
||||
export default OAuthInput;
|
||||
|
|
|
@ -26,18 +26,17 @@ class OAuthInputConnector extends Component {
|
|||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
accessToken,
|
||||
accessTokenSecret,
|
||||
result,
|
||||
onChange
|
||||
} = this.props;
|
||||
|
||||
if (accessToken &&
|
||||
accessToken !== prevProps.accessToken &&
|
||||
accessTokenSecret &&
|
||||
accessTokenSecret !== prevProps.accessTokenSecret) {
|
||||
onChange({ name: 'AccessToken', value: accessToken });
|
||||
onChange({ name: 'AccessTokenSecret', value: accessTokenSecret });
|
||||
if (!result || result === prevProps.result) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object.keys(result).forEach((key) => {
|
||||
onChange({ name: key, value: result[key] });
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount = () => {
|
||||
|
@ -70,8 +69,7 @@ class OAuthInputConnector extends Component {
|
|||
}
|
||||
|
||||
OAuthInputConnector.propTypes = {
|
||||
accessToken: PropTypes.string,
|
||||
accessTokenSecret: PropTypes.string,
|
||||
result: PropTypes.object,
|
||||
provider: PropTypes.string.isRequired,
|
||||
providerData: PropTypes.object.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
|
|
|
@ -7,19 +7,6 @@ import FormLabel from 'Components/Form/FormLabel';
|
|||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
|
||||
function getType(type) {
|
||||
// Textbox,
|
||||
// Password,
|
||||
// Checkbox,
|
||||
// Select,
|
||||
// Path,
|
||||
// FilePath,
|
||||
// Hidden,
|
||||
// Tag,
|
||||
// Action,
|
||||
// Url,
|
||||
// Captcha
|
||||
// OAuth
|
||||
|
||||
switch (type) {
|
||||
case 'captcha':
|
||||
return inputTypes.CAPTCHA;
|
||||
|
@ -27,6 +14,8 @@ function getType(type) {
|
|||
return inputTypes.CHECK;
|
||||
case 'password':
|
||||
return inputTypes.PASSWORD;
|
||||
case 'number':
|
||||
return inputTypes.NUMBER;
|
||||
case 'path':
|
||||
return inputTypes.PATH;
|
||||
case 'select':
|
||||
|
@ -83,6 +72,7 @@ function ProviderFieldFormGroup(props) {
|
|||
<FormInputGroup
|
||||
type={getType(type)}
|
||||
name={name}
|
||||
label={label}
|
||||
helpText={helpText}
|
||||
helpLink={helpLink}
|
||||
value={value}
|
||||
|
|
|
@ -32,7 +32,7 @@ function RootFolderSelectInputSelectedValue(props) {
|
|||
}
|
||||
|
||||
RootFolderSelectInputSelectedValue.propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
value: PropTypes.string,
|
||||
freeSpace: PropTypes.number,
|
||||
includeFreeSpace: PropTypes.bool.isRequired
|
||||
};
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
min-width: 20%;
|
||||
max-width: 100%;
|
||||
width: 0%;
|
||||
height: 21px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,20 +58,20 @@ class TagInput extends Component {
|
|||
return name;
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onInputContainerPress = () => {
|
||||
this._autosuggestRef.input.focus();
|
||||
}
|
||||
|
||||
onTagAdd(tag) {
|
||||
addTag = _.debounce((tag) => {
|
||||
this.props.onTagAdd(tag);
|
||||
|
||||
this.setState({
|
||||
value: '',
|
||||
suggestions: []
|
||||
});
|
||||
}, 250, { leading: true, trailing: false })
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onInputContainerPress = () => {
|
||||
this._autosuggestRef.input.focus();
|
||||
}
|
||||
|
||||
onInputChange = (event, { newValue, method }) => {
|
||||
|
@ -116,10 +116,9 @@ class TagInput extends Component {
|
|||
const tag = getTag(value, selectedIndex, suggestions, allowNew);
|
||||
|
||||
if (tag) {
|
||||
this.onTagAdd(tag);
|
||||
this.addTag(tag);
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,7 +146,7 @@ class TagInput extends Component {
|
|||
const tag = getTag(value, selectedIndex, suggestions, allowNew);
|
||||
|
||||
if (tag) {
|
||||
this.onTagAdd(tag);
|
||||
this.addTag(tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,7 +173,7 @@ class TagInput extends Component {
|
|||
}
|
||||
|
||||
onSuggestionSelected = (event, { suggestion }) => {
|
||||
this.onTagAdd(suggestion);
|
||||
this.addTag(suggestion);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -262,7 +261,7 @@ class TagInput extends Component {
|
|||
}
|
||||
|
||||
export const tagShape = {
|
||||
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
|
||||
id: PropTypes.oneOfType([PropTypes.bool, PropTypes.number, PropTypes.string]).isRequired,
|
||||
name: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue