mirror of
https://github.com/morpheus65535/bazarr.git
synced 2024-11-10 17:13:35 +08:00
Merge remote-tracking branch 'origin/development' into development
This commit is contained in:
commit
7b0ddf3fa1
16 changed files with 157 additions and 100 deletions
|
@ -25,7 +25,3 @@ def show_message(msg):
|
|||
|
||||
def show_progress(id, name, value, count):
|
||||
event_stream(type="progress", payload={"id": id, "name": name, "value": value, "count": count})
|
||||
|
||||
|
||||
def hide_progress(id, delay=3):
|
||||
event_stream(type="progress", action="delete", payload={"id": id, "delay": delay})
|
||||
|
|
|
@ -9,7 +9,7 @@ from config import settings, url_sonarr
|
|||
from helper import path_mappings
|
||||
from list_subtitles import store_subtitles, series_full_scan_subtitles
|
||||
from get_subtitle import episode_download_subtitles
|
||||
from event_handler import event_stream, show_progress, hide_progress
|
||||
from event_handler import event_stream, show_progress
|
||||
|
||||
headers = {"User-Agent": os.environ["SZ_USER_AGENT"]}
|
||||
|
||||
|
@ -63,8 +63,6 @@ def sync_episodes():
|
|||
else:
|
||||
episodes_to_add.append(episodeParser(episode))
|
||||
|
||||
hide_progress(id='episodes_progress')
|
||||
|
||||
# Remove old episodes from DB
|
||||
removed_episodes = list(set(current_episodes_db_list) - set(current_episodes_sonarr))
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ from get_rootfolder import check_radarr_rootfolder
|
|||
|
||||
from get_subtitle import movies_download_subtitles
|
||||
from database import database, dict_converter, get_exclusion_clause
|
||||
from event_handler import event_stream, show_progress, hide_progress
|
||||
from event_handler import event_stream, show_progress
|
||||
|
||||
headers = {"User-Agent": os.environ["SZ_USER_AGENT"]}
|
||||
|
||||
|
@ -87,8 +87,6 @@ def update_movies():
|
|||
movie_default_profile=movie_default_profile,
|
||||
audio_profiles=audio_profiles))
|
||||
|
||||
hide_progress(id='movies_progress')
|
||||
|
||||
# Remove old movies from DB
|
||||
removed_movies = list(set(current_movies_db_list) - set(current_movies_radarr))
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ from get_rootfolder import check_sonarr_rootfolder
|
|||
from database import database, dict_converter
|
||||
from utils import get_sonarr_version
|
||||
from helper import path_mappings
|
||||
from event_handler import event_stream, show_progress, hide_progress
|
||||
from event_handler import event_stream, show_progress
|
||||
|
||||
headers = {"User-Agent": os.environ["SZ_USER_AGENT"]}
|
||||
|
||||
|
@ -66,8 +66,6 @@ def update_series():
|
|||
tags_dict=tagsDict, serie_default_profile=serie_default_profile,
|
||||
audio_profiles=audio_profiles))
|
||||
|
||||
hide_progress(id='series_progress')
|
||||
|
||||
# Remove old series from DB
|
||||
removed_series = list(set(current_shows_db_list) - set(current_shows_sonarr))
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ from subsyncer import subsync
|
|||
from guessit import guessit
|
||||
from database import database, dict_mapper, get_exclusion_clause, get_profiles_list, get_audio_profile_languages, \
|
||||
get_desired_languages
|
||||
from event_handler import event_stream, show_progress, hide_progress
|
||||
from event_handler import event_stream, show_progress
|
||||
from embedded_subs_reader import parse_video_metadata
|
||||
|
||||
from analytics import track_event
|
||||
|
@ -806,7 +806,7 @@ def series_download_subtitles(no):
|
|||
logging.info("BAZARR All providers are throttled")
|
||||
break
|
||||
|
||||
hide_progress(id='series_search_progress_{}'.format(no))
|
||||
|
||||
|
||||
|
||||
def episode_download_subtitles(no):
|
||||
|
@ -929,8 +929,6 @@ def movies_download_subtitles(no):
|
|||
logging.info("BAZARR All providers are throttled")
|
||||
break
|
||||
|
||||
hide_progress(id='movie_search_progress_{}'.format(no))
|
||||
|
||||
|
||||
def wanted_download_subtitles(path):
|
||||
episodes_details = database.execute("SELECT table_episodes.path, table_episodes.missing_subtitles, "
|
||||
|
@ -1100,7 +1098,7 @@ def wanted_search_missing_subtitles_series():
|
|||
logging.info("BAZARR All providers are throttled")
|
||||
return
|
||||
|
||||
hide_progress(id='wanted_episodes_progress')
|
||||
|
||||
logging.info('BAZARR Finished searching for missing Series Subtitles. Check History for more information.')
|
||||
|
||||
|
||||
|
@ -1124,7 +1122,7 @@ def wanted_search_missing_subtitles_movies():
|
|||
logging.info("BAZARR All providers are throttled")
|
||||
return
|
||||
|
||||
hide_progress(id='wanted_movies_progress')
|
||||
|
||||
logging.info('BAZARR Finished searching for missing Movies Subtitles. Check History for more information.')
|
||||
|
||||
|
||||
|
@ -1402,7 +1400,7 @@ def upgrade_subtitles():
|
|||
language_code, provider, score, subs_id, subs_path)
|
||||
send_notifications(episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message)
|
||||
|
||||
hide_progress('upgrade_episodes_progress')
|
||||
|
||||
|
||||
if settings.general.getboolean('use_radarr'):
|
||||
for i, movie in enumerate(movies_to_upgrade, 1):
|
||||
|
@ -1468,7 +1466,7 @@ def upgrade_subtitles():
|
|||
history_log_movie(3, movie['radarrId'], message, path, language_code, provider, score, subs_id, subs_path)
|
||||
send_notifications_movie(movie['radarrId'], message)
|
||||
|
||||
hide_progress(id='upgrade_movies_progress')
|
||||
|
||||
|
||||
logging.info('BAZARR Finished searching for Subtitles to upgrade. Check History for more information.')
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ from config import settings
|
|||
from helper import path_mappings, get_subtitle_destination_folder
|
||||
|
||||
from embedded_subs_reader import embedded_subs_reader
|
||||
from event_handler import event_stream, show_progress, hide_progress
|
||||
from event_handler import event_stream, show_progress
|
||||
from charamel import Detector
|
||||
|
||||
gc.enable()
|
||||
|
@ -489,8 +489,6 @@ def series_full_scan_subtitles():
|
|||
count=count_episodes)
|
||||
store_subtitles(episode['path'], path_mappings.path_replace(episode['path']))
|
||||
|
||||
hide_progress(id='episodes_disk_scan')
|
||||
|
||||
gc.collect()
|
||||
|
||||
|
||||
|
@ -505,8 +503,6 @@ def movies_full_scan_subtitles():
|
|||
count=count_movies)
|
||||
store_subtitles_movie(movie['path'], path_mappings.path_replace_movie(movie['path']))
|
||||
|
||||
hide_progress(id='movies_disk_scan')
|
||||
|
||||
gc.collect()
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { createAction } from "redux-actions";
|
||||
import {
|
||||
ActionCallback,
|
||||
ActionDispatcher,
|
||||
|
@ -122,8 +121,3 @@ export function createCallbackAction<T extends AsyncActionCreator>(
|
|||
return (...args: Parameters<T>) =>
|
||||
callbackActionFactory(fn(args), success, error);
|
||||
}
|
||||
|
||||
// Helper
|
||||
export function createDeleteAction(type: string): SocketIO.ActionFn {
|
||||
return createAction(type, (id?: number[]) => id ?? []);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { createDeleteAction } from "../../@socketio/reducer";
|
||||
import { MoviesApi } from "../../apis";
|
||||
import {
|
||||
MOVIES_DELETE_ITEMS,
|
||||
|
@ -7,7 +8,7 @@ import {
|
|||
MOVIES_UPDATE_LIST,
|
||||
MOVIES_UPDATE_WANTED_LIST,
|
||||
} from "../constants";
|
||||
import { createAsyncAction, createDeleteAction } from "./factory";
|
||||
import { createAsyncAction } from "./factory";
|
||||
|
||||
export const movieUpdateList = createAsyncAction(
|
||||
MOVIES_UPDATE_LIST,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { createDeleteAction } from "../../@socketio/reducer";
|
||||
import { EpisodesApi, SeriesApi } from "../../apis";
|
||||
import {
|
||||
SERIES_DELETE_EPISODES,
|
||||
|
@ -9,7 +10,7 @@ import {
|
|||
SERIES_UPDATE_LIST,
|
||||
SERIES_UPDATE_WANTED_LIST,
|
||||
} from "../constants";
|
||||
import { createAsyncAction, createDeleteAction } from "./factory";
|
||||
import { createAsyncAction } from "./factory";
|
||||
|
||||
export const seriesUpdateWantedList = createAsyncAction(
|
||||
SERIES_UPDATE_WANTED_LIST,
|
||||
|
|
|
@ -54,7 +54,10 @@ export function useSystemLogs() {
|
|||
export function useSystemTasks() {
|
||||
const items = useReduxStore((s) => s.system.tasks);
|
||||
const update = useReduxAction(systemUpdateTasks);
|
||||
useSocketIOReducer("task", update);
|
||||
const reducer = useMemo<SocketIO.Reducer>(() => ({ key: "task", update }), [
|
||||
update,
|
||||
]);
|
||||
useSocketIOReducer(reducer);
|
||||
|
||||
useEffect(() => {
|
||||
update();
|
||||
|
@ -245,10 +248,18 @@ export function useEpisodesBy(seriesId?: number) {
|
|||
const actionById = useReduxAction(episodeUpdateById);
|
||||
const wrapActionById = useWrapToOptionalId(actionById);
|
||||
const deleteAction = useReduxAction(episodeDeleteItems);
|
||||
useSocketIOReducer("episode", undefined, wrapActionById, deleteAction);
|
||||
const episodeReducer = useMemo<SocketIO.Reducer>(
|
||||
() => ({ key: "episode", update: wrapActionById, delete: deleteAction }),
|
||||
[wrapActionById, deleteAction]
|
||||
);
|
||||
useSocketIOReducer(episodeReducer);
|
||||
|
||||
const wrapAction = useWrapToOptionalId(action);
|
||||
useSocketIOReducer("series", undefined, wrapAction);
|
||||
const seriesReducer = useMemo<SocketIO.Reducer>(
|
||||
() => ({ key: "series", update: wrapAction }),
|
||||
[wrapAction]
|
||||
);
|
||||
useSocketIOReducer(seriesReducer);
|
||||
|
||||
useEffect(() => {
|
||||
update();
|
||||
|
@ -315,7 +326,15 @@ export function useWantedSeries() {
|
|||
|
||||
const updateAction = useWrapToOptionalId(update);
|
||||
const deleteAction = useReduxAction(seriesDeleteWantedItems);
|
||||
useSocketIOReducer("episode-wanted", undefined, updateAction, deleteAction);
|
||||
const reducer = useMemo<SocketIO.Reducer>(
|
||||
() => ({
|
||||
key: "episode-wanted",
|
||||
update: updateAction,
|
||||
delete: deleteAction,
|
||||
}),
|
||||
[updateAction, deleteAction]
|
||||
);
|
||||
useSocketIOReducer(reducer);
|
||||
|
||||
return stateBuilder(items, update);
|
||||
}
|
||||
|
@ -326,7 +345,15 @@ export function useWantedMovies() {
|
|||
|
||||
const updateAction = useWrapToOptionalId(update);
|
||||
const deleteAction = useReduxAction(movieDeleteWantedItems);
|
||||
useSocketIOReducer("movie-wanted", undefined, updateAction, deleteAction);
|
||||
const reducer = useMemo<SocketIO.Reducer>(
|
||||
() => ({
|
||||
key: "movie-wanted",
|
||||
update: updateAction,
|
||||
delete: deleteAction,
|
||||
}),
|
||||
[updateAction, deleteAction]
|
||||
);
|
||||
useSocketIOReducer(reducer);
|
||||
|
||||
return stateBuilder(items, update);
|
||||
}
|
||||
|
@ -334,8 +361,11 @@ export function useWantedMovies() {
|
|||
export function useBlacklistMovies() {
|
||||
const update = useReduxAction(movieUpdateBlacklist);
|
||||
const items = useReduxStore((d) => d.movie.blacklist);
|
||||
|
||||
useSocketIOReducer("movie-blacklist", update);
|
||||
const reducer = useMemo<SocketIO.Reducer>(
|
||||
() => ({ key: "movie-blacklist", update }),
|
||||
[update]
|
||||
);
|
||||
useSocketIOReducer(reducer);
|
||||
|
||||
useEffect(() => {
|
||||
update();
|
||||
|
@ -346,8 +376,11 @@ export function useBlacklistMovies() {
|
|||
export function useBlacklistSeries() {
|
||||
const update = useReduxAction(seriesUpdateBlacklist);
|
||||
const items = useReduxStore((d) => d.series.blacklist);
|
||||
|
||||
useSocketIOReducer("episode-blacklist", update);
|
||||
const reducer = useMemo<SocketIO.Reducer>(
|
||||
() => ({ key: "episode-blacklist", update }),
|
||||
[update]
|
||||
);
|
||||
useSocketIOReducer(reducer);
|
||||
|
||||
useEffect(() => {
|
||||
update();
|
||||
|
@ -358,8 +391,11 @@ export function useBlacklistSeries() {
|
|||
export function useMoviesHistory() {
|
||||
const update = useReduxAction(movieUpdateHistoryList);
|
||||
const items = useReduxStore((s) => s.movie.historyList);
|
||||
|
||||
useSocketIOReducer("movie-history", update);
|
||||
const reducer = useMemo<SocketIO.Reducer>(
|
||||
() => ({ key: "movie-history", update }),
|
||||
[update]
|
||||
);
|
||||
useSocketIOReducer(reducer);
|
||||
|
||||
useEffect(() => {
|
||||
update();
|
||||
|
@ -370,8 +406,11 @@ export function useMoviesHistory() {
|
|||
export function useSeriesHistory() {
|
||||
const update = useReduxAction(seriesUpdateHistoryList);
|
||||
const items = useReduxStore((s) => s.series.historyList);
|
||||
|
||||
useSocketIOReducer("episode-history", update);
|
||||
const reducer = useMemo<SocketIO.Reducer>(
|
||||
() => ({ key: "episode-history", update }),
|
||||
[update]
|
||||
);
|
||||
useSocketIOReducer(reducer);
|
||||
|
||||
useEffect(() => {
|
||||
update();
|
||||
|
|
|
@ -39,7 +39,7 @@ const reducer = handleActions<ReduxStore.Site, any>(
|
|||
action: Action<ReduxStore.Notification[]>
|
||||
) => {
|
||||
const notifications = uniqBy(
|
||||
[...action.payload, ...state.notifications],
|
||||
[...action.payload.reverse(), ...state.notifications],
|
||||
(n) => n.id
|
||||
);
|
||||
return { ...state, notifications };
|
||||
|
@ -51,7 +51,7 @@ const reducer = handleActions<ReduxStore.Site, any>(
|
|||
},
|
||||
[SITE_PROGRESS_ADD]: (state, action: Action<ReduxStore.Progress[]>) => {
|
||||
const progress = uniqBy(
|
||||
[...action.payload, ...state.progress],
|
||||
[...action.payload.reverse(), ...state.progress],
|
||||
(n) => n.id
|
||||
);
|
||||
return { ...state, progress };
|
||||
|
|
|
@ -1,29 +1,20 @@
|
|||
import { useCallback, useEffect, useMemo } from "react";
|
||||
import { useCallback, useEffect } from "react";
|
||||
import Socketio from ".";
|
||||
import { log } from "../utilites/logger";
|
||||
|
||||
export function useSocketIOReducer(
|
||||
key: SocketIO.EventType,
|
||||
any?: () => void,
|
||||
update?: SocketIO.ActionFn,
|
||||
remove?: SocketIO.ActionFn
|
||||
) {
|
||||
const reducer = useMemo<SocketIO.Reducer>(
|
||||
() => ({ key, any, update, delete: remove }),
|
||||
[key, any, update, remove]
|
||||
);
|
||||
export function useSocketIOReducer(reducer: SocketIO.Reducer) {
|
||||
useEffect(() => {
|
||||
Socketio.addReducer(reducer);
|
||||
log("info", "listening to SocketIO event", key);
|
||||
log("info", "listening to SocketIO event", reducer.key);
|
||||
return () => {
|
||||
Socketio.removeReducer(reducer);
|
||||
};
|
||||
}, [reducer, key]);
|
||||
}, [reducer]);
|
||||
}
|
||||
|
||||
export function useWrapToOptionalId(
|
||||
fn: (id: number[]) => void
|
||||
): SocketIO.ActionFn {
|
||||
): SocketIO.ActionFn<number> {
|
||||
return useCallback(
|
||||
(id?: number[]) => {
|
||||
if (id) {
|
||||
|
|
|
@ -27,7 +27,7 @@ class SocketIOClient {
|
|||
this.socket.on("data", this.onEvent.bind(this));
|
||||
|
||||
this.events = [];
|
||||
this.debounceReduce = debounce(this.reduce, 200);
|
||||
this.debounceReduce = debounce(this.reduce, 20);
|
||||
this.reducers = [];
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ class SocketIOClient {
|
|||
|
||||
forIn(element, (ids, key) => {
|
||||
ids = uniq(ids);
|
||||
const action = handler[key as SocketIO.ActionType];
|
||||
const action = handler[key as SocketIO.Action];
|
||||
if (action) {
|
||||
action(ids);
|
||||
} else if (anyAction === undefined) {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { createAction } from "redux-actions";
|
||||
import {
|
||||
badgeUpdateAll,
|
||||
bootstrap,
|
||||
|
@ -6,6 +7,7 @@ import {
|
|||
seriesDeleteItems,
|
||||
seriesUpdateList,
|
||||
siteAddNotifications,
|
||||
siteAddProgress,
|
||||
siteInitializationFailed,
|
||||
siteUpdateOffline,
|
||||
systemUpdateLanguagesAll,
|
||||
|
@ -13,10 +15,16 @@ import {
|
|||
} from "../@redux/actions";
|
||||
import reduxStore from "../@redux/store";
|
||||
|
||||
function bindToReduxStore(fn: (ids?: number[]) => any): SocketIO.ActionFn {
|
||||
function bindToReduxStore(
|
||||
fn: (ids?: number[]) => any
|
||||
): SocketIO.ActionFn<number> {
|
||||
return (ids?: number[]) => reduxStore.dispatch(fn(ids));
|
||||
}
|
||||
|
||||
export function createDeleteAction(type: string): SocketIO.ActionFn<number> {
|
||||
return createAction(type, (id?: number[]) => id ?? []);
|
||||
}
|
||||
|
||||
export function createDefaultReducer(): SocketIO.Reducer[] {
|
||||
return [
|
||||
{
|
||||
|
@ -44,7 +52,7 @@ export function createDefaultReducer(): SocketIO.Reducer[] {
|
|||
},
|
||||
{
|
||||
key: "message",
|
||||
update: (msg?: string[]) => {
|
||||
update: (msg) => {
|
||||
if (msg) {
|
||||
const notifications = msg.map<ReduxStore.Notification>((message) => ({
|
||||
message,
|
||||
|
@ -57,6 +65,14 @@ export function createDefaultReducer(): SocketIO.Reducer[] {
|
|||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "progress",
|
||||
update: (progress) => {
|
||||
if (progress) {
|
||||
reduxStore.dispatch(siteAddProgress(progress));
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "series",
|
||||
update: bindToReduxStore(seriesUpdateList),
|
||||
|
|
64
frontend/src/@types/socket.d.ts
vendored
64
frontend/src/@types/socket.d.ts
vendored
|
@ -1,43 +1,55 @@
|
|||
namespace SocketIO {
|
||||
type EventType =
|
||||
| "connect"
|
||||
| "connect_error"
|
||||
| "disconnect"
|
||||
type Action = "update" | "delete";
|
||||
|
||||
type EventType = NumEventType | NullEventType | SpecialEventType;
|
||||
|
||||
type NumEventType =
|
||||
| "movie"
|
||||
| "series"
|
||||
| "episode"
|
||||
| "episode-history"
|
||||
| "episode-blacklist"
|
||||
| "episode-wanted"
|
||||
| "movie-history"
|
||||
| "movie-wanted";
|
||||
|
||||
type NullEventType =
|
||||
| "connect"
|
||||
| "connect_error"
|
||||
| "disconnect"
|
||||
| "episode-blacklist"
|
||||
| "episode-history"
|
||||
| "movie-blacklist"
|
||||
| "movie-wanted"
|
||||
| "movie-history"
|
||||
| "badges"
|
||||
| "task"
|
||||
| "settings"
|
||||
| "languages"
|
||||
| "message";
|
||||
| "languages";
|
||||
|
||||
type ActionType = "update" | "delete";
|
||||
type SpecialEventType = "message" | "progress";
|
||||
|
||||
interface Event {
|
||||
type: EventType;
|
||||
action: ActionType;
|
||||
payload: any; // TODO: Use specific types
|
||||
type ReducerCreator<E extends EventType, T> = ValueOf<
|
||||
{
|
||||
[P in E]: {
|
||||
key: P;
|
||||
any?: () => void;
|
||||
} & Partial<Record<Action, ActionFn<T>>>;
|
||||
}
|
||||
|
||||
type ActionFn = (payload?: any[]) => void;
|
||||
|
||||
type Reducer = {
|
||||
key: EventType;
|
||||
any?: () => any;
|
||||
} & Partial<Record<ActionType, ActionFn>>;
|
||||
|
||||
type ActionRecord = OptionalRecord<
|
||||
EventType,
|
||||
OptionalRecord<ActionType, any[]>
|
||||
>;
|
||||
|
||||
type Event = {
|
||||
type: EventType;
|
||||
action: Action;
|
||||
payload: any;
|
||||
};
|
||||
|
||||
type ActionFn<T> = (payload?: T[]) => void;
|
||||
|
||||
type Reducer =
|
||||
| ReducerCreator<NumEventType, number>
|
||||
| ReducerCreator<NullEventType, null>
|
||||
| ReducerCreator<"message", string>
|
||||
| ReducerCreator<"progress", CustomEvent.Progress>;
|
||||
|
||||
type ActionRecord = OptionalRecord<EventType, OptionalRecord<Action, any[]>>;
|
||||
|
||||
namespace CustomEvent {
|
||||
type Progress = ReduxStore.Progress;
|
||||
}
|
||||
|
|
|
@ -4,9 +4,13 @@ import {
|
|||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { capitalize } from "lodash";
|
||||
import React, { FunctionComponent, useCallback, useMemo } from "react";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
} from "react";
|
||||
import { ProgressBar, Toast } from "react-bootstrap";
|
||||
import { useTimeoutWhen } from "rooks";
|
||||
import {
|
||||
siteRemoveNotifications,
|
||||
siteRemoveProgress,
|
||||
|
@ -48,7 +52,12 @@ const NotificationToast: FunctionComponent<MessageHolderProps> = (props) => {
|
|||
id,
|
||||
]);
|
||||
|
||||
useTimeoutWhen(remove, timeout);
|
||||
useEffect(() => {
|
||||
const handle = setTimeout(remove, timeout);
|
||||
return () => {
|
||||
clearTimeout(handle);
|
||||
};
|
||||
}, [props, remove, timeout]);
|
||||
|
||||
return (
|
||||
<Toast onClose={remove} animation={false}>
|
||||
|
@ -75,12 +84,22 @@ const ProgressToast: FunctionComponent<ProgressHolderProps> = ({
|
|||
const removeProgress = useReduxAction(siteRemoveProgress);
|
||||
const remove = useCallback(() => removeProgress(id), [removeProgress, id]);
|
||||
|
||||
// TODO: Auto remove
|
||||
useEffect(() => {
|
||||
const handle = setTimeout(remove, 5 * 1000);
|
||||
return () => {
|
||||
clearTimeout(handle);
|
||||
};
|
||||
}, [value, remove]);
|
||||
|
||||
const incomplete = value / count < 1;
|
||||
|
||||
return (
|
||||
<Toast onClose={remove}>
|
||||
<Toast.Header hidden={incomplete}>
|
||||
<span className="mr-auto">Background Task</span>
|
||||
</Toast.Header>
|
||||
<Toast.Body>
|
||||
<div className="mb-2 mt-1">
|
||||
<div className="mb-2 mt-1 text-nowrap text-truncate">
|
||||
<FontAwesomeIcon
|
||||
className="mr-2"
|
||||
icon={faPaperPlane}
|
||||
|
@ -89,7 +108,7 @@ const ProgressToast: FunctionComponent<ProgressHolderProps> = ({
|
|||
</div>
|
||||
<ProgressBar
|
||||
className="my-1"
|
||||
animated
|
||||
animated={incomplete}
|
||||
now={value / count}
|
||||
max={1}
|
||||
label={`${value}/${count}`}
|
||||
|
|
Loading…
Reference in a new issue