mirror of
https://github.com/suitenumerique/docs.git
synced 2026-05-13 02:16:42 +02:00
🩺(project) reload app if front and back unsync
We observe some cases where the frontend and backend versions can get out of sync, which can cause issues. To mitigate this, we want to implement a mechanism that detects when the frontend and backend versions are mismatched and triggers a reload of the application to ensure they are in sync.
This commit is contained in:
@@ -17,6 +17,7 @@ and this project adheres to
|
||||
|
||||
### Fixed
|
||||
|
||||
- 🩺(project) reload app if front and back unsync #2276
|
||||
- 🐛(frontend) fix patch and comments #2273
|
||||
- 🐛(frontend) interlinking are exported correctly in print mode #2269
|
||||
- 💬(frontend) add missing link in onboarding description #2233
|
||||
|
||||
@@ -2841,6 +2841,7 @@ class ConfigView(drf.views.APIView):
|
||||
dict_settings[setting] = getattr(settings, setting)
|
||||
|
||||
dict_settings["theme_customization"] = self._load_theme_customization()
|
||||
dict_settings["RELEASE_VERSION"] = settings.RELEASE
|
||||
|
||||
return drf.response.Response(dict_settings)
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ pytestmark = pytest.mark.django_db
|
||||
FRONTEND_THEME="test-theme",
|
||||
MEDIA_BASE_URL="http://testserver/",
|
||||
POSTHOG_KEY={"id": "132456", "host": "https://eu.i.posthog-test.com"},
|
||||
RELEASE="1.0.0",
|
||||
SENTRY_DSN="https://sentry.test/123",
|
||||
THEME_CUSTOMIZATION_FILE_PATH="",
|
||||
)
|
||||
@@ -77,6 +78,7 @@ def test_api_config(is_authenticated):
|
||||
"LANGUAGE_CODE": "en-us",
|
||||
"MEDIA_BASE_URL": "http://testserver/",
|
||||
"POSTHOG_KEY": {"id": "132456", "host": "https://eu.i.posthog-test.com"},
|
||||
"RELEASE_VERSION": "1.0.0",
|
||||
"SENTRY_DSN": "https://sentry.test/123",
|
||||
"TRASHBIN_CUTOFF_DAYS": 30,
|
||||
"theme_customization": {},
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
import { createDoc, getCurrentConfig, verifyDocName } from './utils-common';
|
||||
import {
|
||||
createDoc,
|
||||
getCurrentConfig,
|
||||
overrideConfig,
|
||||
verifyDocName,
|
||||
} from './utils-common';
|
||||
import { writeInEditor } from './utils-editor';
|
||||
import { SignIn, expectLoginPage } from './utils-signin';
|
||||
import { createRootSubPage } from './utils-sub-pages';
|
||||
@@ -145,6 +150,29 @@ test.describe('Doc Routing', () => {
|
||||
);
|
||||
await expect(page).toHaveTitle(/401 Unauthorized - Docs/);
|
||||
});
|
||||
|
||||
test('checks redirect if unsync version', async ({ page }) => {
|
||||
await overrideConfig(page, {
|
||||
RELEASE_VERSION: '0.0.0',
|
||||
});
|
||||
|
||||
let counterReload = 0;
|
||||
await page.route(/.*\/users\/me\/$/, async (route) => {
|
||||
counterReload += 1;
|
||||
await route.continue();
|
||||
});
|
||||
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// The sessionStorage guard should be set to the mismatched backend version.
|
||||
const reloadVersion = await page.evaluate(() =>
|
||||
sessionStorage.getItem('reload-version'),
|
||||
);
|
||||
expect(reloadVersion).toBe('0.0.0');
|
||||
|
||||
// The page should have reloaded once
|
||||
expect(counterReload).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Doc Routing: Not logged', () => {
|
||||
|
||||
@@ -4,6 +4,7 @@ import path from 'path';
|
||||
import { Locator, Page, TestInfo, expect } from '@playwright/test';
|
||||
|
||||
import theme_customization from '../../../../../backend/impress/configuration/theme/default.json';
|
||||
import { version as packageJsonVersion } from '../../package.json';
|
||||
|
||||
export type BrowserName = 'chromium' | 'firefox' | 'webkit';
|
||||
export const BROWSERS: BrowserName[] = ['chromium', 'webkit', 'firefox'];
|
||||
@@ -40,6 +41,7 @@ export const CONFIG = {
|
||||
],
|
||||
LANGUAGE_CODE: 'en-us',
|
||||
POSTHOG_KEY: {},
|
||||
RELEASE_VERSION: packageJsonVersion,
|
||||
SENTRY_DSN: null,
|
||||
TRASHBIN_CUTOFF_DAYS: 30,
|
||||
theme_customization,
|
||||
|
||||
@@ -2,6 +2,8 @@ const crypto = require('crypto');
|
||||
|
||||
const { InjectManifest } = require('workbox-webpack-plugin');
|
||||
|
||||
const { version } = require('./package.json');
|
||||
|
||||
const buildId = crypto.randomBytes(256).toString('hex').slice(0, 8);
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
@@ -25,6 +27,7 @@ const nextConfig = {
|
||||
generateBuildId: () => buildId,
|
||||
env: {
|
||||
NEXT_PUBLIC_BUILD_ID: buildId,
|
||||
NEXT_PUBLIC_APP_VERSION: version,
|
||||
},
|
||||
/**
|
||||
* In dev mode, Next.js doesn't use Webpack, but Turbopack.
|
||||
|
||||
@@ -85,6 +85,32 @@ export const ConfigProvider = ({ children }: PropsWithChildren) => {
|
||||
});
|
||||
}, [conf?.CRISP_WEBSITE_ID]);
|
||||
|
||||
useEffect(() => {
|
||||
const frontendVersion = process.env.NEXT_PUBLIC_APP_VERSION;
|
||||
|
||||
if (
|
||||
!conf?.RELEASE_VERSION ||
|
||||
!frontendVersion ||
|
||||
conf.RELEASE_VERSION === frontendVersion
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Avoid infinite reload loops: only reload once per backend version
|
||||
const RELOAD_VERSION_KEY = 'reload-version';
|
||||
try {
|
||||
const reloadedForVersion = sessionStorage.getItem(RELOAD_VERSION_KEY);
|
||||
if (reloadedForVersion === conf.RELEASE_VERSION) {
|
||||
return;
|
||||
}
|
||||
|
||||
sessionStorage.setItem(RELOAD_VERSION_KEY, conf.RELEASE_VERSION);
|
||||
window.location.reload();
|
||||
} catch {
|
||||
console.warn('Failed to access sessionStorage for version reload logic');
|
||||
}
|
||||
}, [conf?.RELEASE_VERSION]);
|
||||
|
||||
if (!conf) {
|
||||
return (
|
||||
<Box $height="100vh" $width="100vw" $align="center" $justify="center">
|
||||
|
||||
@@ -57,6 +57,7 @@ export interface ConfigResponse {
|
||||
LANGUAGE_CODE: string;
|
||||
MEDIA_BASE_URL?: string;
|
||||
POSTHOG_KEY?: PostHogConf;
|
||||
RELEASE_VERSION: string;
|
||||
SENTRY_DSN?: string;
|
||||
TRASHBIN_CUTOFF_DAYS?: number;
|
||||
theme_customization?: ThemeCustomization;
|
||||
@@ -94,13 +95,13 @@ export const KEY_CONFIG = 'config';
|
||||
|
||||
export function useConfig() {
|
||||
const cachedData = getCachedTranslation();
|
||||
const oneHour = 1000 * 60 * 60;
|
||||
const staleTime = 1000 * 60 * 5;
|
||||
|
||||
return useQuery<ConfigResponse, APIError, ConfigResponse>({
|
||||
queryKey: [KEY_CONFIG],
|
||||
queryFn: () => getConfig(),
|
||||
initialData: cachedData,
|
||||
staleTime: oneHour,
|
||||
initialDataUpdatedAt: Date.now() - oneHour, // Force initial data to be considered stale
|
||||
staleTime,
|
||||
initialDataUpdatedAt: Date.now() - staleTime, // Force initial data to be considered stale
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user