diff --git a/src/apps/experimental/routes/home.tsx b/src/apps/experimental/routes/home.tsx index 0b0e38f3b2..af14e252e1 100644 --- a/src/apps/experimental/routes/home.tsx +++ b/src/apps/experimental/routes/home.tsx @@ -101,6 +101,8 @@ const Home: FunctionComponent = () => { controller.refreshed = true; tabController.current = controller; + }).catch(err => { + console.error('[Home] failed to get tab controller', err); }); }, [ getTabController ]); diff --git a/src/apps/experimental/routes/movies/GenresView.tsx b/src/apps/experimental/routes/movies/GenresView.tsx index a2c1d7a476..dd1af9efc9 100644 --- a/src/apps/experimental/routes/movies/GenresView.tsx +++ b/src/apps/experimental/routes/movies/GenresView.tsx @@ -23,6 +23,8 @@ const GenresView: FC = ({ topParentId }) => { ).then((result) => { setItemsResult(result); loading.hide(); + }).catch(err => { + console.error('[GenresView] failed to fetch genres', err); }); }, [topParentId]); diff --git a/src/apps/experimental/routes/movies/SuggestionsView.tsx b/src/apps/experimental/routes/movies/SuggestionsView.tsx index 48b402efbc..1d468d009b 100644 --- a/src/apps/experimental/routes/movies/SuggestionsView.tsx +++ b/src/apps/experimental/routes/movies/SuggestionsView.tsx @@ -30,6 +30,8 @@ const SuggestionsView: FC = ({ topParentId }) => { const autoFocus = useCallback((page) => { import('../../../../components/autoFocuser').then(({ default: autoFocuser }) => { autoFocuser.autoFocus(page); + }).catch(err => { + console.error('[SuggestionsView] failed to load data', err); }); }, []); @@ -55,6 +57,8 @@ const SuggestionsView: FC = ({ topParentId }) => { loading.hide(); autoFocus(page); + }).catch(err => { + console.error('[SuggestionsView] failed to fetch items', err); }); }, [autoFocus]); @@ -72,6 +76,8 @@ const SuggestionsView: FC = ({ topParentId }) => { setLatestItems(items); autoFocus(page); + }).catch(err => { + console.error('[SuggestionsView] failed to fetch latest items', err); }); }, [autoFocus]); @@ -95,6 +101,8 @@ const SuggestionsView: FC = ({ topParentId }) => { setRecommendations(result); autoFocus(page); + }).catch(err => { + console.error('[SuggestionsView] failed to fetch recommendations', err); }); }, [autoFocus]); diff --git a/src/apps/experimental/routes/movies/index.tsx b/src/apps/experimental/routes/movies/index.tsx index e2e7bfa4de..64f66368c8 100644 --- a/src/apps/experimental/routes/movies/index.tsx +++ b/src/apps/experimental/routes/movies/index.tsx @@ -114,6 +114,8 @@ const Movies: FC = () => { window.ApiClient.getItem(window.ApiClient.getCurrentUserId(), parentId).then((item) => { page.setAttribute('data-title', item.Name as string); libraryMenu.setTitle(item.Name); + }).catch(err => { + console.error('[movies] failed to fetch library', err); }); } else { page.setAttribute('data-title', globalize.translate('Movies')); diff --git a/src/apps/stable/routes/user/useredit.tsx b/src/apps/stable/routes/user/useredit.tsx index f099ee6407..c4acdfaaee 100644 --- a/src/apps/stable/routes/user/useredit.tsx +++ b/src/apps/stable/routes/user/useredit.tsx @@ -32,7 +32,10 @@ const getCheckedElementDataIds = (elements: NodeListOf) => ( ); function onSaveComplete() { - Dashboard.navigate('userprofiles.html'); + Dashboard.navigate('userprofiles.html') + .catch(err => { + console.error('[useredit] failed to navigate to user profile', err); + }); loading.hide(); toast(globalize.translate('SettingsSaved')); } @@ -133,6 +136,8 @@ const UserEdit: FunctionComponent = () => { const chkEnableDeleteAllFolders = page.querySelector('.chkEnableDeleteAllFolders') as HTMLInputElement; chkEnableDeleteAllFolders.checked = user.Policy.EnableContentDeletion; triggerChange(chkEnableDeleteAllFolders); + }).catch(err => { + console.error('[useredit] failed to fetch channels', err); }); }, []); @@ -146,14 +151,20 @@ const UserEdit: FunctionComponent = () => { window.ApiClient.getJSON(window.ApiClient.getUrl('Auth/Providers')).then(function (providers) { loadAuthProviders(user, providers); + }).catch(err => { + console.error('[useredit] failed to fetch auth providers', err); }); window.ApiClient.getJSON(window.ApiClient.getUrl('Auth/PasswordResetProviders')).then(function (providers) { loadPasswordResetProviders(user, providers); + }).catch(err => { + console.error('[useredit] failed to fetch password reset providers', err); }); window.ApiClient.getJSON(window.ApiClient.getUrl('Library/MediaFolders', { IsHidden: false })).then(function (folders) { loadDeleteFolders(user, folders.Items); + }).catch(err => { + console.error('[useredit] failed to fetch media folders', err); }); const disabledUserBanner = page.querySelector('.disabledUserBanner') as HTMLDivElement; @@ -197,6 +208,8 @@ const UserEdit: FunctionComponent = () => { loading.show(); getUser().then(function (user) { loadUser(user); + }).catch(err => { + console.error('[useredit] failed to load data', err); }); }, [loadUser]); @@ -240,18 +253,21 @@ const UserEdit: FunctionComponent = () => { user.Policy.EnableContentDeletionFromFolders = user.Policy.EnableContentDeletion ? [] : getCheckedElementDataIds(page.querySelectorAll('.chkFolder')); user.Policy.SyncPlayAccess = (page.querySelector('#selectSyncPlayAccess') as HTMLSelectElement).value as SyncPlayUserAccessType; - window.ApiClient.updateUser(user) - .then(() => ( - window.ApiClient.updateUserPolicy(user.Id || '', user.Policy || {}) - )).then(() => { - onSaveComplete(); - }); + window.ApiClient.updateUser(user).then(() => ( + window.ApiClient.updateUserPolicy(user.Id || '', user.Policy || {}) + )).then(() => { + onSaveComplete(); + }).catch(err => { + console.error('[useredit] failed to update user', err); + }); }; const onSubmit = (e: Event) => { loading.show(); getUser().then(function (result) { saveUser(result); + }).catch(err => { + console.error('[useredit] failed to fetch user', err); }); e.preventDefault(); e.stopPropagation(); @@ -264,6 +280,8 @@ const UserEdit: FunctionComponent = () => { window.ApiClient.getNamedConfiguration('network').then(function (config) { (page.querySelector('.fldRemoteAccess') as HTMLDivElement).classList.toggle('hide', !config.EnableRemoteAccess); + }).catch(err => { + console.error('[useredit] failed to load network config', err); }); (page.querySelector('.editUserProfileForm') as HTMLFormElement).addEventListener('submit', onSubmit); diff --git a/src/apps/stable/routes/user/userlibraryaccess.tsx b/src/apps/stable/routes/user/userlibraryaccess.tsx index e255376104..e9af88cb1f 100644 --- a/src/apps/stable/routes/user/userlibraryaccess.tsx +++ b/src/apps/stable/routes/user/userlibraryaccess.tsx @@ -148,6 +148,8 @@ const UserLibraryAccess: FunctionComponent = () => { const promise4 = window.ApiClient.getJSON(window.ApiClient.getUrl('Devices')); Promise.all([promise1, promise2, promise3, promise4]).then(function (responses) { loadUser(responses[0], responses[1].Items, responses[2].Items, responses[3].Items); + }).catch(err => { + console.error('[userlibraryaccess] failed to load data', err); }); }, [loadUser]); @@ -166,6 +168,8 @@ const UserLibraryAccess: FunctionComponent = () => { const userId = getParameterByName('userId'); window.ApiClient.getUser(userId).then(function (result) { saveUser(result); + }).catch(err => { + console.error('[userlibraryaccess] failed to fetch user', err); }); e.preventDefault(); e.stopPropagation(); @@ -203,6 +207,8 @@ const UserLibraryAccess: FunctionComponent = () => { user.Policy.BlockedMediaFolders = null; window.ApiClient.updateUserPolicy(user.Id, user.Policy).then(function () { onSaveComplete(); + }).catch(err => { + console.error('[userlibraryaccess] failed to update user policy', err); }); }; diff --git a/src/apps/stable/routes/user/usernew.tsx b/src/apps/stable/routes/user/usernew.tsx index 051bbce9b7..22758500ea 100644 --- a/src/apps/stable/routes/user/usernew.tsx +++ b/src/apps/stable/routes/user/usernew.tsx @@ -93,6 +93,8 @@ const UserNew: FunctionComponent = () => { loadMediaFolders(responses[0].Items); loadChannels(responses[1].Items); loading.hide(); + }).catch(err => { + console.error('[usernew] failed to load data', err); }); }, [loadChannels, loadMediaFolders]); @@ -138,7 +140,12 @@ const UserNew: FunctionComponent = () => { } window.ApiClient.updateUserPolicy(user.Id, user.Policy).then(function () { - Dashboard.navigate('useredit.html?userId=' + user.Id); + Dashboard.navigate('useredit.html?userId=' + user.Id) + .catch(err => { + console.error('[usernew] failed to navigate to edit user page', err); + }); + }).catch(err => { + console.error('[usernew] failed to update user policy', err); }); }, function () { toast(globalize.translate('ErrorDefault')); diff --git a/src/apps/stable/routes/user/userparentalcontrol.tsx b/src/apps/stable/routes/user/userparentalcontrol.tsx index ce02ba0f33..bee0fde1c7 100644 --- a/src/apps/stable/routes/user/userparentalcontrol.tsx +++ b/src/apps/stable/routes/user/userparentalcontrol.tsx @@ -197,6 +197,8 @@ const UserParentalControl: FunctionComponent = () => { const promise2 = window.ApiClient.getParentalRatings(); Promise.all([promise1, promise2]).then(function (responses) { loadUser(responses[0], responses[1]); + }).catch(err => { + console.error('[userparentalcontrol] failed to load data', err); }); }, [loadUser]); @@ -231,6 +233,8 @@ const UserParentalControl: FunctionComponent = () => { user.Policy.BlockedTags = getBlockedTagsFromPage(); window.ApiClient.updateUserPolicy(user.Id, user.Policy).then(function () { onSaveComplete(); + }).catch(err => { + console.error('[userparentalcontrol] failed to update user policy', err); }); }; @@ -248,7 +252,11 @@ const UserParentalControl: FunctionComponent = () => { schedules[index] = updatedSchedule; renderAccessSchedule(schedules); + }).catch(() => { + // access schedule closed }); + }).catch(err => { + console.error('[userparentalcontrol] failed to load access schedule', err); }); }; @@ -279,7 +287,11 @@ const UserParentalControl: FunctionComponent = () => { tags.push(value); loadBlockedTags(tags); } + }).catch(() => { + // prompt closed }); + }).catch(err => { + console.error('[userparentalcontrol] failed to load prompt', err); }); }; @@ -288,6 +300,8 @@ const UserParentalControl: FunctionComponent = () => { const userId = getParameterByName('userId'); window.ApiClient.getUser(userId).then(function (result) { saveUser(result); + }).catch(err => { + console.error('[userparentalcontrol] failed to fetch user', err); }); e.preventDefault(); e.stopPropagation(); diff --git a/src/apps/stable/routes/user/userpassword.tsx b/src/apps/stable/routes/user/userpassword.tsx index 3a518d6379..544e8c6dec 100644 --- a/src/apps/stable/routes/user/userpassword.tsx +++ b/src/apps/stable/routes/user/userpassword.tsx @@ -19,6 +19,8 @@ const UserPassword: FunctionComponent = () => { } setUserName(user.Name); loading.hide(); + }).catch(err => { + console.error('[userpassword] failed to fetch user', err); }); }, [userId]); useEffect(() => { diff --git a/src/apps/stable/routes/user/userprofile.tsx b/src/apps/stable/routes/user/userprofile.tsx index 7b1575d2c1..0c038bc84a 100644 --- a/src/apps/stable/routes/user/userprofile.tsx +++ b/src/apps/stable/routes/user/userprofile.tsx @@ -59,8 +59,12 @@ const UserProfile: FunctionComponent = () => { (page.querySelector('#btnDeleteImage') as HTMLButtonElement).classList.add('hide'); (page.querySelector('#btnAddImage') as HTMLButtonElement).classList.remove('hide'); } + }).catch(err => { + console.error('[userprofile] failed to get current user', err); }); loading.hide(); + }).catch(err => { + console.error('[userprofile] failed to load data', err); }); }, [userId]); @@ -110,6 +114,8 @@ const UserProfile: FunctionComponent = () => { window.ApiClient.uploadUserImage(userId, ImageType.Primary, file).then(function () { loading.hide(); reloadUser(); + }).catch(err => { + console.error('[userprofile] failed to upload image', err); }); }; @@ -125,7 +131,11 @@ const UserProfile: FunctionComponent = () => { window.ApiClient.deleteUserImage(userId, ImageType.Primary).then(function () { loading.hide(); reloadUser(); + }).catch(err => { + console.error('[userprofile] failed to delete image', err); }); + }).catch(() => { + // confirm dialog closed }); }); diff --git a/src/apps/stable/routes/user/userprofiles.tsx b/src/apps/stable/routes/user/userprofiles.tsx index 1eb2c9ee2e..b386533f4b 100644 --- a/src/apps/stable/routes/user/userprofiles.tsx +++ b/src/apps/stable/routes/user/userprofiles.tsx @@ -31,6 +31,8 @@ const UserProfiles: FunctionComponent = () => { window.ApiClient.getUsers().then(function (result) { setUsers(result); loading.hide(); + }).catch(err => { + console.error('[userprofiles] failed to fetch users', err); }); }; @@ -83,22 +85,35 @@ const UserProfiles: FunctionComponent = () => { callback: function (id: string) { switch (id) { case 'open': - Dashboard.navigate('useredit.html?userId=' + userId); + Dashboard.navigate('useredit.html?userId=' + userId) + .catch(err => { + console.error('[userprofiles] failed to navigate to user edit page', err); + }); break; case 'access': - Dashboard.navigate('userlibraryaccess.html?userId=' + userId); + Dashboard.navigate('userlibraryaccess.html?userId=' + userId) + .catch(err => { + console.error('[userprofiles] failed to navigate to user library page', err); + }); break; case 'parentalcontrol': - Dashboard.navigate('userparentalcontrol.html?userId=' + userId); + Dashboard.navigate('userparentalcontrol.html?userId=' + userId) + .catch(err => { + console.error('[userprofiles] failed to navigate to parental control page', err); + }); break; case 'delete': deleteUser(userId); } } + }).catch(() => { + // action sheet closed }); + }).catch(err => { + console.error('[userprofiles] failed to load action sheet', err); }); }; @@ -114,7 +129,11 @@ const UserProfiles: FunctionComponent = () => { loading.show(); window.ApiClient.deleteUser(id).then(function () { loadData(); + }).catch(err => { + console.error('[userprofiles] failed to delete user', err); }); + }).catch(() => { + // confirm dialog closed }); }; @@ -127,7 +146,10 @@ const UserProfiles: FunctionComponent = () => { }); (page.querySelector('#btnAddUser') as HTMLButtonElement).addEventListener('click', function() { - Dashboard.navigate('usernew.html'); + Dashboard.navigate('usernew.html') + .catch(err => { + console.error('[userprofiles] failed to navigate to new user page', err); + }); }); }, []); diff --git a/src/components/ConnectionRequired.tsx b/src/components/ConnectionRequired.tsx index c61e7c52ba..ca6c26b091 100644 --- a/src/components/ConnectionRequired.tsx +++ b/src/components/ConnectionRequired.tsx @@ -99,7 +99,10 @@ const ConnectionRequired: FunctionComponent = ({ } // Bounce to the correct page in the login flow - bounce(firstConnection); + bounce(firstConnection) + .catch(err => { + console.error('[ConnectionRequired] failed to bounce', err); + }); }, [bounce, navigate]); const validateUserAccess = useCallback(async () => { @@ -109,7 +112,10 @@ const ConnectionRequired: FunctionComponent = ({ if ((isAdminRequired || isUserRequired) && !client?.isLoggedIn()) { try { console.warn('[ConnectionRequired] unauthenticated user attempted to access user route'); - bounce(await ServerConnections.connect()); + bounce(await ServerConnections.connect()) + .catch(err => { + console.error('[ConnectionRequired] failed to bounce', err); + }); } catch (ex) { console.warn('[ConnectionRequired] error bouncing from user route', ex); } @@ -122,7 +128,10 @@ const ConnectionRequired: FunctionComponent = ({ const user = await client?.getCurrentUser(); if (!user?.Policy?.IsAdministrator) { console.warn('[ConnectionRequired] normal user attempted to access admin route'); - bounce(await ServerConnections.connect()); + bounce(await ServerConnections.connect()) + .catch(err => { + console.error('[ConnectionRequired] failed to bounce', err); + }); return; } } catch (ex) { @@ -143,9 +152,15 @@ const ConnectionRequired: FunctionComponent = ({ appRouter.firstConnectionResult = null; if (firstConnection && firstConnection.State !== ConnectionState.SignedIn) { - handleIncompleteWizard(firstConnection); + handleIncompleteWizard(firstConnection) + .catch(err => { + console.error('[ConnectionRequired] failed to start wizard', err); + }); } else { - validateUserAccess(); + validateUserAccess() + .catch(err => { + console.error('[ConnectionRequired] failed to validate user access', err); + }); } }, [handleIncompleteWizard, validateUserAccess]); diff --git a/src/components/common/Filter.tsx b/src/components/common/Filter.tsx index c3316df1a2..c3ccdd62f3 100644 --- a/src/components/common/Filter.tsx +++ b/src/components/common/Filter.tsx @@ -32,7 +32,11 @@ const Filter: FC = ({ serverId: window.ApiClient.serverId(), filterMenuOptions: getFilterMenuOptions(), setfilters: setViewQuerySettings + }).catch(() => { + // filter menu closed }); + }).catch(err => { + console.error('[Filter] failed to load filter menu', err); }); }, [viewQuerySettings, getVisibleFilters, topParentId, getItemTypes, getFilterMenuOptions, setViewQuerySettings]); diff --git a/src/components/common/GenresItemsContainer.tsx b/src/components/common/GenresItemsContainer.tsx index 796b6fa119..09623e7e57 100644 --- a/src/components/common/GenresItemsContainer.tsx +++ b/src/components/common/GenresItemsContainer.tsx @@ -73,6 +73,8 @@ const GenresItemsContainer: FC = ({ centerText: true, showYear: true }); + }).catch(err => { + console.error('[GenresItemsContainer] failed to fetch items', err); }); }, [getPortraitShape, topParentId]); diff --git a/src/components/common/NewCollection.tsx b/src/components/common/NewCollection.tsx index 4eadda8e36..837fe85fd3 100644 --- a/src/components/common/NewCollection.tsx +++ b/src/components/common/NewCollection.tsx @@ -12,7 +12,11 @@ const NewCollection: FC = () => { collectionEditor.show({ items: [], serverId: serverId + }).catch(() => { + // closed collection editor }); + }).catch(err => { + console.error('[NewCollection] failed to load collection editor', err); }); }, []); diff --git a/src/components/common/SelectView.tsx b/src/components/common/SelectView.tsx index f718529857..bfb34555b8 100644 --- a/src/components/common/SelectView.tsx +++ b/src/components/common/SelectView.tsx @@ -22,7 +22,11 @@ const SelectView: FC = ({ settings: viewQuerySettings, visibleSettings: getVisibleViewSettings(), setviewsettings: setViewQuerySettings + }).catch(() => { + // view settings closed }); + }).catch(err => { + console.error('[SelectView] failed to load view settings', err); }); }, [getVisibleViewSettings, viewQuerySettings, setViewQuerySettings]); diff --git a/src/components/common/Shuffle.tsx b/src/components/common/Shuffle.tsx index 7d5b06be4b..093dc74874 100644 --- a/src/components/common/Shuffle.tsx +++ b/src/components/common/Shuffle.tsx @@ -18,6 +18,8 @@ const Shuffle: FC = ({ itemsResult = {}, topParentId }) => { topParentId as string ).then((item) => { playbackManager.shuffle(item); + }).catch(err => { + console.error('[Shuffle] failed to fetch items', err); }); }, [topParentId]); diff --git a/src/components/common/Sort.tsx b/src/components/common/Sort.tsx index 5c5d1b6193..db5cb89956 100644 --- a/src/components/common/Sort.tsx +++ b/src/components/common/Sort.tsx @@ -25,7 +25,11 @@ const Sort: FC = ({ settings: viewQuerySettings, sortOptions: getSortMenuOptions(), setSortValues: setViewQuerySettings + }).catch(() => { + // sort menu closed }); + }).catch(err => { + console.error('[Sort] failed to load sort menu', err); }); }, [getSortMenuOptions, viewQuerySettings, setViewQuerySettings]); diff --git a/src/components/common/ViewItemsContainer.tsx b/src/components/common/ViewItemsContainer.tsx index d4f2937513..5cbc7aace6 100644 --- a/src/components/common/ViewItemsContainer.tsx +++ b/src/components/common/ViewItemsContainer.tsx @@ -335,9 +335,13 @@ const ViewItemsContainer: FC = ({ import('../../components/autoFocuser').then(({ default: autoFocuser }) => { autoFocuser.autoFocus(page); + }).catch(err => { + console.error('[ViewItemsContainer] failed to load autofocuser', err); }); loading.hide(); setisLoading(true); + }).catch(err => { + console.error('[ViewItemsContainer] failed to fetch data', err); }); }, [fetchData]); diff --git a/src/components/dashboard/users/UserPasswordForm.tsx b/src/components/dashboard/users/UserPasswordForm.tsx index 0337c06510..d7801fdb42 100644 --- a/src/components/dashboard/users/UserPasswordForm.tsx +++ b/src/components/dashboard/users/UserPasswordForm.tsx @@ -66,6 +66,8 @@ const UserPasswordForm: FunctionComponent = ({ userId }: IProps) => { import('../../autoFocuser').then(({ default: autoFocuser }) => { autoFocuser.autoFocus(page); + }).catch(err => { + console.error('[UserPasswordForm] failed to load autofocuser', err); }); (page.querySelector('#txtCurrentPassword') as HTMLInputElement).value = ''; @@ -81,7 +83,9 @@ const UserPasswordForm: FunctionComponent = ({ userId }: IProps) => { return; } - loadUser(); + loadUser().catch(err => { + console.error('[UserPasswordForm] failed to load user', err); + }); const onSubmit = (e: Event) => { if ((page.querySelector('#txtNewPassword') as HTMLInputElement).value != (page.querySelector('#txtNewPasswordConfirm') as HTMLInputElement).value) { @@ -109,7 +113,9 @@ const UserPasswordForm: FunctionComponent = ({ userId }: IProps) => { loading.hide(); toast(globalize.translate('PasswordSaved')); - loadUser(); + loadUser().catch(err => { + console.error('[UserPasswordForm] failed to load user', err); + }); }, function () { loading.hide(); Dashboard.alert({ @@ -132,6 +138,8 @@ const UserPasswordForm: FunctionComponent = ({ userId }: IProps) => { if (easyPassword) { window.ApiClient.updateEasyPassword(userId, easyPassword).then(function () { onEasyPasswordSaved(); + }).catch(err => { + console.error('[UserPasswordForm] failed to update easy password', err); }); } else { onEasyPasswordSaved(); @@ -153,8 +161,14 @@ const UserPasswordForm: FunctionComponent = ({ userId }: IProps) => { loading.hide(); toast(globalize.translate('SettingsSaved')); - loadUser(); + loadUser().catch(err => { + console.error('[UserPasswordForm] failed to load user', err); + }); + }).catch(err => { + console.error('[UserPasswordForm] failed to update user configuration', err); }); + }).catch(err => { + console.error('[UserPasswordForm] failed to fetch user', err); }); }; @@ -169,8 +183,14 @@ const UserPasswordForm: FunctionComponent = ({ userId }: IProps) => { message: globalize.translate('PinCodeResetComplete'), title: globalize.translate('HeaderPinCodeReset') }); - loadUser(); + loadUser().catch(err => { + console.error('[UserPasswordForm] failed to load user', err); + }); + }).catch(err => { + console.error('[UserPasswordForm] failed to reset easy password', err); }); + }).catch(() => { + // confirm dialog was closed }); }; @@ -184,8 +204,14 @@ const UserPasswordForm: FunctionComponent = ({ userId }: IProps) => { message: globalize.translate('PasswordResetComplete'), title: globalize.translate('ResetPassword') }); - loadUser(); + loadUser().catch(err => { + console.error('[UserPasswordForm] failed to load user', err); + }); + }).catch(err => { + console.error('[UserPasswordForm] failed to reset user password', err); }); + }).catch(() => { + // confirm dialog was closed }); }; diff --git a/src/components/search/LiveTVSearchResults.tsx b/src/components/search/LiveTVSearchResults.tsx index a087dc23cc..12d862804d 100644 --- a/src/components/search/LiveTVSearchResults.tsx +++ b/src/components/search/LiveTVSearchResults.tsx @@ -79,7 +79,9 @@ const LiveTVSearchResults: FunctionComponent = ({ serv fetchItems(apiClient, { IncludeItemTypes: 'LiveTvProgram', IsMovie: true - }).then(result => setMovies(result.Items || [])); + }) + .then(result => setMovies(result.Items || [])) + .catch(() => setMovies([])); // Episodes row fetchItems(apiClient, { IncludeItemTypes: 'LiveTvProgram', @@ -88,22 +90,30 @@ const LiveTVSearchResults: FunctionComponent = ({ serv IsSports: false, IsKids: false, IsNews: false - }).then(result => setEpisodes(result.Items || [])); + }) + .then(result => setEpisodes(result.Items || [])) + .catch(() => setEpisodes([])); // Sports row fetchItems(apiClient, { IncludeItemTypes: 'LiveTvProgram', IsSports: true - }).then(result => setSports(result.Items || [])); + }) + .then(result => setSports(result.Items || [])) + .catch(() => setSports([])); // Kids row fetchItems(apiClient, { IncludeItemTypes: 'LiveTvProgram', IsKids: true - }).then(result => setKids(result.Items || [])); + }) + .then(result => setKids(result.Items || [])) + .catch(() => setKids([])); // News row fetchItems(apiClient, { IncludeItemTypes: 'LiveTvProgram', IsNews: true - }).then(result => setNews(result.Items || [])); + }) + .then(result => setNews(result.Items || [])) + .catch(() => setNews([])); // Programs row fetchItems(apiClient, { IncludeItemTypes: 'LiveTvProgram', @@ -112,10 +122,13 @@ const LiveTVSearchResults: FunctionComponent = ({ serv IsSports: false, IsKids: false, IsNews: false - }).then(result => setPrograms(result.Items || [])); + }) + .then(result => setPrograms(result.Items || [])) + .catch(() => setPrograms([])); // Channels row fetchItems(apiClient, { IncludeItemTypes: 'TvChannel' }) - .then(result => setChannels(result.Items || [])); + .then(result => setChannels(result.Items || [])) + .catch(() => setChannels([])); } }, [collectionType, parentId, query, serverId]); diff --git a/src/components/search/SearchResults.tsx b/src/components/search/SearchResults.tsx index 731cc6ec35..f8e5a12fbd 100644 --- a/src/components/search/SearchResults.tsx +++ b/src/components/search/SearchResults.tsx @@ -123,38 +123,48 @@ const SearchResults: FunctionComponent = ({ serverId = windo if (!collectionType || isMovies(collectionType)) { // Movies row fetchItems(apiClient, { IncludeItemTypes: 'Movie' }) - .then(result => setMovies(result.Items)); + .then(result => setMovies(result.Items)) + .catch(() => setMovies([])); } // TV Show libraries if (!collectionType || isTVShows(collectionType)) { // Shows row fetchItems(apiClient, { IncludeItemTypes: 'Series' }) - .then(result => setShows(result.Items)); + .then(result => setShows(result.Items)) + .catch(() => setShows([])); // Episodes row fetchItems(apiClient, { IncludeItemTypes: 'Episode' }) - .then(result => setEpisodes(result.Items)); + .then(result => setEpisodes(result.Items)) + .catch(() => setEpisodes([])); } // People are included for Movies and TV Shows if (!collectionType || isMovies(collectionType) || isTVShows(collectionType)) { // People row - fetchPeople(apiClient).then(result => setPeople(result.Items)); + fetchPeople(apiClient) + .then(result => setPeople(result.Items)) + .catch(() => setPeople([])); } // Music libraries if (!collectionType || isMusic(collectionType)) { // Playlists row fetchItems(apiClient, { IncludeItemTypes: 'Playlist' }) - .then(results => setPlaylists(results.Items)); + .then(results => setPlaylists(results.Items)) + .catch(() => setPlaylists([])); // Artists row - fetchArtists(apiClient).then(result => setArtists(result.Items)); + fetchArtists(apiClient) + .then(result => setArtists(result.Items)) + .catch(() => setArtists([])); // Albums row fetchItems(apiClient, { IncludeItemTypes: 'MusicAlbum' }) - .then(result => setAlbums(result.Items)); + .then(result => setAlbums(result.Items)) + .catch(() => setAlbums([])); // Songs row fetchItems(apiClient, { IncludeItemTypes: 'Audio' }) - .then(result => setSongs(result.Items)); + .then(result => setSongs(result.Items)) + .catch(() => setSongs([])); } // Other libraries do not support in-library search currently @@ -163,28 +173,37 @@ const SearchResults: FunctionComponent = ({ serverId = windo fetchItems(apiClient, { MediaTypes: 'Video', ExcludeItemTypes: 'Movie,Episode,TvChannel' - }).then(result => setVideos(result.Items)); + }) + .then(result => setVideos(result.Items)) + .catch(() => setVideos([])); // Programs row fetchItems(apiClient, { IncludeItemTypes: 'LiveTvProgram' }) - .then(result => setPrograms(result.Items)); + .then(result => setPrograms(result.Items)) + .catch(() => setPrograms([])); // Channels row fetchItems(apiClient, { IncludeItemTypes: 'TvChannel' }) - .then(result => setChannels(result.Items)); + .then(result => setChannels(result.Items)) + .catch(() => setChannels([])); // Photo Albums row fetchItems(apiClient, { IncludeItemTypes: 'PhotoAlbum' }) - .then(result => setPhotoAlbums(result.Items)); + .then(result => setPhotoAlbums(result.Items)) + .catch(() => setPhotoAlbums([])); // Photos row fetchItems(apiClient, { IncludeItemTypes: 'Photo' }) - .then(result => setPhotos(result.Items)); + .then(result => setPhotos(result.Items)) + .catch(() => setPhotos([])); // Audio Books row fetchItems(apiClient, { IncludeItemTypes: 'AudioBook' }) - .then(result => setAudioBooks(result.Items)); + .then(result => setAudioBooks(result.Items)) + .catch(() => setAudioBooks([])); // Books row fetchItems(apiClient, { IncludeItemTypes: 'Book' }) - .then(result => setBooks(result.Items)); + .then(result => setBooks(result.Items)) + .catch(() => setBooks([])); // Collections row fetchItems(apiClient, { IncludeItemTypes: 'BoxSet' }) - .then(result => setCollections(result.Items)); + .then(result => setCollections(result.Items)) + .catch(() => setCollections([])); } }, [collectionType, fetchArtists, fetchItems, fetchPeople, query, serverId]); diff --git a/src/components/search/SearchSuggestions.tsx b/src/components/search/SearchSuggestions.tsx index 8d07d95da8..aefb831fe0 100644 --- a/src/components/search/SearchSuggestions.tsx +++ b/src/components/search/SearchSuggestions.tsx @@ -45,7 +45,11 @@ const SearchSuggestions: FunctionComponent = ({ parentId parentId: parentId || undefined, enableTotalRecordCount: false }) - .then(result => setSuggestions(result.data.Items || [])); + .then(result => setSuggestions(result.data.Items || [])) + .catch(err => { + console.error('[SearchSuggestions] failed to fetch search suggestions', err); + setSuggestions([]); + }); } }, [ api, parentId, user ]); diff --git a/src/elements/emby-button/LinkButton.tsx b/src/elements/emby-button/LinkButton.tsx index dceeac7b99..af2e5aa1d3 100644 --- a/src/elements/emby-button/LinkButton.tsx +++ b/src/elements/emby-button/LinkButton.tsx @@ -33,7 +33,10 @@ const LinkButton: React.FC = ({ } } else { e.preventDefault(); - appRouter.show(url); + appRouter.show(url) + .catch(err => { + console.error('[LinkButton] failed to show url', url, err); + }); } } else { e.preventDefault(); diff --git a/src/utils/dashboard.js b/src/utils/dashboard.js index a126aa1a58..8ceb81229f 100644 --- a/src/utils/dashboard.js +++ b/src/utils/dashboard.js @@ -107,6 +107,12 @@ export function getConfigurationResourceUrl(name) { }); } +/** + * Navigate to a url. + * @param {string} url - The url to navigate to. + * @param {boolean} [preserveQueryString] - A flag to indicate the current query string should be appended to the new url. + * @returns {Promise} + */ export function navigate(url, preserveQueryString) { if (!url) { throw new Error('url cannot be null or empty');