mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 07:15: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();
|
||||
});
|
||||
|
||||
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 () => {
|
||||
localStorage.setItem(DONE_FLAG, '1');
|
||||
let resolveInspect: ((value: any) => void) | undefined;
|
||||
|
||||
@@ -33,11 +33,11 @@ function buildMappings(): ServerIndexMapping[] {
|
||||
|
||||
async function runGenreTagsPhase(): Promise<void> {
|
||||
const state = useMigrationStore.getState();
|
||||
state.setStep('genreTags');
|
||||
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();
|
||||
state.setGenreTagsInspect(inspect);
|
||||
if (!inspect.needed) {
|
||||
@@ -45,6 +45,8 @@ async function runGenreTagsPhase(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
state.setStep('genreTags');
|
||||
state.setError(null);
|
||||
state.setPhase('running');
|
||||
const maxAttempts = 3;
|
||||
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
||||
|
||||
Reference in New Issue
Block a user