import { AfterViewInit, OnDestroy } from '@angular/core';
import { BaseEntity, CompositeKey } from '@memberjunction/core';
import type { UserInfo } from '@memberjunction/core';
import { ResourceData } from '@memberjunction/core-entities';
import type { MJConversationEntity } from '@memberjunction/core-entities';
import { BaseResourceComponent } from '@memberjunction/ng-shared';
import type { ComponentSpec } from '@memberjunction/interactive-component-types';
import type { MJTaskEntity } from '@memberjunction/core-entities';
import type { NavigationRequest } from '@memberjunction/ng-conversations';
import type { AppContextSnapshot } from '@memberjunction/ai-core-plus';
import { type CuratedFormSchema } from '@memberjunction/interactive-component-types/forms';
import { type FormCanvasElement, type FormCanvasModel, type FormCanvasSection } from '../ComponentStudio/services/form-canvas-model';
import type { FormOverrideDialogResult } from '../ComponentStudio/components/form-override-dialog.component';
import * as i0 from "@angular/core";
/**
 * Persisted shape for the cockpit's resizable-pane sizes + collapse state.
 * Versioned via the storage key (`v1`) so future schema changes can read +
 * migrate older JSON without breaking on shape drift.
 */
export interface FormBuilderPrefs {
    /** Percent (0-100) widths of the three top-level shell panes. */
    leftPanePct?: number;
    centerPanePct?: number;
    chatPanePct?: number;
    /** Collapse flags persist across reloads. */
    leftCollapsed?: boolean;
    chatCollapsed?: boolean;
    /** Last center-pane tab used (Preview / Code / Layout). */
    lastCenterPaneMode?: 'preview' | 'code' | 'layout';
    /** Height percent (0-100) for the forms-list section inside the left rail.
     *  The versions panel takes the remainder. Drag the splitter to change. */
    formsListHeightPct?: number;
    /** Inner-panel collapse flags (VS-Code-style). When true, that section
     *  shrinks to a header bar and the sibling takes full height. */
    formsListCollapsed?: boolean;
    versionsCollapsed?: boolean;
    /** 'list' (flat) | 'tree' (Schema → Entity → Forms). */
    formsViewMode?: 'list' | 'tree';
    /** Entity filter selection ('All' or specific entity name). */
    formsEntityFilter?: string;
    /** Status filter chips. Forms whose OverrideStatus is in this set show. */
    formsStatusFilter?: ReadonlyArray<'Active' | 'Pending' | 'Inactive'>;
    /** Sort mode. */
    formsSortMode?: 'updated-desc' | 'updated-asc' | 'name-asc' | 'name-desc';
    /** Component IDs the user has pinned to the top of the list. */
    pinnedFormIds?: ReadonlyArray<string>;
}
/**
 * One Component version in the active form's Name lineage. The version rail
 * lists these; clicking activates / previews / diffs.
 */
export interface ComponentVersionRow {
    ID: string;
    Name: string;
    Version: string;
    VersionSequence: number;
    Status: string;
    UpdatedAt: Date | null;
    /** True when this version is the one currently pointed at by an Active
     *  override for the calling user. */
    IsActive: boolean;
    /** True when this version is pointed at by a Pending override for the
     *  user (i.e. an AI-authored refinement awaiting activation). */
    IsPending: boolean;
}
/**
 * Lightweight summary of a form-role Component, populated from MJ: Components
 * for the left-rail picker. Specification is loaded on demand when the user
 * actually opens a form so we don't pay the JSON parse cost N times.
 */
interface FormComponentSummary {
    ID: string;
    Name: string;
    Namespace: string | null;
    /**
     * `Component.Status` (Draft / Published / Deprecated) — kept on the
     * summary for callers that need it (e.g. the version rail), but NOT
     * what the left rail badge displays. The left rail surfaces the
     * **override** status (see `OverrideStatus` below) because that's
     * what drives runtime visibility for the user.
     */
    Status: string | null;
    /**
     * The current user's `EntityFormOverride.Status` (Active / Inactive /
     * Pending) for this Component, when an override exists. Null when no
     * user-scope override binds to this Component — in which case the
     * runtime falls through to a higher-scope (Role/Global) override or
     * the CodeGen Angular default. Populated by `loadExistingForms` via
     * a single batch lookup against `MJ: Entity Form Overrides`.
     */
    OverrideStatus: 'Active' | 'Inactive' | 'Pending' | null;
    Description: string | null;
    TargetEntityName: string | null;
    /** Entity ID extracted from the user's override (when present) — used to
     *  resolve EntityInfo for icon/schema/name lookups. Null when no
     *  user-scope override binds to this Component. */
    TargetEntityID?: string | null;
    /** Cached entity display name (resolved via provider.EntityByName at
     *  loadExistingForms time). Used as the per-row entity subtitle. */
    TargetEntityDisplayName?: string | null;
    /** Cached entity icon class (Font Awesome) from EntityInfo.Icon. */
    TargetEntityIcon?: string | null;
    /** Cached entity schema name — drives tree-view grouping. */
    TargetEntitySchemaName?: string | null;
    /** Component row's last-modified timestamp — for "edited 2h ago" sorts. */
    UpdatedAt?: Date | null;
}
/**
 * Form Builder resource — the standalone Form Studio canvas reachable from
 * the top-left Application rail. Provides a drag-drop canvas, field-binding
 * inspector, and EntityFormOverride activation flow that mirrors Component
 * Studio's contextual Form Builder tab but as its own dedicated workspace.
 *
 * Owns its OWN state — does NOT depend on `ComponentStudioStateService`,
 * which is provided per-Component-Studio-dashboard. The canvas and right
 * panel children are state-agnostic and accept everything via @Input/@Output.
 *
 * Per `dashboards/CLAUDE.md`, this resource MUST call `NotifyLoadComplete()`
 * after the initial load — without it, the shell loading screen hangs forever
 * on direct URL navigation (e.g. `/app/form-studio/Form%20Builder`).
 */
export declare class FormBuilderResourceComponent extends BaseResourceComponent implements AfterViewInit, OnDestroy {
    GetResourceDisplayName(_data: ResourceData): Promise<string>;
    GetResourceIconClass(_data: ResourceData): Promise<string>;
    LeftRailCollapsed: boolean;
    RightRailCollapsed: boolean;
    ChatPaneCollapsed: boolean;
    IsLoading: boolean;
    ExistingForms: FormComponentSummary[];
    LeftRailFilter: string;
    /** Percent (0-100) height of the forms-list section within the left
     *  rail. The versions panel takes the remainder. */
    FormsListHeightPct: number;
    FormsListCollapsed: boolean;
    VersionsCollapsed: boolean;
    FormsViewMode: 'list' | 'tree';
    /** Selected entity filter. Empty string = "All entities". */
    FormsEntityFilter: string;
    /** Status chips currently enabled. Active+Pending+Inactive by default
     *  so the list shows everything. Toggle a chip OFF to hide that bucket. */
    FormsStatusFilter: Set<'Active' | 'Pending' | 'Inactive'>;
    FormsSortMode: 'updated-desc' | 'updated-asc' | 'name-asc' | 'name-desc';
    /** Pinned form Component IDs (kept sticky at the top of the list). */
    PinnedFormIds: Set<string>;
    /** Right-click context-menu state. */
    ContextMenuForm: FormComponentSummary | null;
    ContextMenuX: number;
    ContextMenuY: number;
    ContextMenuOpen: boolean;
    /** Entity-filter dropdown open state. */
    EntityFilterDropdownOpen: boolean;
    EntityFilterSearch: string;
    /** When the user starts a diff via right-click on a version row,
     *  this holds the first selection. Click another row to compare. */
    DiffSourceVersionID: string | null;
    /** When set, render the diff modal showing both specs side-by-side. */
    DiffTargetVersionID: string | null;
    DiffSourceCode: string;
    DiffTargetCode: string;
    ShowDiffDialog: boolean;
    /**
     * Center-pane view mode for the cockpit. Default is 'preview' because the
     * preview is the most useful single view when a form is loaded; users
     * tab to 'code' to edit and 'layout' for the (legacy) drag-drop canvas.
     */
    CenterPaneMode: 'preview' | 'code' | 'layout';
    /**
     * Version rail data. Lineage = all Component rows sharing the active
     * form's Name. Ordered by VersionSequence DESC so the newest is on top.
     */
    Versions: ComponentVersionRow[];
    /**
     * The version row matching the Component currently loaded in the
     * editor (`SelectedFormID`). Drives the floating "Viewing v1.0.0"
     * overlay on the center pane so the user always knows which
     * version's spec they're looking at — particularly useful when
     * they've clicked an older row in the version rail to inspect
     * historical work, and the on-screen form differs from what the
     * runtime is actually serving.
     */
    get CurrentSelectedVersion(): ComponentVersionRow | null;
    VersionsLoading: boolean;
    ActiveVersionID: string | null;
    /**
     * Live preview state. When the user switches to the Preview tab, we load
     * a Top-1 record from `TargetEntityName` and mount `<mj-interactive-form>`
     * with the working `componentSpec` derived from the current EditableCode.
     * Failure modes (no record, RunView error) fall back to a synthetic
     * NewRecord() so the form still mounts — the user just sees an empty
     * draft instead of a broken pane.
     */
    PreviewRecord: BaseEntity | null;
    PreviewRecordIsReal: boolean;
    PreviewRecordLabel: string;
    PreviewLoading: boolean;
    PreviewError: string | null;
    PreviewPickerOpen: boolean;
    /**
     * The saved ComponentSpec from the last loaded form, preserved so the
     * Preview pane can merge live code edits over the rich metadata
     * (dataRequirements / description / functionalRequirements / technicalDesign)
     * rather than rebuilding from `EditableCode` alone. Retrospective fix #5.
     */
    SavedSpec: ComponentSpec | null;
    /**
     * True when the in-memory code (EditableCode) has diverged from what the
     * canvas can represent — e.g. hand-authored sections, computed JSX the
     * canvas-parser can't round-trip. Set by `hydrateCanvasFromCode`. The
     * Layout tab shows a warning banner so the user knows the canvas will
     * overwrite parts of the code on save. Retrospective fix #6.
     */
    CanvasDiverged: boolean;
    PreviewSearchTerm: string;
    PreviewSearchResults: Array<{
        ID: string;
        Label: string;
    }>;
    /**
     * AppContext snapshot fed to the embedded `<mj-conversation-chat-area>`
     * so the agent sees the cockpit's current form + entity. Sourced from
     * `NavigationService.AppContextSnapshot$` — the same snapshot the floating
     * overlay uses — so both surfaces see identical context. Our cockpit-
     * specific state is pushed in via `SetAgentContext()` (which the Explorer
     * app shell merges into the snapshot's `AdditionalContext`).
     */
    ChatAppContext: AppContextSnapshot | null;
    /**
     * Resolved ID of the Form Builder agent. Looked up once at init via
     * RunView. Bound to `<mj-conversation-chat-area>`'s `[defaultAgentId]`
     * so messages route directly to the Form Builder agent instead of going
     * through Sage — Sage doesn't author forms, the Form Builder agent does.
     * Null until the lookup resolves (or if the agent isn't installed); in
     * that case the chat falls back to Sage routing.
     */
    FormBuilderAgentId: string | null;
    private appContextSubscription;
    private entityEventSubscription;
    /**
     * Subscription to `InteractiveFormsEngine` Forms$/Overrides$. Fires
     * whenever the engine's cache is mutated (local save, remote-invalidate,
     * delete) and drives a sync recompute of {@link ExistingForms} and
     * {@link Versions}. Replaces the old "call loadExistingForms after every
     * mutation" pattern — engine + observable handle invalidation.
     */
    private engineSubscription;
    /**
     * Conversation state for the embedded chat. Initially null/new; when the
     * user sends the first message, the chat-area emits `conversationCreated`
     * and we flip these so subsequent renders keep the same conversation.
     * Without this binding, the chat appears "stuck" on the welcome message
     * because the wrapper never picks up the new conversation ID.
     */
    ChatConversation: MJConversationEntity | null;
    ChatConversationId: string | null;
    /**
     * Lightweight list of all conversations across the active form's
     * lineage — feeds the chat header's "N conversations" dropdown so the
     * user can switch back to a prior thread instead of being locked into
     * just the most-recent one. Populated alongside loadLinkedConversation.
     */
    LineageConversations: Array<{
        ID: string;
        Name: string | null;
        UpdatedAt: Date | null;
    }>;
    ConversationHistoryDropdownOpen: boolean;
    ChatIsNewConversation: boolean;
    /**
     * Pending message + attachments that came back on `conversationCreated`.
     * The chat-area emits these as part of its atomic state-handoff so the
     * parent can re-feed them after the conversation has an ID. The
     * chat-area's `pendingMessageConsumed` event tells us when to clear.
     * Without this loop, the user's first message creates the conversation
     * but never actually posts.
     */
    ChatPendingMessage: string | null;
    ChatPendingAttachments: unknown[] | null;
    /**
     * Thread state for the embedded chat. Mirrors the workspace shell's
     * pattern: chat-area emits `threadOpened` with a thread ID when the
     * user drills into a sub-thread, and `threadClosed` when they leave.
     * Forwarded back as `[threadId]` so the chat-area knows which thread
     * to render. Without these handlers, clicking a thread message in
     * the cockpit's chat appears to do nothing (the chat-area emits but
     * no one binds back).
     */
    ChatThreadId: string | null;
    /**
     * Pending artifact pointer for the chat-area to scroll to / highlight
     * after navigation. Set when an artifact link inside the chat is
     * clicked (the chat-area asks us to surface a specific artifact
     * version) and cleared when consumed.
     */
    ChatPendingArtifactId: string | null;
    ChatPendingArtifactVersionNumber: number | null;
    /**
     * Environment ID for the embedded chat-area. Resource components in
     * Explorer accept this via ResourceData.Configuration; we fall back to
     * the default environment when not supplied.
     */
    get ChatEnvironmentId(): string;
    /**
     * Pane sizes (percent) for the 3-pane horizontal split. Initialized
     * from {@link FormBuilderPrefs} loaded out of UserInfoEngine on init;
     * mutated by the splitter's drag-end event; written back via
     * {@link savePrefs}.
     */
    LeftPanePct: number;
    CenterPanePct: number;
    ChatPanePct: number;
    /**
     * True when a form is "actively being shown" — either an existing
     * form is loaded (SelectedFormID set) or the user clicked New Form
     * (IsNewForm). The right-side chat pane is gated on this so empty
     * cockpits don't render an agent shell against no subject.
     */
    get HasActiveForm(): boolean;
    SelectedFormID: string | null;
    SelectedFormName: string;
    IsNewForm: boolean;
    TargetEntityName: string | null;
    Schema: CuratedFormSchema | null;
    Canvas: FormCanvasModel | null;
    SelectedElementId: string | null;
    SelectedSectionId: string | null;
    EditableCode: string;
    DirtyFlag: boolean;
    IsEntityPickerOpen: boolean;
    EntityPickerSearch: string;
    EntityChoices: ReadonlyArray<{
        Name: string;
        DisplayName: string;
    }>;
    /**
     * State for the cockpit's reusable confirm dialog. Replaces the
     * browser-native `window.confirm()` calls (delete form, discard
     * unsaved edits) with a styled in-app dialog. Three reasons for the
     * switch: (a) consistent visual language with the override + diff
     * dialogs, (b) confirm/cancel button order matches MJ convention
     * (primary left), (c) browser confirm is blocked by some browsers /
     * tools when triggered from event handlers without recent user
     * gesture (e.g. agent-driven flows).
     *
     * Hold the resolver callback alongside the state so multiple confirm
     * call-sites can share the same dialog without each one re-binding.
     */
    ConfirmDialog: {
        Open: boolean;
        Title: string;
        Body: string;
        ConfirmLabel: string;
        CancelLabel: string;
        Danger: boolean;
        OnConfirm: () => void | Promise<void>;
        OnCancel?: () => void;
    } | null;
    ShowFormOverrideDialog: boolean;
    PendingOverrideComponentID: string | null;
    PendingOverrideComponentName: string;
    PendingOverrideEntityName: string;
    /** Pre-fill values forwarded to the override dialog. Populated by
     *  OnSave (for post-save flow) or OpenEditFormDetailsDialog (for the
     *  edit-existing-override flow). */
    PendingOverrideInitialName: string | null;
    PendingOverrideInitialDescription: string | null;
    PendingOverrideInitialNotes: string | null;
    PendingOverrideInitialStatus: 'Active' | 'Inactive' | 'Pending' | null;
    PendingOverrideInitialScope: 'User' | 'Role' | 'Global' | null;
    PendingOverrideInitialRoleID: string | null | undefined;
    PendingOverrideInitialPriority: number | undefined;
    /** Edit-mode flag — when true, the dialog updates the existing
     *  override (`EditingOverrideID`) instead of creating a new one. */
    FormOverrideDialogEditMode: boolean;
    EditingOverrideID: string | null;
    private readonly cdr;
    private readonly notifications;
    private readonly overrideService;
    private readonly conversationBridge;
    /**
     * Name of the Application this cockpit lives in — must match the
     * `Application.Name` column. "Form Studio" is the nav-item LABEL
     * inside the "Component Studio" app, not a separate application;
     * the canonical Application row is named "Component Studio". See
     * `/metadata/applications/.component-studio-application.json`.
     */
    private static readonly COCKPIT_APP_NAME;
    /**
     * ID of the Application that owns this cockpit. Resolved at init from
     * `Metadata.Applications` (the in-memory cache populated at provider
     * bootstrap — NO RunView round-trip) and forwarded to the embedded
     * chat-area as `[applicationId]`, so conversations created inside this
     * cockpit are scoped to the Form Studio app and don't pollute the
     * main Chat list.
     */
    CockpitApplicationId: string | null;
    /**
     * EntityID for `MJ: Components`, resolved from `Metadata.Entities` at
     * init. Bound to `<mj-conversation-chat-area>`'s `[linkedEntityId]`
     * so conversations created in the cockpit are stamped as "about a
     * Component" — enabling the future "show prior conversations about
     * THIS form" surface. In-memory lookup, no RunView.
     */
    ComponentsEntityID: string | null;
    private get provider();
    get currentUser(): UserInfo | null;
    ngAfterViewInit(): Promise<void>;
    ngOnDestroy(): void;
    /**
     * MJGlobal event handler — fires whenever any BaseEntity in the app
     * is saved/deleted/etc. We filter aggressively here: only react to
     * `save` (local + remote-invalidate from the agent's server-side
     * action) on `MJ: Components` or `MJ: Entity Form Overrides`, and
     * only when the affected row belongs to the lineage of the form
     * currently loaded in this cockpit. Anything else bails immediately
     * — this listener runs for every entity save in the entire app, so
     * cheapness matters.
     */
    private handleEntityEvent;
    /**
     * Normalize the `{ID, Name}` we need to match a BaseEntity event against
     * the active form, regardless of whether the event came from a local
     * `Save()` (with a live `baseEntity` attached) or a server-broadcast
     * `remote-invalidate` (where `baseEntity` is null and the row lives in
     * `evt.payload.primaryKeyValues` + `evt.payload.recordData`, both
     * JSON-stringified by `MJServer/src/index.ts:626-641`).
     */
    private resolveEntityEventIdentity;
    /**
     * Agent (or another client) just modified the Component / Override
     * for the form currently loaded in this cockpit. Reload the spec
     * from the same Component so the canvas + code + preview reflect
     * the new state without forcing a manual refresh.
     *
     * Guards: don't clobber unsaved user edits — if the cockpit has its
     * own `DirtyFlag` set, surface a notification instead of silently
     * overwriting. The user can manually re-pick the form when ready.
     */
    private handleAgentEditedActiveForm;
    /**
     * One-shot lookup of the Form Builder agent's ID. Used to bind the
     * chat-area's `[defaultAgentId]` so the cockpit's chat skips Sage routing
     * and addresses messages directly to the form-authoring specialist.
     *
     * Uses `AIEngineBase.Instance.Agents` (the in-memory cache that's
     * already loaded on app boot) rather than a RunView round-trip. This
     * also avoids the easy-to-trip entity-name typo (`'AI Agents'` vs
     * `'MJ: AI Agents'`) that previously left FormBuilderAgentId null and
     * silently fell back to Sage routing.
     */
    private resolveFormBuilderAgentId;
    /**
     * Recompute the left-rail forms list from `InteractiveFormsEngine`'s
     * in-memory caches. **Synchronous** in spirit — the `async` signature is
     * kept for backwards-compat with existing call sites and to surface
     * future lazy-load needs cleanly. Reads only from the engine, never the
     * DB. Driven by the engine subscription in {@link ngAfterViewInit}, so
     * any save/delete/remote-invalidate refreshes this list automatically.
     *
     * Representative selection per Name lineage (Active > Pending >
     * Inactive > none, then VersionSequence DESC) and the projection to
     * {@link FormComponentSummary} match the previous RunView-based
     * implementation exactly.
     */
    private loadExistingForms;
    /**
     * Forms list filtered + sorted per the user's left-rail prefs.
     * Pipeline: search text → entity filter → status chips → sort →
     * pinned-first. The result drives both the flat-list view and is
     * grouped by schema/entity for the tree view.
     */
    get filteredForms(): ReadonlyArray<FormComponentSummary>;
    /**
     * Tree-view groups: forms grouped by SchemaName → EntityName. Falls
     * back to a synthetic "(no entity)" group for forms without a
     * user-scope override bound to an entity.
     */
    get treeGroups(): ReadonlyArray<{
        schema: string;
        entities: ReadonlyArray<{
            entity: string;
            entityDisplay: string;
            icon: string | null;
            forms: ReadonlyArray<FormComponentSummary>;
        }>;
    }>;
    /**
     * Distinct entity names that appear in the current forms list — used
     * to populate the entity-filter dropdown. Empty string ("") = "All
     * entities", added at the top. Search-text-filtered when the user
     * is typing into the dropdown's own search box.
     */
    get entityFilterOptions(): ReadonlyArray<{
        name: string;
        display: string;
        icon: string | null;
        count: number;
    }>;
    OnLeftRailFilterChange(event: Event): void;
    ToggleFormsViewMode(): void;
    ToggleEntityFilterDropdown(): void;
    OnEntityFilterSearch(e: Event): void;
    PickEntityFilter(entityName: string): void;
    ToggleStatusFilter(status: 'Active' | 'Pending' | 'Inactive'): void;
    SetFormsSortMode(mode: 'updated-desc' | 'updated-asc' | 'name-asc' | 'name-desc'): void;
    TogglePinForm(form: FormComponentSummary, event?: Event): void;
    IsFormPinned(form: FormComponentSummary): boolean;
    ToggleFormsListCollapsed(): void;
    ToggleVersionsCollapsed(): void;
    /**
     * Drag-end handler for the inner vertical splitter between the forms
     * list and the versions panel inside the left rail. Persists the
     * percent split so the user's preferred layout sticks across reloads.
     */
    OnInnerSplitterDragEnd(event: {
        sizes: ReadonlyArray<number | '*'>;
    }): void;
    /** Right-click context menu on a form row. Opens at click coords. */
    OnFormRowContextMenu(form: FormComponentSummary, event: MouseEvent): void;
    CloseContextMenu(): void;
    ContextMenuDuplicate(): Promise<void>;
    ContextMenuDelete(): Promise<void>;
    ContextMenuCopyID(): void;
    ContextMenuExportSpec(): void;
    ContextMenuTogglePin(): void;
    ToggleLeftRail(): void;
    ToggleRightRail(): void;
    ToggleChatPane(): void;
    SetCenterPaneMode(mode: 'preview' | 'code' | 'layout'): void;
    /**
     * Live `ComponentSpec` for the Preview pane. Derived from the in-memory
     * `EditableCode` so the preview reflects unsaved edits — switching to
     * Preview while typing in Code shows the in-progress version, not the
     * last-saved one. Falls back to null when there's no code yet, in which
     * case the Preview pane shows a friendly empty state.
     */
    get PreviewSpec(): import('@memberjunction/interactive-component-types').ComponentSpec | null;
    /**
     * Load a Top-1 record from the target entity to bind into the preview.
     * If the entity has no rows, we still mount the form against a synthetic
     * NewRecord() so the layout / styling / event handlers can be evaluated.
     */
    loadPreviewRecord(): Promise<void>;
    /** Pull a human label from the record's NameField or primary key. */
    private recordLabel;
    /**
     * Handle a LoadErrorChanged emit from <mj-interactive-form> in the
     * Preview pane. Surfaces the error in the cockpit's own error state so
     * users see "Preview failed" in the cockpit chrome instead of having
     * to look inside the form's React shell. Retrospective fix #10.
     */
    OnPreviewLoadError(message: string | null): void;
    /**
     * Open the preview record (the entity row currently bound to
     * `<mj-interactive-form>`) in a fresh Explorer tab. Useful sanity-check
     * — render the form against this same record in the production
     * resolver path to confirm the cockpit's preview matches reality.
     */
    OpenPreviewRecord(): void;
    TogglePreviewPicker(): void;
    /** Search-as-you-type for the preview record picker. */
    OnPreviewSearchInput(event: Event): Promise<void>;
    /**
     * Shared loader for the preview record picker. Empty term → top N
     * by name. Non-empty term → `LIKE %term%` on the name field. Both
     * paths share the result-mapping logic so the dropdown looks the same.
     */
    private loadPreviewPickerResults;
    /** User picked a different record from the search results — re-bind preview. */
    OnPreviewRecordPicked(item: {
        ID: string;
        Label: string;
    }): Promise<void>;
    /**
     * Direct-edit handler used by `<mj-code-editor>` via ngModelChange.
     * Receives the new editor value as a string. Marks the form dirty so
     * the Save button activates; the Layout-tab canvas is *not* re-derived
     * here (avoids destructive round-trips when the JSX has hand-authored
     * bits the canvas-parser can't model).
     */
    /**
     * Chat-area emitted `conversationCreated` after the user sent the first
     * message — switch the embedded chat out of "new conversation" mode so
     * subsequent renders show the live conversation thread. Without this,
     * the chat appears stuck on its welcome screen.
     */
    OnChatConversationCreated(event: {
        conversation: MJConversationEntity;
        pendingMessage?: string;
        pendingAttachments?: unknown[];
    }): void;
    /**
     * Chat-area finished delivering the pending message — clear the buffer
     * so a re-render doesn't try to send it again.
     */
    OnChatPendingMessageConsumed(): void;
    /**
     * Chat-area emitted `openEntityRecord` — user clicked an entity link
     * inside an agent reply. Open the record as a new Explorer tab via
     * NavigationService (same as the workspace's actionable-command
     * path, but executed directly here since the cockpit has no
     * intermediate workspace shell).
     */
    OnChatOpenEntityRecord(event: {
        entityName: string;
        compositeKey: CompositeKey;
    }): void;
    /**
     * Chat-area emitted a generic `navigationRequest` (cross-resource
     * navigation, e.g. "go to Collections with this artifact"). Route
     * via NavigationService.OpenNavItemByName.
     */
    OnChatNavigationRequest(event: NavigationRequest): void;
    /**
     * Chat-area emitted `taskClicked` — user clicked a task pill in an
     * agent reply. The workspace switches to its Tasks tab; the cockpit
     * has no Tasks tab, so open the task record directly.
     */
    OnChatTaskClicked(task: MJTaskEntity): void;
    /**
     * Chat-area emitted `artifactLinkClicked` — user clicked an artifact
     * link inside a message. Conversation-type links point at another
     * conversation in main Chat; collection-type links point at a
     * collection. Both route into the main Chat / Collections app via
     * NavigationService so the artifact opens in its native context
     * (the cockpit is form-authoring focused, not the right surface to
     * render arbitrary artifacts inline).
     */
    OnChatArtifactLinkClicked(event: {
        type: 'conversation' | 'collection';
        id: string;
    }): void;
    /** Chat-area emitted `conversationRenamed` — purely informational for the cockpit (no convo list to animate). */
    OnChatConversationRenamed(event: {
        conversationId: string;
        name: string;
        description: string;
    }): void;
    /** Thread drill-down: chat-area opened a sub-thread. Track ID so the chat-area renders it. */
    OnChatThreadOpened(threadId: string): void;
    /** Thread drill-down: chat-area closed the sub-thread. Clear ID. */
    OnChatThreadClosed(): void;
    /** Pending artifact handed off to the chat-area (e.g. via deep link) has been consumed. */
    OnChatPendingArtifactConsumed(): void;
    /**
     * Load cockpit prefs from UserInfoEngine. Called once during
     * ngAfterViewInit. Missing / unparseable values fall through to the
     * defaults declared at field-init time — never throws.
     */
    private loadPrefs;
    /**
     * Write the current cockpit UI state back to UserInfoEngine, debounced
     * (the engine handles debouncing internally). Called from the splitter's
     * drag-end event, the collapse toggles, and the center-pane mode setter.
     */
    private savePrefs;
    /**
     * Splitter drag-end handler. `sizes` from angular-split is an array of
     * `SplitAreaSize` values (number | '*' for auto-size); for our
     * percent-unit splitter only numbers come through, but the union forces
     * us to filter. Order matches the visible-pane order: [left?, center, chat?].
     */
    OnSplitterDragEnd(event: {
        sizes: ReadonlyArray<number | '*'>;
    }): void;
    OnEditableCodeChange(next: string | null | undefined): void;
    /**
     * Load all Component versions sharing the active form's Name. The version
     * rail renders these; `Active` / `Pending` flags come from cross-referencing
     * EntityFormOverrides for the user. Tolerates missing user / empty results
     * — version rail just shows nothing in that case.
     */
    /**
     * Look up the most-recent conversation linked to the active form
     * (LinkedEntityID=MJ:Components, LinkedRecordID anywhere in the form's
     * Component lineage for this entity) for the current user and bind it
     * to the embedded chat.
     *
     * **Lineage-aware**: a Form Builder conversation belongs to "this form"
     * (the Component.Name lineage), not to a single Component version. When
     * the agent does a `patch`/`minor`/`major` bump via Modify Interactive
     * Form, prior conversations were stamped with the old ComponentID — a
     * naive `LinkedRecordID = SelectedFormID` lookup would orphan them. We
     * expand the lookup to all Components in the same lineage by joining
     * `vwComponents.Name = SelectedFormName` with
     * `vwEntityFormOverrides.EntityID = TargetEntityID` inside an `IN`
     * subquery so it stays one round-trip.
     *
     * Note: this is ONLY about which prior conversation to show in the
     * cockpit chat. New conversations are still stamped with the current
     * SelectedFormID; the lineage join on read picks them up across
     * version bumps. Runtime form resolution is completely unaffected.
     *
     * If none exists, reset to a fresh pre-conversation state — the
     * suppressed empty-state path in <mj-conversation-chat-area> renders
     * the normal header + mode picker + input so the user can start a
     * new linked conversation in place. Errors are tolerated (chat just
     * stays on the previous state).
     */
    private loadLinkedConversationForActiveForm;
    ToggleConversationHistoryDropdown(): void;
    /**
     * Switch the embedded chat to a different conversation in the same
     * lineage. Used by the header's "N conversations" dropdown.
     */
    PickLineageConversation(c: {
        ID: string;
        Name: string | null;
    }): Promise<void>;
    /**
     * Build the ExtraFilter for the lineage-aware conversation lookup.
     * Falls back to single-version filtering when the lineage signals
     * (SelectedFormName, TargetEntityName→ID, or the schema/view metadata
     * for Components/Overrides) aren't available — degrades to the
     * original behavior rather than breaking the chat.
     */
    private buildLinkedConvoFilter;
    /**
     * One-shot retry wrapper around the conversation lookup. The shared
     * GraphQLDataProvider occasionally throws "Entity null not found in
     * metadata" when the React form-preview's own RunView wave is in
     * flight concurrently — the failure is transient. Retrying once after
     * a short delay clears it.
     */
    private runLinkedConvoQuery;
    /** Reset embedded chat to the pre-conversation state for a new form. */
    private resetChatToFresh;
    /**
     * Recompute the version-rail rows from `InteractiveFormsEngine`'s
     * caches — all Component rows in the active form's Name lineage, joined
     * against the current user's override rows to tag Active / Pending.
     * No DB round-trip. Auto-refreshed by the engine subscription in
     * {@link ngAfterViewInit} on any save/delete/remote-invalidate.
     *
     * Kept `async` for callers that already `await` it; the body is sync.
     */
    loadVersionsForActiveForm(): Promise<void>;
    /**
     * Open the chat overlay with the active-form context already set. The
     * overlay is mounted at the app root; we don't construct it here. The
     * agent context is kept fresh by `registerAgentContext()` (called on
     * every form change).
     *
     * Side effect: also un-collapses the chat pane so the user sees the
     * surface they just clicked.
     */
    OnOpenInChat(): void;
    /**
     * Re-point this form's Active override at the picked version. Called
     * from the version rail "Make Active" button. Delegates to the
     * `Activate Interactive Form Version` action when the version is Pending,
     * otherwise delegates to `Revert Interactive Form` (re-point Active
     * override to an older Component row in the same Name lineage).
     */
    OnActivateVersion(version: ComponentVersionRow): Promise<void>;
    /**
     * Version-rail row click. Loads that version's Component into the
     * cockpit's editor (Preview / Code / Layout) — does NOT change which
     * version the runtime resolver picks for users (that's still driven
     * by the Active override). To promote an older version to Active,
     * the user clicks the row's "Activate" / "Restore" button.
     *
     * No-op when the row is already loaded. Builds a synthetic summary
     * and delegates to {@link OnFormPicked} so the load path is exactly
     * the same as picking from the left rail (handles dirty-discard
     * confirmation, schema rebuild, version rail refresh, agent context
     * push, etc.).
     */
    OnVersionRowClick(v: ComponentVersionRow): Promise<void>;
    /**
     * Begin a diff selection from the version rail. The clicked version
     * becomes the "source"; the next clicked version becomes the "target"
     * and we render a side-by-side diff modal.
     *
     * Click the same version twice → cancels the selection.
     */
    OnVersionDiffClick(v: ComponentVersionRow, event: Event): Promise<void>;
    CloseDiffDialog(): void;
    /** Helper: lookup the version row for a given ID, used in the diff title. */
    versionByID(id: string | null): ComponentVersionRow | null;
    OnFormPicked(form: FormComponentSummary): Promise<void>;
    /**
     * Look up an EntityFormOverride that points at this Component and return
     * the bound entity's name. Used by `OnFormPicked` to recover the target
     * entity for forms that have been activated against a real entity.
     */
    /**
     * Override metadata for the active form — captured at form-load time so
     * the agent context can carry it inline (no `Get Active Form For Entity`
     * round-trip needed). The Form Builder agent prompt's lifecycle rules
     * branch on whether an active override exists and what its scope/status
     * is; passing this snapshot upfront lets the agent jump straight to
     * `Modify Interactive Form` instead of guessing.
     */
    ActiveOverrideID: string | null;
    ActiveOverrideScope: string | null;
    ActiveOverrideStatus: string | null;
    /** Whether the cockpit's override-status popover is open. */
    OverrideStatusPickerOpen: boolean;
    /** Inline saving flag — disables the picker buttons mid-save. */
    OverrideStatusSaving: boolean;
    /**
     * Allowed values for `EntityFormOverride.Status` mirrored from the
     * DB CHECK constraint / EntityFieldValue rows. Hardcoded for two
     * reasons: (a) they're stable schema enums, and (b) the picker UI
     * needs them statically to render labels + icons without round-trip.
     */
    readonly OverrideStatusOptions: ReadonlyArray<{
        value: 'Active' | 'Inactive' | 'Pending';
        label: string;
        description: string;
        icon: string;
    }>;
    /** Toggle the override status popover. No-op when no override is loaded. */
    ToggleOverrideStatusPicker(): void;
    /**
     * Persist a new status on the currently-loaded EntityFormOverride.
     * Loads the entity, sets the status, saves, then mirrors the new
     * value onto the cockpit's local snapshot fields so the agent
     * context + UI stay in sync. The BaseEntity event subscription
     * above will also fire as a side effect, but our local guard
     * (`ActiveOverrideStatus` already up to date) keeps the cockpit
     * from triggering a spurious refresh.
     */
    OnOverrideStatusPicked(next: 'Active' | 'Inactive' | 'Pending'): Promise<void>;
    private lookupEntityForComponent;
    OnNewForm(): void;
    private confirmDiscard;
    /**
     * Best-effort parse of the `Specification` JSON column on MJ: Components.
     * Returns `null` if the column is empty or malformed — callers should
     * fall back to empty-code initialization in that case.
     */
    private parseSpec;
    /**
     * Best-effort attempt to extract the target entity from a form
     * Component's stored code. Form components conventionally reference
     * `host.entityName` or `entityName="…"`. If we can't infer it, the user
     * needs to re-pick from the entity dropdown.
     */
    private inferTargetEntityFromCode;
    OnFormNameInput(event: Event): void;
    ToggleEntityPicker(): void;
    OnEntityPickerSearch(event: Event): void;
    get filteredEntityChoices(): ReadonlyArray<{
        Name: string;
        DisplayName: string;
    }>;
    OnEntityPicked(entityName: string): void;
    private refreshEntityChoices;
    OnCanvasChanged(next: FormCanvasModel): void;
    OnElementSelected(payload: {
        sectionId: string;
        elementId: string;
    }): void;
    OnSectionSelected(sectionId: string): void;
    OnDeselected(): void;
    OnElementChanged(next: FormCanvasElement): void;
    OnSectionChanged(next: FormCanvasSection): void;
    OnElementDeleted(elementId: string): void;
    OnSectionDeleted(sectionId: string): void;
    OnFieldAddedFromPalette(payload: {
        fieldName: string;
    }): void;
    private focusedSection;
    private regenerateCode;
    private hydrateCanvasFromCode;
    OnSave(): Promise<void>;
    /**
     * Delete the currently-loaded form's Component AND any EntityFormOverride
     * rows pointing at it. Without the cascade, deleting just the Component
     * would leave orphan overrides whose resolver lookups fail silently.
     */
    OnDelete(): Promise<void>;
    OnFormOverrideDialogConfirm(result: FormOverrideDialogResult): Promise<void>;
    OnFormOverrideDialogDismiss(): void;
    private resetOverrideDialogState;
    /**
     * Open the form-override dialog in EDIT MODE — pre-fills all fields
     * from the active override row so the user can rename, retag, or
     * adjust scope/priority/status without retyping. On confirm, the
     * existing override is updated in place rather than a new one being
     * created.
     *
     * Available from the cockpit's toolbar via the "Edit details" pencil
     * icon next to the form name.
     */
    OpenEditFormDetailsDialog(): Promise<void>;
    /**
     * Update an existing EntityFormOverride row's editable fields from the
     * dialog result. Returns true on success, false on save failure.
     */
    private updateOverrideFromDialog;
    /**
     * Refresh `ActiveOverride*` fields after an edit so the cockpit chrome
     * picks up the new Status/Scope. Used by the edit-details dialog flow.
     */
    private refreshActiveOverrideMetadata;
    /**
     * Compact list of the active entity's relationships, used to seed
     * the agent's context so it knows which related entities are
     * available to link to this form (sub-tables, lookups, etc.).
     *
     * Intentionally **summary-only** — name, relationship type, and
     * join fields. Full schemas for any related entity are still a
     * single `Get Entity Schema For Form` tool call away. Keeping this
     * list compact (~20-50 entries × ~80 chars = a few KB) avoids
     * token bloat while still giving the agent enough to plan without
     * asking the user "what entity links to this?".
     */
    /**
     * Compact catalog of **Active** Component Libraries the agent can
     * declare in `ComponentSpec.libraries`. Read from
     * `ComponentMetadataEngine` (cached at cockpit init). Same shape Skip
     * uses to inform Codesmith Agent — Form Builder forms run in the
     * exact same React runtime, so any Active library is fair game.
     *
     * Per-library payload is kept lean: Name (npm package), Category
     * (UI / Charting / Utility / Other), GlobalVariable (the runtime
     * binding the agent uses inside JSX), Description (one-liner), and
     * Version. UsageInstructions are included only when present AND
     * short (<500 chars) — longer docs would balloon the prompt.
     *
     * Result sorted by Category then Name so the agent sees related
     * libraries grouped together (all Charting options adjacent, all UI,
     * etc.).
     */
    /**
     * Pre-render the AvailableLibraries catalog as markdown for the agent
     * prompt. Token-efficient vs the previous JSON-array shape: nested
     * heading structure that LLMs parse natively, ~40-50% fewer tokens on
     * a typical 25-30 library catalog, and easier to skim in agent-run
     * logs. Grouped by Category (UI, Charting, etc.) with library entries
     * as `### Name (Category)` and per-library bullets for description,
     * version, GlobalVariable, and short usage instructions.
     */
    private buildAvailableLibrariesMarkdown;
    /**
     * Pre-render the active form's curated schema as markdown for the
     * agent prompt. Replaces the JSON Schema payload — same information,
     * roughly half the tokens, and easier to read in logs.
     *
     * Field names are wrapped in inline code (`` `name` ``) so underscores
     * (e.g. `__mj_Internal`) don't get parsed as emphasis. Other text is
     * left raw — LLMs tolerate minor markdown imperfections in description
     * prose fine.
     */
    private buildSchemaMarkdown;
    /**
     * Pre-render the active entity's related-entities summary as markdown.
     * Compact one-line-per-related entry — agent sees what tables it could
     * pull in (lookups, sub-grids, related-record cards) without paying the
     * token cost of full schemas (those are still one `Get Entity Schema
     * For Form` action call away).
     */
    private buildRelatedEntitiesMarkdown;
    private registerAgentContext;
    private markDirty;
    static ɵfac: i0.ɵɵFactoryDeclaration<FormBuilderResourceComponent, never>;
    static ɵcmp: i0.ɵɵComponentDeclaration<FormBuilderResourceComponent, "mj-form-builder-resource", never, {}, {}, never, never, false, never>;
}
/** Tree-shake protection — referenced from the dashboards module loader. */
export declare function LoadFormBuilderResourceComponent(): void;
export {};
//# sourceMappingURL=form-builder-resource.component.d.ts.map