Add pagination support to history page

This commit is contained in:
LASER-Yi 2021-08-17 22:27:33 +08:00
parent 156cf1882c
commit 8348118ff2
15 changed files with 92 additions and 79 deletions

View File

@ -1419,7 +1419,8 @@ class EpisodesHistory(Resource):
if episodeid:
query_conditions.append((TableEpisodes.sonarrEpisodeId == episodeid))
query_condition = reduce(operator.and_, query_conditions)
episode_history = TableHistory.select(TableShows.title.alias('seriesTitle'),
episode_history = TableHistory.select(TableHistory.id,
TableShows.title.alias('seriesTitle'),
TableEpisodes.monitored,
TableEpisodes.season.concat('x').concat(TableEpisodes.episode).alias('episode_number'),
TableEpisodes.title.alias('episodeTitle'),
@ -1535,7 +1536,8 @@ class MoviesHistory(Resource):
query_conditions.append((TableMovies.radarrId == radarrid))
query_condition = reduce(operator.and_, query_conditions)
movie_history = TableHistoryMovie.select(TableHistoryMovie.action,
movie_history = TableHistoryMovie.select(TableHistoryMovie.id,
TableHistoryMovie.action,
TableMovies.title,
TableHistoryMovie.timestamp,
TableHistoryMovie.description,

View File

@ -55,15 +55,17 @@ export const movieUpdateWantedByRange = createAsyncThunk(
}
);
export const movieUpdateHistory = createAsyncThunk(
"movies/history/update",
async () => {
const response = await MoviesApi.history();
export const movieUpdateHistoryByRange = createAsyncThunk(
"movies/history/update/range",
async (params: Parameter.Range) => {
const response = await MoviesApi.history(params);
return response;
}
);
export const movieMarkHistoryDirty = createAction("movies/history/mark_dirty");
export const movieMarkHistoryDirty = createAction<number[]>(
"movies/history/mark_dirty"
);
export const movieUpdateBlacklist = createAsyncThunk(
"movies/blacklist/update",

View File

@ -77,15 +77,17 @@ export const episodeUpdateById = createAsyncThunk(
}
);
export const episodesUpdateHistory = createAsyncThunk(
"episodes/history/update",
async () => {
const response = await EpisodesApi.history();
export const episodesUpdateHistoryByRange = createAsyncThunk(
"episodes/history/update/range",
async (param: Parameter.Range) => {
const response = await EpisodesApi.history(param);
return response;
}
);
export const episodesMarkHistoryDirty = createAction("episodes/history/update");
export const episodesMarkHistoryDirty = createAction<number[]>(
"episodes/history/update"
);
export const episodesUpdateBlacklist = createAsyncThunk(
"episodes/blacklist/update",

View File

@ -3,7 +3,6 @@ import { useEntityItemById, useEntityToList } from "../../utilites";
import {
movieUpdateBlacklist,
movieUpdateById,
movieUpdateHistory,
movieUpdateWantedById,
} from "../actions";
import { useAutoDirtyUpdate, useAutoUpdate } from "./async";
@ -62,9 +61,7 @@ export function useBlacklistMovies() {
}
export function useMoviesHistory() {
const update = useReduxAction(movieUpdateHistory);
const items = useReduxStore((s) => s.movies.historyList);
useAutoUpdate(items, update);
return items;
}

View File

@ -2,7 +2,6 @@ import { useCallback, useEffect, useMemo } from "react";
import { useEntityItemById, useEntityToList } from "../../utilites";
import {
episodesUpdateBlacklist,
episodesUpdateHistory,
episodeUpdateById,
episodeUpdateBySeriesId,
seriesUpdateById,
@ -94,9 +93,7 @@ export function useBlacklistSeries() {
}
export function useSeriesHistory() {
const update = useReduxAction(episodesUpdateHistory);
const items = useReduxStore((s) => s.series.historyList);
useAutoUpdate(items, update);
return items;
}

View File

@ -10,7 +10,7 @@ import {
movieUpdateBlacklist,
movieUpdateById,
movieUpdateByRange,
movieUpdateHistory,
movieUpdateHistoryByRange,
movieUpdateWantedById,
movieUpdateWantedByRange,
} from "../actions";
@ -23,14 +23,14 @@ import {
interface Movie {
movieList: Async.Entity<Item.Movie>;
wantedMovieList: Async.Entity<Wanted.Movie>;
historyList: Async.Item<History.Movie[]>;
historyList: Async.Entity<History.Movie>;
blacklist: Async.Item<Blacklist.Movie[]>;
}
const defaultMovie: Movie = {
movieList: AsyncUtility.getDefaultEntity("radarrId"),
wantedMovieList: AsyncUtility.getDefaultEntity("radarrId"),
historyList: AsyncUtility.getDefaultItem(),
historyList: AsyncUtility.getDefaultEntity("id"),
blacklist: AsyncUtility.getDefaultItem(),
};
@ -50,8 +50,8 @@ const reducer = createReducer(defaultMovie, (builder) => {
dirty: movieMarkWantedDirtyById,
});
createAsyncItemReducer(builder, (s) => s.historyList, {
all: movieUpdateHistory,
createAsyncEntityReducer(builder, (s) => s.historyList, {
range: movieUpdateHistoryByRange,
dirty: movieMarkHistoryDirty,
});

View File

@ -5,7 +5,7 @@ import {
episodesMarkHistoryDirty,
episodesRemoveById,
episodesUpdateBlacklist,
episodesUpdateHistory,
episodesUpdateHistoryByRange,
episodeUpdateById,
episodeUpdateBySeriesId,
seriesMarkDirtyById,
@ -29,7 +29,7 @@ interface Series {
seriesList: Async.Entity<Item.Series>;
wantedEpisodesList: Async.Entity<Wanted.Episode>;
episodeList: Async.List<Item.Episode>;
historyList: Async.Item<History.Episode[]>;
historyList: Async.Entity<History.Episode>;
blacklist: Async.Item<Blacklist.Episode[]>;
}
@ -37,7 +37,7 @@ const defaultSeries: Series = {
seriesList: AsyncUtility.getDefaultEntity("sonarrSeriesId"),
wantedEpisodesList: AsyncUtility.getDefaultEntity("sonarrEpisodeId"),
episodeList: AsyncUtility.getDefaultList("sonarrEpisodeId"),
historyList: AsyncUtility.getDefaultItem(),
historyList: AsyncUtility.getDefaultEntity("id"),
blacklist: AsyncUtility.getDefaultItem(),
};
@ -72,8 +72,8 @@ const reducer = createReducer(defaultSeries, (builder) => {
dirty: seriesMarkWantedDirtyById,
});
createAsyncItemReducer(builder, (s) => s.historyList, {
all: episodesUpdateHistory,
createAsyncEntityReducer(builder, (s) => s.historyList, {
range: episodesUpdateHistoryByRange,
dirty: episodesMarkHistoryDirty,
});

View File

@ -2,11 +2,9 @@ import { ActionCreator } from "@reduxjs/toolkit";
import {
episodesMarkBlacklistDirty,
episodesMarkDirtyById,
episodesMarkHistoryDirty,
episodesRemoveById,
movieMarkBlacklistDirty,
movieMarkDirtyById,
movieMarkHistoryDirty,
movieMarkWantedDirtyById,
movieRemoveById,
movieRemoveWantedById,
@ -130,7 +128,7 @@ export function createDefaultReducer(): SocketIO.Reducer[] {
},
{
key: "movie-history",
any: bindReduxAction(movieMarkHistoryDirty),
// any: bindReduxAction(movieMarkHistoryDirty),
},
{
key: "movie-blacklist",
@ -138,7 +136,7 @@ export function createDefaultReducer(): SocketIO.Reducer[] {
},
{
key: "episode-history",
any: bindReduxAction(episodesMarkHistoryDirty),
// any: bindReduxAction(episodesMarkHistoryDirty),
},
{
key: "episode-blacklist",

View File

@ -195,6 +195,7 @@ declare namespace History {
TagType &
MonitoredType &
Partial<ItemHistoryType> & {
id: number;
action: number;
blacklisted: boolean;
score?: string;

View File

@ -4,7 +4,9 @@ import React, { FunctionComponent, useMemo } from "react";
import { Badge, OverlayTrigger, Popover } from "react-bootstrap";
import { Link } from "react-router-dom";
import { Column } from "react-table";
import { movieUpdateHistoryByRange } from "../../@redux/actions";
import { useMoviesHistory } from "../../@redux/hooks";
import { useReduxAction } from "../../@redux/hooks/base";
import { MoviesApi } from "../../apis";
import { HistoryIcon, LanguageText, TextPopover } from "../../components";
import { BlacklistButton } from "../../generic/blacklist";
@ -14,6 +16,7 @@ interface Props {}
const MoviesHistoryView: FunctionComponent<Props> = () => {
const movies = useMoviesHistory();
const loader = useReduxAction(movieUpdateHistoryByRange);
const columns: Column<History.Movie>[] = useMemo<Column<History.Movie>[]>(
() => [
@ -128,7 +131,8 @@ const MoviesHistoryView: FunctionComponent<Props> = () => {
<HistoryGenericView
type="movies"
state={movies}
columns={columns as Column<History.Base>[]}
loader={loader}
columns={columns}
></HistoryGenericView>
);
};

View File

@ -4,7 +4,9 @@ import React, { FunctionComponent, useMemo } from "react";
import { Badge, OverlayTrigger, Popover } from "react-bootstrap";
import { Link } from "react-router-dom";
import { Column } from "react-table";
import { episodesUpdateHistoryByRange } from "../../@redux/actions";
import { useSeriesHistory } from "../../@redux/hooks";
import { useReduxAction } from "../../@redux/hooks/base";
import { EpisodesApi } from "../../apis";
import { HistoryIcon, LanguageText, TextPopover } from "../../components";
import { BlacklistButton } from "../../generic/blacklist";
@ -14,6 +16,7 @@ interface Props {}
const SeriesHistoryView: FunctionComponent<Props> = () => {
const series = useSeriesHistory();
const loader = useReduxAction(episodesUpdateHistoryByRange);
const columns: Column<History.Episode>[] = useMemo<Column<History.Episode>[]>(
() => [
@ -137,7 +140,8 @@ const SeriesHistoryView: FunctionComponent<Props> = () => {
<HistoryGenericView
type="series"
state={series}
columns={columns as Column<History.Base>[]}
loader={loader}
columns={columns}
></HistoryGenericView>
);
};

View File

@ -1,21 +1,23 @@
import { capitalize } from "lodash";
import React, { FunctionComponent } from "react";
import React from "react";
import { Container, Row } from "react-bootstrap";
import { Helmet } from "react-helmet";
import { Column } from "react-table";
import { AsyncOverlay, PageTable } from "../../components";
import { AsyncPageTable } from "../../components";
interface Props {
interface Props<T extends History.Base> {
type: "movies" | "series";
state: Readonly<Async.Item<History.Base[]>>;
columns: Column<History.Base>[];
state: Readonly<Async.Entity<T>>;
loader: (param: Parameter.Range) => void;
columns: Column<T>[];
}
const HistoryGenericView: FunctionComponent<Props> = ({
function HistoryGenericView<T extends History.Base = History.Base>({
state,
loader,
columns,
type,
}) => {
}: Props<T>) {
const typeName = capitalize(type);
return (
<Container fluid>
@ -23,18 +25,16 @@ const HistoryGenericView: FunctionComponent<Props> = ({
<title>{typeName} History - Bazarr</title>
</Helmet>
<Row>
<AsyncOverlay ctx={state}>
{({ content }) => (
<PageTable
emptyText={`Nothing Found in ${typeName} History`}
columns={columns}
data={content ?? []}
></PageTable>
)}
</AsyncOverlay>
<AsyncPageTable
emptyText={`Nothing Found in ${typeName} History`}
entity={state}
loader={loader}
columns={columns}
data={[]}
></AsyncPageTable>
</Row>
</Container>
);
};
}
export default HistoryGenericView;

View File

@ -53,16 +53,20 @@ class EpisodeApi extends BaseApi {
});
}
async history(episodeid?: number): Promise<History.Episode[]> {
return new Promise<History.Episode[]>((resolve, reject) => {
this.get<DataWrapper<History.Episode[]>>("/history", { episodeid })
.then((result) => {
resolve(result.data.data);
})
.catch((reason) => {
reject(reason);
});
});
async history(params: Parameter.Range) {
const response = await this.get<AsyncDataWrapper<History.Episode>>(
"/history",
params
);
return response.data;
}
async historyBy(episodeid: number) {
const response = await this.get<AsyncDataWrapper<History.Episode>>(
"/history",
{ episodeid }
);
return response.data;
}
async downloadSubtitles(

View File

@ -93,18 +93,20 @@ class MovieApi extends BaseApi {
});
}
async history(id?: number): Promise<History.Movie[]> {
return new Promise<History.Movie[]>((resolve, reject) => {
this.get<DataWrapper<History.Movie[]>>("/history", {
radarrid: id,
})
.then((result) => {
resolve(result.data.data);
})
.catch((reason) => {
reject(reason);
});
});
async history(params: Parameter.Range) {
const response = await this.get<AsyncDataWrapper<History.Movie>>(
"/history",
params
);
return response.data;
}
async historyBy(radarrid: number) {
const response = await this.get<AsyncDataWrapper<History.Movie>>(
"/history",
{ radarrid }
);
return response.data;
}
async action(action: FormType.MoviesAction) {

View File

@ -14,8 +14,8 @@ export const MovieHistoryModal: FunctionComponent<BaseModalProps> = (props) => {
const movie = useModalPayload<Item.Movie>(modal.modalKey);
const [history, updateHistory] = useAsyncRequest(
MoviesApi.history.bind(MoviesApi),
[]
MoviesApi.historyBy.bind(MoviesApi),
{ data: [], total: 0 }
);
const update = useCallback(() => {
@ -98,7 +98,7 @@ export const MovieHistoryModal: FunctionComponent<BaseModalProps> = (props) => {
<PageTable
emptyText="No History Found"
columns={columns}
data={content}
data={content.data}
></PageTable>
)}
</AsyncOverlay>
@ -114,8 +114,8 @@ export const EpisodeHistoryModal: FunctionComponent<
const episode = useModalPayload<Item.Episode>(props.modalKey);
const [history, updateHistory] = useAsyncRequest(
EpisodesApi.history.bind(EpisodesApi),
[]
EpisodesApi.historyBy.bind(EpisodesApi),
{ data: [], total: 0 }
);
const update = useCallback(() => {
@ -199,7 +199,7 @@ export const EpisodeHistoryModal: FunctionComponent<
<PageTable
emptyText="No History Found"
columns={columns}
data={content}
data={content.data}
></PageTable>
)}
</AsyncOverlay>