@memberjunction/ng-entity-action-ux 0.0.1 → 5.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +175 -43
  2. package/dist/lib/ai-prompt-selector/ai-prompt-selector.component.d.ts +41 -0
  3. package/dist/lib/ai-prompt-selector/ai-prompt-selector.component.d.ts.map +1 -0
  4. package/dist/lib/ai-prompt-selector/ai-prompt-selector.component.js +231 -0
  5. package/dist/lib/ai-prompt-selector/ai-prompt-selector.component.js.map +1 -0
  6. package/dist/lib/base-entity-action-runtime-ux.d.ts +31 -0
  7. package/dist/lib/base-entity-action-runtime-ux.d.ts.map +1 -0
  8. package/dist/lib/base-entity-action-runtime-ux.js +34 -0
  9. package/dist/lib/base-entity-action-runtime-ux.js.map +1 -0
  10. package/dist/lib/entity-action-ux-host.component.d.ts +32 -0
  11. package/dist/lib/entity-action-ux-host.component.d.ts.map +1 -0
  12. package/dist/lib/entity-action-ux-host.component.js +89 -0
  13. package/dist/lib/entity-action-ux-host.component.js.map +1 -0
  14. package/dist/lib/field-rules-builder/field-rules-builder.component.d.ts +62 -0
  15. package/dist/lib/field-rules-builder/field-rules-builder.component.d.ts.map +1 -0
  16. package/dist/lib/field-rules-builder/field-rules-builder.component.js +406 -0
  17. package/dist/lib/field-rules-builder/field-rules-builder.component.js.map +1 -0
  18. package/dist/lib/field-rules-model.d.ts +32 -0
  19. package/dist/lib/field-rules-model.d.ts.map +1 -0
  20. package/dist/lib/field-rules-model.js +76 -0
  21. package/dist/lib/field-rules-model.js.map +1 -0
  22. package/dist/lib/prompt-grouping.d.ts +20 -0
  23. package/dist/lib/prompt-grouping.d.ts.map +1 -0
  24. package/dist/lib/prompt-grouping.js +30 -0
  25. package/dist/lib/prompt-grouping.js.map +1 -0
  26. package/dist/lib/record-process-runner/record-process-runner-ux.component.d.ts +76 -0
  27. package/dist/lib/record-process-runner/record-process-runner-ux.component.d.ts.map +1 -0
  28. package/dist/lib/record-process-runner/record-process-runner-ux.component.js +506 -0
  29. package/dist/lib/record-process-runner/record-process-runner-ux.component.js.map +1 -0
  30. package/dist/lib/runtime-ux-context.d.ts +52 -0
  31. package/dist/lib/runtime-ux-context.d.ts.map +1 -0
  32. package/dist/lib/runtime-ux-context.js +2 -0
  33. package/dist/lib/runtime-ux-context.js.map +1 -0
  34. package/dist/lib/scope.d.ts +12 -0
  35. package/dist/lib/scope.d.ts.map +1 -0
  36. package/dist/lib/scope.js +25 -0
  37. package/dist/lib/scope.js.map +1 -0
  38. package/dist/public-api.d.ts +15 -0
  39. package/dist/public-api.d.ts.map +1 -0
  40. package/dist/public-api.js +27 -0
  41. package/dist/public-api.js.map +1 -0
  42. package/package.json +47 -6
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-rules-builder.component.js","sourceRoot":"","sources":["../../../src/lib/field-rules-builder/field-rules-builder.component.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview A visual authoring surface for a {@link FieldRuleSet} — the rules that drive a FieldRules\n * Record Process. Each rule sets a target field from a chosen source (static / another field / formula /\n * entity lookup / AI prompt), optionally gated by a condition. Validates live against the entity's metadata\n * via `EntityFieldRules.Validate`, and emits the typed rule set (the consumer serializes it into the\n * Record Process `Configuration`).\n * @module @memberjunction/ng-entity-action-ux\n */\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, inject } from '@angular/core';\nimport { EntityFieldRules, Metadata, type EntityInfo, type IMetadataProvider } from '@memberjunction/core';\nimport type { FieldRuleSet } from '@memberjunction/global';\nimport { AIPromptSelectorComponent } from '../ai-prompt-selector/ai-prompt-selector.component';\nimport { blankRuleDraft, draftsToRuleSet, ruleToDraft, type BuilderSourceKind, type RuleDraft } from '../field-rules-model';\nimport { MJEmptyStateComponent } from '@memberjunction/ng-ui-components';\n\n@Component({\n selector: 'mj-field-rules-builder',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [AIPromptSelectorComponent, MJEmptyStateComponent],\n template: `\n <div class=\"frb\">\n <div class=\"frb-head\">\n <div>\n <h3>Field rules</h3>\n <p class=\"frb-sub\">Each rule sets a field on every matching {{ EntityLabel }}. Use the preview before applying.</p>\n </div>\n <button type=\"button\" class=\"frb-add\" (click)=\"AddRule()\"><i class=\"fa-solid fa-plus\"></i> Add rule</button>\n </div>\n\n @if (Rules.length === 0) {\n <mj-empty-state class=\"frb-empty\" Size=\"compact\" Icon=\"\" Title=\"No rules yet\" Message=\"Click Add rule to start.\" />\n }\n\n @for (rule of Rules; track $index) {\n <div class=\"frb-rule\">\n <div class=\"frb-rule-head\">\n <span class=\"frb-rule-num\">{{ $index + 1 }}</span>\n <span class=\"frb-set\">Set</span>\n <select class=\"mj-input frb-target\" [value]=\"rule.TargetField\" (change)=\"SetTarget($index, $event)\">\n <option value=\"\">— field —</option>\n @for (f of WritableFields; track f.Name) { <option [value]=\"f.Name\">{{ f.DisplayNameOrName }}</option> }\n </select>\n <span class=\"frb-set\">from</span>\n <select class=\"mj-input frb-kind\" [value]=\"rule.SourceKind\" (change)=\"SetKind($index, $event)\">\n <option value=\"static\">a fixed value</option>\n <option value=\"field\">another field</option>\n <option value=\"formula\">a formula</option>\n <option value=\"lookup\">a lookup</option>\n <option value=\"prompt\">an AI prompt</option>\n </select>\n <button type=\"button\" class=\"frb-del\" title=\"Remove rule\" (click)=\"RemoveRule($index)\"><i class=\"fa-solid fa-trash\"></i></button>\n </div>\n\n <div class=\"frb-source\">\n @switch (rule.SourceKind) {\n @case ('static') {\n <input class=\"mj-input\" placeholder=\"Value\" [value]=\"rule.StaticValue\" (input)=\"SetField($index, 'StaticValue', $event)\" />\n }\n @case ('field') {\n <select class=\"mj-input\" [value]=\"rule.SourceField\" (change)=\"SetField($index, 'SourceField', $event)\">\n <option value=\"\">— source field —</option>\n @for (f of AllFields; track f.Name) { <option [value]=\"f.Name\">{{ f.DisplayNameOrName }}</option> }\n </select>\n }\n @case ('formula') {\n <input class=\"mj-input\" placeholder=\"e.g. fields.FirstName + ' ' + fields.LastName\" [value]=\"rule.Formula\" (input)=\"SetField($index, 'Formula', $event)\" />\n }\n @case ('lookup') {\n <div class=\"frb-lookup\">\n <input class=\"mj-input\" placeholder=\"Lookup entity\" [value]=\"rule.LookupEntity\" (input)=\"SetField($index, 'LookupEntity', $event)\" />\n <input class=\"mj-input\" placeholder=\"Match field\" [value]=\"rule.LookupMatchField\" (input)=\"SetField($index, 'LookupMatchField', $event)\" />\n <input class=\"mj-input\" placeholder=\"= this record's field\" [value]=\"rule.LookupMatchValueField\" (input)=\"SetField($index, 'LookupMatchValueField', $event)\" />\n <input class=\"mj-input\" placeholder=\"Return field\" [value]=\"rule.LookupReturnField\" (input)=\"SetField($index, 'LookupReturnField', $event)\" />\n </div>\n }\n @case ('prompt') {\n <mj-ai-prompt-selector [Value]=\"rule.PromptID\" (ValueChange)=\"SetPrompt($index, $event)\"></mj-ai-prompt-selector>\n }\n }\n </div>\n\n <div class=\"frb-cond\">\n <span class=\"frb-cond-label\">Only when</span>\n <input class=\"mj-input\" placeholder=\"(always) — e.g. fields.Status === 'Active'\" [value]=\"rule.Condition\" (input)=\"SetField($index, 'Condition', $event)\" />\n </div>\n </div>\n }\n\n @if (Errors.length > 0) {\n <div class=\"frb-errors\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n <ul>@for (e of Errors; track e) { <li>{{ e }}</li> }</ul>\n </div>\n }\n </div>\n `,\n styles: [`\n .frb { color: var(--mj-text-primary); display: flex; flex-direction: column; gap: 12px; }\n .frb-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }\n .frb-head h3 { margin: 0; font-size: 16px; }\n .frb-sub { margin: 2px 0 0; font-size: 13px; color: var(--mj-text-muted); }\n .frb-add { display: flex; align-items: center; gap: 6px; padding: 7px 12px; border: 1px solid var(--mj-brand-primary);\n color: var(--mj-brand-primary); background: transparent; border-radius: var(--mj-radius-sm, 6px); cursor: pointer; font-weight: 600; }\n .frb-add:hover { background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent); }\n .frb-empty { padding: 20px; text-align: center; color: var(--mj-text-muted); border: 1px dashed var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px); }\n .frb-rule { border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-md, 8px); padding: 12px; background: var(--mj-bg-surface-card); }\n .frb-rule-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }\n .frb-rule-num { width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center;\n border-radius: 50%; background: var(--mj-brand-primary); color: var(--mj-text-inverse); font-size: 12px; font-weight: 700; }\n .frb-set { color: var(--mj-text-secondary); font-size: 14px; }\n .frb-target, .frb-kind { min-width: 150px; }\n .frb-del { margin-left: auto; border: none; background: transparent; color: var(--mj-text-muted); cursor: pointer; padding: 4px 8px; }\n .frb-del:hover { color: var(--mj-status-error); }\n .frb-source { margin-top: 10px; }\n .frb-source .mj-input { width: 100%; }\n .frb-lookup { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 8px; }\n .frb-cond { display: flex; align-items: center; gap: 8px; margin-top: 10px; }\n .frb-cond-label { font-size: 13px; color: var(--mj-text-muted); white-space: nowrap; }\n .frb-cond .mj-input { flex: 1; }\n .frb-errors { display: flex; gap: 10px; padding: 10px 12px; background: var(--mj-status-error-bg); color: var(--mj-status-error-text);\n border-radius: var(--mj-radius-sm, 6px); font-size: 13px; }\n .frb-errors ul { margin: 0; padding-left: 18px; }\n `],\n})\nexport class FieldRulesBuilderComponent {\n private cdr = inject(ChangeDetectorRef);\n\n public Rules: RuleDraft[] = [];\n public Errors: string[] = [];\n public WritableFields: Array<{ Name: string; DisplayNameOrName: string }> = [];\n public AllFields: Array<{ Name: string; DisplayNameOrName: string }> = [];\n\n private _entityName = '';\n private entity?: EntityInfo;\n\n /** Metadata provider (multi-provider). Falls back to the global default when null. */\n @Input() Provider: IMetadataProvider | null = null;\n\n /** The entity whose fields the rules target. Loads the field lists when set. */\n @Input()\n set EntityName(value: string) {\n const prev = this._entityName;\n this._entityName = value;\n if (value && value !== prev) this.loadEntity();\n }\n get EntityName(): string { return this._entityName; }\n\n /**\n * Serialized form of our last emitted rule set. Consumers typically feed our `ValueChange` output\n * straight back in as `[Value]` (controlled-component style). Re-seeding the drafts from that echo\n * would wipe in-progress edits — most visibly a freshly-added **blank** rule, which serializes to\n * nothing (`draftsToRuleSet` drops rules with no target), so the echo arrives as `{Rules:[]}` and\n * resets the row the user just added. We ignore the echo and only re-seed on a genuinely different\n * (external) value.\n */\n private lastEmittedJSON: string | null = null;\n\n /** The initial rule set (e.g. an existing Record Process Configuration). */\n @Input()\n set Value(value: FieldRuleSet | null | undefined) {\n const incomingJSON = JSON.stringify(value?.Rules ?? []);\n if (incomingJSON === this.lastEmittedJSON) {\n return; // echo of our own emit — keep the live drafts intact\n }\n this.lastEmittedJSON = incomingJSON;\n this.Rules = value?.Rules ? value.Rules.map((r) => ruleToDraft(r)) : [];\n this.validate();\n }\n\n /** Emits the typed rule set on every edit; the consumer serializes it into the Configuration. */\n @Output() ValueChange = new EventEmitter<FieldRuleSet>();\n\n /** Emits the live validation result (true when every rule is valid against the entity). */\n @Output() ValidChange = new EventEmitter<boolean>();\n\n get EntityLabel(): string { return this.entity?.DisplayName || this.entity?.Name || 'record'; }\n\n AddRule(): void {\n this.Rules = [...this.Rules, blankRuleDraft()];\n this.emit();\n }\n\n RemoveRule(index: number): void {\n this.Rules = this.Rules.filter((_, i) => i !== index);\n this.emit();\n }\n\n SetTarget(index: number, event: Event): void {\n this.Rules[index].TargetField = (event.target as HTMLSelectElement).value;\n this.emit();\n }\n\n SetKind(index: number, event: Event): void {\n this.Rules[index].SourceKind = (event.target as HTMLSelectElement).value as BuilderSourceKind;\n this.emit();\n }\n\n SetField(index: number, field: keyof RuleDraft, event: Event): void {\n (this.Rules[index][field] as string) = (event.target as HTMLInputElement | HTMLSelectElement).value;\n this.emit();\n }\n\n SetPrompt(index: number, promptID: string | null): void {\n this.Rules[index].PromptID = promptID;\n this.emit();\n }\n\n /** Serializes the drafts, validates, and emits. */\n private emit(): void {\n const ruleSet = draftsToRuleSet(this.Rules);\n // Record what we're about to emit so the echo (consumer feeding it back via [Value]) is recognized\n // and ignored — see lastEmittedJSON. Must mirror the Value setter's comparison basis (Rules array).\n this.lastEmittedJSON = JSON.stringify(ruleSet.Rules ?? []);\n this.validate(ruleSet);\n this.ValueChange.emit(ruleSet);\n this.cdr.detectChanges();\n }\n\n private validate(ruleSet: FieldRuleSet = draftsToRuleSet(this.Rules)): void {\n if (!this._entityName) {\n this.Errors = [];\n } else {\n const result = EntityFieldRules.Validate(this._entityName, ruleSet, this.Provider ?? undefined);\n this.Errors = result.Errors;\n this.ValidChange.emit(result.Valid);\n }\n this.cdr.detectChanges();\n }\n\n private loadEntity(): void {\n this.entity = (this.Provider ?? Metadata.Provider)?.EntityByName(this._entityName);\n const map = (f: { Name: string; DisplayName?: string }) => ({ Name: f.Name, DisplayNameOrName: f.DisplayName || f.Name });\n this.AllFields = this.entity ? this.entity.Fields.map(map) : [];\n this.WritableFields = this.entity ? this.entity.Fields.filter((f) => !f.ReadOnly && !f.IsPrimaryKey).map(map) : [];\n this.validate();\n }\n}\n"]}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @fileoverview Pure (Angular-free) model + serialization for the field-rules builder: the flattened
3
+ * {@link RuleDraft} the UI edits, and the lossless mapping to/from the engine's {@link FieldRuleSet}.
4
+ * Kept separate from the component so it's unit-testable without a TestBed and reusable elsewhere.
5
+ * @module @memberjunction/ng-entity-action-ux
6
+ */
7
+ import type { FieldRule, FieldRuleSet, FieldRuleValueSource } from '@memberjunction/global';
8
+ /** The source kinds the visual builder edits directly (entityDocument is authored as JSON for now). */
9
+ export type BuilderSourceKind = 'static' | 'field' | 'formula' | 'lookup' | 'prompt';
10
+ /** The editable, flattened form of one rule (one screen row). */
11
+ export interface RuleDraft {
12
+ TargetField: string;
13
+ SourceKind: BuilderSourceKind;
14
+ StaticValue: string;
15
+ SourceField: string;
16
+ Formula: string;
17
+ LookupEntity: string;
18
+ LookupMatchField: string;
19
+ LookupMatchValueField: string;
20
+ LookupReturnField: string;
21
+ PromptID: string | null;
22
+ Condition: string;
23
+ }
24
+ /** A fresh, empty draft (static source, no target). */
25
+ export declare function blankRuleDraft(): RuleDraft;
26
+ /** Maps a draft to the engine's discriminated {@link FieldRuleValueSource}. */
27
+ export declare function draftToSource(d: RuleDraft): FieldRuleValueSource;
28
+ /** Builds a {@link FieldRuleSet} from drafts, dropping any with no target field. */
29
+ export declare function draftsToRuleSet(drafts: RuleDraft[]): FieldRuleSet;
30
+ /** Inflates an engine rule back into an editable draft (inverse of {@link draftToSource}). */
31
+ export declare function ruleToDraft(rule: FieldRule): RuleDraft;
32
+ //# sourceMappingURL=field-rules-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-rules-model.d.ts","sourceRoot":"","sources":["../../src/lib/field-rules-model.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE5F,uGAAuG;AACvG,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAErF,iEAAiE;AACjE,MAAM,WAAW,SAAS;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,uDAAuD;AACvD,wBAAgB,cAAc,IAAI,SAAS,CAM1C;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,CAAC,EAAE,SAAS,GAAG,oBAAoB,CAsBhE;AAED,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,YAAY,CAUjE;AAED,8FAA8F;AAC9F,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,CA4BtD"}
@@ -0,0 +1,76 @@
1
+ /** A fresh, empty draft (static source, no target). */
2
+ export function blankRuleDraft() {
3
+ return {
4
+ TargetField: '', SourceKind: 'static', StaticValue: '', SourceField: '', Formula: '',
5
+ LookupEntity: '', LookupMatchField: '', LookupMatchValueField: '', LookupReturnField: '',
6
+ PromptID: null, Condition: '',
7
+ };
8
+ }
9
+ /** Maps a draft to the engine's discriminated {@link FieldRuleValueSource}. */
10
+ export function draftToSource(d) {
11
+ switch (d.SourceKind) {
12
+ case 'field':
13
+ return { Kind: 'field', Field: d.SourceField };
14
+ case 'formula':
15
+ return { Kind: 'formula', Expression: d.Formula };
16
+ case 'lookup':
17
+ return {
18
+ Kind: 'lookup',
19
+ Lookup: {
20
+ Entity: d.LookupEntity,
21
+ MatchField: d.LookupMatchField,
22
+ MatchValue: { Kind: 'field', Field: d.LookupMatchValueField },
23
+ ReturnField: d.LookupReturnField,
24
+ },
25
+ };
26
+ case 'prompt':
27
+ return { Kind: 'prompt', Prompt: { PromptID: d.PromptID ?? '' } };
28
+ case 'static':
29
+ default:
30
+ return { Kind: 'static', Value: d.StaticValue };
31
+ }
32
+ }
33
+ /** Builds a {@link FieldRuleSet} from drafts, dropping any with no target field. */
34
+ export function draftsToRuleSet(drafts) {
35
+ return {
36
+ Rules: drafts
37
+ .filter((d) => d.TargetField)
38
+ .map((d) => ({
39
+ TargetField: d.TargetField,
40
+ Source: draftToSource(d),
41
+ ...(d.Condition ? { Condition: d.Condition } : {}),
42
+ })),
43
+ };
44
+ }
45
+ /** Inflates an engine rule back into an editable draft (inverse of {@link draftToSource}). */
46
+ export function ruleToDraft(rule) {
47
+ const d = blankRuleDraft();
48
+ d.TargetField = rule.TargetField;
49
+ d.Condition = rule.Condition ?? '';
50
+ const s = rule.Source;
51
+ // entityDocument has no first-class builder UI yet — surface it as a (read-only-ish) static slot.
52
+ d.SourceKind = s.Kind === 'entityDocument' ? 'static' : s.Kind;
53
+ switch (s.Kind) {
54
+ case 'static':
55
+ d.StaticValue = s.Value == null ? '' : String(s.Value);
56
+ break;
57
+ case 'field':
58
+ d.SourceField = s.Field;
59
+ break;
60
+ case 'formula':
61
+ d.Formula = s.Expression;
62
+ break;
63
+ case 'lookup':
64
+ d.LookupEntity = s.Lookup.Entity;
65
+ d.LookupMatchField = s.Lookup.MatchField;
66
+ d.LookupReturnField = s.Lookup.ReturnField;
67
+ if (s.Lookup.MatchValue.Kind === 'field')
68
+ d.LookupMatchValueField = s.Lookup.MatchValue.Field;
69
+ break;
70
+ case 'prompt':
71
+ d.PromptID = s.Prompt.PromptID;
72
+ break;
73
+ }
74
+ return d;
75
+ }
76
+ //# sourceMappingURL=field-rules-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-rules-model.js","sourceRoot":"","sources":["../../src/lib/field-rules-model.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Pure (Angular-free) model + serialization for the field-rules builder: the flattened\n * {@link RuleDraft} the UI edits, and the lossless mapping to/from the engine's {@link FieldRuleSet}.\n * Kept separate from the component so it's unit-testable without a TestBed and reusable elsewhere.\n * @module @memberjunction/ng-entity-action-ux\n */\nimport type { FieldRule, FieldRuleSet, FieldRuleValueSource } from '@memberjunction/global';\n\n/** The source kinds the visual builder edits directly (entityDocument is authored as JSON for now). */\nexport type BuilderSourceKind = 'static' | 'field' | 'formula' | 'lookup' | 'prompt';\n\n/** The editable, flattened form of one rule (one screen row). */\nexport interface RuleDraft {\n TargetField: string;\n SourceKind: BuilderSourceKind;\n StaticValue: string;\n SourceField: string;\n Formula: string;\n LookupEntity: string;\n LookupMatchField: string;\n LookupMatchValueField: string;\n LookupReturnField: string;\n PromptID: string | null;\n Condition: string;\n}\n\n/** A fresh, empty draft (static source, no target). */\nexport function blankRuleDraft(): RuleDraft {\n return {\n TargetField: '', SourceKind: 'static', StaticValue: '', SourceField: '', Formula: '',\n LookupEntity: '', LookupMatchField: '', LookupMatchValueField: '', LookupReturnField: '',\n PromptID: null, Condition: '',\n };\n}\n\n/** Maps a draft to the engine's discriminated {@link FieldRuleValueSource}. */\nexport function draftToSource(d: RuleDraft): FieldRuleValueSource {\n switch (d.SourceKind) {\n case 'field':\n return { Kind: 'field', Field: d.SourceField };\n case 'formula':\n return { Kind: 'formula', Expression: d.Formula };\n case 'lookup':\n return {\n Kind: 'lookup',\n Lookup: {\n Entity: d.LookupEntity,\n MatchField: d.LookupMatchField,\n MatchValue: { Kind: 'field', Field: d.LookupMatchValueField },\n ReturnField: d.LookupReturnField,\n },\n };\n case 'prompt':\n return { Kind: 'prompt', Prompt: { PromptID: d.PromptID ?? '' } };\n case 'static':\n default:\n return { Kind: 'static', Value: d.StaticValue };\n }\n}\n\n/** Builds a {@link FieldRuleSet} from drafts, dropping any with no target field. */\nexport function draftsToRuleSet(drafts: RuleDraft[]): FieldRuleSet {\n return {\n Rules: drafts\n .filter((d) => d.TargetField)\n .map((d): FieldRule => ({\n TargetField: d.TargetField,\n Source: draftToSource(d),\n ...(d.Condition ? { Condition: d.Condition } : {}),\n })),\n };\n}\n\n/** Inflates an engine rule back into an editable draft (inverse of {@link draftToSource}). */\nexport function ruleToDraft(rule: FieldRule): RuleDraft {\n const d = blankRuleDraft();\n d.TargetField = rule.TargetField;\n d.Condition = rule.Condition ?? '';\n const s = rule.Source;\n // entityDocument has no first-class builder UI yet — surface it as a (read-only-ish) static slot.\n d.SourceKind = s.Kind === 'entityDocument' ? 'static' : s.Kind;\n switch (s.Kind) {\n case 'static':\n d.StaticValue = s.Value == null ? '' : String(s.Value);\n break;\n case 'field':\n d.SourceField = s.Field;\n break;\n case 'formula':\n d.Formula = s.Expression;\n break;\n case 'lookup':\n d.LookupEntity = s.Lookup.Entity;\n d.LookupMatchField = s.Lookup.MatchField;\n d.LookupReturnField = s.Lookup.ReturnField;\n if (s.Lookup.MatchValue.Kind === 'field') d.LookupMatchValueField = s.Lookup.MatchValue.Field;\n break;\n case 'prompt':\n d.PromptID = s.Prompt.PromptID;\n break;\n }\n return d;\n}\n"]}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @fileoverview Pure grouping/filtering for the AI-prompt selector. Extracted for unit-testability.
3
+ * @module @memberjunction/ng-entity-action-ux
4
+ */
5
+ /** A flat prompt option from the metadata view. */
6
+ export interface PromptOption {
7
+ ID: string;
8
+ Name: string;
9
+ Category: string;
10
+ }
11
+ /** A category group of prompts (preserves the encounter order of categories). */
12
+ export interface PromptGroup {
13
+ Category: string;
14
+ Prompts: PromptOption[];
15
+ }
16
+ /** Groups prompts by their category name (blank → "Uncategorized"), preserving input order. */
17
+ export declare function groupPromptsByCategory(prompts: PromptOption[]): PromptGroup[];
18
+ /** Case-insensitive name filter that drops emptied groups. */
19
+ export declare function filterPromptGroups(groups: PromptGroup[], query: string): PromptGroup[];
20
+ //# sourceMappingURL=prompt-grouping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-grouping.d.ts","sourceRoot":"","sources":["../../src/lib/prompt-grouping.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,mDAAmD;AACnD,MAAM,WAAW,YAAY;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;CAAE;AAE7E,iFAAiF;AACjF,MAAM,WAAW,WAAW;IAAG,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,YAAY,EAAE,CAAC;CAAE;AAE3E,+FAA+F;AAC/F,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,WAAW,EAAE,CAc7E;AAED,8DAA8D;AAC9D,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,EAAE,CAMtF"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @fileoverview Pure grouping/filtering for the AI-prompt selector. Extracted for unit-testability.
3
+ * @module @memberjunction/ng-entity-action-ux
4
+ */
5
+ /** Groups prompts by their category name (blank → "Uncategorized"), preserving input order. */
6
+ export function groupPromptsByCategory(prompts) {
7
+ const groups = [];
8
+ const index = new Map();
9
+ for (const p of prompts) {
10
+ const category = p.Category || 'Uncategorized';
11
+ let group = index.get(category);
12
+ if (!group) {
13
+ group = { Category: category, Prompts: [] };
14
+ index.set(category, group);
15
+ groups.push(group);
16
+ }
17
+ group.Prompts.push(p);
18
+ }
19
+ return groups;
20
+ }
21
+ /** Case-insensitive name filter that drops emptied groups. */
22
+ export function filterPromptGroups(groups, query) {
23
+ const q = query.trim().toLowerCase();
24
+ if (!q)
25
+ return groups;
26
+ return groups
27
+ .map((g) => ({ Category: g.Category, Prompts: g.Prompts.filter((p) => p.Name.toLowerCase().includes(q)) }))
28
+ .filter((g) => g.Prompts.length > 0);
29
+ }
30
+ //# sourceMappingURL=prompt-grouping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-grouping.js","sourceRoot":"","sources":["../../src/lib/prompt-grouping.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,+FAA+F;AAC/F,MAAM,UAAU,sBAAsB,CAAC,OAAuB;IAC1D,MAAM,MAAM,GAAkB,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC7C,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACtB,MAAM,QAAQ,GAAG,CAAC,CAAC,QAAQ,IAAI,eAAe,CAAC;QAC/C,IAAI,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,KAAK,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YAC5C,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,kBAAkB,CAAC,MAAqB,EAAE,KAAa;IACnE,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,IAAI,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC;IACtB,OAAO,MAAM;SACR,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SAC1G,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC7C,CAAC","sourcesContent":["/**\n * @fileoverview Pure grouping/filtering for the AI-prompt selector. Extracted for unit-testability.\n * @module @memberjunction/ng-entity-action-ux\n */\n\n/** A flat prompt option from the metadata view. */\nexport interface PromptOption { ID: string; Name: string; Category: string; }\n\n/** A category group of prompts (preserves the encounter order of categories). */\nexport interface PromptGroup { Category: string; Prompts: PromptOption[]; }\n\n/** Groups prompts by their category name (blank → \"Uncategorized\"), preserving input order. */\nexport function groupPromptsByCategory(prompts: PromptOption[]): PromptGroup[] {\n const groups: PromptGroup[] = [];\n const index = new Map<string, PromptGroup>();\n for (const p of prompts) {\n const category = p.Category || 'Uncategorized';\n let group = index.get(category);\n if (!group) {\n group = { Category: category, Prompts: [] };\n index.set(category, group);\n groups.push(group);\n }\n group.Prompts.push(p);\n }\n return groups;\n}\n\n/** Case-insensitive name filter that drops emptied groups. */\nexport function filterPromptGroups(groups: PromptGroup[], query: string): PromptGroup[] {\n const q = query.trim().toLowerCase();\n if (!q) return groups;\n return groups\n .map((g) => ({ Category: g.Category, Prompts: g.Prompts.filter((p) => p.Name.toLowerCase().includes(q)) }))\n .filter((g) => g.Prompts.length > 0);\n}\n"]}
@@ -0,0 +1,76 @@
1
+ import { BaseEntityActionRuntimeUX } from '../base-entity-action-runtime-ux';
2
+ import * as i0 from "@angular/core";
3
+ /** The run summary the runner renders, mapped from the operation's typed output. */
4
+ interface RunSummary {
5
+ Success: boolean;
6
+ ProcessRunID?: string;
7
+ Processed: number;
8
+ Succeeded: number;
9
+ Errored: number;
10
+ Skipped: number;
11
+ Status?: string;
12
+ ErrorMessage?: string;
13
+ }
14
+ /** The driver's flow state. */
15
+ type RunnerState = 'loading' | 'preview' | 'applying' | 'done' | 'error';
16
+ /** One computed field change (mirrors the engine's `FieldChange` for the bits the UI shows). */
17
+ interface DiffChange {
18
+ Field: string;
19
+ OldValue: unknown;
20
+ NewValue: unknown;
21
+ Applied: boolean;
22
+ Changed: boolean;
23
+ Error?: string;
24
+ }
25
+ /** A per-record row of the preview table. */
26
+ interface RecordDiffRow {
27
+ RecordID: string;
28
+ Status: string;
29
+ Changes: DiffChange[];
30
+ ErrorMessage?: string;
31
+ }
32
+ export declare class RecordProcessRunnerUXComponent extends BaseEntityActionRuntimeUX {
33
+ private cdr;
34
+ /** Cap on preview rows we render (the apply step always covers the full scope). */
35
+ private static readonly MAX_PREVIEW_ROWS;
36
+ State: RunnerState;
37
+ ErrorMessage: string;
38
+ DiffRows: RecordDiffRow[];
39
+ PreviewResult?: RunSummary;
40
+ AppliedResult?: RunSummary;
41
+ ChangedRecordCount: number;
42
+ TotalChangeCount: number;
43
+ Truncated: boolean;
44
+ get Title(): string;
45
+ get EntityLabel(): string;
46
+ get HasChanges(): boolean;
47
+ get SkippedCount(): number;
48
+ get ErroredCount(): number;
49
+ get DoneMessage(): string;
50
+ /** Step 1: run a dry-run on the server and load the resulting per-record diff. */
51
+ Start(): Promise<void>;
52
+ /** Step 2: the user confirmed — run for real. */
53
+ Apply(): Promise<void>;
54
+ /** Closes after a successful apply, telling the host to refresh. */
55
+ Finish(): void;
56
+ /** Dismiss without applying (also used for the error/close button). */
57
+ OnCancel(): void;
58
+ /** Renders a value for the diff table (delegates to the pure helper). */
59
+ Display(value: unknown): string;
60
+ /**
61
+ * Runs the `RecordProcess.RunNow` Remote Operation and maps its typed output to a {@link RunSummary}.
62
+ * `Execute` routes through the host's provider — marshalled over the generic `ExecuteRemoteOperation`
63
+ * transport on the client, in-process on the server — so there is no bespoke resolver/client.
64
+ */
65
+ private runOp;
66
+ /** Reads `MJ: Process Run Details` for the dry-run and builds the per-record diff rows. */
67
+ private loadDiff;
68
+ /** Builds the engine scope from the host-supplied context (delegates to the pure helper). */
69
+ private buildScope;
70
+ private recordProcessID;
71
+ private toError;
72
+ static ɵfac: i0.ɵɵFactoryDeclaration<RecordProcessRunnerUXComponent, never>;
73
+ static ɵcmp: i0.ɵɵComponentDeclaration<RecordProcessRunnerUXComponent, "mj-record-process-runner-ux", never, {}, {}, never, never, true, never>;
74
+ }
75
+ export {};
76
+ //# sourceMappingURL=record-process-runner-ux.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record-process-runner-ux.component.d.ts","sourceRoot":"","sources":["../../../src/lib/record-process-runner/record-process-runner-ux.component.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;;AAG7E,oFAAoF;AACpF,UAAU,UAAU;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,+BAA+B;AAC/B,KAAK,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC;AAEzE,gGAAgG;AAChG,UAAU,UAAU;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AASD,6CAA6C;AAC7C,UAAU,aAAa;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAUD,qBAmIa,8BAA+B,SAAQ,yBAAyB;IACzE,OAAO,CAAC,GAAG,CAA6B;IAExC,mFAAmF;IACnF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAO;IAExC,KAAK,EAAE,WAAW,CAAa;IAC/B,YAAY,SAAM;IAClB,QAAQ,EAAE,aAAa,EAAE,CAAM;IAC/B,aAAa,CAAC,EAAE,UAAU,CAAC;IAC3B,aAAa,CAAC,EAAE,UAAU,CAAC;IAC3B,kBAAkB,SAAK;IACvB,gBAAgB,SAAK;IACrB,SAAS,UAAS;IAEzB,IAAI,KAAK,IAAI,MAAM,CAA8D;IACjF,IAAI,WAAW,IAAI,MAAM,CAAiG;IAC1H,IAAI,UAAU,IAAI,OAAO,CAAwC;IACjE,IAAI,YAAY,IAAI,MAAM,CAA6C;IACvE,IAAI,YAAY,IAAI,MAAM,CAA6C;IACvE,IAAI,WAAW,IAAI,MAAM,CAGxB;IAED,kFAAkF;IAC5E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAuB5B,iDAAiD;IAC3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB5B,oEAAoE;IACpE,MAAM,IAAI,IAAI;IAId,uEAAuE;IACvE,QAAQ,IAAI,IAAI;IAKhB,yEAAyE;IACzE,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM;IAI/B;;;;OAIG;YACW,KAAK;IAkBnB,2FAA2F;YAC7E,QAAQ;IA+BtB,6FAA6F;IAC7F,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,OAAO;yCAtJN,8BAA8B;2CAA9B,8BAA8B;CA2J1C"}