Skip to content

Commit

Permalink
New: Indexer flags
Browse files Browse the repository at this point in the history
(cherry picked from commit 7a768b5d0faf9aa57e78aee19cefee8fb19a42d5)
  • Loading branch information
mynameisbogdan committed Mar 10, 2024
1 parent 4781675 commit d0df761
Show file tree
Hide file tree
Showing 59 changed files with 877 additions and 29 deletions.
3 changes: 3 additions & 0 deletions frontend/src/App/State/SettingsAppState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import AppSectionState, {
import DownloadClient from 'typings/DownloadClient';
import ImportList from 'typings/ImportList';
import Indexer from 'typings/Indexer';
import IndexerFlag from 'typings/IndexerFlag';
import Notification from 'typings/Notification';
import { UiSettings } from 'typings/UiSettings';

Expand All @@ -27,11 +28,13 @@ export interface NotificationAppState
extends AppSectionState<Notification>,
AppSectionDeleteState {}

export type IndexerFlagSettingsAppState = AppSectionState<IndexerFlag>;
export type UiSettingsAppState = AppSectionState<UiSettings>;

interface SettingsAppState {
downloadClients: DownloadClientAppState;
importLists: ImportListAppState;
indexerFlags: IndexerFlagSettingsAppState;
indexers: IndexerAppState;
notifications: NotificationAppState;
uiSettings: UiSettingsAppState;
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/Author/Details/BookRow.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,9 @@

width: 80px;
}

.indexerFlags {
composes: cell from '~Components/Table/Cells/TableRowCell.css';

width: 50px;
}
1 change: 1 addition & 0 deletions frontend/src/Author/Details/BookRow.css.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'indexerFlags': string;
'monitored': string;
'pageCount': string;
'position': string;
Expand Down
29 changes: 29 additions & 0 deletions frontend/src/Author/Details/BookRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import BookSearchCellConnector from 'Book/BookSearchCellConnector';
import BookTitleLink from 'Book/BookTitleLink';
import IndexerFlags from 'Book/IndexerFlags';
import Icon from 'Components/Icon';
import MonitorToggleButton from 'Components/MonitorToggleButton';
import StarRating from 'Components/StarRating';
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import TableRow from 'Components/Table/TableRow';
import Popover from 'Components/Tooltip/Popover';
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import BookStatus from './BookStatus';
import styles from './BookRow.css';

Expand Down Expand Up @@ -67,6 +72,7 @@ class BookRow extends Component {
authorMonitored,
titleSlug,
bookFiles,
indexerFlags,
isEditorActive,
isSelected,
onSelectedChange,
Expand Down Expand Up @@ -190,6 +196,24 @@ class BookRow extends Component {
);
}

if (name === 'indexerFlags') {
return (
<TableRowCell
key={name}
className={styles.indexerFlags}
>
{indexerFlags ? (
<Popover
anchor={<Icon name={icons.FLAG} kind={kinds.PRIMARY} />}
title={translate('IndexerFlags')}
body={<IndexerFlags indexerFlags={indexerFlags} />}
position={tooltipPositions.LEFT}
/>
) : null}
</TableRowCell>
);
}

if (name === 'status') {
return (
<TableRowCell
Expand Down Expand Up @@ -235,6 +259,7 @@ BookRow.propTypes = {
position: PropTypes.string,
pageCount: PropTypes.number,
ratings: PropTypes.object.isRequired,
indexerFlags: PropTypes.number.isRequired,
titleSlug: PropTypes.string.isRequired,
isSaving: PropTypes.bool,
authorMonitored: PropTypes.bool.isRequired,
Expand All @@ -246,4 +271,8 @@ BookRow.propTypes = {
onMonitorBookPress: PropTypes.func.isRequired
};

BookRow.defaultProps = {
indexerFlags: 0
};

export default BookRow;
15 changes: 8 additions & 7 deletions frontend/src/Author/Details/BookRowConnector.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,18 @@ import BookRow from './BookRow';
const selectBookFiles = createSelector(
(state) => state.bookFiles,
(bookFiles) => {
const {
items
} = bookFiles;
const { items } = bookFiles;

const bookFileDict = items.reduce((acc, file) => {
return items.reduce((acc, file) => {
const bookId = file.bookId;
if (!acc.hasOwnProperty(bookId)) {
acc[bookId] = [];
}

acc[bookId].push(file);

return acc;
}, {});

return bookFileDict;
}
);

Expand All @@ -31,10 +28,14 @@ function createMapStateToProps() {
selectBookFiles,
(state, { id }) => id,
(author = {}, bookFiles, bookId) => {
const files = bookFiles[bookId] ?? [];
const bookFile = files[0];

return {
authorMonitored: author.monitored,
authorName: author.authorName,
bookFiles: bookFiles[bookId] ?? []
bookFiles: files,
indexerFlags: bookFile ? bookFile.indexerFlags : 0
};
}
);
Expand Down
26 changes: 26 additions & 0 deletions frontend/src/Book/IndexerFlags.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import { useSelector } from 'react-redux';
import createIndexerFlagsSelector from 'Store/Selectors/createIndexerFlagsSelector';

interface IndexerFlagsProps {
indexerFlags: number;
}

function IndexerFlags({ indexerFlags = 0 }: IndexerFlagsProps) {
const allIndexerFlags = useSelector(createIndexerFlagsSelector);

const flags = allIndexerFlags.items.filter(
// eslint-disable-next-line no-bitwise
(item) => (indexerFlags & item.id) === item.id
);

return flags.length ? (
<ul>
{flags.map((flag, index) => {
return <li key={index}>{flag.name}</li>;
})}
</ul>
) : null;
}

export default IndexerFlags;
5 changes: 5 additions & 0 deletions frontend/src/Components/Form/FormInputGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import DownloadClientSelectInputConnector from './DownloadClientSelectInputConne
import EnhancedSelectInput from './EnhancedSelectInput';
import EnhancedSelectInputConnector from './EnhancedSelectInputConnector';
import FormInputHelpText from './FormInputHelpText';
import IndexerFlagsSelectInput from './IndexerFlagsSelectInput';
import IndexerSelectInputConnector from './IndexerSelectInputConnector';
import KeyValueListInput from './KeyValueListInput';
import MetadataProfileSelectInputConnector from './MetadataProfileSelectInputConnector';
Expand Down Expand Up @@ -83,6 +84,9 @@ function getComponent(type) {
case inputTypes.INDEXER_SELECT:
return IndexerSelectInputConnector;

case inputTypes.INDEXER_FLAGS_SELECT:
return IndexerFlagsSelectInput;

case inputTypes.DOWNLOAD_CLIENT_SELECT:
return DownloadClientSelectInputConnector;

Expand Down Expand Up @@ -288,6 +292,7 @@ FormInputGroup.propTypes = {
includeNoChange: PropTypes.bool,
includeNoChangeDisabled: PropTypes.bool,
selectedValueOptions: PropTypes.object,
indexerFlags: PropTypes.number,
pending: PropTypes.bool,
errors: PropTypes.arrayOf(PropTypes.object),
warnings: PropTypes.arrayOf(PropTypes.object),
Expand Down
62 changes: 62 additions & 0 deletions frontend/src/Components/Form/IndexerFlagsSelectInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React, { useCallback } from 'react';
import { useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import EnhancedSelectInput from './EnhancedSelectInput';

const selectIndexerFlagsValues = (selectedFlags: number) =>
createSelector(
(state: AppState) => state.settings.indexerFlags,
(indexerFlags) => {
const value = indexerFlags.items.reduce((acc: number[], { id }) => {
// eslint-disable-next-line no-bitwise
if ((selectedFlags & id) === id) {
acc.push(id);
}

return acc;
}, []);

const values = indexerFlags.items.map(({ id, name }) => ({
key: id,
value: name,
}));

return {
value,
values,
};
}
);

interface IndexerFlagsSelectInputProps {
name: string;
indexerFlags: number;
onChange(payload: object): void;
}

function IndexerFlagsSelectInput(props: IndexerFlagsSelectInputProps) {
const { indexerFlags, onChange } = props;

const { value, values } = useSelector(selectIndexerFlagsValues(indexerFlags));

const onChangeWrapper = useCallback(
({ name, value }: { name: string; value: number[] }) => {
const indexerFlags = value.reduce((acc, flagId) => acc + flagId, 0);

onChange({ name, value: indexerFlags });
},
[onChange]
);

return (
<EnhancedSelectInput
{...props}
value={value}
values={values}
onChange={onChangeWrapper}
/>
);
}

export default IndexerFlagsSelectInput;
22 changes: 21 additions & 1 deletion frontend/src/Components/Page/PageConnector.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ import { fetchTranslations, saveDimensions, setIsSidebarVisible } from 'Store/Ac
import { fetchAuthor } from 'Store/Actions/authorActions';
import { fetchBooks } from 'Store/Actions/bookActions';
import { fetchCustomFilters } from 'Store/Actions/customFilterActions';
import { fetchImportLists, fetchLanguages, fetchMetadataProfiles, fetchQualityProfiles, fetchUISettings } from 'Store/Actions/settingsActions';
import {
fetchImportLists,
fetchIndexerFlags,
fetchLanguages,
fetchMetadataProfiles,
fetchQualityProfiles,
fetchUISettings
} from 'Store/Actions/settingsActions';
import { fetchStatus } from 'Store/Actions/systemActions';
import { fetchTags } from 'Store/Actions/tagActions';
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
Expand Down Expand Up @@ -51,6 +58,7 @@ const selectIsPopulated = createSelector(
(state) => state.settings.qualityProfiles.isPopulated,
(state) => state.settings.metadataProfiles.isPopulated,
(state) => state.settings.importLists.isPopulated,
(state) => state.settings.indexerFlags.isPopulated,
(state) => state.system.status.isPopulated,
(state) => state.app.translations.isPopulated,
(
Expand All @@ -61,6 +69,7 @@ const selectIsPopulated = createSelector(
qualityProfilesIsPopulated,
metadataProfilesIsPopulated,
importListsIsPopulated,
indexerFlagsIsPopulated,
systemStatusIsPopulated,
translationsIsPopulated
) => {
Expand All @@ -72,6 +81,7 @@ const selectIsPopulated = createSelector(
qualityProfilesIsPopulated &&
metadataProfilesIsPopulated &&
importListsIsPopulated &&
indexerFlagsIsPopulated &&
systemStatusIsPopulated &&
translationsIsPopulated
);
Expand All @@ -86,6 +96,7 @@ const selectErrors = createSelector(
(state) => state.settings.qualityProfiles.error,
(state) => state.settings.metadataProfiles.error,
(state) => state.settings.importLists.error,
(state) => state.settings.indexerFlags.error,
(state) => state.system.status.error,
(state) => state.app.translations.error,
(
Expand All @@ -96,6 +107,7 @@ const selectErrors = createSelector(
qualityProfilesError,
metadataProfilesError,
importListsError,
indexerFlagsError,
systemStatusError,
translationsError
) => {
Expand All @@ -107,6 +119,7 @@ const selectErrors = createSelector(
qualityProfilesError ||
metadataProfilesError ||
importListsError ||
indexerFlagsError ||
systemStatusError ||
translationsError
);
Expand All @@ -120,6 +133,7 @@ const selectErrors = createSelector(
qualityProfilesError,
metadataProfilesError,
importListsError,
indexerFlagsError,
systemStatusError,
translationsError
};
Expand Down Expand Up @@ -177,6 +191,9 @@ function createMapDispatchToProps(dispatch, props) {
dispatchFetchImportLists() {
dispatch(fetchImportLists());
},
dispatchFetchIndexerFlags() {
dispatch(fetchIndexerFlags());
},
dispatchFetchUISettings() {
dispatch(fetchUISettings());
},
Expand Down Expand Up @@ -218,6 +235,7 @@ class PageConnector extends Component {
this.props.dispatchFetchQualityProfiles();
this.props.dispatchFetchMetadataProfiles();
this.props.dispatchFetchImportLists();
this.props.dispatchFetchIndexerFlags();
this.props.dispatchFetchUISettings();
this.props.dispatchFetchStatus();
this.props.dispatchFetchTranslations();
Expand Down Expand Up @@ -245,6 +263,7 @@ class PageConnector extends Component {
dispatchFetchQualityProfiles,
dispatchFetchMetadataProfiles,
dispatchFetchImportLists,
dispatchFetchIndexerFlags,
dispatchFetchUISettings,
dispatchFetchStatus,
dispatchFetchTranslations,
Expand Down Expand Up @@ -287,6 +306,7 @@ PageConnector.propTypes = {
dispatchFetchQualityProfiles: PropTypes.func.isRequired,
dispatchFetchMetadataProfiles: PropTypes.func.isRequired,
dispatchFetchImportLists: PropTypes.func.isRequired,
dispatchFetchIndexerFlags: PropTypes.func.isRequired,
dispatchFetchUISettings: PropTypes.func.isRequired,
dispatchFetchStatus: PropTypes.func.isRequired,
dispatchFetchTranslations: PropTypes.func.isRequired,
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/Helpers/Props/icons.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import {
faFileImport as fasFileImport,
faFileInvoice as farFileInvoice,
faFilter as fasFilter,
faFlag as fasFlag,
faFolderOpen as fasFolderOpen,
faForward as fasForward,
faHeart as fasHeart,
Expand Down Expand Up @@ -155,6 +156,7 @@ export const FATAL = fasTimesCircle;
export const FILE = farFile;
export const FILEIMPORT = fasFileImport;
export const FILTER = fasFilter;
export const FLAG = fasFlag;
export const FOLDER = farFolder;
export const FOLDER_OPEN = fasFolderOpen;
export const GROUP = farObjectGroup;
Expand Down
1 change: 1 addition & 0 deletions frontend/src/Helpers/Props/inputTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const QUALITY_PROFILE_SELECT = 'qualityProfileSelect';
export const METADATA_PROFILE_SELECT = 'metadataProfileSelect';
export const BOOK_EDITION_SELECT = 'bookEditionSelect';
export const INDEXER_SELECT = 'indexerSelect';
export const INDEXER_FLAGS_SELECT = 'indexerFlagsSelect';
export const DOWNLOAD_CLIENT_SELECT = 'downloadClientSelect';
export const ROOT_FOLDER_SELECT = 'rootFolderSelect';
export const SELECT = 'select';
Expand Down

0 comments on commit d0df761

Please sign in to comment.