@memberjunction/ng-dashboards 5.36.0 → 5.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +32 -0
  2. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +14 -0
  3. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
  4. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +450 -292
  5. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
  6. package/dist/ComponentStudio/component-studio-dashboard.component.d.ts +73 -1
  7. package/dist/ComponentStudio/component-studio-dashboard.component.d.ts.map +1 -1
  8. package/dist/ComponentStudio/component-studio-dashboard.component.js +512 -127
  9. package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
  10. package/dist/ComponentStudio/component-studio-resource.component.d.ts +22 -0
  11. package/dist/ComponentStudio/component-studio-resource.component.d.ts.map +1 -0
  12. package/dist/ComponentStudio/component-studio-resource.component.js +55 -0
  13. package/dist/ComponentStudio/component-studio-resource.component.js.map +1 -0
  14. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts +104 -45
  15. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts.map +1 -1
  16. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js +234 -331
  17. package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js.map +1 -1
  18. package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.d.ts +54 -0
  19. package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.d.ts.map +1 -0
  20. package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.js +339 -0
  21. package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.js.map +1 -0
  22. package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.d.ts +65 -0
  23. package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.d.ts.map +1 -0
  24. package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.js +492 -0
  25. package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.js.map +1 -0
  26. package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.d.ts +88 -0
  27. package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.d.ts.map +1 -0
  28. package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.js +457 -0
  29. package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.js.map +1 -0
  30. package/dist/ComponentStudio/components/form-override-dialog.component.d.ts +106 -0
  31. package/dist/ComponentStudio/components/form-override-dialog.component.d.ts.map +1 -0
  32. package/dist/ComponentStudio/components/form-override-dialog.component.js +478 -0
  33. package/dist/ComponentStudio/components/form-override-dialog.component.js.map +1 -0
  34. package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts +54 -0
  35. package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts.map +1 -1
  36. package/dist/ComponentStudio/components/workspace/component-preview.component.js +361 -50
  37. package/dist/ComponentStudio/components/workspace/component-preview.component.js.map +1 -1
  38. package/dist/ComponentStudio/components/workspace/editor-tabs.component.d.ts +10 -0
  39. package/dist/ComponentStudio/components/workspace/editor-tabs.component.d.ts.map +1 -1
  40. package/dist/ComponentStudio/components/workspace/editor-tabs.component.js +114 -45
  41. package/dist/ComponentStudio/components/workspace/editor-tabs.component.js.map +1 -1
  42. package/dist/ComponentStudio/services/canvas-to-code.d.ts +32 -0
  43. package/dist/ComponentStudio/services/canvas-to-code.d.ts.map +1 -0
  44. package/dist/ComponentStudio/services/canvas-to-code.js +347 -0
  45. package/dist/ComponentStudio/services/canvas-to-code.js.map +1 -0
  46. package/dist/ComponentStudio/services/code-to-canvas.d.ts +32 -0
  47. package/dist/ComponentStudio/services/code-to-canvas.d.ts.map +1 -0
  48. package/dist/ComponentStudio/services/code-to-canvas.js +92 -0
  49. package/dist/ComponentStudio/services/code-to-canvas.js.map +1 -0
  50. package/dist/ComponentStudio/services/component-studio-state.service.d.ts +29 -0
  51. package/dist/ComponentStudio/services/component-studio-state.service.d.ts.map +1 -1
  52. package/dist/ComponentStudio/services/component-studio-state.service.js +76 -0
  53. package/dist/ComponentStudio/services/component-studio-state.service.js.map +1 -1
  54. package/dist/ComponentStudio/services/entity-form-override.service.d.ts +86 -0
  55. package/dist/ComponentStudio/services/entity-form-override.service.d.ts.map +1 -0
  56. package/dist/ComponentStudio/services/entity-form-override.service.js +246 -0
  57. package/dist/ComponentStudio/services/entity-form-override.service.js.map +1 -0
  58. package/dist/ComponentStudio/services/field-binding-scanner.d.ts +29 -0
  59. package/dist/ComponentStudio/services/field-binding-scanner.d.ts.map +1 -0
  60. package/dist/ComponentStudio/services/field-binding-scanner.js +110 -0
  61. package/dist/ComponentStudio/services/field-binding-scanner.js.map +1 -0
  62. package/dist/ComponentStudio/services/form-canvas-model.d.ts +56 -0
  63. package/dist/ComponentStudio/services/form-canvas-model.d.ts.map +1 -0
  64. package/dist/ComponentStudio/services/form-canvas-model.js +35 -0
  65. package/dist/ComponentStudio/services/form-canvas-model.js.map +1 -0
  66. package/dist/ComponentStudio/services/form-host-props-fixture.d.ts +10 -0
  67. package/dist/ComponentStudio/services/form-host-props-fixture.d.ts.map +1 -0
  68. package/dist/ComponentStudio/services/form-host-props-fixture.js +10 -0
  69. package/dist/ComponentStudio/services/form-host-props-fixture.js.map +1 -0
  70. package/dist/DataExplorer/data-explorer-dashboard.component.js +2 -2
  71. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  72. package/dist/FormBuilder/form-builder-resource.component.d.ts +964 -0
  73. package/dist/FormBuilder/form-builder-resource.component.d.ts.map +1 -0
  74. package/dist/FormBuilder/form-builder-resource.component.js +4487 -0
  75. package/dist/FormBuilder/form-builder-resource.component.js.map +1 -0
  76. package/dist/FormBuilder/form-builder-version-rail.helpers.d.ts +55 -0
  77. package/dist/FormBuilder/form-builder-version-rail.helpers.d.ts.map +1 -0
  78. package/dist/FormBuilder/form-builder-version-rail.helpers.js +73 -0
  79. package/dist/FormBuilder/form-builder-version-rail.helpers.js.map +1 -0
  80. package/dist/Home/home-application.d.ts +21 -1
  81. package/dist/Home/home-application.d.ts.map +1 -1
  82. package/dist/Home/home-application.js +60 -8
  83. package/dist/Home/home-application.js.map +1 -1
  84. package/dist/QueryBrowser/query-browser-resource.component.d.ts +14 -14
  85. package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
  86. package/dist/QueryBrowser/query-browser-resource.component.js +11 -10
  87. package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
  88. package/dist/component-studio-dashboards.module.d.ts +34 -22
  89. package/dist/component-studio-dashboards.module.d.ts.map +1 -1
  90. package/dist/component-studio-dashboards.module.js +65 -9
  91. package/dist/component-studio-dashboards.module.js.map +1 -1
  92. package/package.json +54 -53
