mirror of
https://github.com/Readarr/Readarr.git
synced 2026-04-18 21:34:28 -04:00
New: Release Profiles, Frontend updates (#580)
* New: Release Profiles - UI Updates * New: Release Profiles - API Changes * New: Release Profiles - Test Updates * New: Release Profiles - Backend Updates * New: Interactive Artist Search * New: Change Montiored on Album Details Page * New: Show Duration on Album Details Page * Fixed: Manual Import not working if no albums are Missing * Fixed: Sort search input by sortTitle * Fixed: Queue columnLabel throwing JS error
This commit is contained in:
@@ -3,15 +3,18 @@
|
||||
overflow-x: hidden;
|
||||
padding: 5px;
|
||||
border-bottom: 1px solid $borderColor;
|
||||
font-size: 14px;
|
||||
font-size: $defaultFontSize;
|
||||
|
||||
&:hover {
|
||||
background-color: $tableRowHoverBackgroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
.status {
|
||||
width: 10px;
|
||||
.eventWrapper {
|
||||
display: flex;
|
||||
flex: 1 0 1px;
|
||||
overflow-x: hidden;
|
||||
padding-left: 6px;
|
||||
border-left-width: 4px;
|
||||
border-left-style: solid;
|
||||
}
|
||||
@@ -24,6 +27,7 @@
|
||||
.time {
|
||||
flex: 0 0 120px;
|
||||
margin-right: 10px;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.artistName,
|
||||
@@ -80,16 +84,16 @@
|
||||
|
||||
@media only screen and (max-width: $breakpointSmall) {
|
||||
.event {
|
||||
position: relative;
|
||||
flex-wrap: wrap;
|
||||
padding-left: 10px;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.status {
|
||||
position: absolute;
|
||||
top: 7%;
|
||||
left: 0;
|
||||
height: 86%;
|
||||
.eventWrapper {
|
||||
display: block;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.date {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.date,
|
||||
|
||||
@@ -49,7 +49,8 @@ class AgendaEvent extends Component {
|
||||
queueItem,
|
||||
showDate,
|
||||
timeFormat,
|
||||
longDateFormat
|
||||
longDateFormat,
|
||||
colorImpairedMode
|
||||
} = this.props;
|
||||
|
||||
const startTime = moment(releaseDate);
|
||||
@@ -74,8 +75,9 @@ class AgendaEvent extends Component {
|
||||
|
||||
<div
|
||||
className={classNames(
|
||||
styles.status,
|
||||
styles[statusStyle]
|
||||
styles.eventWrapper,
|
||||
styles[statusStyle],
|
||||
colorImpairedMode && 'colorImpaired'
|
||||
)}
|
||||
/>
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@ function createMapStateToProps() {
|
||||
artist,
|
||||
queueItem,
|
||||
timeFormat: uiSettings.timeFormat,
|
||||
longDateFormat: uiSettings.longDateFormat
|
||||
longDateFormat: uiSettings.longDateFormat,
|
||||
colorImpairedMode: uiSettings.enableColorImpairedMode
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
@@ -41,8 +41,20 @@ class CalendarConnector extends Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
useCurrentPage,
|
||||
fetchCalendar,
|
||||
gotoCalendarToday
|
||||
} = this.props;
|
||||
|
||||
registerPagePopulator(this.repopulate);
|
||||
this.props.gotoCalendarToday();
|
||||
|
||||
if (useCurrentPage) {
|
||||
fetchCalendar();
|
||||
} else {
|
||||
gotoCalendarToday();
|
||||
}
|
||||
|
||||
this.scheduleUpdate();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
||||
import FilterMenu from 'Components/Menu/FilterMenu';
|
||||
import NoArtist from 'Artist/NoArtist';
|
||||
import CalendarLinkModal from './iCal/CalendarLinkModal';
|
||||
import Legend from './Legend/Legend';
|
||||
import CalendarOptionsModal from './Options/CalendarOptionsModal';
|
||||
import LegendConnector from './Legend/LegendConnector';
|
||||
import CalendarConnector from './CalendarConnector';
|
||||
import styles from './CalendarPage.css';
|
||||
|
||||
@@ -26,6 +27,7 @@ class CalendarPage extends Component {
|
||||
|
||||
this.state = {
|
||||
isCalendarLinkModalOpen: false,
|
||||
isOptionsModalOpen: false,
|
||||
width: 0
|
||||
};
|
||||
}
|
||||
@@ -48,6 +50,23 @@ class CalendarPage extends Component {
|
||||
this.setState({ isCalendarLinkModalOpen: false });
|
||||
}
|
||||
|
||||
onOptionsPress = () => {
|
||||
this.setState({ isOptionsModalOpen: true });
|
||||
}
|
||||
|
||||
onOptionsModalClose = () => {
|
||||
this.setState({ isOptionsModalOpen: false });
|
||||
}
|
||||
|
||||
onSearchMissingPress = () => {
|
||||
const {
|
||||
missingAlbumIds,
|
||||
onSearchMissingPress
|
||||
} = this.props;
|
||||
|
||||
onSearchMissingPress(missingAlbumIds);
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
@@ -56,17 +75,20 @@ class CalendarPage extends Component {
|
||||
selectedFilterKey,
|
||||
filters,
|
||||
hasArtist,
|
||||
colorImpairedMode,
|
||||
missingAlbumIds,
|
||||
isSearchingForMissing,
|
||||
useCurrentPage,
|
||||
onFilterSelect
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
isCalendarLinkModalOpen,
|
||||
isOptionsModalOpen
|
||||
} = this.state;
|
||||
|
||||
const isMeasured = this.state.width > 0;
|
||||
|
||||
let PageComponent = 'div';
|
||||
|
||||
if (isMeasured) {
|
||||
PageComponent = hasArtist ? CalendarConnector : NoArtist;
|
||||
}
|
||||
const PageComponent = hasArtist ? CalendarConnector : NoArtist;
|
||||
|
||||
return (
|
||||
<PageContent title="Calendar">
|
||||
@@ -77,9 +99,23 @@ class CalendarPage extends Component {
|
||||
iconName={icons.CALENDAR}
|
||||
onPress={this.onGetCalendarLinkPress}
|
||||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label="Search for Missing"
|
||||
iconName={icons.SEARCH}
|
||||
isDisabled={!missingAlbumIds.length}
|
||||
isSpinning={isSearchingForMissing}
|
||||
onPress={this.onSearchMissingPress}
|
||||
/>
|
||||
</PageToolbarSection>
|
||||
|
||||
<PageToolbarSection alignContent={align.RIGHT}>
|
||||
<PageToolbarButton
|
||||
label="Options"
|
||||
iconName={icons.POSTER}
|
||||
onPress={this.onOptionsPress}
|
||||
/>
|
||||
|
||||
<FilterMenu
|
||||
alignMenu={align.RIGHT}
|
||||
isDisabled={!hasArtist}
|
||||
@@ -99,19 +135,31 @@ class CalendarPage extends Component {
|
||||
whitelist={['width']}
|
||||
onMeasure={this.onMeasure}
|
||||
>
|
||||
<PageComponent />
|
||||
{
|
||||
isMeasured ?
|
||||
<PageComponent
|
||||
useCurrentPage={useCurrentPage}
|
||||
/> :
|
||||
<div />
|
||||
}
|
||||
</Measure>
|
||||
|
||||
{
|
||||
hasArtist &&
|
||||
<Legend colorImpairedMode={colorImpairedMode} />
|
||||
<LegendConnector />
|
||||
}
|
||||
</PageContentBodyConnector>
|
||||
|
||||
<CalendarLinkModal
|
||||
isOpen={this.state.isCalendarLinkModalOpen}
|
||||
isOpen={isCalendarLinkModalOpen}
|
||||
onModalClose={this.onGetCalendarLinkModalClose}
|
||||
/>
|
||||
|
||||
<CalendarOptionsModal
|
||||
isOpen={isOptionsModalOpen}
|
||||
onModalClose={this.onOptionsModalClose}
|
||||
/>
|
||||
|
||||
</PageContent>
|
||||
);
|
||||
}
|
||||
@@ -121,7 +169,10 @@ CalendarPage.propTypes = {
|
||||
selectedFilterKey: PropTypes.string.isRequired,
|
||||
filters: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
hasArtist: PropTypes.bool.isRequired,
|
||||
colorImpairedMode: PropTypes.bool.isRequired,
|
||||
missingAlbumIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
isSearchingForMissing: PropTypes.bool.isRequired,
|
||||
useCurrentPage: PropTypes.bool.isRequired,
|
||||
onSearchMissingPress: PropTypes.func.isRequired,
|
||||
onDaysCountChange: PropTypes.func.isRequired,
|
||||
onFilterSelect: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
@@ -1,22 +1,80 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { setCalendarDaysCount, setCalendarFilter } from 'Store/Actions/calendarActions';
|
||||
import moment from 'moment';
|
||||
import { isCommandExecuting } from 'Utilities/Command';
|
||||
import isBefore from 'Utilities/Date/isBefore';
|
||||
import withCurrentPage from 'Components/withCurrentPage';
|
||||
import { searchMissing, setCalendarDaysCount, setCalendarFilter } from 'Store/Actions/calendarActions';
|
||||
import createArtistCountSelector from 'Store/Selectors/createArtistCountSelector';
|
||||
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
|
||||
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
|
||||
import CalendarPage from './CalendarPage';
|
||||
|
||||
function createMissingAlbumIdsSelector() {
|
||||
return createSelector(
|
||||
(state) => state.calendar.start,
|
||||
(state) => state.calendar.end,
|
||||
(state) => state.calendar.items,
|
||||
(state) => state.queue.details.items,
|
||||
(start, end, albums, queueDetails) => {
|
||||
return albums.reduce((acc, album) => {
|
||||
const releaseDate = album.releaseDate;
|
||||
|
||||
if (
|
||||
album.percentOfTracks < 100 &&
|
||||
moment(releaseDate).isAfter(start) &&
|
||||
moment(releaseDate).isBefore(end) &&
|
||||
isBefore(album.releaseDate) &&
|
||||
!queueDetails.some((details) => !!details.album && details.album.id === album.id)
|
||||
) {
|
||||
acc.push(album.id);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function createIsSearchingSelector() {
|
||||
return createSelector(
|
||||
(state) => state.calendar.searchMissingCommandId,
|
||||
createCommandsSelector(),
|
||||
(searchMissingCommandId, commands) => {
|
||||
if (searchMissingCommandId == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isCommandExecuting(commands.find((command) => {
|
||||
return command.id === searchMissingCommandId;
|
||||
}));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.calendar,
|
||||
(state) => state.calendar.selectedFilterKey,
|
||||
(state) => state.calendar.filters,
|
||||
createArtistCountSelector(),
|
||||
createUISettingsSelector(),
|
||||
(calendar, artistCount, uiSettings) => {
|
||||
createMissingAlbumIdsSelector(),
|
||||
createIsSearchingSelector(),
|
||||
(
|
||||
selectedFilterKey,
|
||||
filters,
|
||||
artistCount,
|
||||
uiSettings,
|
||||
missingAlbumIds,
|
||||
isSearchingForMissing
|
||||
) => {
|
||||
return {
|
||||
selectedFilterKey: calendar.selectedFilterKey,
|
||||
filters: calendar.filters,
|
||||
showUpcoming: calendar.showUpcoming,
|
||||
selectedFilterKey,
|
||||
filters,
|
||||
colorImpairedMode: uiSettings.enableColorImpairedMode,
|
||||
hasArtist: !!artistCount
|
||||
hasArtist: !!artistCount,
|
||||
missingAlbumIds,
|
||||
isSearchingForMissing
|
||||
};
|
||||
}
|
||||
);
|
||||
@@ -24,6 +82,9 @@ function createMapStateToProps() {
|
||||
|
||||
function createMapDispatchToProps(dispatch, props) {
|
||||
return {
|
||||
onSearchMissingPress(albumIds) {
|
||||
dispatch(searchMissing({ albumIds }));
|
||||
},
|
||||
onDaysCountChange(dayCount) {
|
||||
dispatch(setCalendarDaysCount({ dayCount }));
|
||||
},
|
||||
@@ -34,4 +95,6 @@ function createMapDispatchToProps(dispatch, props) {
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(createMapStateToProps, createMapDispatchToProps)(CalendarPage);
|
||||
export default withCurrentPage(
|
||||
connect(createMapStateToProps, createMapDispatchToProps)(CalendarPage)
|
||||
);
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
.artistName {
|
||||
color: #3a3f51;
|
||||
font-size: 14px;
|
||||
font-size: $defaultFontSize;
|
||||
}
|
||||
|
||||
.absoluteEpisodeNumber {
|
||||
@@ -53,7 +53,7 @@
|
||||
border-left-color: $gray;
|
||||
|
||||
&:global(.colorImpaired) {
|
||||
background: repeating-linear-gradient(45deg, transparent, transparent 5px, #eee 5px, #eee 10px);
|
||||
background: repeating-linear-gradient(45deg, transparent, transparent 5px, $colorImpairedGradient 5px, $colorImpairedGradient 10px);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
border-left-color: $dangerColor;
|
||||
|
||||
&:global(.colorImpaired) {
|
||||
background: repeating-linear-gradient(90deg, transparent, transparent 5px, #eee 5px, #eee 10px);
|
||||
background: repeating-linear-gradient(90deg, transparent, transparent 5px, $colorImpairedGradient 5px, $colorImpairedGradient 10px);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,6 @@
|
||||
border-left-color: $blue;
|
||||
|
||||
&:global(.colorImpaired) {
|
||||
background: repeating-linear-gradient(90deg, transparent, transparent 5px, #eee 5px, #eee 10px);
|
||||
background: repeating-linear-gradient(90deg, transparent, transparent 5px, $colorImpairedGradient 5px, $colorImpairedGradient 10px);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import React, { Component } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import getStatusStyle from 'Calendar/getStatusStyle';
|
||||
import albumEntities from 'Album/albumEntities';
|
||||
import Icon from 'Components/Icon';
|
||||
import Link from 'Components/Link/Link';
|
||||
import CalendarEventQueueDetails from './CalendarEventQueueDetails';
|
||||
|
||||
@@ -1,9 +1,29 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import LegendItem from './LegendItem';
|
||||
import LegendIconItem from './LegendIconItem';
|
||||
import styles from './Legend.css';
|
||||
|
||||
function Legend({ colorImpairedMode }) {
|
||||
function Legend(props) {
|
||||
const {
|
||||
showCutoffUnmetIcon,
|
||||
colorImpairedMode
|
||||
} = props;
|
||||
|
||||
const iconsToShow = [];
|
||||
|
||||
if (showCutoffUnmetIcon) {
|
||||
iconsToShow.push(
|
||||
<LegendIconItem
|
||||
name="Cutoff Not Met"
|
||||
icon={icons.TRACK_FILE}
|
||||
kind={kinds.WARNING}
|
||||
tooltip="Quality or language cutoff has not been met"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.legend}>
|
||||
<div>
|
||||
@@ -47,11 +67,24 @@ function Legend({ colorImpairedMode }) {
|
||||
colorImpairedMode={colorImpairedMode}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{iconsToShow[0]}
|
||||
</div>
|
||||
|
||||
{
|
||||
iconsToShow.length > 1 &&
|
||||
<div>
|
||||
{iconsToShow[1]}
|
||||
{iconsToShow[2]}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Legend.propTypes = {
|
||||
showCutoffUnmetIcon: PropTypes.bool.isRequired,
|
||||
colorImpairedMode: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
|
||||
import Legend from './Legend';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.calendar.options,
|
||||
createUISettingsSelector(),
|
||||
(calendarOptions, uiSettings) => {
|
||||
return {
|
||||
...calendarOptions,
|
||||
colorImpairedMode: uiSettings.enableColorImpairedMode
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(createMapStateToProps)(Legend);
|
||||
@@ -0,0 +1,10 @@
|
||||
.legendIconItem {
|
||||
margin: 3px 0;
|
||||
margin-right: 6px;
|
||||
width: 150px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Icon from 'Components/Icon';
|
||||
import styles from './LegendIconItem.css';
|
||||
|
||||
function LegendIconItem(props) {
|
||||
const {
|
||||
name,
|
||||
icon,
|
||||
kind,
|
||||
tooltip
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={styles.legendIconItem}
|
||||
title={tooltip}
|
||||
>
|
||||
<Icon
|
||||
className={styles.icon}
|
||||
name={icon}
|
||||
kind={kind}
|
||||
/>
|
||||
|
||||
{name}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
LegendIconItem.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
icon: PropTypes.object.isRequired,
|
||||
kind: PropTypes.string.isRequired,
|
||||
tooltip: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default LegendIconItem;
|
||||
@@ -0,0 +1,29 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import CalendarOptionsModalContentConnector from './CalendarOptionsModalContentConnector';
|
||||
|
||||
function CalendarOptionsModal(props) {
|
||||
const {
|
||||
isOpen,
|
||||
onModalClose
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<CalendarOptionsModalContentConnector
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
CalendarOptionsModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default CalendarOptionsModal;
|
||||
@@ -0,0 +1,216 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { inputTypes } from 'Helpers/Props';
|
||||
import FieldSet from 'Components/FieldSet';
|
||||
import Button from 'Components/Link/Button';
|
||||
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 ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import { firstDayOfWeekOptions, weekColumnOptions, timeFormatOptions } from 'Settings/UI/UISettings';
|
||||
|
||||
class CalendarOptionsModalContent extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
const {
|
||||
firstDayOfWeek,
|
||||
calendarWeekColumnHeader,
|
||||
timeFormat,
|
||||
enableColorImpairedMode
|
||||
} = props;
|
||||
|
||||
this.state = {
|
||||
firstDayOfWeek,
|
||||
calendarWeekColumnHeader,
|
||||
timeFormat,
|
||||
enableColorImpairedMode
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
firstDayOfWeek,
|
||||
calendarWeekColumnHeader,
|
||||
timeFormat,
|
||||
enableColorImpairedMode
|
||||
} = this.props;
|
||||
|
||||
if (
|
||||
prevProps.firstDayOfWeek !== firstDayOfWeek ||
|
||||
prevProps.calendarWeekColumnHeader !== calendarWeekColumnHeader ||
|
||||
prevProps.timeFormat !== timeFormat ||
|
||||
prevProps.enableColorImpairedMode !== enableColorImpairedMode
|
||||
) {
|
||||
this.setState({
|
||||
firstDayOfWeek,
|
||||
calendarWeekColumnHeader,
|
||||
timeFormat,
|
||||
enableColorImpairedMode
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onOptionInputChange = ({ name, value }) => {
|
||||
const {
|
||||
dispatchSetCalendarOption
|
||||
} = this.props;
|
||||
|
||||
dispatchSetCalendarOption({ [name]: value });
|
||||
}
|
||||
|
||||
onGlobalInputChange = ({ name, value }) => {
|
||||
const {
|
||||
dispatchSaveUISettings
|
||||
} = this.props;
|
||||
|
||||
const setting = { [name]: value };
|
||||
|
||||
this.setState(setting, () => {
|
||||
dispatchSaveUISettings(setting);
|
||||
});
|
||||
}
|
||||
|
||||
onLinkFocus = (event) => {
|
||||
event.target.select();
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
collapseMultipleAlbums,
|
||||
showCutoffUnmetIcon,
|
||||
onModalClose
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
firstDayOfWeek,
|
||||
calendarWeekColumnHeader,
|
||||
timeFormat,
|
||||
enableColorImpairedMode
|
||||
} = this.state;
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
Calendar Options
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
<FieldSet legend="Local">
|
||||
<Form>
|
||||
<FormGroup>
|
||||
<FormLabel>Collapse Multiple Albums</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="collapseMultipleAlbums"
|
||||
value={collapseMultipleAlbums}
|
||||
helpText="Collapse multiple albums releasing on the same day"
|
||||
onChange={this.onOptionInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Icon for Cutoff Unmet</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="showCutoffUnmetIcon"
|
||||
value={showCutoffUnmetIcon}
|
||||
helpText="Show icon for files when the cutoff hasn't been met"
|
||||
onChange={this.onOptionInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
</FieldSet>
|
||||
|
||||
<FieldSet legend="Global">
|
||||
<Form>
|
||||
<FormGroup>
|
||||
<FormLabel>First Day of Week</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="firstDayOfWeek"
|
||||
values={firstDayOfWeekOptions}
|
||||
value={firstDayOfWeek}
|
||||
onChange={this.onGlobalInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Week Column Header</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="calendarWeekColumnHeader"
|
||||
values={weekColumnOptions}
|
||||
value={calendarWeekColumnHeader}
|
||||
onChange={this.onGlobalInputChange}
|
||||
helpText="Shown above each column when week is the active view"
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Time Format</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="timeFormat"
|
||||
values={timeFormatOptions}
|
||||
value={timeFormat}
|
||||
onChange={this.onGlobalInputChange}
|
||||
/>
|
||||
</FormGroup><FormGroup>
|
||||
<FormLabel>Enable Color-Impaired Mode</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="enableColorImpairedMode"
|
||||
value={enableColorImpairedMode}
|
||||
helpText="Altered style to allow color-impaired users to better distinguish color coded information"
|
||||
onChange={this.onGlobalInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
</Form>
|
||||
</FieldSet>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button onPress={onModalClose}>
|
||||
Close
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
CalendarOptionsModalContent.propTypes = {
|
||||
collapseMultipleAlbums: PropTypes.bool.isRequired,
|
||||
showCutoffUnmetIcon: PropTypes.bool.isRequired,
|
||||
firstDayOfWeek: PropTypes.number.isRequired,
|
||||
calendarWeekColumnHeader: PropTypes.string.isRequired,
|
||||
timeFormat: PropTypes.string.isRequired,
|
||||
enableColorImpairedMode: PropTypes.bool.isRequired,
|
||||
dispatchSetCalendarOption: PropTypes.func.isRequired,
|
||||
dispatchSaveUISettings: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default CalendarOptionsModalContent;
|
||||
@@ -0,0 +1,25 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { setCalendarOption } from 'Store/Actions/calendarActions';
|
||||
import CalendarOptionsModalContent from './CalendarOptionsModalContent';
|
||||
import { saveUISettings } from 'Store/Actions/settingsActions';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.calendar.options,
|
||||
(state) => state.settings.ui.item,
|
||||
(options, uiSettings) => {
|
||||
return {
|
||||
...options,
|
||||
...uiSettings
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
dispatchSetCalendarOption: setCalendarOption,
|
||||
dispatchSaveUISettings: saveUISettings
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(CalendarOptionsModalContent);
|
||||
Reference in New Issue
Block a user