mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
fix(notices): hand the release notice only to a bundle built for the running version
After an update the service worker keeps serving the previous bundle until the new one is installed. That shell announces the release layout too, so the layout alone let it draw the notice with its own older texts and use it up for the version now running with one click on X. The bundle now sends the version it was built as (client/package.json, baked in by define), and the server compares it with its own before it hands a notice with a release block over. A shell of another version is told nothing and gets the notice after the reload, from the bundle that can draw it. This holds for every update, not only the one that introduced the parameter.
This commit is contained in:
@@ -6,9 +6,9 @@ import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
||||
import { CurrentUser } from '../auth/current-user.decorator';
|
||||
|
||||
/**
|
||||
* `?supports=release` names the layouts the calling bundle can draw, comma separated.
|
||||
* A missing or malformed value means none, which is what every bundle before this
|
||||
* parameter sent.
|
||||
* `?supports=release` names the layouts the calling bundle can draw, comma separated,
|
||||
* and `?ui=4.3.0` the version the bundle was built as. A missing or malformed value
|
||||
* means none, which is what every bundle before these parameters sent.
|
||||
*/
|
||||
function parseSupports(raw: string | string[] | undefined): Set<string> {
|
||||
const values = Array.isArray(raw) ? raw : [raw];
|
||||
@@ -30,8 +30,12 @@ export class SystemNoticesController {
|
||||
constructor(private readonly notices: SystemNoticesService) {}
|
||||
|
||||
@Get('active')
|
||||
active(@CurrentUser() user: User, @Query('supports') supports?: string | string[]): SystemNoticeDto[] {
|
||||
return this.notices.getActiveFor(user.id, parseSupports(supports));
|
||||
active(
|
||||
@CurrentUser() user: User,
|
||||
@Query('supports') supports?: string | string[],
|
||||
@Query('ui') ui?: string | string[],
|
||||
): SystemNoticeDto[] {
|
||||
return this.notices.getActiveFor(user.id, parseSupports(supports), typeof ui === 'string' ? ui.trim() : undefined);
|
||||
}
|
||||
|
||||
@Post(':id/dismiss')
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import semver from 'semver';
|
||||
import type { SystemNoticeDto } from '@trek/shared';
|
||||
import { getActiveNoticesFor, dismissNotice } from '../../systemNotices/service';
|
||||
import { getActiveNoticesFor, dismissNotice, getCurrentAppVersion } from '../../systemNotices/service';
|
||||
import { AddonsService } from '../addons/addons.service';
|
||||
import { RuntimeEnvService } from '../app-config/runtime-env.service';
|
||||
|
||||
@@ -19,22 +20,35 @@ export class SystemNoticesService {
|
||||
) {}
|
||||
|
||||
/**
|
||||
* `supports` names the layouts the calling bundle can draw. A notice with a release
|
||||
* block is held back from a bundle that does not name `release`: after an update the
|
||||
* service worker keeps serving the previous bundle until the new one is installed,
|
||||
* and that bundle would draw the release notice as bare keys and let the reader
|
||||
* dismiss it for good, because the dismissal is recorded against the server's
|
||||
* version. A bundle that never sends the parameter loses only the notice it could
|
||||
* not read anyway and gets it after the reload. Nothing is spent by holding it back:
|
||||
* a notice is used up by a dismissal and by nothing else.
|
||||
* `supports` names the layouts the calling bundle can draw, `uiVersion` the version
|
||||
* that bundle was built as. A notice with a release block goes only to a bundle that
|
||||
* names `release` AND was built for the version the server is running: after an
|
||||
* update the service worker keeps serving the previous bundle until the new one is
|
||||
* installed, and that bundle would draw the release notice with its own, older
|
||||
* texts (or as bare keys) and let the reader dismiss it for good, because the
|
||||
* dismissal is recorded against the server's version. The version match is what
|
||||
* makes this hold for every update, not only the one that introduced the
|
||||
* parameter: a 4.3.0 shell asking a 4.3.1 server is told nothing, and gets the
|
||||
* notice after the reload from the bundle that can draw it. A bundle that sends
|
||||
* neither loses only the notice it could not read anyway. Nothing is spent by
|
||||
* holding it back: a notice is used up by a dismissal and by nothing else.
|
||||
*/
|
||||
getActiveFor(userId: number, supports: ReadonlySet<string> = new Set()): SystemNoticeDto[] {
|
||||
getActiveFor(userId: number, supports: ReadonlySet<string> = new Set(), uiVersion?: string): SystemNoticeDto[] {
|
||||
const notices = getActiveNoticesFor(
|
||||
userId,
|
||||
(addonId) => this.addons.isAddonEnabled(addonId),
|
||||
this.env.isManaged(),
|
||||
) as SystemNoticeDto[];
|
||||
return supports.has('release') ? notices : notices.filter(n => !n.release);
|
||||
return supports.has('release') && this.bundleMatchesServer(uiVersion)
|
||||
? notices
|
||||
: notices.filter(n => !n.release);
|
||||
}
|
||||
|
||||
/** Whether the bundle asking was built for the version this server runs. */
|
||||
private bundleMatchesServer(uiVersion: string | undefined): boolean {
|
||||
const ui = uiVersion ? semver.coerce(uiVersion)?.version : undefined;
|
||||
const app = semver.coerce(getCurrentAppVersion())?.version;
|
||||
return !!ui && !!app && ui === app;
|
||||
}
|
||||
|
||||
dismiss(userId: number, noticeId: string): boolean {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { SYSTEM_NOTICES } from './registry.js';
|
||||
import { evaluate } from './conditions.js';
|
||||
import type { SystemNotice, SystemNoticeDTO } from './types.js';
|
||||
|
||||
function getCurrentAppVersion(): string {
|
||||
export function getCurrentAppVersion(): string {
|
||||
const fromEnv = semver.valid(readEnv().app.appVersion ?? '');
|
||||
if (fromEnv) return fromEnv;
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user