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'