import { useParams } from 'common' import { ArrowUpCircle, Edit, MoreVertical, Pause, Play, RotateCcw, Trash } from 'lucide-react' import { parseAsInteger, useQueryState } from 'nuqs' import { toast } from 'sonner' import { Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from 'ui' import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader' import { getStatusName, PIPELINE_DISABLE_ALLOWED_FROM, PIPELINE_ENABLE_ALLOWED_FROM, PIPELINE_ERROR_MESSAGES, } from './Pipeline.utils' import { PipelineStatusName } from './Replication.constants' import AlertError from '@/components/ui/AlertError' import { ReplicationPipelineStatusData } from '@/data/replication/pipeline-status-query' import { Pipeline } from '@/data/replication/pipelines-query' import { useRestartPipelineHelper } from '@/data/replication/restart-pipeline-helper' import { useStartPipelineMutation } from '@/data/replication/start-pipeline-mutation' import { useStopPipelineMutation } from '@/data/replication/stop-pipeline-mutation' import { PipelineStatusRequestStatus, usePipelineRequestStatus, } from '@/state/replication-pipeline-request-status' import type { ResponseError } from '@/types' interface RowMenuProps { destinationId: number pipeline: Pipeline | undefined pipelineStatus?: ReplicationPipelineStatusData['status'] error: ResponseError | null isLoading: boolean isError: boolean hasUpdate?: boolean onDeleteClick: () => void onUpdateClick?: () => void } export const RowMenu = ({ destinationId, pipeline, pipelineStatus, error, isLoading, isError, hasUpdate = false, onDeleteClick, onUpdateClick, }: RowMenuProps) => { const { ref: projectRef } = useParams() const statusName = getStatusName(pipelineStatus) const [, setEdit] = useQueryState( 'edit', parseAsInteger.withOptions({ history: 'push', clearOnDefault: true }) ) const { mutateAsync: startPipeline } = useStartPipelineMutation() const { mutateAsync: stopPipeline } = useStopPipelineMutation() const { restartPipeline } = useRestartPipelineHelper() const { getRequestStatus, setRequestStatus: setGlobalRequestStatus } = usePipelineRequestStatus() const requestStatus = pipeline?.id ? getRequestStatus(pipeline.id) : PipelineStatusRequestStatus.None // Show actions when not in a transitional state const canPerformActions = requestStatus === PipelineStatusRequestStatus.None && statusName !== PipelineStatusName.STARTING && [PipelineStatusName.STOPPED, PipelineStatusName.STARTED, PipelineStatusName.FAILED].includes( statusName as PipelineStatusName ) // Show both stop and restart for started/failed states const showStopAndRestart = canPerformActions && (statusName === PipelineStatusName.STARTED || statusName === PipelineStatusName.FAILED) // Show only start for stopped state const showStart = canPerformActions && statusName === PipelineStatusName.STOPPED const onEnablePipeline = async () => { if (!projectRef) return console.error('Project ref is required') if (!pipeline) return toast.error(PIPELINE_ERROR_MESSAGES.NO_PIPELINE_FOUND) try { // Only show 'enabling' when transitioning from allowed states if (PIPELINE_ENABLE_ALLOWED_FROM.includes(statusName as any)) { setGlobalRequestStatus(pipeline.id, PipelineStatusRequestStatus.StartRequested, statusName) } await startPipeline({ projectRef, pipelineId: pipeline.id }) } catch (error) { setGlobalRequestStatus(pipeline.id, PipelineStatusRequestStatus.None) toast.error(PIPELINE_ERROR_MESSAGES.ENABLE_DESTINATION) } } const onDisablePipeline = async () => { if (!projectRef) return console.error('Project ref is required') if (!pipeline) return toast.error(PIPELINE_ERROR_MESSAGES.NO_PIPELINE_FOUND) try { // Only show 'disabling' when transitioning from allowed states if (PIPELINE_DISABLE_ALLOWED_FROM.includes(statusName as any)) { setGlobalRequestStatus(pipeline.id, PipelineStatusRequestStatus.StopRequested, statusName) } await stopPipeline({ projectRef, pipelineId: pipeline.id }) } catch (error) { setGlobalRequestStatus(pipeline.id, PipelineStatusRequestStatus.None) toast.error(PIPELINE_ERROR_MESSAGES.DISABLE_DESTINATION) } } const onRestartPipeline = async () => { if (!projectRef) return console.error('Project ref is required') if (!pipeline) return toast.error(PIPELINE_ERROR_MESSAGES.NO_PIPELINE_FOUND) try { setGlobalRequestStatus(pipeline.id, PipelineStatusRequestStatus.RestartRequested, statusName) await restartPipeline({ projectRef, pipelineId: pipeline.id }) } catch (error) { setGlobalRequestStatus(pipeline.id, PipelineStatusRequestStatus.None) toast.error(PIPELINE_ERROR_MESSAGES.ENABLE_DESTINATION) } } return (
Update available
Start pipeline
Restart pipeline
Stop pipeline
Edit destination
Delete destination