aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modern/src/App.jsx2
-rw-r--r--modern/src/UpdateController.tsx58
-rw-r--r--modern/src/common/attributes/useServerAttributes.js4
-rw-r--r--modern/src/resources/l10n/en.json2
-rw-r--r--modern/vite.config.js1
5 files changed, 66 insertions, 1 deletions
diff --git a/modern/src/App.jsx b/modern/src/App.jsx
index 89785cfa..4fe34f64 100644
--- a/modern/src/App.jsx
+++ b/modern/src/App.jsx
@@ -8,6 +8,7 @@ import SocketController from './SocketController';
import CachingController from './CachingController';
import { useEffectAsync } from './reactHelper';
import { sessionActions } from './store';
+import UpdateController from './UpdateController';
const useStyles = makeStyles(() => ({
page: {
@@ -48,6 +49,7 @@ const App = () => {
<>
<SocketController />
<CachingController />
+ <UpdateController />
<div className={classes.page}>
<Outlet />
</div>
diff --git a/modern/src/UpdateController.tsx b/modern/src/UpdateController.tsx
new file mode 100644
index 00000000..0b2b7985
--- /dev/null
+++ b/modern/src/UpdateController.tsx
@@ -0,0 +1,58 @@
+import { Snackbar, IconButton } from '@mui/material';
+import RefreshIcon from '@mui/icons-material/Refresh';
+import React from 'react'
+import { useSelector } from 'react-redux';
+import { useTranslation } from './common/components/LocalizationProvider';
+import { useRegisterSW } from 'virtual:pwa-register/react'
+
+// Based on https://vite-pwa-org.netlify.app/frameworks/react.html
+function UpdateController() {
+ const t = useTranslation();
+
+ const swUpdateInterval = useSelector((state) => state.session.server.attributes.serviceWorkerUpdateInterval || 3600000);
+
+ const {
+ needRefresh: [needRefresh],
+ updateServiceWorker,
+ } = useRegisterSW({
+ onRegisteredSW(swUrl, swRegistration) {
+ if (swUpdateInterval > 0 && swRegistration) {
+ setInterval(async () => {
+ if (!(!swRegistration.installing && navigator)) {
+ return;
+ }
+
+ if (('connection' in navigator) && !navigator.onLine) {
+ return;
+ }
+
+ const newSW = await fetch(swUrl, {
+ cache: 'no-store',
+ headers: {
+ 'cache': 'no-store',
+ 'cache-control': 'no-cache',
+ },
+ });
+
+ if (newSW?.status === 200) {
+ await swRegistration.update();
+ }
+ }, swUpdateInterval);
+ }
+ }
+ });
+
+ return (
+ <Snackbar
+ open={needRefresh}
+ message={t('settingsUpdateAvailable')}
+ action={(
+ <IconButton color="inherit" onClick={() => updateServiceWorker(true)}>
+ <RefreshIcon />
+ </IconButton>
+ )}
+ />
+ );
+}
+
+export default UpdateController;
diff --git a/modern/src/common/attributes/useServerAttributes.js b/modern/src/common/attributes/useServerAttributes.js
index 4339840e..e724c2b0 100644
--- a/modern/src/common/attributes/useServerAttributes.js
+++ b/modern/src/common/attributes/useServerAttributes.js
@@ -43,6 +43,10 @@ export default (t) => useMemo(() => ({
name: t('settingsTotpForce'),
type: 'boolean',
},
+ serviceWorkerUpdateInterval: {
+ name: t('settingsServiceWorkerUpdateInterval'),
+ type: 'number',
+ },
'ui.disableLoginLanguage': {
name: t('attributeUiDisableLoginLanguage'),
type: 'boolean',
diff --git a/modern/src/resources/l10n/en.json b/modern/src/resources/l10n/en.json
index ed9516b5..d2e9c7ca 100644
--- a/modern/src/resources/l10n/en.json
+++ b/modern/src/resources/l10n/en.json
@@ -226,6 +226,8 @@
"settingsDarkMode": "Dark Mode",
"settingsTotpEnable": "Enable One-time Password",
"settingsTotpForce": "Force One-time Password",
+ "settingsServiceWorkerUpdateInterval": "ServiceWorker Update Interval",
+ "settingsUpdateAvailable": "There is an update available.",
"reportTitle": "Reports",
"reportScheduled": "Scheduled Reports",
"reportDevice": "Device",
diff --git a/modern/vite.config.js b/modern/vite.config.js
index 200579da..9f6df445 100644
--- a/modern/vite.config.js
+++ b/modern/vite.config.js
@@ -19,7 +19,6 @@ export default defineConfig(() => ({
svgr(),
react(),
VitePWA({
- registerType: 'autoUpdate',
workbox: {
navigateFallbackDenylist: [/^\/api/],
},