feat: Display a toast notification after library migration, powered by new migration status in the API response.
This commit is contained in:
parent
f11c015f7e
commit
741126c0b4
3 changed files with 33 additions and 9 deletions
|
|
@ -114,8 +114,8 @@ export async function POST(request: NextRequest) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await ensureDocumentsV1Ready();
|
const documentsMigrated = await ensureDocumentsV1Ready();
|
||||||
await ensureAudiobooksV1Ready();
|
const audiobooksMigrated = await ensureAudiobooksV1Ready();
|
||||||
const rekey = await rekeyAudiobooksV1(mappings);
|
const rekey = await rekeyAudiobooksV1(mappings);
|
||||||
|
|
||||||
const documentsReady = await isDocumentsV1Ready();
|
const documentsReady = await isDocumentsV1Ready();
|
||||||
|
|
@ -125,6 +125,8 @@ export async function POST(request: NextRequest) {
|
||||||
success: true,
|
success: true,
|
||||||
documentsReady,
|
documentsReady,
|
||||||
audiobooksReady,
|
audiobooksReady,
|
||||||
|
documentsMigrated,
|
||||||
|
audiobooksMigrated,
|
||||||
rekey,
|
rekey,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
|
|
@ -103,11 +103,31 @@ export function ConfigProvider({ children }: { children: ReactNode }) {
|
||||||
|
|
||||||
// Run server-side v1 migrations proactively, since the client may now
|
// Run server-side v1 migrations proactively, since the client may now
|
||||||
// reference SHA-based IDs immediately after the Dexie migration.
|
// reference SHA-based IDs immediately after the Dexie migration.
|
||||||
await fetch('/api/migrations/v1', {
|
const response = await fetch('/api/migrations/v1', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ mappings }),
|
body: JSON.stringify({ mappings }),
|
||||||
}).catch(() => undefined);
|
}).catch(() => null);
|
||||||
|
|
||||||
|
if (response?.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
const didMigrate =
|
||||||
|
data.documentsMigrated ||
|
||||||
|
data.audiobooksMigrated ||
|
||||||
|
(data.rekey?.renamed ?? 0) > 0 ||
|
||||||
|
(data.rekey?.merged ?? 0) > 0;
|
||||||
|
|
||||||
|
if (didMigrate) {
|
||||||
|
toast.success('Library migration complete', {
|
||||||
|
duration: 5000,
|
||||||
|
icon: '📦',
|
||||||
|
style: {
|
||||||
|
background: 'var(--offbase)',
|
||||||
|
color: 'var(--foreground)',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('Startup migrations failed:', error);
|
console.warn('Startup migrations failed:', error);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,18 +101,18 @@ function safeDocumentName(rawName: string, fallback: string): string {
|
||||||
return baseName.replaceAll('\u0000', '').slice(0, 240) || fallback;
|
return baseName.replaceAll('\u0000', '').slice(0, 240) || fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function ensureDocumentsV1Ready(): Promise<void> {
|
export async function ensureDocumentsV1Ready(): Promise<boolean> {
|
||||||
await mkdir(DOCSTORE_DIR, { recursive: true });
|
await mkdir(DOCSTORE_DIR, { recursive: true });
|
||||||
await mkdir(DOCUMENTS_V1_DIR, { recursive: true });
|
await mkdir(DOCUMENTS_V1_DIR, { recursive: true });
|
||||||
|
|
||||||
const state = await loadMigrationState();
|
const state = await loadMigrationState();
|
||||||
if (state.documentsV1Migrated && !(await hasLegacyDocumentFiles())) {
|
if (state.documentsV1Migrated && !(await hasLegacyDocumentFiles())) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(await hasLegacyDocumentFiles())) {
|
if (!(await hasLegacyDocumentFiles())) {
|
||||||
await saveMigrationState({ documentsV1Migrated: true });
|
await saveMigrationState({ documentsV1Migrated: true });
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let entries: Array<import('fs').Dirent> = [];
|
let entries: Array<import('fs').Dirent> = [];
|
||||||
|
|
@ -165,6 +165,7 @@ export async function ensureDocumentsV1Ready(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
await saveMigrationState({ documentsV1Migrated: !(await hasLegacyDocumentFiles()) });
|
await saveMigrationState({ documentsV1Migrated: !(await hasLegacyDocumentFiles()) });
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function hasLegacyAudiobookDirs(): Promise<boolean> {
|
async function hasLegacyAudiobookDirs(): Promise<boolean> {
|
||||||
|
|
@ -269,7 +270,7 @@ async function mergeDirectoryContents(sourceDir: string, targetDir: string): Pro
|
||||||
return { moved, skipped };
|
return { moved, skipped };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function ensureAudiobooksV1Ready(): Promise<void> {
|
export async function ensureAudiobooksV1Ready(): Promise<boolean> {
|
||||||
await mkdir(DOCSTORE_DIR, { recursive: true });
|
await mkdir(DOCSTORE_DIR, { recursive: true });
|
||||||
await mkdir(AUDIOBOOKS_V1_DIR, { recursive: true });
|
await mkdir(AUDIOBOOKS_V1_DIR, { recursive: true });
|
||||||
|
|
||||||
|
|
@ -284,7 +285,7 @@ export async function ensureAudiobooksV1Ready(): Promise<void> {
|
||||||
if (hasExtraKeys) {
|
if (hasExtraKeys) {
|
||||||
await saveMigrationState({ audiobooksV1Migrated: true });
|
await saveMigrationState({ audiobooksV1Migrated: true });
|
||||||
}
|
}
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let entries: Array<import('fs').Dirent> = [];
|
let entries: Array<import('fs').Dirent> = [];
|
||||||
|
|
@ -333,6 +334,7 @@ export async function ensureAudiobooksV1Ready(): Promise<void> {
|
||||||
const finalLegacyRemaining = await hasLegacyAudiobookDirs();
|
const finalLegacyRemaining = await hasLegacyAudiobookDirs();
|
||||||
const finalLegacyChaptersRemaining = await hasLegacyAudiobookChapterLayout();
|
const finalLegacyChaptersRemaining = await hasLegacyAudiobookChapterLayout();
|
||||||
await saveMigrationState({ audiobooksV1Migrated: !finalLegacyRemaining && !finalLegacyChaptersRemaining });
|
await saveMigrationState({ audiobooksV1Migrated: !finalLegacyRemaining && !finalLegacyChaptersRemaining });
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
type LegacyChapterMeta = {
|
type LegacyChapterMeta = {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue