mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
fix migration dialog
This commit is contained in:
@@ -24,6 +24,7 @@ import {
|
|||||||
CURRENT_PROJECT_VERSION,
|
CURRENT_PROJECT_VERSION,
|
||||||
migrations,
|
migrations,
|
||||||
runStorageMigrations,
|
runStorageMigrations,
|
||||||
|
type MigrationProgress,
|
||||||
} from "@/services/storage/migrations";
|
} from "@/services/storage/migrations";
|
||||||
import { DEFAULT_TIMELINE_VIEW_STATE } from "@/constants/timeline-constants";
|
import { DEFAULT_TIMELINE_VIEW_STATE } from "@/constants/timeline-constants";
|
||||||
|
|
||||||
@@ -58,7 +59,13 @@ export class ProjectManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.storageMigrationPromise = (async () => {
|
this.storageMigrationPromise = (async () => {
|
||||||
await runStorageMigrations({ migrations });
|
await runStorageMigrations({
|
||||||
|
migrations,
|
||||||
|
onProgress: (progress: MigrationProgress) => {
|
||||||
|
this.migrationState = progress;
|
||||||
|
this.notify();
|
||||||
|
},
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
await this.storageMigrationPromise;
|
await this.storageMigrationPromise;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { V0toV1Migration } from "./v0-to-v1";
|
|||||||
import { V1toV2Migration } from "./v1-to-v2";
|
import { V1toV2Migration } from "./v1-to-v2";
|
||||||
import { V2toV3Migration } from "./v2-to-v3";
|
import { V2toV3Migration } from "./v2-to-v3";
|
||||||
export { runStorageMigrations } from "./runner";
|
export { runStorageMigrations } from "./runner";
|
||||||
|
export type { MigrationProgress } from "./runner";
|
||||||
|
|
||||||
export const CURRENT_PROJECT_VERSION = 3;
|
export const CURRENT_PROJECT_VERSION = 3;
|
||||||
|
|
||||||
|
|||||||
@@ -4,18 +4,27 @@ import {
|
|||||||
} from "@/services/storage/indexeddb-adapter";
|
} from "@/services/storage/indexeddb-adapter";
|
||||||
import type { StorageMigration } from "./base";
|
import type { StorageMigration } from "./base";
|
||||||
import type { ProjectRecord } from "./transformers/types";
|
import type { ProjectRecord } from "./transformers/types";
|
||||||
import { getProjectId } from "./transformers/utils";
|
import { getProjectId, isRecord } from "./transformers/utils";
|
||||||
|
|
||||||
export interface StorageMigrationResult {
|
export interface StorageMigrationResult {
|
||||||
migratedCount: number;
|
migratedCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MigrationProgress {
|
||||||
|
isMigrating: boolean;
|
||||||
|
fromVersion: number | null;
|
||||||
|
toVersion: number | null;
|
||||||
|
projectName: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
let hasCleanedUpMetaDb = false;
|
let hasCleanedUpMetaDb = false;
|
||||||
|
|
||||||
export async function runStorageMigrations({
|
export async function runStorageMigrations({
|
||||||
migrations,
|
migrations,
|
||||||
|
onProgress,
|
||||||
}: {
|
}: {
|
||||||
migrations: StorageMigration[];
|
migrations: StorageMigration[];
|
||||||
|
onProgress?: (progress: MigrationProgress) => void;
|
||||||
}): Promise<StorageMigrationResult> {
|
}): Promise<StorageMigrationResult> {
|
||||||
// One-time cleanup: delete the old global version database
|
// One-time cleanup: delete the old global version database
|
||||||
if (!hasCleanedUpMetaDb) {
|
if (!hasCleanedUpMetaDb) {
|
||||||
@@ -44,8 +53,20 @@ export async function runStorageMigrations({
|
|||||||
|
|
||||||
let projectRecord = project as ProjectRecord;
|
let projectRecord = project as ProjectRecord;
|
||||||
let currentVersion = getProjectVersion({ project: 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) {
|
for (const migration of orderedMigrations) {
|
||||||
if (migration.from !== currentVersion) {
|
if (migration.from !== currentVersion) {
|
||||||
continue;
|
continue;
|
||||||
@@ -54,24 +75,28 @@ export async function runStorageMigrations({
|
|||||||
const result = await migration.transform(projectRecord);
|
const result = await migration.transform(projectRecord);
|
||||||
|
|
||||||
if (result.skipped) {
|
if (result.skipped) {
|
||||||
break; // Project is already at this version or higher
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update project with migrated version
|
|
||||||
const projectId = getProjectId({ project: result.project });
|
const projectId = getProjectId({ project: result.project });
|
||||||
if (!projectId) {
|
if (!projectId) {
|
||||||
break; // Can't save without ID
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
await projectsAdapter.set(projectId, result.project);
|
await projectsAdapter.set(projectId, result.project);
|
||||||
migratedCount++;
|
migratedCount++;
|
||||||
currentVersion = migration.to;
|
currentVersion = migration.to;
|
||||||
|
|
||||||
// Use migrated project for next iteration
|
|
||||||
projectRecord = result.project;
|
projectRecord = result.project;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onProgress?.({
|
||||||
|
isMigrating: false,
|
||||||
|
fromVersion: null,
|
||||||
|
toVersion: null,
|
||||||
|
projectName: null,
|
||||||
|
});
|
||||||
|
|
||||||
return { migratedCount };
|
return { migratedCount };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,3 +117,17 @@ function getProjectVersion({ project }: { project: ProjectRecord }): number {
|
|||||||
// v0 - no scenes
|
// v0 - no scenes
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -148,7 +148,6 @@ async function migrateProject({
|
|||||||
|
|
||||||
const transformedTracks = await transformTracks({
|
const transformedTracks = await transformTracks({
|
||||||
tracks,
|
tracks,
|
||||||
projectId,
|
|
||||||
loadMediaAsset,
|
loadMediaAsset,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -252,11 +251,9 @@ async function loadTracksFromLegacyDB({
|
|||||||
|
|
||||||
async function transformTracks({
|
async function transformTracks({
|
||||||
tracks,
|
tracks,
|
||||||
projectId,
|
|
||||||
loadMediaAsset,
|
loadMediaAsset,
|
||||||
}: {
|
}: {
|
||||||
tracks: unknown[];
|
tracks: unknown[];
|
||||||
projectId: string;
|
|
||||||
loadMediaAsset?: ({
|
loadMediaAsset?: ({
|
||||||
mediaId,
|
mediaId,
|
||||||
}: {
|
}: {
|
||||||
@@ -279,7 +276,6 @@ async function transformTracks({
|
|||||||
if (trackType === "media") {
|
if (trackType === "media") {
|
||||||
const videoTrack = await transformMediaTrack({
|
const videoTrack = await transformMediaTrack({
|
||||||
track: track as LegacyMediaTrack,
|
track: track as LegacyMediaTrack,
|
||||||
projectId,
|
|
||||||
loadMediaAsset,
|
loadMediaAsset,
|
||||||
isMain: !isFirstVideoTrackFound,
|
isMain: !isFirstVideoTrackFound,
|
||||||
});
|
});
|
||||||
@@ -306,12 +302,10 @@ async function transformTracks({
|
|||||||
|
|
||||||
async function transformMediaTrack({
|
async function transformMediaTrack({
|
||||||
track,
|
track,
|
||||||
projectId,
|
|
||||||
loadMediaAsset,
|
loadMediaAsset,
|
||||||
isMain,
|
isMain,
|
||||||
}: {
|
}: {
|
||||||
track: LegacyMediaTrack;
|
track: LegacyMediaTrack;
|
||||||
projectId: string;
|
|
||||||
loadMediaAsset?: ({
|
loadMediaAsset?: ({
|
||||||
mediaId,
|
mediaId,
|
||||||
}: {
|
}: {
|
||||||
|
|||||||
@@ -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 { StorageMigration } from "./base";
|
||||||
import type { ProjectRecord } from "./transformers/types";
|
import type { ProjectRecord } from "./transformers/types";
|
||||||
import { transformProjectV0ToV1 } from "./transformers/v0-to-v1";
|
import { transformProjectV0ToV1 } from "./transformers/v0-to-v1";
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
/*
|
|
||||||
* Adds a "duration" field to each project's metadata
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { StorageMigration } from "./base";
|
import { StorageMigration } from "./base";
|
||||||
import type { ProjectRecord } from "./transformers/types";
|
import type { ProjectRecord } from "./transformers/types";
|
||||||
import { transformProjectV2ToV3 } from "./transformers/v2-to-v3";
|
import { transformProjectV2ToV3 } from "./transformers/v2-to-v3";
|
||||||
|
|||||||
Reference in New Issue
Block a user