/** * P1 Puck Plugin * * Adds P1 functionality to the Puck editor's plugin rail. * Provides branch selection, document management, and other P1-specific controls. */ import React from 'react'; import type { Branch, Document, DocumentLiveState, DocumentVersion, PuckData, RegisteredAgent, ActorPresence, UnpublishDocumentOptions } from '@pantheon-systems/css-client'; import type { PageNotFoundProps } from '../../pds/components/PageNotFound.js'; import type { SiteMenuItem, CurrentUser } from '../../pds/components/P1EditorHeader.js'; import type { Template } from '../../features/content-type-templates/types.js'; import type { TemplateSummary } from '../../features/content-type-templates/types.js'; import type { LogoutStore } from '../logout-store.js'; import type { DocumentSyncStore } from './document-sync-plugin.js'; /** * Watches for changes to permission-affecting state (user role, template, * historical version) and forces Puck to re-resolve all component permissions. * * Puck caches resolvePermissions results per component instance and only * re-resolves when the component's own data changes. Changes to the * resolver function (from role/template switches) don't invalidate the cache. * This component bridges that gap by calling refreshPermissions(force=true) * whenever the P1 permission resolver reference changes. */ export declare function PermissionRefresher(): React.ReactElement | null; /** * Everything the canvas panel needs except the way home, which the editor supplies. */ export type PageNotFoundCanvasState = Omit; /** * Options for creating the P1 Plugin */ export interface P1PluginOptions { /** List of available branches */ branches: Branch[]; /** Currently selected branch */ currentBranch: Branch | null; /** Callback when branch is switched */ onBranchSwitch: (branchId: string) => void; /** Getter function to check if there are unsaved changes (function to avoid stale closures) */ getHasUnsavedChanges?: () => boolean; /** List of documents on the current branch */ documents?: Document[]; /** Currently selected document path */ selectedDocumentPath?: string | null; /** Callback when a document is selected */ onDocumentSelect?: (path: string) => void; /** * Set by `useP1Editor` when the open path has no page. Renders the * page-not-found panel in the canvas, leaving the editor chrome in place. */ pageNotFound?: PageNotFoundProps | null; /** Callback to create a new document */ onDocumentCreate?: (path: string, template?: TemplateSummary | null, title?: string, locale?: string) => Promise; /** Hand a "Generate with AI" brief (+ the new page's path/title) to the chatbot. */ onGenerateWithAI?: (brief: string, page: { path: string; title: string; }) => void; /** Whether a page already lives at a path on the current branch. */ isPathTaken?: (path: string) => Promise; /** Show the header's Zappy AI Assistant toggle. Pass the same flag that gates the chat plugin. */ showAIPanelToggle?: boolean; /** Callback to delete a document */ onDocumentDelete?: (documentId: string, path: string) => Promise; /** Whether documents are loading */ documentsLoading?: boolean; /** List of versions for the current document */ versions?: DocumentVersion[]; /** Whether versions are loading */ versionsLoading?: boolean; /** @deprecated No longer used by the editor UI. Will be removed in a future release. */ publishedStatus?: 'published' | 'unpublished-changes' | 'draft'; /** Currently selected version ID for comparison */ selectedVersionId?: string; /** Callback when a version is selected */ onVersionSelect?: (version: DocumentVersion) => void; /** Callback when user restores a previous version to current. Calls POST .../versions/:id/restore server-side. */ onRestoreVersion?: (version: DocumentVersion) => Promise; /** Whether the current user is allowed to revert versions. */ canRevert?: boolean; /** Resolves a display name for a version author. Falls back to createdById or type label. */ resolveAuthorName?: (id: string, type: 'user' | 'agent') => string | undefined; /** Callback to compare two versions */ onCompare?: (beforeVersionId: string, afterVersionId: string) => void; /** * Data to sync to Puck's internal state. Used with dataSyncKey * to update Puck's data without remounting (preserving sidebar state). * This is rendered inside the plugin which is guaranteed to be inside Puck's context. * @deprecated Use getSyncData getter for better performance (avoids plugin recreation) */ syncData?: PuckData | null; /** * Key that changes when we want to force a data sync to Puck. * Use version ID or document ID to trigger sync on version/document changes. * @deprecated Use getDataSyncKey getter for better performance (avoids plugin recreation) */ dataSyncKey?: string | null; /** * Getter function for sync data. Preferred over syncData to avoid plugin recreation * on every sync, which reduces flickering during real-time collaboration. */ getSyncData?: () => PuckData | undefined; /** * Getter function for data sync key. Preferred over dataSyncKey to avoid plugin recreation * on every sync, which reduces flickering during real-time collaboration. */ getDataSyncKey?: () => string | undefined; /** * When true, the plugin reads sync data directly from P1PuckContext. * This is the recommended approach as it keeps sync logic in the integration layer. * When false, you must provide syncData/dataSyncKey or getSyncData/getDataSyncKey. * @default true */ useContextSync?: boolean; /** * Document-sync store shared with the document-sync plugin. When present, * context-based sync leaves document switches to that plugin — see * resolveContextSyncKey. */ documentSyncStore?: Pick; /** Whether to show presence indicator in the plugin panel */ showPresenceIndicator?: boolean; /** Current presence list */ presence?: ActorPresence[]; /** Whether to show agent activity section */ showAgentActivity?: boolean; /** Currently active agents */ activeAgents?: ActorPresence[]; /** Whether to show agent action trigger button */ showAgentActions?: boolean; /** Available agents for triggering actions */ availableAgents?: RegisteredAgent[]; /** Callback when agent action is triggered */ onAgentAction?: (agentId: string, intent: string, targetRegions?: string[]) => void; /** Callback when stop agent button is clicked */ onStopAgent?: (agent: ActorPresence) => void; /** Whether to show focus regions being edited */ showFocusRegions?: boolean; /** Regions currently being edited by agents */ agentEditingRegions?: string[]; /** Puck config for rendering merge previews. When provided, enables the built-in merge review overlay. */ puckConfig?: unknown; /** * Callback when user selection changes in the Puck editor. * Used to report focus regions for proactive collision detection. * @param path - JSON path of selected item (e.g., "/content/0"), or null if deselected * @param itemId - Component ID, or null if deselected */ onSelectionChange?: (path: string | null, itemId: string | null) => void; /** Site name displayed in the editor header */ siteName?: string; /** Menu items shown in the site dropdown */ siteMenuItems?: SiteMenuItem[]; /** Site ID for linking to the P1 dashboard */ siteId?: string; /** Base URL for the P1 dashboard (defaults to https://content.pantheon.io) */ dashboardUrl?: string; /** Custom logo image URL for the editor header */ logoUrl?: string; /** Currently authenticated user */ currentUser?: CurrentUser; /** Callback when user logs out */ onLogout?: () => void | Promise; /** Logout progress and failure state. The header subscribes to it directly. */ logoutStore?: LogoutStore; /** @deprecated No longer used by the editor UI. Will be removed in a future release. */ onCompareWithLive?: () => void; /** Live site URL for the publish popover's "View site" link and copy button. */ siteUrl?: string; /** Shows the demo go-live screens. Set by the editor from LaunchDarkly. */ goLiveStub?: boolean; /** Callback for the publish action. When omitted, context's publishDocument is used. */ onPublish?: () => Promise | void; /** * Unpublishes the open page from live, sending its visitors to `redirectTo` when given; `childDocumentIds` and * `translationDocumentIds` also take down those pages. Adds Unpublish to the Live publish menu. * `options` carries `redirectTo` too, so it can be passed to `documents.unpublish` as it is. */ onUnpublish?: (redirectTo?: string, options?: UnpublishDocumentOptions) => Promise; /** Whether the open page is live. Main branch only. */ liveState?: DocumentLiveState; /** Where visitors to the open page are redirected while it is unpublished. */ unpublishRedirectTo?: string; /** Callback for the per-page go live action (branch context only). */ onGoLivePage?: () => void; /** Callback for the Review & Publish action */ onReviewAndPublish?: () => void; /** Callback for the Review Workstream action (shown when on a branch) */ onReviewWorkstream?: () => void; /** Callback for the Create Workstream action */ onCreateWorkstream?: () => void; /** Called when the user creates a new workstream. Receives the branch name. */ onCreateBranch?: (name: string) => Promise; /** Called after a go-live deployment completes (success or failure) and the user dismisses the result screen. */ onGoLiveComplete?: () => void; /** Available templates for document creation */ templates?: TemplateSummary[]; /** Whether templates are loading */ templatesLoading?: boolean; /** Create a new template (Create Page modal's "New template" flow). */ onCreateTemplate?: (params: { name: string; label: string; description?: string; defaultUrlPattern?: string; }) => Promise