mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 07:15:47 +00:00
feat(whats-new): remote release notes with dev workspace mode (#1058)
* feat(whats-new): remote release notes with dev workspace mode Add WHATS_NEW.md, CI whats-new.md asset upload, and client fetch/cache with embedded fallbacks. Dev and -dev builds read the full file from the repo for debugging; RC/stable download the release asset on first use. * fix(whats-new): render ## headings and add changelog tab Parse h2 sections in release-notes markdown; load changelog alongside highlights and let users switch views on the What's New page. * fix(whats-new): prefetch on startup and fix CI typecheck prebuild Prefetch whats-new asset when the shell loads on RC/stable builds. Run prebuild:release-notes before tsc and coverage jobs so the gitignored generated bundle exists in CI. * docs: CHANGELOG and credits for What's New remote notes (PR #1058) * fix(whats-new): always slice embedded release notes to current line Drop full CHANGELOG embed for -dev bundles; tauri:dev still reads live markdown from the repo. Ignore all of src/generated/ in git. * fix(whats-new): fetch release asset via Rust to bypass CORS Route whats-new.md download through fetch_url_bytes; rename the technical tab label; add fetch unit tests (PR #1058 review).
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
import { useEffect } from 'react';
|
||||
import { version as appVersion } from '../../package.json';
|
||||
import { isWorkspaceReleaseNotesMode } from '../utils/releaseNotes/releaseNotesChannel';
|
||||
import { resolveReleaseNotes } from '../utils/releaseNotes/releaseNotesResolve';
|
||||
|
||||
/**
|
||||
* Warm the release-notes cache after an update (RC/stable only).
|
||||
* Runs once per app session; resolveReleaseNotes skips network when cached.
|
||||
*/
|
||||
export function usePrefetchReleaseNotes(version: string = appVersion): void {
|
||||
useEffect(() => {
|
||||
if (isWorkspaceReleaseNotesMode(version)) return;
|
||||
void resolveReleaseNotes(version).catch(() => {
|
||||
/* offline or missing asset — embedded fallback loads on /whats-new */
|
||||
});
|
||||
}, [version]);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { version as appVersion } from '../../package.json';
|
||||
import {
|
||||
resolveChangelogEntry,
|
||||
resolveReleaseNotes,
|
||||
type ReleaseNotesSource,
|
||||
} from '../utils/releaseNotes/releaseNotesResolve';
|
||||
import type { ReleaseNotesEntry } from '../utils/releaseNotes/releaseNotesMatch';
|
||||
|
||||
export interface UseReleaseNotesResult {
|
||||
loading: boolean;
|
||||
whatsNewEntry: ReleaseNotesEntry | null;
|
||||
changelogEntry: ReleaseNotesEntry | null;
|
||||
whatsNewSource: ReleaseNotesSource;
|
||||
}
|
||||
|
||||
export function useReleaseNotes(version: string = appVersion): UseReleaseNotesResult {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [whatsNewEntry, setWhatsNewEntry] = useState<ReleaseNotesEntry | null>(null);
|
||||
const [changelogEntry, setChangelogEntry] = useState<ReleaseNotesEntry | null>(null);
|
||||
const [whatsNewSource, setWhatsNewSource] = useState<ReleaseNotesSource>('empty');
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
setLoading(true);
|
||||
|
||||
Promise.all([resolveReleaseNotes(version), resolveChangelogEntry(version)])
|
||||
.then(([whatsNew, changelog]) => {
|
||||
if (cancelled) return;
|
||||
setWhatsNewEntry(whatsNew.entry);
|
||||
setWhatsNewSource(whatsNew.source);
|
||||
setChangelogEntry(changelog.entry);
|
||||
})
|
||||
.catch(() => {
|
||||
if (cancelled) return;
|
||||
setWhatsNewEntry(null);
|
||||
setChangelogEntry(null);
|
||||
setWhatsNewSource('empty');
|
||||
})
|
||||
.finally(() => {
|
||||
if (!cancelled) setLoading(false);
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [version]);
|
||||
|
||||
return { loading, whatsNewEntry, changelogEntry, whatsNewSource };
|
||||
}
|
||||
Reference in New Issue
Block a user