@memberjunction/ng-dashboards 5.37.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.
- package/README.md +32 -0
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +14 -0
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +450 -292
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts +73 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.js +512 -127
- package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
- package/dist/ComponentStudio/component-studio-resource.component.d.ts +22 -0
- package/dist/ComponentStudio/component-studio-resource.component.d.ts.map +1 -0
- package/dist/ComponentStudio/component-studio-resource.component.js +55 -0
- package/dist/ComponentStudio/component-studio-resource.component.js.map +1 -0
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts +104 -45
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js +234 -331
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js.map +1 -1
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.d.ts +54 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.js +339 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.js.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.d.ts +65 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.js +492 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.js.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.d.ts +88 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.js +457 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.js.map +1 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.d.ts +106 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.js +478 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.js.map +1 -0
- package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts +54 -0
- package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/workspace/component-preview.component.js +361 -50
- package/dist/ComponentStudio/components/workspace/component-preview.component.js.map +1 -1
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.d.ts +10 -0
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.js +114 -45
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.js.map +1 -1
- package/dist/ComponentStudio/services/canvas-to-code.d.ts +32 -0
- package/dist/ComponentStudio/services/canvas-to-code.d.ts.map +1 -0
- package/dist/ComponentStudio/services/canvas-to-code.js +347 -0
- package/dist/ComponentStudio/services/canvas-to-code.js.map +1 -0
- package/dist/ComponentStudio/services/code-to-canvas.d.ts +32 -0
- package/dist/ComponentStudio/services/code-to-canvas.d.ts.map +1 -0
- package/dist/ComponentStudio/services/code-to-canvas.js +92 -0
- package/dist/ComponentStudio/services/code-to-canvas.js.map +1 -0
- package/dist/ComponentStudio/services/component-studio-state.service.d.ts +29 -0
- package/dist/ComponentStudio/services/component-studio-state.service.d.ts.map +1 -1
- package/dist/ComponentStudio/services/component-studio-state.service.js +76 -0
- package/dist/ComponentStudio/services/component-studio-state.service.js.map +1 -1
- package/dist/ComponentStudio/services/entity-form-override.service.d.ts +86 -0
- package/dist/ComponentStudio/services/entity-form-override.service.d.ts.map +1 -0
- package/dist/ComponentStudio/services/entity-form-override.service.js +246 -0
- package/dist/ComponentStudio/services/entity-form-override.service.js.map +1 -0
- package/dist/ComponentStudio/services/field-binding-scanner.d.ts +29 -0
- package/dist/ComponentStudio/services/field-binding-scanner.d.ts.map +1 -0
- package/dist/ComponentStudio/services/field-binding-scanner.js +110 -0
- package/dist/ComponentStudio/services/field-binding-scanner.js.map +1 -0
- package/dist/ComponentStudio/services/form-canvas-model.d.ts +56 -0
- package/dist/ComponentStudio/services/form-canvas-model.d.ts.map +1 -0
- package/dist/ComponentStudio/services/form-canvas-model.js +35 -0
- package/dist/ComponentStudio/services/form-canvas-model.js.map +1 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.d.ts +10 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.d.ts.map +1 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.js +10 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.js.map +1 -0
- package/dist/DataExplorer/data-explorer-dashboard.component.js +2 -2
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/FormBuilder/form-builder-resource.component.d.ts +964 -0
- package/dist/FormBuilder/form-builder-resource.component.d.ts.map +1 -0
- package/dist/FormBuilder/form-builder-resource.component.js +4487 -0
- package/dist/FormBuilder/form-builder-resource.component.js.map +1 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.d.ts +55 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.d.ts.map +1 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.js +73 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.js.map +1 -0
- package/dist/Home/home-application.d.ts +21 -1
- package/dist/Home/home-application.d.ts.map +1 -1
- package/dist/Home/home-application.js +60 -8
- package/dist/Home/home-application.js.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.d.ts +14 -14
- package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.js +11 -10
- package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
- package/dist/component-studio-dashboards.module.d.ts +34 -22
- package/dist/component-studio-dashboards.module.d.ts.map +1 -1
- package/dist/component-studio-dashboards.module.js +65 -9
- package/dist/component-studio-dashboards.module.js.map +1 -1
- 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
|