Skip to content

Commit 48bdaf5

Browse files
authored
fix: online manager subscribe state (#2312)
* fix: background recovery when offline Signed-off-by: Adam Setch <adam.setch@outlook.com> * fix: background recovery when offline Signed-off-by: Adam Setch <adam.setch@outlook.com> * fix: background recovery when offline Signed-off-by: Adam Setch <adam.setch@outlook.com> --------- Signed-off-by: Adam Setch <adam.setch@outlook.com>
1 parent d365dae commit 48bdaf5

File tree

25 files changed

+206
-88
lines changed

25 files changed

+206
-88
lines changed

docs/src/components/GitHubRepo.astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ const loadRepoStats = async (): Promise<RepoStats> => {
3030
stars: formatCount(repository.data.stargazers_count),
3131
latestReleaseName: latestRelease.data.name?.replace('v', '') ?? '',
3232
};
33-
} catch (error) {
34-
console.error('Failed to load repo stats', error);
33+
} catch (err) {
34+
console.error('Failed to load repo stats', err);
3535
return {
3636
forks: '',
3737
stars: '',

docs/src/components/LatestRelease.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ const loadInitialData = async (): Promise<HeroData> => {
9292
? format(latestRelease.data.published_at, 'dd/MM/yyyy')
9393
: '',
9494
};
95-
} catch (error) {
95+
} catch (err) {
9696
return {
9797
downloadLinks: {
9898
alt: [],

src/main/index.ts

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
type BrowserWindowConstructorOptions,
1212
globalShortcut,
1313
nativeTheme,
14-
net,
1514
safeStorage,
1615
shell,
1716
} from 'electron';
@@ -27,6 +26,7 @@ import {
2726
type IAutoLaunch,
2827
type IKeyboardShortcut,
2928
type IOpenExternal,
29+
type ITrayColorUpdate,
3030
} from '../shared/events';
3131
import { logError, logInfo, logWarn } from '../shared/logger';
3232
import { Theme } from '../shared/theme';
@@ -181,26 +181,29 @@ app.whenReady().then(async () => {
181181
},
182182
);
183183

184-
onMainEvent(EVENTS.UPDATE_ICON_COLOR, (_, notificationsCount: number) => {
185-
if (!mb.tray.isDestroyed()) {
186-
if (!net.isOnline()) {
187-
setOfflineIcon();
188-
return;
189-
}
184+
onMainEvent(
185+
EVENTS.UPDATE_ICON_COLOR,
186+
(_, { notificationsCount, isOnline }: ITrayColorUpdate) => {
187+
if (!mb.tray.isDestroyed()) {
188+
if (!isOnline) {
189+
setOfflineIcon();
190+
return;
191+
}
190192

191-
if (notificationsCount < 0) {
192-
setErrorIcon();
193-
return;
194-
}
193+
if (notificationsCount < 0) {
194+
setErrorIcon();
195+
return;
196+
}
195197

196-
if (notificationsCount > 0) {
197-
setActiveIcon();
198-
return;
199-
}
198+
if (notificationsCount > 0) {
199+
setActiveIcon();
200+
return;
201+
}
200202

201-
setIdleIcon();
202-
}
203-
});
203+
setIdleIcon();
204+
}
205+
},
206+
);
204207

205208
onMainEvent(EVENTS.UPDATE_ICON_TITLE, (_, title: string) => {
206209
if (!mb.tray.isDestroyed()) {
@@ -258,15 +261,15 @@ app.whenReady().then(async () => {
258261
handleMainEvent(EVENTS.SAFE_STORAGE_DECRYPT, (_, value: string) => {
259262
try {
260263
return safeStorage.decryptString(Buffer.from(value, 'base64'));
261-
} catch (error) {
264+
} catch (err) {
262265
// If decryption fails, the data was likely encrypted with a different app identity
263266
// This can happen when migrating between build systems or changing app configuration
264267
logError(
265268
'main:safe-storage-decrypt',
266269
'Failed to decrypt value - data may be from old build',
267-
error,
270+
err,
268271
);
269-
throw error;
272+
throw err;
270273
}
271274
});
272275
});

src/main/updater.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ export default class AppUpdater {
111111
try {
112112
logInfo('app updater', 'Checking for updates on application launch');
113113
await autoUpdater.checkForUpdatesAndNotify();
114-
} catch (e) {
115-
logError('auto updater', 'Initial check failed', e as Error);
114+
} catch (err) {
115+
logError('auto updater', 'Initial check failed', err as Error);
116116
}
117117
}
118118

@@ -121,8 +121,8 @@ export default class AppUpdater {
121121
try {
122122
logInfo('app updater', 'Checking for updates on a periodic schedule');
123123
await autoUpdater.checkForUpdatesAndNotify();
124-
} catch (e) {
125-
logError('auto updater', 'Scheduled check failed', e as Error);
124+
} catch (err) {
125+
logError('auto updater', 'Scheduled check failed', err as Error);
126126
}
127127
}, APPLICATION.UPDATE_CHECK_INTERVAL_MS);
128128
}

src/preload/index.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,10 @@ describe('preload/index', () => {
9292
expect(sendMainEventMock).toHaveBeenNthCalledWith(
9393
1,
9494
EVENTS.UPDATE_ICON_COLOR,
95-
-1,
95+
{
96+
isOnline: true,
97+
notificationsCount: -1,
98+
},
9699
);
97100
});
98101

src/preload/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ export const api = {
3434
},
3535

3636
tray: {
37-
updateColor: (notificationsCount = 0) => {
38-
sendMainEvent(EVENTS.UPDATE_ICON_COLOR, notificationsCount);
37+
updateColor: (notificationsCount = 0, isOnline = true) => {
38+
sendMainEvent(EVENTS.UPDATE_ICON_COLOR, { notificationsCount, isOnline });
3939
},
4040

4141
updateTitle: (title = '') => sendMainEvent(EVENTS.UPDATE_ICON_TITLE, title),
@@ -117,10 +117,10 @@ export const api = {
117117
// Context isolation is always enabled in this app
118118
try {
119119
contextBridge.exposeInMainWorld('atlassify', api);
120-
} catch (error) {
120+
} catch (err) {
121121
// biome-ignore lint/suspicious/noConsole: preload environment is strictly sandboxed
122122
console.error(
123123
'[preload] Failed to expose Atlassify Bridge API to renderer',
124-
error,
124+
err,
125125
);
126126
}

src/renderer/context/App.tsx

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import { createContext, type ReactNode, useEffect, useMemo } from 'react';
1+
import {
2+
createContext,
3+
type ReactNode,
4+
useEffect,
5+
useMemo,
6+
useState,
7+
} from 'react';
8+
9+
import { onlineManager } from '@tanstack/react-query';
210

311
import { useAccounts } from '../hooks/useAccounts';
412
import { useKeyboardNavigation } from '../hooks/useKeyboardNavigation';
@@ -35,6 +43,8 @@ export interface AppContextState {
3543
) => Promise<void>;
3644

3745
focusedNotificationId: string | null;
46+
47+
isOnline: boolean;
3848
}
3949

4050
export const AppContext = createContext<Partial<AppContextState> | undefined>(
@@ -56,6 +66,8 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
5666
const useUnreadActiveIcon = useSettingsStore((s) => s.useUnreadActiveIcon);
5767
const useAlternateIdleIcon = useSettingsStore((s) => s.useAlternateIdleIcon);
5868

69+
const [isOnline, setIsOnline] = useState(false);
70+
5971
const {
6072
status,
6173
globalError,
@@ -82,14 +94,15 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
8294
// biome-ignore lint/correctness/useExhaustiveDependencies: We want to update the tray on setting or notification changes
8395
useEffect(() => {
8496
const trayCount = status === 'error' ? -1 : notificationCount;
85-
setTrayIconColorAndTitle(trayCount, hasMoreAccountNotifications);
97+
setTrayIconColorAndTitle(trayCount, hasMoreAccountNotifications, isOnline);
8698
}, [
8799
showNotificationsCountInTray,
88100
useUnreadActiveIcon,
89101
useAlternateIdleIcon,
90102
status,
91103
notificationCount,
92104
hasMoreAccountNotifications,
105+
isOnline,
93106
]);
94107

95108
useEffect(() => {
@@ -100,6 +113,25 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
100113
});
101114
}, [resetAccounts, resetFilters]);
102115

116+
// Online / Offline status monitoring via TanStack Query onlineManager
117+
useEffect(() => {
118+
const handle = () => {
119+
try {
120+
const online = onlineManager.isOnline();
121+
122+
setIsOnline(online);
123+
} catch (_err) {
124+
// ignore
125+
}
126+
};
127+
128+
// Subscribe and call immediately to set initial status
129+
const unsubscribe = onlineManager.subscribe(handle);
130+
handle();
131+
132+
return () => unsubscribe();
133+
}, []);
134+
103135
const contextValues: AppContextState = useMemo(
104136
() => ({
105137
status,
@@ -116,6 +148,8 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
116148
markNotificationsUnread,
117149

118150
focusedNotificationId,
151+
152+
isOnline,
119153
}),
120154
[
121155
status,
@@ -132,6 +166,8 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
132166
markNotificationsUnread,
133167

134168
focusedNotificationId,
169+
170+
isOnline,
135171
],
136172
);
137173

src/renderer/i18n/locales/de.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@
4242
"description2": "Bitte überprüfen Sie Ihre Netzwerkverbindung, einschließlich der Frage, ob Sie ein VPN benötigen, und versuchen Sie es erneut.",
4343
"title": "Netzwerkfehler"
4444
},
45+
"offline": {
46+
"description1": "Ihr Gerät ist offline.",
47+
"description2": "Bitte überprüfen Sie Ihre Netzwerkverbindung.",
48+
"title": "Netzwerk offline"
49+
},
4550
"unknown": {
4651
"description1": "Bitte versuchen Sie es später erneut.",
4752
"title": "Hoppla! Etwas lief schief"

src/renderer/i18n/locales/en.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@
4242
"description1": "Unable to connect to Atlassian Cloud.",
4343
"description2": "Please check your network connection, including whether you require a VPN, and try again."
4444
},
45+
"offline": {
46+
"title": "Network Offline",
47+
"description1": "Your device is offline.",
48+
"description2": "Please check your network connection."
49+
},
4550
"unknown": {
4651
"title": "Oops! Something went wrong",
4752
"description1": "Please try again later."

src/renderer/i18n/locales/es.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@
4242
"description2": "Consulte su conexión de red, incluso si necesita una VPN, y vuelva a intentarlo.",
4343
"title": "Error de red"
4444
},
45+
"offline": {
46+
"description1": "Su dispositivo está desconectado.",
47+
"description2": "Por favor verifique su conexión de red.",
48+
"title": "Red sin conexión"
49+
},
4550
"unknown": {
4651
"description1": "Vuelva a intentarlo más tarde.",
4752
"title": "¡Ups! Algo salió mal"

0 commit comments

Comments
 (0)