@memberjunction/ng-dashboards 5.36.0 → 5.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -0
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +14 -0
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +450 -292
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts +73 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.js +512 -127
- package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
- package/dist/ComponentStudio/component-studio-resource.component.d.ts +22 -0
- package/dist/ComponentStudio/component-studio-resource.component.d.ts.map +1 -0
- package/dist/ComponentStudio/component-studio-resource.component.js +55 -0
- package/dist/ComponentStudio/component-studio-resource.component.js.map +1 -0
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts +104 -45
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js +234 -331
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js.map +1 -1
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.d.ts +54 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.js +339 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-canvas.component.js.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.d.ts +65 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.js +492 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-right-panel.component.js.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.d.ts +88 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.js +457 -0
- package/dist/ComponentStudio/components/form-builder/form-builder-tab.component.js.map +1 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.d.ts +106 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.d.ts.map +1 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.js +478 -0
- package/dist/ComponentStudio/components/form-override-dialog.component.js.map +1 -0
- package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts +54 -0
- package/dist/ComponentStudio/components/workspace/component-preview.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/workspace/component-preview.component.js +361 -50
- package/dist/ComponentStudio/components/workspace/component-preview.component.js.map +1 -1
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.d.ts +10 -0
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.js +114 -45
- package/dist/ComponentStudio/components/workspace/editor-tabs.component.js.map +1 -1
- package/dist/ComponentStudio/services/canvas-to-code.d.ts +32 -0
- package/dist/ComponentStudio/services/canvas-to-code.d.ts.map +1 -0
- package/dist/ComponentStudio/services/canvas-to-code.js +347 -0
- package/dist/ComponentStudio/services/canvas-to-code.js.map +1 -0
- package/dist/ComponentStudio/services/code-to-canvas.d.ts +32 -0
- package/dist/ComponentStudio/services/code-to-canvas.d.ts.map +1 -0
- package/dist/ComponentStudio/services/code-to-canvas.js +92 -0
- package/dist/ComponentStudio/services/code-to-canvas.js.map +1 -0
- package/dist/ComponentStudio/services/component-studio-state.service.d.ts +29 -0
- package/dist/ComponentStudio/services/component-studio-state.service.d.ts.map +1 -1
- package/dist/ComponentStudio/services/component-studio-state.service.js +76 -0
- package/dist/ComponentStudio/services/component-studio-state.service.js.map +1 -1
- package/dist/ComponentStudio/services/entity-form-override.service.d.ts +86 -0
- package/dist/ComponentStudio/services/entity-form-override.service.d.ts.map +1 -0
- package/dist/ComponentStudio/services/entity-form-override.service.js +246 -0
- package/dist/ComponentStudio/services/entity-form-override.service.js.map +1 -0
- package/dist/ComponentStudio/services/field-binding-scanner.d.ts +29 -0
- package/dist/ComponentStudio/services/field-binding-scanner.d.ts.map +1 -0
- package/dist/ComponentStudio/services/field-binding-scanner.js +110 -0
- package/dist/ComponentStudio/services/field-binding-scanner.js.map +1 -0
- package/dist/ComponentStudio/services/form-canvas-model.d.ts +56 -0
- package/dist/ComponentStudio/services/form-canvas-model.d.ts.map +1 -0
- package/dist/ComponentStudio/services/form-canvas-model.js +35 -0
- package/dist/ComponentStudio/services/form-canvas-model.js.map +1 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.d.ts +10 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.d.ts.map +1 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.js +10 -0
- package/dist/ComponentStudio/services/form-host-props-fixture.js.map +1 -0
- package/dist/DataExplorer/data-explorer-dashboard.component.js +2 -2
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/FormBuilder/form-builder-resource.component.d.ts +964 -0
- package/dist/FormBuilder/form-builder-resource.component.d.ts.map +1 -0
- package/dist/FormBuilder/form-builder-resource.component.js +4487 -0
- package/dist/FormBuilder/form-builder-resource.component.js.map +1 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.d.ts +55 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.d.ts.map +1 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.js +73 -0
- package/dist/FormBuilder/form-builder-version-rail.helpers.js.map +1 -0
- package/dist/Home/home-application.d.ts +21 -1
- package/dist/Home/home-application.d.ts.map +1 -1
- package/dist/Home/home-application.js +60 -8
- package/dist/Home/home-application.js.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.d.ts +14 -14
- package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.js +11 -10
- package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
- package/dist/component-studio-dashboards.module.d.ts +34 -22
- package/dist/component-studio-dashboards.module.d.ts.map +1 -1
- package/dist/component-studio-dashboards.module.js +65 -9
- package/dist/component-studio-dashboards.module.js.map +1 -1
- package/package.json +54 -53
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component-preview.component.js","sourceRoot":"","sources":["../../../../src/ComponentStudio/components/workspace/component-preview.component.ts","../../../../src/ComponentStudio/components/workspace/component-preview.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Output,\n EventEmitter,\n OnInit,\n OnDestroy,\n ViewChild,\n ChangeDetectorRef\n} from '@angular/core';\nimport { Subject, takeUntil } from 'rxjs';\nimport { ComponentSpec } from '@memberjunction/interactive-component-types';\nimport { ReactComponentEvent, MJReactComponent } from '@memberjunction/ng-react';\nimport { CompositeKey } from '@memberjunction/core';\nimport { SharedService } from '@memberjunction/ng-shared';\nimport {\n ComponentStudioStateService,\n ComponentError\n} from '../../services/component-studio-state.service';\n\n/**\n * Viewport size preset for the component preview\n */\nexport type ViewportSize = 'mobile' | 'tablet' | 'desktop';\n\ninterface ViewportPreset {\n Size: ViewportSize;\n Label: string;\n Icon: string;\n MaxWidth: string;\n}\n\n/**\n * Component Preview - TOP section of CENTER panel.\n * Renders the live React component preview with toolbar controls.\n */\n@Component({\n standalone: false,\n selector: 'mj-component-preview',\n templateUrl: './component-preview.component.html',\n styleUrls: ['./component-preview.component.css']\n})\nexport class ComponentPreviewComponent implements OnInit, OnDestroy {\n\n @ViewChild('reactComponent') ReactComponentRef?: MJReactComponent;\n\n @Output() AskAIToFix = new EventEmitter<ComponentError>();\n\n // --- Viewport ---\n public ActiveViewport: ViewportSize = 'desktop';\n\n public readonly ViewportPresets: ViewportPreset[] = [\n { Size: 'mobile', Label: 'Mobile (375px)', Icon: 'fa-mobile-screen', MaxWidth: '375px' },\n { Size: 'tablet', Label: 'Tablet (768px)', Icon: 'fa-tablet-screen-button', MaxWidth: '768px' },\n { Size: 'desktop', Label: 'Desktop (100%)', Icon: 'fa-desktop', MaxWidth: '100%' }\n ];\n\n // --- Local spec for refresh cycle ---\n public LocalComponentSpec: ComponentSpec | null = null;\n\n private destroy$ = new Subject<void>();\n\n constructor(\n public State: ComponentStudioStateService,\n private cdr: ChangeDetectorRef\n ) {}\n\n ngOnInit(): void {\n this.syncSpecFromState();\n\n this.State.StateChanged\n .pipe(takeUntil(this.destroy$))\n .subscribe(() => {\n this.syncSpecFromState();\n this.cdr.detectChanges();\n });\n\n this.State.RefreshComponent\n .pipe(takeUntil(this.destroy$))\n .subscribe(() => {\n this.refreshPreview();\n });\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n // ============================================================\n // TOOLBAR ACTIONS\n // ============================================================\n\n public RunSelectedComponent(): void {\n if (this.State.SelectedComponent) {\n this.State.RunComponent(this.State.SelectedComponent);\n }\n }\n\n public StopComponent(): void {\n MJReactComponent.forceClearRegistries();\n this.State.StopComponent();\n }\n\n public RefreshComponent(): void {\n if (this.State.SelectedComponent && this.State.IsRunning) {\n MJReactComponent.forceClearRegistries();\n this.refreshPreview();\n }\n }\n\n public SetViewport(size: ViewportSize): void {\n this.ActiveViewport = size;\n this.cdr.detectChanges();\n }\n\n public SendErrorToAI(): void {\n if (this.State.CurrentError) {\n this.AskAIToFix.emit(this.State.CurrentError);\n this.State.SendErrorToAI.emit(this.State.CurrentError);\n }\n }\n\n // ============================================================\n // VIEWPORT HELPERS\n // ============================================================\n\n public GetActivePreset(): ViewportPreset {\n return this.ViewportPresets.find(p => p.Size === this.ActiveViewport) || this.ViewportPresets[2];\n }\n\n public GetPreviewContainerMaxWidth(): string {\n return this.GetActivePreset().MaxWidth;\n }\n\n // ============================================================\n // REACT COMPONENT EVENTS\n // ============================================================\n\n public OnComponentEvent(event: ReactComponentEvent): void {\n if (event.type === 'error') {\n this.State.CurrentError = {\n type: event.payload?.source || 'Component Error',\n message: event.payload?.error || 'An error occurred while rendering the component',\n technicalDetails: event.payload?.errorInfo || event.payload\n };\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Fires once the React bridge has resolved the full component hierarchy from the\n * registry. The bridge stores the resolved spec (with real dependency code, not\n * registry-reference stubs) on its public `resolvedComponentSpec` field — pull it\n * across so the code-editor tabs can render actual source instead of \"No code available\".\n */\n public OnReactInitialized(): void {\n const resolvedSpec = this.ReactComponentRef?.resolvedComponentSpec;\n if (resolvedSpec) {\n this.State.UpdateWithResolvedSpec(resolvedSpec);\n this.cdr.detectChanges();\n }\n }\n\n public OnOpenEntityRecord(event: { entityName: string; key: CompositeKey }): void {\n SharedService.Instance.OpenEntityRecord(event.entityName, event.key);\n }\n\n // ============================================================\n // STATE HELPERS\n // ============================================================\n\n public GetComponentName(): string {\n if (!this.State.SelectedComponent) return '';\n return this.State.GetComponentName(this.State.SelectedComponent);\n }\n\n public GetComponentDescription(): string | undefined {\n if (!this.State.SelectedComponent) return undefined;\n return this.State.GetComponentDescription(this.State.SelectedComponent);\n }\n\n // ============================================================\n // PRIVATE\n // ============================================================\n\n private syncSpecFromState(): void {\n this.LocalComponentSpec = this.State.ComponentSpec;\n }\n\n /**\n * Refresh the preview by nulling the spec, detecting changes,\n * then restoring the spec after a short delay. The bridge's own\n * `initializeComponent` purges the runtime registry + manager fetch cache\n * for the new spec's keys, so consumers don't need to clear anything here.\n */\n private refreshPreview(): void {\n if (!this.State.SelectedComponent) return;\n\n const spec = this.State.ComponentSpec;\n\n // Null out to force React to unmount\n this.LocalComponentSpec = null;\n this.cdr.detectChanges();\n\n // Re-set after a brief pause to force fresh mount\n setTimeout(() => {\n this.LocalComponentSpec = spec;\n this.State.ComponentSpec = spec;\n this.State.CurrentError = null;\n try {\n this.cdr.detectChanges();\n } catch (error) {\n console.error('Error during refresh detectChanges:', error);\n }\n }, 10);\n }\n}\n","<div class=\"component-preview\">\n <!-- Toolbar -->\n <div class=\"preview-toolbar\">\n <div class=\"toolbar-left\">\n @if (State.SelectedComponent) {\n @if (State.IsRunning) {\n <button class=\"toolbar-btn stop-btn\" (click)=\"StopComponent()\" title=\"Stop component\">\n <i class=\"fa-solid fa-stop\"></i>\n <span>Stop</span>\n </button>\n <button class=\"toolbar-btn\" (click)=\"RefreshComponent()\" title=\"Refresh component\">\n <i class=\"fa-solid fa-rotate-right\"></i>\n <span>Refresh</span>\n </button>\n } @else {\n <button class=\"toolbar-btn run-btn\" (click)=\"RunSelectedComponent()\" title=\"Run component\">\n <i class=\"fa-solid fa-play\"></i>\n <span>Run</span>\n </button>\n }\n }\n </div>\n\n <div class=\"toolbar-center\">\n <!-- Viewport Size Selector (segmented control) -->\n @if (State.IsRunning) {\n <div class=\"viewport-selector\">\n @for (preset of ViewportPresets; track preset.Size) {\n <button\n class=\"viewport-btn\"\n [class.active]=\"ActiveViewport === preset.Size\"\n (click)=\"SetViewport(preset.Size)\"\n [title]=\"preset.Label\">\n <i class=\"fa-solid\" [ngClass]=\"preset.Icon\"></i>\n </button>\n }\n </div>\n }\n </div>\n\n <div class=\"toolbar-right\">\n @if (State.CurrentError) {\n <button class=\"toolbar-btn ai-fix-btn\" (click)=\"SendErrorToAI()\" title=\"Ask AI to fix this error\">\n <i class=\"fa-solid fa-wand-magic-sparkles\"></i>\n <span>Ask AI to Fix</span>\n </button>\n }\n @if (State.IsRunning && State.SelectedComponent) {\n <span class=\"running-indicator\">\n <i class=\"fa-solid fa-circle running-dot\"></i>\n {{ GetComponentName() }}\n </span>\n }\n </div>\n </div>\n\n <!-- Preview Area -->\n <div class=\"preview-area\">\n @if (!State.SelectedComponent) {\n <!-- Empty State: No component selected -->\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-eye fa-3x\"></i>\n <h3>Select a component to preview</h3>\n <p>Choose a component from the sidebar to see its live preview here.</p>\n </div>\n } @else if (!State.IsRunning) {\n <!-- Component selected but not running -->\n <div class=\"empty-state run-state\">\n <i class=\"fa-solid fa-play-circle fa-3x\"></i>\n <h3>{{ GetComponentName() }}</h3>\n <p>{{ GetComponentDescription() || 'No description available' }}</p>\n <button class=\"run-component-btn\" (click)=\"RunSelectedComponent()\">\n <i class=\"fa-solid fa-play\"></i> Run Component\n </button>\n </div>\n } @else if (LocalComponentSpec) {\n <!-- Live Preview Container -->\n <div class=\"preview-container\"\n [style.max-width]=\"GetPreviewContainerMaxWidth()\"\n [class.mobile]=\"ActiveViewport === 'mobile'\"\n [class.tablet]=\"ActiveViewport === 'tablet'\"\n [class.desktop]=\"ActiveViewport === 'desktop'\">\n <mj-react-component\n #reactComponent\n [component]=\"LocalComponentSpec\"\n (componentEvent)=\"OnComponentEvent($event)\"\n (initialized)=\"OnReactInitialized()\"\n (openEntityRecord)=\"OnOpenEntityRecord($event)\">\n </mj-react-component>\n </div>\n\n <!-- Error Overlay (inline, does not replace the component) -->\n @if (State.CurrentError) {\n <div class=\"error-overlay\">\n <div class=\"error-overlay-content\">\n <div class=\"error-overlay-header\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span class=\"error-overlay-title\">{{ State.CurrentError.type }}</span>\n </div>\n <p class=\"error-overlay-message\">{{ State.CurrentError.message }}</p>\n <div class=\"error-overlay-actions\">\n <button class=\"toolbar-btn\" (click)=\"RefreshComponent()\">\n <i class=\"fa-solid fa-rotate-right\"></i> Retry\n </button>\n <button class=\"toolbar-btn ai-fix-btn\" (click)=\"SendErrorToAI()\">\n <i class=\"fa-solid fa-wand-magic-sparkles\"></i> Ask AI to Fix\n </button>\n </div>\n </div>\n </div>\n }\n }\n </div>\n</div>\n"]}
|
|
1
|
+
{"version":3,"file":"component-preview.component.js","sourceRoot":"","sources":["../../../../src/ComponentStudio/components/workspace/component-preview.component.ts","../../../../src/ComponentStudio/components/workspace/component-preview.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Output,\n EventEmitter,\n OnInit,\n OnDestroy,\n ViewChild,\n ChangeDetectorRef\n} from '@angular/core';\nimport { Subject, takeUntil } from 'rxjs';\nimport { ComponentSpec } from '@memberjunction/interactive-component-types';\nimport {\n buildCuratedFormSchema,\n FormHostProps,\n FormMode,\n} from '@memberjunction/interactive-component-types/forms';\nimport { ReactComponentEvent, MJReactComponent } from '@memberjunction/ng-react';\nimport {\n BaseEntity,\n CompositeKey,\n LogError,\n Metadata,\n RunView,\n} from '@memberjunction/core';\nimport { SharedService } from '@memberjunction/ng-shared';\nimport {\n ComponentStudioStateService,\n ComponentError\n} from '../../services/component-studio-state.service';\nimport { buildFixtureFormHostProps } from '../../services/form-host-props-fixture';\n\n/**\n * Viewport size preset for the component preview\n */\nexport type ViewportSize = 'mobile' | 'tablet' | 'desktop';\n\ninterface ViewportPreset {\n Size: ViewportSize;\n Label: string;\n Icon: string;\n MaxWidth: string;\n}\n\n/**\n * Component Preview - TOP section of CENTER panel.\n * Renders the live React component preview with toolbar controls.\n */\n@Component({\n standalone: false,\n selector: 'mj-component-preview',\n templateUrl: './component-preview.component.html',\n styleUrls: ['./component-preview.component.css']\n})\nexport class ComponentPreviewComponent implements OnInit, OnDestroy {\n\n @ViewChild('reactComponent') ReactComponentRef?: MJReactComponent;\n\n @Output() AskAIToFix = new EventEmitter<ComponentError>();\n\n // --- Viewport ---\n public ActiveViewport: ViewportSize = 'desktop';\n\n public readonly ViewportPresets: ViewportPreset[] = [\n { Size: 'mobile', Label: 'Mobile (375px)', Icon: 'fa-mobile-screen', MaxWidth: '375px' },\n { Size: 'tablet', Label: 'Tablet (768px)', Icon: 'fa-tablet-screen-button', MaxWidth: '768px' },\n { Size: 'desktop', Label: 'Desktop (100%)', Icon: 'fa-desktop', MaxWidth: '100%' }\n ];\n\n // --- Local spec for refresh cycle ---\n public LocalComponentSpec: ComponentSpec | null = null;\n\n // ----- Form-role preview controls (sandboxed) -----\n /** Recent records of the target entity for the optional real-record picker. */\n public RecentRecords: Array<{ ID: string; Display: string }> = [];\n public SelectedRecordID: string | null = null;\n /** When a real record is loaded, this holds its fields keyed by name. */\n public LoadedRecordValues: Record<string, unknown> | null = null;\n public IsLoadingRecord = false;\n /** Last 20 events emitted by the previewed component, newest first. */\n public EventLog: Array<{ Timestamp: Date; Type: string; Payload: string }> = [];\n\n private destroy$ = new Subject<void>();\n private lastLoadedEntity: string | null = null;\n\n constructor(\n public State: ComponentStudioStateService,\n private cdr: ChangeDetectorRef\n ) {}\n\n ngOnInit(): void {\n this.syncSpecFromState();\n\n this.State.StateChanged\n .pipe(takeUntil(this.destroy$))\n .subscribe(() => {\n this.syncSpecFromState();\n this.maybeRefreshRecentRecords();\n this.cdr.detectChanges();\n });\n\n this.State.RefreshComponent\n .pipe(takeUntil(this.destroy$))\n .subscribe(() => {\n this.refreshPreview();\n });\n\n this.maybeRefreshRecentRecords();\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n // ============================================================\n // TOOLBAR ACTIONS\n // ============================================================\n\n public RunSelectedComponent(): void {\n if (this.State.SelectedComponent) {\n this.State.RunComponent(this.State.SelectedComponent);\n }\n }\n\n public StopComponent(): void {\n MJReactComponent.forceClearRegistries();\n this.State.StopComponent();\n }\n\n public RefreshComponent(): void {\n if (this.State.SelectedComponent && this.State.IsRunning) {\n MJReactComponent.forceClearRegistries();\n this.refreshPreview();\n }\n }\n\n public SetViewport(size: ViewportSize): void {\n this.ActiveViewport = size;\n this.cdr.detectChanges();\n }\n\n public SendErrorToAI(): void {\n if (this.State.CurrentError) {\n this.AskAIToFix.emit(this.State.CurrentError);\n this.State.SendErrorToAI.emit(this.State.CurrentError);\n }\n }\n\n // ============================================================\n // VIEWPORT HELPERS\n // ============================================================\n\n public GetActivePreset(): ViewportPreset {\n return this.ViewportPresets.find(p => p.Size === this.ActiveViewport) || this.ViewportPresets[2];\n }\n\n public GetPreviewContainerMaxWidth(): string {\n return this.GetActivePreset().MaxWidth;\n }\n\n // ============================================================\n // REACT COMPONENT EVENTS\n // ============================================================\n\n public OnComponentEvent(event: ReactComponentEvent): void {\n if (event.type === 'error') {\n this.State.CurrentError = {\n type: event.payload?.source || 'Component Error',\n message: event.payload?.error || 'An error occurred while rendering the component',\n technicalDetails: event.payload?.errorInfo || event.payload\n };\n this.cdr.detectChanges();\n return;\n }\n // Form-role event sandbox — log BeforeSave / BeforeDelete /\n // FieldChanged events but never let them persist. The previewed\n // component should treat the response as a no-op.\n if (this.IsFormRolePreview) {\n this.logEvent(event.type, event.payload);\n this.cdr.detectChanges();\n }\n }\n\n // ============================================================\n // FORM PREVIEW HELPERS\n // ============================================================\n\n /** True when the current spec is form-role (drives the sandbox UI). */\n public get IsFormRolePreview(): boolean {\n const spec = this.LocalComponentSpec;\n return !!spec && (spec.componentRole === 'form' || spec.type === 'form');\n }\n\n /** Convenience for the template — the entity name the form binds to. */\n public get FormTargetEntity(): string | null {\n return this.State.FormTargetEntityName;\n }\n\n /** Selected preview mode (delegates to the shared state). */\n public get FormPreviewMode(): FormMode {\n return this.State.FormPreviewMode;\n }\n\n public SetFormPreviewMode(mode: FormMode): void {\n this.State.FormPreviewMode = mode;\n // Switching mode invalidates any loaded record diff — clear it so the\n // refreshed render starts fresh.\n if (mode === 'create') {\n this.SelectedRecordID = null;\n this.LoadedRecordValues = null;\n }\n this.refreshPreview();\n }\n\n /** Add an entry to the event log; keep the log bounded to 20 entries. */\n private logEvent(type: string, payload: unknown): void {\n const entry = {\n Timestamp: new Date(),\n Type: type,\n Payload: this.summarisePayload(payload),\n };\n this.EventLog = [entry, ...this.EventLog].slice(0, 20);\n }\n\n private summarisePayload(payload: unknown): string {\n if (payload == null) return '—';\n try {\n const s = JSON.stringify(payload);\n return s.length > 200 ? s.slice(0, 200) + '…' : s;\n } catch {\n return String(payload);\n }\n }\n\n public ClearEventLog(): void {\n this.EventLog = [];\n this.cdr.detectChanges();\n }\n\n /**\n * Load the top 10 most-recent records for the target entity so the\n * preview can swap from fixture to real-record mode. Re-runs whenever\n * the target entity changes; quiet no-op if entity isn't set yet.\n */\n private async maybeRefreshRecentRecords(): Promise<void> {\n const entityName = this.State.FormTargetEntityName;\n if (!entityName || entityName === this.lastLoadedEntity) return;\n this.lastLoadedEntity = entityName;\n this.RecentRecords = [];\n try {\n const rv = RunView.FromMetadataProvider(this.State.Provider);\n const entityInfo = this.State.Provider.EntityByName(entityName);\n const nameField = entityInfo?.NameField?.Name ?? 'ID';\n const fields = nameField === 'ID' ? ['ID'] : ['ID', nameField];\n const result = await rv.RunView<Record<string, unknown>>({\n EntityName: entityName,\n Fields: fields,\n OrderBy: '__mj_UpdatedAt DESC',\n MaxRows: 10,\n ResultType: 'simple',\n });\n if (result.Success && Array.isArray(result.Results)) {\n this.RecentRecords = result.Results.map(r => ({\n ID: String(r['ID'] ?? ''),\n Display: String(r[nameField] ?? r['ID'] ?? ''),\n })).filter(r => r.ID.length > 0);\n }\n } catch (err) {\n LogError(`ComponentPreview.maybeRefreshRecentRecords: ${err instanceof Error ? err.message : String(err)}`);\n }\n this.cdr.detectChanges();\n }\n\n /**\n * Load a real record for preview. We pull the full entity object then\n * extract its field values into a plain object for FormHostProps.\n * Sandboxed — any BeforeSave/BeforeDelete events emitted by the previewed\n * component are logged, never applied.\n */\n public async OnPickRecord(event: Event): Promise<void> {\n const id = (event.target as HTMLSelectElement).value || null;\n this.SelectedRecordID = id;\n if (!id) {\n this.LoadedRecordValues = null;\n this.refreshPreview();\n return;\n }\n const entityName = this.State.FormTargetEntityName;\n if (!entityName) return;\n this.IsLoadingRecord = true;\n this.cdr.detectChanges();\n try {\n const provider = this.State.Provider;\n const entity = await provider.GetEntityObject<BaseEntity>(entityName, provider.CurrentUser);\n const compositeKey = CompositeKey.FromID(id);\n const loaded = await entity.InnerLoad(compositeKey);\n if (loaded) {\n const values: Record<string, unknown> = {};\n for (const f of entity.Fields) {\n values[f.Name] = f.Value;\n }\n this.LoadedRecordValues = values;\n } else {\n this.LoadedRecordValues = null;\n }\n } catch (err) {\n LogError(`ComponentPreview.OnPickRecord: ${err instanceof Error ? err.message : String(err)}`);\n this.LoadedRecordValues = null;\n } finally {\n this.IsLoadingRecord = false;\n }\n this.refreshPreview();\n }\n\n /**\n * Fires once the React bridge has resolved the full component hierarchy from the\n * registry. The bridge stores the resolved spec (with real dependency code, not\n * registry-reference stubs) on its public `resolvedComponentSpec` field — pull it\n * across so the code-editor tabs can render actual source instead of \"No code available\".\n */\n public OnReactInitialized(): void {\n const resolvedSpec = this.ReactComponentRef?.resolvedComponentSpec;\n if (resolvedSpec) {\n this.State.UpdateWithResolvedSpec(resolvedSpec);\n this.cdr.detectChanges();\n }\n }\n\n public OnOpenEntityRecord(event: { entityName: string; key: CompositeKey }): void {\n SharedService.Instance.OpenEntityRecord(event.entityName, event.key);\n }\n\n // ============================================================\n // STATE HELPERS\n // ============================================================\n\n public GetComponentName(): string {\n if (!this.State.SelectedComponent) return '';\n return this.State.GetComponentName(this.State.SelectedComponent);\n }\n\n public GetComponentDescription(): string | undefined {\n if (!this.State.SelectedComponent) return undefined;\n return this.State.GetComponentDescription(this.State.SelectedComponent);\n }\n\n // ============================================================\n // PRIVATE\n // ============================================================\n\n private syncSpecFromState(): void {\n this.LocalComponentSpec = this.State.ComponentSpec;\n }\n\n /**\n * Fixture `FormHostProps` for form-role component previews. Built from\n * the curated schema of `State.FormTargetEntityName` — the entity the\n * user picked in the Field Binding Inspector. Returns an empty object\n * when (a) the current spec isn't a form, (b) no target entity is\n * selected, or (c) the entity isn't registered with the provider — in\n * which case the previewed component sees `record === undefined` and\n * should handle that gracefully (the Studio skeleton does).\n *\n * The mode toggles to 'edit' so authors can see how inputs render\n * without manually flipping mode each refresh.\n */\n public get FixtureFormHostProps(): Partial<FormHostProps> | object {\n const spec = this.LocalComponentSpec;\n if (!spec || (spec.componentRole !== 'form' && spec.type !== 'form')) {\n return {};\n }\n const entityName = this.State.FormTargetEntityName;\n if (!entityName) {\n return {};\n }\n const provider = this.State.Provider;\n if (!provider) return {};\n const schema = buildCuratedFormSchema(entityName, provider);\n if (!schema) return {};\n const mode = this.State.FormPreviewMode;\n const fixture = buildFixtureFormHostProps(schema, mode);\n\n // If the user picked a real record, overlay its field values on top of\n // the fixture (which has the right shape for entityMetadata + caps).\n // The record is still sandboxed — events fired by the previewed\n // component never reach a Save().\n if (this.LoadedRecordValues && mode !== 'create') {\n return {\n ...fixture,\n record: this.LoadedRecordValues,\n primaryKey: this.SelectedRecordID\n ? { ID: this.SelectedRecordID }\n : fixture.primaryKey,\n };\n }\n return fixture;\n }\n\n /**\n * Refresh the preview by nulling the spec, detecting changes,\n * then restoring the spec after a short delay. The bridge's own\n * `initializeComponent` purges the runtime registry + manager fetch cache\n * for the new spec's keys, so consumers don't need to clear anything here.\n */\n private refreshPreview(): void {\n if (!this.State.SelectedComponent) return;\n\n const spec = this.State.ComponentSpec;\n\n // Null out to force React to unmount\n this.LocalComponentSpec = null;\n this.cdr.detectChanges();\n\n // Re-set after a brief pause to force fresh mount\n setTimeout(() => {\n this.LocalComponentSpec = spec;\n this.State.ComponentSpec = spec;\n this.State.CurrentError = null;\n try {\n this.cdr.detectChanges();\n } catch (error) {\n console.error('Error during refresh detectChanges:', error);\n }\n }, 10);\n }\n}\n","<div class=\"component-preview\">\n <!-- Toolbar -->\n <div class=\"preview-toolbar\">\n <div class=\"toolbar-left\">\n @if (State.SelectedComponent) {\n @if (State.IsRunning) {\n <button class=\"toolbar-btn stop-btn\" (click)=\"StopComponent()\" title=\"Stop component\">\n <i class=\"fa-solid fa-stop\"></i>\n <span>Stop</span>\n </button>\n <button class=\"toolbar-btn\" (click)=\"RefreshComponent()\" title=\"Refresh component\">\n <i class=\"fa-solid fa-rotate-right\"></i>\n <span>Refresh</span>\n </button>\n } @else {\n <button class=\"toolbar-btn run-btn\" (click)=\"RunSelectedComponent()\" title=\"Run component\">\n <i class=\"fa-solid fa-play\"></i>\n <span>Run</span>\n </button>\n }\n }\n </div>\n\n <div class=\"toolbar-center\">\n <!-- Viewport Size Selector (segmented control) -->\n @if (State.IsRunning) {\n <div class=\"viewport-selector\">\n @for (preset of ViewportPresets; track preset.Size) {\n <button\n class=\"viewport-btn\"\n [class.active]=\"ActiveViewport === preset.Size\"\n (click)=\"SetViewport(preset.Size)\"\n [title]=\"preset.Label\">\n <i class=\"fa-solid\" [ngClass]=\"preset.Icon\"></i>\n </button>\n }\n </div>\n }\n </div>\n\n <div class=\"toolbar-right\">\n @if (State.CurrentError) {\n <button class=\"toolbar-btn ai-fix-btn\" (click)=\"SendErrorToAI()\" title=\"Ask AI to fix this error\">\n <i class=\"fa-solid fa-wand-magic-sparkles\"></i>\n <span>Ask AI to Fix</span>\n </button>\n }\n @if (State.IsRunning && State.SelectedComponent) {\n <span class=\"running-indicator\">\n <i class=\"fa-solid fa-circle running-dot\"></i>\n {{ GetComponentName() }}\n </span>\n }\n </div>\n </div>\n\n <!-- Form-role preview controls (banner + mode + real-record picker).\n Visible only for componentRole==='form' components, since they're\n the only ones that bind to a record. -->\n @if (IsFormRolePreview && State.IsRunning) {\n <div class=\"form-preview-bar\">\n <div class=\"form-preview-banner\">\n <i class=\"fa-solid fa-shield-halved\"></i>\n PREVIEW — changes will not be saved\n </div>\n <div class=\"form-preview-controls\">\n <!-- Mode pills synced with the Form Builder tab -->\n <div class=\"form-mode-pills\">\n <button class=\"form-mode-pill\"\n [class.active]=\"FormPreviewMode === 'view'\"\n (click)=\"SetFormPreviewMode('view')\">View</button>\n <button class=\"form-mode-pill\"\n [class.active]=\"FormPreviewMode === 'edit'\"\n (click)=\"SetFormPreviewMode('edit')\">Edit</button>\n <button class=\"form-mode-pill\"\n [class.active]=\"FormPreviewMode === 'create'\"\n (click)=\"SetFormPreviewMode('create')\">Create</button>\n </div>\n\n <!-- Real-record picker; null = fixture data -->\n @if (FormPreviewMode !== 'create' && FormTargetEntity) {\n <div class=\"form-record-picker\">\n <label>Record</label>\n <select [value]=\"SelectedRecordID ?? ''\" (change)=\"OnPickRecord($event)\">\n <option value=\"\">— Fixture data —</option>\n @for (r of RecentRecords; track r.ID) {\n <option [value]=\"r.ID\">{{ r.Display }}</option>\n }\n </select>\n @if (IsLoadingRecord) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n }\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Preview Area -->\n <div class=\"preview-area\">\n @if (!State.SelectedComponent) {\n <!-- Empty State: No component selected -->\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-eye fa-3x\"></i>\n <h3>Select a component to preview</h3>\n <p>Choose a component from the sidebar to see its live preview here.</p>\n </div>\n } @else if (!State.IsRunning) {\n <!-- Component selected but not running -->\n <div class=\"empty-state run-state\">\n <i class=\"fa-solid fa-play-circle fa-3x\"></i>\n <h3>{{ GetComponentName() }}</h3>\n <p>{{ GetComponentDescription() || 'No description available' }}</p>\n <button class=\"run-component-btn\" (click)=\"RunSelectedComponent()\">\n <i class=\"fa-solid fa-play\"></i> Run Component\n </button>\n </div>\n } @else if (LocalComponentSpec) {\n <!-- Live Preview Container -->\n <div class=\"preview-container\"\n [style.max-width]=\"GetPreviewContainerMaxWidth()\"\n [class.mobile]=\"ActiveViewport === 'mobile'\"\n [class.tablet]=\"ActiveViewport === 'tablet'\"\n [class.desktop]=\"ActiveViewport === 'desktop'\">\n <mj-react-component\n #reactComponent\n [component]=\"LocalComponentSpec\"\n [componentProps]=\"FixtureFormHostProps\"\n (componentEvent)=\"OnComponentEvent($event)\"\n (initialized)=\"OnReactInitialized()\"\n (openEntityRecord)=\"OnOpenEntityRecord($event)\">\n </mj-react-component>\n </div>\n\n <!-- Form-role sandboxed event log -->\n @if (IsFormRolePreview && EventLog.length > 0) {\n <div class=\"form-event-log\">\n <div class=\"form-event-log-header\">\n <i class=\"fa-solid fa-list\"></i>\n <span>Events (sandboxed)</span>\n <span class=\"spacer\"></span>\n <button class=\"form-event-log-clear\" (click)=\"ClearEventLog()\">Clear</button>\n </div>\n <ul class=\"form-event-log-list\">\n @for (e of EventLog; track $index) {\n <li class=\"form-event-log-row\">\n <span class=\"form-event-log-ts\">{{ e.Timestamp | date:'HH:mm:ss' }}</span>\n <span class=\"form-event-log-type\">{{ e.Type }}</span>\n <span class=\"form-event-log-payload\">{{ e.Payload }}</span>\n </li>\n }\n </ul>\n </div>\n }\n\n <!-- Error Overlay (inline, does not replace the component) -->\n @if (State.CurrentError) {\n <div class=\"error-overlay\">\n <div class=\"error-overlay-content\">\n <div class=\"error-overlay-header\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span class=\"error-overlay-title\">{{ State.CurrentError.type }}</span>\n </div>\n <p class=\"error-overlay-message\">{{ State.CurrentError.message }}</p>\n <div class=\"error-overlay-actions\">\n <button class=\"toolbar-btn\" (click)=\"RefreshComponent()\">\n <i class=\"fa-solid fa-rotate-right\"></i> Retry\n </button>\n <button class=\"toolbar-btn ai-fix-btn\" (click)=\"SendErrorToAI()\">\n <i class=\"fa-solid fa-wand-magic-sparkles\"></i> Ask AI to Fix\n </button>\n </div>\n </div>\n </div>\n }\n }\n </div>\n</div>\n"]}
|
|
@@ -5,10 +5,20 @@ export declare class EditorTabsComponent implements OnInit, OnDestroy {
|
|
|
5
5
|
state: ComponentStudioStateService;
|
|
6
6
|
private cdr;
|
|
7
7
|
private stateChangedSub;
|
|
8
|
+
/** Tracked so we can default to the Form Builder tab the first time a form-role component loads. */
|
|
9
|
+
private lastFormRole;
|
|
8
10
|
constructor(state: ComponentStudioStateService, cdr: ChangeDetectorRef);
|
|
9
11
|
ngOnInit(): void;
|
|
10
12
|
ngOnDestroy(): void;
|
|
11
13
|
SelectTab(index: number): void;
|
|
14
|
+
/** True iff the current spec declares itself form-role. */
|
|
15
|
+
get IsFormRoleComponent(): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Auto-select the Form Builder tab the first time a form-role component
|
|
18
|
+
* appears in state. Don't fight the user after that — if they switched
|
|
19
|
+
* to Code or Spec, leave them there on subsequent state updates.
|
|
20
|
+
*/
|
|
21
|
+
private maybeAutoSelectFormBuilder;
|
|
12
22
|
static ɵfac: i0.ɵɵFactoryDeclaration<EditorTabsComponent, never>;
|
|
13
23
|
static ɵcmp: i0.ɵɵComponentDeclaration<EditorTabsComponent, "mj-editor-tabs", never, {}, {}, never, never, false, never>;
|
|
14
24
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor-tabs.component.d.ts","sourceRoot":"","sources":["../../../../src/ComponentStudio/components/workspace/editor-tabs.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"editor-tabs.component.d.ts","sourceRoot":"","sources":["../../../../src/ComponentStudio/components/workspace/editor-tabs.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGhF,OAAO,EAAE,2BAA2B,EAAE,MAAM,+CAA+C,CAAC;;AAc5F,qBAgIa,mBAAoB,YAAW,MAAM,EAAE,SAAS;IAOlD,KAAK,EAAE,2BAA2B;IACzC,OAAO,CAAC,GAAG;IANb,OAAO,CAAC,eAAe,CAA6B;IACpD,oGAAoG;IACpG,OAAO,CAAC,YAAY,CAAS;gBAGpB,KAAK,EAAE,2BAA2B,EACjC,GAAG,EAAE,iBAAiB;IAGhC,QAAQ,IAAI,IAAI;IAShB,WAAW,IAAI,IAAI;IAOnB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK9B,2DAA2D;IAC3D,IAAW,mBAAmB,IAAI,OAAO,CAGxC;IAED;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;yCA3CvB,mBAAmB;2CAAnB,mBAAmB;CAwD/B"}
|
|
@@ -5,35 +5,69 @@ import * as i2 from "../editors/spec-editor.component";
|
|
|
5
5
|
import * as i3 from "../editors/code-editor-panel.component";
|
|
6
6
|
import * as i4 from "../editors/requirements-editor.component";
|
|
7
7
|
import * as i5 from "../editors/data-requirements-editor.component";
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
import * as i6 from "../form-builder/form-builder-tab.component";
|
|
9
|
+
function EditorTabsComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
10
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
11
|
+
i0.ɵɵelementStart(0, "button", 3);
|
|
12
|
+
i0.ɵɵlistener("click", function EditorTabsComponent_Conditional_2_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SelectTab(5)); });
|
|
13
|
+
i0.ɵɵelement(1, "i", 12);
|
|
14
|
+
i0.ɵɵtext(2, " Form Builder ");
|
|
15
|
+
i0.ɵɵelementEnd();
|
|
16
|
+
} if (rf & 2) {
|
|
17
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
18
|
+
i0.ɵɵclassProp("active", ctx_r1.state.ActiveTab === 5);
|
|
10
19
|
} }
|
|
11
20
|
function EditorTabsComponent_Case_20_Template(rf, ctx) { if (rf & 1) {
|
|
12
|
-
i0.ɵɵelement(0, "mj-
|
|
21
|
+
i0.ɵɵelement(0, "mj-spec-editor");
|
|
13
22
|
} }
|
|
14
23
|
function EditorTabsComponent_Case_21_Template(rf, ctx) { if (rf & 1) {
|
|
15
|
-
i0.ɵɵelement(0, "mj-
|
|
24
|
+
i0.ɵɵelement(0, "mj-code-editor-panel");
|
|
25
|
+
} }
|
|
26
|
+
function EditorTabsComponent_Case_22_Template(rf, ctx) { if (rf & 1) {
|
|
27
|
+
i0.ɵɵelement(0, "mj-requirements-editor", 11);
|
|
16
28
|
} if (rf & 2) {
|
|
17
29
|
i0.ɵɵproperty("Field", "functionalRequirements")("Title", "Functional Requirements");
|
|
18
30
|
} }
|
|
19
|
-
function
|
|
20
|
-
i0.ɵɵelement(0, "mj-requirements-editor",
|
|
31
|
+
function EditorTabsComponent_Case_23_Template(rf, ctx) { if (rf & 1) {
|
|
32
|
+
i0.ɵɵelement(0, "mj-requirements-editor", 11);
|
|
21
33
|
} if (rf & 2) {
|
|
22
34
|
i0.ɵɵproperty("Field", "technicalDesign")("Title", "Technical Design");
|
|
23
35
|
} }
|
|
24
|
-
function
|
|
36
|
+
function EditorTabsComponent_Case_24_Template(rf, ctx) { if (rf & 1) {
|
|
25
37
|
i0.ɵɵelement(0, "mj-data-requirements-editor");
|
|
26
38
|
} }
|
|
39
|
+
function EditorTabsComponent_Case_25_Template(rf, ctx) { if (rf & 1) {
|
|
40
|
+
const _r3 = i0.ɵɵgetCurrentView();
|
|
41
|
+
i0.ɵɵelementStart(0, "mj-form-builder-tab", 13);
|
|
42
|
+
i0.ɵɵlistener("RequestCodeTab", function EditorTabsComponent_Case_25_Template_mj_form_builder_tab_RequestCodeTab_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SelectTab(1)); });
|
|
43
|
+
i0.ɵɵelementEnd();
|
|
44
|
+
} }
|
|
45
|
+
/**
|
|
46
|
+
* Tab index constants. The Form Builder tab is conditional — it only shows
|
|
47
|
+
* up for form-role components — so we key tabs by stable index rather than
|
|
48
|
+
* position-in-array. State service stores ActiveTab as the numeric index.
|
|
49
|
+
*/
|
|
50
|
+
const TAB_SPEC = 0;
|
|
51
|
+
const TAB_CODE = 1;
|
|
52
|
+
const TAB_REQUIREMENTS = 2;
|
|
53
|
+
const TAB_DESIGN = 3;
|
|
54
|
+
const TAB_DATA = 4;
|
|
55
|
+
const TAB_FORM_BUILDER = 5;
|
|
27
56
|
export class EditorTabsComponent {
|
|
28
57
|
state;
|
|
29
58
|
cdr;
|
|
30
59
|
stateChangedSub = null;
|
|
60
|
+
/** Tracked so we can default to the Form Builder tab the first time a form-role component loads. */
|
|
61
|
+
lastFormRole = false;
|
|
31
62
|
constructor(state, cdr) {
|
|
32
63
|
this.state = state;
|
|
33
64
|
this.cdr = cdr;
|
|
34
65
|
}
|
|
35
66
|
ngOnInit() {
|
|
67
|
+
this.lastFormRole = this.IsFormRoleComponent;
|
|
68
|
+
this.maybeAutoSelectFormBuilder();
|
|
36
69
|
this.stateChangedSub = this.state.StateChanged.subscribe(() => {
|
|
70
|
+
this.maybeAutoSelectFormBuilder();
|
|
37
71
|
this.cdr.detectChanges();
|
|
38
72
|
});
|
|
39
73
|
}
|
|
@@ -47,41 +81,68 @@ export class EditorTabsComponent {
|
|
|
47
81
|
this.state.ActiveTab = index;
|
|
48
82
|
this.cdr.detectChanges();
|
|
49
83
|
}
|
|
84
|
+
/** True iff the current spec declares itself form-role. */
|
|
85
|
+
get IsFormRoleComponent() {
|
|
86
|
+
const spec = this.state.GetCurrentSpec();
|
|
87
|
+
return spec?.componentRole === 'form' || spec?.type === 'form';
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Auto-select the Form Builder tab the first time a form-role component
|
|
91
|
+
* appears in state. Don't fight the user after that — if they switched
|
|
92
|
+
* to Code or Spec, leave them there on subsequent state updates.
|
|
93
|
+
*/
|
|
94
|
+
maybeAutoSelectFormBuilder() {
|
|
95
|
+
const isForm = this.IsFormRoleComponent;
|
|
96
|
+
if (isForm && !this.lastFormRole) {
|
|
97
|
+
this.state.ActiveTab = TAB_FORM_BUILDER;
|
|
98
|
+
}
|
|
99
|
+
else if (!isForm && this.lastFormRole) {
|
|
100
|
+
// If we leave a form-role component, drop back to Spec.
|
|
101
|
+
if (this.state.ActiveTab === TAB_FORM_BUILDER) {
|
|
102
|
+
this.state.ActiveTab = TAB_SPEC;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
this.lastFormRole = isForm;
|
|
106
|
+
}
|
|
50
107
|
static ɵfac = function EditorTabsComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EditorTabsComponent)(i0.ɵɵdirectiveInject(i1.ComponentStudioStateService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
|
|
51
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EditorTabsComponent, selectors: [["mj-editor-tabs"]], standalone: false, decls:
|
|
52
|
-
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)
|
|
53
|
-
i0.ɵɵ
|
|
54
|
-
i0.ɵɵ
|
|
55
|
-
i0.ɵɵ
|
|
108
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EditorTabsComponent, selectors: [["mj-editor-tabs"]], standalone: false, decls: 26, vars: 12, consts: [[1, "editor-tabs-container"], [1, "tab-bar"], [1, "tab-pill", 3, "active"], [1, "tab-pill", 3, "click"], [1, "fa-solid", "fa-file-code"], [1, "fa-solid", "fa-code"], [1, "fa-solid", "fa-clipboard-list"], [1, "fa-solid", "fa-drafting-compass"], [1, "fa-solid", "fa-database"], [1, "tab-spacer"], [1, "tab-content"], [3, "Field", "Title"], [1, "fa-solid", "fa-table-list"], [3, "RequestCodeTab"]], template: function EditorTabsComponent_Template(rf, ctx) { if (rf & 1) {
|
|
109
|
+
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1);
|
|
110
|
+
i0.ɵɵconditionalCreate(2, EditorTabsComponent_Conditional_2_Template, 3, 2, "button", 2);
|
|
111
|
+
i0.ɵɵelementStart(3, "button", 3);
|
|
112
|
+
i0.ɵɵlistener("click", function EditorTabsComponent_Template_button_click_3_listener() { return ctx.SelectTab(0); });
|
|
113
|
+
i0.ɵɵelement(4, "i", 4);
|
|
114
|
+
i0.ɵɵtext(5, " Spec ");
|
|
56
115
|
i0.ɵɵelementEnd();
|
|
57
|
-
i0.ɵɵelementStart(
|
|
58
|
-
i0.ɵɵlistener("click", function
|
|
59
|
-
i0.ɵɵelement(
|
|
60
|
-
i0.ɵɵtext(
|
|
116
|
+
i0.ɵɵelementStart(6, "button", 3);
|
|
117
|
+
i0.ɵɵlistener("click", function EditorTabsComponent_Template_button_click_6_listener() { return ctx.SelectTab(1); });
|
|
118
|
+
i0.ɵɵelement(7, "i", 5);
|
|
119
|
+
i0.ɵɵtext(8, " Code ");
|
|
61
120
|
i0.ɵɵelementEnd();
|
|
62
|
-
i0.ɵɵelementStart(
|
|
63
|
-
i0.ɵɵlistener("click", function
|
|
64
|
-
i0.ɵɵelement(
|
|
65
|
-
i0.ɵɵtext(
|
|
121
|
+
i0.ɵɵelementStart(9, "button", 3);
|
|
122
|
+
i0.ɵɵlistener("click", function EditorTabsComponent_Template_button_click_9_listener() { return ctx.SelectTab(2); });
|
|
123
|
+
i0.ɵɵelement(10, "i", 6);
|
|
124
|
+
i0.ɵɵtext(11, " Requirements ");
|
|
66
125
|
i0.ɵɵelementEnd();
|
|
67
|
-
i0.ɵɵelementStart(
|
|
68
|
-
i0.ɵɵlistener("click", function
|
|
69
|
-
i0.ɵɵelement(
|
|
70
|
-
i0.ɵɵtext(
|
|
126
|
+
i0.ɵɵelementStart(12, "button", 3);
|
|
127
|
+
i0.ɵɵlistener("click", function EditorTabsComponent_Template_button_click_12_listener() { return ctx.SelectTab(3); });
|
|
128
|
+
i0.ɵɵelement(13, "i", 7);
|
|
129
|
+
i0.ɵɵtext(14, " Design ");
|
|
71
130
|
i0.ɵɵelementEnd();
|
|
72
|
-
i0.ɵɵelementStart(
|
|
73
|
-
i0.ɵɵlistener("click", function
|
|
74
|
-
i0.ɵɵelement(
|
|
75
|
-
i0.ɵɵtext(
|
|
131
|
+
i0.ɵɵelementStart(15, "button", 3);
|
|
132
|
+
i0.ɵɵlistener("click", function EditorTabsComponent_Template_button_click_15_listener() { return ctx.SelectTab(4); });
|
|
133
|
+
i0.ɵɵelement(16, "i", 8);
|
|
134
|
+
i0.ɵɵtext(17, " Data ");
|
|
76
135
|
i0.ɵɵelementEnd();
|
|
77
|
-
i0.ɵɵelement(
|
|
136
|
+
i0.ɵɵelement(18, "span", 9);
|
|
78
137
|
i0.ɵɵelementEnd();
|
|
79
|
-
i0.ɵɵelementStart(
|
|
80
|
-
i0.ɵɵconditionalCreate(
|
|
138
|
+
i0.ɵɵelementStart(19, "div", 10);
|
|
139
|
+
i0.ɵɵconditionalCreate(20, EditorTabsComponent_Case_20_Template, 1, 0, "mj-spec-editor")(21, EditorTabsComponent_Case_21_Template, 1, 0, "mj-code-editor-panel")(22, EditorTabsComponent_Case_22_Template, 1, 2, "mj-requirements-editor", 11)(23, EditorTabsComponent_Case_23_Template, 1, 2, "mj-requirements-editor", 11)(24, EditorTabsComponent_Case_24_Template, 1, 0, "mj-data-requirements-editor")(25, EditorTabsComponent_Case_25_Template, 1, 0, "mj-form-builder-tab");
|
|
81
140
|
i0.ɵɵelementEnd()();
|
|
82
141
|
} if (rf & 2) {
|
|
83
|
-
let
|
|
142
|
+
let tmp_6_0;
|
|
84
143
|
i0.ɵɵadvance(2);
|
|
144
|
+
i0.ɵɵconditional(ctx.IsFormRoleComponent ? 2 : -1);
|
|
145
|
+
i0.ɵɵadvance();
|
|
85
146
|
i0.ɵɵclassProp("active", ctx.state.ActiveTab === 0);
|
|
86
147
|
i0.ɵɵadvance(3);
|
|
87
148
|
i0.ɵɵclassProp("active", ctx.state.ActiveTab === 1);
|
|
@@ -92,27 +153,32 @@ export class EditorTabsComponent {
|
|
|
92
153
|
i0.ɵɵadvance(3);
|
|
93
154
|
i0.ɵɵclassProp("active", ctx.state.ActiveTab === 4);
|
|
94
155
|
i0.ɵɵadvance(5);
|
|
95
|
-
i0.ɵɵconditional((
|
|
96
|
-
} }, dependencies: [i2.SpecEditorComponent, i3.CodeEditorPanelComponent, i4.RequirementsEditorComponent, i5.DataRequirementsEditorComponent], styles: ["[_nghost-%COMP%] {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n\n .editor-tabs-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n flex: 1;\n overflow: hidden;\n }\n\n .tab-bar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 0 8px;\n height: 38px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 2px;\n }\n\n .tab-pill[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 5px 12px;\n border: none;\n border-radius: 8px;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n font-family: inherit;\n }\n\n .tab-pill[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n }\n\n .tab-pill.active[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n font-weight: 600;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n }\n\n .tab-pill[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n }\n\n .tab-spacer[_ngcontent-%COMP%] {\n flex: 1;\n }\n\n .tab-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .tab-content[_ngcontent-%COMP%] > *[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n }"] });
|
|
156
|
+
i0.ɵɵconditional((tmp_6_0 = ctx.state.ActiveTab) === 0 ? 20 : tmp_6_0 === 1 ? 21 : tmp_6_0 === 2 ? 22 : tmp_6_0 === 3 ? 23 : tmp_6_0 === 4 ? 24 : tmp_6_0 === 5 ? 25 : -1);
|
|
157
|
+
} }, dependencies: [i2.SpecEditorComponent, i3.CodeEditorPanelComponent, i4.RequirementsEditorComponent, i5.DataRequirementsEditorComponent, i6.FormBuilderTabComponent], styles: ["[_nghost-%COMP%] {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n\n .editor-tabs-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n flex: 1;\n overflow: hidden;\n }\n\n .tab-bar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 0 8px;\n height: 38px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 2px;\n }\n\n .tab-pill[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 5px 12px;\n border: none;\n border-radius: 8px;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n font-family: inherit;\n }\n\n .tab-pill[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n }\n\n .tab-pill.active[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n font-weight: 600;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n }\n\n .tab-pill[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n }\n\n .tab-spacer[_ngcontent-%COMP%] {\n flex: 1;\n }\n\n .tab-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .tab-content[_ngcontent-%COMP%] > *[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n }"] });
|
|
97
158
|
}
|
|
98
159
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EditorTabsComponent, [{
|
|
99
160
|
type: Component,
|
|
100
161
|
args: [{ standalone: false, selector: 'mj-editor-tabs', template: `
|
|
101
162
|
<div class="editor-tabs-container">
|
|
102
163
|
<div class="tab-bar">
|
|
103
|
-
|
|
164
|
+
@if (IsFormRoleComponent) {
|
|
165
|
+
<button class="tab-pill" [class.active]="state.ActiveTab === ${TAB_FORM_BUILDER}" (click)="SelectTab(${TAB_FORM_BUILDER})">
|
|
166
|
+
<i class="fa-solid fa-table-list"></i> Form Builder
|
|
167
|
+
</button>
|
|
168
|
+
}
|
|
169
|
+
<button class="tab-pill" [class.active]="state.ActiveTab === ${TAB_SPEC}" (click)="SelectTab(${TAB_SPEC})">
|
|
104
170
|
<i class="fa-solid fa-file-code"></i> Spec
|
|
105
171
|
</button>
|
|
106
|
-
<button class="tab-pill" [class.active]="state.ActiveTab ===
|
|
172
|
+
<button class="tab-pill" [class.active]="state.ActiveTab === ${TAB_CODE}" (click)="SelectTab(${TAB_CODE})">
|
|
107
173
|
<i class="fa-solid fa-code"></i> Code
|
|
108
174
|
</button>
|
|
109
|
-
<button class="tab-pill" [class.active]="state.ActiveTab ===
|
|
175
|
+
<button class="tab-pill" [class.active]="state.ActiveTab === ${TAB_REQUIREMENTS}" (click)="SelectTab(${TAB_REQUIREMENTS})">
|
|
110
176
|
<i class="fa-solid fa-clipboard-list"></i> Requirements
|
|
111
177
|
</button>
|
|
112
|
-
<button class="tab-pill" [class.active]="state.ActiveTab ===
|
|
178
|
+
<button class="tab-pill" [class.active]="state.ActiveTab === ${TAB_DESIGN}" (click)="SelectTab(${TAB_DESIGN})">
|
|
113
179
|
<i class="fa-solid fa-drafting-compass"></i> Design
|
|
114
180
|
</button>
|
|
115
|
-
<button class="tab-pill" [class.active]="state.ActiveTab ===
|
|
181
|
+
<button class="tab-pill" [class.active]="state.ActiveTab === ${TAB_DATA}" (click)="SelectTab(${TAB_DATA})">
|
|
116
182
|
<i class="fa-solid fa-database"></i> Data
|
|
117
183
|
</button>
|
|
118
184
|
<span class="tab-spacer"></span>
|
|
@@ -120,25 +186,28 @@ export class EditorTabsComponent {
|
|
|
120
186
|
|
|
121
187
|
<div class="tab-content">
|
|
122
188
|
@switch (state.ActiveTab) {
|
|
123
|
-
@case (
|
|
189
|
+
@case (${TAB_SPEC}) {
|
|
124
190
|
<mj-spec-editor></mj-spec-editor>
|
|
125
191
|
}
|
|
126
|
-
@case (
|
|
192
|
+
@case (${TAB_CODE}) {
|
|
127
193
|
<mj-code-editor-panel></mj-code-editor-panel>
|
|
128
194
|
}
|
|
129
|
-
@case (
|
|
195
|
+
@case (${TAB_REQUIREMENTS}) {
|
|
130
196
|
<mj-requirements-editor [Field]="'functionalRequirements'" [Title]="'Functional Requirements'"></mj-requirements-editor>
|
|
131
197
|
}
|
|
132
|
-
@case (
|
|
198
|
+
@case (${TAB_DESIGN}) {
|
|
133
199
|
<mj-requirements-editor [Field]="'technicalDesign'" [Title]="'Technical Design'"></mj-requirements-editor>
|
|
134
200
|
}
|
|
135
|
-
@case (
|
|
201
|
+
@case (${TAB_DATA}) {
|
|
136
202
|
<mj-data-requirements-editor></mj-data-requirements-editor>
|
|
137
203
|
}
|
|
204
|
+
@case (${TAB_FORM_BUILDER}) {
|
|
205
|
+
<mj-form-builder-tab (RequestCodeTab)="SelectTab(${TAB_CODE})"></mj-form-builder-tab>
|
|
206
|
+
}
|
|
138
207
|
}
|
|
139
208
|
</div>
|
|
140
209
|
</div>
|
|
141
210
|
`, styles: ["\n :host {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n\n .editor-tabs-container {\n display: flex;\n flex-direction: column;\n flex: 1;\n overflow: hidden;\n }\n\n .tab-bar {\n display: flex;\n align-items: center;\n padding: 0 8px;\n height: 38px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 2px;\n }\n\n .tab-pill {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 5px 12px;\n border: none;\n border-radius: 8px;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n font-family: inherit;\n }\n\n .tab-pill:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n }\n\n .tab-pill.active {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n font-weight: 600;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n }\n\n .tab-pill i {\n font-size: 11px;\n }\n\n .tab-spacer {\n flex: 1;\n }\n\n .tab-content {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .tab-content > * {\n flex: 1;\n overflow: hidden;\n }\n "] }]
|
|
142
211
|
}], () => [{ type: i1.ComponentStudioStateService }, { type: i0.ChangeDetectorRef }], null); })();
|
|
143
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EditorTabsComponent, { className: "EditorTabsComponent", filePath: "src/ComponentStudio/components/workspace/editor-tabs.component.ts", lineNumber:
|
|
212
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EditorTabsComponent, { className: "EditorTabsComponent", filePath: "src/ComponentStudio/components/workspace/editor-tabs.component.ts", lineNumber: 146 }); })();
|
|
144
213
|
//# sourceMappingURL=editor-tabs.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor-tabs.component.js","sourceRoot":"","sources":["../../../../src/ComponentStudio/components/workspace/editor-tabs.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAwC,MAAM,eAAe,CAAC
|
|
1
|
+
{"version":3,"file":"editor-tabs.component.js","sourceRoot":"","sources":["../../../../src/ComponentStudio/components/workspace/editor-tabs.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';\nimport { Subscription } from 'rxjs';\nimport { ComponentSpec } from '@memberjunction/interactive-component-types';\nimport { ComponentStudioStateService } from '../../services/component-studio-state.service';\n\n/**\n * Tab index constants. The Form Builder tab is conditional — it only shows\n * up for form-role components — so we key tabs by stable index rather than\n * position-in-array. State service stores ActiveTab as the numeric index.\n */\nconst TAB_SPEC = 0;\nconst TAB_CODE = 1;\nconst TAB_REQUIREMENTS = 2;\nconst TAB_DESIGN = 3;\nconst TAB_DATA = 4;\nconst TAB_FORM_BUILDER = 5;\n\n@Component({\n standalone: false,\n selector: 'mj-editor-tabs',\n template: `\n <div class=\"editor-tabs-container\">\n <div class=\"tab-bar\">\n @if (IsFormRoleComponent) {\n <button class=\"tab-pill\" [class.active]=\"state.ActiveTab === ${TAB_FORM_BUILDER}\" (click)=\"SelectTab(${TAB_FORM_BUILDER})\">\n <i class=\"fa-solid fa-table-list\"></i> Form Builder\n </button>\n }\n <button class=\"tab-pill\" [class.active]=\"state.ActiveTab === ${TAB_SPEC}\" (click)=\"SelectTab(${TAB_SPEC})\">\n <i class=\"fa-solid fa-file-code\"></i> Spec\n </button>\n <button class=\"tab-pill\" [class.active]=\"state.ActiveTab === ${TAB_CODE}\" (click)=\"SelectTab(${TAB_CODE})\">\n <i class=\"fa-solid fa-code\"></i> Code\n </button>\n <button class=\"tab-pill\" [class.active]=\"state.ActiveTab === ${TAB_REQUIREMENTS}\" (click)=\"SelectTab(${TAB_REQUIREMENTS})\">\n <i class=\"fa-solid fa-clipboard-list\"></i> Requirements\n </button>\n <button class=\"tab-pill\" [class.active]=\"state.ActiveTab === ${TAB_DESIGN}\" (click)=\"SelectTab(${TAB_DESIGN})\">\n <i class=\"fa-solid fa-drafting-compass\"></i> Design\n </button>\n <button class=\"tab-pill\" [class.active]=\"state.ActiveTab === ${TAB_DATA}\" (click)=\"SelectTab(${TAB_DATA})\">\n <i class=\"fa-solid fa-database\"></i> Data\n </button>\n <span class=\"tab-spacer\"></span>\n </div>\n\n <div class=\"tab-content\">\n @switch (state.ActiveTab) {\n @case (${TAB_SPEC}) {\n <mj-spec-editor></mj-spec-editor>\n }\n @case (${TAB_CODE}) {\n <mj-code-editor-panel></mj-code-editor-panel>\n }\n @case (${TAB_REQUIREMENTS}) {\n <mj-requirements-editor [Field]=\"'functionalRequirements'\" [Title]=\"'Functional Requirements'\"></mj-requirements-editor>\n }\n @case (${TAB_DESIGN}) {\n <mj-requirements-editor [Field]=\"'technicalDesign'\" [Title]=\"'Technical Design'\"></mj-requirements-editor>\n }\n @case (${TAB_DATA}) {\n <mj-data-requirements-editor></mj-data-requirements-editor>\n }\n @case (${TAB_FORM_BUILDER}) {\n <mj-form-builder-tab (RequestCodeTab)=\"SelectTab(${TAB_CODE})\"></mj-form-builder-tab>\n }\n }\n </div>\n </div>\n `,\n styles: [`\n :host {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n\n .editor-tabs-container {\n display: flex;\n flex-direction: column;\n flex: 1;\n overflow: hidden;\n }\n\n .tab-bar {\n display: flex;\n align-items: center;\n padding: 0 8px;\n height: 38px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 2px;\n }\n\n .tab-pill {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 5px 12px;\n border: none;\n border-radius: 8px;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n font-family: inherit;\n }\n\n .tab-pill:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n }\n\n .tab-pill.active {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\n font-weight: 600;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n }\n\n .tab-pill i {\n font-size: 11px;\n }\n\n .tab-spacer {\n flex: 1;\n }\n\n .tab-content {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .tab-content > * {\n flex: 1;\n overflow: hidden;\n }\n `]\n})\nexport class EditorTabsComponent implements OnInit, OnDestroy {\n\n private stateChangedSub: Subscription | null = null;\n /** Tracked so we can default to the Form Builder tab the first time a form-role component loads. */\n private lastFormRole = false;\n\n constructor(\n public state: ComponentStudioStateService,\n private cdr: ChangeDetectorRef\n ) {}\n\n ngOnInit(): void {\n this.lastFormRole = this.IsFormRoleComponent;\n this.maybeAutoSelectFormBuilder();\n this.stateChangedSub = this.state.StateChanged.subscribe(() => {\n this.maybeAutoSelectFormBuilder();\n this.cdr.detectChanges();\n });\n }\n\n ngOnDestroy(): void {\n if (this.stateChangedSub) {\n this.stateChangedSub.unsubscribe();\n this.stateChangedSub = null;\n }\n }\n\n SelectTab(index: number): void {\n this.state.ActiveTab = index;\n this.cdr.detectChanges();\n }\n\n /** True iff the current spec declares itself form-role. */\n public get IsFormRoleComponent(): boolean {\n const spec: ComponentSpec | null = this.state.GetCurrentSpec();\n return spec?.componentRole === 'form' || spec?.type === 'form';\n }\n\n /**\n * Auto-select the Form Builder tab the first time a form-role component\n * appears in state. Don't fight the user after that — if they switched\n * to Code or Spec, leave them there on subsequent state updates.\n */\n private maybeAutoSelectFormBuilder(): void {\n const isForm = this.IsFormRoleComponent;\n if (isForm && !this.lastFormRole) {\n this.state.ActiveTab = TAB_FORM_BUILDER;\n } else if (!isForm && this.lastFormRole) {\n // If we leave a form-role component, drop back to Spec.\n if (this.state.ActiveTab === TAB_FORM_BUILDER) {\n this.state.ActiveTab = TAB_SPEC;\n }\n }\n this.lastFormRole = isForm;\n }\n\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure-function code generator: FormCanvasModel → JSX string.
|
|
3
|
+
*
|
|
4
|
+
* The output conforms to the form-role component contract:
|
|
5
|
+
* - Destructures FormHostProps (record, mode, entityMetadata, callbacks, ...)
|
|
6
|
+
* - Maintains a local draft diff so edits don't mutate the BaseEntity snapshot
|
|
7
|
+
* - Registers RequestSave / RequestCancel via callbacks.RegisterMethod
|
|
8
|
+
* - Emits BeforeSave with dirtyFields when the host toolbar fires Save
|
|
9
|
+
* - No Save / Cancel buttons in the body — the host toolbar owns them
|
|
10
|
+
* - References only fields from the curated schema (linter requirement)
|
|
11
|
+
*
|
|
12
|
+
* This file is *intentionally* a pure function with no side effects so it can
|
|
13
|
+
* be unit-tested without DOM / Angular wiring.
|
|
14
|
+
*/
|
|
15
|
+
import type { CuratedFormSchema } from '@memberjunction/interactive-component-types/forms';
|
|
16
|
+
import type { FormCanvasModel } from './form-canvas-model';
|
|
17
|
+
/**
|
|
18
|
+
* Build a JS-safe identifier from a free-form component name. Caller is
|
|
19
|
+
* responsible for handling empty results.
|
|
20
|
+
*/
|
|
21
|
+
export declare function toComponentIdentifier(name: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Generate the full Component code string from a canvas model.
|
|
24
|
+
*
|
|
25
|
+
* @param canvas - the canvas model to render
|
|
26
|
+
* @param schema - the curated form schema for the canvas's entity (used to
|
|
27
|
+
* resolve field types / FK display fields / enum allowed values)
|
|
28
|
+
* @param componentName - human-readable component name (used for the JS
|
|
29
|
+
* function identifier)
|
|
30
|
+
*/
|
|
31
|
+
export declare function generateCodeFromCanvas(canvas: FormCanvasModel, schema: CuratedFormSchema, componentName: string): string;
|
|
32
|
+
//# sourceMappingURL=canvas-to-code.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-to-code.d.ts","sourceRoot":"","sources":["../../../src/ComponentStudio/services/canvas-to-code.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAoB,MAAM,mDAAmD,CAAC;AAC7G,OAAO,KAAK,EAAE,eAAe,EAAwC,MAAM,qBAAqB,CAAC;AAEjG;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI1D;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAClC,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,iBAAiB,EACzB,aAAa,EAAE,MAAM,GACtB,MAAM,CAyGR"}
|