diff --git a/posthog/api/batch_imports.py b/posthog/api/batch_imports.py
index d1d4f7fd8f..4dacde6dc0 100644
--- a/posthog/api/batch_imports.py
+++ b/posthog/api/batch_imports.py
@@ -427,7 +427,7 @@ class BatchImportViewSet(TeamAndOrgViewSetMixin, viewsets.ModelViewSet):
return Response(response_serializer.data, status=status.HTTP_201_CREATED)
@action(methods=["POST"], detail=True)
- def pause(self, request: Request, pk=None) -> Response:
+ def pause(self, request: Request, **kwargs) -> Response:
"""Pause a running batch import."""
batch_import = self.get_object()
@@ -444,7 +444,7 @@ class BatchImportViewSet(TeamAndOrgViewSetMixin, viewsets.ModelViewSet):
return Response({"status": "paused"})
@action(methods=["POST"], detail=True)
- def resume(self, request: Request, pk=None) -> Response:
+ def resume(self, request: Request, **kwargs) -> Response:
"""Resume a paused batch import."""
batch_import = self.get_object()
diff --git a/products/managed_migrations/frontend/ManagedMigration.tsx b/products/managed_migrations/frontend/ManagedMigration.tsx
index f7c814a055..0ae3d9b2f8 100644
--- a/products/managed_migrations/frontend/ManagedMigration.tsx
+++ b/products/managed_migrations/frontend/ManagedMigration.tsx
@@ -214,6 +214,7 @@ export function ManagedMigration(): JSX.Element {
export function ManagedMigrations(): JSX.Element {
const { managedMigrationId, migrations, migrationsLoading } = useValues(managedMigrationLogic)
+ const { pauseMigration, resumeMigration } = useActions(managedMigrationLogic)
const calculateProgress = (migration: ManagedMigration): { progress: number; completed: number; total: number } => {
if (migration.state?.parts && Array.isArray(migration.state.parts)) {
@@ -399,6 +400,36 @@ export function ManagedMigrations(): JSX.Element {
dataIndex: 'status_message',
render: (_: any, migration: ManagedMigration) => migration.status_message || '-',
},
+ {
+ title: 'Actions',
+ key: 'actions',
+ render: (_: any, migration: ManagedMigration) => {
+ if (migration.status === 'running') {
+ return (
+ pauseMigration(migration.id)}
+ loading={migrationsLoading}
+ >
+ Pause
+
+ )
+ } else if (migration.status === 'paused') {
+ return (
+ resumeMigration(migration.id)}
+ loading={migrationsLoading}
+ >
+ Resume
+
+ )
+ }
+ return null
+ },
+ },
]}
emptyState="No migrations found. Create a new migration to get started."
/>
diff --git a/products/managed_migrations/frontend/managedMigrationLogic.ts b/products/managed_migrations/frontend/managedMigrationLogic.ts
index bf6aed3d89..2d77ba5fc2 100644
--- a/products/managed_migrations/frontend/managedMigrationLogic.ts
+++ b/products/managed_migrations/frontend/managedMigrationLogic.ts
@@ -57,6 +57,8 @@ export const managedMigrationLogic = kea([
}),
actions({
editManagedMigration: (id: string | null) => ({ id }),
+ pauseMigration: (id: string) => ({ id }),
+ resumeMigration: (id: string) => ({ id }),
startPolling: true,
stopPolling: true,
}),
@@ -179,6 +181,26 @@ export const managedMigrationLogic = kea([
lemonToast.error('Failed to create migration. Please try again.')
}
},
+ pauseMigration: async ({ id }) => {
+ try {
+ const projectId = ApiConfig.getCurrentProjectId()
+ await api.create(`api/projects/${projectId}/managed_migrations/${id}/pause/`)
+ lemonToast.success('Migration paused successfully')
+ actions.loadMigrations()
+ } catch (error: any) {
+ lemonToast.error(error?.message || 'Failed to pause migration')
+ }
+ },
+ resumeMigration: async ({ id }) => {
+ try {
+ const projectId = ApiConfig.getCurrentProjectId()
+ await api.create(`api/projects/${projectId}/managed_migrations/${id}/resume/`)
+ lemonToast.success('Migration resumed successfully')
+ actions.loadMigrations()
+ } catch (error: any) {
+ lemonToast.error(error?.message || 'Failed to resume migration')
+ }
+ },
loadMigrationsSuccess: () => {
const hasRunningMigrations = values.migrations.some(
(migration: ManagedMigration) => migration.status === 'running'