Changed: Remove Language Profiles (#870)

* Changed: Remove Language Profiles

* fixup! Changed: Remove Language Profiles

* fixup! Changed: Remove Language Profiles

* Remove unused method in FileNameBuilder

* Fixed: Cleanup Int Converter Copy/Paste Issues and Grammar
This commit is contained in:
Qstick
2019-08-02 07:50:09 -04:00
committed by GitHub
parent 8f791abbf6
commit 8b860bcb82
227 changed files with 345 additions and 5873 deletions
@@ -1,27 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import { sizes } from 'Helpers/Props';
import Modal from 'Components/Modal/Modal';
import EditLanguageProfileModalContentConnector from './EditLanguageProfileModalContentConnector';
function EditLanguageProfileModal({ isOpen, onModalClose, ...otherProps }) {
return (
<Modal
size={sizes.MEDIUM}
isOpen={isOpen}
onModalClose={onModalClose}
>
<EditLanguageProfileModalContentConnector
{...otherProps}
onModalClose={onModalClose}
/>
</Modal>
);
}
EditLanguageProfileModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default EditLanguageProfileModal;
@@ -1,43 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { clearPendingChanges } from 'Store/Actions/baseActions';
import EditLanguageProfileModal from './EditLanguageProfileModal';
function mapStateToProps() {
return {};
}
const mapDispatchToProps = {
clearPendingChanges
};
class EditLanguageProfileModalConnector extends Component {
//
// Listeners
onModalClose = () => {
this.props.clearPendingChanges({ section: 'settings.languageProfiles' });
this.props.onModalClose();
}
//
// Render
render() {
return (
<EditLanguageProfileModal
{...this.props}
onModalClose={this.onModalClose}
/>
);
}
}
EditLanguageProfileModalConnector.propTypes = {
onModalClose: PropTypes.func.isRequired,
clearPendingChanges: PropTypes.func.isRequired
};
export default connect(mapStateToProps, mapDispatchToProps)(EditLanguageProfileModalConnector);
@@ -1,3 +0,0 @@
.deleteButtonContainer {
margin-right: auto;
}
@@ -1,165 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import { inputTypes, kinds } from 'Helpers/Props';
import Button from 'Components/Link/Button';
import SpinnerErrorButton from 'Components/Link/SpinnerErrorButton';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import ModalContent from 'Components/Modal/ModalContent';
import ModalHeader from 'Components/Modal/ModalHeader';
import ModalBody from 'Components/Modal/ModalBody';
import ModalFooter from 'Components/Modal/ModalFooter';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormLabel from 'Components/Form/FormLabel';
import FormInputGroup from 'Components/Form/FormInputGroup';
import LanguageProfileItems from './LanguageProfileItems';
import styles from './EditLanguageProfileModalContent.css';
function EditLanguageProfileModalContent(props) {
const {
isFetching,
error,
isSaving,
saveError,
languages,
item,
isInUse,
onInputChange,
onCutoffChange,
onSavePress,
onModalClose,
onDeleteLanguageProfilePress,
...otherProps
} = props;
const {
id,
name,
upgradeAllowed,
cutoff,
languages: itemLanguages
} = item;
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
{id ? 'Edit Language Profile' : 'Add Language Profile'}
</ModalHeader>
<ModalBody>
{
isFetching &&
<LoadingIndicator />
}
{
!isFetching && !!error &&
<div>Unable to add a new language profile, please try again.</div>
}
{
!isFetching && !error &&
<Form {...otherProps}>
<FormGroup>
<FormLabel>Name</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="name"
{...name}
onChange={onInputChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>
Upgrades Allowed
</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="upgradeAllowed"
{...upgradeAllowed}
helpText="If disabled languages will not be upgraded"
onChange={onInputChange}
/>
</FormGroup>
{
upgradeAllowed.value &&
<FormGroup>
<FormLabel>Upgrade Until</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="cutoff"
{...cutoff}
value={cutoff ? cutoff.value.id : 0}
values={languages}
helpText="Once this language is reached Lidarr will no longer download albums"
onChange={onCutoffChange}
/>
</FormGroup>
}
<LanguageProfileItems
languageProfileItems={itemLanguages.value}
errors={itemLanguages.errors}
warnings={itemLanguages.warnings}
{...otherProps}
/>
</Form>
}
</ModalBody>
<ModalFooter>
{
id &&
<div
className={styles.deleteButtonContainer}
title={isInUse ? 'Can\'t delete a language profile that is attached to an artist or import list' : undefined}
>
<Button
kind={kinds.DANGER}
isDisabled={isInUse}
onPress={onDeleteLanguageProfilePress}
>
Delete
</Button>
</div>
}
<Button
onPress={onModalClose}
>
Cancel
</Button>
<SpinnerErrorButton
isSpinning={isSaving}
error={saveError}
onPress={onSavePress}
>
Save
</SpinnerErrorButton>
</ModalFooter>
</ModalContent>
);
}
EditLanguageProfileModalContent.propTypes = {
isFetching: PropTypes.bool.isRequired,
error: PropTypes.object,
isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object,
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
item: PropTypes.object.isRequired,
isInUse: PropTypes.bool.isRequired,
onInputChange: PropTypes.func.isRequired,
onCutoffChange: PropTypes.func.isRequired,
onSavePress: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired,
onDeleteLanguageProfilePress: PropTypes.func
};
export default EditLanguageProfileModalContent;
@@ -1,189 +0,0 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createProfileInUseSelector from 'Store/Selectors/createProfileInUseSelector';
import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
import { fetchLanguageProfileSchema, setLanguageProfileValue, saveLanguageProfile } from 'Store/Actions/settingsActions';
import EditLanguageProfileModalContent from './EditLanguageProfileModalContent';
function createLanguagesSelector() {
return createSelector(
createProviderSettingsSelector('languageProfiles'),
(languageProfile) => {
const languages = languageProfile.item.languages;
if (!languages || !languages.value) {
return [];
}
return _.reduceRight(languages.value, (result, { allowed, language }) => {
if (allowed) {
result.push({
key: language.id,
value: language.name
});
}
return result;
}, []);
}
);
}
function createMapStateToProps() {
return createSelector(
createProviderSettingsSelector('languageProfiles'),
createLanguagesSelector(),
createProfileInUseSelector('languageProfileId'),
(languageProfile, languages, isInUse) => {
return {
languages,
...languageProfile,
isInUse
};
}
);
}
const mapDispatchToProps = {
fetchLanguageProfileSchema,
setLanguageProfileValue,
saveLanguageProfile
};
class EditLanguageProfileModalContentConnector extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
dragIndex: null,
dropIndex: null
};
}
componentDidMount() {
if (!this.props.id && !this.props.isPopulated) {
this.props.fetchLanguageProfileSchema();
}
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.isSaving && !this.props.isSaving && !this.props.saveError) {
this.props.onModalClose();
}
}
//
// Listeners
onInputChange = ({ name, value }) => {
this.props.setLanguageProfileValue({ name, value });
}
onCutoffChange = ({ name, value }) => {
const id = parseInt(value);
const item = _.find(this.props.item.languages.value, (i) => i.language.id === id);
this.props.setLanguageProfileValue({ name, value: item.language });
}
onSavePress = () => {
this.props.saveLanguageProfile({ id: this.props.id });
}
onLanguageProfileItemAllowedChange = (id, allowed) => {
const languageProfile = _.cloneDeep(this.props.item);
const item = _.find(languageProfile.languages.value, (i) => i.language.id === id);
item.allowed = allowed;
this.props.setLanguageProfileValue({
name: 'languages',
value: languageProfile.languages.value
});
const cutoff = languageProfile.cutoff.value;
// If the cutoff isn't allowed anymore or there isn't a cutoff set one
if (!cutoff || !_.find(languageProfile.languages.value, (i) => i.language.id === cutoff.id).allowed) {
const firstAllowed = _.find(languageProfile.languages.value, { allowed: true });
this.props.setLanguageProfileValue({ name: 'cutoff', value: firstAllowed ? firstAllowed.language : null });
}
}
onLanguageProfileItemDragMove = (dragIndex, dropIndex) => {
if (this.state.dragIndex !== dragIndex || this.state.dropIndex !== dropIndex) {
this.setState({
dragIndex,
dropIndex
});
}
}
onLanguageProfileItemDragEnd = ({ id }, didDrop) => {
const {
dragIndex,
dropIndex
} = this.state;
if (didDrop && dropIndex !== null) {
const languageProfile = _.cloneDeep(this.props.item);
const languages = languageProfile.languages.value.splice(dragIndex, 1);
languageProfile.languages.value.splice(dropIndex, 0, languages[0]);
this.props.setLanguageProfileValue({
name: 'languages',
value: languageProfile.languages.value
});
}
this.setState({
dragIndex: null,
dropIndex: null
});
}
//
// Render
render() {
if (_.isEmpty(this.props.item.languages) && !this.props.isFetching) {
return null;
}
return (
<EditLanguageProfileModalContent
{...this.state}
{...this.props}
onSavePress={this.onSavePress}
onInputChange={this.onInputChange}
onCutoffChange={this.onCutoffChange}
onLanguageProfileItemAllowedChange={this.onLanguageProfileItemAllowedChange}
onLanguageProfileItemDragMove={this.onLanguageProfileItemDragMove}
onLanguageProfileItemDragEnd={this.onLanguageProfileItemDragEnd}
/>
);
}
}
EditLanguageProfileModalContentConnector.propTypes = {
id: PropTypes.number,
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object,
item: PropTypes.object.isRequired,
setLanguageProfileValue: PropTypes.func.isRequired,
fetchLanguageProfileSchema: PropTypes.func.isRequired,
saveLanguageProfile: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(EditLanguageProfileModalContentConnector);
@@ -1,31 +0,0 @@
.languageProfile {
composes: card from '~Components/Card.css';
width: 300px;
}
.nameContainer {
display: flex;
justify-content: space-between;
}
.name {
@add-mixin truncate;
margin-bottom: 20px;
font-weight: 300;
font-size: 24px;
}
.cloneButton {
composes: button from '~Components/Link/IconButton.css';
height: 36px;
}
.languages {
display: flex;
flex-wrap: wrap;
margin-top: 5px;
pointer-events: all;
}
@@ -1,147 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { icons, kinds } from 'Helpers/Props';
import Card from 'Components/Card';
import Label from 'Components/Label';
import IconButton from 'Components/Link/IconButton';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import EditLanguageProfileModalConnector from './EditLanguageProfileModalConnector';
import styles from './LanguageProfile.css';
class LanguageProfile extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
isEditLanguageProfileModalOpen: false,
isDeleteLanguageProfileModalOpen: false
};
}
//
// Listeners
onEditLanguageProfilePress = () => {
this.setState({ isEditLanguageProfileModalOpen: true });
}
onEditLanguageProfileModalClose = () => {
this.setState({ isEditLanguageProfileModalOpen: false });
}
onDeleteLanguageProfilePress = () => {
this.setState({
isEditLanguageProfileModalOpen: false,
isDeleteLanguageProfileModalOpen: true
});
}
onDeleteLanguageProfileModalClose = () => {
this.setState({ isDeleteLanguageProfileModalOpen: false });
}
onConfirmDeleteLanguageProfile = () => {
this.props.onConfirmDeleteLanguageProfile(this.props.id);
}
onCloneLanguageProfilePress = () => {
const {
id,
onCloneLanguageProfilePress
} = this.props;
onCloneLanguageProfilePress(id);
}
//
// Render
render() {
const {
id,
name,
upgradeAllowed,
cutoff,
languages,
isDeleting
} = this.props;
return (
<Card
className={styles.languageProfile}
overlayContent={true}
onPress={this.onEditLanguageProfilePress}
>
<div className={styles.nameContainer}>
<div className={styles.name}>
{name}
</div>
<IconButton
className={styles.cloneButton}
title="Clone Profile"
name={icons.CLONE}
onPress={this.onCloneLanguageProfilePress}
/>
</div>
<div className={styles.languages}>
{
languages.map((item) => {
if (!item.allowed) {
return null;
}
const isCutoff = upgradeAllowed && item.language.id === cutoff.id;
return (
<Label
key={item.language.id}
kind={isCutoff ? kinds.INFO : kinds.default}
title={isCutoff ? 'Upgrade until this language is met or exceeded' : null}
>
{item.language.name}
</Label>
);
})
}
</div>
<EditLanguageProfileModalConnector
id={id}
isOpen={this.state.isEditLanguageProfileModalOpen}
onModalClose={this.onEditLanguageProfileModalClose}
onDeleteLanguageProfilePress={this.onDeleteLanguageProfilePress}
/>
<ConfirmModal
isOpen={this.state.isDeleteLanguageProfileModalOpen}
kind={kinds.DANGER}
title="Delete Language Profile"
message={`Are you sure you want to delete the language profile '${name}'?`}
confirmLabel="Delete"
isSpinning={isDeleting}
onConfirm={this.onConfirmDeleteLanguageProfile}
onCancel={this.onDeleteLanguageProfileModalClose}
/>
</Card>
);
}
}
LanguageProfile.propTypes = {
id: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
upgradeAllowed: PropTypes.bool.isRequired,
cutoff: PropTypes.object.isRequired,
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
isDeleting: PropTypes.bool.isRequired,
onConfirmDeleteLanguageProfile: PropTypes.func.isRequired,
onCloneLanguageProfilePress: PropTypes.func.isRequired
};
export default LanguageProfile;
@@ -1,44 +0,0 @@
.languageProfileItem {
display: flex;
align-items: stretch;
width: 100%;
border: 1px solid #aaa;
border-radius: 4px;
background: #fafafa;
}
.checkContainer {
position: relative;
margin-right: 4px;
margin-bottom: 7px;
margin-left: 8px;
}
.languageName {
display: flex;
flex-grow: 1;
margin-bottom: 0;
margin-left: 2px;
font-weight: normal;
line-height: 36px;
cursor: pointer;
}
.dragHandle {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
margin-left: auto;
width: $dragHandleWidth;
text-align: center;
cursor: grab;
}
.dragIcon {
top: 0;
}
.isDragging {
opacity: 0.25;
}
@@ -1,83 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import classNames from 'classnames';
import { icons } from 'Helpers/Props';
import Icon from 'Components/Icon';
import CheckInput from 'Components/Form/CheckInput';
import styles from './LanguageProfileItem.css';
class LanguageProfileItem extends Component {
//
// Listeners
onAllowedChange = ({ value }) => {
const {
languageId,
onLanguageProfileItemAllowedChange
} = this.props;
onLanguageProfileItemAllowedChange(languageId, value);
}
//
// Render
render() {
const {
name,
allowed,
isDragging,
connectDragSource
} = this.props;
return (
<div
className={classNames(
styles.languageProfileItem,
isDragging && styles.isDragging,
)}
>
<label
className={styles.languageName}
>
<CheckInput
containerClassName={styles.checkContainer}
name={name}
value={allowed}
onChange={this.onAllowedChange}
/>
{name}
</label>
{
connectDragSource(
<div className={styles.dragHandle}>
<Icon
className={styles.dragIcon}
name={icons.REORDER}
/>
</div>
)
}
</div>
);
}
}
LanguageProfileItem.propTypes = {
languageId: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
allowed: PropTypes.bool.isRequired,
sortIndex: PropTypes.number.isRequired,
isDragging: PropTypes.bool.isRequired,
connectDragSource: PropTypes.func,
onLanguageProfileItemAllowedChange: PropTypes.func
};
LanguageProfileItem.defaultProps = {
// The drag preview will not connect the drag handle.
connectDragSource: (node) => node
};
export default LanguageProfileItem;
@@ -1,4 +0,0 @@
.dragPreview {
width: 380px;
opacity: 0.75;
}
@@ -1,90 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { DragLayer } from 'react-dnd';
import dimensions from 'Styles/Variables/dimensions.js';
import { QUALITY_PROFILE_ITEM } from 'Helpers/dragTypes';
import DragPreviewLayer from 'Components/DragPreviewLayer';
import LanguageProfileItem from './LanguageProfileItem';
import styles from './LanguageProfileItemDragPreview.css';
const formGroupSmallWidth = parseInt(dimensions.formGroupSmallWidth);
const formLabelLargeWidth = parseInt(dimensions.formLabelLargeWidth);
const formLabelRightMarginWidth = parseInt(dimensions.formLabelRightMarginWidth);
const dragHandleWidth = parseInt(dimensions.dragHandleWidth);
function collectDragLayer(monitor) {
return {
item: monitor.getItem(),
itemType: monitor.getItemType(),
currentOffset: monitor.getSourceClientOffset()
};
}
class LanguageProfileItemDragPreview extends Component {
//
// Render
render() {
const {
item,
itemType,
currentOffset
} = this.props;
if (!currentOffset || itemType !== QUALITY_PROFILE_ITEM) {
return null;
}
// The offset is shifted because the drag handle is on the right edge of the
// list item and the preview is wider than the drag handle.
const { x, y } = currentOffset;
const handleOffset = formGroupSmallWidth - formLabelLargeWidth - formLabelRightMarginWidth - dragHandleWidth;
const transform = `translate3d(${x - handleOffset}px, ${y}px, 0)`;
const style = {
position: 'absolute',
WebkitTransform: transform,
msTransform: transform,
transform
};
const {
languageId,
name,
allowed,
sortIndex
} = item;
return (
<DragPreviewLayer>
<div
className={styles.dragPreview}
style={style}
>
<LanguageProfileItem
languageId={languageId}
name={name}
allowed={allowed}
sortIndex={sortIndex}
isDragging={false}
/>
</div>
</DragPreviewLayer>
);
}
}
LanguageProfileItemDragPreview.propTypes = {
item: PropTypes.object,
itemType: PropTypes.string,
currentOffset: PropTypes.shape({
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired
})
};
/* eslint-disable new-cap */
export default DragLayer(collectDragLayer)(LanguageProfileItemDragPreview);
/* eslint-enable new-cap */
@@ -1,18 +0,0 @@
.languageProfileItemDragSource {
padding: 4px 0;
}
.languageProfileItemPlaceholder {
width: 100%;
height: 36px;
border: 1px dotted #aaa;
border-radius: 4px;
}
.languageProfileItemPlaceholderBefore {
margin-bottom: 8px;
}
.languageProfileItemPlaceholderAfter {
margin-top: 8px;
}
@@ -1,159 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { findDOMNode } from 'react-dom';
import { DragSource, DropTarget } from 'react-dnd';
import classNames from 'classnames';
import { QUALITY_PROFILE_ITEM } from 'Helpers/dragTypes';
import LanguageProfileItem from './LanguageProfileItem';
import styles from './LanguageProfileItemDragSource.css';
const languageProfileItemDragSource = {
beginDrag({ languageId, name, allowed, sortIndex }) {
return {
languageId,
name,
allowed,
sortIndex
};
},
endDrag(props, monitor, component) {
props.onLanguageProfileItemDragEnd(monitor.getItem(), monitor.didDrop());
}
};
const languageProfileItemDropTarget = {
hover(props, monitor, component) {
const dragIndex = monitor.getItem().sortIndex;
const hoverIndex = props.sortIndex;
const hoverBoundingRect = findDOMNode(component).getBoundingClientRect();
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
const clientOffset = monitor.getClientOffset();
const hoverClientY = clientOffset.y - hoverBoundingRect.top;
// Moving up, only trigger if drag position is above 50%
if (dragIndex < hoverIndex && hoverClientY > hoverMiddleY) {
return;
}
// Moving down, only trigger if drag position is below 50%
if (dragIndex > hoverIndex && hoverClientY < hoverMiddleY) {
return;
}
props.onLanguageProfileItemDragMove(dragIndex, hoverIndex);
}
};
function collectDragSource(connect, monitor) {
return {
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging()
};
}
function collectDropTarget(connect, monitor) {
return {
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver()
};
}
class LanguageProfileItemDragSource extends Component {
//
// Render
render() {
const {
languageId,
name,
allowed,
sortIndex,
isDragging,
isDraggingUp,
isDraggingDown,
isOver,
connectDragSource,
connectDropTarget,
onLanguageProfileItemAllowedChange
} = this.props;
const isBefore = !isDragging && isDraggingUp && isOver;
const isAfter = !isDragging && isDraggingDown && isOver;
// if (isDragging && !isOver) {
// return null;
// }
return connectDropTarget(
<div
className={classNames(
styles.languageProfileItemDragSource,
isBefore && styles.isDraggingUp,
isAfter && styles.isDraggingDown
)}
>
{
isBefore &&
<div
className={classNames(
styles.languageProfileItemPlaceholder,
styles.languageProfileItemPlaceholderBefore
)}
/>
}
<LanguageProfileItem
languageId={languageId}
name={name}
allowed={allowed}
sortIndex={sortIndex}
isDragging={isDragging}
isOver={isOver}
connectDragSource={connectDragSource}
onLanguageProfileItemAllowedChange={onLanguageProfileItemAllowedChange}
/>
{
isAfter &&
<div
className={classNames(
styles.languageProfileItemPlaceholder,
styles.languageProfileItemPlaceholderAfter
)}
/>
}
</div>
);
}
}
LanguageProfileItemDragSource.propTypes = {
languageId: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
allowed: PropTypes.bool.isRequired,
sortIndex: PropTypes.number.isRequired,
isDragging: PropTypes.bool,
isDraggingUp: PropTypes.bool,
isDraggingDown: PropTypes.bool,
isOver: PropTypes.bool,
connectDragSource: PropTypes.func,
connectDropTarget: PropTypes.func,
onLanguageProfileItemAllowedChange: PropTypes.func.isRequired,
onLanguageProfileItemDragMove: PropTypes.func.isRequired,
onLanguageProfileItemDragEnd: PropTypes.func.isRequired
};
/* eslint-disable new-cap */
export default DropTarget(
QUALITY_PROFILE_ITEM,
languageProfileItemDropTarget,
collectDropTarget
)(DragSource(
QUALITY_PROFILE_ITEM,
languageProfileItemDragSource,
collectDragSource
)(LanguageProfileItemDragSource));
/* eslint-enable new-cap */
@@ -1,6 +0,0 @@
.languages {
margin-top: 10px;
/* TODO: This should consider the number of languages in the list */
min-height: 550px;
user-select: none;
}
@@ -1,103 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import FormGroup from 'Components/Form/FormGroup';
import FormLabel from 'Components/Form/FormLabel';
import FormInputHelpText from 'Components/Form/FormInputHelpText';
import LanguageProfileItemDragSource from './LanguageProfileItemDragSource';
import LanguageProfileItemDragPreview from './LanguageProfileItemDragPreview';
import styles from './LanguageProfileItems.css';
class LanguageProfileItems extends Component {
//
// Render
render() {
const {
dragIndex,
dropIndex,
languageProfileItems,
errors,
warnings,
...otherProps
} = this.props;
const isDragging = dropIndex !== null;
const isDraggingUp = isDragging && dropIndex > dragIndex;
const isDraggingDown = isDragging && dropIndex < dragIndex;
return (
<FormGroup>
<FormLabel>Languages</FormLabel>
<div>
<FormInputHelpText
text="Languages higher in the list are more preferred. Only checked languages are wanted"
/>
{
errors.map((error, index) => {
return (
<FormInputHelpText
key={index}
text={error.message}
isError={true}
isCheckInput={false}
/>
);
})
}
{
warnings.map((warning, index) => {
return (
<FormInputHelpText
key={index}
text={warning.message}
isWarning={true}
isCheckInput={false}
/>
);
})
}
<div className={styles.languages}>
{
languageProfileItems.map(({ allowed, language }, index) => {
return (
<LanguageProfileItemDragSource
key={language.id}
languageId={language.id}
name={language.name}
allowed={allowed}
sortIndex={index}
isDragging={isDragging}
isDraggingUp={isDraggingUp}
isDraggingDown={isDraggingDown}
{...otherProps}
/>
);
}).reverse()
}
<LanguageProfileItemDragPreview />
</div>
</div>
</FormGroup>
);
}
}
LanguageProfileItems.propTypes = {
dragIndex: PropTypes.number,
dropIndex: PropTypes.number,
languageProfileItems: PropTypes.arrayOf(PropTypes.object).isRequired,
errors: PropTypes.arrayOf(PropTypes.object),
warnings: PropTypes.arrayOf(PropTypes.object)
};
LanguageProfileItems.defaultProps = {
errors: [],
warnings: []
};
export default LanguageProfileItems;
@@ -1,31 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createLanguageProfileSelector from 'Store/Selectors/createLanguageProfileSelector';
function createMapStateToProps() {
return createSelector(
createLanguageProfileSelector(),
(languageProfile) => {
return {
name: languageProfile.name
};
}
);
}
function LanguageProfileNameConnector({ name, ...otherProps }) {
return (
<span>
{name}
</span>
);
}
LanguageProfileNameConnector.propTypes = {
languageProfileId: PropTypes.number.isRequired,
name: PropTypes.string.isRequired
};
export default connect(createMapStateToProps)(LanguageProfileNameConnector);
@@ -1,21 +0,0 @@
.languageProfiles {
display: flex;
flex-wrap: wrap;
}
.addLanguageProfile {
composes: languageProfile from '~./LanguageProfile.css';
background-color: $cardAlternateBackgroundColor;
color: $gray;
text-align: center;
font-size: 45px;
}
.center {
display: inline-block;
padding: 5px 20px 0;
border: 1px solid $borderColor;
border-radius: 4px;
background-color: $white;
}
@@ -1,107 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import sortByName from 'Utilities/Array/sortByName';
import { icons } from 'Helpers/Props';
import FieldSet from 'Components/FieldSet';
import Card from 'Components/Card';
import Icon from 'Components/Icon';
import PageSectionContent from 'Components/Page/PageSectionContent';
import LanguageProfile from './LanguageProfile';
import EditLanguageProfileModalConnector from './EditLanguageProfileModalConnector';
import styles from './LanguageProfiles.css';
class LanguageProfiles extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
isLanguageProfileModalOpen: false
};
}
//
// Listeners
onCloneLanguageProfilePress = (id) => {
this.props.onCloneLanguageProfilePress(id);
this.setState({ isLanguageProfileModalOpen: true });
}
onEditLanguageProfilePress = () => {
this.setState({ isLanguageProfileModalOpen: true });
}
onModalClose = () => {
this.setState({ isLanguageProfileModalOpen: false });
}
//
// Render
render() {
const {
items,
isDeleting,
onConfirmDeleteLanguageProfile,
...otherProps
} = this.props;
return (
<FieldSet legend="Language Profiles">
<PageSectionContent
errorMessage="Unable to load Language Profiles"
{...otherProps}
>
<div className={styles.languageProfiles}>
{
items.sort(sortByName).map((item) => {
return (
<LanguageProfile
key={item.id}
{...item}
isDeleting={isDeleting}
onConfirmDeleteLanguageProfile={onConfirmDeleteLanguageProfile}
onCloneLanguageProfilePress={this.onCloneLanguageProfilePress}
/>
);
})
}
<Card
className={styles.addLanguageProfile}
onPress={this.onEditLanguageProfilePress}
>
<div className={styles.center}>
<Icon
name={icons.ADD}
size={45}
/>
</div>
</Card>
</div>
<EditLanguageProfileModalConnector
isOpen={this.state.isLanguageProfileModalOpen}
onModalClose={this.onModalClose}
/>
</PageSectionContent>
</FieldSet>
);
}
}
LanguageProfiles.propTypes = {
advancedSettings: PropTypes.bool.isRequired,
isFetching: PropTypes.bool.isRequired,
error: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
isDeleting: PropTypes.bool.isRequired,
onConfirmDeleteLanguageProfile: PropTypes.func.isRequired,
onCloneLanguageProfilePress: PropTypes.func.isRequired
};
export default LanguageProfiles;
@@ -1,67 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { fetchLanguageProfiles, deleteLanguageProfile, cloneLanguageProfile } from 'Store/Actions/settingsActions';
import LanguageProfiles from './LanguageProfiles';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.advancedSettings,
(state) => state.settings.languageProfiles,
(advancedSettings, languageProfiles) => {
return {
advancedSettings,
...languageProfiles
};
}
);
}
const mapDispatchToProps = {
dispatchFetchLanguageProfiles: fetchLanguageProfiles,
dispatchDeleteLanguageProfile: deleteLanguageProfile,
dispatchCloneLanguageProfile: cloneLanguageProfile
};
class LanguageProfilesConnector extends Component {
//
// Lifecycle
componentDidMount() {
this.props.dispatchFetchLanguageProfiles();
}
//
// Listeners
onConfirmDeleteLanguageProfile = (id) => {
this.props.dispatchDeleteLanguageProfile({ id });
}
onCloneLanguageProfilePress = (id) => {
this.props.dispatchCloneLanguageProfile({ id });
}
//
// Render
render() {
return (
<LanguageProfiles
onConfirmDeleteLanguageProfile={this.onConfirmDeleteLanguageProfile}
onCloneLanguageProfilePress={this.onCloneLanguageProfilePress}
{...this.props}
/>
);
}
}
LanguageProfilesConnector.propTypes = {
dispatchFetchLanguageProfiles: PropTypes.func.isRequired,
dispatchDeleteLanguageProfile: PropTypes.func.isRequired,
dispatchCloneLanguageProfile: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(LanguageProfilesConnector);
@@ -5,7 +5,6 @@ import PageContent from 'Components/Page/PageContent';
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import QualityProfilesConnector from './Quality/QualityProfilesConnector';
import LanguageProfilesConnector from './Language/LanguageProfilesConnector';
import MetadataProfilesConnector from './Metadata/MetadataProfilesConnector';
import DelayProfilesConnector from './Delay/DelayProfilesConnector';
import ReleaseProfilesConnector from './Release/ReleaseProfilesConnector';
@@ -24,7 +23,6 @@ class Profiles extends Component {
<PageContentBodyConnector>
<QualityProfilesConnector />
<LanguageProfilesConnector />
<MetadataProfilesConnector />
<DelayProfilesConnector />
<ReleaseProfilesConnector />