feat(updates): "What's New" highlights after update + pre-update teaser
Surfaces release highlights to admins, sourced from the GitHub release notes (no AI at runtime). Bullets are written once per release in CI via GitHub Models (see docs/ci/whatsnew-highlights.yml) into a <!-- whatsnew --> block; the app reads that block and falls back to the changelog's "### Features" for releases without it — so it works against today's releases immediately. - backend utils/whatsNew.parseWhatsNew(body): curated block else Features section, strips scope/PR-links, de-dups, caps at 8 (tested). - GET /admin/system/updates/whatsnew: highlights for every version moved through since the per-instance marker (whatsnew_last_seen_version); fresh installs self-anchor silently. Best-effort, never errors. - POST /admin/system/updates/whatsnew/seen: advance the marker (per-instance). - /admin/system/updates also returns latestHighlights for the teaser. - Frontend: WhatsNewBanner (green bar -> modal with "Full changelog" link) on the dashboard via adminService; UpdateNotification shows a "New features include:" teaser. i18n de/en. No migration (uses app_settings).
This commit is contained in:
@@ -341,6 +341,22 @@ export interface AnalyticsData {
|
||||
devicesSource?: 'umami' | 'access_logs';
|
||||
}
|
||||
|
||||
export interface WhatsNewVersion {
|
||||
version: string;
|
||||
name: string;
|
||||
htmlUrl: string;
|
||||
publishedAt: string;
|
||||
bullets: string[];
|
||||
}
|
||||
|
||||
export interface WhatsNewResponse {
|
||||
enabled: boolean;
|
||||
hasNews: boolean;
|
||||
fromVersion?: string;
|
||||
toVersion?: string;
|
||||
versions?: WhatsNewVersion[];
|
||||
}
|
||||
|
||||
export const adminService = {
|
||||
// Dashboard statistics
|
||||
async getDashboardStats(): Promise<DashboardStats> {
|
||||
@@ -370,6 +386,16 @@ export const adminService = {
|
||||
return response.data;
|
||||
},
|
||||
|
||||
// After-update "What's New" highlights (per-instance acknowledgement).
|
||||
async getWhatsNew(): Promise<WhatsNewResponse> {
|
||||
const response = await api.get<WhatsNewResponse>('/admin/system/updates/whatsnew');
|
||||
return response.data;
|
||||
},
|
||||
|
||||
async markWhatsNewSeen(): Promise<void> {
|
||||
await api.post('/admin/system/updates/whatsnew/seen');
|
||||
},
|
||||
|
||||
// Backup-integrity verifier (read-only diagnostic). `scope` filters
|
||||
// which document classes to walk; omit for a full scan.
|
||||
async getBackupIntegrity(
|
||||
|
||||
Reference in New Issue
Block a user