/** * useMergeResolution Hook * * Central state machine for multi-document merge conflict resolution. * Manages document list, per-document strategy selection, cherry-pick * state, preview fetching, navigation, and merge execution. */ import type { P1Client, PuckData, DocumentConflictType, MergeRequest } from '@pantheon-systems/css-client'; import type { PuckFieldClassification } from './utils/puckFieldClassifier.js'; export type DocumentResolutionStrategy = 'accept-draft' | 'accept-live' | 'cherry-pick' | 'unresolved'; /** How this document changed in the merge */ export type DocumentChangeType = 'new-on-draft' | 'draft-changed' | 'conflicting' | 'deleted-on-draft' | 'deleted-on-main'; export interface DocumentResolution { documentId: string; documentPath: string; strategy: DocumentResolutionStrategy; /** How this document changed in the merge */ changeType: DocumentChangeType; cherryPickSelections: Record; mergedSnapshot: PuckData | null; sourceSnapshot: PuckData | null; targetSnapshot: PuckData | null; conflictType: DocumentConflictType; classifiedFields: PuckFieldClassification[] | null; sourceVersionId?: string | null; targetVersionId?: string | null; /** * Set once a page's content and metadata are decided separately; * `strategy`/`mergedSnapshot` are then derived from the pair. */ aspects?: Record | null; /** The language tag the document carries on the source branch; null when it names none. */ sourceLocale?: string | null; /** * The language tag the document carries on the target branch; null when it * names none or the document is new on the source branch. */ targetLocale?: string | null; } export type DocumentAspect = 'content' | 'metadata'; export declare function aspectStrategy(doc: DocumentResolution, aspect: DocumentAspect): DocumentResolutionStrategy; export type GoLivePhase = 'idle' | 'preparing' | 'publishing' | 'finishing' | 'done' | 'failed'; export interface GoLiveState { phase: GoLivePhase; progress?: { processed: number; total: number; }; error?: string; failedDocuments?: { documentId: string; path: string; error: string | null; }[]; result?: { checkpointId?: string; }; } export interface UseMergeResolutionOptions { client: P1Client; siteId: string; sourceBranchId: string; targetBranchId: string; sourceBranchName: string; targetBranchName: string; /** When provided, only these documents are included after loadPreview. */ documentIds?: string[]; mode?: 'workstream' | 'workstream-page'; onStaleReview?: (newConflicts: number) => void; /** Override poll interval in ms (default 2000). Tests pass 0. */ pollIntervalMs?: number; } export interface UseMergeResolutionReturn { documents: DocumentResolution[]; currentIndex: number; currentDocument: DocumentResolution | null; totalCount: number; resolvedCount: number; unresolvedCount: number; allResolved: boolean; previewLoading: boolean; previewError: string | null; mergeExecuting: boolean; mergeError: string | null; mergeSuccess: boolean; mergeRequest: MergeRequest | null; mergeRequestCreating: boolean; mergeRequestError: string | null; /** @deprecated Use goLive() (added with the go-live flow); kept for existing callers. */ createMergeRequest: (title?: string) => Promise; /** @deprecated Use goLive() (added with the go-live flow); kept for existing callers. */ approveMergeRequest: () => Promise; goLiveState: GoLiveState; goLive: () => Promise; retryGoLive: () => Promise; goToDocument: (index: number) => void; goToNext: () => void; goToPrevious: () => void; goToNextUnresolved: () => void; /** `aspect` decides only that half of a page whose content and metadata are split. */ setStrategy: (documentId: string, strategy: DocumentResolutionStrategy, aspect?: DocumentAspect) => void; setAllStrategy: (strategy: 'accept-draft' | 'accept-live') => void; setRemainingStrategy: (strategy: 'accept-draft' | 'accept-live') => void; setCherryPickSelection: (documentId: string, componentId: string, propName: string, choice: 'source' | 'target') => void; acceptAllComponentProps: (documentId: string, componentId: string, choice: 'source' | 'target') => void; prepareCherryPick: (documentId: string) => void; setComponentSelection: (documentId: string, componentId: string, choice: 'source' | 'target') => void; setCherryPickAll: (documentId: string, choice: 'source' | 'target') => void; resetCherryPick: (documentId: string) => void; snapshotCherryPick: (documentId: string) => Record; restoreCherryPick: (documentId: string, selections: Record) => void; /** @deprecated Use goLive() (added with the go-live flow); kept for existing callers. */ executeMerge: (message?: string) => Promise; loadPreview: () => Promise; } export declare function isDeleteConflict(conflictType: DocumentConflictType): boolean; export declare function useMergeResolution(options: UseMergeResolutionOptions): UseMergeResolutionReturn;