mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-28 10:06:47 +00:00
fix(library): stop genre-tags migration gate flashing on every launch (#1061)
runGenreTagsPhase entered the blocking 'inspecting' phase before awaiting the inspect IPC, so the migration modal briefly appeared on every startup once the one-time genre backfill was already complete. Inspect first without a blocking phase and only switch to 'running' when work is actually needed.
This commit is contained in:
@@ -129,6 +129,40 @@ describe('useMigrationOrchestrator', () => {
|
|||||||
expect(rewriteFrontendStoreKeysMock).not.toHaveBeenCalled();
|
expect(rewriteFrontendStoreKeysMock).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('keeps startup non-blocking while genre-tags inspect is pending (no gate flash)', async () => {
|
||||||
|
localStorage.setItem(DONE_FLAG, '1');
|
||||||
|
migrationInspectMock.mockResolvedValue({
|
||||||
|
needsMigration: false,
|
||||||
|
hasSkippedUnknownServerRows: false,
|
||||||
|
canRun: true,
|
||||||
|
warnings: [],
|
||||||
|
unmappedEmptyBucket: false,
|
||||||
|
library: { totalLegacyRows: 0, skippedUnknownServerRows: 0, tables: {} },
|
||||||
|
analysis: { totalLegacyRows: 0, skippedUnknownServerRows: 0, tables: {} },
|
||||||
|
mappings: [{ legacyId: 'legacy-a', indexKey: 'a.test' }],
|
||||||
|
});
|
||||||
|
let resolveGenre: ((value: any) => void) | undefined;
|
||||||
|
libraryGenreTagsInspectMock.mockImplementation(
|
||||||
|
() => new Promise(resolve => { resolveGenre = resolve; }),
|
||||||
|
);
|
||||||
|
|
||||||
|
renderHook(() => useMigrationOrchestrator());
|
||||||
|
|
||||||
|
// Server-index precheck resolved; genre inspect still pending. The gate must
|
||||||
|
// not be blocking (phase stays 'idle', never 'inspecting'/'running').
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(libraryGenreTagsInspectMock).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
expect(useMigrationStore.getState().phase).toBe('idle');
|
||||||
|
|
||||||
|
if (!resolveGenre) throw new Error('genre inspect resolver not captured');
|
||||||
|
resolveGenre({ needed: false, totalTracks: 100, doneTracks: 100 });
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(useMigrationStore.getState().phase).toBe('completed');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('keeps startup non-blocking while done-flag precheck is pending', async () => {
|
it('keeps startup non-blocking while done-flag precheck is pending', async () => {
|
||||||
localStorage.setItem(DONE_FLAG, '1');
|
localStorage.setItem(DONE_FLAG, '1');
|
||||||
let resolveInspect: ((value: any) => void) | undefined;
|
let resolveInspect: ((value: any) => void) | undefined;
|
||||||
|
|||||||
@@ -33,11 +33,11 @@ function buildMappings(): ServerIndexMapping[] {
|
|||||||
|
|
||||||
async function runGenreTagsPhase(): Promise<void> {
|
async function runGenreTagsPhase(): Promise<void> {
|
||||||
const state = useMigrationStore.getState();
|
const state = useMigrationStore.getState();
|
||||||
state.setStep('genreTags');
|
|
||||||
state.setGenreTagsProgress(null);
|
state.setGenreTagsProgress(null);
|
||||||
state.setError(null);
|
|
||||||
state.setPhase('inspecting');
|
|
||||||
|
|
||||||
|
// Inspect first WITHOUT entering a blocking phase. An already-migrated launch
|
||||||
|
// must not flash the gate while this inspect IPC round-trips (regression: the
|
||||||
|
// modal briefly appeared on every startup once the backfill was complete).
|
||||||
const inspect = await libraryGenreTagsInspect();
|
const inspect = await libraryGenreTagsInspect();
|
||||||
state.setGenreTagsInspect(inspect);
|
state.setGenreTagsInspect(inspect);
|
||||||
if (!inspect.needed) {
|
if (!inspect.needed) {
|
||||||
@@ -45,6 +45,8 @@ async function runGenreTagsPhase(): Promise<void> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.setStep('genreTags');
|
||||||
|
state.setError(null);
|
||||||
state.setPhase('running');
|
state.setPhase('running');
|
||||||
const maxAttempts = 3;
|
const maxAttempts = 3;
|
||||||
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user