@memberjunction/interactive-component-types 5.37.0 → 5.39.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 +20 -0
- package/dist/component-spec.d.ts +20 -0
- package/dist/component-spec.d.ts.map +1 -1
- package/dist/component-spec.js.map +1 -1
- package/dist/forms/curated-form-schema.d.ts +87 -0
- package/dist/forms/curated-form-schema.d.ts.map +1 -0
- package/dist/forms/curated-form-schema.js +124 -0
- package/dist/forms/curated-form-schema.js.map +1 -0
- package/dist/forms/default-form-scaffold.d.ts +37 -0
- package/dist/forms/default-form-scaffold.d.ts.map +1 -0
- package/dist/forms/default-form-scaffold.js +278 -0
- package/dist/forms/default-form-scaffold.js.map +1 -0
- package/dist/forms/form-event-names.d.ts +64 -0
- package/dist/forms/form-event-names.d.ts.map +1 -0
- package/dist/forms/form-event-names.js +29 -0
- package/dist/forms/form-event-names.js.map +1 -0
- package/dist/forms/form-host-props-fixture.d.ts +23 -0
- package/dist/forms/form-host-props-fixture.d.ts.map +1 -0
- package/dist/forms/form-host-props-fixture.js +74 -0
- package/dist/forms/form-host-props-fixture.js.map +1 -0
- package/dist/forms/form-host-props.d.ts +41 -0
- package/dist/forms/form-host-props.d.ts.map +1 -0
- package/dist/forms/form-host-props.js +11 -0
- package/dist/forms/form-host-props.js.map +1 -0
- package/dist/forms/form-method-names.d.ts +35 -0
- package/dist/forms/form-method-names.d.ts.map +1 -0
- package/dist/forms/form-method-names.js +21 -0
- package/dist/forms/form-method-names.js.map +1 -0
- package/dist/forms/form-spec-info.d.ts +23 -0
- package/dist/forms/form-spec-info.d.ts.map +1 -0
- package/dist/forms/form-spec-info.js +27 -0
- package/dist/forms/form-spec-info.js.map +1 -0
- package/dist/forms/index.d.ts +29 -0
- package/dist/forms/index.d.ts.map +1 -0
- package/dist/forms/index.js +30 -0
- package/dist/forms/index.js.map +1 -0
- package/package.json +15 -3
package/README.md
CHANGED
|
@@ -477,6 +477,26 @@ All interfaces are fully typed with TypeScript, providing:
|
|
|
477
477
|
- Better code documentation
|
|
478
478
|
- Reduced runtime errors
|
|
479
479
|
|
|
480
|
+
## Forms subpath (`@memberjunction/interactive-component-types/forms`)
|
|
481
|
+
|
|
482
|
+
The `/forms` subpath provides the **form-role contract** for components that
|
|
483
|
+
declare `componentRole: 'form'` — the substrate that lets MJ render
|
|
484
|
+
runtime-author forms inside Explorer with the same toolbar / save / delete
|
|
485
|
+
behavior as a CodeGen-generated Angular form.
|
|
486
|
+
|
|
487
|
+
| Export | Purpose |
|
|
488
|
+
|---|---|
|
|
489
|
+
| `FormHostProps` | What the host wrapper passes a form-role React component (entity name, primary key, record snapshot, mode, permissions). |
|
|
490
|
+
| `FormEventNames` / `FormBeforeSaveArgs` / etc. | Standard event names + payload types the component emits via `callbacks.NotifyEvent`. |
|
|
491
|
+
| `FormMethodNames` | Standard methods the component registers (`RequestSave`, `RequestCancel`) so the host toolbar can drive its save flow. |
|
|
492
|
+
| `isFormRole(spec)` | Type-guard: does this `ComponentSpec` declare `componentRole: 'form'`? |
|
|
493
|
+
| `CuratedFormSchema`, `buildCuratedFormSchema(entityName, provider)` | Curated, LLM-friendly view of an entity's schema for form authoring — FK references resolved to `{entity, displayField}`, value lists annotated with `allowedValues`, audit/virtual/computed fields stripped. |
|
|
494
|
+
| `buildDefaultFormScaffold(entityName, provider)` | Produces a working form-role `ComponentSpec` that mirrors the CodeGen Angular default layout. Used as the baseline by the Form Builder agent and the dashboard's "New form" flow. |
|
|
495
|
+
| `buildFixtureFormHostProps(schema, mode?)` | Synthesizes type-appropriate fixture values for live-preview rendering when no real `BaseEntity` is available (used by Component Studio preview + the chat artifact viewer's fallback mode). |
|
|
496
|
+
| `getDeclaredFormEntityName(spec)` | Resolves the entity a form binds to from `spec.entityName` or `spec.dataRequirements.entities[0].name`. Pure helper shared by every form-role consumer. |
|
|
497
|
+
|
|
498
|
+
See [/plans/interactive-forms/phase-2-runtime-loop.md](../../plans/interactive-forms/phase-2-runtime-loop.md) for the full architecture, lifecycle, and security model (Create / Modify / Activate / Revert + ownership checks).
|
|
499
|
+
|
|
480
500
|
## Dependencies
|
|
481
501
|
|
|
482
502
|
- `@memberjunction/core`: Core MemberJunction types and interfaces
|
package/dist/component-spec.d.ts
CHANGED
|
@@ -2,6 +2,12 @@ import { ComponentEvent, ComponentProperty } from "./component-props-events.js";
|
|
|
2
2
|
import { ComponentDataRequirements } from "./data-requirements.js";
|
|
3
3
|
import { ComponentLibraryDependency } from "./library-dependency.js";
|
|
4
4
|
import { ComponentTypeDefinition } from "./component-constraints.js";
|
|
5
|
+
/**
|
|
6
|
+
* Contract a component commits to implementing. Hosts use this to decide how
|
|
7
|
+
* to mount the component and what props/events to wire up. Authoring agents
|
|
8
|
+
* use it to target a known shape.
|
|
9
|
+
*/
|
|
10
|
+
export type ComponentRole = 'form' | 'dashboard' | 'widget' | 'report' | 'detail-pane';
|
|
5
11
|
/**
|
|
6
12
|
* Tracks the current change being applied to this component.
|
|
7
13
|
* Populated by Impact Assessor at the start of a modification flow,
|
|
@@ -128,6 +134,20 @@ export declare class ComponentSpec {
|
|
|
128
134
|
* Self-declared type - some common options below, can be any string if the standard ones aren't sufficient
|
|
129
135
|
*/
|
|
130
136
|
type: "report" | "dashboard" | "form" | "table" | "chart" | "navigation" | "search" | string;
|
|
137
|
+
/**
|
|
138
|
+
* Declares the contract this component implements.
|
|
139
|
+
*
|
|
140
|
+
* Distinct from `type` (which is descriptive): `componentRole` is a *commitment* that the
|
|
141
|
+
* component's props, events, and methods conform to a role-specific contract, letting hosts
|
|
142
|
+
* mount it generically and letting authoring agents target a known shape.
|
|
143
|
+
*
|
|
144
|
+
* - `form`: implements `FormHostProps` + standard form events/methods (see `@memberjunction/interactivecomponents/forms`).
|
|
145
|
+
* Hosted by `InteractiveFormComponent` against a `BaseEntity` record.
|
|
146
|
+
* - `dashboard` | `widget` | `report` | `detail-pane`: reserved for future role contracts.
|
|
147
|
+
*
|
|
148
|
+
* Unset = a generic component, mounted directly. No behavior change for existing components.
|
|
149
|
+
*/
|
|
150
|
+
componentRole?: ComponentRole;
|
|
131
151
|
/**
|
|
132
152
|
* JavaScript code
|
|
133
153
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component-spec.d.ts","sourceRoot":"","sources":["../src/component-spec.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"component-spec.d.ts","sourceRoot":"","sources":["../src/component-spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component-spec.js","sourceRoot":"","sources":["../src/component-spec.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"component-spec.js","sourceRoot":"","sources":["../src/component-spec.ts"],"names":[],"mappings":"AAuFA;;GAEG;AACH,MAAM,OAAO,aAAa;CA8LzB;AAAA,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Curated form-relevant view of an entity's metadata.
|
|
3
|
+
*
|
|
4
|
+
* Used in three places:
|
|
5
|
+
* - The `GetEntitySchemaForForm` action, which serves this shape to the
|
|
6
|
+
* Form Builder agent so the LLM has tight, LLM-friendly field info
|
|
7
|
+
* (FKs resolved, value lists annotated, audit/internal fields stripped).
|
|
8
|
+
* - The Component Studio field-binding inspector, which lists these
|
|
9
|
+
* fields in its right-panel sidebar.
|
|
10
|
+
* - The Component Studio fixture-record live preview, which generates
|
|
11
|
+
* type-appropriate sample values per field for the in-progress form.
|
|
12
|
+
*
|
|
13
|
+
* The shape is deliberately tighter than `EntityInfo`/`EntityFieldInfo`:
|
|
14
|
+
* audit fields are out, FK references are resolved to `{entity, displayField}`,
|
|
15
|
+
* value-list fields are normalised to `allowedValues: string[]`, and the
|
|
16
|
+
* type union is narrowed to six LLM-friendly buckets rather than raw SQL
|
|
17
|
+
* type strings.
|
|
18
|
+
*/
|
|
19
|
+
import type { EntityInfo, IMetadataProvider } from '@memberjunction/core';
|
|
20
|
+
/** Foreign-key target info, resolved at curation time. */
|
|
21
|
+
export interface CuratedFormFieldFK {
|
|
22
|
+
/** Display name of the related entity, e.g. "Accounts". */
|
|
23
|
+
entity: string;
|
|
24
|
+
/** The name-field on the related entity, e.g. "Name". May be absent if the related entity has no NameField. */
|
|
25
|
+
displayField?: string;
|
|
26
|
+
}
|
|
27
|
+
/** Normalised type bucket for a form field. */
|
|
28
|
+
export type CuratedFormFieldType = 'string' | 'number' | 'boolean' | 'datetime' | 'enum' | 'foreign-key';
|
|
29
|
+
/** A single field in the curated schema. */
|
|
30
|
+
export interface CuratedFormField {
|
|
31
|
+
/** Database column name, e.g. "AccountID". */
|
|
32
|
+
name: string;
|
|
33
|
+
/** Human-readable label if different from `name`. */
|
|
34
|
+
displayName?: string;
|
|
35
|
+
/** Field description from extended properties / EntityField.Description. */
|
|
36
|
+
description?: string;
|
|
37
|
+
/** Normalised type bucket. */
|
|
38
|
+
type: CuratedFormFieldType;
|
|
39
|
+
/** True iff a user must supply a value when creating a new record. */
|
|
40
|
+
required: boolean;
|
|
41
|
+
/** True iff the field is part of the primary key. */
|
|
42
|
+
isPrimaryKey: boolean;
|
|
43
|
+
/** Maximum string length when `type === 'string'`. */
|
|
44
|
+
maxLength?: number;
|
|
45
|
+
/** Allowed values when `type === 'enum'`. */
|
|
46
|
+
allowedValues?: string[];
|
|
47
|
+
/** FK target when `type === 'foreign-key'`. */
|
|
48
|
+
references?: CuratedFormFieldFK;
|
|
49
|
+
/** Display order from `EntityField.Sequence`. */
|
|
50
|
+
sequence: number;
|
|
51
|
+
}
|
|
52
|
+
/** Curated entity-level schema for form authoring / rendering. */
|
|
53
|
+
export interface CuratedFormSchema {
|
|
54
|
+
/** Fully-qualified entity name, e.g. "MJ: Applications". */
|
|
55
|
+
entityName: string;
|
|
56
|
+
/** Human-readable label, e.g. "Application". */
|
|
57
|
+
displayName: string;
|
|
58
|
+
/** Entity description if available. */
|
|
59
|
+
description?: string;
|
|
60
|
+
/** Name of the field that serves as the record's display label. */
|
|
61
|
+
nameField?: string;
|
|
62
|
+
/** Curated fields, in display order. */
|
|
63
|
+
fields: CuratedFormField[];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Build the curated schema for an entity.
|
|
67
|
+
*
|
|
68
|
+
* Strips fields the form layer shouldn't surface:
|
|
69
|
+
* - `__mj_*` audit columns (CreatedAt / UpdatedAt).
|
|
70
|
+
* - Computed columns (`IsVirtual && IsComputed`) — read-only at the DB level.
|
|
71
|
+
* - Pure view-only columns (`IsVirtual && !IsComputed`) — not writable.
|
|
72
|
+
*
|
|
73
|
+
* Primary-key fields are kept but flagged with `isPrimaryKey`. The form
|
|
74
|
+
* layer uses these for display only; persistence flows through
|
|
75
|
+
* `FormHostProps.primaryKey`.
|
|
76
|
+
*
|
|
77
|
+
* Returns `null` if the entity is not registered with the provider.
|
|
78
|
+
*/
|
|
79
|
+
export declare function buildCuratedFormSchema(entityName: string, provider: IMetadataProvider): CuratedFormSchema | null;
|
|
80
|
+
/**
|
|
81
|
+
* Same as {@link buildCuratedFormSchema} but takes an already-resolved
|
|
82
|
+
* `EntityInfo`. Useful when callers already hold the EntityInfo (e.g.
|
|
83
|
+
* inside `InteractiveFormComponent.rebuildFormHostProps`) and want to
|
|
84
|
+
* skip the second lookup.
|
|
85
|
+
*/
|
|
86
|
+
export declare function curateFromEntityInfo(entity: EntityInfo, provider: IMetadataProvider): CuratedFormSchema;
|
|
87
|
+
//# sourceMappingURL=curated-form-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"curated-form-schema.d.ts","sourceRoot":"","sources":["../../src/forms/curated-form-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAmB,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE3F,0DAA0D;AAC1D,MAAM,WAAW,kBAAkB;IAC/B,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC;IACf,+GAA+G;IAC/G,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,+CAA+C;AAC/C,MAAM,MAAM,oBAAoB,GAC1B,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,UAAU,GACV,MAAM,GACN,aAAa,CAAC;AAEpB,4CAA4C;AAC5C,MAAM,WAAW,gBAAgB;IAC7B,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8BAA8B;IAC9B,IAAI,EAAE,oBAAoB,CAAC;IAC3B,sEAAsE;IACtE,QAAQ,EAAE,OAAO,CAAC;IAClB,qDAAqD;IACrD,YAAY,EAAE,OAAO,CAAC;IACtB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,kEAAkE;AAClE,MAAM,WAAW,iBAAiB;IAC9B,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAClC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,iBAAiB,GAC5B,iBAAiB,GAAG,IAAI,CAM1B;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAChC,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,iBAAiB,GAC5B,iBAAiB,CAanB"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the curated schema for an entity.
|
|
3
|
+
*
|
|
4
|
+
* Strips fields the form layer shouldn't surface:
|
|
5
|
+
* - `__mj_*` audit columns (CreatedAt / UpdatedAt).
|
|
6
|
+
* - Computed columns (`IsVirtual && IsComputed`) — read-only at the DB level.
|
|
7
|
+
* - Pure view-only columns (`IsVirtual && !IsComputed`) — not writable.
|
|
8
|
+
*
|
|
9
|
+
* Primary-key fields are kept but flagged with `isPrimaryKey`. The form
|
|
10
|
+
* layer uses these for display only; persistence flows through
|
|
11
|
+
* `FormHostProps.primaryKey`.
|
|
12
|
+
*
|
|
13
|
+
* Returns `null` if the entity is not registered with the provider.
|
|
14
|
+
*/
|
|
15
|
+
export function buildCuratedFormSchema(entityName, provider) {
|
|
16
|
+
const entity = provider.EntityByName(entityName);
|
|
17
|
+
if (!entity) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
return curateFromEntityInfo(entity, provider);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Same as {@link buildCuratedFormSchema} but takes an already-resolved
|
|
24
|
+
* `EntityInfo`. Useful when callers already hold the EntityInfo (e.g.
|
|
25
|
+
* inside `InteractiveFormComponent.rebuildFormHostProps`) and want to
|
|
26
|
+
* skip the second lookup.
|
|
27
|
+
*/
|
|
28
|
+
export function curateFromEntityInfo(entity, provider) {
|
|
29
|
+
const fields = entity.Fields
|
|
30
|
+
.filter(shouldIncludeField)
|
|
31
|
+
.map(f => curateField(f, provider))
|
|
32
|
+
.sort((a, b) => a.sequence - b.sequence);
|
|
33
|
+
return {
|
|
34
|
+
entityName: entity.Name,
|
|
35
|
+
displayName: entity.DisplayName ?? entity.Name,
|
|
36
|
+
description: entity.Description ?? undefined,
|
|
37
|
+
nameField: entity.NameField?.Name,
|
|
38
|
+
fields,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** Pre-filter: drop audit and non-writable columns. */
|
|
42
|
+
function shouldIncludeField(field) {
|
|
43
|
+
if (field.Name?.startsWith('__mj_')) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
if (field.IsVirtual) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
function curateField(field, provider) {
|
|
52
|
+
const type = inferType(field);
|
|
53
|
+
const required = isRequired(field);
|
|
54
|
+
const out = {
|
|
55
|
+
name: field.Name,
|
|
56
|
+
displayName: field.DisplayName && field.DisplayName !== field.Name ? field.DisplayName : undefined,
|
|
57
|
+
description: field.Description ?? undefined,
|
|
58
|
+
type,
|
|
59
|
+
required,
|
|
60
|
+
isPrimaryKey: !!field.IsPrimaryKey,
|
|
61
|
+
sequence: field.Sequence ?? 0,
|
|
62
|
+
};
|
|
63
|
+
if (type === 'string') {
|
|
64
|
+
const max = field.MaxLength;
|
|
65
|
+
if (max && max > 0) {
|
|
66
|
+
out.maxLength = max;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (type === 'enum') {
|
|
70
|
+
out.allowedValues = field.EntityFieldValues?.map(v => v.Value).filter(Boolean) ?? [];
|
|
71
|
+
}
|
|
72
|
+
if (type === 'foreign-key') {
|
|
73
|
+
out.references = resolveForeignKey(field, provider);
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Map an `EntityFieldInfo` to one of six normalised buckets. Order of checks
|
|
79
|
+
* matters: foreign-key trumps the raw TSType (an FK can be stored as
|
|
80
|
+
* uniqueidentifier and would otherwise look like 'string'), and enum trumps
|
|
81
|
+
* the raw type when the field has a value list.
|
|
82
|
+
*/
|
|
83
|
+
function inferType(field) {
|
|
84
|
+
if (field.RelatedEntity) {
|
|
85
|
+
return 'foreign-key';
|
|
86
|
+
}
|
|
87
|
+
if (field.ValueListType && field.ValueListType !== 'None' &&
|
|
88
|
+
field.EntityFieldValues && field.EntityFieldValues.length > 0) {
|
|
89
|
+
return 'enum';
|
|
90
|
+
}
|
|
91
|
+
switch (field.TSType) {
|
|
92
|
+
case 'number':
|
|
93
|
+
return 'number';
|
|
94
|
+
case 'boolean':
|
|
95
|
+
return 'boolean';
|
|
96
|
+
case 'Date':
|
|
97
|
+
return 'datetime';
|
|
98
|
+
default:
|
|
99
|
+
return 'string';
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A field is "required" for form purposes when the user must supply a value
|
|
104
|
+
* to create the record. PKs are excluded (auto-assigned) and so are fields
|
|
105
|
+
* with database defaults (the DB will fill them).
|
|
106
|
+
*/
|
|
107
|
+
function isRequired(field) {
|
|
108
|
+
if (field.IsPrimaryKey) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
if (field.DefaultValue && field.DefaultValue.length > 0) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
return !field.AllowsNull;
|
|
115
|
+
}
|
|
116
|
+
function resolveForeignKey(field, provider) {
|
|
117
|
+
const targetName = field.RelatedEntity;
|
|
118
|
+
const target = provider.EntityByName(targetName);
|
|
119
|
+
return {
|
|
120
|
+
entity: targetName,
|
|
121
|
+
displayField: target?.NameField?.Name,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=curated-form-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"curated-form-schema.js","sourceRoot":"","sources":["../../src/forms/curated-form-schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default form scaffold builder.
|
|
3
|
+
*
|
|
4
|
+
* Given an entity's curated schema + section/category metadata from CodeGen,
|
|
5
|
+
* produces a working `ComponentSpec` whose JSX mirrors the layout the Angular
|
|
6
|
+
* CodeGen form would render for the same entity. This is the *floor* that
|
|
7
|
+
* agents (Form Builder, Skip) and Form Studio's "New form" flow start from —
|
|
8
|
+
* not the ceiling. Most rich forms transform or replace this aggressively;
|
|
9
|
+
* the scaffold's job is to guarantee day-one parity with the default Angular
|
|
10
|
+
* form so the runtime form path is never worse than the default.
|
|
11
|
+
*
|
|
12
|
+
* The output is intentionally a small, hand-readable JSX function that uses
|
|
13
|
+
* the host-provided `record`, `entityMetadata`, `mode`, and `callbacks`. It
|
|
14
|
+
* does NOT touch BaseEntity, Metadata, or RunView for the record being
|
|
15
|
+
* edited — that's the form-role layering invariant.
|
|
16
|
+
*/
|
|
17
|
+
import type { EntityInfo, IMetadataProvider } from '@memberjunction/core';
|
|
18
|
+
import type { ComponentSpec } from '../component-spec.js';
|
|
19
|
+
/**
|
|
20
|
+
* Build a working scaffold ComponentSpec for `entityName`. Returns `null` if
|
|
21
|
+
* the entity isn't registered.
|
|
22
|
+
*
|
|
23
|
+
* Scaffold rules (mirror CodeGen):
|
|
24
|
+
* - Sections come from `EntityField.Category` + `GeneratedFormSectionType`.
|
|
25
|
+
* - Top-section fields render above the section list.
|
|
26
|
+
* - Field input type derives from `TSType` + `ValueListType` (textarea for
|
|
27
|
+
* long strings, checkbox for booleans, datepicker for dates, select for
|
|
28
|
+
* value lists, fk-picker for FKs, number for numeric).
|
|
29
|
+
* - System Metadata section is always last and starts collapsed.
|
|
30
|
+
* - 2-column grid by default; long-string and textarea fields go full-span.
|
|
31
|
+
*/
|
|
32
|
+
export declare function buildDefaultFormScaffold(entityName: string, provider: IMetadataProvider): ComponentSpec | null;
|
|
33
|
+
/** Same as {@link buildDefaultFormScaffold} but takes an already-resolved EntityInfo. */
|
|
34
|
+
export declare function buildScaffoldFromEntityInfo(entity: EntityInfo, provider: IMetadataProvider): ComponentSpec;
|
|
35
|
+
/** Strip non-identifier characters so the function name is valid JS. */
|
|
36
|
+
export declare function sanitizeComponentName(raw: string): string;
|
|
37
|
+
//# sourceMappingURL=default-form-scaffold.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"default-form-scaffold.d.ts","sourceRoot":"","sources":["../../src/forms/default-form-scaffold.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,UAAU,EAAmB,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAkCvD;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CACpC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,iBAAiB,GAC5B,aAAa,GAAG,IAAI,CAItB;AAED,yFAAyF;AACzF,wBAAgB,2BAA2B,CACvC,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,iBAAiB,GAC5B,aAAa,CAgBf;AA2OD,wEAAwE;AACxE,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIzD"}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { curateFromEntityInfo } from './curated-form-schema.js';
|
|
2
|
+
const DEFAULT_ICON = 'fa-solid fa-circle-info';
|
|
3
|
+
/**
|
|
4
|
+
* Build a working scaffold ComponentSpec for `entityName`. Returns `null` if
|
|
5
|
+
* the entity isn't registered.
|
|
6
|
+
*
|
|
7
|
+
* Scaffold rules (mirror CodeGen):
|
|
8
|
+
* - Sections come from `EntityField.Category` + `GeneratedFormSectionType`.
|
|
9
|
+
* - Top-section fields render above the section list.
|
|
10
|
+
* - Field input type derives from `TSType` + `ValueListType` (textarea for
|
|
11
|
+
* long strings, checkbox for booleans, datepicker for dates, select for
|
|
12
|
+
* value lists, fk-picker for FKs, number for numeric).
|
|
13
|
+
* - System Metadata section is always last and starts collapsed.
|
|
14
|
+
* - 2-column grid by default; long-string and textarea fields go full-span.
|
|
15
|
+
*/
|
|
16
|
+
export function buildDefaultFormScaffold(entityName, provider) {
|
|
17
|
+
const entity = provider.EntityByName(entityName);
|
|
18
|
+
if (!entity)
|
|
19
|
+
return null;
|
|
20
|
+
return buildScaffoldFromEntityInfo(entity, provider);
|
|
21
|
+
}
|
|
22
|
+
/** Same as {@link buildDefaultFormScaffold} but takes an already-resolved EntityInfo. */
|
|
23
|
+
export function buildScaffoldFromEntityInfo(entity, provider) {
|
|
24
|
+
const schema = curateFromEntityInfo(entity, provider);
|
|
25
|
+
const layout = computeSectionLayout(entity, schema);
|
|
26
|
+
const code = renderJsx(entity, schema, layout);
|
|
27
|
+
const name = sanitizeComponentName(`${entity.ClassName || entity.Name}Form`);
|
|
28
|
+
return {
|
|
29
|
+
name,
|
|
30
|
+
title: `${schema.displayName} Form`,
|
|
31
|
+
description: `Default form scaffold for ${schema.displayName}. Mirrors the CodeGen Angular layout. Customize freely.`,
|
|
32
|
+
type: 'Form',
|
|
33
|
+
componentRole: 'form',
|
|
34
|
+
location: 'embedded',
|
|
35
|
+
code,
|
|
36
|
+
functionalRequirements: defaultFunctionalRequirements(schema),
|
|
37
|
+
technicalDesign: defaultTechnicalDesign(schema, layout),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
// ── section / field planning ─────────────────────────────────────────────
|
|
41
|
+
function computeSectionLayout(entity, schema) {
|
|
42
|
+
const sections = new Map();
|
|
43
|
+
// Index for stable ordering: insertion order matches CodeGen behaviour
|
|
44
|
+
// because we walk entity.Fields, which is already sequence-ordered.
|
|
45
|
+
const topFields = [];
|
|
46
|
+
for (const field of entity.Fields) {
|
|
47
|
+
if (!field.IncludeInGeneratedForm)
|
|
48
|
+
continue;
|
|
49
|
+
if (field.Name?.startsWith('__mj_'))
|
|
50
|
+
continue; // audit
|
|
51
|
+
if (field.IsPrimaryKey)
|
|
52
|
+
continue; // PKs not editable in forms
|
|
53
|
+
if (field.IsVirtual)
|
|
54
|
+
continue; // virtual / computed
|
|
55
|
+
const sf = toScaffoldField(field, schema);
|
|
56
|
+
switch (field.GeneratedFormSectionType) {
|
|
57
|
+
case 'Top':
|
|
58
|
+
topFields.push(sf);
|
|
59
|
+
break;
|
|
60
|
+
case 'Category': {
|
|
61
|
+
const cat = (field.Category && field.Category.trim()) || 'Details';
|
|
62
|
+
ensureSection(sections, cat, iconForCategory(cat, entity), false).fields.push(sf);
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
case 'Details':
|
|
66
|
+
default:
|
|
67
|
+
ensureSection(sections, 'Details', 'fa-solid fa-circle-info', false).fields.push(sf);
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// System metadata always last, collapsed by default
|
|
72
|
+
const systemFields = entity.Fields
|
|
73
|
+
.filter(f => f.Name === '__mj_CreatedAt' || f.Name === '__mj_UpdatedAt')
|
|
74
|
+
.map(f => ({
|
|
75
|
+
name: f.Name,
|
|
76
|
+
label: f.DisplayName || f.Name,
|
|
77
|
+
inputType: 'datepicker',
|
|
78
|
+
fullSpan: false,
|
|
79
|
+
readOnly: true,
|
|
80
|
+
}));
|
|
81
|
+
const ordered = [];
|
|
82
|
+
if (topFields.length > 0) {
|
|
83
|
+
ordered.push({ title: '', icon: '', fields: topFields, collapsed: false });
|
|
84
|
+
}
|
|
85
|
+
for (const sect of sections.values()) {
|
|
86
|
+
if (sect.fields.length > 0)
|
|
87
|
+
ordered.push(sect);
|
|
88
|
+
}
|
|
89
|
+
if (systemFields.length > 0) {
|
|
90
|
+
ordered.push({
|
|
91
|
+
title: 'System Metadata',
|
|
92
|
+
icon: 'fa-solid fa-cog',
|
|
93
|
+
fields: systemFields,
|
|
94
|
+
collapsed: true,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return ordered;
|
|
98
|
+
}
|
|
99
|
+
function ensureSection(map, title, icon, collapsed) {
|
|
100
|
+
let s = map.get(title);
|
|
101
|
+
if (!s) {
|
|
102
|
+
s = { title, icon, fields: [], collapsed };
|
|
103
|
+
map.set(title, s);
|
|
104
|
+
}
|
|
105
|
+
return s;
|
|
106
|
+
}
|
|
107
|
+
function toScaffoldField(field, schema) {
|
|
108
|
+
const curated = schema.fields.find(c => c.name === field.Name);
|
|
109
|
+
const label = field.DisplayName && field.DisplayName !== field.Name ? field.DisplayName : field.Name;
|
|
110
|
+
const inputType = pickInputType(field, curated);
|
|
111
|
+
const fullSpan = inputType === 'textarea' || (field.MaxLength && field.MaxLength > 100) || false;
|
|
112
|
+
return {
|
|
113
|
+
name: field.Name,
|
|
114
|
+
label,
|
|
115
|
+
inputType,
|
|
116
|
+
relatedEntity: field.RelatedEntity || undefined,
|
|
117
|
+
allowedValues: curated?.allowedValues,
|
|
118
|
+
fullSpan: !!fullSpan,
|
|
119
|
+
readOnly: !!field.ReadOnly,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function pickInputType(field, curated) {
|
|
123
|
+
// FK takes precedence — FKs may be numeric/uuid but we want a picker.
|
|
124
|
+
if (field.RelatedEntity)
|
|
125
|
+
return 'fk';
|
|
126
|
+
if (curated?.type === 'enum')
|
|
127
|
+
return 'select';
|
|
128
|
+
if (field.ValueListType && field.ValueListType !== 'None')
|
|
129
|
+
return 'select';
|
|
130
|
+
if (field.TSType === 'boolean')
|
|
131
|
+
return 'checkbox';
|
|
132
|
+
if (field.TSType === 'Date')
|
|
133
|
+
return 'datepicker';
|
|
134
|
+
if (field.TSType === 'number')
|
|
135
|
+
return 'number';
|
|
136
|
+
// long strings → textarea
|
|
137
|
+
if ((field.MaxLength ?? 0) < 0 || (field.MaxLength ?? 0) > 1000)
|
|
138
|
+
return 'textarea';
|
|
139
|
+
return 'textbox';
|
|
140
|
+
}
|
|
141
|
+
function iconForCategory(category, _entity) {
|
|
142
|
+
const lower = category.toLowerCase();
|
|
143
|
+
if (/address|location|geo/.test(lower))
|
|
144
|
+
return 'fa-solid fa-map-marker-alt';
|
|
145
|
+
if (/contact|email|phone/.test(lower))
|
|
146
|
+
return 'fa-solid fa-address-card';
|
|
147
|
+
if (/price|cost|payment|financial|billing|invoice/.test(lower))
|
|
148
|
+
return 'fa-solid fa-dollar-sign';
|
|
149
|
+
if (/date|time|schedule|calendar/.test(lower))
|
|
150
|
+
return 'fa-solid fa-calendar';
|
|
151
|
+
if (/status|state|stage|workflow/.test(lower))
|
|
152
|
+
return 'fa-solid fa-flag';
|
|
153
|
+
if (/metadata|technical|system|config/.test(lower))
|
|
154
|
+
return 'fa-solid fa-cog';
|
|
155
|
+
if (/identity|profile|user|account/.test(lower))
|
|
156
|
+
return 'fa-solid fa-fingerprint';
|
|
157
|
+
if (/description|notes|comment|narrative/.test(lower))
|
|
158
|
+
return 'fa-solid fa-align-left';
|
|
159
|
+
return DEFAULT_ICON;
|
|
160
|
+
}
|
|
161
|
+
// ── JSX rendering ────────────────────────────────────────────────────────
|
|
162
|
+
function renderJsx(entity, schema, layout) {
|
|
163
|
+
const componentName = sanitizeComponentName(`${entity.ClassName || entity.Name}Form`);
|
|
164
|
+
const renderField = (f, indent) => {
|
|
165
|
+
const span = f.fullSpan ? ' span={2}' : '';
|
|
166
|
+
const readOnly = f.readOnly ? ' readOnly' : '';
|
|
167
|
+
// The scaffold uses host-provided primitives we register in the
|
|
168
|
+
// harness. The agent or user can swap these for arbitrary JSX.
|
|
169
|
+
return `${indent}<Field name="${f.name}" label="${escapeJsx(f.label)}"${span}${readOnly} />`;
|
|
170
|
+
};
|
|
171
|
+
const renderSection = (s, indent) => {
|
|
172
|
+
if (!s.title) {
|
|
173
|
+
// top-area fields render bare
|
|
174
|
+
return s.fields.map(f => renderField(f, indent)).join('\n');
|
|
175
|
+
}
|
|
176
|
+
const grid = s.fields.map(f => renderField(f, `${indent} `)).join('\n');
|
|
177
|
+
return [
|
|
178
|
+
`${indent}<Section title="${escapeJsx(s.title)}" icon="${s.icon}"${s.collapsed ? ' defaultCollapsed' : ''}>`,
|
|
179
|
+
`${indent} <Grid columns={2}>`,
|
|
180
|
+
grid,
|
|
181
|
+
`${indent} </Grid>`,
|
|
182
|
+
`${indent}</Section>`,
|
|
183
|
+
].join('\n');
|
|
184
|
+
};
|
|
185
|
+
const body = layout.map(s => renderSection(s, ' ')).join('\n\n');
|
|
186
|
+
return `function ${componentName}(props) {
|
|
187
|
+
// FormHostProps — see @memberjunction/interactive-component-types/forms
|
|
188
|
+
const { record, entityMetadata, mode, canEdit, canDelete, canCreate, callbacks, utilities } = props;
|
|
189
|
+
|
|
190
|
+
// Local edit state. Saves flow through callbacks.NotifyEvent('BeforeSave', { dirtyFields });
|
|
191
|
+
// the wrapper applies dirtyFields to its BaseEntity and persists.
|
|
192
|
+
const [draft, setDraft] = React.useState(record || {});
|
|
193
|
+
const [dirtyFields, setDirty] = React.useState({});
|
|
194
|
+
|
|
195
|
+
// Re-flow when host pushes a new record (after save, after mode change, etc.)
|
|
196
|
+
React.useEffect(() => {
|
|
197
|
+
if (record) {
|
|
198
|
+
setDraft(record);
|
|
199
|
+
setDirty({});
|
|
200
|
+
}
|
|
201
|
+
}, [record]);
|
|
202
|
+
|
|
203
|
+
// Toolbar contract: the host's record-form-container has Save / Cancel buttons.
|
|
204
|
+
// Register methods so those buttons drive our save flow.
|
|
205
|
+
React.useEffect(() => {
|
|
206
|
+
if (!callbacks?.RegisterMethod) return;
|
|
207
|
+
callbacks.RegisterMethod('RequestSave', () => {
|
|
208
|
+
callbacks.NotifyEvent('BeforeSave', { dirtyFields, cancel: false });
|
|
209
|
+
});
|
|
210
|
+
callbacks.RegisterMethod('RequestCancel', () => {
|
|
211
|
+
setDraft(record || {});
|
|
212
|
+
setDirty({});
|
|
213
|
+
});
|
|
214
|
+
}, [callbacks, dirtyFields, record]);
|
|
215
|
+
|
|
216
|
+
const onField = (name, value) => {
|
|
217
|
+
setDraft(d => ({ ...d, [name]: value }));
|
|
218
|
+
setDirty(d => ({ ...d, [name]: value }));
|
|
219
|
+
callbacks?.NotifyEvent?.('FieldChanged', { fieldName: name, value });
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// Convenience: pass everything needed by the registered <Field> primitive.
|
|
223
|
+
const Field = ({ name, label, span, readOnly }) => {
|
|
224
|
+
const fieldMeta = entityMetadata?.fields?.find(x => x.name === name);
|
|
225
|
+
return utilities.components.FormField({
|
|
226
|
+
name, label, span, readOnly: readOnly || !canEdit || mode === 'view',
|
|
227
|
+
value: draft?.[name],
|
|
228
|
+
onChange: onField,
|
|
229
|
+
field: fieldMeta,
|
|
230
|
+
});
|
|
231
|
+
};
|
|
232
|
+
const Section = utilities.components.FormSection;
|
|
233
|
+
const Grid = utilities.components.FormGrid;
|
|
234
|
+
|
|
235
|
+
return (
|
|
236
|
+
<div className="mj-form" data-entity="${escapeJsx(schema.entityName)}">
|
|
237
|
+
${body || ' {/* no fields visible — entity has no IncludeInGeneratedForm fields */}'}
|
|
238
|
+
</div>
|
|
239
|
+
);
|
|
240
|
+
}`;
|
|
241
|
+
}
|
|
242
|
+
function defaultFunctionalRequirements(schema) {
|
|
243
|
+
return [
|
|
244
|
+
`Default form for ${schema.displayName}.`,
|
|
245
|
+
'',
|
|
246
|
+
`Renders all editable fields for the entity in the layout defined by EntityField metadata`,
|
|
247
|
+
`(Category, GeneratedFormSectionType, Sequence). Mirrors the Angular CodeGen form so the`,
|
|
248
|
+
`runtime form path achieves day-one parity with the default Angular form.`,
|
|
249
|
+
'',
|
|
250
|
+
'Supports view, edit, and create modes. Emits BeforeSave with dirty-field deltas.',
|
|
251
|
+
].join('\n');
|
|
252
|
+
}
|
|
253
|
+
function defaultTechnicalDesign(schema, layout) {
|
|
254
|
+
return [
|
|
255
|
+
`Bound to entity '${schema.entityName}'.`,
|
|
256
|
+
'',
|
|
257
|
+
'Layout:',
|
|
258
|
+
...layout.map(s => s.title
|
|
259
|
+
? ` - ${s.title} (${s.fields.length} field${s.fields.length === 1 ? '' : 's'}${s.collapsed ? ', collapsed by default' : ''})`
|
|
260
|
+
: ` - [Top area] (${s.fields.length} field${s.fields.length === 1 ? '' : 's'})`),
|
|
261
|
+
'',
|
|
262
|
+
'Host contract:',
|
|
263
|
+
' - FormHostProps.record is the live snapshot from BaseEntity.',
|
|
264
|
+
' - callbacks.NotifyEvent(\'BeforeSave\', { dirtyFields }) commits.',
|
|
265
|
+
' - RegisterMethod(\'RequestSave\') / (\'RequestCancel\') hook into the host toolbar.',
|
|
266
|
+
].join('\n');
|
|
267
|
+
}
|
|
268
|
+
/** Strip non-identifier characters so the function name is valid JS. */
|
|
269
|
+
export function sanitizeComponentName(raw) {
|
|
270
|
+
const cleaned = raw.replace(/[^A-Za-z0-9_]/g, '');
|
|
271
|
+
if (!cleaned || /^\d/.test(cleaned))
|
|
272
|
+
return `Form_${cleaned || 'Component'}`;
|
|
273
|
+
return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
|
|
274
|
+
}
|
|
275
|
+
function escapeJsx(s) {
|
|
276
|
+
return s.replace(/"/g, '"');
|
|
277
|
+
}
|
|
278
|
+
//# sourceMappingURL=default-form-scaffold.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"default-form-scaffold.js","sourceRoot":"","sources":["../../src/forms/default-form-scaffold.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard event names for components that declare `componentRole: 'form'`.
|
|
3
|
+
*
|
|
4
|
+
* The host (`InteractiveFormComponent` on the Angular side) listens for these
|
|
5
|
+
* events on the React component via the existing `NotifyEvent` callback and
|
|
6
|
+
* the cancelable/paired event infrastructure in `component-events.ts`.
|
|
7
|
+
*
|
|
8
|
+
* Every name is exported as a `const` so authoring agents and component code
|
|
9
|
+
* can reference the same string without typos.
|
|
10
|
+
*/
|
|
11
|
+
import type { CancelableEventArgs, AfterEventArgs, BaseEventArgs } from '../component-events.js';
|
|
12
|
+
export declare const FormEventNames: {
|
|
13
|
+
/** Cancelable. Host requests save. Component emits with the dirty-field diff. */
|
|
14
|
+
readonly BeforeSave: "BeforeSave";
|
|
15
|
+
/** Reports save outcome. Paired with BeforeSave. */
|
|
16
|
+
readonly AfterSave: "AfterSave";
|
|
17
|
+
/** Cancelable. Host requests delete. */
|
|
18
|
+
readonly BeforeDelete: "BeforeDelete";
|
|
19
|
+
/** Reports delete outcome. Paired with BeforeDelete. */
|
|
20
|
+
readonly AfterDelete: "AfterDelete";
|
|
21
|
+
/** Cancelable. Form asks host (or vice versa) to switch between view/edit. */
|
|
22
|
+
readonly EditModeChangeRequested: "EditModeChangeRequested";
|
|
23
|
+
/** Reports a single field change. Drives dirty tracking on the host. */
|
|
24
|
+
readonly FieldChanged: "FieldChanged";
|
|
25
|
+
/** Reports dirty state transitions. */
|
|
26
|
+
readonly DirtyStateChanged: "DirtyStateChanged";
|
|
27
|
+
/** Reports validity transitions. */
|
|
28
|
+
readonly ValidationChanged: "ValidationChanged";
|
|
29
|
+
};
|
|
30
|
+
export type FormEventName = typeof FormEventNames[keyof typeof FormEventNames];
|
|
31
|
+
/** Args for `BeforeSave`. Component fills `dirtyFields` with the typed diff. */
|
|
32
|
+
export interface FormBeforeSaveArgs extends CancelableEventArgs {
|
|
33
|
+
dirtyFields: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
/** Args for `AfterSave`. */
|
|
36
|
+
export interface FormAfterSaveArgs extends AfterEventArgs {
|
|
37
|
+
/** Optional: the saved record snapshot (post-save server values). */
|
|
38
|
+
record?: Record<string, unknown>;
|
|
39
|
+
}
|
|
40
|
+
/** Args for `BeforeDelete`. No payload beyond the cancel flag. */
|
|
41
|
+
export type FormBeforeDeleteArgs = CancelableEventArgs;
|
|
42
|
+
/** Args for `AfterDelete`. */
|
|
43
|
+
export type FormAfterDeleteArgs = AfterEventArgs;
|
|
44
|
+
/** Args for `EditModeChangeRequested`. */
|
|
45
|
+
export interface FormEditModeChangeRequestedArgs extends CancelableEventArgs {
|
|
46
|
+
requestedMode: 'view' | 'edit';
|
|
47
|
+
}
|
|
48
|
+
/** Args for `FieldChanged`. */
|
|
49
|
+
export interface FormFieldChangedArgs extends BaseEventArgs {
|
|
50
|
+
fieldName: string;
|
|
51
|
+
oldValue: unknown;
|
|
52
|
+
newValue: unknown;
|
|
53
|
+
}
|
|
54
|
+
/** Args for `DirtyStateChanged`. */
|
|
55
|
+
export interface FormDirtyStateChangedArgs extends BaseEventArgs {
|
|
56
|
+
isDirty: boolean;
|
|
57
|
+
dirtyFieldCount: number;
|
|
58
|
+
}
|
|
59
|
+
/** Args for `ValidationChanged`. */
|
|
60
|
+
export interface FormValidationChangedArgs extends BaseEventArgs {
|
|
61
|
+
isValid: boolean;
|
|
62
|
+
errors?: string[];
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=form-event-names.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-event-names.d.ts","sourceRoot":"","sources":["../../src/forms/form-event-names.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE9F,eAAO,MAAM,cAAc;IACvB,iFAAiF;;IAEjF,oDAAoD;;IAEpD,wCAAwC;;IAExC,wDAAwD;;IAExD,8EAA8E;;IAE9E,wEAAwE;;IAExE,uCAAuC;;IAEvC,oCAAoC;;CAE9B,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,OAAO,cAAc,CAAC,MAAM,OAAO,cAAc,CAAC,CAAC;AAE/E,gFAAgF;AAChF,MAAM,WAAW,kBAAmB,SAAQ,mBAAmB;IAC3D,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED,4BAA4B;AAC5B,MAAM,WAAW,iBAAkB,SAAQ,cAAc;IACrD,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,kEAAkE;AAClE,MAAM,MAAM,oBAAoB,GAAG,mBAAmB,CAAC;AAEvD,8BAA8B;AAC9B,MAAM,MAAM,mBAAmB,GAAG,cAAc,CAAC;AAEjD,0CAA0C;AAC1C,MAAM,WAAW,+BAAgC,SAAQ,mBAAmB;IACxE,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC;CAClC;AAED,+BAA+B;AAC/B,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IACvD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACrB;AAED,oCAAoC;AACpC,MAAM,WAAW,yBAA0B,SAAQ,aAAa;IAC5D,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CAC3B;AAED,oCAAoC;AACpC,MAAM,WAAW,yBAA0B,SAAQ,aAAa;IAC5D,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard event names for components that declare `componentRole: 'form'`.
|
|
3
|
+
*
|
|
4
|
+
* The host (`InteractiveFormComponent` on the Angular side) listens for these
|
|
5
|
+
* events on the React component via the existing `NotifyEvent` callback and
|
|
6
|
+
* the cancelable/paired event infrastructure in `component-events.ts`.
|
|
7
|
+
*
|
|
8
|
+
* Every name is exported as a `const` so authoring agents and component code
|
|
9
|
+
* can reference the same string without typos.
|
|
10
|
+
*/
|
|
11
|
+
export const FormEventNames = {
|
|
12
|
+
/** Cancelable. Host requests save. Component emits with the dirty-field diff. */
|
|
13
|
+
BeforeSave: 'BeforeSave',
|
|
14
|
+
/** Reports save outcome. Paired with BeforeSave. */
|
|
15
|
+
AfterSave: 'AfterSave',
|
|
16
|
+
/** Cancelable. Host requests delete. */
|
|
17
|
+
BeforeDelete: 'BeforeDelete',
|
|
18
|
+
/** Reports delete outcome. Paired with BeforeDelete. */
|
|
19
|
+
AfterDelete: 'AfterDelete',
|
|
20
|
+
/** Cancelable. Form asks host (or vice versa) to switch between view/edit. */
|
|
21
|
+
EditModeChangeRequested: 'EditModeChangeRequested',
|
|
22
|
+
/** Reports a single field change. Drives dirty tracking on the host. */
|
|
23
|
+
FieldChanged: 'FieldChanged',
|
|
24
|
+
/** Reports dirty state transitions. */
|
|
25
|
+
DirtyStateChanged: 'DirtyStateChanged',
|
|
26
|
+
/** Reports validity transitions. */
|
|
27
|
+
ValidationChanged: 'ValidationChanged',
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=form-event-names.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-event-names.js","sourceRoot":"","sources":["../../src/forms/form-event-names.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC1B,iFAAiF;IACjF,UAAU,EAAE,YAAY;IACxB,oDAAoD;IACpD,SAAS,EAAE,WAAW;IACtB,wCAAwC;IACxC,YAAY,EAAE,cAAc;IAC5B,wDAAwD;IACxD,WAAW,EAAE,aAAa;IAC1B,8EAA8E;IAC9E,uBAAuB,EAAE,yBAAyB;IAClD,wEAAwE;IACxE,YAAY,EAAE,cAAc;IAC5B,uCAAuC;IACvC,iBAAiB,EAAE,mBAAmB;IACtC,oCAAoC;IACpC,iBAAiB,EAAE,mBAAmB;CAChC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixture `FormHostProps` builder. Renders a form-role component against
|
|
3
|
+
* synthetic, type-appropriate data when no real BaseEntity is available —
|
|
4
|
+
* used by:
|
|
5
|
+
* - Component Studio's live preview (designing a form before any record exists)
|
|
6
|
+
* - The chat artifact viewer when the spec's declared entity is unknown,
|
|
7
|
+
* unresolvable, or has no rows yet
|
|
8
|
+
*
|
|
9
|
+
* Field-value rules (kept small + deterministic so the preview is stable
|
|
10
|
+
* across re-renders):
|
|
11
|
+
* string → "Sample <FieldName>"
|
|
12
|
+
* string with maxLength <= 24 → "Sample"
|
|
13
|
+
* number → 42
|
|
14
|
+
* boolean → true
|
|
15
|
+
* datetime → today, ISO format
|
|
16
|
+
* enum → allowedValues[0]
|
|
17
|
+
* foreign-key → { ID: STABLE_FK_UUID, <displayField>: "Sample <TargetEntity>" }
|
|
18
|
+
* primary key → STABLE_FIXTURE_UUID
|
|
19
|
+
*/
|
|
20
|
+
import type { CuratedFormSchema } from './curated-form-schema.js';
|
|
21
|
+
import type { FormHostProps, FormMode } from './form-host-props.js';
|
|
22
|
+
export declare function buildFixtureFormHostProps(schema: CuratedFormSchema, mode?: FormMode): FormHostProps;
|
|
23
|
+
//# sourceMappingURL=form-host-props-fixture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-host-props-fixture.d.ts","sourceRoot":"","sources":["../../src/forms/form-host-props-fixture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAoB,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACjF,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGjE,wBAAgB,yBAAyB,CACrC,MAAM,EAAE,iBAAiB,EACzB,IAAI,GAAE,QAAiB,GACxB,aAAa,CAyBf"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export function buildFixtureFormHostProps(schema, mode = 'view') {
|
|
2
|
+
const record = {};
|
|
3
|
+
for (const f of schema.fields) {
|
|
4
|
+
record[f.name] = fixtureValue(f);
|
|
5
|
+
}
|
|
6
|
+
const primaryKeyFields = schema.fields.filter(f => f.isPrimaryKey);
|
|
7
|
+
const primaryKey = mode === 'create' || primaryKeyFields.length === 0
|
|
8
|
+
? null
|
|
9
|
+
: Object.fromEntries(primaryKeyFields.map(f => [f.name, record[f.name]]));
|
|
10
|
+
return {
|
|
11
|
+
entityName: schema.entityName,
|
|
12
|
+
primaryKey,
|
|
13
|
+
record,
|
|
14
|
+
entityMetadata: {
|
|
15
|
+
fields: schemaFieldsToSimple(schema),
|
|
16
|
+
displayName: schema.displayName,
|
|
17
|
+
nameField: schema.nameField,
|
|
18
|
+
},
|
|
19
|
+
mode,
|
|
20
|
+
canEdit: true,
|
|
21
|
+
canDelete: true,
|
|
22
|
+
canCreate: true,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** Convert curated fields to the minimal SimpleEntityFieldInfo shape FormHostProps needs. */
|
|
26
|
+
function schemaFieldsToSimple(schema) {
|
|
27
|
+
return schema.fields.map(f => ({
|
|
28
|
+
name: f.name,
|
|
29
|
+
sequence: f.sequence,
|
|
30
|
+
defaultInView: !f.isPrimaryKey,
|
|
31
|
+
type: f.type,
|
|
32
|
+
allowsNull: !f.required,
|
|
33
|
+
isPrimaryKey: f.isPrimaryKey,
|
|
34
|
+
possibleValues: f.allowedValues,
|
|
35
|
+
description: f.description,
|
|
36
|
+
// SimpleEntityFieldInfo is a class; we cast to the structural shape
|
|
37
|
+
// — the React component doesn't call methods on it, only reads.
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
function fixtureValue(f) {
|
|
41
|
+
if (f.isPrimaryKey) {
|
|
42
|
+
return STABLE_FIXTURE_ID;
|
|
43
|
+
}
|
|
44
|
+
switch (f.type) {
|
|
45
|
+
case 'number':
|
|
46
|
+
return 42;
|
|
47
|
+
case 'boolean':
|
|
48
|
+
return true;
|
|
49
|
+
case 'datetime':
|
|
50
|
+
return new Date().toISOString();
|
|
51
|
+
case 'enum':
|
|
52
|
+
return f.allowedValues?.[0] ?? null;
|
|
53
|
+
case 'foreign-key': {
|
|
54
|
+
const targetEntity = f.references?.entity ?? 'Related';
|
|
55
|
+
const displayField = f.references?.displayField ?? 'Name';
|
|
56
|
+
return {
|
|
57
|
+
ID: STABLE_FIXTURE_FK_ID,
|
|
58
|
+
[displayField]: `Sample ${targetEntity.replace(/^MJ:\s*/, '')}`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
case 'string':
|
|
62
|
+
default: {
|
|
63
|
+
const max = f.maxLength ?? 0;
|
|
64
|
+
if (max > 0 && max <= 24) {
|
|
65
|
+
return 'Sample';
|
|
66
|
+
}
|
|
67
|
+
return `Sample ${f.displayName ?? f.name}`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/** Stable fake UUIDs so re-renders don't churn React component identity. */
|
|
72
|
+
const STABLE_FIXTURE_ID = '00000000-0000-0000-0000-000000000001';
|
|
73
|
+
const STABLE_FIXTURE_FK_ID = '00000000-0000-0000-0000-000000000002';
|
|
74
|
+
//# sourceMappingURL=form-host-props-fixture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-host-props-fixture.js","sourceRoot":"","sources":["../../src/forms/form-host-props-fixture.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Props the host (`InteractiveFormComponent`) passes to a form-role component.
|
|
3
|
+
*
|
|
4
|
+
* The React side never touches `BaseEntity` — it operates against this plain
|
|
5
|
+
* snapshot. When the form needs to commit, it fires `BeforeSave` with the
|
|
6
|
+
* dirty-field diff and the host applies that to the BaseEntity and calls
|
|
7
|
+
* `record.Save()`. This keeps the React contract portable and avoids the
|
|
8
|
+
* `.Set()` stringly-typed trap.
|
|
9
|
+
*/
|
|
10
|
+
import { SimpleEntityFieldInfo } from '../data-requirements.js';
|
|
11
|
+
/** Mode the form is currently rendered in. */
|
|
12
|
+
export type FormMode = 'view' | 'edit' | 'create';
|
|
13
|
+
/** Subset of the entity's metadata the form needs at render time. */
|
|
14
|
+
export interface FormEntityMetadata {
|
|
15
|
+
/** Field list, simplified (plain objects, no BaseEntity methods). */
|
|
16
|
+
fields: SimpleEntityFieldInfo[];
|
|
17
|
+
/** Human-readable name of the entity (e.g. "Customer"). */
|
|
18
|
+
displayName: string;
|
|
19
|
+
/** Optional: the field used as the record's display name (e.g. "Name", "Title"). */
|
|
20
|
+
nameField?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Props passed to every form-role component. Plain data, no instance methods.
|
|
24
|
+
*
|
|
25
|
+
* `primaryKey` is serialized as a plain object — the React side does not need
|
|
26
|
+
* the `CompositeKey` class; the Angular wrapper reconstructs one when it has to
|
|
27
|
+
* load or save. `null` indicates a not-yet-persisted record (create flow).
|
|
28
|
+
*/
|
|
29
|
+
export interface FormHostProps {
|
|
30
|
+
entityName: string;
|
|
31
|
+
/** Composite-key field values as a plain object, or `null` for new records. */
|
|
32
|
+
primaryKey: Record<string, unknown> | null;
|
|
33
|
+
/** Plain snapshot of the record (BaseEntity.GetAll() result). */
|
|
34
|
+
record: Record<string, unknown>;
|
|
35
|
+
entityMetadata: FormEntityMetadata;
|
|
36
|
+
mode: FormMode;
|
|
37
|
+
canEdit: boolean;
|
|
38
|
+
canDelete: boolean;
|
|
39
|
+
canCreate: boolean;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=form-host-props.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-host-props.d.ts","sourceRoot":"","sources":["../../src/forms/form-host-props.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,8CAA8C;AAC9C,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;AAElD,qEAAqE;AACrE,MAAM,WAAW,kBAAkB;IAC/B,qEAAqE;IACrE,MAAM,EAAE,qBAAqB,EAAE,CAAC;IAChC,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC3C,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,cAAc,EAAE,kBAAkB,CAAC;IACnC,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;CACtB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Props the host (`InteractiveFormComponent`) passes to a form-role component.
|
|
3
|
+
*
|
|
4
|
+
* The React side never touches `BaseEntity` — it operates against this plain
|
|
5
|
+
* snapshot. When the form needs to commit, it fires `BeforeSave` with the
|
|
6
|
+
* dirty-field diff and the host applies that to the BaseEntity and calls
|
|
7
|
+
* `record.Save()`. This keeps the React contract portable and avoids the
|
|
8
|
+
* `.Set()` stringly-typed trap.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=form-host-props.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-host-props.js","sourceRoot":"","sources":["../../src/forms/form-host-props.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard method names a form-role component registers with the host via
|
|
3
|
+
* `RegisterMethod`. The host (`InteractiveFormComponent`) invokes these in
|
|
4
|
+
* response to toolbar actions, sidebar updates, etc.
|
|
5
|
+
*
|
|
6
|
+
* Components don't have to implement every method — `RequestSave` and
|
|
7
|
+
* `RequestCancel` are the minimum useful set.
|
|
8
|
+
*/
|
|
9
|
+
export declare const FormMethodNames: {
|
|
10
|
+
/** Host (toolbar) asks the form to start its save flow. Form fires `BeforeSave`. */
|
|
11
|
+
readonly RequestSave: "RequestSave";
|
|
12
|
+
/** Discard edits. Form fires `EditModeChangeRequested` → 'view'. */
|
|
13
|
+
readonly RequestCancel: "RequestCancel";
|
|
14
|
+
/** Host pushes a mode change (e.g. entered edit via the toolbar). */
|
|
15
|
+
readonly SetEditMode: "SetEditMode";
|
|
16
|
+
/** Host pulls a single field value (used by related panels). */
|
|
17
|
+
readonly GetFieldValue: "GetFieldValue";
|
|
18
|
+
/** Host pushes a single field value (used by sidebars / related panels). */
|
|
19
|
+
readonly SetFieldValue: "SetFieldValue";
|
|
20
|
+
};
|
|
21
|
+
export type FormMethodName = typeof FormMethodNames[keyof typeof FormMethodNames];
|
|
22
|
+
/** Signature for the `SetEditMode` method. */
|
|
23
|
+
export type FormSetEditModeArgs = {
|
|
24
|
+
mode: 'view' | 'edit';
|
|
25
|
+
};
|
|
26
|
+
/** Signature for the `GetFieldValue` method. */
|
|
27
|
+
export type FormGetFieldValueArgs = {
|
|
28
|
+
fieldName: string;
|
|
29
|
+
};
|
|
30
|
+
/** Signature for the `SetFieldValue` method. */
|
|
31
|
+
export type FormSetFieldValueArgs = {
|
|
32
|
+
fieldName: string;
|
|
33
|
+
value: unknown;
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=form-method-names.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-method-names.d.ts","sourceRoot":"","sources":["../../src/forms/form-method-names.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,eAAO,MAAM,eAAe;IACxB,oFAAoF;;IAEpF,oEAAoE;;IAEpE,qEAAqE;;IAErE,gEAAgE;;IAEhE,4EAA4E;;CAEtE,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,OAAO,eAAe,CAAC,MAAM,OAAO,eAAe,CAAC,CAAC;AAElF,8CAA8C;AAC9C,MAAM,MAAM,mBAAmB,GAAG;IAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC;AAE5D,gDAAgD;AAChD,MAAM,MAAM,qBAAqB,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D,gDAAgD;AAChD,MAAM,MAAM,qBAAqB,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard method names a form-role component registers with the host via
|
|
3
|
+
* `RegisterMethod`. The host (`InteractiveFormComponent`) invokes these in
|
|
4
|
+
* response to toolbar actions, sidebar updates, etc.
|
|
5
|
+
*
|
|
6
|
+
* Components don't have to implement every method — `RequestSave` and
|
|
7
|
+
* `RequestCancel` are the minimum useful set.
|
|
8
|
+
*/
|
|
9
|
+
export const FormMethodNames = {
|
|
10
|
+
/** Host (toolbar) asks the form to start its save flow. Form fires `BeforeSave`. */
|
|
11
|
+
RequestSave: 'RequestSave',
|
|
12
|
+
/** Discard edits. Form fires `EditModeChangeRequested` → 'view'. */
|
|
13
|
+
RequestCancel: 'RequestCancel',
|
|
14
|
+
/** Host pushes a mode change (e.g. entered edit via the toolbar). */
|
|
15
|
+
SetEditMode: 'SetEditMode',
|
|
16
|
+
/** Host pulls a single field value (used by related panels). */
|
|
17
|
+
GetFieldValue: 'GetFieldValue',
|
|
18
|
+
/** Host pushes a single field value (used by sidebars / related panels). */
|
|
19
|
+
SetFieldValue: 'SetFieldValue',
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=form-method-names.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-method-names.js","sourceRoot":"","sources":["../../src/forms/form-method-names.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC3B,oFAAoF;IACpF,WAAW,EAAE,aAAa;IAC1B,oEAAoE;IACpE,aAAa,EAAE,eAAe;IAC9B,qEAAqE;IACrE,WAAW,EAAE,aAAa;IAC1B,gEAAgE;IAChE,aAAa,EAAE,eAAe;IAC9B,4EAA4E;IAC5E,aAAa,EAAE,eAAe;CACxB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Small pure helpers for extracting form-binding info from a `ComponentSpec`.
|
|
3
|
+
*
|
|
4
|
+
* The artifact viewer's form-aware branch and the Form Builder dashboard
|
|
5
|
+
* both need to answer "which entity does this form bind to?" — the answer
|
|
6
|
+
* lives in either `spec.entityName` (explicit) or
|
|
7
|
+
* `spec.dataRequirements.entities[0].name` (inferred). Centralizing the
|
|
8
|
+
* resolution rule here means both surfaces produce the same answer and a
|
|
9
|
+
* spec author only has to learn one convention.
|
|
10
|
+
*/
|
|
11
|
+
import type { ComponentSpec } from '../component-spec.js';
|
|
12
|
+
/**
|
|
13
|
+
* Resolve the entity the form binds to.
|
|
14
|
+
*
|
|
15
|
+
* Lookup order:
|
|
16
|
+
* 1. `spec.entityName` if set (trimmed; empty strings → null)
|
|
17
|
+
* 2. `spec.dataRequirements.entities[0].name` if present
|
|
18
|
+
* 3. `null` — caller decides whether to fall back to a fixture or warn
|
|
19
|
+
*/
|
|
20
|
+
export declare function getDeclaredFormEntityName(spec: (ComponentSpec & {
|
|
21
|
+
entityName?: unknown;
|
|
22
|
+
}) | null | undefined): string | null;
|
|
23
|
+
//# sourceMappingURL=form-spec-info.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-spec-info.d.ts","sourceRoot":"","sources":["../../src/forms/form-spec-info.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAIrC,IAAI,EAAE,CAAC,aAAa,GAAG;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GAAG,IAAI,GAAG,SAAS,GACpE,MAAM,GAAG,IAAI,CAYf"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the entity the form binds to.
|
|
3
|
+
*
|
|
4
|
+
* Lookup order:
|
|
5
|
+
* 1. `spec.entityName` if set (trimmed; empty strings → null)
|
|
6
|
+
* 2. `spec.dataRequirements.entities[0].name` if present
|
|
7
|
+
* 3. `null` — caller decides whether to fall back to a fixture or warn
|
|
8
|
+
*/
|
|
9
|
+
export function getDeclaredFormEntityName(
|
|
10
|
+
// `entityName` isn't a typed ComponentSpec field — it's an extension some
|
|
11
|
+
// specs carry. Use a structural input that allows it without breaking on
|
|
12
|
+
// strict-mode Pick<>.
|
|
13
|
+
spec) {
|
|
14
|
+
if (!spec)
|
|
15
|
+
return null;
|
|
16
|
+
const direct = spec.entityName;
|
|
17
|
+
if (typeof direct === 'string' && direct.trim().length > 0) {
|
|
18
|
+
return direct.trim();
|
|
19
|
+
}
|
|
20
|
+
const dr = spec.dataRequirements;
|
|
21
|
+
const first = dr?.entities?.[0]?.name;
|
|
22
|
+
if (typeof first === 'string' && first.trim().length > 0) {
|
|
23
|
+
return first.trim();
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=form-spec-info.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-spec-info.js","sourceRoot":"","sources":["../../src/forms/form-spec-info.ts"],"names":[],"mappings":"AAYA;;;;;;;GAOG;AACH,MAAM,UAAU,yBAAyB;AACrC,0EAA0E;AAC1E,yEAAyE;AACzE,sBAAsB;AACtB,IAAmE;IAEnE,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,MAAM,GAAI,IAA4C,CAAC,UAAU,CAAC;IACxE,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzD,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;IACzB,CAAC;IACD,MAAM,EAAE,GAAG,IAAI,CAAC,gBAAmF,CAAC;IACpG,MAAM,KAAK,GAAG,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;IACtC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvD,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Form-role contract for components that declare `componentRole: 'form'`.
|
|
3
|
+
*
|
|
4
|
+
* Three small pieces, kept on a subpath so the generic IC package stays clean:
|
|
5
|
+
* - `FormHostProps` — what the host passes the component
|
|
6
|
+
* - `FormEventNames` + typed arg interfaces — events the component emits
|
|
7
|
+
* - `FormMethodNames` + arg types — methods the component registers
|
|
8
|
+
*
|
|
9
|
+
* Hand-written, Studio-built, and agent-generated form components all target
|
|
10
|
+
* this contract. Import via the subpath:
|
|
11
|
+
*
|
|
12
|
+
* import { FormHostProps, FormEventNames, FormMethodNames }
|
|
13
|
+
* from '@memberjunction/interactive-component-types/forms';
|
|
14
|
+
*
|
|
15
|
+
* Note: this is the npm package name — the plan doc shorthands it as
|
|
16
|
+
* `@memberjunction/interactivecomponents`, which is the directory name, not
|
|
17
|
+
* the published name.
|
|
18
|
+
*/
|
|
19
|
+
export * from './form-host-props.js';
|
|
20
|
+
export * from './form-event-names.js';
|
|
21
|
+
export * from './form-method-names.js';
|
|
22
|
+
export * from './curated-form-schema.js';
|
|
23
|
+
export * from './default-form-scaffold.js';
|
|
24
|
+
export * from './form-host-props-fixture.js';
|
|
25
|
+
export * from './form-spec-info.js';
|
|
26
|
+
import type { ComponentSpec } from '../component-spec.js';
|
|
27
|
+
/** True iff the spec commits to the form-role contract. */
|
|
28
|
+
export declare function isFormRole(spec: Pick<ComponentSpec, 'componentRole'>): boolean;
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/forms/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AAEjC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,2DAA2D;AAC3D,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,eAAe,CAAC,GAAG,OAAO,CAE9E"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Form-role contract for components that declare `componentRole: 'form'`.
|
|
3
|
+
*
|
|
4
|
+
* Three small pieces, kept on a subpath so the generic IC package stays clean:
|
|
5
|
+
* - `FormHostProps` — what the host passes the component
|
|
6
|
+
* - `FormEventNames` + typed arg interfaces — events the component emits
|
|
7
|
+
* - `FormMethodNames` + arg types — methods the component registers
|
|
8
|
+
*
|
|
9
|
+
* Hand-written, Studio-built, and agent-generated form components all target
|
|
10
|
+
* this contract. Import via the subpath:
|
|
11
|
+
*
|
|
12
|
+
* import { FormHostProps, FormEventNames, FormMethodNames }
|
|
13
|
+
* from '@memberjunction/interactive-component-types/forms';
|
|
14
|
+
*
|
|
15
|
+
* Note: this is the npm package name — the plan doc shorthands it as
|
|
16
|
+
* `@memberjunction/interactivecomponents`, which is the directory name, not
|
|
17
|
+
* the published name.
|
|
18
|
+
*/
|
|
19
|
+
export * from './form-host-props.js';
|
|
20
|
+
export * from './form-event-names.js';
|
|
21
|
+
export * from './form-method-names.js';
|
|
22
|
+
export * from './curated-form-schema.js';
|
|
23
|
+
export * from './default-form-scaffold.js';
|
|
24
|
+
export * from './form-host-props-fixture.js';
|
|
25
|
+
export * from './form-spec-info.js';
|
|
26
|
+
/** True iff the spec commits to the form-role contract. */
|
|
27
|
+
export function isFormRole(spec) {
|
|
28
|
+
return spec.componentRole === 'form';
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/forms/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AAIjC,2DAA2D;AAC3D,MAAM,UAAU,UAAU,CAAC,IAA0C;IACjE,OAAO,IAAI,CAAC,aAAa,KAAK,MAAM,CAAC;AACzC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/interactive-component-types",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.39.0",
|
|
5
5
|
"description": "MemberJunction: Interactive Component - Type specifications for MJ Interactive UI Componentry",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./forms": {
|
|
15
|
+
"types": "./dist/forms/index.d.ts",
|
|
16
|
+
"import": "./dist/forms/index.js",
|
|
17
|
+
"default": "./dist/forms/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
8
20
|
"files": [
|
|
9
21
|
"/dist"
|
|
10
22
|
],
|
|
@@ -20,8 +32,8 @@
|
|
|
20
32
|
"typescript": "^5.9.3"
|
|
21
33
|
},
|
|
22
34
|
"dependencies": {
|
|
23
|
-
"@memberjunction/core": "5.
|
|
24
|
-
"@memberjunction/ai-vectors-memory": "5.
|
|
35
|
+
"@memberjunction/core": "5.39.0",
|
|
36
|
+
"@memberjunction/ai-vectors-memory": "5.39.0"
|
|
25
37
|
},
|
|
26
38
|
"repository": {
|
|
27
39
|
"type": "git",
|