fix migration dialog

This commit is contained in:
Maze Winther 2026-02-05 14:28:16 +01:00
parent 2257ca2e6f
commit d0b4b1a5fc
6 changed files with 55 additions and 24 deletions

View File

@ -24,6 +24,7 @@ import {
CURRENT_PROJECT_VERSION,
migrations,
runStorageMigrations,
type MigrationProgress,
} from "@/services/storage/migrations";
import { DEFAULT_TIMELINE_VIEW_STATE } from "@/constants/timeline-constants";
@ -58,7 +59,13 @@ export class ProjectManager {
}
this.storageMigrationPromise = (async () => {
await runStorageMigrations({ migrations });
await runStorageMigrations({
migrations,
onProgress: (progress: MigrationProgress) => {
this.migrationState = progress;
this.notify();
},
});
})();
await this.storageMigrationPromise;

View File

@ -3,6 +3,7 @@ import { V0toV1Migration } from "./v0-to-v1";
import { V1toV2Migration } from "./v1-to-v2";
import { V2toV3Migration } from "./v2-to-v3";
export { runStorageMigrations } from "./runner";
export type { MigrationProgress } from "./runner";
export const CURRENT_PROJECT_VERSION = 3;

View File

@ -4,18 +4,27 @@ import {
} from "@/services/storage/indexeddb-adapter";
import type { StorageMigration } from "./base";
import type { ProjectRecord } from "./transformers/types";
import { getProjectId } from "./transformers/utils";
import { getProjectId, isRecord } from "./transformers/utils";
export interface StorageMigrationResult {
migratedCount: number;
}
export interface MigrationProgress {
isMigrating: boolean;
fromVersion: number | null;
toVersion: number | null;
projectName: string | null;
}
let hasCleanedUpMetaDb = false;
export async function runStorageMigrations({
migrations,
onProgress,
}: {
migrations: StorageMigration[];
onProgress?: (progress: MigrationProgress) => void;
}): Promise<StorageMigrationResult> {
// One-time cleanup: delete the old global version database
if (!hasCleanedUpMetaDb) {
@ -44,8 +53,20 @@ export async function runStorageMigrations({
let projectRecord = project as ProjectRecord;
let currentVersion = getProjectVersion({ project: projectRecord });
const targetVersion = orderedMigrations.at(-1)?.to ?? currentVersion;
if (currentVersion >= targetVersion) {
continue;
}
const projectName = getProjectName({ project: projectRecord });
onProgress?.({
isMigrating: true,
fromVersion: currentVersion,
toVersion: targetVersion,
projectName,
});
// Apply migrations sequentially until project is up to date
for (const migration of orderedMigrations) {
if (migration.from !== currentVersion) {
continue;
@ -54,24 +75,28 @@ export async function runStorageMigrations({
const result = await migration.transform(projectRecord);
if (result.skipped) {
break; // Project is already at this version or higher
break;
}
// Update project with migrated version
const projectId = getProjectId({ project: result.project });
if (!projectId) {
break; // Can't save without ID
break;
}
await projectsAdapter.set(projectId, result.project);
migratedCount++;
currentVersion = migration.to;
// Use migrated project for next iteration
projectRecord = result.project;
}
}
onProgress?.({
isMigrating: false,
fromVersion: null,
toVersion: null,
projectName: null,
});
return { migratedCount };
}
@ -92,3 +117,17 @@ function getProjectVersion({ project }: { project: ProjectRecord }): number {
// v0 - no scenes
return 0;
}
function getProjectName({ project }: { project: ProjectRecord }): string | null {
const metadata = project.metadata;
if (isRecord(metadata) && typeof metadata.name === "string") {
return metadata.name;
}
// v0 had name directly on project
if (typeof project.name === "string") {
return project.name;
}
return null;
}

View File

@ -148,7 +148,6 @@ async function migrateProject({
const transformedTracks = await transformTracks({
tracks,
projectId,
loadMediaAsset,
});
@ -252,11 +251,9 @@ async function loadTracksFromLegacyDB({
async function transformTracks({
tracks,
projectId,
loadMediaAsset,
}: {
tracks: unknown[];
projectId: string;
loadMediaAsset?: ({
mediaId,
}: {
@ -279,7 +276,6 @@ async function transformTracks({
if (trackType === "media") {
const videoTrack = await transformMediaTrack({
track: track as LegacyMediaTrack,
projectId,
loadMediaAsset,
isMain: !isFirstVideoTrackFound,
});
@ -306,12 +302,10 @@ async function transformTracks({
async function transformMediaTrack({
track,
projectId,
loadMediaAsset,
isMain,
}: {
track: LegacyMediaTrack;
projectId: string;
loadMediaAsset?: ({
mediaId,
}: {

View File

@ -1,9 +1,3 @@
/*
* Ensures every project has at least one scene
* Adds a default "Main scene" if none exist
* Sets currentSceneId to the new scene's id
*/
import { StorageMigration } from "./base";
import type { ProjectRecord } from "./transformers/types";
import { transformProjectV0ToV1 } from "./transformers/v0-to-v1";

View File

@ -1,7 +1,3 @@
/*
* Adds a "duration" field to each project's metadata
*/
import { StorageMigration } from "./base";
import type { ProjectRecord } from "./transformers/types";
import { transformProjectV2ToV3 } from "./transformers/v2-to-v3";