@@ -0,0 +1,964 @@
1
+ import { AfterViewInit, OnDestroy } from '@angular/core';
2
+ import { BaseEntity, CompositeKey } from '@memberjunction/core';
3
+ import type { UserInfo } from '@memberjunction/core';
4
+ import { ResourceData } from '@memberjunction/core-entities';
5
+ import type { MJConversationEntity } from '@memberjunction/core-entities';
6
+ import { BaseResourceComponent } from '@memberjunction/ng-shared';
7
+ import type { ComponentSpec } from '@memberjunction/interactive-component-types';
8
+ import type { MJTaskEntity } from '@memberjunction/core-entities';
9
+ import type { NavigationRequest } from '@memberjunction/ng-conversations';
10
+ import type { AppContextSnapshot } from '@memberjunction/ai-core-plus';
11
+ import { type CuratedFormSchema } from '@memberjunction/interactive-component-types/forms';
12
+ import { type FormCanvasElement, type FormCanvasModel, type FormCanvasSection } from '../ComponentStudio/services/form-canvas-model';
13
+ import type { FormOverrideDialogResult } from '../ComponentStudio/components/form-override-dialog.component';
14
+ import * as i0 from "@angular/core";
15
+ /**
16
+ * Persisted shape for the cockpit's resizable-pane sizes + collapse state.
17
+ * Versioned via the storage key (`v1`) so future schema changes can read +
18
+ * migrate older JSON without breaking on shape drift.
19
+ */
20
+ export interface FormBuilderPrefs {
21
+ /** Percent (0-100) widths of the three top-level shell panes. */
22
+ leftPanePct?: number;
23
+ centerPanePct?: number;
24
+ chatPanePct?: number;
25
+ /** Collapse flags persist across reloads. */
26
+ leftCollapsed?: boolean;
27
+ chatCollapsed?: boolean;
28
+ /** Last center-pane tab used (Preview / Code / Layout). */
29
+ lastCenterPaneMode?: 'preview' | 'code' | 'layout';
30
+ /** Height percent (0-100) for the forms-list section inside the left rail.
31
+ * The versions panel takes the remainder. Drag the splitter to change. */
32
+ formsListHeightPct?: number;
33
+ /** Inner-panel collapse flags (VS-Code-style). When true, that section
34
+ * shrinks to a header bar and the sibling takes full height. */
35
+ formsListCollapsed?: boolean;
36
+ versionsCollapsed?: boolean;
37
+ /** 'list' (flat) | 'tree' (Schema → Entity → Forms). */
38
+ formsViewMode?: 'list' | 'tree';
39
+ /** Entity filter selection ('All' or specific entity name). */
40
+ formsEntityFilter?: string;
41
+ /** Status filter chips. Forms whose OverrideStatus is in this set show. */
42
+ formsStatusFilter?: ReadonlyArray<'Active' | 'Pending' | 'Inactive'>;
43
+ /** Sort mode. */
44
+ formsSortMode?: 'updated-desc' | 'updated-asc' | 'name-asc' | 'name-desc';
45
+ /** Component IDs the user has pinned to the top of the list. */
46
+ pinnedFormIds?: ReadonlyArray<string>;
47
+ }
48
+ /**
49
+ * One Component version in the active form's Name lineage. The version rail
50
+ * lists these; clicking activates / previews / diffs.
51
+ */
52
+ export interface ComponentVersionRow {
53
+ ID: string;
54
+ Name: string;
55
+ Version: string;
56
+ VersionSequence: number;
57
+ Status: string;
58
+ UpdatedAt: Date | null;
59
+ /** True when this version is the one currently pointed at by an Active
60
+ * override for the calling user. */
61
+ IsActive: boolean;
62
+ /** True when this version is pointed at by a Pending override for the
63
+ * user (i.e. an AI-authored refinement awaiting activation). */
64
+ IsPending: boolean;
65
+ }
66
+ /**
67
+ * Lightweight summary of a form-role Component, populated from MJ: Components
68
+ * for the left-rail picker. Specification is loaded on demand when the user
69
+ * actually opens a form so we don't pay the JSON parse cost N times.
70
+ */
71
+ interface FormComponentSummary {
72
+ ID: string;
73
+ Name: string;
74
+ Namespace: string | null;
75
+ /**
76
+ * `Component.Status` (Draft / Published / Deprecated) — kept on the
77
+ * summary for callers that need it (e.g. the version rail), but NOT
78
+ * what the left rail badge displays. The left rail surfaces the
79
+ * **override** status (see `OverrideStatus` below) because that's
80
+ * what drives runtime visibility for the user.
81
+ */
82
+ Status: string | null;
83
+ /**
84
+ * The current user's `EntityFormOverride.Status` (Active / Inactive /
85
+ * Pending) for this Component, when an override exists. Null when no
86
+ * user-scope override binds to this Component — in which case the
87
+ * runtime falls through to a higher-scope (Role/Global) override or
88
+ * the CodeGen Angular default. Populated by `loadExistingForms` via
89
+ * a single batch lookup against `MJ: Entity Form Overrides`.
90
+ */
91
+ OverrideStatus: 'Active' | 'Inactive' | 'Pending' | null;
92
+ Description: string | null;
93
+ TargetEntityName: string | null;
94
+ /** Entity ID extracted from the user's override (when present) — used to
95
+ * resolve EntityInfo for icon/schema/name lookups. Null when no
96
+ * user-scope override binds to this Component. */
97
+ TargetEntityID?: string | null;
98
+ /** Cached entity display name (resolved via provider.EntityByName at
99
+ * loadExistingForms time). Used as the per-row entity subtitle. */
100
+ TargetEntityDisplayName?: string | null;
101
+ /** Cached entity icon class (Font Awesome) from EntityInfo.Icon. */
102
+ TargetEntityIcon?: string | null;
103
+ /** Cached entity schema name — drives tree-view grouping. */
104
+ TargetEntitySchemaName?: string | null;
105
+ /** Component row's last-modified timestamp — for "edited 2h ago" sorts. */
106
+ UpdatedAt?: Date | null;
107
+ }
108
+ /**
109
+ * Form Builder resource — the standalone Form Studio canvas reachable from
110
+ * the top-left Application rail. Provides a drag-drop canvas, field-binding
111
+ * inspector, and EntityFormOverride activation flow that mirrors Component
112
+ * Studio's contextual Form Builder tab but as its own dedicated workspace.
113
+ *
114
+ * Owns its OWN state — does NOT depend on `ComponentStudioStateService`,
115
+ * which is provided per-Component-Studio-dashboard. The canvas and right
116
+ * panel children are state-agnostic and accept everything via @Input/@Output.
117
+ *
118
+ * Per `dashboards/CLAUDE.md`, this resource MUST call `NotifyLoadComplete()`
119
+ * after the initial load — without it, the shell loading screen hangs forever
120
+ * on direct URL navigation (e.g. `/app/form-studio/Form%20Builder`).
121
+ */
122
+ export declare class FormBuilderResourceComponent extends BaseResourceComponent implements AfterViewInit, OnDestroy {
123
+ GetResourceDisplayName(_data: ResourceData): Promise<string>;
124
+ GetResourceIconClass(_data: ResourceData): Promise<string>;
125
+ LeftRailCollapsed: boolean;
126
+ RightRailCollapsed: boolean;
127
+ ChatPaneCollapsed: boolean;
128
+ IsLoading: boolean;
129
+ ExistingForms: FormComponentSummary[];
130
+ LeftRailFilter: string;
131
+ /** Percent (0-100) height of the forms-list section within the left
132
+ * rail. The versions panel takes the remainder. */
133
+ FormsListHeightPct: number;
134
+ FormsListCollapsed: boolean;
135
+ VersionsCollapsed: boolean;
136
+ FormsViewMode: 'list' | 'tree';
137
+ /** Selected entity filter. Empty string = "All entities". */
138
+ FormsEntityFilter: string;
139
+ /** Status chips currently enabled. Active+Pending+Inactive by default
140
+ * so the list shows everything. Toggle a chip OFF to hide that bucket. */
141
+ FormsStatusFilter: Set<'Active' | 'Pending' | 'Inactive'>;
142
+ FormsSortMode: 'updated-desc' | 'updated-asc' | 'name-asc' | 'name-desc';
143
+ /** Pinned form Component IDs (kept sticky at the top of the list). */
144
+ PinnedFormIds: Set<string>;
145
+ /** Right-click context-menu state. */
146
+ ContextMenuForm: FormComponentSummary | null;
147
+ ContextMenuX: number;
148
+ ContextMenuY: number;
149
+ ContextMenuOpen: boolean;
150
+ /** Entity-filter dropdown open state. */
151
+ EntityFilterDropdownOpen: boolean;
152
+ EntityFilterSearch: string;
153
+ /** When the user starts a diff via right-click on a version row,
154
+ * this holds the first selection. Click another row to compare. */
155
+ DiffSourceVersionID: string | null;
156
+ /** When set, render the diff modal showing both specs side-by-side. */
157
+ DiffTargetVersionID: string | null;
158
+ DiffSourceCode: string;
159
+ DiffTargetCode: string;
160
+ ShowDiffDialog: boolean;
161
+ /**
162
+ * Center-pane view mode for the cockpit. Default is 'preview' because the
163
+ * preview is the most useful single view when a form is loaded; users
164
+ * tab to 'code' to edit and 'layout' for the (legacy) drag-drop canvas.
165
+ */
166
+ CenterPaneMode: 'preview' | 'code' | 'layout';
167
+ /**
168
+ * Version rail data. Lineage = all Component rows sharing the active
169
+ * form's Name. Ordered by VersionSequence DESC so the newest is on top.
170
+ */
171
+ Versions: ComponentVersionRow[];
172
+ /**
173
+ * The version row matching the Component currently loaded in the
174
+ * editor (`SelectedFormID`). Drives the floating "Viewing v1.0.0"
175
+ * overlay on the center pane so the user always knows which
176
+ * version's spec they're looking at — particularly useful when
177
+ * they've clicked an older row in the version rail to inspect
178
+ * historical work, and the on-screen form differs from what the
179
+ * runtime is actually serving.
180
+ */
181
+ get CurrentSelectedVersion(): ComponentVersionRow | null;
182
+ VersionsLoading: boolean;
183
+ ActiveVersionID: string | null;
184
+ /**
185
+ * Live preview state. When the user switches to the Preview tab, we load
186
+ * a Top-1 record from `TargetEntityName` and mount `<mj-interactive-form>`
187
+ * with the working `componentSpec` derived from the current EditableCode.
188
+ * Failure modes (no record, RunView error) fall back to a synthetic
189
+ * NewRecord() so the form still mounts — the user just sees an empty
190
+ * draft instead of a broken pane.
191
+ */
192
+ PreviewRecord: BaseEntity | null;
193
+ PreviewRecordIsReal: boolean;
194
+ PreviewRecordLabel: string;
195
+ PreviewLoading: boolean;
196
+ PreviewError: string | null;
197
+ PreviewPickerOpen: boolean;
198
+ /**
199
+ * The saved ComponentSpec from the last loaded form, preserved so the
200
+ * Preview pane can merge live code edits over the rich metadata
201
+ * (dataRequirements / description / functionalRequirements / technicalDesign)
202
+ * rather than rebuilding from `EditableCode` alone. Retrospective fix #5.
203
+ */
204
+ SavedSpec: ComponentSpec | null;
205
+ /**
206
+ * True when the in-memory code (EditableCode) has diverged from what the
207
+ * canvas can represent — e.g. hand-authored sections, computed JSX the
208
+ * canvas-parser can't round-trip. Set by `hydrateCanvasFromCode`. The
209
+ * Layout tab shows a warning banner so the user knows the canvas will
210
+ * overwrite parts of the code on save. Retrospective fix #6.
211
+ */
212
+ CanvasDiverged: boolean;
213
+ PreviewSearchTerm: string;
214
+ PreviewSearchResults: Array<{
215
+ ID: string;
216
+ Label: string;
217
+ }>;
218
+ /**
219
+ * AppContext snapshot fed to the embedded `<mj-conversation-chat-area>`
220
+ * so the agent sees the cockpit's current form + entity. Sourced from
221
+ * `NavigationService.AppContextSnapshot$` — the same snapshot the floating
222
+ * overlay uses — so both surfaces see identical context. Our cockpit-
223
+ * specific state is pushed in via `SetAgentContext()` (which the Explorer
224
+ * app shell merges into the snapshot's `AdditionalContext`).
225
+ */
226
+ ChatAppContext: AppContextSnapshot | null;
227
+ /**
228
+ * Resolved ID of the Form Builder agent. Looked up once at init via
229
+ * RunView. Bound to `<mj-conversation-chat-area>`'s `[defaultAgentId]`
230
+ * so messages route directly to the Form Builder agent instead of going
231
+ * through Sage — Sage doesn't author forms, the Form Builder agent does.
232
+ * Null until the lookup resolves (or if the agent isn't installed); in
233
+ * that case the chat falls back to Sage routing.
234
+ */
235
+ FormBuilderAgentId: string | null;
236
+ private appContextSubscription;
237
+ private entityEventSubscription;
238
+ /**
239
+ * Subscription to `InteractiveFormsEngine` Forms$/Overrides$. Fires
240
+ * whenever the engine's cache is mutated (local save, remote-invalidate,
241
+ * delete) and drives a sync recompute of {@link ExistingForms} and
242
+ * {@link Versions}. Replaces the old "call loadExistingForms after every
243
+ * mutation" pattern — engine + observable handle invalidation.
244
+ */
245
+ private engineSubscription;
246
+ /**
247
+ * Conversation state for the embedded chat. Initially null/new; when the
248
+ * user sends the first message, the chat-area emits `conversationCreated`
249
+ * and we flip these so subsequent renders keep the same conversation.
250
+ * Without this binding, the chat appears "stuck" on the welcome message
251
+ * because the wrapper never picks up the new conversation ID.
252
+ */
253
+ ChatConversation: MJConversationEntity | null;
254
+ ChatConversationId: string | null;
255
+ /**
256
+ * Lightweight list of all conversations across the active form's
257
+ * lineage — feeds the chat header's "N conversations" dropdown so the
258
+ * user can switch back to a prior thread instead of being locked into
259
+ * just the most-recent one. Populated alongside loadLinkedConversation.
260
+ */
261
+ LineageConversations: Array<{
262
+ ID: string;
263
+ Name: string | null;
264
+ UpdatedAt: Date | null;
265
+ }>;
266
+ ConversationHistoryDropdownOpen: boolean;
267
+ ChatIsNewConversation: boolean;
268
+ /**
269
+ * Pending message + attachments that came back on `conversationCreated`.
270
+ * The chat-area emits these as part of its atomic state-handoff so the
271
+ * parent can re-feed them after the conversation has an ID. The
272
+ * chat-area's `pendingMessageConsumed` event tells us when to clear.
273
+ * Without this loop, the user's first message creates the conversation
274
+ * but never actually posts.
275
+ */
276
+ ChatPendingMessage: string | null;
277
+ ChatPendingAttachments: unknown[] | null;
278
+ /**
279
+ * Thread state for the embedded chat. Mirrors the workspace shell's
280
+ * pattern: chat-area emits `threadOpened` with a thread ID when the
281
+ * user drills into a sub-thread, and `threadClosed` when they leave.
282
+ * Forwarded back as `[threadId]` so the chat-area knows which thread
283
+ * to render. Without these handlers, clicking a thread message in
284
+ * the cockpit's chat appears to do nothing (the chat-area emits but
285
+ * no one binds back).
286
+ */
287
+ ChatThreadId: string | null;
288
+ /**
289
+ * Pending artifact pointer for the chat-area to scroll to / highlight
290
+ * after navigation. Set when an artifact link inside the chat is
291
+ * clicked (the chat-area asks us to surface a specific artifact
292
+ * version) and cleared when consumed.
293
+ */
294
+ ChatPendingArtifactId: string | null;
295
+ ChatPendingArtifactVersionNumber: number | null;
296
+ /**
297
+ * Environment ID for the embedded chat-area. Resource components in
298
+ * Explorer accept this via ResourceData.Configuration; we fall back to
299
+ * the default environment when not supplied.
300
+ */
301
+ get ChatEnvironmentId(): string;
302
+ /**
303
+ * Pane sizes (percent) for the 3-pane horizontal split. Initialized
304
+ * from {@link FormBuilderPrefs} loaded out of UserInfoEngine on init;
305
+ * mutated by the splitter's drag-end event; written back via
306
+ * {@link savePrefs}.
307
+ */
308
+ LeftPanePct: number;
309
+ CenterPanePct: number;
310
+ ChatPanePct: number;
311
+ /**
312
+ * True when a form is "actively being shown" — either an existing
313
+ * form is loaded (SelectedFormID set) or the user clicked New Form
314
+ * (IsNewForm). The right-side chat pane is gated on this so empty
315
+ * cockpits don't render an agent shell against no subject.
316
+ */
317
+ get HasActiveForm(): boolean;
318
+ SelectedFormID: string | null;
319
+ SelectedFormName: string;
320
+ IsNewForm: boolean;
321
+ TargetEntityName: string | null;
322
+ Schema: CuratedFormSchema | null;
323
+ Canvas: FormCanvasModel | null;
324
+ SelectedElementId: string | null;
325
+ SelectedSectionId: string | null;
326
+ EditableCode: string;
327
+ DirtyFlag: boolean;
328
+ IsEntityPickerOpen: boolean;
329
+ EntityPickerSearch: string;
330
+ EntityChoices: ReadonlyArray<{
331
+ Name: string;
332
+ DisplayName: string;
333
+ }>;
334
+ /**
335
+ * State for the cockpit's reusable confirm dialog. Replaces the
336
+ * browser-native `window.confirm()` calls (delete form, discard
337
+ * unsaved edits) with a styled in-app dialog. Three reasons for the
338
+ * switch: (a) consistent visual language with the override + diff
339
+ * dialogs, (b) confirm/cancel button order matches MJ convention
340
+ * (primary left), (c) browser confirm is blocked by some browsers /
341
+ * tools when triggered from event handlers without recent user
342
+ * gesture (e.g. agent-driven flows).
343
+ *
344
+ * Hold the resolver callback alongside the state so multiple confirm
345
+ * call-sites can share the same dialog without each one re-binding.
346
+ */
347
+ ConfirmDialog: {
348
+ Open: boolean;
349
+ Title: string;
350
+ Body: string;
351
+ ConfirmLabel: string;
352
+ CancelLabel: string;
353
+ Danger: boolean;
354
+ OnConfirm: () => void | Promise<void>;
355
+ OnCancel?: () => void;
356
+ } | null;
357
+ ShowFormOverrideDialog: boolean;
358
+ PendingOverrideComponentID: string | null;
359
+ PendingOverrideComponentName: string;
360
+ PendingOverrideEntityName: string;
361
+ /** Pre-fill values forwarded to the override dialog. Populated by
362
+ * OnSave (for post-save flow) or OpenEditFormDetailsDialog (for the
363
+ * edit-existing-override flow). */
364
+ PendingOverrideInitialName: string | null;
365
+ PendingOverrideInitialDescription: string | null;
366
+ PendingOverrideInitialNotes: string | null;
367
+ PendingOverrideInitialStatus: 'Active' | 'Inactive' | 'Pending' | null;
368
+ PendingOverrideInitialScope: 'User' | 'Role' | 'Global' | null;
369
+ PendingOverrideInitialRoleID: string | null | undefined;
370
+ PendingOverrideInitialPriority: number | undefined;
371
+ /** Edit-mode flag — when true, the dialog updates the existing
372
+ * override (`EditingOverrideID`) instead of creating a new one. */
373
+ FormOverrideDialogEditMode: boolean;
374
+ EditingOverrideID: string | null;
375
+ private readonly cdr;
376
+ private readonly notifications;
377
+ private readonly overrideService;
378
+ private readonly conversationBridge;
379
+ /**
380
+ * Name of the Application this cockpit lives in — must match the
381
+ * `Application.Name` column. "Form Studio" is the nav-item LABEL
382
+ * inside the "Component Studio" app, not a separate application;
383
+ * the canonical Application row is named "Component Studio". See
384
+ * `/metadata/applications/.component-studio-application.json`.
385
+ */
386
+ private static readonly COCKPIT_APP_NAME;
387
+ /**
388
+ * ID of the Application that owns this cockpit. Resolved at init from
389
+ * `Metadata.Applications` (the in-memory cache populated at provider
390
+ * bootstrap — NO RunView round-trip) and forwarded to the embedded
391
+ * chat-area as `[applicationId]`, so conversations created inside this
392
+ * cockpit are scoped to the Form Studio app and don't pollute the
393
+ * main Chat list.
394
+ */
395
+ CockpitApplicationId: string | null;
396
+ /**
397
+ * EntityID for `MJ: Components`, resolved from `Metadata.Entities` at
398
+ * init. Bound to `<mj-conversation-chat-area>`'s `[linkedEntityId]`
399
+ * so conversations created in the cockpit are stamped as "about a
400
+ * Component" — enabling the future "show prior conversations about
401
+ * THIS form" surface. In-memory lookup, no RunView.
402
+ */
403
+ ComponentsEntityID: string | null;
404
+ private get provider();
405
+ get currentUser(): UserInfo | null;
406
+ ngAfterViewInit(): Promise<void>;
407
+ ngOnDestroy(): void;
408
+ /**
409
+ * MJGlobal event handler — fires whenever any BaseEntity in the app
410
+ * is saved/deleted/etc. We filter aggressively here: only react to
411
+ * `save` (local + remote-invalidate from the agent's server-side
412
+ * action) on `MJ: Components` or `MJ: Entity Form Overrides`, and
413
+ * only when the affected row belongs to the lineage of the form
414
+ * currently loaded in this cockpit. Anything else bails immediately
415
+ * — this listener runs for every entity save in the entire app, so
416
+ * cheapness matters.
417
+ */
418
+ private handleEntityEvent;
419
+ /**
420
+ * Normalize the `{ID, Name}` we need to match a BaseEntity event against
421
+ * the active form, regardless of whether the event came from a local
422
+ * `Save()` (with a live `baseEntity` attached) or a server-broadcast
423
+ * `remote-invalidate` (where `baseEntity` is null and the row lives in
424
+ * `evt.payload.primaryKeyValues` + `evt.payload.recordData`, both
425
+ * JSON-stringified by `MJServer/src/index.ts:626-641`).
426
+ */
427
+ private resolveEntityEventIdentity;
428
+ /**
429
+ * Agent (or another client) just modified the Component / Override
430
+ * for the form currently loaded in this cockpit. Reload the spec
431
+ * from the same Component so the canvas + code + preview reflect
432
+ * the new state without forcing a manual refresh.
433
+ *
434
+ * Guards: don't clobber unsaved user edits — if the cockpit has its
435
+ * own `DirtyFlag` set, surface a notification instead of silently
436
+ * overwriting. The user can manually re-pick the form when ready.
437
+ */
438
+ private handleAgentEditedActiveForm;
439
+ /**
440
+ * One-shot lookup of the Form Builder agent's ID. Used to bind the
441
+ * chat-area's `[defaultAgentId]` so the cockpit's chat skips Sage routing
442
+ * and addresses messages directly to the form-authoring specialist.
443
+ *
444
+ * Uses `AIEngineBase.Instance.Agents` (the in-memory cache that's
445
+ * already loaded on app boot) rather than a RunView round-trip. This
446
+ * also avoids the easy-to-trip entity-name typo (`'AI Agents'` vs
447
+ * `'MJ: AI Agents'`) that previously left FormBuilderAgentId null and
448
+ * silently fell back to Sage routing.
449
+ */
450
+ private resolveFormBuilderAgentId;
451
+ /**
452
+ * Recompute the left-rail forms list from `InteractiveFormsEngine`'s
453
+ * in-memory caches. **Synchronous** in spirit — the `async` signature is
454
+ * kept for backwards-compat with existing call sites and to surface
455
+ * future lazy-load needs cleanly. Reads only from the engine, never the
456
+ * DB. Driven by the engine subscription in {@link ngAfterViewInit}, so
457
+ * any save/delete/remote-invalidate refreshes this list automatically.
458
+ *
459
+ * Representative selection per Name lineage (Active > Pending >
460
+ * Inactive > none, then VersionSequence DESC) and the projection to
461
+ * {@link FormComponentSummary} match the previous RunView-based
462
+ * implementation exactly.
463
+ */
464
+ private loadExistingForms;
465
+ /**
466
+ * Forms list filtered + sorted per the user's left-rail prefs.
467
+ * Pipeline: search text → entity filter → status chips → sort →
468
+ * pinned-first. The result drives both the flat-list view and is
469
+ * grouped by schema/entity for the tree view.
470
+ */
471
+ get filteredForms(): ReadonlyArray<FormComponentSummary>;
472
+ /**
473
+ * Tree-view groups: forms grouped by SchemaName → EntityName. Falls
474
+ * back to a synthetic "(no entity)" group for forms without a
475
+ * user-scope override bound to an entity.
476
+ */
477
+ get treeGroups(): ReadonlyArray<{
478
+ schema: string;
479
+ entities: ReadonlyArray<{
480
+ entity: string;
481
+ entityDisplay: string;
482
+ icon: string | null;
483
+ forms: ReadonlyArray<FormComponentSummary>;
484
+ }>;
485
+ }>;
486
+ /**
487
+ * Distinct entity names that appear in the current forms list — used
488
+ * to populate the entity-filter dropdown. Empty string ("") = "All
489
+ * entities", added at the top. Search-text-filtered when the user
490
+ * is typing into the dropdown's own search box.
491
+ */
492
+ get entityFilterOptions(): ReadonlyArray<{
493
+ name: string;
494
+ display: string;
495
+ icon: string | null;
496
+ count: number;
497
+ }>;
498
+ OnLeftRailFilterChange(event: Event): void;
499
+ ToggleFormsViewMode(): void;
500
+ ToggleEntityFilterDropdown(): void;
501
+ OnEntityFilterSearch(e: Event): void;
502
+ PickEntityFilter(entityName: string): void;
503
+ ToggleStatusFilter(status: 'Active' | 'Pending' | 'Inactive'): void;
504
+ SetFormsSortMode(mode: 'updated-desc' | 'updated-asc' | 'name-asc' | 'name-desc'): void;
505
+ TogglePinForm(form: FormComponentSummary, event?: Event): void;
506
+ IsFormPinned(form: FormComponentSummary): boolean;
507
+ ToggleFormsListCollapsed(): void;
508
+ ToggleVersionsCollapsed(): void;
509
+ /**
510
+ * Drag-end handler for the inner vertical splitter between the forms
511
+ * list and the versions panel inside the left rail. Persists the
512
+ * percent split so the user's preferred layout sticks across reloads.
513
+ */
514
+ OnInnerSplitterDragEnd(event: {
515
+ sizes: ReadonlyArray<number | '*'>;
516
+ }): void;
517
+ /** Right-click context menu on a form row. Opens at click coords. */
518
+ OnFormRowContextMenu(form: FormComponentSummary, event: MouseEvent): void;
519
+ CloseContextMenu(): void;
520
+ ContextMenuDuplicate(): Promise<void>;
521
+ ContextMenuDelete(): Promise<void>;
522
+ ContextMenuCopyID(): void;
523
+ ContextMenuExportSpec(): void;
524
+ ContextMenuTogglePin(): void;
525
+ ToggleLeftRail(): void;
526
+ ToggleRightRail(): void;
527
+ ToggleChatPane(): void;
528
+ SetCenterPaneMode(mode: 'preview' | 'code' | 'layout'): void;
529
+ /**
530
+ * Live `ComponentSpec` for the Preview pane. Derived from the in-memory
531
+ * `EditableCode` so the preview reflects unsaved edits — switching to
532
+ * Preview while typing in Code shows the in-progress version, not the
533
+ * last-saved one. Falls back to null when there's no code yet, in which
534
+ * case the Preview pane shows a friendly empty state.
535
+ */
536
+ get PreviewSpec(): import('@memberjunction/interactive-component-types').ComponentSpec | null;
537
+ /**
538
+ * Load a Top-1 record from the target entity to bind into the preview.
539
+ * If the entity has no rows, we still mount the form against a synthetic
540
+ * NewRecord() so the layout / styling / event handlers can be evaluated.
541
+ */
542
+ loadPreviewRecord(): Promise<void>;
543
+ /** Pull a human label from the record's NameField or primary key. */
544
+ private recordLabel;
545
+ /**
546
+ * Handle a LoadErrorChanged emit from <mj-interactive-form> in the
547
+ * Preview pane. Surfaces the error in the cockpit's own error state so
548
+ * users see "Preview failed" in the cockpit chrome instead of having
549
+ * to look inside the form's React shell. Retrospective fix #10.
550
+ */
551
+ OnPreviewLoadError(message: string | null): void;
552
+ /**
553
+ * Open the preview record (the entity row currently bound to
554
+ * `<mj-interactive-form>`) in a fresh Explorer tab. Useful sanity-check
555
+ * — render the form against this same record in the production
556
+ * resolver path to confirm the cockpit's preview matches reality.
557
+ */
558
+ OpenPreviewRecord(): void;
559
+ TogglePreviewPicker(): void;
560
+ /** Search-as-you-type for the preview record picker. */
561
+ OnPreviewSearchInput(event: Event): Promise<void>;
562
+ /**
563
+ * Shared loader for the preview record picker. Empty term → top N
564
+ * by name. Non-empty term → `LIKE %term%` on the name field. Both
565
+ * paths share the result-mapping logic so the dropdown looks the same.
566
+ */
567
+ private loadPreviewPickerResults;
568
+ /** User picked a different record from the search results — re-bind preview. */
569
+ OnPreviewRecordPicked(item: {
570
+ ID: string;
571
+ Label: string;
572
+ }): Promise<void>;
573
+ /**
574
+ * Direct-edit handler used by `<mj-code-editor>` via ngModelChange.
575
+ * Receives the new editor value as a string. Marks the form dirty so
576
+ * the Save button activates; the Layout-tab canvas is *not* re-derived
577
+ * here (avoids destructive round-trips when the JSX has hand-authored
578
+ * bits the canvas-parser can't model).
579
+ */
580
+ /**
581
+ * Chat-area emitted `conversationCreated` after the user sent the first
582
+ * message — switch the embedded chat out of "new conversation" mode so
583
+ * subsequent renders show the live conversation thread. Without this,
584
+ * the chat appears stuck on its welcome screen.
585
+ */
586
+ OnChatConversationCreated(event: {
587
+ conversation: MJConversationEntity;
588
+ pendingMessage?: string;
589
+ pendingAttachments?: unknown[];
590
+ }): void;
591
+ /**
592
+ * Chat-area finished delivering the pending message — clear the buffer
593
+ * so a re-render doesn't try to send it again.
594
+ */
595
+ OnChatPendingMessageConsumed(): void;
596
+ /**
597
+ * Chat-area emitted `openEntityRecord` — user clicked an entity link
598
+ * inside an agent reply. Open the record as a new Explorer tab via
599
+ * NavigationService (same as the workspace's actionable-command
600
+ * path, but executed directly here since the cockpit has no
601
+ * intermediate workspace shell).
602
+ */
603
+ OnChatOpenEntityRecord(event: {
604
+ entityName: string;
605
+ compositeKey: CompositeKey;
606
+ }): void;
607
+ /**
608
+ * Chat-area emitted a generic `navigationRequest` (cross-resource
609
+ * navigation, e.g. "go to Collections with this artifact"). Route
610
+ * via NavigationService.OpenNavItemByName.
611
+ */
612
+ OnChatNavigationRequest(event: NavigationRequest): void;
613
+ /**
614
+ * Chat-area emitted `taskClicked` — user clicked a task pill in an
615
+ * agent reply. The workspace switches to its Tasks tab; the cockpit
616
+ * has no Tasks tab, so open the task record directly.
617
+ */
618
+ OnChatTaskClicked(task: MJTaskEntity): void;
619
+ /**
620
+ * Chat-area emitted `artifactLinkClicked` — user clicked an artifact
621
+ * link inside a message. Conversation-type links point at another
622
+ * conversation in main Chat; collection-type links point at a
623
+ * collection. Both route into the main Chat / Collections app via
624
+ * NavigationService so the artifact opens in its native context
625
+ * (the cockpit is form-authoring focused, not the right surface to
626
+ * render arbitrary artifacts inline).
627
+ */
628
+ OnChatArtifactLinkClicked(event: {
629
+ type: 'conversation' | 'collection';
630
+ id: string;
631
+ }): void;
632
+ /** Chat-area emitted `conversationRenamed` — purely informational for the cockpit (no convo list to animate). */
633
+ OnChatConversationRenamed(event: {
634
+ conversationId: string;
635
+ name: string;
636
+ description: string;
637
+ }): void;
638
+ /** Thread drill-down: chat-area opened a sub-thread. Track ID so the chat-area renders it. */
639
+ OnChatThreadOpened(threadId: string): void;
640
+ /** Thread drill-down: chat-area closed the sub-thread. Clear ID. */
641
+ OnChatThreadClosed(): void;
642
+ /** Pending artifact handed off to the chat-area (e.g. via deep link) has been consumed. */
643
+ OnChatPendingArtifactConsumed(): void;
644
+ /**
645
+ * Load cockpit prefs from UserInfoEngine. Called once during
646
+ * ngAfterViewInit. Missing / unparseable values fall through to the
647
+ * defaults declared at field-init time — never throws.
648
+ */
649
+ private loadPrefs;
650
+ /**
651
+ * Write the current cockpit UI state back to UserInfoEngine, debounced
652
+ * (the engine handles debouncing internally). Called from the splitter's
653
+ * drag-end event, the collapse toggles, and the center-pane mode setter.
654
+ */
655
+ private savePrefs;
656
+ /**
657
+ * Splitter drag-end handler. `sizes` from angular-split is an array of
658
+ * `SplitAreaSize` values (number | '*' for auto-size); for our
659
+ * percent-unit splitter only numbers come through, but the union forces
660
+ * us to filter. Order matches the visible-pane order: [left?, center, chat?].
661
+ */
662
+ OnSplitterDragEnd(event: {
663
+ sizes: ReadonlyArray<number | '*'>;
664
+ }): void;
665
+ OnEditableCodeChange(next: string | null | undefined): void;
666
+ /**
667
+ * Load all Component versions sharing the active form's Name. The version
668
+ * rail renders these; `Active` / `Pending` flags come from cross-referencing
669
+ * EntityFormOverrides for the user. Tolerates missing user / empty results
670
+ * — version rail just shows nothing in that case.
671
+ */
672
+ /**
673
+ * Look up the most-recent conversation linked to the active form
674
+ * (LinkedEntityID=MJ:Components, LinkedRecordID anywhere in the form's
675
+ * Component lineage for this entity) for the current user and bind it
676
+ * to the embedded chat.
677
+ *
678
+ * **Lineage-aware**: a Form Builder conversation belongs to "this form"
679
+ * (the Component.Name lineage), not to a single Component version. When
680
+ * the agent does a `patch`/`minor`/`major` bump via Modify Interactive
681
+ * Form, prior conversations were stamped with the old ComponentID — a
682
+ * naive `LinkedRecordID = SelectedFormID` lookup would orphan them. We
683
+ * expand the lookup to all Components in the same lineage by joining
684
+ * `vwComponents.Name = SelectedFormName` with
685
+ * `vwEntityFormOverrides.EntityID = TargetEntityID` inside an `IN`
686
+ * subquery so it stays one round-trip.
687
+ *
688
+ * Note: this is ONLY about which prior conversation to show in the
689
+ * cockpit chat. New conversations are still stamped with the current
690
+ * SelectedFormID; the lineage join on read picks them up across
691
+ * version bumps. Runtime form resolution is completely unaffected.
692
+ *
693
+ * If none exists, reset to a fresh pre-conversation state — the
694
+ * suppressed empty-state path in <mj-conversation-chat-area> renders
695
+ * the normal header + mode picker + input so the user can start a
696
+ * new linked conversation in place. Errors are tolerated (chat just
697
+ * stays on the previous state).
698
+ */
699
+ private loadLinkedConversationForActiveForm;
700
+ ToggleConversationHistoryDropdown(): void;
701
+ /**
702
+ * Switch the embedded chat to a different conversation in the same
703
+ * lineage. Used by the header's "N conversations" dropdown.
704
+ */
705
+ PickLineageConversation(c: {
706
+ ID: string;
707
+ Name: string | null;
708
+ }): Promise<void>;
709
+ /**
710
+ * Build the ExtraFilter for the lineage-aware conversation lookup.
711
+ * Falls back to single-version filtering when the lineage signals
712
+ * (SelectedFormName, TargetEntityName→ID, or the schema/view metadata
713
+ * for Components/Overrides) aren't available — degrades to the
714
+ * original behavior rather than breaking the chat.
715
+ */
716
+ private buildLinkedConvoFilter;
717
+ /**
718
+ * One-shot retry wrapper around the conversation lookup. The shared
719
+ * GraphQLDataProvider occasionally throws "Entity null not found in
720
+ * metadata" when the React form-preview's own RunView wave is in
721
+ * flight concurrently — the failure is transient. Retrying once after
722
+ * a short delay clears it.
723
+ */
724
+ private runLinkedConvoQuery;
725
+ /** Reset embedded chat to the pre-conversation state for a new form. */
726
+ private resetChatToFresh;
727
+ /**
728
+ * Recompute the version-rail rows from `InteractiveFormsEngine`'s
729
+ * caches — all Component rows in the active form's Name lineage, joined
730
+ * against the current user's override rows to tag Active / Pending.
731
+ * No DB round-trip. Auto-refreshed by the engine subscription in
732
+ * {@link ngAfterViewInit} on any save/delete/remote-invalidate.
733
+ *
734
+ * Kept `async` for callers that already `await` it; the body is sync.
735
+ */
736
+ loadVersionsForActiveForm(): Promise<void>;
737
+ /**
738
+ * Open the chat overlay with the active-form context already set. The
739
+ * overlay is mounted at the app root; we don't construct it here. The
740
+ * agent context is kept fresh by `registerAgentContext()` (called on
741
+ * every form change).
742
+ *
743
+ * Side effect: also un-collapses the chat pane so the user sees the
744
+ * surface they just clicked.
745
+ */
746
+ OnOpenInChat(): void;
747
+ /**
748
+ * Re-point this form's Active override at the picked version. Called
749
+ * from the version rail "Make Active" button. Delegates to the
750
+ * `Activate Interactive Form Version` action when the version is Pending,
751
+ * otherwise delegates to `Revert Interactive Form` (re-point Active
752
+ * override to an older Component row in the same Name lineage).
753
+ */
754
+ OnActivateVersion(version: ComponentVersionRow): Promise<void>;
755
+ /**
756
+ * Version-rail row click. Loads that version's Component into the
757
+ * cockpit's editor (Preview / Code / Layout) — does NOT change which
758
+ * version the runtime resolver picks for users (that's still driven
759
+ * by the Active override). To promote an older version to Active,
760
+ * the user clicks the row's "Activate" / "Restore" button.
761
+ *
762
+ * No-op when the row is already loaded. Builds a synthetic summary
763
+ * and delegates to {@link OnFormPicked} so the load path is exactly
764
+ * the same as picking from the left rail (handles dirty-discard
765
+ * confirmation, schema rebuild, version rail refresh, agent context
766
+ * push, etc.).
767
+ */
768
+ OnVersionRowClick(v: ComponentVersionRow): Promise<void>;
769
+ /**
770
+ * Begin a diff selection from the version rail. The clicked version
771
+ * becomes the "source"; the next clicked version becomes the "target"
772
+ * and we render a side-by-side diff modal.
773
+ *
774
+ * Click the same version twice → cancels the selection.
775
+ */
776
+ OnVersionDiffClick(v: ComponentVersionRow, event: Event): Promise<void>;
777
+ CloseDiffDialog(): void;
778
+ /** Helper: lookup the version row for a given ID, used in the diff title. */
779
+ versionByID(id: string | null): ComponentVersionRow | null;
780
+ OnFormPicked(form: FormComponentSummary): Promise<void>;
781
+ /**
782
+ * Look up an EntityFormOverride that points at this Component and return
783
+ * the bound entity's name. Used by `OnFormPicked` to recover the target
784
+ * entity for forms that have been activated against a real entity.
785
+ */
786
+ /**
787
+ * Override metadata for the active form — captured at form-load time so
788
+ * the agent context can carry it inline (no `Get Active Form For Entity`
789
+ * round-trip needed). The Form Builder agent prompt's lifecycle rules
790
+ * branch on whether an active override exists and what its scope/status
791
+ * is; passing this snapshot upfront lets the agent jump straight to
792
+ * `Modify Interactive Form` instead of guessing.
793
+ */
794
+ ActiveOverrideID: string | null;
795
+ ActiveOverrideScope: string | null;
796
+ ActiveOverrideStatus: string | null;
797
+ /** Whether the cockpit's override-status popover is open. */
798
+ OverrideStatusPickerOpen: boolean;
799
+ /** Inline saving flag — disables the picker buttons mid-save. */
800
+ OverrideStatusSaving: boolean;
801
+ /**
802
+ * Allowed values for `EntityFormOverride.Status` mirrored from the
803
+ * DB CHECK constraint / EntityFieldValue rows. Hardcoded for two
804
+ * reasons: (a) they're stable schema enums, and (b) the picker UI
805
+ * needs them statically to render labels + icons without round-trip.
806
+ */
807
+ readonly OverrideStatusOptions: ReadonlyArray<{
808
+ value: 'Active' | 'Inactive' | 'Pending';
809
+ label: string;
810
+ description: string;
811
+ icon: string;
812
+ }>;
813
+ /** Toggle the override status popover. No-op when no override is loaded. */
814
+ ToggleOverrideStatusPicker(): void;
815
+ /**
816
+ * Persist a new status on the currently-loaded EntityFormOverride.
817
+ * Loads the entity, sets the status, saves, then mirrors the new
818
+ * value onto the cockpit's local snapshot fields so the agent
819
+ * context + UI stay in sync. The BaseEntity event subscription
820
+ * above will also fire as a side effect, but our local guard
821
+ * (`ActiveOverrideStatus` already up to date) keeps the cockpit
822
+ * from triggering a spurious refresh.
823
+ */
824
+ OnOverrideStatusPicked(next: 'Active' | 'Inactive' | 'Pending'): Promise<void>;
825
+ private lookupEntityForComponent;
826
+ OnNewForm(): void;
827
+ private confirmDiscard;
828
+ /**
829
+ * Best-effort parse of the `Specification` JSON column on MJ: Components.
830
+ * Returns `null` if the column is empty or malformed — callers should
831
+ * fall back to empty-code initialization in that case.
832
+ */
833
+ private parseSpec;
834
+ /**
835
+ * Best-effort attempt to extract the target entity from a form
836
+ * Component's stored code. Form components conventionally reference
837
+ * `host.entityName` or `entityName="…"`. If we can't infer it, the user
838
+ * needs to re-pick from the entity dropdown.
839
+ */
840
+ private inferTargetEntityFromCode;
841
+ OnFormNameInput(event: Event): void;
842
+ ToggleEntityPicker(): void;
843
+ OnEntityPickerSearch(event: Event): void;
844
+ get filteredEntityChoices(): ReadonlyArray<{
845
+ Name: string;
846
+ DisplayName: string;
847
+ }>;
848
+ OnEntityPicked(entityName: string): void;
849
+ private refreshEntityChoices;
850
+ OnCanvasChanged(next: FormCanvasModel): void;
851
+ OnElementSelected(payload: {
852
+ sectionId: string;
853
+ elementId: string;
854
+ }): void;
855
+ OnSectionSelected(sectionId: string): void;
856
+ OnDeselected(): void;
857
+ OnElementChanged(next: FormCanvasElement): void;
858
+ OnSectionChanged(next: FormCanvasSection): void;
859
+ OnElementDeleted(elementId: string): void;
860
+ OnSectionDeleted(sectionId: string): void;
861
+ OnFieldAddedFromPalette(payload: {
862
+ fieldName: string;
863
+ }): void;
864
+ private focusedSection;
865
+ private regenerateCode;
866
+ private hydrateCanvasFromCode;
867
+ OnSave(): Promise<void>;
868
+ /**
869
+ * Delete the currently-loaded form's Component AND any EntityFormOverride
870
+ * rows pointing at it. Without the cascade, deleting just the Component
871
+ * would leave orphan overrides whose resolver lookups fail silently.
872
+ */
873
+ OnDelete(): Promise<void>;
874
+ OnFormOverrideDialogConfirm(result: FormOverrideDialogResult): Promise<void>;
875
+ OnFormOverrideDialogDismiss(): void;
876
+ private resetOverrideDialogState;
877
+ /**
878
+ * Open the form-override dialog in EDIT MODE — pre-fills all fields
879
+ * from the active override row so the user can rename, retag, or
880
+ * adjust scope/priority/status without retyping. On confirm, the
881
+ * existing override is updated in place rather than a new one being
882
+ * created.
883
+ *
884
+ * Available from the cockpit's toolbar via the "Edit details" pencil
885
+ * icon next to the form name.
886
+ */
887
+ OpenEditFormDetailsDialog(): Promise<void>;
888
+ /**
889
+ * Update an existing EntityFormOverride row's editable fields from the
890
+ * dialog result. Returns true on success, false on save failure.
891
+ */
892
+ private updateOverrideFromDialog;
893
+ /**
894
+ * Refresh `ActiveOverride*` fields after an edit so the cockpit chrome
895
+ * picks up the new Status/Scope. Used by the edit-details dialog flow.
896
+ */
897
+ private refreshActiveOverrideMetadata;
898
+ /**
899
+ * Compact list of the active entity's relationships, used to seed
900
+ * the agent's context so it knows which related entities are
901
+ * available to link to this form (sub-tables, lookups, etc.).
902
+ *
903
+ * Intentionally **summary-only** — name, relationship type, and
904
+ * join fields. Full schemas for any related entity are still a
905
+ * single `Get Entity Schema For Form` tool call away. Keeping this
906
+ * list compact (~20-50 entries × ~80 chars = a few KB) avoids
907
+ * token bloat while still giving the agent enough to plan without
908
+ * asking the user "what entity links to this?".
909
+ */
910
+ /**
911
+ * Compact catalog of **Active** Component Libraries the agent can
912
+ * declare in `ComponentSpec.libraries`. Read from
913
+ * `ComponentMetadataEngine` (cached at cockpit init). Same shape Skip
914
+ * uses to inform Codesmith Agent — Form Builder forms run in the
915
+ * exact same React runtime, so any Active library is fair game.
916
+ *
917
+ * Per-library payload is kept lean: Name (npm package), Category
918
+ * (UI / Charting / Utility / Other), GlobalVariable (the runtime
919
+ * binding the agent uses inside JSX), Description (one-liner), and
920
+ * Version. UsageInstructions are included only when present AND
921
+ * short (<500 chars) — longer docs would balloon the prompt.
922
+ *
923
+ * Result sorted by Category then Name so the agent sees related
924
+ * libraries grouped together (all Charting options adjacent, all UI,
925
+ * etc.).
926
+ */
927
+ /**
928
+ * Pre-render the AvailableLibraries catalog as markdown for the agent
929
+ * prompt. Token-efficient vs the previous JSON-array shape: nested
930
+ * heading structure that LLMs parse natively, ~40-50% fewer tokens on
931
+ * a typical 25-30 library catalog, and easier to skim in agent-run
932
+ * logs. Grouped by Category (UI, Charting, etc.) with library entries
933
+ * as `### Name (Category)` and per-library bullets for description,
934
+ * version, GlobalVariable, and short usage instructions.
935
+ */
936
+ private buildAvailableLibrariesMarkdown;
937
+ /**
938
+ * Pre-render the active form's curated schema as markdown for the
939
+ * agent prompt. Replaces the JSON Schema payload — same information,
940
+ * roughly half the tokens, and easier to read in logs.
941
+ *
942
+ * Field names are wrapped in inline code (`` `name` ``) so underscores
943
+ * (e.g. `__mj_Internal`) don't get parsed as emphasis. Other text is
944
+ * left raw — LLMs tolerate minor markdown imperfections in description
945
+ * prose fine.
946
+ */
947
+ private buildSchemaMarkdown;
948
+ /**
949
+ * Pre-render the active entity's related-entities summary as markdown.
950
+ * Compact one-line-per-related entry — agent sees what tables it could
951
+ * pull in (lookups, sub-grids, related-record cards) without paying the
952
+ * token cost of full schemas (those are still one `Get Entity Schema
953
+ * For Form` action call away).
954
+ */
955
+ private buildRelatedEntitiesMarkdown;
956
+ private registerAgentContext;
957
+ private markDirty;
958
+ static ɵfac: i0.ɵɵFactoryDeclaration<FormBuilderResourceComponent, never>;
959
+ static ɵcmp: i0.ɵɵComponentDeclaration<FormBuilderResourceComponent, "mj-form-builder-resource", never, {}, {}, never, never, false, never>;
960
+ }
961
+ /** Tree-shake protection — referenced from the dashboards module loader. */
962
+ export declare function LoadFormBuilderResourceComponent(): void;
963
+ export {};
964
+ //# sourceMappingURL=form-builder-resource.component.d.ts.map